discerner 1.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +97 -0
  4. data/Rakefile +29 -0
  5. data/app/assets/images/discerner/add.png +0 -0
  6. data/app/assets/images/discerner/ajax-loader.gif +0 -0
  7. data/app/assets/images/discerner/bar.gif +0 -0
  8. data/app/assets/images/discerner/bullet_arrow_down.png +0 -0
  9. data/app/assets/images/discerner/bullet_arrow_up.png +0 -0
  10. data/app/assets/images/discerner/cog.png +0 -0
  11. data/app/assets/images/discerner/delete.png +0 -0
  12. data/app/assets/images/discerner/edit.png +0 -0
  13. data/app/assets/images/discerner/excel.png +0 -0
  14. data/app/assets/images/discerner/greencheck.gif +0 -0
  15. data/app/assets/images/discerner/rails.png +0 -0
  16. data/app/assets/images/discerner/show.png +0 -0
  17. data/app/assets/images/discerner/switch_minus.gif +0 -0
  18. data/app/assets/images/discerner/switch_plus.gif +0 -0
  19. data/app/assets/javascripts/discerner/application.js +20 -0
  20. data/app/assets/javascripts/discerner/combobox.js +301 -0
  21. data/app/assets/javascripts/discerner/discerner.js +19 -0
  22. data/app/assets/javascripts/discerner/export_parameters.js +13 -0
  23. data/app/assets/javascripts/discerner/jquery/jquery.blockUI.js +576 -0
  24. data/app/assets/javascripts/discerner/jquery/jquery.form.js +1074 -0
  25. data/app/assets/javascripts/discerner/nested_attributes.js +69 -0
  26. data/app/assets/javascripts/discerner/search_combinations.js +49 -0
  27. data/app/assets/javascripts/discerner/search_parameter.js +131 -0
  28. data/app/assets/javascripts/discerner/search_parameter_value.js +172 -0
  29. data/app/assets/javascripts/discerner/searches.js +93 -0
  30. data/app/assets/javascripts/discerner/url.js +42 -0
  31. data/app/assets/stylesheets/discerner/application.css +16 -0
  32. data/app/assets/stylesheets/discerner/buttons.sass +13 -0
  33. data/app/assets/stylesheets/discerner/categorized_autocompleter.sass +53 -0
  34. data/app/assets/stylesheets/discerner/discerner.sass +51 -0
  35. data/app/assets/stylesheets/discerner/export_parameters.sass +43 -0
  36. data/app/assets/stylesheets/discerner/links.sass +29 -0
  37. data/app/assets/stylesheets/discerner/searches.sass +205 -0
  38. data/app/assets/stylesheets/discerner/tables.sass +32 -0
  39. data/app/controllers/discerner/application_controller.rb +2 -0
  40. data/app/controllers/discerner/export_parameters_controller.rb +5 -0
  41. data/app/controllers/discerner/parameters_controller.rb +5 -0
  42. data/app/controllers/discerner/searches_controller.rb +5 -0
  43. data/app/helpers/discerner/application_helper.rb +4 -0
  44. data/app/helpers/discerner/parameters_helper.rb +5 -0
  45. data/app/helpers/discerner/searches_helper.rb +5 -0
  46. data/app/models/discerner/dictionary.rb +5 -0
  47. data/app/models/discerner/export_parameter.rb +5 -0
  48. data/app/models/discerner/operator.rb +5 -0
  49. data/app/models/discerner/parameter.rb +5 -0
  50. data/app/models/discerner/parameter_category.rb +5 -0
  51. data/app/models/discerner/parameter_type.rb +5 -0
  52. data/app/models/discerner/parameter_value.rb +5 -0
  53. data/app/models/discerner/parameter_value_categorization.rb +5 -0
  54. data/app/models/discerner/parameter_value_category.rb +5 -0
  55. data/app/models/discerner/search.rb +5 -0
  56. data/app/models/discerner/search_combination.rb +5 -0
  57. data/app/models/discerner/search_parameter.rb +5 -0
  58. data/app/models/discerner/search_parameter_value.rb +5 -0
  59. data/app/views/discerner/export_parameters/index.html.haml +55 -0
  60. data/app/views/discerner/parameters/_values_autocompleter.html.haml +49 -0
  61. data/app/views/discerner/parameters/values.html.haml +1 -0
  62. data/app/views/discerner/searches/_form.html.haml +21 -0
  63. data/app/views/discerner/searches/_form_combined_searches.html.haml +32 -0
  64. data/app/views/discerner/searches/_form_controls.html.haml +8 -0
  65. data/app/views/discerner/searches/_form_header.html.haml +39 -0
  66. data/app/views/discerner/searches/_form_search_parameters.html.haml +28 -0
  67. data/app/views/discerner/searches/_list.html.haml +17 -0
  68. data/app/views/discerner/searches/_search_combination_fields.html.haml +22 -0
  69. data/app/views/discerner/searches/_search_parameter_fields.html.haml +48 -0
  70. data/app/views/discerner/searches/_search_parameter_value_fields.html.haml +62 -0
  71. data/app/views/discerner/searches/_summary.html.haml +25 -0
  72. data/app/views/discerner/searches/edit.html.haml +8 -0
  73. data/app/views/discerner/searches/index.html.haml +13 -0
  74. data/app/views/discerner/searches/index.js.haml +1 -0
  75. data/app/views/discerner/searches/new.html.haml +3 -0
  76. data/app/views/discerner/searches/rename.html.haml +6 -0
  77. data/app/views/discerner/searches/update.js.haml +7 -0
  78. data/app/views/discerner/shared/_categorized_autocompleter_items.html.haml +15 -0
  79. data/app/views/discerner/shared/_error_messages.html.haml +5 -0
  80. data/app/views/layouts/discerner/searches.html.erb +17 -0
  81. data/config/cucumber.yml +8 -0
  82. data/config/routes.rb +17 -0
  83. data/db/migrate/20121004040716_create_discerner_dictionaries.rb +11 -0
  84. data/db/migrate/20121004153043_create_discerner_parameter_categories.rb +12 -0
  85. data/db/migrate/20121005194843_create_discerner_parameter_types.rb +11 -0
  86. data/db/migrate/20121005203223_create_discerner_parameters.rb +14 -0
  87. data/db/migrate/20121008154855_create_discerner_operators.rb +13 -0
  88. data/db/migrate/20121008160313_create_discerner_operators_parameter_types.rb +8 -0
  89. data/db/migrate/20121008161455_create_discerner_parameter_values.rb +13 -0
  90. data/db/migrate/20121008180829_create_discerner_searches.rb +11 -0
  91. data/db/migrate/20121008182443_create_discerner_search_parameters.rb +11 -0
  92. data/db/migrate/20121011205130_create_discerner_search_parameter_values.rb +15 -0
  93. data/db/migrate/20121211213215_add_dictionary_id_to_discerner_searches.rb +5 -0
  94. data/db/migrate/20130205193602_create_discerner_search_combinations.rb +12 -0
  95. data/db/migrate/20130211230636_create_discerner_export_parameters.rb +9 -0
  96. data/db/migrate/20130213185818_add_search_columns_to_discerner_parameters.rb +38 -0
  97. data/db/migrate/20130213205255_rename_database_name_to_search_value_in_discerner_parameter_values.rb +5 -0
  98. data/db/migrate/20130215165416_add_searchable_to_discerner_parameters.rb +5 -0
  99. data/db/migrate/20130218230257_add_exclusive_to_discerner_parameters.rb +5 -0
  100. data/db/migrate/20130220163015_replace_integer_type_with_numeric.rb +22 -0
  101. data/db/migrate/20130221172826_add_unique_identifier_to_discerner_parameters.rb +5 -0
  102. data/db/migrate/20130222052924_change_search_attribute_to_method.rb +29 -0
  103. data/db/migrate/20130222070959_add_export_columns_to_discerner_parameters.rb +6 -0
  104. data/db/migrate/20130227031747_add_unique_identifier_to_discerner_operators.rb +16 -0
  105. data/db/migrate/20130306015019_change_discerner_parameter_values_name.rb +9 -0
  106. data/db/migrate/20130306212430_add_deleted_at_to_discerner_search_parameters.rb +5 -0
  107. data/db/migrate/20130306212504_add_deleted_at_to_discerner_search_parameter_values.rb +5 -0
  108. data/db/migrate/20130306212527_add_deleted_at_to_discerner_search_combinations.rb +5 -0
  109. data/db/migrate/20130306212818_add_deleted_at_to_discerner_export_parameters.rb +5 -0
  110. data/db/migrate/20130311190717_add_operator_type_to_discerner_operators.rb +5 -0
  111. data/db/migrate/20131212175110_remove_extra_search_parameter_values.rb +10 -0
  112. data/db/migrate/20140204170625_create_discerner_parameter_value_categories.rb +16 -0
  113. data/db/migrate/20140204170646_create_discerner_parameter_value_categorizations.rb +12 -0
  114. data/db/migrate/20140227191827_remove_blank_parameter_values_from_export_parameters.rb +10 -0
  115. data/db/seeds.rb +0 -0
  116. data/lib/discerner/engine.rb +16 -0
  117. data/lib/discerner/methods/controllers/export_parameters_controller.rb +38 -0
  118. data/lib/discerner/methods/controllers/parameters_controller.rb +30 -0
  119. data/lib/discerner/methods/controllers/searches_controller.rb +204 -0
  120. data/lib/discerner/methods/helpers/searches_helper.rb +145 -0
  121. data/lib/discerner/methods/models/dictionary.rb +54 -0
  122. data/lib/discerner/methods/models/export_parameter.rb +35 -0
  123. data/lib/discerner/methods/models/operator.rb +42 -0
  124. data/lib/discerner/methods/models/parameter.rb +90 -0
  125. data/lib/discerner/methods/models/parameter_category.rb +60 -0
  126. data/lib/discerner/methods/models/parameter_type.rb +33 -0
  127. data/lib/discerner/methods/models/parameter_value.rb +87 -0
  128. data/lib/discerner/methods/models/parameter_value_categorization.rb +21 -0
  129. data/lib/discerner/methods/models/parameter_value_category.rb +45 -0
  130. data/lib/discerner/methods/models/search.rb +147 -0
  131. data/lib/discerner/methods/models/search_combination.rb +50 -0
  132. data/lib/discerner/methods/models/search_parameter.rb +128 -0
  133. data/lib/discerner/methods/models/search_parameter_value.rb +130 -0
  134. data/lib/discerner/methods/models/soft_delete.rb +35 -0
  135. data/lib/discerner/methods/models/warning.rb +15 -0
  136. data/lib/discerner/parser.rb +497 -0
  137. data/lib/discerner/version.rb +3 -0
  138. data/lib/discerner.rb +4 -0
  139. data/lib/generators/discerner/dictionary/dictionary_generator.rb +38 -0
  140. data/lib/generators/discerner/dictionary/templates/model.rb +15 -0
  141. data/lib/generators/discerner/dictionary/templates/show.xls.erb +37 -0
  142. data/lib/generators/discerner/dictionary/templates/view.html.haml +2 -0
  143. data/lib/generators/discerner/install/install_generator.rb +153 -0
  144. data/lib/generators/discerner/install/templates/controllers/export_parameters_controller.rb +20 -0
  145. data/lib/generators/discerner/install/templates/controllers/parameters_controller.rb +15 -0
  146. data/lib/generators/discerner/install/templates/controllers/searches_controller.rb +39 -0
  147. data/lib/generators/discerner/install/templates/dictionaries.yml +236 -0
  148. data/lib/generators/discerner/install/templates/helpers/searches_helper.rb +9 -0
  149. data/lib/generators/discerner/install/templates/models/book.rb +15 -0
  150. data/lib/generators/discerner/install/templates/models/dictionary.rb +9 -0
  151. data/lib/generators/discerner/install/templates/models/export_parameter.rb +9 -0
  152. data/lib/generators/discerner/install/templates/models/operator.rb +9 -0
  153. data/lib/generators/discerner/install/templates/models/parameter.rb +10 -0
  154. data/lib/generators/discerner/install/templates/models/parameter_category.rb +9 -0
  155. data/lib/generators/discerner/install/templates/models/parameter_type.rb +9 -0
  156. data/lib/generators/discerner/install/templates/models/parameter_value.rb +9 -0
  157. data/lib/generators/discerner/install/templates/models/parameter_value_categorization.rb +9 -0
  158. data/lib/generators/discerner/install/templates/models/parameter_value_category.rb +9 -0
  159. data/lib/generators/discerner/install/templates/models/search.rb +9 -0
  160. data/lib/generators/discerner/install/templates/models/search_combination.rb +9 -0
  161. data/lib/generators/discerner/install/templates/models/search_parameter.rb +9 -0
  162. data/lib/generators/discerner/install/templates/models/search_parameter_value.rb +9 -0
  163. data/lib/generators/discerner/install/templates/views/layouts/searches.html.erb +17 -0
  164. data/lib/setup/operators.yml +91 -0
  165. data/lib/tasks/cucumber.rake +65 -0
  166. data/lib/tasks/discerner_tasks.rake +30 -0
  167. metadata +531 -0
