visual_condition_builder 0.0.2

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +155 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/javascripts/visual_condition_builder/Sortable.js +1385 -0
  6. data/app/assets/javascripts/visual_condition_builder/autoNumeric-2.0-BETA.js +2156 -0
  7. data/app/assets/javascripts/visual_condition_builder/autonumeric_ujs.js +94 -0
  8. data/app/assets/javascripts/visual_condition_builder/condition_builder.js +633 -0
  9. data/app/assets/javascripts/visual_condition_builder/diacritics.js +116 -0
  10. data/app/assets/javascripts/visual_condition_builder/select2.full.js +6436 -0
  11. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ar.js +3 -0
  12. data/app/assets/javascripts/visual_condition_builder/select2_i18n/az.js +3 -0
  13. data/app/assets/javascripts/visual_condition_builder/select2_i18n/bg.js +3 -0
  14. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ca.js +3 -0
  15. data/app/assets/javascripts/visual_condition_builder/select2_i18n/cs.js +3 -0
  16. data/app/assets/javascripts/visual_condition_builder/select2_i18n/da.js +3 -0
  17. data/app/assets/javascripts/visual_condition_builder/select2_i18n/de.js +3 -0
  18. data/app/assets/javascripts/visual_condition_builder/select2_i18n/el.js +3 -0
  19. data/app/assets/javascripts/visual_condition_builder/select2_i18n/en.js +3 -0
  20. data/app/assets/javascripts/visual_condition_builder/select2_i18n/es.js +3 -0
  21. data/app/assets/javascripts/visual_condition_builder/select2_i18n/et.js +3 -0
  22. data/app/assets/javascripts/visual_condition_builder/select2_i18n/eu.js +3 -0
  23. data/app/assets/javascripts/visual_condition_builder/select2_i18n/fa.js +3 -0
  24. data/app/assets/javascripts/visual_condition_builder/select2_i18n/fi.js +3 -0
  25. data/app/assets/javascripts/visual_condition_builder/select2_i18n/fr.js +3 -0
  26. data/app/assets/javascripts/visual_condition_builder/select2_i18n/gl.js +3 -0
  27. data/app/assets/javascripts/visual_condition_builder/select2_i18n/he.js +3 -0
  28. data/app/assets/javascripts/visual_condition_builder/select2_i18n/hi.js +3 -0
  29. data/app/assets/javascripts/visual_condition_builder/select2_i18n/hr.js +3 -0
  30. data/app/assets/javascripts/visual_condition_builder/select2_i18n/hu.js +3 -0
  31. data/app/assets/javascripts/visual_condition_builder/select2_i18n/id.js +3 -0
  32. data/app/assets/javascripts/visual_condition_builder/select2_i18n/is.js +3 -0
  33. data/app/assets/javascripts/visual_condition_builder/select2_i18n/it.js +3 -0
  34. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ja.js +3 -0
  35. data/app/assets/javascripts/visual_condition_builder/select2_i18n/km.js +3 -0
  36. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ko.js +3 -0
  37. data/app/assets/javascripts/visual_condition_builder/select2_i18n/lt.js +3 -0
  38. data/app/assets/javascripts/visual_condition_builder/select2_i18n/lv.js +3 -0
  39. data/app/assets/javascripts/visual_condition_builder/select2_i18n/mk.js +3 -0
  40. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ms.js +3 -0
  41. data/app/assets/javascripts/visual_condition_builder/select2_i18n/nb.js +3 -0
  42. data/app/assets/javascripts/visual_condition_builder/select2_i18n/nl.js +3 -0
  43. data/app/assets/javascripts/visual_condition_builder/select2_i18n/pl.js +3 -0
  44. data/app/assets/javascripts/visual_condition_builder/select2_i18n/pt-BR.js +3 -0
  45. data/app/assets/javascripts/visual_condition_builder/select2_i18n/pt.js +3 -0
  46. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ro.js +3 -0
  47. data/app/assets/javascripts/visual_condition_builder/select2_i18n/ru.js +3 -0
  48. data/app/assets/javascripts/visual_condition_builder/select2_i18n/sk.js +3 -0
  49. data/app/assets/javascripts/visual_condition_builder/select2_i18n/sr-Cyrl.js +3 -0
  50. data/app/assets/javascripts/visual_condition_builder/select2_i18n/sr.js +3 -0
  51. data/app/assets/javascripts/visual_condition_builder/select2_i18n/sv.js +3 -0
  52. data/app/assets/javascripts/visual_condition_builder/select2_i18n/th.js +3 -0
  53. data/app/assets/javascripts/visual_condition_builder/select2_i18n/tr.js +3 -0
  54. data/app/assets/javascripts/visual_condition_builder/select2_i18n/uk.js +3 -0
  55. data/app/assets/javascripts/visual_condition_builder/select2_i18n/vi.js +3 -0
  56. data/app/assets/javascripts/visual_condition_builder/select2_i18n/zh-CN.js +3 -0
  57. data/app/assets/javascripts/visual_condition_builder/select2_i18n/zh-TW.js +3 -0
  58. data/app/assets/javascripts/visual_condition_builder.js +6 -0
  59. data/app/assets/stylesheets/visual_condition_builder/condition_builder.css +87 -0
  60. data/app/assets/stylesheets/visual_condition_builder/select2-bootstrap.css +722 -0
  61. data/app/assets/stylesheets/visual_condition_builder/select2.css +484 -0
  62. data/app/assets/stylesheets/visual_condition_builder.css +5 -0
  63. data/app/controllers/application_widget.rb +56 -0
  64. data/app/controllers/visual_condition_builder/application_controller.rb +5 -0
  65. data/app/controllers/visual_condition_builder/widgets_controller.rb +45 -0
  66. data/app/helpers/visual_condition_builder/application_helper.rb +74 -0
  67. data/app/models/visual_condition_builder/user.rb +10 -0
  68. data/app/views/visual_condition_builder/widgets/_widgets_list.html.erb +24 -0
  69. data/app/views/visual_condition_builder/widgets/index.html.erb +25 -0
  70. data/config/initializers/assets.rb +1 -0
  71. data/config/initializers/visual_condition_builder.rb +7 -0
  72. data/config/routes.rb +19 -0
  73. data/lib/generators/templates/create_taxweb_widgets_users.rb +18 -0
  74. data/lib/generators/templates/generic_widget.erb +12 -0
  75. data/lib/generators/templates/generic_widget.html.erb +2 -0
  76. data/lib/generators/visual_condition_builder/install_generator.rb +26 -0
  77. data/lib/generators/visual_condition_builder/view_generator.rb +11 -0
  78. data/lib/generators/visual_condition_builder/widget_generator.rb +25 -0
  79. data/lib/visual_condition_builder/converter.rb +22 -0
  80. data/lib/visual_condition_builder/dictionary.rb +166 -0
  81. data/lib/visual_condition_builder/engine.rb +6 -0
  82. data/lib/visual_condition_builder/helper.rb +19 -0
  83. data/lib/visual_condition_builder/version.rb +3 -0
  84. data/lib/visual_condition_builder.rb +9 -0
  85. metadata +127 -0
