From 057428a0f4d0d82b852b1dbf7442d6bce24dbba8 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Wed, 24 Jul 2013 21:47:10 -0700 Subject: [PATCH] Refactor search builder js to better handle different operators CRM-13032 --- templates/CRM/Contact/Form/Search/Builder.js | 277 ++++++++----------- 1 file changed, 121 insertions(+), 156 deletions(-) diff --git a/templates/CRM/Contact/Form/Search/Builder.js b/templates/CRM/Contact/Form/Search/Builder.js index e46ee5e80d..f1d0cdf1e4 100644 --- a/templates/CRM/Contact/Form/Search/Builder.js +++ b/templates/CRM/Contact/Form/Search/Builder.js @@ -1,74 +1,69 @@ // http://civicrm.org/licensing (function($, CRM) { - // @var: default select operator options - var operators, operatorCount; + 'use strict'; /** - * 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() { - var field = $(this).val(); + function handleUserInputField() { 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]) { removeSelect(row); } - if ($.inArray(field, CRM.searchBuilder.dateFields) < 0) { - removeDate(row); - if (CRM.searchBuilder.fieldOptions[field]) { - buildSelect(row, field); - } - } else { - buildDate(row); + buildSelect(row, field, op); } - } - /** - * Handle Search Operator Selection - */ - 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(''); - } - select.val(value).change(); - } + if ($.inArray(field, CRM.searchBuilder.dateFields) < 0) { + removeDate(row); } - // Hide value field if the operator doesn't take a value 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 field: string */ - function buildSelect(row, field) { - // Remove operators that can't be used with a select - removeOperators(row, ['LIKE', 'RLIKE']); - var op = $('select[id^=operator]', row); - if (op.val() == 'IN' || op.val() == 'NOT IN') { - var multiSelect = 'multiple="multiple">'; + function buildSelect(row, field, op) { + var multiSelect = ''; + // Operators that will get a single drop down list of choices. + var dropDownSingleOps = ['=', '!=']; + // Multiple select drop down list. + var dropDownMultipleOps = ['IN', 'NOT IN']; + + if ($.inArray(op, dropDownMultipleOps) > -1) { + multiSelect = 'multiple="multiple"'; } - else { - var multiSelect = '>'; + else if ($.inArray(op, dropDownSingleOps) < 0) { + // 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(); - $('input[id^=value]', row).hide().after(''); + fetchOptions(row, field); } @@ -117,9 +112,14 @@ value = value.slice(1, -1); } var options = value.split(','); - var op = $('select[id^=operator]', row); - if (op.val() != 'IN' && op.val() != 'NOT IN' && options.length > 1) { - options = [options[0]]; + if (select.attr('multiple') == 'multiple') { + select.find('option').remove(); + } + else { + select.find('option').text(ts('- select -')); + if (options.length > 1) { + options = [options[0]]; + } } $.each(CRM.searchBuilder.fieldOptions[field], function(value, label) { var selected = ($.inArray(value, options) > -1) ? 'selected="selected"' : ''; @@ -135,18 +135,20 @@ function removeSelect(row) { $('.crm-search-value input', row).show(); $('.crm-search-value select', row).remove(); - restoreOperators(row); } /** - * Add a datepicker + * Add a datepicker if appropriate for this operation * @param row: jQuery object */ - function buildDate(row) { + function buildDate(row, op) { var input = $('.crm-search-value input', row); - if (!input.hasClass('hasDatepicker')) { - // Remove operators that can't be used with a date - removeOperators(row, ['IN', 'NOT IN', 'LIKE', 'RLIKE', 'IS EMPTY', 'IS NOT EMPTY']); + // These are operations that should not get a datepicker + var datePickerOp = ($.inArray(op, ['IN', 'NOT IN', 'LIKE', 'RLIKE']) < 0); + if (!datePickerOp) { + removeDate(row); + } + else if (!input.hasClass('hasDatepicker')) { input.addClass('dateplugin').datepicker({ dateFormat: 'yymmdd', changeMonth: true, @@ -163,115 +165,78 @@ function removeDate(row) { var input = $('.crm-search-value input', row); if (input.hasClass('hasDatepicker')) { - restoreOperators(row); input.removeClass('dateplugin').val('').datepicker('destroy'); } } - /** - * Remove operators from a row - * @param row: jQuery object - * @param illegal: array - */ - function removeOperators(row, illegal) { - var value = $('select[id^=operator]').val(); - $('select[id^=operator] option', row).each(function() { - if ($.inArray($(this).attr('value'), illegal) > -1) { - $(this).remove(); - } - }); - 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(); - } + // Initialize display: Hide empty blocks & fields + var newBlock = CRM.searchBuilder && CRM.searchBuilder.newBlock || 0; + $('.crm-search-block', '#Builder').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 { - empty = false; + row.hide(); } - }); - if (empty) { - block.hide(); + } + else { + empty = false; } }); + if (empty) { + block.hide(); + } + }); - $('#Builder') - // Reset and hide row - .on('click', '.crm-reset-builder-row', function() { - var row = $(this).closest('tr'); - $('input, select', row).val('').change(); - row.hide(); - // Hide entire block if this is the only visible row - if (row.siblings(':visible').length < 2) { - row.closest('.crm-search-block').hide(); - } + $('#Builder') + // Reset and hide row + .on('click', '.crm-reset-builder-row', function() { + var row = $(this).closest('tr'); + $('input, select', row).val('').change(); + row.hide(); + // Hide entire block if this is the only visible row + if (row.siblings(':visible').length < 2) { + 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; - }) - // Add new field - if there's a hidden one, show it - // Otherwise we submit form to 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; - } - }) - // 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() { - if ($('.crm-search-block:hidden', '#Builder').length) { - var block = $('.crm-search-block:hidden', '#Builder').first(); - block.show(); - $('tr:first-child, tr.crm-search-builder-add-row', block).show(); - return false; - } - }) - // Handle field selection - .on('change', 'select[id^=mapper][id$="_1"]', handleFieldSelection) - // Handle operator selection - .on('change', 'select[id^=operator]', handleOperatorSelection) - // Handle option selection - update hidden value field - .on('change', '.crm-search-value select', function() { - 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); - }); + } + }) + // Add new block - if there's a hidden one, show it + // Otherwise allow form to submit and fetch more from the server + .on('click', '#addBlock', function() { + if ($('.crm-search-block:hidden', '#Builder').length) { + var block = $('.crm-search-block:hidden', '#Builder').first(); + block.show(); + $('tr:first-child, tr.crm-search-builder-add-row', block).show(); + return false; + } + }) + // Handle field and operator selection + .on('change', 'select[id^=mapper][id$="_1"], select[id^=operator]', handleUserInputField) + // Handle option selection - update hidden value field + .on('change', '.crm-search-value select', function() { + var value = $(this).val() || ''; + if ($(this).attr('multiple') == 'multiple' && value.length) { + value = '(' + value.join(',') + ')'; + } + $(this).siblings('input').val(value); + }) + ; + + $().crmAccordions(); + $('select[id^=mapper][id$="_1"]', '#Builder').each(handleUserInputField); })(cj, CRM); -- 2.25.1