@@ -0,0 +1,69 @@
1
+ NestedAttributes = function (config) {
2
+ var that = this,
3
+ defaultConfig = {
4
+ removeStyle: 'hide',
5
+ undeleteOnChange: false,
6
+ add: true,
7
+ remove: true
8
+ };
9
+ this.config = $.extend(defaultConfig, config);
10
+
11
+ if (this.config.undeleteOnChange) {
12
+ $(this.config.container).find("input, select, textarea").change(function () {
13
+ $(that.config.container).find('.delete_' + that.config.association).prev("input[type=hidden]").val("0");
14
+ });
15
+ }
16
+
17
+ $(this.config.container).find("input, select, textarea").focus(function () {
18
+ $(this).select();
19
+ });
20
+
21
+ if (this.config.remove) {
22
+ var link = $(this.config.container).find('.delete_' + this.config.association)
23
+ $(document).off('click', link.selector)
24
+ $(document).on('click', link.selector, function() {
25
+ that.remove_fields(this, that.config.removeStyle);
26
+
27
+ if (that.config.removeHandler) {
28
+ that.config.removeHandler.call(that.config.caller);
29
+ }
30
+ });
31
+ }
32
+
33
+ if (this.config.add) {
34
+ var link = $(this.config.container).find('.add_' + this.config.association)
35
+ $(document).off('click', link.selector)
36
+ $(document).on('click', link.selector, function() {
37
+ that.add_fields(this, that.config.association, that.config.content);
38
+
39
+ if (that.config.addHandler) {
40
+ that.config.addHandler.call(that.config.caller);
41
+ }
42
+ });
43
+ }
44
+ };
45
+
46
+ NestedAttributes.prototype = {
47
+ remove_fields: function (link, removeStyle) {
48
+ $(link).prev("input[type=hidden]").val("1");
49
+ if (removeStyle === 'hide' ) {
50
+ $(link).closest(".fields").hide();
51
+ $(link).closest(".fields").prev('.error').hide();
52
+ }
53
+ else if (removeStyle === 'clear' ) {
54
+ $(link).closest(".fields").find('input').clearFields();
55
+ $(link).closest(".fields").find('select').clearFields();
56
+ $(link).closest(".fields").find('textarea').clearFields();
57
+ }
58
+ },
59
+
60
+ add_fields: function(link, association, content) {
61
+ var new_id = new Date().getTime(),
62
+ regexp1 = new RegExp("new_" + association, "g"),
63
+ regexp2 = new RegExp("new_nested_record", "g");
64
+
65
+ content = content.replace(regexp1, new_id);
66
+ content = content.replace(regexp2, 'new_nested_record_' + new_id);
67
+ $(link).closest("." + association).find('.nested_records_' + association).append(content);
68
+ }
69
+ };
@@ -0,0 +1,49 @@
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
+
4
+ Discerner.SearchCombination.UI = function (config) {
5
+ var dictionarySelector = $('.discerner_search_dictionary select#search_dictionary_id'),
6
+ selectedDictionaryOption = $(dictionarySelector).find('option:selected:last'),
7
+
8
+ setupCombinedSearches = function () {
9
+ var search_combinations = $('.search_combinations').find('.nested_records_search_combinations tr.search_combination'),
10
+ display_orders = search_combinations.find('input[name$="[display_order]"]'),
11
+ i = 0;
12
+
13
+ // set up predicate for selected searches
14
+ search_combinations.filter(':visible:not(:first)').find('.combined_search_operator span').html('and');
15
+
16
+ // get max display order
17
+ $.each(display_orders, function(){
18
+ var val = parseInt($(this).val());
19
+ if (val >= i) { i = val }
20
+ });
21
+
22
+ // assign display order to combined searches without it
23
+ $.each(display_orders, function(){
24
+ if ($(this).val().length == 0) {
25
+ i = i + 1
26
+ $(this).val(i);
27
+ }
28
+ })
29
+
30
+ // hide combined searches options that do not belong to selected dictionary
31
+ if (dictionarySelector.length > 0){
32
+ dictionary_class = $(dictionarySelector).find('option:selected:last').attr('class')
33
+ $('.search_combinations_combobox_autocompleter').find('option:not(.' + dictionary_class +'):not([value=""])').detach();
34
+ };
35
+
36
+ // setup autocompleters for newly added row
37
+ $(".search_combinations_combobox_autocompleter").combobox({watermark:'an existing search'});
38
+ };
39
+
40
+ searchCombinationNestedAttributesForm = new NestedAttributes({
41
+ container: $('.search_combinations'),
42
+ association: 'search_combinations',
43
+ content: config.searchCombinationsTemplate,
44
+ addHandler: setupCombinedSearches,
45
+ caller: this
46
+ });
47
+
48
+ setupCombinedSearches();
49
+ }
@@ -0,0 +1,131 @@
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
+
4
+ Discerner.SearchParameter.UI = function (config) {
5
+ var parametersUrl = new Discerner.Url(config.parametersUrl),
6
+ dictionarySelector = $('.discerner_search_dictionary select#search_dictionary_id'),
7
+ selectedDictionaryOption = $(dictionarySelector).find('option:selected:last'),
8
+
9
+ setupParameters = function () {
10
+ var search_parameters = $('.search_parameters').find('.nested_records_search_parameters tr.search_parameter'),
11
+ display_orders = search_parameters.find('input:not([name*="search_parameter_values_attributes"])[name$="[display_order]"]'),
12
+ i = 0;
13
+
14
+ search_parameters.filter(':visible:not(:first)').find('.parameter_boolean_operator span').html('and');
15
+
16
+ // remove parameter options that do not belong to selected dictionary
17
+ if (dictionarySelector.length > 0){
18
+ dictionary_class = $(dictionarySelector).find('option:selected:last').attr('class');
19
+ $.each($('div.parameter_category'), function(){
20
+ if (!$(this).hasClass(dictionary_class)) {
21
+ $(this).remove();
22
+ }
23
+ });
24
+ $.each($('select.parameters_combobox_autocompleter option'), function(){
25
+ if (!($(this).hasClass(dictionary_class) || $(this).val() == '')) {
26
+ $(this).remove();
27
+ }
28
+ });
29
+ };
30
+ $(".parameters_combobox_autocompleter").combobox({watermark:'a criteria'});
31
+
32
+ // get max display order
33
+ $.each(display_orders, function(){
34
+ var val = parseInt($(this).val());
35
+ if (val >= i) { i = val }
36
+ });
37
+
38
+ // assign display order to search predicates without it
39
+ $.each(display_orders, function(){
40
+ if ($(this).val().length == 0) {
41
+ i = i + 1
42
+ $(this).val(i);
43
+ }
44
+ })
45
+ },
46
+ searchParametersNestedAttributesForm = new NestedAttributes({
47
+ container: $('.search_parameters'),
48
+ association: 'search_parameters',
49
+ content: config.searchParametersTemplate,
50
+ addHandler: setupParameters,
51
+ caller: this
52
+ });
53
+
54
+ // handle criteria autocompleter button click
55
+ $(document).on('click', '.parameter .categorized_autocompleter_link', function () {
56
+ var popup = $(this).siblings('.div-category-popup'),
57
+ select = $(this).siblings('select').first(),
58
+ // get all the "sibling" dropdowns
59
+ sibling_selects = $('select.' + select.attr('class')).filter(function(){
60
+ return $(this).closest('tr').find('td.remove input[name$="[_destroy]"]:not([name*="[search_parameter_values_attributes]"])').filter(function() { return this.value === '1'; }).length == 0 // exclude rows marked for destroy
61
+ }),
62
+ // get all selected parameter options from sibling selects
63
+ matching_selected_options = sibling_selects.find('option.exclusive:selected');
64
+ // match selected options from sibling selects with the source select options
65
+ // (they will have different base ids for each set but same value)
66
+ popup.find('.criteria a.categorized_autocompleter_item_link').removeClass('selection_disabled');
67
+ $.each(matching_selected_options, function(){
68
+ option = select.find('option[value=' + $(this).val() + ']');
69
+ popup.find('.parameter_category .criteria a.categorized_autocompleter_item_link[rel="' + $(option).attr('id') + '"]').addClass('selection_disabled');
70
+ })
71
+ toggleCategorizedAutocompleterPopup(this);
72
+ toggleCategorizedAutocompleterPopup($(this).closest('.search_parameter').find('.parameter_value a.expanded_categorized_autocompleter_link'));
73
+ });
74
+
75
+ // handle criteria popup list link click
76
+ $(document).on('click', '.parameter .categorized_autocompleter_item_link:not(.selection_disabled)', function () {
77
+ var autocompleter = $(this).parents('.categorized_autocompleter').find('select.parameters_combobox_autocompleter'),
78
+ categorizedItemEl = document.getElementById($(this).attr('rel'));
79
+ categorizedAutocompleterLink = $(this).parents('.categorized_autocompleter').find('.categorized_autocompleter_link');
80
+ autocompleter.combobox('setValue', categorizedItemEl.text);
81
+ autocompleter.change();
82
+ toggleCategorizedAutocompleterPopup(categorizedAutocompleterLink);
83
+ });
84
+
85
+ // toggle criteria popup
86
+ var toggleCategorizedAutocompleterPopup = function (link) {
87
+ var popup = $(link).parents('.categorized_autocompleter').find('.div-category-popup');
88
+ if ($(link).hasClass('collapsed_categorized_autocompleter_link')) {
89
+ popup.show();
90
+ $(link).removeClass('collapsed_categorized_autocompleter_link');
91
+ $(link).addClass('expanded_categorized_autocompleter_link');
92
+ }
93
+ else {
94
+ popup.hide();
95
+ $(link).removeClass('expanded_categorized_autocompleter_link');
96
+ $(link).addClass('collapsed_categorized_autocompleter_link');
97
+ }
98
+ };
99
+
100
+ // handle changing selections for criteria autocompleter
101
+ $(document).on('change', '.parameter select.parameters_combobox_autocompleter', function () {
102
+ var that = this,
103
+ predicate = $(that).closest('.search_parameter'),
104
+ selected_option = $(that).find('option:selected:last'),
105
+ add_button = $(predicate).find('a.add_search_parameter_values');
106
+
107
+ $(predicate).find('.nested_records_search_parameter_values .search_parameter_value .delete_search_parameter_values').click();
108
+ if ($(selected_option).length == 0 || $(selected_option).val() == ''){
109
+ $(add_button).hide();
110
+ }
111
+ else if ($(selected_option).hasClass('list')){
112
+ $($(predicate).find('.tmp_link')).remove();
113
+ console.log(parametersUrl.sub({ question_id: this.value }))
114
+ $.get(parametersUrl.sub({ question_id: this.value }), function (data) {
115
+ $.each(data.parameter_values, function() {
116
+ $(add_button).click();
117
+ var row = $(predicate).find('.nested_records_search_parameter_values .search_parameter_value').filter(':last');
118
+ row.find('.parameter_value span').text(this.name);
119
+ row.find('.parameter_value_id').val(this.parameter_value_id);
120
+ $(add_button).hide();
121
+ });
122
+ });
123
+ } else {
124
+ $(add_button).show();
125
+ $(add_button).click();
126
+ }
127
+ });
128
+
129
+ setupParameters();
130
+ };
131
+
@@ -0,0 +1,172 @@
1
+ Discerner.SearchParameterValue.UI = function (config) {
2
+ var that = this,
3
+ parametersUrl = new Discerner.Url(config.parametersUrl),
4
+ hideValue = function(e){
5
+ if (!$(e).hasClass('invisible')){
6
+ $(e).addClass('invisible');
7
+ }
8
+ };
9
+ showValue = function(e){
10
+ if ($(e).hasClass('invisible')){
11
+ $(e).removeClass('invisible');
12
+ }
13
+ };
14
+ setupOperator = function(o){
15
+ var row = $(o).closest('tr');
16
+ option = $(o).find('option:selected');
17
+ if (option.hasClass('range')){
18
+ showValue($(row).find('.additional_value'));
19
+ } else {
20
+ hideValue($(row).find('.additional_value'));
21
+ }
22
+ if (option.hasClass('presence')){
23
+ hideValue($(row).find('.value'));
24
+ } else {
25
+ showValue($(row).find('.value'));
26
+ }
27
+ },
28
+ setupParameterValues = function(){
29
+ var row = $(config.container).find('.nested_records_search_parameter_values .search_parameter_value').last(),
30
+ selectedParameter = $(config.container).find('select.parameters_combobox_autocompleter option:selected:last');
31
+
32
+ row.find('td').hide();
33
+ hideValue($(row).find('.additional_value').show());
34
+ row.find('.parameter_values_boolean_operator').show();
35
+
36
+ if ($(selectedParameter).hasClass('list')) { // list parameters
37
+ row.find('.chosen, .parameter_value').show();
38
+ $(config.container).find('a.add_search_parameter_values').hide();
39
+ $(config.container).find('.additional_value').hide();
40
+ } else if ($(selectedParameter).hasClass('combobox')) { // combobox parameters
41
+ var input = $(row).find('input.parameter_value_id');
42
+ $(config.container).find('.additional_value').hide();
43
+ if (input.length > 0) {
44
+ $.get( parametersUrl.sub({ question_id: selectedParameter.val(), search_parameter_value_id: input.closest('tr.search_parameter_value').attr('id') }), function( data ) {
45
+ container = $(input).closest('td');
46
+ $(input).detach();
47
+ container.append( data );
48
+ container.find('select').attr('id', input.attr('id')).attr('name', input.attr('name')).combobox({ watermark:'a value'});
49
+ handleParameterValuelPopupListClick(row);
50
+ handleParameterValueAutocompleterButtonLink(row);
51
+ });
52
+ }
53
+ $(config.container).find('.parameter_value, .remove').show();
54
+ $(config.container).find('a.add_search_parameter_values').show();
55
+ } else { // date, text and numeric parameters
56
+ var parameter_classes = ['date', 'numeric', 'text', 'string'];
57
+ for (var i in parameter_classes) {
58
+ if ($(selectedParameter).hasClass(parameter_classes[i])) {
59
+ row.find('.operator option:not(.' + parameter_classes[i] +')').detach();
60
+ row.find('.operator, .value, .remove').show();
61
+ $(config.container).find('a.add_search_parameter_values').show();
62
+ if (parameter_classes[i] == 'date') {
63
+ row.find('.value input, .additional_value input').addClass('datepicker');
64
+ }
65
+ }
66
+ }
67
+ }
68
+ $(config.container).find('.nested_records_search_parameter_values tr.search_parameter_value:visible:not(:first)')
69
+ .find('.parameter_values_boolean_operator span').html('or');
70
+
71
+ var i = 0,
72
+ display_orders = config.container.find('input[name*="search_parameter_values_attributes"][name$="[display_order]"]');
73
+
74
+ // get max display order
75
+ $.each(display_orders, function(){
76
+ var val = parseInt($(this).val());
77
+ if (val >= i) { i = val }
78
+ });
79
+ // assign display order to search predicates without it
80
+ $.each(display_orders, function(){
81
+ if ($(this).val().length == 0) {
82
+ i = i + 1
83
+ $(this).val(i);
84
+ }
85
+ });
86
+ $(config.container).find(".parameter_values_combobox_autocompleter").combobox({watermark:'a value'});
87
+ },
88
+ searchParameterValuesNestedAttributesForm = new NestedAttributes({
89
+ container: config.container,
90
+ association: 'search_parameter_values',
91
+ content: config.searchParameterValuesTemplate,
92
+ addHandler: setupParameterValues,
93
+ caller: this
94
+ });
95
+
96
+ // toggle parameter value popup
97
+ var toggleCategorizedAutocompleterPopup = function (link) {
98
+ var popup = $(link).parents('.categorized_autocompleter').find('.div-category-popup');
99
+ if ($(link).hasClass('collapsed_categorized_autocompleter_link')) {
100
+ popup.show();
101
+ $(link).removeClass('collapsed_categorized_autocompleter_link');
102
+ $(link).addClass('expanded_categorized_autocompleter_link');
103
+ }
104
+ else {
105
+ popup.hide();
106
+ $(link).removeClass('expanded_categorized_autocompleter_link');
107
+ $(link).addClass('collapsed_categorized_autocompleter_link');
108
+ }
109
+ };
110
+
111
+ // handle parameter value autocompleter button click
112
+ var handleParameterValueAutocompleterButtonLink = function(container){
113
+ $(container).find('.parameter_value .categorized_autocompleter_link').on('click', function(){
114
+ var popup = $(this).siblings('.div-category-popup'),
115
+ select = $(this).siblings('select').first(),
116
+ // get all the "sibling" dropdowns
117
+ sibling_selects = $('select.' + select.attr('class')).filter(function(){
118
+ return $(this).closest('tr').find('td.remove input[name$="[_destroy]"]:not([name*="[search_parameter_values_attributes]"])').filter(function() { return this.value === '1'; }).length == 0 // exclude rows marked for destroy
119
+ }),
120
+ // get all selected parameter options from sibling selects
121
+ matching_selected_options = sibling_selects.find('option.exclusive:selected');
122
+ // match selected options from sibling selects with the source select options
123
+ // (they will have different base ids for each set but same value)
124
+ popup.find('.parameter value a.categorized_autocompleter_item_link').removeClass('selection_disabled');
125
+ $.each(matching_selected_options, function(){
126
+ option = select.find('option[value=' + $(this).val() + ']');
127
+ popup.find('.search_parameter .parameter value a.categorized_autocompleter_item_link[rel="' + $(option).attr('id') + '"]').addClass('selection_disabled');
128
+ })
129
+ toggleCategorizedAutocompleterPopup(this);
130
+ toggleCategorizedAutocompleterPopup($(this).closest('.search_parameter').find('.parameter a.expanded_categorized_autocompleter_link'));
131
+ });
132
+ }
133
+
134
+ // handle parameter value popup list link click
135
+ var handleParameterValuelPopupListClick = function(container) {
136
+ $(container).find('.parameter_value .categorized_autocompleter_item_link:not(.selection_disabled)').on('click', function(e){
137
+ e.preventDefault();
138
+ var autocompleter = $(this).parents('.categorized_autocompleter').find('select.parameter_values_combobox_autocompleter'),
139
+ categorizedItemEl = document.getElementById($(this).attr('rel'));
140
+ categorizedAutocompleterLink = $(this).parents('.categorized_autocompleter').find('.categorized_autocompleter_link');
141
+ autocompleter.combobox('setValue', categorizedItemEl.text);
142
+ autocompleter.change();
143
+ toggleCategorizedAutocompleterPopup(categorizedAutocompleterLink);
144
+ });
145
+ }
146
+
147
+ setupParameterValues();
148
+ handleParameterValuelPopupListClick(config.container);
149
+ handleParameterValueAutocompleterButtonLink(config.container);
150
+
151
+ $.each($('.operator'), function() { setupOperator(this); });
152
+
153
+ $(document).on('change', '.operator select', function(){
154
+ setupOperator(this);
155
+ });
156
+
157
+ $(document).on('click', '.show-category-items', function(e) {
158
+ e.preventDefault();
159
+ $(this).closest('.categorized-parameter-values, .uncategorized-parameter-values').find('.category-items').show();
160
+ $(this).addClass('hide-category-items');
161
+ $(this).removeClass('show-category-items');
162
+ $(this).html('less')
163
+ });
164
+
165
+ $(document).on('click', '.hide-category-items', function(e) {
166
+ e.preventDefault();
167
+ $(this).closest('.categorized-parameter-values, .uncategorized-parameter-values').find('.category-items').hide();
168
+ $(this).addClass('show-category-items');
169
+ $(this).removeClass('hide-category-items');
170
+ $(this).html('more')
171
+ });
172
+ };
@@ -0,0 +1,93 @@
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
+
4
+ Discerner.Search.UI = function (config) {
5
+ var dictionarySelector = $('.discerner_search_dictionary select#search_dictionary_id'),
6
+ dictionaryContainer = $('.discerner_search_dictionary span'),
7
+ selectedDictionaryOption = $(dictionarySelector).find('option:selected:last');
8
+
9
+ var toggleControls = function() {
10
+ selectedDictionaryOption = $(dictionarySelector).find('option:selected:last');
11
+ if (dictionarySelector.length > 0 && selectedDictionaryOption.length == 0 || selectedDictionaryOption.val() == '') {
12
+ $('.search_parameters').hide();
13
+ $('.search_combinations').hide();
14
+ $('.discerner_dictionary_required_message').show();
15
+ } else {
16
+ $('.search_parameters').show();
17
+ $('.search_combinations').show();
18
+ $('.discerner_dictionary_required_message').hide();
19
+ }
20
+ }
21
+
22
+ // handle dictionary selection change
23
+ $(dictionarySelector).bind('change', function(){
24
+ $('a.delete_search_parameters').trigger('click');
25
+ $('a.delete_search_combinations').trigger('click');
26
+ toggleControls();
27
+ $('a.add_search_parameters').trigger('click');
28
+ $('a.add_search_combinations').trigger('click');
29
+ });
30
+
31
+ // block UI on form submit
32
+ $('#discerner_search_form form, #results form').bind('submit', function(){
33
+ $.blockUI({
34
+ title: 'Loading ... ',
35
+ message: '<p>Please be patient</p>',
36
+ fadeIn: 0,
37
+ timeout: 20000000,
38
+ showOverlay: true,
39
+ centerY: true,
40
+ theme: true
41
+ });
42
+ });
43
+
44
+ $(document).on('mouseover', '.datepicker', function() {
45
+ $(this).datepicker({
46
+ altFormat: 'yy-mm-dd',
47
+ dateFormat: 'yy-mm-dd',
48
+ changeMonth: true,
49
+ changeYear: true,
50
+ yearRange: config.yearRange
51
+ });
52
+ });
53
+
54
+ // handle search name editing
55
+ $('#discerner_search_form .discerner_search_name_edit a').bind('click', function(){
56
+ $(this).closest('span.discerner_search_name_edit').hide();
57
+ $(this).closest('span.discerner_search_name_edit').siblings('span.discerner_search_name').hide();
58
+ $(this).closest('div').append($('<span>').load(config.renameUrl + ' form').addClass('discerner_search_name_edit_dialog'));
59
+ return false;
60
+ });
61
+
62
+ // handle search name editing (submit the form)
63
+ $(document).on('click','#discerner_search_form .discerner_search_name_edit_dialog input[type="submit"]', function(){
64
+ var form = $(this).closest('form');
65
+ $.ajax({
66
+ type: form.attr('method'),
67
+ url: form.attr('action'),
68
+ data: form.serializeArray(),
69
+ dataType: 'script'
70
+ });
71
+
72
+ return false;
73
+ })
74
+
75
+ // handle cancel on search name editing
76
+ $(document).on('click', '#discerner_search_form .discerner_search_name_edit_dialog a.cancel', function() {
77
+ $('span.discerner_search_name_edit_dialog').siblings('span.discerner_search_name').show();
78
+ $('span.discerner_search_name_edit_dialog').siblings('span.discerner_search_name_edit').show();
79
+ $('span.discerner_search_name_edit_dialog').remove();
80
+ $("#messages").html('');
81
+ return false;
82
+ });
83
+
84
+ $(document).ready(function(){
85
+ if ((dictionarySelector.length == 0 || selectedDictionaryOption.length != 0) && ($('tr.search_parameter:visible').length == 0)){
86
+ $('a.add_search_parameters').trigger('click');
87
+ $('a.add_search_combinations').trigger('click');
88
+ }
89
+ });
90
+
91
+ toggleControls();
92
+ };
93
+
@@ -0,0 +1,42 @@
1
+ Discerner.Url = function (url) {
2
+ this.url = url;
3
+ };
4
+
5
+ Discerner.Url.prototype = {
6
+ sub: function (params) {
7
+ var url = this.url,
8
+ newUrl = this.url,
9
+ queryString = [],
10
+ encodedArg = undefined,
11
+ encodeParam = undefined,
12
+ param = undefined;
13
+
14
+ for (param in params) {
15
+ if (params.hasOwnProperty(param)) {
16
+ encodedParam = encodeURIComponent(param);
17
+ encodedArg = encodeURIComponent(params[param]);
18
+ newUrl = url.replace(':' + param, encodedArg);
19
+ if (url == newUrl) {
20
+ queryString.push(encodedParam + '=' + encodedArg);
21
+ }
22
+ url = newUrl;
23
+ }
24
+ }
25
+
26
+ if (queryString.length > 0) {
27
+ if (url.indexOf('?') > 0) {
28
+ return url + queryString.join('&');
29
+ } else {
30
+ return url + '?' + queryString.join('&');
31
+ }
32
+ } else {
33
+ return url;
34
+ }
35
+ },
36
+
37
+ parameters: function () {
38
+ return $.map(this.url.match(/:\w+/g) || [], function (o, i) {
39
+ return o.substring(1);
40
+ });
41
+ }
42
+ };
@@ -0,0 +1,16 @@
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 jquery.ui.autocomplete
13
+ *= require jquery.ui.datepicker
14
+ *= require jquery.ui.button
15
+ *= require_tree .
16
+ */
@@ -0,0 +1,13 @@
1
+ #discerner_searches, #discerner_search
2
+ div.discerner-buttons
3
+ :margin 1em 0
4
+
5
+ a.discerner-button-negative, button.discerner-button-negative, input.discerner-button-negative
6
+ :color #800000
7
+ :font-weight bold
8
+
9
+ a.discerner-button-positive, button.discerner-button-positive, input.discerner-button-positive
10
+ :color #529214
11
+ :font-weight bold
12
+
13
+
@@ -0,0 +1,53 @@
1
+ #discerner_searches, #discerner_search
2
+ .categorized_autocompleter_link, .categorized_autocompleter_link:hover
3
+ :padding 2px 20px 2px 2px
4
+ :text-decoration none !important
5
+
6
+ .collapsed_categorized_autocompleter_link, .collapsed_categorized_autocompleter_link:hover
7
+ :background url(bullet_arrow_down.png) 48px 2px no-repeat
8
+ .expanded_categorized_autocompleter_link, .expanded_categorized_autocompleter_link:hover
9
+ :background url(bullet_arrow_up.png) 48px 2px no-repeat
10
+
11
+ .div-category-popup
12
+ :position absolute
13
+ :z-index 1000
14
+ :background white
15
+
16
+ .div-category-list
17
+ :overflow auto
18
+
19
+ .category
20
+ :padding-bottom 5px
21
+ :padding-left 5px
22
+ :padding-right 5px
23
+ :padding-top 15px
24
+ :clear both
25
+
26
+ .category-name
27
+ :font-weight bold
28
+ :margin-bottom 0
29
+ :margin-left 0
30
+ :margin-right 0
31
+ :margin-top 0
32
+ :padding-bottom 0
33
+ :padding-left 0
34
+ :padding-right 0
35
+ :padding-top 0
36
+
37
+ .column
38
+ :float left
39
+ :margin-right 5px
40
+ :width 225px
41
+
42
+ .criteria
43
+ :margin-bottom 3px
44
+ :margin-left 0
45
+ :margin-right 0
46
+ :margin-top 3px
47
+
48
+ .categorized_autocompleter
49
+ :position relative
50
+
51
+ button.ui-button
52
+ :display none
53
+