lolita 3.2.0.rc.5 → 3.2.0.rc.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/Gemfile +6 -2
  2. data/History.rdoc +12 -4
  3. data/Rakefile +7 -0
  4. data/VERSION +1 -1
  5. data/app/assets/images/lolita/search_icon.png +0 -0
  6. data/app/assets/javascripts/lolita/application.js +1 -1
  7. data/app/assets/javascripts/lolita/tab.js +31 -2
  8. data/app/assets/stylesheets/lolita/application.css +1 -0
  9. data/app/assets/stylesheets/lolita/style.css.erb +49 -3
  10. data/app/controllers/lolita/field_data_controller.rb +14 -2
  11. data/app/controllers/lolita/rest_controller.rb +7 -2
  12. data/app/helpers/lolita_helper.rb +0 -1
  13. data/app/views/components/lolita/configuration/field/array/habtm_autocomplete/_display.html.haml +11 -0
  14. data/app/views/components/lolita/configuration/field/string/disabled/_display.html.erb +1 -1
  15. data/app/views/components/lolita/configuration/list/_paginator.html.erb +1 -1
  16. data/app/views/components/lolita/configuration/list/_title.html.erb +6 -1
  17. data/app/views/components/lolita/configuration/search/_display.html.haml +2 -0
  18. data/app/views/components/lolita/navigation/_tree.html.erb +16 -25
  19. data/app/views/components/lolita/shared/_header.html.erb +1 -1
  20. data/app/views/layouts/lolita/application.html.erb +2 -3
  21. data/config/locales/en.yml +1 -24
  22. data/config/locales/lv.yml +1 -0
  23. data/config/routes.rb +2 -1
  24. data/lib/generators/lolita/install_generator.rb +2 -5
  25. data/lib/generators/templates/lolita.rb +0 -4
  26. data/lib/lolita/adapter/abstract_adapter.rb +1 -0
  27. data/lib/lolita/adapter/active_record.rb +19 -0
  28. data/lib/lolita/adapter/mongoid.rb +60 -0
  29. data/lib/lolita/configuration/list.rb +23 -2
  30. data/lib/lolita/configuration/search.rb +90 -0
  31. data/lib/lolita/controller_additions.rb +15 -0
  32. data/lib/lolita/controllers/authorization_helpers.rb +56 -0
  33. data/lib/lolita/controllers/internal_helpers.rb +2 -2
  34. data/lib/lolita/controllers/user_helpers.rb +23 -11
  35. data/lib/lolita/mapping.rb +12 -0
  36. data/lib/lolita/modules/rest.rb +1 -1
  37. data/lib/lolita/navigation/branch.rb +50 -1
  38. data/lib/lolita/navigation/tree.rb +10 -0
  39. data/lib/lolita/rails/routes.rb +1 -4
  40. data/lib/lolita/rails.rb +0 -2
  41. data/lib/lolita/search/simple.rb +76 -0
  42. data/lib/lolita.rb +24 -19
  43. data/lolita.gemspec +29 -60
  44. data/lolita.gemspec.orig +434 -0
  45. data/spec/configuration/list_spec.rb +19 -14
  46. data/spec/configuration/search_spec.rb +44 -0
  47. data/spec/rails_app/app/mongoid/post.rb +4 -0
  48. data/spec/search/simple_spec.rb +48 -0
  49. data/vendor/assets/javascripts/application_vendor_lolita.js +0 -1
  50. data/vendor/assets/stylesheets/jquery-ui-1.8.16.custom.css +568 -0
  51. metadata +88 -85
  52. data/lib/generators/helpers/file_helper.rb +0 -22
  53. data/lib/lolita/controllers/view_user_helpers.rb +0 -13
data/Gemfile CHANGED
@@ -24,8 +24,12 @@ group :assets do
24
24
  gem 'uglifier'
25
25
  end
26
26
 
27
- gem "jeweler", "~> 1.5.2", :group=>:development
27
+ gem "jeweler", "~> 1.6.4", :group=>:development
28
28
  group :test,:development do
29
+ gem "metric_fu"
30
+ gem "fattr"
31
+ gem "arrayfields"
32
+ gem "map"
29
33
  gem "rspec", "~>2.6.0"
30
34
  gem "rspec-rails","~>2.6.1"
31
35
  gem "factory_girl"
@@ -35,4 +39,4 @@ group :test,:development do
35
39
  # gem "capybara"
