cullender 0.0.1

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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/javascripts/cullender/application.js +13 -0
  6. data/app/assets/javascripts/cullender/rules.js +46 -0
  7. data/app/assets/stylesheets/cullender/application.css +13 -0
  8. data/app/assets/stylesheets/cullender/rules.css.scss +15 -0
  9. data/app/controllers/cullender/rules_controller.rb +68 -0
  10. data/app/controllers/cullender_controller.rb +105 -0
  11. data/app/helpers/cullender/rules_helper.rb +136 -0
  12. data/app/models/cullender/rule.rb +204 -0
  13. data/app/views/cullender/rules/_form.html.erb +20 -0
  14. data/app/views/cullender/rules/_trigger_fields.html.erb +19 -0
  15. data/app/views/cullender/rules/create.js.erb +3 -0
  16. data/app/views/cullender/rules/index.html.erb +25 -0
  17. data/app/views/cullender/rules/new.html.erb +1 -0
  18. data/app/views/cullender/rules/show.html.erb +3 -0
  19. data/config/locales/en.yml +12 -0
  20. data/config/routes.rb +4 -0
  21. data/lib/cullender.rb +96 -0
  22. data/lib/cullender/controllers/filter_logic.rb +89 -0
  23. data/lib/cullender/controllers/scoped_views.rb +17 -0
  24. data/lib/cullender/core_ext/hash.rb +1 -0
  25. data/lib/cullender/core_ext/hash/deep_delete.rb +13 -0
  26. data/lib/cullender/engine.rb +15 -0
  27. data/lib/cullender/engine/routes.rb +306 -0
  28. data/lib/cullender/mapping.rb +139 -0
  29. data/lib/cullender/version.rb +3 -0
  30. data/lib/generators/cullender/cullender_generator.rb +66 -0
  31. data/lib/generators/cullender/install_generator.rb +18 -0
  32. data/lib/generators/cullender/orm_helpers.rb +32 -0
  33. data/lib/generators/cullender/templates/cullender.rb +3 -0
  34. data/lib/generators/cullender/templates/cullender_migration.rb +13 -0
  35. data/lib/tasks/cullender_tasks.rake +4 -0
  36. data/spec/controllers/cullender/rules_controller_spec.rb +180 -0
  37. data/spec/cullender/controllers/filter_logic_spec.rb +233 -0
  38. data/spec/dummy/README.rdoc +28 -0
  39. data/spec/dummy/Rakefile +6 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +17 -0
  41. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  42. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  43. data/spec/dummy/app/controllers/events_controller.rb +60 -0
  44. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy/app/models/event.rb +16 -0
  46. data/spec/dummy/app/views/cullender/rules/_form.html.erb +33 -0
  47. data/spec/dummy/app/views/cullender/rules/index.html.erb +24 -0
  48. data/spec/dummy/app/views/cullender/rules/new.html.erb +1 -0
  49. data/spec/dummy/app/views/cullender/rules/show.html.erb +3 -0
  50. data/spec/dummy/app/views/events/_form.html.erb +21 -0
  51. data/spec/dummy/app/views/events/edit.html.erb +6 -0
  52. data/spec/dummy/app/views/events/index.html.erb +27 -0
  53. data/spec/dummy/app/views/events/new.html.erb +5 -0
  54. data/spec/dummy/app/views/events/show.html.erb +10 -0
  55. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  56. data/spec/dummy/bin/bundle +3 -0
  57. data/spec/dummy/bin/rails +4 -0
  58. data/spec/dummy/bin/rake +4 -0
  59. data/spec/dummy/config.ru +4 -0
  60. data/spec/dummy/config/application.rb +23 -0
  61. data/spec/dummy/config/boot.rb +9 -0
  62. data/spec/dummy/config/database.yml +25 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +27 -0
  65. data/spec/dummy/config/environments/production.rb +80 -0
  66. data/spec/dummy/config/environments/test.rb +36 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/cullender.rb +3 -0
  69. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  70. data/spec/dummy/config/initializers/inflections.rb +16 -0
  71. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  72. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  73. data/spec/dummy/config/initializers/session_store.rb +3 -0
  74. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  75. data/spec/dummy/config/locales/cullender.en.yml +12 -0
  76. data/spec/dummy/config/locales/en.yml +23 -0
  77. data/spec/dummy/config/routes.rb +5 -0
  78. data/spec/dummy/db/development.sqlite3 +0 -0
  79. data/spec/dummy/db/migrate/123344556676_create_cullender_tables.rb +12 -0
  80. data/spec/dummy/db/schema.rb +24 -0
  81. data/spec/dummy/db/test.sqlite3 +0 -0
  82. data/spec/dummy/log/development.log +9987 -0
  83. data/spec/dummy/log/test.log +19786 -0
  84. data/spec/dummy/public/404.html +27 -0
  85. data/spec/dummy/public/422.html +26 -0
  86. data/spec/dummy/public/500.html +26 -0
  87. data/spec/dummy/public/favicon.ico +0 -0
  88. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  89. data/spec/dummy/tmp/cache/assets/development/sprockets/268a828ee4997cf5c19106e5f00fcfb8 +0 -0
  90. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  91. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  92. data/spec/dummy/tmp/cache/assets/development/sprockets/56b2eb9b46b9aca7e86b5132ddf0d9de +0 -0
  93. data/spec/dummy/tmp/cache/assets/development/sprockets/750887406b3e8dacb2b03f986330932d +0 -0
  94. data/spec/dummy/tmp/cache/assets/development/sprockets/750b42e431d194c41f5b1cde4a257e47 +0 -0
  95. data/spec/dummy/tmp/cache/assets/development/sprockets/921642fe740290e9e5e88a706e5a562c +0 -0
  96. data/spec/dummy/tmp/cache/assets/development/sprockets/a967ed3fc5f8406f3ff72180775f1b40 +0 -0
  97. data/spec/dummy/tmp/cache/assets/development/sprockets/ae74bf4fc3fd20e7f7b98860b8ef0f74 +0 -0
  98. data/spec/dummy/tmp/cache/assets/development/sprockets/c7dbd1f5acc2d5bc078363f4f3c70c54 +0 -0
  99. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  100. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  101. data/spec/dummy/tmp/cache/assets/development/sprockets/d995daf8d6f36c27b6e9d1b4672eaf1e +0 -0
  102. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  103. data/spec/helpers/cullender/rules_helper_spec.rb +360 -0
  104. data/spec/models/cullender/rule_spec.rb +425 -0
  105. data/spec/requests/rules_spec.rb +19 -0
  106. data/spec/spec_helper.rb +60 -0
  107. metadata +319 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 84cd07f131f0613540f841cfd74fd0d99080ecf5
