presenting 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/LICENSE +20 -0
  2. data/README +10 -0
  3. data/Rakefile +22 -0
  4. data/app/assets/javascript/grid.js +0 -0
  5. data/app/assets/javascript/search.js +13 -0
  6. data/app/assets/stylesheets/details-color.css +7 -0
  7. data/app/assets/stylesheets/details.css +10 -0
  8. data/app/assets/stylesheets/form.css +1 -0
  9. data/app/assets/stylesheets/grid-color.css +71 -0
  10. data/app/assets/stylesheets/grid.css +64 -0
  11. data/app/assets/stylesheets/search-color.css +16 -0
  12. data/app/assets/stylesheets/search.css +45 -0
  13. data/app/controllers/presentation/assets_controller.rb +42 -0
  14. data/app/views/presentations/_details.erb +11 -0
  15. data/app/views/presentations/_field_search.erb +14 -0
  16. data/app/views/presentations/_form.erb +20 -0
  17. data/app/views/presentations/_grid.erb +70 -0
  18. data/app/views/presentations/_search.erb +7 -0
  19. data/config/routes.rb +3 -0
  20. data/lib/presentation/base.rb +48 -0
  21. data/lib/presentation/details.rb +19 -0
  22. data/lib/presentation/field_search.rb +65 -0
  23. data/lib/presentation/form.rb +149 -0
  24. data/lib/presentation/grid.rb +160 -0
  25. data/lib/presentation/search.rb +9 -0
  26. data/lib/presenting/attribute.rb +51 -0
  27. data/lib/presenting/configurable.rb +10 -0
  28. data/lib/presenting/defaults.rb +10 -0
  29. data/lib/presenting/field_set.rb +26 -0
  30. data/lib/presenting/form_helpers.rb +51 -0
  31. data/lib/presenting/helpers.rb +110 -0
  32. data/lib/presenting/sanitize.rb +19 -0
  33. data/lib/presenting/search.rb +185 -0
  34. data/lib/presenting/sorting.rb +87 -0
  35. data/lib/presenting/view.rb +3 -0
  36. data/lib/presenting.rb +9 -0
  37. data/rails/init.rb +12 -0
  38. data/test/assets_test.rb +58 -0
  39. data/test/attribute_test.rb +61 -0
  40. data/test/configurable_test.rb +20 -0
  41. data/test/details_test.rb +68 -0
  42. data/test/field_search_test.rb +102 -0
  43. data/test/field_set_test.rb +46 -0
  44. data/test/form_test.rb +287 -0
  45. data/test/grid_test.rb +219 -0
  46. data/test/helpers_test.rb +72 -0
  47. data/test/presenting_test.rb +15 -0
  48. data/test/rails/app/controllers/application_controller.rb +15 -0
  49. data/test/rails/app/controllers/users_controller.rb +36 -0
  50. data/test/rails/app/helpers/application_helper.rb +3 -0
  51. data/test/rails/app/helpers/users_helper.rb +2 -0
  52. data/test/rails/app/models/user.rb +2 -0
  53. data/test/rails/app/views/layouts/application.html.erb +15 -0
  54. data/test/rails/app/views/users/index.html.erb +10 -0
  55. data/test/rails/app/views/users/new.html.erb +2 -0
  56. data/test/rails/app/views/users/show.html.erb +1 -0
  57. data/test/rails/config/boot.rb +109 -0
  58. data/test/rails/config/database.yml +17 -0
  59. data/test/rails/config/environment.rb +13 -0
  60. data/test/rails/config/environments/development.rb +17 -0
  61. data/test/rails/config/environments/production.rb +24 -0
  62. data/test/rails/config/environments/test.rb +22 -0
  63. data/test/rails/config/locales/en.yml +5 -0
  64. data/test/rails/config/routes.rb +5 -0
  65. data/test/rails/db/development.sqlite3 +0 -0
  66. data/test/rails/db/migrate/20090213085444_create_users.rb +13 -0
  67. data/test/rails/db/migrate/20090213085607_populate_users.rb +13 -0
  68. data/test/rails/db/schema.rb +23 -0
  69. data/test/rails/db/test.sqlite3 +0 -0
  70. data/test/rails/log/development.log +858 -0
  71. data/test/rails/public/404.html +30 -0
  72. data/test/rails/public/422.html +30 -0
  73. data/test/rails/public/500.html +33 -0
  74. data/test/rails/public/javascripts/application.js +2 -0
  75. data/test/rails/public/javascripts/jquery.livequery.min.js +11 -0
  76. data/test/rails/public/javascripts/prototype.js +4320 -0
  77. data/test/rails/script/console +3 -0
  78. data/test/rails/script/dbconsole +3 -0
  79. data/test/rails/script/destroy +3 -0
  80. data/test/rails/script/generate +3 -0
  81. data/test/rails/script/plugin +3 -0
  82. data/test/rails/script/runner +3 -0
  83. data/test/rails/script/server +3 -0
  84. data/test/sanitize_test.rb +15 -0
  85. data/test/search_conditions_test.rb +137 -0
  86. data/test/search_test.rb +30 -0
  87. data/test/sorting_test.rb +63 -0
  88. data/test/test_helper.rb +66 -0
  89. metadata +217 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Lance Ivy
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,10 @@
1
+ Presenting
2
+ ==========
3
+ Bringing together my work on ActiveScaffold and Components into standardized, reusable view macros.
4
+
5
+ Performance
6
+ ===========
7
+ I don't see why it wouldn't be fast. But if anyone "discovers":http://rpm.newrelic.com a "problem":http://ruby-prof.rubyforge.org/, we can go from there. Why worry early?
8
+
9
+
10
+ Copyright (c) 2008 Lance Ivy, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the presenting plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the presenting plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Presenting'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
File without changes
@@ -0,0 +1,13 @@
1
+ $('.presentation-search .compact fieldset label').livequery(function() {
2
+ var label = $(this);
3
+ var field = label.siblings('input');
4
+ if (!field[0] || field.attr('type') == 'checkbox') return;
5
+
6
+ label.addClass('overlabel');
7
+
8
+ var hide_label = function() { label.css('text-indent', '-1000px') };
9
+ var show_label = function() { this.value || label.css('text-indent', '0px') };
10
+
11
+ $(field).focus(hide_label).blur(show_label).each(hide_label).each(show_label);
12
+ $(label).click(function() {field.focus()});
13
+ });
@@ -0,0 +1,7 @@
1
+ .presentation-details dt {
2
+ color: #444;
3
+ }
4
+
5
+ .presentation-details dd {
6
+ border-color: #888;
7
+ }
@@ -0,0 +1,10 @@
1
+ .presentation-details dt {
2
+ font-weight: bold;
3
+ }
4
+
5
+ .presentation-details dd {
6
+ margin-left: 0;
7
+ padding-bottom: 0.5em;
8
+ border-bottom: 1px dotted;
9
+ margin-bottom: 0.5em;
10
+ }
@@ -0,0 +1 @@
1
+ .presentation-form {}
@@ -0,0 +1,71 @@
1
+ .presentation-grid a {
2
+ color: #06c;
3
+ }
4
+
5
+ .presentation-grid {
6
+ font-family: sans-serif;
7
+ background-color: #fff;
8
+ }
9
+
10
+ .presentation-grid caption {
11
+ background-color: transparent;
12
+ }
13
+
14
+ .presentation-grid thead {
15
+ background-color: transparent;
16
+ }
17
+
18
+ .presentation-grid thead th {
19
+ border-bottom: 2px solid #aaa;
20
+ font-weight: normal;
21
+ color: #666;
22
+ background-color: transparent;
23
+ }
24
+
25
+ .presentation-grid tbody tr.even {
26
+ background-color: #e6f2ff;
27
+ border-bottom: 1px solid #c5dbf7;
28
+ border-top: 1px solid #c5dbf7;
29
+ }
30
+
31
+ .presentation-grid tbody td.sorted {
32
+ background-color: #f5f5f5;
33
+ }
34
+
35
+ .presentation-grid tbody tr.even td.sorted {
36
+ background-color: #c5dbf7;
37
+ }
38
+
39
+ .presentation-grid tfoot .pagination {
40
+ margin-top: 0.5em;
41
+ }
42
+
43
+ .presentation-grid tfoot .pagination a {
44
+ text-decoration: none;
45
+ }
46
+
47
+ .presentation-grid tfoot .pagination .prev_page,
48
+ .presentation-grid tfoot .pagination .next_page {
49
+ padding: 0.1em 0.5em;
50
+ background-color: #eee;
51
+ border: 1px solid #e5e5e5;
52
+ }
53
+
54
+ .presentation-grid tfoot .pagination a.prev_page:hover,
55
+ .presentation-grid tfoot .pagination a.next_page:hover {
56
+ background-color: #e6f2ff;
57
+ border-color: #c5dbf7;
58
+ }
59
+
60
+ .presentation-grid tfoot .pagination .prev_page {
61
+ margin-right: 0.7em;
62
+ }
63
+
64
+ .presentation-grid tfoot .pagination .next_page {
65
+ margin-left: 0.7em;
66
+ }
67
+
68
+ .presentation-grid tfoot .pagination .current {
69
+ padding: 0.1em 0.5em;
70
+ border: 1px solid #e5e5e5;
71
+ }
@@ -0,0 +1,64 @@
1
+ /** cellspacing **/
2
+ .presentation-grid table,
3
+ .presentation-grid td,
4
+ .presentation-grid th {
5
+ border: 0;
6
+ border-collapse: collapse;
7
+ }
8
+
9
+ .presentation-grid table {
10
+ width: 100%;
11
+ }
12
+
13
+ .presentation-grid caption {
14
+ text-align: left;
15
+ font-weight: bold;
16
+ padding-left: 0.2em;
17
+ }
18
+
19
+ .presentation-grid th {
20
+ padding: 0.2em 0.5em 0em 0.2em;
21
+ text-align: left;
22
+ vertical-align: bottom;
23
+ }
24
+
25
+ .presentation-grid th a {
26
+ text-decoration: none;
27
+ }
28
+
29
+ .presentation-grid td {
30
+ padding: 0.4em 0.5em 0.4em 0.2em;
31
+ vertical-align: top;
32
+ }
33
+
34
+ .presentation-grid ul.actions {
35
+ overflow: auto;
36
+ zoom: 1;
37
+ float: right;
38
+ list-style: none;
39
+ margin: 0;
40
+ padding: 0;
41
+ }
42
+
43
+ .presentation-grid ul.actions li {
44
+ float: left;
45
+ }
46
+
47
+ .presentation-grid ul.actions li a {
48
+ font-weight: normal;
49
+ display: block;
50
+ padding: 0em 0.3em;
51
+ text-decoration: none;
52
+ }
53
+
54
+ .presentation-grid ul.actions li a:hover {
55
+ text-decoration: underline;
56
+ }
57
+
58
+ .presentation-grid ul.actions li a {
59
+ outline: none;
60
+ }
61
+
62
+ .presentation-grid caption ul.actions {
63
+ margin-right: 0.5em;
64
+ }
@@ -0,0 +1,16 @@
1
+ .presentation-search label {
2
+ color: #666;
3
+ }
4
+
5
+ .presentation-search fieldset {
6
+ border: 1px solid #c5dbf7;
7
+ background-color: #e6f2ff;
8
+ padding: 2px;
9
+ }
10
+
11
+ .presentation-search fieldset.submit {
12
+ border: 0px;
13
+ padding: 0px;
14
+ background-color: transparent;
15
+ }
16
+
@@ -0,0 +1,45 @@
1
+ .presentation-search {
2
+ overflow: hidden;
3
+ zoom: 1;
4
+ }
5
+
6
+ .presentation-search fieldset {
7
+ border: 0;
8
+ margin: 0 0.5em 1em 0;
9
+ padding: 0;
10
+ float: left;
11
+ width: 145px;
12
+ }
13
+
14
+ .presentation-search fieldset label {
15
+ font-weight: normal;
16
+ margin: 0;
17
+ padding: 0;
18
+ text-transform: none;
19
+ }
20
+
21
+ .presentation-search fieldset input,
22
+ .presentation-search fieldset select {
23
+ padding: 0px;
24
+ margin: 0px;
25
+ }
26
+
27
+ /* for overlabels (requires javascript) */
28
+
29
+ .presentation-search .compact label {
30
+ display: inline;
31
+ }
32
+
33
+ .presentation-search .compact fieldset {
34
+ position: relative;
35
+ width: auto;
36
+ }
37
+
38
+ .presentation-search .compact fieldset label.overlabel {
39
+ display: block;
40
+ position: absolute;
41
+ top: 0.2em;
42
+ left: 0.5em;
43
+ z-index: 1;
44
+ cursor: text;
45
+ }
@@ -0,0 +1,42 @@
1
+ class Presentation::AssetsController < ActionController::Base
2
+ # TODO: consider packaging a minifier so we get the perfect solution: a cached, minified bundle of assets
3
+ caches_page :stylesheet, :javascript
4
+
5
+ def stylesheet
6
+ dir = asset_path(:stylesheets)
7
+ sheet = params[:id].split(',').collect{ |id| File.read("#{dir}/#{id}.css") }.join("\n")
8
+
9
+ respond_to do |type|
10
+ type.css {render :text => sheet}
11
+ end
12
+ end
13
+
14
+ # TODO: bundle unobtrusive javascripts that can add behavior.
15
+ # - jquery vs prototype (i'll develop jquery, and wait for prototype contributions)
16
+ # - ajax links with html response
17
+ # - - inline
18
+ # - - modal dialog
19
+ # - ajax links with js response
20
+ # - ajax links with no response
21
+ # - inline editing
22
+ # - "dirty" form awareness
23
+ # - tabbed forms
24
+ # - tooltips for extended information (e.g. column description or truncated field text)
25
+ # - basic form validation
26
+ # - - required fields
27
+ # TODO: tests for ujs
28
+ def javascript
29
+ dir = asset_path(:javascript)
30
+ script = params[:id].split(',').collect{ |id| File.read("#{dir}/#{id}.js") }.join("\n")
31
+
32
+ respond_to do |type|
33
+ type.js {render :text => script}
34
+ end
35
+ end
36
+
37
+ protected
38
+
39
+ def asset_path(type)
40
+ File.join(File.dirname(__FILE__), '..', '..', 'assets', type.to_s)
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ <div class="presentation-details">
2
+ <% if @details.title %>
3
+ <h3><%= @details.title %></h3>
4
+ <% end %>
5
+ <dl>
6
+ <% @details.fields.each do |field| %>
7
+ <dt><%= field.name %></dt>
8
+ <dd><%= present(field.value_from(@details.presentable), :h => field.sanitize?) %></dd>
9
+ <% end %>
10
+ </dl>
11
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class="presentation-search">
2
+ <% form_tag @search.url, :method => :get, :class => ("compact" if @search.compact) do %>
3
+ <% @search.fields.each do |field| %>
4
+ <fieldset>
5
+ <label><%= field.name %></label>
6
+ <%= present(field, "#{field.type}_search", :name => "search[#{field.param}][value]") %>
7
+ </fieldset>
8
+ <% end %>
9
+ <fieldset class="submit">
10
+ <input type="submit" value="Search" class="submit" />
11
+ <%= link_to 'reset', @search.url %>
12
+ </fieldset>
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,20 @@
1
+ <% form_for @form.presentable, :url => @form.url, :method => @form.method, :html => @form.html do |f| %>
2
+ <% @form.groups.each do |group| %>
3
+ <fieldset>
4
+ <% unless group.name.blank? %>
5
+ <legend><%= group.name %></legend>
6
+ <% end %>
7
+ <% group.fields.each do |field| %>
8
+ <% if field.type.to_sym == :hidden %>
9
+ <%= f.present(field) %>
10
+ <% else %>
11
+ <div class="field">
12
+ <%= f.label field.name, field.label %>
13
+ <%= f.present(field) %>
14
+ </div>
15
+ <% end %>
16
+ <% end %>
17
+ </fieldset>
18
+ <% end %>
19
+ <%= f.submit @form.button %>
20
+ <% end %>
@@ -0,0 +1,70 @@
1
+ <div id="<%= @grid.id %>" class="presentation-grid">
2
+ <table>
3
+ <% unless @grid.title.blank? and @grid.links.empty? %>
4
+ <caption>
5
+ <% unless @grid.links.empty? %>
6
+ <ul class="actions">
7
+ <% @grid.links.each do |link| %>
8
+ <li><%= link %></li>
9
+ <% end %>
10
+ </ul>
11
+ <% end %>
12
+
13
+ <%= @grid.title %>
14
+ </caption>
15
+ <% end %>
16
+ <thead>
17
+ <tr>
18
+ <% @grid.fields.each do |field| %>
19
+ <th class="<%= field.id %>">
20
+ <% if field.sortable? %>
21
+ <%= link_to field.name, field.sorted_url(request), :class => "sortable" %>
22
+ <% else %>
23
+ <%= field.name %>
24
+ <% end %>
25
+ </th>
26
+ <% end %>
27
+ <% unless @grid.record_links.empty? %>
28
+ <th></th>
29
+ <% end %>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ <% if @grid.presentable.blank? %>
34
+ <tr>
35
+ <td colspan="<%= @grid.colspan %>">
36
+ No records found.
37
+ </td>
38
+ </tr>
39
+ <% else %>
40
+ <% @grid.presentable.each do |record| %>
41
+ <tr class="<%= cycle('odd', 'even') %>">
42
+ <% @grid.fields.each do |field| %>
43
+ <td class="<%= [field.id, ('sorted' if field.is_sorted?(request))].compact.join(' ') %>">
44
+ <%= present(field.value_from(record), :h => field.sanitize?) %>
45
+ </td>
46
+ <% end %>
47
+ <% unless @grid.record_links.empty? %>
48
+ <td>
49
+ <ul class="actions">
50
+ <% @grid.record_links.each do |link| %>
51
+ <li><%= link.call(record) %></li>
52
+ <% end %>
53
+ </ul>
54
+ </td>
55
+ <% end %>
56
+ </tr>
57
+ <% end %>
58
+ <% end %>
59
+ </tbody>
60
+ <% if @grid.paginate? %>
61
+ <tfoot>
62
+ <tr>
63
+ <td colspan="<%= @grid.colspan %>">
64
+ <%= will_paginate @grid.presentable %>
65
+ </td>
66
+ </tr>
67
+ </tfoot>
68
+ <% end %>
69
+ </table>
70
+ </div>
@@ -0,0 +1,7 @@
1
+ <div class="presentation-search">
2
+ <% form_tag @search.url, :method => :get do %>
3
+ <%= text_field_tag 'search', params[:search] %>
4
+ <input type="submit" value="Search" class="submit" />
5
+ <%= link_to 'reset', @search.url %>
6
+ <% end %>
7
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ Presenting.draw_routes(map)
3
+ end
@@ -0,0 +1,48 @@
1
+ module Presentation
2
+ class Base
3
+ include Presenting::Configurable
4
+
5
+ def render
6
+ view.render :partial => "presentations/#{self.class.to_s.split('::').last.underscore}"
7
+ end
8
+
9
+ attr_accessor :presentable
10
+
11
+ ##
12
+ ## begin ActionView compat
13
+ ##
14
+
15
+ attr_accessor :controller # not strictly for compat, but it makes the compat easy
16
+
17
+ def request
18
+ controller.request
19
+ end
20
+
21
+ def url_for(*args)
22
+ controller.url_for(*args)
23
+ end
24
+
25
+ def params
26
+ request.parameters
27
+ end
28
+
29
+ ## end ActionView compat
30
+
31
+ protected
32
+
33
+ # what the presentation is called in its templates
34
+ def iname
35
+ :presentation
36
+ end
37
+
38
+ # a reference to the view
39
+ def view #:nodoc:
40
+ @view ||= Presenting::View.new(ActionController::Base.view_paths, assigns_for_view, self)
41
+ end
42
+
43
+ def assigns_for_view
44
+ {iname => self, :_request => request}
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ module Presentation
2
+ # TODO: abstract what's common between Record and Grid into a shared module or reusable objects or something
3
+ class Details < Grid
4
+ def iname; :details end
5
+
6
+ # The display title for this presentation. Will default based on the id.
7
+ attr_accessor :title
8
+
9
+ def fields=(args)
10
+ args.each do |field|
11
+ self.fields << field
12
+ end
13
+ end
14
+
15
+ def fields
16
+ @fields ||= Presenting::FieldSet.new(Presenting::Attribute, :name, :value)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,65 @@
1
+ module Presentation
2
+ class FieldSearch < Search
3
+ # This method supports the configuration-on-initialization paradigm. It makes:
4
+ # present = Presentation::FieldSearch.new(:fields => [
5
+ # {:a => {:type => :list, :options => %w(foo bar baz)}},
6
+ # :b,
7
+ # {:c => :boolean}
8
+ # ])
9
+ #
10
+ # equivalent to:
11
+ #
12
+ # present = Presentation::FieldSearch.new
13
+ # present.fields << {:a => {:type => :list, :options => %w(foo bar baz)}}
14
+ # present.fields << :b
15
+ # present.fields << {:c => :boolean}
16
+ def fields=(args)
17
+ args.each do |field|
18
+ self.fields << field
19
+ end
20
+ end
21
+
22
+ def fields
23
+ @fields ||= Presenting::FieldSet.new(Field, :param, :type)
24
+ end
25
+
26
+ def compact
27
+ @compact != false
28
+ end
29
+ attr_writer :compact
30
+
31
+ class Field
32
+ include Presenting::Configurable
33
+
34
+ # the display name of the field.
35
+ attr_reader :name
36
+ def name=(val)
37
+ @name = val.is_a?(Symbol) ? val.to_s.titleize : val
38
+ end
39
+
40
+ # the parameter name of the field. note that this is not necessarily the name of a database column or record attribute.
41
+ # it simply needs to be recognized as a "field" by the controller logic.
42
+ attr_reader :param
43
+ def param=(val)
44
+ self.name ||= val
45
+ @param = val.to_s.underscore.downcase.gsub(' ', '_')
46
+ end
47
+
48
+ # the type of search interface for this field. supported options:
49
+ # * :text (default)
50
+ # * :checkbox
51
+ # * :time [planned]
52
+ # * :list [planned]
53
+ def type
54
+ @type ||= :text
55
+ end
56
+ attr_writer :type
57
+
58
+ # extra options for the field.
59
+ def options
60
+ @options ||= {}
61
+ end
62
+ attr_writer :options
63
+ end
64
+ end
65
+ end