radiant-sitemap_search-extension 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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