| 1 | // https://civicrm.org/licensing |
| 2 | jQuery(function($) { |
| 3 | $('body') |
| 4 | // Enable administrators to edit option lists in a dialog |
| 5 | .on('click', 'a.crm-option-edit-link', CRM.popup) |
| 6 | .on('crmPopupFormSuccess', 'a.crm-option-edit-link', function() { |
| 7 | $(this).trigger('crmOptionsEdited'); |
| 8 | var optionEditPath = $(this).data('option-edit-path'); |
| 9 | var $selects = $('select[data-option-edit-path="' + optionEditPath + '"]'); |
| 10 | var $inputs = $('input[data-option-edit-path="' + optionEditPath + '"]'); |
| 11 | var $radios = $inputs.filter('[type=radio]'); |
| 12 | var $checkboxes = $inputs.filter('[type=checkbox]'); |
| 13 | |
| 14 | if ($selects.length > 0) { |
| 15 | rebuildOptions($selects, CRM.utils.setOptions); |
| 16 | } |
| 17 | else if ($radios.length > 0) { |
| 18 | rebuildOptions($radios, rebuildRadioOptions); |
| 19 | } |
| 20 | else if ($checkboxes.length > 0) { |
| 21 | rebuildOptions($checkboxes, rebuildCheckboxOptions); |
| 22 | } |
| 23 | }); |
| 24 | |
| 25 | /** |
| 26 | * Fetches options using metadata from the existing ones and calls the |
| 27 | * function to rebuild them |
| 28 | * @param $existing {object} The existing options, used as metadata store |
| 29 | * @param rebuilder {function} Function to be called to rebuild the options |
| 30 | */ |
| 31 | function rebuildOptions($existing, rebuilder) { |
| 32 | if ($existing.data('api-entity') && $existing.data('api-field')) { |
| 33 | var params = { |
| 34 | sequential: 1, |
| 35 | field: $existing.data('api-field') |
| 36 | }; |
| 37 | $.extend(params, $existing.data('option-edit-context')); |
| 38 | |
| 39 | CRM.api3($existing.data('api-entity'), 'getoptions', params) |
| 40 | .done(function(data) { |
| 41 | rebuilder($existing, data.values); |
| 42 | }); |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * Rebuild checkbox input options, overwriting the existing options |
| 48 | * |
| 49 | * @param $existing {object} the existing checkbox options |
| 50 | * @param newOptions {array} in format returned by api.getoptions |
| 51 | */ |
| 52 | function rebuildCheckboxOptions($existing, newOptions) { |
| 53 | var $parent = $existing.first().parent(), |
| 54 | $firstExisting = $existing.first(), |
| 55 | optionName = $firstExisting.attr('name'), |
| 56 | optionAttributes = |
| 57 | 'data-option-edit-path =' + $firstExisting.data('option-edit-path') + |
| 58 | ' data-api-entity = ' + $firstExisting.data('api-entity') + |
| 59 | ' data-api-field = ' + $firstExisting.data('api-field'); |
| 60 | |
| 61 | var prefix = optionName.substr(0, optionName.lastIndexOf("[")); |
| 62 | |
| 63 | var checkedBoxes = []; |
| 64 | $parent.find('input:checked').each(function() { |
| 65 | checkedBoxes.push($(this).attr('id')); |
| 66 | }); |
| 67 | |
| 68 | // remove existing checkboxes |
| 69 | $parent.find('input[type=checkbox]').remove(); |
| 70 | |
| 71 | // find existing labels for the checkboxes |
| 72 | var $checkboxLabels = $parent.find('label').filter(function() { |
| 73 | var forAttr = $(this).attr('for') || ''; |
| 74 | |
| 75 | return forAttr.indexOf(prefix) !== -1; |
| 76 | }); |
| 77 | |
| 78 | // find what is used to separate the elements; spaces or linebreaks |
| 79 | var $elementAfterLabel = $checkboxLabels.first().next(); |
| 80 | var separator = $elementAfterLabel.is('br') ? '<br/>' : ' '; |
| 81 | |
| 82 | // remove existing labels |
| 83 | $checkboxLabels.remove(); |
| 84 | |
| 85 | // remove linebreaks in container |
| 86 | $parent.find('br').remove(); |
| 87 | |
| 88 | // remove separator whitespace in container |
| 89 | $parent.html(function (i, html) { |
| 90 | return html.replace(/ /g, ''); |
| 91 | }); |
| 92 | |
| 93 | var renderedOptions = ''; |
| 94 | // replace missing br at start of element |
| 95 | if (separator === '<br/>') { |
| 96 | $parent.prepend(separator); |
| 97 | renderedOptions = separator; |
| 98 | } |
| 99 | |
| 100 | newOptions.forEach(function(option) { |
| 101 | var optionId = prefix + '_' + option.key, |
| 102 | checked = ''; |
| 103 | |
| 104 | if ($.inArray(optionId, checkedBoxes) !== -1) { |
| 105 | checked = ' checked="checked"'; |
| 106 | } |
| 107 | |
| 108 | renderedOptions += '<input type="checkbox" ' + |
| 109 | ' value="1"' + |
| 110 | ' id="' + optionId + '"' + |
| 111 | ' name="' + prefix + '[' + option.key +']' + '"' + |
| 112 | checked + |
| 113 | ' class="crm-form-checkbox"' + |
| 114 | optionAttributes + |
| 115 | '><label for="' + optionId + '">' + option.value + '</label>' + |
| 116 | separator; |
| 117 | }); |
| 118 | |
| 119 | // remove final separator |
| 120 | renderedOptions = renderedOptions.substring(0, renderedOptions.lastIndexOf(separator)); |
| 121 | |
| 122 | var $editLink = $parent.find('.crm-option-edit-link'); |
| 123 | |
| 124 | // try to insert before the edit link to maintain structure |
| 125 | if ($editLink.length > 0) { |
| 126 | $(renderedOptions).insertBefore($editLink); |
| 127 | } |
| 128 | else { |
| 129 | $parent.append(renderedOptions); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Rebuild radio input options, overwriting the existing options |
| 135 | * |
| 136 | * @param $existing {object} the existing input options |
| 137 | * @param newOptions {array} in format returned by api.getoptions |
| 138 | */ |
| 139 | function rebuildRadioOptions($existing, newOptions) { |
| 140 | var $parent = $existing.first().parent(), |
| 141 | $firstExisting = $existing.first(), |
| 142 | optionName = $firstExisting.attr('name'), |
| 143 | renderedOptions = '', |
| 144 | checkedValue = parseInt($parent.find('input:checked').attr('value')), |
| 145 | optionAttributes = |
| 146 | 'data-option-edit-path =' + $firstExisting.attr('data-option-edit-path') + |
| 147 | ' data-api-entity = ' + $firstExisting.attr('data-api-entity') + |
| 148 | ' data-api-field = ' + $firstExisting.attr('data-api-field'); |
| 149 | |
| 150 | // remove existing radio inputs and labels |
| 151 | $parent.find('input, label').remove(); |
| 152 | |
| 153 | newOptions.forEach(function(option) { |
| 154 | var optionId = 'CIVICRM_QFID_' + option.key + '_' + optionName, |
| 155 | checked = (option.key === checkedValue) ? ' checked="checked"' : ''; |
| 156 | |
| 157 | renderedOptions += '<input type="radio" ' + |
| 158 | ' value=' + option.key + |
| 159 | ' id="' + optionId +'"' + |
| 160 | ' name="' + optionName + '"' + |
| 161 | checked + |
| 162 | ' class="crm-form-radio"' + |
| 163 | optionAttributes + |
| 164 | '><label for="' + optionId + '">' + option.value + '</label> '; |
| 165 | }); |
| 166 | |
| 167 | $parent.prepend(renderedOptions); |
| 168 | } |
| 169 | }); |