discerner 1.1.18

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 (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
+