36
40
  gem "database_cleaner"
37
41
  # gem "akephalos"
38
- end
42
+ end
data/History.rdoc CHANGED
@@ -1,5 +1,10 @@
1
1
  === Version 3.2.0
2
2
  * Enhancements
3
+ * _only_ options added for <b>lolita_for</b>
4
+ * New options _visible_ added to Lolita::Mapping, now is possible to exclude resource from navigation tree
5
+ * Search functionality added, included in List
6
+ * All modules that need to be included by Lolita controllers is added in one Lolita::ControllerAddition
7
+ * Basic authorization added, now with CanCan.
3
8
  * Created adapter Field and Association classes. Field and association access methods convert data to thoes class objects
4
9
  * Factory module created where factory classes are located
5
10
  * Removed specific pagination methods from adapters
@@ -10,17 +15,20 @@
10
15
  * Polymorphic association field
11
16
 
12
17
  * Changes
13
- * using rails 3.1.x
18
+ * noew using rails 3.1.x
14
19
  * #value, #value=, #record_value removed from Lolita::Configuration::Field
15
20
  * Created pagination in list and in adapters; its possible to customize it for model.
16
21
  * All fields must have name as well as tabs must have type
22
+
23
+ * Removed
24
+ * Lolita::FileHelper from generators removed
17
25
 
18
26
  * Bug fixes
19
27
  * Each hook call runs as new instance of Hooks::Runner
20
28
  * All classes fixed to work with both mongoid and AR
21
-
22
-
23
- === Version 3.1.18 /
29
+ * String disabled builder fixed to use form object
30
+
31
+ === Version 3.1.18
24
32
  * Enhancements
25
33
  *
26
34
  * Bug fixes
data/Rakefile CHANGED
@@ -38,3 +38,10 @@ Rake::RDocTask.new do |rdoc|
38
38
  rdoc.rdoc_files.include('README*')
39
39
  rdoc.rdoc_files.include('lib/**/*.rb')
40
40
  end
41
+
42
+ require 'metric_fu'
43
+ MetricFu::Configuration.run do |config|
44
+ config.rcov[:test_files] = ['spec/**/*_spec.rb']
45
+ config.rcov[:rcov_opts] << "-Ispec" # Needed to find spec_helper
46
+ config.metrics -= [:flog]
47
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.rc.5
1
+ 3.2.0.rc.6
@@ -1,4 +1,4 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
3
  //= require application_vendor_lolita
4
- //= require_tree .
4
+ //= require_tree .
@@ -1,3 +1,5 @@
1
+ //= require jquery
2
+ //= require jquery-ui-1.8.13.min
1
3
  $(function(){
2
4
  // Send ajax request with all forms data for given tabs block.
3
5
  function save_tab(tabs){
@@ -42,9 +44,9 @@ $(function(){
42
44
  }
43
45
  else {
44
46
  // Ensure that it is a number and stop the keypress
45
- if (event.keyCode < 48 || event.keyCode > 57 ) {
47
+ if (!((event.keyCode >= 48 && event.keyCode <= 57) || (event.keyCode >= 96 && event.keyCode <= 105))) {
46
48
  event.preventDefault();
47
- }
49
+ }
48
50
  }
49
51
  })
50
52
 
@@ -75,4 +77,31 @@ $(function(){
75
77
  })
76
78
  })
77
79
 
80
+ $("input[data-autocomplete-url]").live("keyup.autocomplete", function(){
81
+ $(this).autocomplete({
82
+ source: function(request, response){
83
+ $.getJSON(this.element.data("autocomplete-url"), {
84
+ term: request.term
85
+ }, response)
86
+ },
87
+ focus: function(){
88
+ return false;
89
+ },
90
+ select: function(event, ui){
91
+ console.log(ui.item.value);
92
+ var li = $("<li></li>").appendTo($(this).closest(".autocomplete-container").find("ul"));
93
+ li.text(ui.item.value);
94
+ $("<a href=''></a>").text(ui.item.delete_link).appendTo(li);
95
+ $("<input type='hidden'>").attr("name", ui.item.name).val(ui.item.id).appendTo(li);
96
+ this.value = "";
97
+ return false;
98
+ }
99
+ });
100
+ });
101
+
102
+ $(".autocomplete-container ul li a").live("click", function(){
103
+ $(this).closest("li").remove();
104
+ return false;
105
+ })
106
+
78
107
  })