@@ -0,0 +1,5 @@
1
+ /*
2
+ *= require visual_condition_builder/select2
3
+ *= require visual_condition_builder/select2-bootstrap
4
+ *= require visual_condition_builder/condition_builder
5
+ */
@@ -0,0 +1,56 @@
1
+ class ApplicationWidget < ::ApplicationController
2
+ include SingletonHelper
3
+
4
+ attr_singleton :refresh_interval, 0
5
+
6
+ def initialize(request)
7
+ self.request = request
8
+ end
9
+
10
+ def render_template(view_file=nil, *args)
11
+ args << {template: view_file}
12
+ render_to_string *args
13
+ end
14
+
15
+ def view(view_file=nil, klass=nil)
16
+ class_caller = klass || (caller[0].match(/(\b\w+)\.rb/)[1] rescue '')
17
+ action_caller = view_file || (caller[0].match(/`(.*)'/)[1] rescue '')
18
+ view_file = "widgets/#{class_caller.to_s.sub('_widget','')}/#{action_caller}" unless lookup_context.find_all(view_file).any?
19
+ instance_variable_set(:@view_file, view_file)
20
+ end
21
+
22
+ def self.name?
23
+ instance_variable_defined?(:@widget_name) ? instance_variable_get(:@widget_name) : ''
24
+ end
25
+
26
+ def self.name!(value)
27
+ # define_singleton_method(:widget_name) {value}
28
+ instance_variable_set(:@widget_name, value)
29
+ end
30
+
31
+ def self.description?(attr=nil)
32
+ attr='widget' if attr.nil?
33
+ instance_variable_defined?("@description_#{attr}") ? instance_variable_get("@description_#{attr}") : ''
34
+ end
35
+
36
+ def self.description!(*args)
37
+ if args.size == 1
38
+ instance_variable_set(:@description_widget, args[0])
39
+ elsif args.size == 2
40
+ instance_variable_set("@description_#{args[0]}", args[1])
41
+ end
42
+ end
43
+
44
+ def self.widgets
45
+ # ApplicationWidget.descendants.map do |klass| #Não estava carregando no primeiro load...
46
+ Dir["#{Rails.root}/app/widgets/*.rb"].map do |file_path|
47
+ file_name = File.basename(file_path, ".rb")
48
+ klass = Object.const_get file_name.classify
49
+ actions = klass.instance_methods(false).map do |action|
50
+ {name: action, description: klass.description?(action)}
51
+ end
52
+ {code: klass.to_s.tableize.sub('_widgets',''), name: klass.name?, description: klass.description?, actions: actions}
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,5 @@
1
+ module VisualConditionBuilder
2
+ class ApplicationController < ::ApplicationController #< ActionController::Base #ENGINE
3
+
4
+ end
5
+ end
@@ -0,0 +1,45 @@
1
+ require_dependency "visual_condition_builder/application_controller"
2
+
3
+ module VisualConditionBuilder
4
+ class WidgetsController < ApplicationController
5
+
6
+ def load
7
+ widget = VisualConditionBuilder::Widget.new(params[:widget_name], self.request)
8
+ content = widget.html(params[:widget_action])
9
+ rescue Exception => e
10
+ content = e.message
11
+ ensure
12
+ render html: content, layout: false
13
+ end
14
+
15
+ def user
16
+ user_id = params[:id] || current_user.id
17
+ @widgets_code = VisualConditionBuilder::User.where(user_id: user_id).pluck(:widget, :action).map{|r| "#{r[0]}_#{r[1]}"}
18
+ render partial: 'widgets_list'
19
+ end
20
+
21
+ def index
22
+ end
23
+
24
+ def save
25
+ user_id = params[:user_id] || current_user.id
26
+ widgets = params[:widgets]
27
+ widget_name_user = []
28
+ action_user = []
29
+ if widgets.present?
30
+ widgets.each do |widget|
31
+ widget_name, action = widget.split('|')
32
+ if widget_name && action
33
+ widget_name_user << widget_name
34
+ action_user << action
35
+ VisualConditionBuilder::User.find_or_create_by(widget: widget_name, action: action, user_id: user_id)
36
+ end
37
+ end
38
+ end
39
+ VisualConditionBuilder::User.where(user_id: user_id).where.not(widget: widget_name_user, action: action_user).destroy_all
40
+ flash[:success] = 'Alterações foram salvas com sucesso!'
41
+ redirect_to visual_condition_builder_path
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,74 @@
1
+ module VisualConditionBuilder
2
+ module ApplicationHelper
3
+
4
+ def build_conditions(dictionary, *args)
5
+ dictionary_name = get_dictionary_name(dictionary)
6
+ container_name = "#{dictionary_name}_condition_container"
7
+
8
+ hArgs = (args ||= []).reduce(Hash.new, :merge)
9
+ hArgs = normalize_placeholder_label(hArgs)
10
+
11
+ builder_options = {
12
+ dictionary: ObrigacaoDictionary.dictionary
13
+ }.deep_merge(hArgs)
14
+
15
+ capture do
16
+ concat(content_tag(:div, nil, id: container_name))
17
+ concat(javascript_tag(<<txtjs
18
+ $(document).ready(function () {
19
+ $('##{container_name}').conditionBuilder(#{builder_options.to_json});
20
+ });
21
+ txtjs
22
+ ))
23
+ end
24
+ end
25
+
26
+ def conditions_fields(dictionary, *args)
27
+ dictionary_name = get_dictionary_name(dictionary)
28
+ container_name = "#{dictionary_name}_condition_container"
29
+ capture do
30
+ content_tag(:div, class: 'dropdown add-condition', data: {target: "##{container_name}"}) do
31
+ concat(content_tag(:button, class: 'btn btn-default dropdown-toggle', data: {toggle: 'dropdown'}, type: 'button') do
32
+ concat(I18n.t(:dropdown, default: ['Fields'], scope: [:condition_builder]))
33
+ concat(content_tag(:span, nil, class:'caret'))
34
+ end)
35
+ concat(content_tag(:ul, class: 'dropdown-menu add-condition-menu') do
36
+ create_conditions_fields_item(ObrigacaoDictionary.fields(get_dictionary_context(dictionary)))
37
+ end)
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+ def create_conditions_fields_item(fields)
44
+ fields.each do |field, attrs|
45
+ if field.is_a?(Hash) #GROUP
46
+ group_label = field.values.first
47
+ concat(content_tag(:li, group_label, class: 'dropdown-header'))
48
+ create_conditions_fields_item(attrs)
49
+ else
50
+ concat(content_tag(:li, link_to(attrs[:label], '#', class: 'add-condition-field', data: {field: field})))
51
+ end
52
+ end
53
+ end
54
+
55
+ def get_dictionary_context(dictionary)
56
+ dictionary.is_a?(Hash) ? dictionary.values.first : :default
57
+ end
58
+ def get_dictionary_name(dictionary)
59
+ "#{dictionary.is_a?(Hash) ? dictionary.keys.first : dictionary}_#{get_dictionary_context(dictionary)}"
60
+ end
61
+
62
+ def normalize_placeholder_label(args)
63
+ args[:placeholder] ||= {}
64
+ [:fields, :operators, :values].each do |attr|
65
+ unless args[:placeholder][attr].present?
66
+ label = I18n.t(attr, default: [''], scope: [:condition_builder, :placeholder])
67
+ args[:placeholder][attr] = label if label.present?
68
+ end
69
+ end
70
+ args
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,10 @@
1
+ module VisualConditionBuilder
2
+ class User < ActiveRecord::Base
3
+
4
+ self.table_name = :visual_condition_builder_users
5
+
6
+ belongs_to :user
7
+
8
+ validates :widget, :action, presence: true
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ <% ApplicationWidget.widgets.each do |widget| %>
2
+ <ul>
3
+ <li>
4
+ <b><%= widget[:name] %></b>
5
+ <br><span class="help-block"><%= widget[:description] %></span>
6
+ <ul>
7
+ <% widget[:actions].each do |action| %>
8
+ <% widget_code = "#{widget[:code]}_#{action[:name]}" %>
9
+ <li>
10
+ <div class="checkbox">
11
+ <%= label_tag widget_code do %>
12
+ <%= check_box_tag 'widgets[]', "#{widget[:code]}|#{action[:name]}", @widgets_code.include?(widget_code), {id: widget_code} %>
13
+ <b><%= action[:name].to_s.humanize %></b>
14
+ <% if action[:description].present? %>
15
+ <br><span class="help-block"><%= action[:description] %></span>
16
+ <% end %>
17
+ <% end %>
18
+ </div>
19
+ </li>
20
+ <% end %>
21
+ </ul>
22
+ </li>
23
+ </ul>
24
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <div class="row">
2
+ <div class="col-md-12">
3
+ <div class="panel panel-default">
4
+ <div class="panel-heading">
5
+ <div class="panel-title">Selecione os Widgets que deseja utilizar:</div>
6
+ </div>
7
+ <div class="panel-body">
8
+ <%= form_tag(visual_condition_builder_save_path, method: :put, class: 'widget_config') do %>
9
+
10
+ <div class="form-group">
11
+ <label class="control-label">Usuário:</label>
12
+ <%= select_tag :user_id, options_from_collection_for_select(User.all, :id, :email, current_user.id), include_blank: false, class: 'form-control widget-user-control' %>
13
+ </div>
14
+
15
+ <fieldset class="widgets_list">
16
+ <legend>Widgets</legend>
17
+ <div class="list"></div>
18
+ </fieldset>
19
+
20
+ <%= submit_tag "Salvar", class: 'btn btn-success' %>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
@@ -0,0 +1 @@
1
+ Rails.application.config.assets.precompile += %w( visual_condition_builder.js visual_condition_builder.css )
@@ -0,0 +1,7 @@
1
+ class Railtie < ::Rails::Railtie
2
+ initializer 'activeservice.autoload', :before => :set_autoload_paths do |app|
3
+ app.config.autoload_paths << "#{Rails.application.config.root}/app/condition_dictionaries"
4
+ end
5
+ end
6
+
7
+
data/config/routes.rb ADDED
@@ -0,0 +1,19 @@
1
+ Rails.application.routes.draw do
2
+
3
+
4
+ namespace :visual_condition_builder do
5
+
6
+ get 'widgets/load/:widget_name/:widget_action', to: 'widgets#load', as: 'load'
7
+ get 'widgets/user(/:id)', to: 'widgets#user', as: 'user'
8
+ get 'widgets', to: 'widgets#index', as: ''
9
+ put 'widgets/save', to: 'widgets#save', as: 'save'
10
+
11
+
12
+ end
13
+
14
+
15
+
16
+
17
+
18
+
19
+ end
@@ -0,0 +1,18 @@
1
+ class CreateVisualConditionBuilderUsers < ActiveRecord::Migration
2
+
3
+ def up
4
+ unless table_exists?(:visual_condition_builder_users)
5
+ create_table :visual_condition_builder_users do |t|
6
+ t.references :user, index: true, foreign_key: false
7
+ t.string :widget
8
+ t.string :action
9
+ t.index [:widget, :action]
10
+ end
11
+ end
12
+ end
13
+
14
+ def down
15
+ drop_table :visual_condition_builder_users if table_exists? :visual_condition_builder_users
16
+ end
17
+
18
+ end
@@ -0,0 +1,12 @@
1
+ class <%= @widget_name %>Widget < ApplicationWidget
2
+
3
+ name! "<%= @widget_name %>"
4
+ description! "O Widget <%= @widget_name %> tem como função..."
5
+ #refresh_interval 60000 #60 segundos para refresh automático
6
+
7
+ description! :exemplo, 'Essa ação é um exemplo'
8
+ def exemplo
9
+ @data = Date.today
10
+ end
11
+
12
+ end
@@ -0,0 +1,2 @@
1
+ <h1>Exemplo de Widget<h1>
2
+ Hoje é <%= data %>
@@ -0,0 +1,26 @@
1
+ require 'rails/generators/base'
2
+ require 'rails/generators/migration'
3
+
4
+ module VisualConditionBuilder
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../../templates", __FILE__)
7
+ include Rails::Generators::Migration
8
+
9
+ class_option :orm
10
+ desc 'Instalando Taxweb Widgets'
11
+
12
+ desc 'Criando Migrations'
13
+ def self.next_migration_number(path)
14
+ unless @prev_migration_nr
15
+ @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
16
+ else
17
+ @prev_migration_nr += 1
18
+ end
19
+ @prev_migration_nr.to_s
20
+ end
21
+
22
+ def create_migration_file
23
+ migration_template 'create_visual_condition_builder_users.rb', 'db/migrate/create_visual_condition_builder_users.rb'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails/generators/base'
2
+
3
+ module VisualConditionBuilder
4
+ class ViewGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../../../../app/views/visual_condition_builder", __FILE__)
6
+
7
+ def copy_views
8
+ directory 'widgets', 'app/views/visual_condition_builder/widgets'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ require 'rails/generators/base'
2
+
3
+ module VisualConditionBuilder
4
+ class WidgetGenerator < Rails::Generators::NamedBase
5
+ source_root File.expand_path("../../templates", __FILE__)
6
+
7
+ def generate_widget
8
+ @widget_name = file_name.classify
9
+ view_dir = "app/views/widgets/#{widget_name_file}"
10
+
11
+ template "generic_widget.erb", File.join('app/widgets', "#{widget_name_file}_widget.rb")
12
+
13
+ if self.behavior == :revoke && Dir.exists?(view_dir)
14
+ require 'fileutils'
15
+ FileUtils.rm_rf(view_dir)
16
+ elsif self.behavior == :invoke
17
+ copy_file "generic_widget.html.erb", File.join(view_dir, 'exemplo.html.erb')
18
+ end
19
+ end
20
+
21
+ def widget_name_file
22
+ file_name.underscore
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module VisualConditionBuilder
2
+ class Converter
3
+ def self.to_ransack(params)
4
+ ransack_q = {}
5
+ conditions = params.is_a?(Array) ? params : JSON.parse(params ||= '[]')
6
+ conditions.map do |p|
7
+ #TODO: Verificar se o código deve ser inserido com inteligência para juntar os campos de mesmo operador
8
+ if ransack_q["#{p[0]}_#{p[1]}"].present?
9
+ old_value = ransack_q["#{p[0]}_#{p[1]}"]
10
+ ransack_q.delete("#{p[0]}_#{p[1]}")
11
+ ransack_q["#{p[0]}_in"] = []
12
+ ransack_q["#{p[0]}_in"] << old_value
13
+ ransack_q["#{p[0]}_in"] << p[2]
14
+ else
15
+ ransack_q["#{p[0]}_#{p[1]}"] = p[2]
16
+ end
17
+ # ransack_q["#{p[0]}_#{p[1]}"] = p[2]
18
+ end
19
+ ransack_q
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,166 @@
1
+ module VisualConditionBuilder
2
+ class Dictionary
3
+ class_attribute :dictionaries
4
+
5
+ class << self
6
+ def method_missing(m, *args, &block)
7
+ if m =~ /_url|_path/
8
+ Rails.application.routes.url_helpers.send(m, args)
9
+ end
10
+ end
11
+
12
+ def dictionary(name=:default, &block)
13
+ (self.dictionaries ||= {})[name] ||= []
14
+ @dictionary_name = name
15
+ block.call if block_given?
16
+ self.dictionaries[name]
17
+ end
18
+
19
+ def fields(dictionary_name=:default)
20
+ dictionary ||= {}
21
+ self.dictionaries[dictionary_name].group_by{|h| h[:group]}.each do |group, attrs|
22
+ dictionary[group] ||= {} if group.present?
23
+ attrs.each do |attr|
24
+ if group.present?
25
+ dictionary[group][attr[:field]] = attr.slice(:label, :type)
26
+ else
27
+ dictionary[attr[:field]] = attr.slice(:label, :type)
28
+ end
29
+ end
30
+ end
31
+ dictionary
32
+ end
33
+
34
+ def param(attr, *args)
35
+ #DEFAULT VALUES
36
+ args = array_hashes_to_hash(args)
37
+ args[:type] ||= 'STRING'
38
+ args[:operators] = operators_by_type(args[:type]) unless args[:operators].present?
39
+ args[:operators] = normalize_operators(args[:operators])
40
+ args[:values] ||= []
41
+ args[:group] ||= ''
42
+ if args[:group].present? && args[:group].is_a?(Symbol)
43
+ args[:label] ||= I18n.t(attr.to_sym, default: attr.to_s.humanize, scope: [:condition_dictionaries, args[:group]])
44
+ args[:field] ||= "#{args[:group]}_#{attr}"
45
+ args[:group] = {args[:group] => I18n.t(args[:group], default: args[:group].to_s, scope: [:condition_builder, :dictionaries])}
46
+ else
47
+ args[:label] ||= I18n.t(attr.to_sym, default: attr.to_s.humanize, scope: [:condition_dictionaries, dictionary_name])
48
+ args[:field] ||= attr
49
+ end
50
+ if args[:values].present? && args[:values].is_a?(Proc)
51
+ args[:values] = args[:values].call
52
+ end
53
+ self.dictionaries[@dictionary_name] << args
54
+ end
55
+
56
+ def operators_by_type(type)
57
+ type = type.present? ? type.to_s.downcase.to_sym : 'string'
58
+ operators = case type
59
+ when :date, :datetime
60
+ [:eq, :between, :today, :yesterday, :this_week, :last_week, :present, :blank]
61
+ when :time
62
+ [:eq, :between, :present, :blank]
63
+ when :decimal, :integer
64
+ [:eq, :between]
65
+ when :string
66
+ [:cont, :eq, :start, :end, :present, :blank]
67
+ else
68
+ [:eq]
69
+ end
70
+ operators.map{|op| operator_default(op) }
71
+ end
72
+
73
+ def normalize_operators(operators)
74
+ operators.map do |operator|
75
+ operator = operator_default(operator) unless operator.is_a?(Hash)
76
+ operator[:no_value] ||= false
77
+ operator[:multiple] ||= false
78
+ operator[:label] ||= operator_translate(operator[:operator])
79
+ operator
80
+ end
81
+ end
82
+
83
+ def operators_list(op=nil)
84
+ operators = {
85
+ between: {multiple: 2},
86
+ today: {no_value: true},
87
+ yesterday: {no_value: true},
88
+ this_week: {no_value: true},
89
+ last_wee: {no_value: true},
90
+
91
+ eq: {multiple: false},
92
+ not_eq: {multiple: false},
93
+
94
+ matches: {multiple: false},
95
+ does_not_match: {multiple: false},
96
+
97
+ lt: {multiple: false},
98
+ gt: {multiple: false},
99
+
100
+ lteq: {multiple: false},
101
+ gteq: {multiple: false},
102
+
103
+ in: {multiple: true},
104
+ not_in: {multiple: true},
105
+
106
+ cont: {multiple: false},
107
+ not_cont: {multiple: false},
108
+
109
+ cont_any: {multiple: true},
110
+ not_cont_any: {multiple: true},
111
+
112
+ cont_all: {multiple: true},
113
+ not_cont_all: {multiple: true},
114
+
115
+ start: {multiple: false},
116
+ not_start: {multiple: false},
117
+
118
+ end: {multiple: false},
119
+ not_end: {multiple: false},
120
+
121
+ true: {no_value: true, multiple: false},
122
+ not_true: {no_value: true, multiple: false},
123
+
124
+ false: {no_value: true, multiple: false},
125
+ not_false: {no_value: true, multiple: false},
126
+
127
+ present: {no_value: true, multiple: false},
128
+ blank: {no_value: true, multiple: false},
129
+
130
+ null: {no_value: true, multiple: false},
131
+ not_null: {no_value: true, multiple: false},
132
+ }
133
+ if op.present?
134
+ (operators[operator_name(op)] || {})
135
+ else
136
+ operators
137
+ end
138
+ end
139
+
140
+ def operator_default(op)
141
+ op_default = operators_list(op)
142
+ operator = {operator: operator_name(op)}
143
+ operator.deep_merge!(op_default) if op_default.present?
144
+ operator
145
+ end
146
+
147
+ def operator_translate(op)
148
+ I18n.t(op, default: op.to_s.humanize, scope: [:condition_builder, :operators])
149
+ end
150
+
151
+ def dictionary_name
152
+ self.to_s.sub('Dictionary', '').underscore.to_sym
153
+ end
154
+
155
+ def array_hashes_to_hash(array=nil)
156
+ array ||= []
157
+ array.reduce Hash.new, :merge
158
+ end
159
+
160
+ def operator_name(op)
161
+ op.to_s.downcase.to_sym
162
+ end
163
+ end
164
+
165
+ end
166
+ end