Skip to content
Snippets Groups Projects
Commit 24893775 authored by colemanw's avatar colemanw
Browse files

Merge pull request #1242 from colemanw/searchBuilderJs

Refactor search builder js to better handle different operators
parents 95d68223 057428a0
No related branches found
No related tags found
No related merge requests found
// http://civicrm.org/licensing // http://civicrm.org/licensing
(function($, CRM) { (function($, CRM) {
// @var: default select operator options 'use strict';
var operators, operatorCount;
/** /**
* Handle Field Selection * Handle user input - field or operator selection.
*
* Decide whether to display select drop down, regular text or date
* field for the given field and row.
*/ */
function handleFieldSelection() { function handleUserInputField() {
var field = $(this).val();
var row = $(this).closest('tr'); var row = $(this).closest('tr');
var field = $('select[id^=mapper][id$="_1"]', row).val();
var op = $('select[id^=operator]', row).val();
// These Ops don't get any input field.
var noFieldOps = ['', 'IS EMPTY', 'IS NOT EMPTY', 'IS NULL', 'IS NOT NULL'];
if ($.inArray(op, noFieldOps) > -1) {
// Hide the fields and return.
$('.crm-search-value', row).hide().find('input, select').val('');
return;
}
$('.crm-search-value', row).show();
if (!CRM.searchBuilder.fieldOptions[field]) { if (!CRM.searchBuilder.fieldOptions[field]) {
removeSelect(row); removeSelect(row);
} }
if ($.inArray(field, CRM.searchBuilder.dateFields) < 0) {
removeDate(row);
if (CRM.searchBuilder.fieldOptions[field]) {
buildSelect(row, field);
}
}
else { else {
buildDate(row); buildSelect(row, field, op);
} }
}
/** if ($.inArray(field, CRM.searchBuilder.dateFields) < 0) {
* Handle Search Operator Selection removeDate(row);
*/
function handleOperatorSelection() {
var noValue = ['', 'IS EMPTY', 'IS NOT EMPTY', 'IS NULL', 'IS NOT NULL'];
var row = $(this).closest('tr');
if ($.inArray($(this).val(), noValue) < 0) {
$('.crm-search-value', row).show();
// Change between multiselect and select when using "IN" operator
var select = $('.crm-search-value select', row);
if (select.length) {
var value = select.val() || '';
var multi = ($(this).val() == 'IN' || $(this).val() == 'NOT IN');
select.attr('multiple', multi);
if (multi) {
$('option[value=""]', select).remove();
}
else if ($('option[value=""]', select).length < 1) {
$(select).prepend('<option value="">' + ts('- select -') + '</option>');
}
select.val(value).change();
}
} }
// Hide value field if the operator doesn't take a value
else { else {
$('.crm-search-value', row).hide().find('input, select').val(''); buildDate(row, op);
} }
} }
/** /**
* Give user a list of options to choose from * Add select list if appropriate for this operation
* @param row: jQuery object * @param row: jQuery object
* @param field: string * @param field: string
*/ */
function buildSelect(row, field) { function buildSelect(row, field, op) {
// Remove operators that can't be used with a select var multiSelect = '';
removeOperators(row, ['LIKE', 'RLIKE']); // Operators that will get a single drop down list of choices.
var op = $('select[id^=operator]', row); var dropDownSingleOps = ['=', '!='];
if (op.val() == 'IN' || op.val() == 'NOT IN') { // Multiple select drop down list.
var multiSelect = 'multiple="multiple">'; var dropDownMultipleOps = ['IN', 'NOT IN'];
if ($.inArray(op, dropDownMultipleOps) > -1) {
multiSelect = 'multiple="multiple"';
} }
else { else if ($.inArray(op, dropDownSingleOps) < 0) {
var multiSelect = '><option value="">' + ts('- select -') + '</option>'; // If this op is neither supported by single or multiple selects, then we should not render a select list.
removeSelect(row);
return;
} }
$('.crm-search-value select', row).remove(); $('.crm-search-value select', row).remove();
$('input[id^=value]', row).hide().after('<select class="form-select required" ' + multiSelect + '</select>'); $('input[id^=value]', row)
.hide()
.after('<select class="form-select required" ' + multiSelect + '><option value="">' + ts('Loading') + '...</option></select>');
fetchOptions(row, field); fetchOptions(row, field);
} }
...@@ -117,9 +112,14 @@ ...@@ -117,9 +112,14 @@
value = value.slice(1, -1); value = value.slice(1, -1);
} }
var options = value.split(','); var options = value.split(',');
var op = $('select[id^=operator]', row); if (select.attr('multiple') == 'multiple') {
if (op.val() != 'IN' && op.val() != 'NOT IN' && options.length > 1) { select.find('option').remove();
options = [options[0]]; }
else {
select.find('option').text(ts('- select -'));
if (options.length > 1) {
options = [options[0]];
}
} }
$.each(CRM.searchBuilder.fieldOptions[field], function(value, label) { $.each(CRM.searchBuilder.fieldOptions[field], function(value, label) {
var selected = ($.inArray(value, options) > -1) ? 'selected="selected"' : ''; var selected = ($.inArray(value, options) > -1) ? 'selected="selected"' : '';
...@@ -135,18 +135,20 @@ ...@@ -135,18 +135,20 @@
function removeSelect(row) { function removeSelect(row) {
$('.crm-search-value input', row).show(); $('.crm-search-value input', row).show();
$('.crm-search-value select', row).remove(); $('.crm-search-value select', row).remove();
restoreOperators(row);
} }
/** /**
* Add a datepicker * Add a datepicker if appropriate for this operation
* @param row: jQuery object * @param row: jQuery object
*/ */
function buildDate(row) { function buildDate(row, op) {
var input = $('.crm-search-value input', row); var input = $('.crm-search-value input', row);
if (!input.hasClass('hasDatepicker')) { // These are operations that should not get a datepicker
// Remove operators that can't be used with a date var datePickerOp = ($.inArray(op, ['IN', 'NOT IN', 'LIKE', 'RLIKE']) < 0);
removeOperators(row, ['IN', 'NOT IN', 'LIKE', 'RLIKE', 'IS EMPTY', 'IS NOT EMPTY']); if (!datePickerOp) {
removeDate(row);
}
else if (!input.hasClass('hasDatepicker')) {
input.addClass('dateplugin').datepicker({ input.addClass('dateplugin').datepicker({
dateFormat: 'yymmdd', dateFormat: 'yymmdd',
changeMonth: true, changeMonth: true,
...@@ -163,115 +165,78 @@ ...@@ -163,115 +165,78 @@
function removeDate(row) { function removeDate(row) {
var input = $('.crm-search-value input', row); var input = $('.crm-search-value input', row);
if (input.hasClass('hasDatepicker')) { if (input.hasClass('hasDatepicker')) {
restoreOperators(row);
input.removeClass('dateplugin').val('').datepicker('destroy'); input.removeClass('dateplugin').val('').datepicker('destroy');
} }
} }
/** // Initialize display: Hide empty blocks & fields
* Remove operators from a row var newBlock = CRM.searchBuilder && CRM.searchBuilder.newBlock || 0;
* @param row: jQuery object $('.crm-search-block', '#Builder').each(function(blockNo) {
* @param illegal: array var block = $(this);
*/ var empty = blockNo + 1 > newBlock;
function removeOperators(row, illegal) { var skippedRow = false;
var value = $('select[id^=operator]').val(); $('tr:not(.crm-search-builder-add-row)', block).each(function(rowNo) {
$('select[id^=operator] option', row).each(function() { var row = $(this);
if ($.inArray($(this).attr('value'), illegal) > -1) { if ($('select:first', row).val() === '') {
$(this).remove(); if (!skippedRow && (rowNo == 0 || blockNo + 1 == newBlock)) {
} skippedRow = true;
});
if (value !== $('select[id^=operator]').val()) {
$('select[id^=operator]').change();
}
}
/**
* Restore operators to the default
* @param row: jQuery object
*/
function restoreOperators(row) {
var op = $('select[id^=operator]', row);
if ($('option', op).length != operatorCount) {
var value = op.val();
op.html(operators).val(value).change();
}
}
$('document').ready(function() {
operators = $('#operator_1_0').html();
operatorCount = $('#operator_1_0 option').length;
// Hide empty blocks & fields
var newBlock = CRM.searchBuilder && CRM.searchBuilder.newBlock || 0;
$('#Builder .crm-search-block').each(function(blockNo) {
var block = $(this);
var empty = blockNo + 1 > newBlock;
var skippedRow = false;
$('tr:not(.crm-search-builder-add-row)', block).each(function(rowNo) {
var row = $(this);
if ($('select:first', row).val() === '') {
if (!skippedRow && (rowNo == 0 || blockNo + 1 == newBlock)) {
skippedRow = true;
}
else {
row.hide();
}
} }
else { else {
empty = false; row.hide();
} }
}); }
if (empty) { else {
block.hide(); empty = false;
} }
}); });
if (empty) {
block.hide();
}
});
$('#Builder') $('#Builder')
// Reset and hide row // Reset and hide row
.on('click', '.crm-reset-builder-row', function() { .on('click', '.crm-reset-builder-row', function() {
var row = $(this).closest('tr'); var row = $(this).closest('tr');
$('input, select', row).val('').change(); $('input, select', row).val('').change();
row.hide(); row.hide();
// Hide entire block if this is the only visible row // Hide entire block if this is the only visible row
if (row.siblings(':visible').length < 2) { if (row.siblings(':visible').length < 2) {
row.closest('.crm-search-block').hide(); row.closest('.crm-search-block').hide();
} }
return false;
})
// Add new field - if there's a hidden one, show it
// Otherwise allow form to submit and fetch more from the server
.on('click', 'input[name^=addMore]', function() {
var table = $(this).closest('table');
if ($('tr:hidden', table).length) {
$('tr:hidden', table).first().show();
return false; return false;
}) }
// Add new field - if there's a hidden one, show it })
// Otherwise we submit form to fetch more from the server // Add new block - if there's a hidden one, show it
.on('click', 'input[name^=addMore]', function() { // Otherwise allow form to submit and fetch more from the server
var table = $(this).closest('table'); .on('click', '#addBlock', function() {
if ($('tr:hidden', table).length) { if ($('.crm-search-block:hidden', '#Builder').length) {
$('tr:hidden', table).first().show(); var block = $('.crm-search-block:hidden', '#Builder').first();
return false; block.show();
} $('tr:first-child, tr.crm-search-builder-add-row', block).show();
}) return false;
// Add new block - if there's a hidden one, show it }
// Otherwise we submit form to fetch more from the server })
.on('click', '#addBlock', function() { // Handle field and operator selection
if ($('.crm-search-block:hidden', '#Builder').length) { .on('change', 'select[id^=mapper][id$="_1"], select[id^=operator]', handleUserInputField)
var block = $('.crm-search-block:hidden', '#Builder').first(); // Handle option selection - update hidden value field
block.show(); .on('change', '.crm-search-value select', function() {
$('tr:first-child, tr.crm-search-builder-add-row', block).show(); var value = $(this).val() || '';
return false; if ($(this).attr('multiple') == 'multiple' && value.length) {
} value = '(' + value.join(',') + ')';
}) }
// Handle field selection $(this).siblings('input').val(value);
.on('change', 'select[id^=mapper][id$="_1"]', handleFieldSelection) })
// Handle operator selection ;
.on('change', 'select[id^=operator]', handleOperatorSelection)
// Handle option selection - update hidden value field $().crmAccordions();
.on('change', '.crm-search-value select', function() { $('select[id^=mapper][id$="_1"]', '#Builder').each(handleUserInputField);
var value = $(this).val() || '';
if ($(this).attr('multiple') == 'multiple' && value.length) {
value = '(' + value.join(',') + ')';
}
$(this).siblings('input').val(value);
})
;
$('select[id^=operator]', '#Builder').each(handleOperatorSelection);
$().crmAccordions();
$('select[id^=mapper][id$="_1"] option[selected=selected]:not([value=""])', '#Builder').parent().each(handleFieldSelection);
});
})(cj, CRM); })(cj, CRM);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment