1 // http://civicrm.org/licensing
5 /* jshint validthis: true */
7 * Handle user input - field or operator selection.
9 * Decide whether to display select drop down, regular text or date
10 * field for the given field and row.
12 function handleUserInputField() {
13 var row
= $(this).closest('tr');
14 var field
= $('select[id^=mapper][id$="_1"]', row
).val();
15 var op
= $('select[id^=operator]', row
).val();
17 // These Ops don't get any input field.
18 var noFieldOps
= ['', 'IS EMPTY', 'IS NOT EMPTY', 'IS NULL', 'IS NOT NULL'];
20 if ($.inArray(op
, noFieldOps
) > -1) {
21 // Hide the fields and return.
22 $('.crm-search-value', row
).hide().find('input, select').val('');
25 $('.crm-search-value', row
).show();
27 if (!CRM
.searchBuilder
.fieldOptions
[field
]) {
31 buildSelect(row
, field
, op
);
34 if ($.inArray(field
, CRM
.searchBuilder
.dateFields
) < 0) {
43 * Add select list if appropriate for this operation
44 * @param row: jQuery object
45 * @param field: string
47 function buildSelect(row
, field
, op
) {
49 // Operators that will get a single drop down list of choices.
50 var dropDownSingleOps
= ['=', '!='];
51 // Multiple select drop down list.
52 var dropDownMultipleOps
= ['IN', 'NOT IN'];
54 if ($.inArray(op
, dropDownMultipleOps
) > -1) {
55 multiSelect
= 'multiple="multiple"';
57 else if ($.inArray(op
, dropDownSingleOps
) < 0) {
58 // If this op is neither supported by single or multiple selects, then we should not render a select list.
63 $('.crm-search-value select', row
).remove();
64 $('input[id^=value]', row
)
66 .after('<select class="crm-form-' + multiSelect
.substr(0, 5) + 'select required" ' + multiSelect
+ '><option value="">' + ts('Loading') + '...</option></select>');
68 fetchOptions(row
, field
);
72 * Retrieve option list for given row
73 * @param row: jQuery object
74 * @param field: string
76 function fetchOptions(row
, field
) {
77 if (CRM
.searchBuilder
.fieldOptions
[field
] === 'yesno') {
78 CRM
.searchBuilder
.fieldOptions
[field
] = [{key
: 1, value
: ts('Yes')}, {key
: 0, value
: ts('No')}];
80 if (typeof(CRM
.searchBuilder
.fieldOptions
[field
]) == 'string') {
81 CRM
.api(CRM
.searchBuilder
.fieldOptions
[field
], 'getoptions', {field
: field
, sequential
: 1}, {
82 success: function(result
, settings
) {
83 var field
= settings
.field
;
85 CRM
.searchBuilder
.fieldOptions
[field
] = result
.values
;
86 buildOptions(settings
.row
, field
);
89 removeSelect(settings
.row
);
92 error: function(result
, settings
) {
93 removeSelect(settings
.row
);
100 buildOptions(row
, field
);
105 * Populate option list for given row
106 * @param row: jQuery object
107 * @param field: string
109 function buildOptions(row
, field
) {
110 var select
= $('.crm-search-value select', row
);
111 var value
= $('input[id^=value]', row
).val();
112 if (value
.length
&& value
.charAt(0) == '(' && value
.charAt(value
.length
- 1) == ')') {
113 value
= value
.slice(1, -1);
115 var options
= value
.split(',');
116 if (select
.attr('multiple') == 'multiple') {
117 select
.find('option').remove();
120 select
.find('option').text(ts('- select -'));
121 if (options
.length
> 1) {
122 options
= [options
[0]];
125 $.each(CRM
.searchBuilder
.fieldOptions
[field
], function(key
, option
) {
126 var selected
= ($.inArray(''+option
.key
, options
) > -1) ? 'selected="selected"' : '';
127 select
.append('<option value="' + option
.key
+ '"' + selected
+ '>' + option
.value
+ '</option>');
133 * Remove select options and restore input to a plain textfield
134 * @param row: jQuery object
136 function removeSelect(row
) {
137 $('.crm-search-value input', row
).show();
138 $('.crm-search-value select', row
).remove();
142 * Add a datepicker if appropriate for this operation
143 * @param row: jQuery object
145 function buildDate(row
, op
) {
146 var input
= $('.crm-search-value input', row
);
147 // These are operations that should not get a datepicker
148 var datePickerOp
= ($.inArray(op
, ['IN', 'NOT IN', 'LIKE', 'RLIKE']) < 0);
152 else if (!input
.hasClass('hasDatepicker')) {
153 input
.addClass('dateplugin').datepicker({
154 dateFormat
: 'yymmdd',
157 yearRange
: '-100:+20'
164 * @param row: jQuery object
166 function removeDate(row
) {
167 var input
= $('.crm-search-value input', row
);
168 if (input
.hasClass('hasDatepicker')) {
169 input
.removeClass('dateplugin').val('').datepicker('destroy');
173 // Initialize display: Hide empty blocks & fields
174 var newBlock
= CRM
.searchBuilder
&& CRM
.searchBuilder
.newBlock
|| 0;
175 function initialize() {
176 $('.crm-search-block', '#Builder').each(function(blockNo
) {
178 var empty
= blockNo
+ 1 > newBlock
;
179 var skippedRow
= false;
180 $('tr:not(.crm-search-builder-add-row)', block
).each(function(rowNo
) {
182 if ($('select:first', row
).val() === '') {
183 if (!skippedRow
&& (rowNo
=== 0 || blockNo
+ 1 == newBlock
)) {
201 $('#crm-main-content-wrapper')
202 // Reset and hide row
203 .on('click', '.crm-reset-builder-row', function() {
204 var row
= $(this).closest('tr');
205 $('input, select', row
).val('').change();
207 // Hide entire block if this is the only visible row
208 if (row
.siblings(':visible').length
< 2) {
209 row
.closest('.crm-search-block').hide();
213 // Add new field - if there's a hidden one, show it
214 // Otherwise allow form to submit and fetch more from the server
215 .on('click', 'input[name^=addMore]', function() {
216 var table
= $(this).closest('table');
217 if ($('tr:hidden', table
).length
) {
218 $('tr:hidden', table
).first().show();
222 // Add new block - if there's a hidden one, show it
223 // Otherwise allow form to submit and fetch more from the server
224 .on('click', '#addBlock', function() {
225 if ($('.crm-search-block:hidden', '#Builder').length
) {
226 var block
= $('.crm-search-block:hidden', '#Builder').first();
228 $('tr:first-child, tr.crm-search-builder-add-row', block
).show();
232 // Handle field and operator selection
233 .on('change', 'select[id^=mapper][id$="_1"], select[id^=operator]', handleUserInputField
)
234 // Handle option selection - update hidden value field
235 .on('change', '.crm-search-value select', function() {
236 var value
= $(this).val() || '';
237 if ($(this).attr('multiple') == 'multiple' && value
.length
) {
238 value
= value
.join(',');
240 $(this).siblings('input').val(value
);
242 .on('crmLoad', function() {
244 $('select[id^=mapper][id$="_1"]', '#Builder').each(handleUserInputField
);
249 // Fetch initial options during page refresh - it's more efficient to bundle them in a single ajax request
250 var initialFields
= {}, fetchFields
= false;
251 $('select[id^=mapper][id$="_1"] option:selected', '#Builder').each(function() {
252 var field
= $(this).attr('value');
253 if (typeof(CRM
.searchBuilder
.fieldOptions
[field
]) == 'string') {
254 initialFields
[field
] = [CRM
.searchBuilder
.fieldOptions
[field
], 'getoptions', {field
: field
, sequential
: 1}];
259 CRM
.api3(initialFields
).done(function(data
) {
260 $.each(data
, function(field
, result
) {
261 CRM
.searchBuilder
.fieldOptions
[field
] = result
.values
;
263 $('select[id^=mapper][id$="_1"]', '#Builder').each(handleUserInputField
);
266 $('select[id^=mapper][id$="_1"]', '#Builder').each(handleUserInputField
);