@@ -1,5 +1,6 @@
1
1
  /*
2
2
  *= require_self
3
+ *= require jquery-ui-1.8.16.custom
3
4
  *= require lolita/default
4
5
  *= require lolita/style
5
6
  */
@@ -4,8 +4,12 @@ html,body{
4
4
  body {background: #f3f3f3; font-size: 13px;}
5
5
 
6
6
  a, a:visited, a:active {color: #7ac1ed; text-decoration: none;}
7
- input[type="button"] {vertical-align: top; padding: 3px 9px;}
8
7
  h1 {font-size: 28px; font-weight: normal; letter-spacing: -1px; line-height: 85px;}
8
+ input[type="button"] {vertical-align: top; padding: 3px 9px;}
9
+ .placeholder {color: #aaa;}
10
+ ::placeholder {color: #aaa;}
11
+ :-moz-placeholder {color: #aaa;}
12
+ ::-webkit-input-placeholder {color: #aaa;}
9
13
 
10
14
  #container {
11
15
  width: 90%;
@@ -109,6 +113,23 @@ header nav .username {margin-right: 15px;}
109
113
 
110
114
  /* -------------------------------- */
111
115
 
116
+ /* autocomplete field*/
117
+
118
+ .autocomplete-container ul {
119
+ margin-left: 30px;
120
+ }
121
+ .autocomplete-container ul li {
122
+ list-style-type: none;
123
+ margin: 5px 0;
124
+ padding-bottom: 5px;
125
+ border-bottom: 1px dashed #DDD;
126
+ }
127
+ .ui-menu .ui-menu-item a {
128
+ font-size: 10px;
129
+ }
130
+
131
+ /* -------------------------------- */
132
+
112
133
  /* error fields and notifications */
113
134
 
114
135
  #main .box form .field_with_errors input,
@@ -315,7 +336,31 @@ a.create {
315
336
 
316
337
  .list table td a:active {position: relative; top: 1px;}
317
338
 
318
- /* filter */
339
+ /* search in list view */
340
+
341
+ #main .boxtitle .black .search {
342
+ position: absolute;
343
+ right: 15px;
344
+ top: 25px;
345
+ background: none;
346
+ padding: 0;
347
+ }
348
+ #main .boxtitle .black .search input {
349
+ font-size: 13px;
350
+ background: #fff url(<%= asset_data_uri "lolita/search_icon.png" %>) no-repeat 5px center;
351
+ padding: 0 10px 0 18px;
352
+ border: 1px solid #ccc;
353
+ border-radius: 10px;
354
+ -moz-border-radius: 10px;
355
+ -webkit-border-radius: 10px;
356
+ height: 20px;
357
+ line-height: 20px\9;
358
+ }
359
+
360
+ /* -------------------------------------------------------------------------------- */
361
+
362
+ /* filter in list view */
363
+
319
364
  #main form.filter {
320
365
  background: #F3F3F3;
321
366
  padding: 10px;
@@ -331,6 +376,7 @@ a.create {
331
376
  #main form.filter label {
332
377
  color: #666;
333
378
  }
379
+
334
380
  /* --------------------------------------------- */
335
381
 
336
382
  /* Pagination */
@@ -440,4 +486,4 @@ a.create {
440
486
  {position: relative;}
441
487
  .ie8 .black {-pie-background: linear-gradient(top, #686868, #2f2f2f);}
442
488
  .ie8 #flash {-pie-background: rgba(255,255,255,0.9);}
443
- /* ----------------------------------------------*/
489
+ /* ----------------------------------------------*/
@@ -2,7 +2,7 @@ class Lolita::FieldDataController < ApplicationController
2
2
  include Lolita::Controllers::UserHelpers
3
3
 
4
4
  before_filter :authenticate_lolita_user!
5
- before_filter :find_field
5
+ before_filter :find_field, :except => [:autocomplete_field]
6
6
 
7
7
  def array_polymorphic
8
8
  klass = params[:class].camelize.constantize
@@ -17,4 +17,16 @@ class Lolita::FieldDataController < ApplicationController
17
17
  field.name.to_s == params[:name].to_s
18
18
  }
19
19
  end
20
- end
20
+
21
+ def autocomplete_field
22
+ model = params[:class].singularize.camelize.constantize
23
+ column = model.lolita.tabs.first.fields.first.name.to_sym
24
+ data = model.where(model.arel_table[column].matches("%#{params[:term]}%")).map do |record|
25
+ {:id => record.id,
26
+ :value => record.send(column),
27
+ :name => "#{params[:field_class].downcase}[#{params[:class].singularize}_ids][]",
28
+ :delete_link => I18n.t("lolita.shared.delete")}
29
+ end
30
+ render :json => data
31
+ end
32
+ end
@@ -1,6 +1,5 @@
1
1
  class Lolita::RestController < ApplicationController
2
- include Lolita::Controllers::UserHelpers
3
- include Lolita::Controllers::InternalHelpers
2
+ include Lolita::ControllerAdditions
4
3
 
5
4
  include Lolita::Hooks
6
5
  add_hook :before_new, :after_new, :before_create,:after_create,:before_edit,:after_edit
@@ -12,12 +11,14 @@ class Lolita::RestController < ApplicationController
12
11
 
13
12
  def new
14
13
  self.run(:before_new)
14
+ authorize!(:create,self.resource_class)
15
15
  build_resource
16
16
  show_form
17
17
  end
18
18
 
19
19
  def create
20
20
  self.run(:before_create)
21
+ authorize!(:create,self.resource_class)
21
22
  build_resource
22
23
  save_and_redirect
23
24
  end
@@ -25,12 +26,14 @@ class Lolita::RestController < ApplicationController
25
26
  def edit
26
27
  self.run(:before_edit)
27
28
  get_resource
29
+ authorize!(:update,self.resource)
28
30
  show_form
29
31
  end
30
32
 
31
33
  def update
32
34
  self.run(:before_update)
33
35
  get_resource
36
+ authorize!(:update,self.resource)
34
37
  if self.resource
35
38
  self.resource=resource_with_attributes(self.resource,resource_attributes)
36
39
  save_and_redirect
@@ -41,6 +44,7 @@ class Lolita::RestController < ApplicationController
41
44
  def destroy
42
45
  self.run(:before_destroy)
43
46
  get_resource
47
+ authorize!(:destroy, self.resource)
44
48
  if self.resource && self.resource.destroy
45
49
  flash[:notice] = ::I18n.t "lolita.shared.destroy_notice"
46
50
  else
@@ -52,6 +56,7 @@ class Lolita::RestController < ApplicationController
52
56
 
53
57
  def index
54
58
  self.run(:before_index)
59
+ authorize!(:read,self.resource_class)
55
60
  respond_to do |format|
56
61
  format.html do
57
62
  build_response_for(:list,:page=>page)
@@ -1,5 +1,4 @@
1
1
  module LolitaHelper
2
-
3
2
  # Classes for div block that is located to the right of menu
4
3
  # This is helpful because different positionings within it exist depending on action
5
4
  def content_classes
@@ -0,0 +1,11 @@
1
+ - ids_method = field.name.to_s.match(/_ids$/) ? field.name : "#{field.name.to_s.singularize}_ids"
2
+
3
+ .autocomplete-container
4
+ = hidden_field_tag "#{resource_name}[#{ids_method}][]",""
5
+ = text_field_tag :"autocomplete-#{resource_name}", nil, :"data-autocomplete-url" => autocomplete_field_path(:field_class => tab_form.object.class.to_s, :class => field.name)
6
+ %ul
7
+ - resource.persisted? && resource.send(field.name).each do |element|
8
+ %li
9
+ = element.send(element.class.lolita.tabs.first.fields.first.name.to_sym)
10
+ = link_to I18n.t("lolita.shared.delete").downcase, nil
11
+ = hidden_field_tag "#{resource_name}[#{ids_method}][]", element.id
@@ -1 +1 @@
1
- <div class="disabled-field"><%= raw(resource.send(field.name)) %></div>
1
+ <div class="disabled-field"><%= raw(tab_form.object.send(field.name)) %></div>
@@ -1 +1 @@
1
- <%= paginate page, :theme => "lolita" %>
1
+ <%= paginate page, :theme => "lolita", :params => params %>
@@ -1,5 +1,10 @@
1
1
  <div class="boxtitle">
2
- <h1 class="black"><%= resource_class.model_name.human(:count=>2) %></h1>
2
+ <h1 class="black">
3
+ <%= resource_class.model_name.human(:count=>2) %>
4
+ <% if list.search %>
5
+ <%= render_component list.search, :display %>
6
+ <% end %>
7
+ </h1>
3
8
  <div class="arrow">
4
9
  </div>
5
10
  </div>
@@ -0,0 +1,2 @@
1
+ = form_tag lolita_resources_path(), :method => :get, :class => "search" do
2
+ %input{:type => "text", :name => "q", :value => params[:q], :placeholder => t("lolita.search")}
@@ -11,29 +11,20 @@
11
11
  end
12
12
  end
13
13
  end %>
14
- <ul <%=!tree.root? ? "class='subtree'" : ""%> >
15
- <% last_branch=tree.branches.last %>
16
- <%tree.branches.each do |branch|
17
- if branch.object.is_a?(Lolita::Mapping)
18
- active=if self.respond_to?(:resource_class)
19
- branch.object ? branch.object.to==resource_class : false
20
- end
21
- end
22
- unless active
23
- active=branch.self_with_children.detect{|b|
24
- if b.options[:active].respond_to?(:call)
25
- b.options[:active].call(self,branch,b)
26
- else
27
- b.options[:url]==request.path
28
- end
29
- }
30
- end
31
- %>
32
- <li class="<%=active ? "active" : ""%> <%=branch.children.branches.any? ? "with-subtree" : ""%> <%=!tree.root? && branch==last_branch ? "last-in-subtree" : ""%>">
33
- <%= link_to branch.title, branch.options[:url] || "#" %>
34
- <% if branch.children.branches.any? %>
35
- <%= render_component(:"lolita/navigation",:tree,:tree=>branch.children) %>
14
+ <% visible ||= (tree.root? || nil) %>
15
+ <% if tree.visible?(self) %>
16
+ <ul <%= !tree.root? ? "class='subtree'" : ""%> style="display:<%=visible ? "block" : "none"%>" >
17
+ <% last_branch=tree.branches.last %>
18
+ <%tree.branches.each do |branch|
19
+ if branch.visible?(self)
20
+ active = branch.active?(self) %>
21
+ <li class="<%=active ? "active" : ""%> <%=branch.subtree? ? "with-subtree" : ""%> <%=!tree.root? && branch==last_branch ? "last-in-subtree" : ""%>">
22
+ <%= link_to branch.title, branch.options[:url] || "#", :onclick => branch.subtree? ? "$(this).next().toggle();return false;" : "" %>
23
+ <% if branch.subtree? %>
24
+ <%= render_component(:"lolita/navigation",:tree,:tree=>branch.children, :visible => active) %>
25
+ <% end %>
26
+ </li>
36
27
  <% end %>
37
- </li>
38
- <% end %>
39
- </ul>
28
+ <% end %>
29
+ </ul>
30
+ <% end %>
@@ -3,7 +3,7 @@
3
3
  <% if lolita_current_user %>
4
4
  <nav>
5
5
  <a href="<%=send(:"edit_#{lolita_current_user.class.to_s.downcase}_password_path")%>" class="username"><%=lolita_current_user.email%></a>
6
- <a href="<%=send(:"destroy_#{lolita_current_user.class.to_s.downcase}_session_path")%>" class="button grey"><%=::I18n.t("lolita.shared.log_out")%></a>
6
+ <%= link_to ::I18n.t("lolita.shared.log_out"), send(:"destroy_#{lolita_current_user.class.to_s.downcase}_session_path"), :class => "button grey", :method => Devise.sign_out_via %>
7
7
  </nav>
8
8
  <% end %>
9
9
  </header>
@@ -9,9 +9,8 @@
9
9
  <head>
10
10
  <meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
11
11
 
12
- <title>Lolita</title><meta name="description" content=""><meta name="author" content="">
13
- <link rel="shortcut icon" href="/lolita/favicon.ico">
14
-
12
+ <title><%=Lolita.application.name%></title><meta name="description" content=""><meta name="author" content="">
13
+ <%= favicon_link_tag "lolita/favicon.ico"%>
15
14
  <%= stylesheet_link_tag "lolita/application.css" %>
16
15
  <%= yield :style %>
17
16
  <%= javascript_include_tag "lolita/application.js" %>
@@ -23,30 +23,7 @@ en:
23
23
  filter:
24
24
  apply_button: Apply
25
25
  include_blank_by_title: " -- Filter by %{title} -- "
26
- lolita:
27
- shared:
28
- save_notice: Successfully saved.
29
- save_alert: Save did not succeed.
30
- log_out: Sign out
31
- edit: Edit
32
- delete: Delete
33
- and: and
34
- powered: Powered Lolita (2010-%{year})
35
- nested_form:
36
- add: "Add %{resource_name}"
37
- tabs:
38
- last_save: Last save
39
- save: Save
40
- save_all: Save all
41
- titles:
42
- default: "Default"
43
- content: "Content"
44
- list:
45
- add_new: Add new %{name}
46
- confirm: "Are you sure you want to delete record?"
47
- filter:
48
- apply_button: Apply
49
- include_blank_by_title: " -- Filter by %{title} -- "
26
+ search: "Search"
50
27
  views:
51
28
  pagination:
52
29
  previous: "&laquo; Previous"
@@ -23,6 +23,7 @@ lv:
23
23
  filter:
24
24
  apply_button: Pielietot
25
25
  include_blank_by_title: " -- Filtrēt pēc %{title} -- "
26
+ search: "Meklēt"
26
27
  views:
27
28
  pagination:
28
29
  previous: "&laquo; Iepriekšējā"
data/config/routes.rb CHANGED
@@ -2,4 +2,5 @@ Rails.application.routes.draw do
2
2
  match '/lolita' => "lolita/info#index"
3
3
  match '/lolita/info/properties' => "lolita/info#properties"
4
4
  match "/lolita/array_field/:name/:field_class/:class/:id" => "lolita/field_data#array_polymorphic", :as => "array_field_data_collector"
5
- end
5
+ match "/lolita/autocomplete_field/:field_class/:class" => "lolita/field_data#autocomplete_field", :as => "autocomplete_field"
6
+ end
@@ -1,21 +1,18 @@
1
- require 'generators/helpers/file_helper'
2
-
3
1
  module Lolita
4
2
  module Generators
5
3
  class InstallGenerator < Rails::Generators::Base
6
- include Lolita::Generators::FileHelper
7
4
  source_root File.expand_path("../../templates", __FILE__)
8
5
  desc "Create lolita initializer."
9
6
 
10
7
 
11
8
  def copy_initializer
12
- template "lolita.rb", "config/initializers/lolita.rb" unless file_exists?("config/initializers/lolita.rb")
9
+ template "lolita.rb", "config/initializers/lolita.rb" unless File.exist?(Rails.root + "config/initializers/lolita.rb")
13
10
  end
14
11
 
15
12
  def install_modules
16
13
  Lolita.modules.each do |module_name|
17
14
 
18
- invoke "#{module_name.to_s.underscore.gsub("/","_")}:install" rescue nil
15
+ invoke "lolita:#{module_name.to_s.underscore.gsub("/","_").gsub(/^lolita_/,"")}:install" rescue nil
19
16
  end
20
17
  end
21
18
 
@@ -8,10 +8,6 @@ Lolita.setup do |config|
8
8
  # Define authentication for Lolita controllers.
9
9
  # Call some of your own methods
10
10
  # config.authentication=:is_admin?
11
- # Or use some customized logic
12
- # config.authentication={
13
- # current_user.is_a?(Admin) || current_user.has_role?(:admin)
14
- # }
15
11
 
16
12
  <% if defined?(Devise) %>
17
13
  <% default_user_class = Devise.mappings.keys.first %>
@@ -8,6 +8,7 @@ module Lolita
8
8
  abstract_method 'method_name,page,per,options', :pagination_scope_from_klass
9
9
  abstract_method 'name',:reflect_on_association,:field_by_name,:field_by_association
10
10
  abstract_method 'id',:find_by_id
11
+ abstract_method 'query', :search
11
12
  end
12
13
  end
13
14
  end
@@ -200,6 +200,25 @@ module Lolita
200
200
  end
201
201
  end
202
202
 
203
+ def search(query, options = {})
204
+ #TODO raise error or warn when there are lot of records and no index on field
205
+ resources = self.klass.arel_table
206
+ content_fields = @dbi.fields.map{|field| field.type!="string" ? nil : field.name.to_sym}.compact
207
+ if options[:fields] && options[:fields].any?
208
+ content_fields = content_fields & options[:fields]
209
+ end
210
+ scope = nil
211
+ content_fields.each_with_index do |field,index|
212
+ new_scope = resources[field].matches("%#{query}%")
213
+ unless index == 0
214
+ scope = scope.or(new_scope)
215
+ else
216
+ scope = new_scope
217
+ end
218
+ end
219
+ self.klass.where(scope)
220
+ end
221
+
203
222
  def db
204
223
  self.klass.connection
205
224
  end
@@ -184,6 +184,66 @@ module Lolita
184
184
  end
185
185
  end
186
186
 
187
+ def search(query, options = {})
188
+ content_fields = @dbi.fields.map{|field|
189
+ if field.type!="string" || field.name.match(/^_/)
190
+ nil
191
+ else
192
+ field.name.to_sym
193
+ end
194
+ }.compact
195
+ if options[:fields] && options[:fields].any?
196
+ content_fields = content_fields & options[:fields]
197
+ end
198
+ content_fields = content_fields.slice(0..3)
199
+ #result = self.map_reduce_search(content_fields,query)
200
+ #debugger
201
+ #result
202
+ where_hash = {}
203
+ content_fields.each do |field|
204
+ where_hash[field] = /#{Regexp.escape(query.to_s)}/
205
+ end
206
+ klass.where(where_hash)
207
+ end
208
+
209
+ #FIXME
210
+ def map_reduce_search(content_fields,query)
211
+ keys = "[" + @dbi.fields.map{|f|
212
+ f.primary? || f.name.to_s.match(/^_/) ? nil : "'#{f.name}'"
213
+ }.compact.join(",").to_s + "]"
214
+ content_keys = "[" + content_fields.map{|f| "'#{f.name}'"}.join(",").to_s + "]"
215
+ result_obj = @dbi.fields.map{|f|
216
+ f.name.to_s.match(/^_/) ? nil : "'#{f.name}': false"
217
+ }.compact.join(",")
218
+ result_obj = "{#{result_obj}}"
219
+ map = %^
220
+ function(){
221
+ var doc = #{result_obj};
222
+ var do_emit = false;
223
+ for(var k in #{content_keys}){
224
+ var c_val = this[k];
225
+ if(c_val && c_val.match(/#{Regexp.escape(query)}/i)){
226
+ do_emit = true;
227
+ break;
228
+ };
229
+ };
230
+ if(true){
231
+ #{keys}.forEach(function(k){
232
+ doc[k] = this.name;
233
+ })
234
+ emit(this.id,doc);
235
+ };
236
+ };
237
+ ^
238
+ reduce = %^
239
+ function(key,values){
240
+
241
+ return values[values.length-1];
242
+ };
243
+ ^
244
+ self.collection.map_reduce(map,reduce, {:out => "custom_mr", :query => {}})
245
+ end
246
+
187
247
  def db
188
248
  self.klass.db
189
249
  end
@@ -18,6 +18,20 @@ module Lolita
18
18
  set_default_attributes
19
19
  end
20
20
 
21
+ # For details see Lolita::Configuration::Search
22
+ def search *args, &block
23
+ if (args && args.any?) || block_given?
24
+ @search = Lolita::Configuration::Search.new(self.dbi,*args,&block)
25
+ end
26
+ @search
27
+ end
28
+
29
+ # Define or return pagination method. This method is used by DBI adapters to delegate domain specific
30
+ # pagination back to model.
31
+ # ====Example
32
+ # list do
33
+ # pagination_method :paginate_with_profiles
34
+ # end
21
35
  def pagination_method(value = nil)
22
36
  if value
23
37
  self.pagination_method = value
@@ -29,8 +43,15 @@ module Lolita
29
43
  @pagination_method = value
30
44
  end
31
45
 
32
- def paginate(current_page, request)
33
- dbi.paginate(current_page,@per,:request => request, :pagination_method => @pagination_method)
46
+ # Return page for list display. Method requires two arguments:
47
+ # * <tt>current_page</tt> - number of current page
48
+ # * <tt>request (optional) </tt> - request that is passed to adapter that passes this to model when #pagination_method is defined
49
+ def paginate(current_page, request = nil)
50
+ page_criteria = dbi.paginate(current_page,@per,:request => request, :pagination_method => @pagination_method)
51
+ if self.search
52
+ page_criteria = page_criteria.merge(self.search.run(request.params[:q],request))
53
+ end
54
+ page_criteria
34
55
  end
35
56
 
36
57
  # Set columns. Allowed classes are Lolita::Configuration::Columns or