4
+ data.tar.gz: b6c36dd6ba6f2bf5d51a5682c1f0a2ff2b263760
5
+ SHA512:
6
+ metadata.gz: 60085f0fc2e0fc7bd4400f4928c14b861b5dde3b3beb38d26c39c3e8900aa4de1a3fbf53a439798376142b4692322429e2d432c9e8641aa62a0aef07d9f1bf48
7
+ data.tar.gz: be7c775c08cf93465cf4fa2cd8f43618bd6030d670a0acf14b005331b4c76d7abadf210f8b6a9bc24c5080985d6a7acef97d48326d1047cf3a9e3c76876db764
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
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.
@@ -0,0 +1,3 @@
1
+ = Cullender
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Cullender'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'spec'
29
+ t.pattern = 'spec/**/*_spec.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,46 @@
1
+ // # Place all the behaviors and hooks related to the matching controller here.
2
+ // # All this logic will automatically be available in application.js.
3
+ // # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
4
+ // # check if there are any rules that have already been applied
5
+ // # if rules have been defined then check if the user is ok if we remove remove them from the form
6
+ //
7
+ // jQuery ->
8
+ // columns = $('#or_raise_field').html()
9
+ // table = $('#rule_table_id :selected').text()
10
+ // escaped_table = table.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
11
+ // options = $(columns).filter("optgroup[label=#{escaped_table}]").html()
12
+ // $('#triggers').hide() unless options
13
+ // $('#rule_table_id').change ->
14
+ // table = $('#rule_table_id :selected').text()
15
+ // escaped_table = table.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
16
+ // options = $(columns).filter("optgroup[label=#{escaped_table}]").html()
17
+ // if options
18
+ // $('.column_select_field').html(options)
19
+ // $('#triggers').show()
20
+ // else
21
+ // $('.column_select_field').empty()
22
+ // $('#triggers').hide()
23
+
24
+
25
+ // jQuery(function() {
26
+ // var columns;
27
+ // columns = $('#or_raise_field').html();
28
+ // populate_rule_column_options();
29
+ // $('#rule_table_id').change(populate_rule_column_options);
30
+
31
+ // function populate_rule_column_options(){
32
+ // var escaped_table, options, table;
33
+ // table = $('#rule_table_id :selected').text();
34
+ // escaped_table = table.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
35
+ // options = $(columns).filter("optgroup[label=" + escaped_table + "]").html();
36
+ // if (options) {
37
+ // $('.column_select_field').html(options);
38
+ // return $('#triggers').show();
39
+ // } else {
40
+ // $('.column_select_field').empty();
41
+ // return $('#triggers').hide();
42
+ // }
43
+ // }
44
+ // });
45
+
46
+ // TODO javascript without rails ujs
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,15 @@
1
+ // Place all the styles related to the rules controller here.
2
+ // They will automatically be included in application.css.
3
+ // You can use Sass (SCSS) here: http://sass-lang.com/
4
+ #rules {
5
+ table{
6
+ td{
7
+ vertical-align:middle;
8
+ }
9
+ .action{
10
+ i{
11
+ margin-right:5px;
12
+ }
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,68 @@
1
+ module Cullender
2
+ class RulesController < CullenderController
3
+ before_action :set_rule, only: [:show, :edit, :update, :destroy]
4
+ include Controllers::FilterLogic
5
+
6
+ # TODO should route without resource. ie not event/rules just /rules
7
+ # GET /rules
8
+ def index
9
+ @rules = Cullender::Rule.all
10
+ end
11
+
12
+ # GET /rules/1
13
+ def show
14
+ params.deep_merge!({"rule" => {"triggers" => @rule.triggers}})
15
+ end
16
+
17
+ # GET /rules/new
18
+ def new
19
+ @rule = Cullender::Rule.new(name: params[:name])
20
+ end
21
+
22
+ # POST /rules
23
+ def create
24
+ flag = apply_filter_actions("triggers", params[:rule], params)
25
+ @rule = Cullender::Rule.new(rule_params)
26
+ respond_to do |format|
27
+ if flag
28
+ format.html {redirect_to send("new_#{resource_name}_rule_url".to_sym,params[:rule])}
29
+ format.js { render "create"}
30
+ else
31
+ if @rule.save
32
+ format.html {redirect_to send("#{resource_name}_rules_url".to_sym), notice: 'Rule was successfully created.'}
33
+ format.js {redirect_to send("#{resource_name}_rules_url".to_sym), notice: 'Rule was successfully created.'}
34
+ else
35
+ format.html {render action: 'new'}
36
+ format.js {render action: 'new'}
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # PATCH/PUT /rules/1
43
+ def update
44
+ if !apply_filter_actions("triggers", params[:rule], params) && @rule.update_attributes(rule_params)
45
+ redirect_to send("#{resource_name}_rules_url".to_sym), notice: 'Rule was successfully updated.'
46
+ else
47
+ render action: 'show'
48
+ end
49
+ end
50
+
51
+ # DELETE /rules/1
52
+ def destroy
53
+ @rule.destroy
54
+ redirect_to send("#{resource_name}_rules_url".to_sym), notice: 'Rule was successfully destroyed.'
55
+ end
56
+
57
+ private
58
+ # Use callbacks to share common setup or constraints between actions.
59
+ def set_rule
60
+ @rule = Cullender::Rule.find(params[:id])
61
+ end
62
+
63
+ # Never trust parameters from the scary internet, only allow the white list through.
64
+ def rule_params
65
+ params.require(:rule).permit!#(:name, :triggers => {})
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,105 @@
1
+ # All Cullender controllers are inherited from here.
2
+ class CullenderController < Cullender.parent_controller.constantize
3
+ include Cullender::Controllers::ScopedViews
4
+
5
+ helpers = %w(resource scope_name resource_name
6
+ resource_class resource_params cullender_mapping)
7
+ hide_action *helpers
8
+ helper_method *helpers
9
+
10
+ prepend_before_filter :assert_is_cullender_resource!
11
+ respond_to *Mime::SET.map(&:to_sym) if mimes_for_respond_to.empty?
12
+
13
+ # Gets the actual resource stored in the instance variable
14
+ def resource
15
+ instance_variable_get(:"@#{resource_name}")
16
+ end
17
+
18
+ # Proxy to cullender map name
19
+ def resource_name
20
+ cullender_mapping.name
21
+ end
22
+ alias :scope_name :resource_name
23
+
24
+ # Proxy to cullender map class
25
+ def resource_class
26
+ cullender_mapping.to
27
+ end
28
+
29
+ def resource_params
30
+ params[resource_name]
31
+ end
32
+
33
+ # Attempt to find the mapped route for cullender based on request path
34
+ def cullender_mapping
35
+ @cullender_mapping ||= request.env["cullender.mapping"]
36
+ end
37
+
38
+ # Override prefixes to consider the scoped view.
39
+ # Notice we need to check for the request due to a bug in
40
+ # Action Controller tests that forces _prefixes to be
41
+ # loaded before even having a request object.
42
+ def _prefixes #:nodoc:
43
+ @_prefixes ||= if self.class.scoped_views? && request && cullender_mapping
44
+ super.unshift("#{cullender_mapping.scoped_path}/#{controller_name}")
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ hide_action :_prefixes
51
+
52
+ protected
53
+
54
+ # Checks whether it's a cullender mapped resource or not.
55
+ def assert_is_cullender_resource! #:nodoc:
56
+ unknown_action! <<-MESSAGE unless cullender_mapping
57
+ Could not find cullender mapping for path #{request.fullpath.inspect}.
58
+ This may happen for two reasons:
59
+
60
+ 1) You forgot to wrap your route inside the scope block. For example:
61
+
62
+ cullender_scope :user do
63
+ match "/some/route" => "some_cullender_controller"
64
+ end
65
+
66
+ 2) You are testing a Cullender controller bypassing the router.
67
+ If so, you can explicitly tell Cullender which mapping to use:
68
+
69
+ @request.env["cullender.mapping"] = Cullender.mappings[:user]
70
+
71
+ MESSAGE
72
+ end
73
+
74
+ # Returns real navigational formats which are supported by Rails
75
+ def navigational_formats
76
+ @navigational_formats ||= Cullender.navigational_formats.select { |format| Mime::EXTENSION_LOOKUP[format.to_s] }
77
+ end
78
+
79
+ def unknown_action!(msg)
80
+ logger.debug "[Cullender] #{msg}" if logger
81
+ raise AbstractController::ActionNotFound, msg
82
+ end
83
+
84
+ # Sets the resource creating an instance variable
85
+ def resource=(new_resource)
86
+ instance_variable_set(:"@#{resource_name}", new_resource)
87
+ end
88
+
89
+ # Build a cullender resource.
90
+ # Assignment bypasses attribute protection when :unsafe option is passed
91
+ def build_resource(hash = nil, options = {})
92
+ hash ||= resource_params || {}
93
+
94
+ if options[:unsafe]
95
+ self.resource = resource_class.new.tap do |resource|
96
+ hash.each do |key, value|
97
+ setter = :"#{key}="
98
+ resource.send(setter, value) if resource.respond_to?(setter)
99
+ end
100
+ end
101
+ else
102
+ self.resource = resource_class.new(hash)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,136 @@
1
+ module Cullender
2
+ module RulesHelper
3
+
4
+
5
+ def render_property_tree(name, mapping, hash, options = {}, hierarchy = [], &block)
6
+ options.merge!(:class => "group level_#{hierarchy.length}")
7
+ last_key = hash.keys.last
8
+ html = content_tag :div, options do
9
+ hash.each do |field, value|
10
+ if value.keys.include?("o")
11
+ property_options = mapping.has_key?(field) ? mapping[field] : {}
12
+ block.call property_item(name, field, property_options, value, hierarchy), last_key == field ? 1 : -1, hierarchy
13
+ else
14
+ hierarchy.push(field)
15
+ block.call render_property_tree(name, mapping, value, {}, hierarchy, &block), last_key == field ? 0 : -1, hierarchy
16
+ end
17
+ end
18
+ end if hash.present?
19
+ hierarchy.pop
20
+ html
21
+ end
22
+
23
+ def extract_field_type(options)
24
+ options.has_key?(:type) && Cullender::Rule::FIELD_TYPE_MAP.has_key?(options[:type]) ? Cullender::Rule::FIELD_TYPE_MAP[options[:type]] : "text_field"
25
+ end
26
+
27
+ # type = Event.property_types.has_key?(field) ? Event.property_types[field] : "string" #Event::FIELDTYPE_MAP[column.datatype]
28
+ def property_item(name, field, options, value_hash = {}, hierarchy = [])
29
+ fieldtype = extract_field_type(options)
30
+ prefix = nested_property_prefix(hierarchy, name)
31
+ operator = value_hash['o'] || nil
32
+ value = value_hash['v'] || nil
33
+ content_tag :div, :class => "item #{field.to_s.parameterize}" do
34
+ submit_tag("-", :name => "remove#{nested_property_prefix(hierarchy, "")}[#{field}]", :class => 'btn') +
35
+ label_tag(field, field, {:for => "#{prefix}[#{field}][v]"}) +
36
+ select_tag( "#{prefix}[#{field}][o]", options_for_select(Cullender::Rule::OPERATORS[fieldtype], operator), :class => "operator") +
37
+ property_value_field(field, fieldtype, value, options, prefix)
38
+ end
39
+ end
40
+
41
+ def link_to_filter(attribute, value, options = {})
42
+ copy_of_params = deep_clone(params)
43
+ copy_of_params.deep_merge!({:filter => {attribute.to_sym => {"v" => value}}})
44
+ link_to_unless( params.has_key?(:filter) && params[:filter].has_key?(attribute), value, copy_of_params, options)
45
+ end
46
+
47
+ def link_to_remove_filter(attribute, value, options = {})
48
+ condition = params.has_key?(:filter) && params[:filter].has_key?(attribute.to_s) && params[:filter][attribute.to_s]['v'].to_s == value.to_s
49
+ copy_of_params = deep_clone(params)
50
+ copy_of_params[:filter].delete(attribute)
51
+ link_to( text_with_close_btn("#{attribute}=#{value}"), copy_of_params, options)
52
+ end
53
+
54
+ def remove_filter_link(attribute, value, count, options = {})
55
+ copy_of_params = deep_clone(params)
56
+ if params.has_key?(:filter) && params[:filter].has_key?(attribute.to_s) && params[:filter][attribute.to_s]['v'].to_s == value.to_s
57
+ copy_of_params[:filter].delete(attribute.to_s)
58
+ link_to "remove", copy_of_params, options
59
+ else
60
+ content_tag(:span, count, options)
61
+ end
62
+ end
63
+
64
+ def cullender_collection_or_select(collection, hierarchy = [], options = {})
65
+ is_base = options.delete(:base)
66
+ prefix = nested_property_prefix(hierarchy)
67
+ content_tag :div, :class => "add_group" do
68
+ select_tag( "or[#{"raise_" if is_base}field]#{prefix}", options_for_select(collection), :class => "column_select_field") +
69
+ submit_tag("OR", :name => "or#{is_base ? "[raise]" : "[commit]"}#{prefix}", :class => 'btn')
70
+ end
71
+ end
72
+
73
+
74
+ def cullender_collection_and_select(collection, hierarchy = [], options = {})
75
+ prefix = nested_property_prefix(hierarchy)
76
+ content_tag :div, :class => "add_filter" do
77
+ select_tag( "and[field]#{prefix}", options_for_select(collection), :class => "column_select_field") +
78
+ submit_tag("AND", :name => "and[commit]#{prefix}", :class => 'btn')
79
+ end
80
+ end
81
+
82
+ def extract_triggers(params)
83
+ if params.has_key?("triggers")
84
+ params["triggers"]
85
+ elsif params.has_key?("rule") && params["rule"].has_key?("triggers")
86
+ params["rule"]["triggers"]
87
+ end
88
+ end
89
+
90
+
91
+ def property_value_field(field, type, value = nil, options = {}, prefix = '')
92
+ default = options.delete(:default)
93
+ case type
94
+ when "number_field", "range_field", "text_field", "check_box"
95
+ send("#{type}_tag".to_sym, "#{prefix}[#{field}][v]", value, {:class => "value"} )
96
+ when "select"
97
+ select_tag("#{prefix}[#{field}][v]", options_for_select({}, value), {:class => "value"})
98
+ when "datetime"
99
+ select_datetime set_datetime(value, default), {:class => "value", :prefix => "#{prefix}[#{field}][v]"}
100
+ when "date"
101
+ select_date set_date(value, default), {:class => "value", :prefix => "#{prefix}[#{field}][v]"}
102
+ else #this includes Event::TEXT and any other field type
103
+ text_field_tag "#{prefix}[#{field}][v]", value, {:class => "value"}
104
+ end
105
+ end
106
+
107
+
108
+ def filter_to_s(key, value)
109
+ "#{key} #{Rule::FILTER_MAP[value["o"]]} #{value["v"]}" if value.has_key?("o") && value.has_key?("v")
110
+ end
111
+
112
+ # nest is an array of values of the hierarchy
113
+ def nested_property_prefix(hierarchy, prefix = nil)
114
+ "#{prefix}#{hierarchy.inject("") {|result, item| result += "[#{item}]"}}"
115
+ end
116
+
117
+ def formatted_triggers(hash)
118
+ ands = []
119
+ ors = []
120
+ hash.each do |key, value|
121
+ if value.keys.include?("o")
122
+ ands << filter_to_s(key, value)
123
+ else
124
+ ors << formatted_triggers(value)
125
+ end
126
+ end if hash.present?
127
+ ors.empty? ? "("+ ands.join(" AND ") + ")" : "(" + ors.join(" OR ") + ")"
128
+ end
129
+
130
+ private
131
+
132
+ def deep_clone(obj)
133
+ Marshal.load(Marshal.dump(obj))
134
+ end
135
+ end
136
+ end