radiant-sitemap_search-extension 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/HELP.textile ADDED
@@ -0,0 +1,11 @@
1
+ The *Sitemap Search* extension, as its name implies, enables you to search your sitemap; pages, snippets and layouts
2
+
3
+ h2. Usage
4
+
5
+ The Search tab is located under 'Content' to the right of 'Pages'
6
+
7
+ The Search box is located in the lower bar of the index page for Pages, Snippets, Layouts.
8
+ If you have the the BannerRotator extension and/or the Templates extension installed, it will be on those index pages also.
9
+ And of course it is also on the Search Results page.
10
+
11
+ Enter your search string, and click the button. Results are sortable by attribute.
data/README.textile ADDED
@@ -0,0 +1,51 @@
1
+ h2. Sitemap Search
2
+
3
+ Created by Sean Cribbs in Fall 2007.
4
+ Revised and generalized by Sean Cribbs and Andrew vonderLuft in August 2008.
5
+ Extended and refactored by Andrew vonderLuft since then.
6
+
7
+ Provides a simple content search of pages, snippets, and layouts.
8
+ Contains rudimentary support for scoping searches within a given site when using the multi_site extension.
9
+
10
+ h2. Revision History
11
+
12
+ * 4/2011 - UI upgrade for Radiant >= 1.0.0; added Layouts; added templates to search from "Templates extension":https://github.com/avonderluft/radiant-templates-extension
13
+ * 2/2010 - add banners to search, from "BannerRotator extension":https://github.com/avonderluft/radiant-banner_rotator-extension
14
+ * 2/2009 - upgraded for compatibility with Radiant 0.7
15
+ * 12/2008 - initial commit
16
+
17
+ h2. Requirements
18
+
19
+ * current version requires Radiant >= 1.0.0
20
+ * tag 0.7.2 available for earlier versions
21
+
22
+ page_list_view extension must be installed
23
+
24
+ From your RADIANT_ROOT:
25
+
26
+ <pre>
27
+ $ script/extension install page_list_view
28
+ </pre>
29
+
30
+ h2. Installation
31
+
32
+ From your RADIANT_ROOT:
33
+
34
+ <pre>
35
+ $ script/extension install sitemap_search
36
+ </pre>
37
+
38
+ Restart your radiant app, and you should be good to go.
39
+
40
+ h2. Usage
41
+
42
+ See the Help doc.
43
+
44
+ h2. To do
45
+
46
+ * Include page fields, e.g. 'keywords' and 'description'
47
+
48
+ h2. Acknowledgments
49
+
50
+ Thanks to Digital Pulp for funding the initial development of this extension as part of the Redken.com project.
51
+ Further support for generalization and release was provided by Con-way.
data/Rakefile ADDED
@@ -0,0 +1,135 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "radiant-sitemap_search-extension"
5
+ gem.summary = %Q{Sitemap Search Extension for Radiant CMS}
6
+ gem.description = %Q{Adds search feature for pages, snippets, layouts, et al.}
7
+ gem.email = "avonderluft@avlux.net"
8
+ gem.homepage = "https://github.com/avonderluft/radiant-sitemap_search-extension"
9
+ gem.authors = ['Andrew vonderLuft','Sean Cribbs']
10
+ gem.add_dependency 'radiant', ">=1.0.0"
11
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package banner_rotator as a gem."
15
+ end
16
+ # I think this is the one that should be moved to the extension Rakefile template
17
+
18
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
19
+ # Check to see if the rspec plugin is installed first and require
20
+ # it if it is. If not, use the gem version.
21
+
22
+ # Determine where the RSpec plugin is by loading the boot
23
+ unless defined? RADIANT_ROOT
24
+ ENV["RAILS_ENV"] = "test"
25
+ case
26
+ when ENV["RADIANT_ENV_FILE"]
27
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
28
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
29
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
30
+ else
31
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
32
+ end
33
+ end
34
+
35
+ require 'rake'
36
+ require 'rake/rdoctask'
37
+ require 'rake/testtask'
38
+
39
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
40
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
41
+ require 'spec/rake/spectask'
42
+ # require 'spec/translator'
43
+
44
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
45
+ Object.send(:remove_const, :RADIANT_ROOT)
46
+
47
+ extension_root = File.expand_path(File.dirname(__FILE__))
48
+
49
+ task :default => :spec
50
+ task :stats => "spec:statsetup"
51
+
52
+ desc "Run all specs in spec directory"
53
+ Spec::Rake::SpecTask.new(:spec) do |t|
54
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
55
+ t.spec_files = FileList['spec/**/*_spec.rb']
56
+ end
57
+
58
+ namespace :spec do
59
+ desc "Run all specs in spec directory with RCov"
60
+ Spec::Rake::SpecTask.new(:rcov) do |t|
61
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
62
+ t.spec_files = FileList['spec/**/*_spec.rb']
63
+ t.rcov = true
64
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
65
+ end
66
+
67
+ desc "Print Specdoc for all specs"
68
+ Spec::Rake::SpecTask.new(:doc) do |t|
69
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
70
+ t.spec_files = FileList['spec/**/*_spec.rb']
71
+ end
72
+
73
+ [:models, :controllers, :views, :helpers].each do |sub|
74
+ desc "Run the specs under spec/#{sub}"
75
+ Spec::Rake::SpecTask.new(sub) do |t|
76
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
77
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
78
+ end
79
+ end
80
+
81
+ # Hopefully no one has written their extensions in pre-0.9 style
82
+ # desc "Translate specs from pre-0.9 to 0.9 style"
83
+ # task :translate do
84
+ # translator = ::Spec::Translator.new
85
+ # dir = RAILS_ROOT + '/spec'
86
+ # translator.translate(dir, dir)
87
+ # end
88
+
89
+ # Setup specs for stats
90
+ task :statsetup do
91
+ require 'code_statistics'
92
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
93
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
94
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
95
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
96
+ ::CodeStatistics::TEST_TYPES << "Model specs"
97
+ ::CodeStatistics::TEST_TYPES << "View specs"
98
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
99
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
100
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
101
+ end
102
+
103
+ namespace :db do
104
+ namespace :fixtures do
105
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
106
+ task :load => :environment do
107
+ require 'active_record/fixtures'
108
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
109
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
110
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ desc 'Generate documentation for the sitemap_search extension.'
118
+ Rake::RDocTask.new(:rdoc) do |rdoc|
119
+ rdoc.rdoc_dir = 'rdoc'
120
+ rdoc.title = 'SitemapSearchExtension'
121
+ rdoc.options << '--line-numbers' << '--inline-source'
122
+ rdoc.rdoc_files.include('README')
123
+ rdoc.rdoc_files.include('lib/**/*.rb')
124
+ end
125
+
126
+ # For extensions that are in transition
127
+ desc 'Test the sitemap_search extension.'
128
+ Rake::TestTask.new(:test) do |t|
129
+ t.libs << 'lib'
130
+ t.pattern = 'test/**/*_test.rb'
131
+ t.verbose = true
132
+ end
133
+
134
+ # Load any custom rakefiles for extension
135
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,13 @@
1
+ class Admin::SearchController < ApplicationController
2
+ def index
3
+ if params[:q]
4
+ @pages = Page.search(params[:q]).uniq
5
+ if current_user.designer? || current_user.admin?
6
+ @snippets = Snippet.search(params[:q]).uniq
7
+ @layouts = Layout.search(params[:q]).uniq
8
+ @templates = Template.search(params[:q]).uniq if defined?(TemplatesExtension)
9
+ @banners = Banner.search(params[:q]).uniq if defined?(BannerRotatorExtension)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ module Admin::SearchHelper
2
+ include Admin::ListViewHelper
3
+
4
+ def link_text(object)
5
+ case object
6
+ when Page
7
+ icon = object.virtual? ? 'virtual-page' : 'page'
8
+ %Q{#{image(icon, :height => 18)} <span class="title">#{object.title}</span>}
9
+ when Snippet
10
+ %Q{#{image('snippet', :height => 18)} <span class="title">#{object.name}</span>}
11
+ when Banner
12
+ %Q{#{image('pictures', :height => 18)} <span class="title">#{object.name}</span>}
13
+ end
14
+ end
15
+
16
+ def link_url(object)
17
+ case object
18
+ when Page; edit_admin_page_path(:id => object)
19
+ when Snippet; edit_admin_snippet_path(:id => object)
20
+ when Banner; edit_admin_banner_path(:id => object)
21
+ end
22
+ end
23
+
24
+ def link_attrs(object)
25
+ {:title => object.url } if Page === object
26
+ end
27
+
28
+ def cell_class(object)
29
+ 'page'
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ - @page_title = t('pages') + ' - ' + default_page_title
2
+
3
+ .outset
4
+ = render_region :top
5
+ %table.index#pages{:summary=>t('page_hierarchy')}
6
+ %thead
7
+ %tr
8
+ - render_region :sitemap_head do |sitemap_head|
9
+ - sitemap_head.title_column_header do
10
+ %th.name= t('page')
11
+ - sitemap_head.status_column_header do
12
+ %th.status= t('status')
13
+ - sitemap_head.actions_column_header do
14
+ %th.actions= t('modify')
15
+ %tbody
16
+ - if @homepage
17
+ = render_node @homepage
18
+ - else
19
+ %tr
20
+ %td.empty{:colspan => admin.page.index.node.length}= t('no_pages')
21
+ = render_region :bottom
22
+
23
+ #actions
24
+ %ul
25
+ - unless @homepage
26
+ %li= link_to image('plus') + " " + t("new_homepage"), new_admin_page_path, :class => 'action_button'
27
+ - else
28
+ = render :partial => 'admin/search/search_action'
@@ -0,0 +1,27 @@
1
+ - include_javascript 'admin/tablekit'
2
+ - include_javascript 'admin/ruledtable'
3
+ - @page_title = t('pages') + ' - ' + default_page_title
4
+
5
+ .outset
6
+ = render_region :top
7
+ %table.index.sortable{:summary=>"Sortable list of pages"}
8
+ %thead
9
+ %tr
10
+ - list_display_attributes.each do |att|
11
+ %th{:class => attribute_header_class(att), :id => attribute_header_id(att) }
12
+ %a
13
+ %span.w1= att.humanize
14
+ %tbody
15
+ - if @pages.any?
16
+ = render :partial => 'page', :collection => @pages
17
+ - else
18
+ %tr
19
+ %td.empty{:colspan => list_display_attributes.length}= t('no_pages')
20
+ #actions
21
+ = pagination_for(@pages)
22
+ %ul
23
+ - unless @pages.any?
24
+ %li= link_to image('plus') + " " + t("new_homepage"), new_admin_page_path, :class => 'action_button'
25
+ = render :partial => 'admin/search/search_action'
26
+
27
+ = render :partial => 'page_list_view_styles'
@@ -0,0 +1,11 @@
1
+ %tr[banner]
2
+ %td.preview
3
+ %a{:href => edit_admin_banner_url(banner)}
4
+ %img.snapshot{:src => banner.background_image, :alt => "#{banner.name} #{t('banner_rotator.banner')}", :title => "#{t('banner_rotator.edit')} #{banner.name} #{t('banner_rotator.banner')}"}
5
+ %td.name= link_to banner.name, edit_admin_banner_url(banner)
6
+ %td.status
7
+ = banner.description if banner.description
8
+ %td.status{:style=>"font-size:75%"}
9
+ = banner.link_url if banner.link_url
10
+ %td.status
11
+ = banner.updated_at.strftime("%m/%d/%Y at %I:%M %p") if banner.updated_at
@@ -0,0 +1,5 @@
1
+ #actions
2
+ = pagination_for(@banners)
3
+ %ul
4
+ %li= link_to image('plus') + " " + t('banner_rotator.new_banner'), new_admin_banner_url
5
+ = render :partial => 'admin/search/search_action'
@@ -0,0 +1,8 @@
1
+ %tr[layout]
2
+ %td.name
3
+ = image('layout', :alt => '')
4
+ = link_to layout.name, edit_admin_layout_url(layout)
5
+ %td.status
6
+ = layout.updated_by.name if layout.updated_by
7
+ %td.status
8
+ = layout.updated_at.strftime("%m/%d/%Y at %I:%M %p") if layout.updated_at
@@ -0,0 +1,5 @@
1
+ #actions
2
+ = pagination_for(@layouts)
3
+ %ul
4
+ %li= link_to image('plus') + " " + t('new_layout'), new_admin_layout_url, :class => 'action_button'
5
+ = render :partial => 'admin/search/search_action'
@@ -0,0 +1,15 @@
1
+ .nav
2
+ = link_to t('pages') + " (#{@pages.size})", '#pages'
3
+ - if designer?
4
+ &bull;
5
+ = link_to t('snippets') + " (#{@snippets.size})", '#snippets'
6
+ &bull;
7
+ = link_to t('layouts') + " (#{@layouts.size})", '#layouts'
8
+ - if defined?(TemplatesExtension)
9
+ &bull;
10
+ = link_to t('templates') + " (#{@templates.size})", '#templates'
11
+ - if defined?(BannerRotatorExtension)
12
+ &bull;
13
+ = link_to t('banner_rotator.banners') + " (#{@banners.size})", '#banners'
14
+ &bull;
15
+ = link_to 'Top', '#top'
@@ -0,0 +1,7 @@
1
+ %li
2
+ #site_search.action_button
3
+ - form_for :site_search, :url => search_path, :html => { :class => 'button_form', :multipart => true } do |f|
4
+ %span
5
+ = f.label :site_search, image('search')
6
+ = text_field_tag :q, params[:q], :title => t('sitemap_search.search_content'), :cols => "20"
7
+ = f.submit t('sitemap_search.search_content')
@@ -0,0 +1,8 @@
1
+ %tr[snippet]
2
+ %td.name
3
+ = image('snippet', :alt => '')
4
+ = link_to snippet.name, edit_admin_snippet_url(snippet)
5
+ %td.status
6
+ = snippet.updated_by.name if snippet.updated_by
7
+ %td.status
8
+ = snippet.updated_at.strftime("%m/%d/%Y at %I:%M %p") if snippet.updated_at
@@ -0,0 +1,5 @@
1
+ #actions
2
+ = pagination_for(@snippets)
3
+ %ul
4
+ %li= link_to image('plus') + " " + t('new_snippet'), new_admin_snippet_url, :class => 'action_button'
5
+ = render :partial => 'admin/search/search_action'
@@ -0,0 +1,8 @@
1
+ %tr[template]
2
+ %td.name
3
+ = image('template', :alt => '')
4
+ = link_to template.name, edit_admin_template_url(template)
5
+ %td.status
6
+ = template.page_class_name if template.page_class_name
7
+ %td.status
8
+ = template.updated_at.strftime("%m/%d/%Y at %I:%M %p") if template.updated_at
@@ -0,0 +1,4 @@
1
+ #actions
2
+ %ul
3
+ %li= link_to image('plus') + " " + t('new_template'), new_admin_template_url
4
+ = render :partial => 'admin/search/search_action'
@@ -0,0 +1,128 @@
1
+ - include_javascript 'admin/ruledtable'
2
+ - include_javascript 'admin/tablekit'
3
+ - @page_title = t('sitemap_search.search_content') + ' - ' + default_page_title
4
+
5
+ - if params[:q]
6
+ - query = ': ' + t('sitemap_search.search_results_for') + " '#{params[:q]}'"
7
+ - results_label = t('pages') + query
8
+ %h3#pages{:style=>"margin-top:-10px"}
9
+ = results_label
10
+ = render :partial => 'results_nav'
11
+ %table#page_list.index.sortable{:summary=>results_label}
12
+ %thead
13
+ %tr
14
+ - list_display_attributes.each do |att|
15
+ %th{:class => attribute_header_class(att), :id => attribute_header_id(att) }
16
+ %a
17
+ %span.w1= att.humanize
18
+ %tbody
19
+ - unless @pages.blank?
20
+ = render :partial => "admin/pages/page", :collection => @pages
21
+ - else
22
+ %tr
23
+ %td.note{:colspan => list_display_attributes.size }
24
+ = params[:q].blank? ? "Empty search." : "No results from query."
25
+
26
+ - if designer?
27
+ - results_label = t('snippets') + query
28
+ %h3#snippets
29
+ = results_label
30
+ = render :partial => 'results_nav'
31
+ %table#snippet_list.index.sortable{:summary=>results_label}
32
+ %thead
33
+ %tr
34
+ - atts = %w{name updated_by updated_at}
35
+ - atts.each do |att|
36
+ %th{:class => attribute_header_class(att), :id => attribute_header_id(att) }
37
+ %a
38
+ %span.w1= att.humanize
39
+ %tbody
40
+ - unless @snippets.blank?
41
+ = render :partial => "snippet", :collection => @snippets
42
+ - else
43
+ %tr
44
+ %td.note{:colspan => atts.size }
45
+ = params[:q].blank? ? "Empty search." : "No results from query."
46
+
47
+ - results_label = t('layouts') + query
48
+ %h3#layouts
49
+ = results_label
50
+ = render :partial => 'results_nav'
51
+ %table#layout_list.index.sortable{:summary=>results_label}
52
+ %thead
53
+ %tr
54
+ - atts = %w{name updated_by updated_at}
55
+ - atts.each do |att|
56
+ %th{:class => attribute_header_class(att), :id => attribute_header_id(att) }
57
+ %a
58
+ %span.w1= att.humanize
59
+ %tbody
60
+ - unless @layouts.blank?
61
+ = render :partial => "layout", :collection => @layouts
62
+ - else
63
+ %tr
64
+ %td.note{:colspan => atts.size }
65
+ = params[:q].blank? ? "Empty search." : "No results from query."
66
+
67
+ - results_label = t('templates') + query
68
+ %h3#templates
69
+ = results_label
70
+ = render :partial => 'results_nav'
71
+ %table#template_list.index.sortable{:summary=>results_label}
72
+ %thead
73
+ %tr
74
+ - atts = %w{name page_class_name updated_at}
75
+ - atts.each do |att|
76
+ %th{:class => attribute_header_class(att), :id => attribute_header_id(att) }
77
+ %a
78
+ %span.w1= att.humanize
79
+ %tbody
80
+ - unless @templates.blank?
81
+ = render :partial => "template", :collection => @templates
82
+ - else
83
+ %tr
84
+ %td.note{:colspan => atts.size }
85
+ = params[:q].blank? ? "Empty search." : "No results from query."
86
+
87
+ - if defined?(BannerRotatorExtension)
88
+ - results_label = t('banner_rotator.banners') + query
89
+ %h3#banners
90
+ = results_label
91
+ = render :partial => 'results_nav'
92
+ %table#banner_list.index.sortable{:summary=>results_label}
93
+ %thead
94
+ %tr
95
+ %th.image
96
+ - atts = %w{name description link_url updated_at}
97
+ - atts.each do |att|
98
+ %th{:class => attribute_header_class(att), :id => attribute_header_id(att) }
99
+ %a
100
+ %span.w1= att.humanize
101
+ %tbody
102
+ - unless @banners.blank?
103
+ = render :partial => "banner", :collection => @banners
104
+ - else
105
+ %tr
106
+ %td.note{:colspan => atts.size + 1 }
107
+ = params[:q].blank? ? "Empty search." : "No results from query."
108
+ - else
109
+ %h3= t('sitemap_search.search_content')
110
+ = t('sitemap_search.instructions')
111
+
112
+ #actions
113
+ %ul
114
+ = render :partial => 'search_action'
115
+
116
+ = render :partial => 'admin/pages/page_list_view_styles'
117
+ - content_for :page_css do
118
+ :sass
119
+ .nav
120
+ float: right
121
+ font-size: 80%
122
+ h3
123
+ padding: 5px
124
+ td
125
+ .snapshot
126
+ height: 40px
127
+ max-width: 320px
128
+ border: 1px solid d5f0ff
@@ -0,0 +1,7 @@
1
+ ---
2
+ en:
3
+ sitemap_search:
4
+ instructions: "Enter query string at bottom of page to search."
5
+ search: "Search"
6
+ search_content: "Search Content"
7
+ search_results_for: "Search Results for"
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.search 'admin/search', :controller => 'admin/search', :action => 'index'
3
+ end
@@ -0,0 +1,41 @@
1
+ module SitemapSearch::Model
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ base.send :cattr_accessor, :search_fields
5
+ base.send :cattr_accessor, :includes
6
+ if base == Page
7
+ base.search_fields = [:title, :slug, :breadcrumb, :content]
8
+ base.search_fields << :draft_content if defined?(ConcurrentDraftExtension)
9
+ base.includes = [:parts]
10
+ elsif base == Snippet
11
+ base.search_fields = [:name, :content]
12
+ base.search_fields << :draft_content if defined?(ConcurrentDraftExtension)
13
+ elsif base == Layout
14
+ base.search_fields = [:name, :content]
15
+ base.search_fields << :draft_content if defined?(ConcurrentDraftExtension)
16
+ elsif defined?(TemplatesExtension) && base == Template
17
+ base.search_fields = [:name, :content]
18
+ elsif defined?(BannerRotatorExtension) && base == Banner
19
+ base.search_fields = [:name, :description, :background_image, :foreground_image, :link_url]
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ def search(query)
25
+ # split up the words in the query, clear out blank ones
26
+ words = query.strip.downcase.split(" ").reject(&:blank?)
27
+ # return no results if query was blank
28
+ return [] if words.empty?
29
+ # wrap each one in the matchers and replicate by the number of fields
30
+ wrapped_words = words.map {|word| ["%#{word}%"] * self.search_fields.size }
31
+ # Construct conditions for each field
32
+ field_conditions = self.search_fields.map {|field| "LOWER(#{field}) LIKE ?"}
33
+ # join them with with an OR
34
+ fields_per_word = field_conditions.join(" OR ")
35
+ # replicate the condition for each word, join them all with an AND
36
+ all_conditions = ([fields_per_word] * words.size).map {|stmt| "(#{stmt})"}.join(" AND ")
37
+ query_conditions = [all_conditions, wrapped_words].flatten
38
+ find(:all, :conditions => query_conditions, :joins => includes)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :sitemap_search do
4
+
5
+ desc "Runs the migration of the Sitemap Search extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ SitemapSearchExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ else
11
+ SitemapSearchExtension.migrator.migrate
12
+ end
13
+ end
14
+
15
+ desc "Copies public assets of the Sitemap Search to the instance public/ directory."
16
+ task :update => :environment do
17
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
18
+ Dir[SitemapSearchExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
19
+ path = file.sub(SitemapSearchExtension.root, '')
20
+ directory = File.dirname(path)
21
+ puts "Copying #{path}..."
22
+ mkdir_p RAILS_ROOT + directory
23
+ cp file, RAILS_ROOT + path
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ # Uncomment this if you reference any of your controllers in activate
2
+ # require_dependency 'application'
3
+
4
+ class SitemapSearchExtension < Radiant::Extension
5
+ version "#{File.read(File.expand_path(File.dirname(__FILE__)) + '/VERSION')}"
6
+ description "Adds simple search feature for pages, snippets, layouts, et al."
7
+ url "https://github.com/avonderluft/radiant-sitemap_search-extension"
8
+
9
+ def activate
10
+ unless defined?(PageListView)
11
+ raise "The Page List View extension is required - install from RAILS_ROOT with 'script/extension install page_list_view'"
12
+ end
13
+ tab "Content" do
14
+ add_item "Search", '/admin/search'
15
+ end
16
+ [Page, Snippet, Layout].each do |klass|
17
+ klass.send :include, SitemapSearch::Model
18
+ end
19
+ admin.snippet.index.bottom.delete 'new_button'
20
+ admin.snippet.index.add :bottom, 'admin/search/snippet_index_bottom'
21
+ admin.layout.index.bottom.delete 'new_button'
22
+ admin.layout.index.add :bottom, 'admin/search/layout_index_bottom'
23
+ if defined?(TemplatesExtension)
24
+ Template.send :include, SitemapSearch::Model
25
+ admin.template.index.bottom.delete 'new_button'
26
+ admin.template.index.add :bottom, 'admin/search/banner_index_bottom'
27
+ end
28
+ if defined?(BannerRotatorExtension)
29
+ Banner.send :include, SitemapSearch::Model
30
+ admin.banner.index.bottom.delete 'new_button'
31
+ admin.banner.index.add :bottom, 'admin/search/template_index_bottom'
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,111 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Admin::SearchController do
4
+ dataset :users
5
+
6
+ [:admin, :designer].each do |user|
7
+ describe "search as user with #{user} privileges" do
8
+ before :each do
9
+ @page, @snippet, @layout = mock_model(Page), mock_model(Snippet), mock_model(Layout)
10
+ Page.stub!(:search).and_return([@page])
11
+ Snippet.stub!(:search).and_return([@snippet])
12
+ Layout.stub!(:search).and_return([@layout])
13
+ login_as user
14
+ end
15
+
16
+ def do_get
17
+ get :index, :q => 'radiant'
18
+ end
19
+ it "should search pages" do
20
+ Page.should_receive(:search).with('radiant').and_return([@page])
21
+ do_get
22
+ end
23
+ it "should search snippets" do
24
+ Snippet.should_receive(:search).with('radiant').and_return([@snippet])
25
+ do_get
26
+ end
27
+ it "should search layouts" do
28
+ Layout.should_receive(:search).with('radiant').and_return([@layout])
29
+ do_get
30
+ end
31
+ if defined?(TemplatesExtension)
32
+ it "should search templates" do
33
+ @banner = mock_model(Template)
34
+ Template.stub!(:search).and_return([@template])
35
+ Template.should_receive(:search).with('radiant').and_return([@template])
36
+ do_get
37
+ end
38
+ end
39
+ if defined?(BannerRotatorExtension)
40
+ it "should search banners" do
41
+ @banner = mock_model(Banner)
42
+ Banner.stub!(:search).and_return([@banner])
43
+ Banner.should_receive(:search).with('radiant').and_return([@banner])
44
+ do_get
45
+ end
46
+ end
47
+ it "should render the index template" do
48
+ do_get
49
+ response.should render_template('index')
50
+ end
51
+ it "should be successful" do
52
+ do_get
53
+ response.should be_success
54
+ end
55
+ end
56
+ end
57
+
58
+ [:existing, :non_admin].each do |user|
59
+ describe "search as user with #{user} privileges" do
60
+ before :each do
61
+ @page, @snippet, @layout = mock_model(Page), mock_model(Snippet), mock_model(Layout)
62
+ Page.stub!(:search).and_return([@page])
63
+ Snippet.stub!(:search).and_return([@snippet])
64
+ Layout.stub!(:search).and_return([@layout])
65
+ login_as user
66
+ end
67
+
68
+ def do_get
69
+ get :index, :q => 'radiant'
70
+ end
71
+
72
+ it "should search pages" do
73
+ Page.should_receive(:search).with('radiant').and_return([@page])
74
+ do_get
75
+ end
76
+ it "should not search snippets" do
77
+ Snippet.should_not_receive(:search).with('radiant')
78
+ do_get
79
+ end
80
+ it "should not search layouts" do
81
+ Layout.should_not_receive(:search).with('radiant')
82
+ do_get
83
+ end
84
+ if defined?(TemplatesExtension)
85
+ it "should not search templates" do
86
+ @banner = mock_model(Template)
87
+ Template.stub!(:search).and_return([@template])
88
+ Template.should_not_receive(:search).with('radiant')
89
+ do_get
90
+ end
91
+ end
92
+ if defined?(BannerRotatorExtension)
93
+ it "should not search banners" do
94
+ @banner = mock_model(Banner)
95
+ Banner.stub!(:search).and_return([@banner])
96
+ Banner.should_not_receive(:search).with('radiant')
97
+ do_get
98
+ end
99
+ end
100
+ it "should render the index template" do
101
+ do_get
102
+ response.should render_template('index')
103
+ end
104
+ it "should be successful" do
105
+ do_get
106
+ response.should be_success
107
+ end
108
+ end
109
+ end
110
+
111
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Page, "search" do
4
+ dataset :pages
5
+
6
+ before :each do
7
+ pages(:radius).update_attributes(:breadcrumb => "Wheat and Rye")
8
+ if defined?(ConcurrentDraft)
9
+ pages(:first).parts.first.update_attributes(:draft_content => "Special draft content")
10
+ else
11
+ pages(:first).parts.first.update_attributes(:content => "Special content")
12
+ end
13
+ end
14
+
15
+ it "should find pages from words in the title" do
16
+ Page.search('wheat').should include(pages(:radius))
17
+ end
18
+ it "should find pages from words in the breadcrumb" do
19
+ Page.search('f').should include(pages(:f))
20
+ end
21
+ # it "should find pages from words in the keywords" do
22
+ # Page.search('harmonious').should include(pages(:assorted))
23
+ # end
24
+ # it "should find pages from words in the description" do
25
+ # Page.search('sweet').should include(pages(:assorted))
26
+ # end
27
+ it "should find pages from words in the slug" do
28
+ Page.search('article-4').should include(pages(:article_4))
29
+ end
30
+ it "should find pages from words in the parts content" do
31
+ Page.search('world!').should include(pages(:home))
32
+ end
33
+ it "should find pages from words in the content" do
34
+ Page.search('special').should include(pages(:first))
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Snippet, "search" do
4
+ dataset :snippets
5
+ before :each do
6
+ if defined?(ConcurrentDraft)
7
+ snippets(:first).update_attributes(:draft_content => "Special draft content")
8
+ else
9
+ snippets(:first).update_attributes(:content => "Special content")
10
+ end
11
+ end
12
+
13
+ it "should find snippets from words in the name" do
14
+ Snippet.search('first').should include(snippets(:first))
15
+ end
16
+
17
+ it "should find snippets from words in the content" do
18
+ Snippet.search('Before').should include(snippets(:yielding))
19
+ end
20
+
21
+ it "should find snippets from words in the content" do
22
+ Snippet.search('special').should include(snippets(:first))
23
+ end
24
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,37 @@
1
+ unless defined? RADIANT_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["RADIANT_ENV_FILE"]
5
+ require ENV["RADIANT_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{RADIANT_ROOT}/spec/spec_helper"
13
+
14
+ if File.directory?(File.dirname(__FILE__) + "/scenarios")
15
+ Scenario.load_paths.unshift File.dirname(__FILE__) + "/scenarios"
16
+ end
17
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
18
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
19
+ end
20
+
21
+ Spec::Runner.configure do |config|
22
+ # config.use_transactional_fixtures = true
23
+ # config.use_instantiated_fixtures = false
24
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
25
+
26
+ # You can declare fixtures for each behaviour like this:
27
+ # describe "...." do
28
+ # fixtures :table_a, :table_b
29
+ #
30
+ # Alternatively, if you prefer to declare them only once, you can
31
+ # do so here, like so ...
32
+ #
33
+ # config.global_fixtures = :table_a, :table_b
34
+ #
35
+ # If you declare global fixtures, be aware that they will be declared
36
+ # for all of your examples, even those that don't use them.
37
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-sitemap_search-extension
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Andrew vonderLuft
14
+ - Sean Cribbs
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-04-22 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: radiant
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 23
31
+ segments:
32
+ - 1
33
+ - 0
34
+ - 0
35
+ version: 1.0.0
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ description: Adds search feature for pages, snippets, layouts, et al.
39
+ email: avonderluft@avlux.net
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - README.textile
46
+ files:
47
+ - HELP.textile
48
+ - README.textile
49
+ - Rakefile
50
+ - VERSION
51
+ - app/controllers/admin/search_controller.rb
52
+ - app/helpers/admin/search_helper.rb
53
+ - app/views/admin/pages/index.html.haml
54
+ - app/views/admin/pages/page_list_view.html.haml
55
+ - app/views/admin/search/_banner.html.haml
56
+ - app/views/admin/search/_banner_index_bottom.html.haml
57
+ - app/views/admin/search/_layout.html.haml
58
+ - app/views/admin/search/_layout_index_bottom.html.haml
59
+ - app/views/admin/search/_results_nav.html.haml
60
+ - app/views/admin/search/_search_action.html.haml
61
+ - app/views/admin/search/_snippet.html.haml
62
+ - app/views/admin/search/_snippet_index_bottom.html.haml
63
+ - app/views/admin/search/_template.html.haml
64
+ - app/views/admin/search/_template_index_bottom.html.haml
65
+ - app/views/admin/search/index.html.haml
66
+ - config/locales/en.yml
67
+ - config/routes.rb
68
+ - lib/sitemap_search/model.rb
69
+ - lib/tasks/sitemap_search_extension_tasks.rake
70
+ - sitemap_search_extension.rb
71
+ - spec/controllers/search_controller_spec.rb
72
+ - spec/models/page_extensions_spec.rb
73
+ - spec/models/snippet_extensions_spec.rb
74
+ - spec/spec.opts
75
+ - spec/spec_helper.rb
76
+ has_rdoc: true
77
+ homepage: https://github.com/avonderluft/radiant-sitemap_search-extension
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options: []
82
+
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ requirements: []
104
+
105
+ rubyforge_project:
106
+ rubygems_version: 1.6.2
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: Sitemap Search Extension for Radiant CMS
110
+ test_files:
111
+ - spec/controllers/search_controller_spec.rb
112
+ - spec/models/page_extensions_spec.rb
113
+ - spec/models/snippet_extensions_spec.rb
114
+ - spec/spec_helper.rb