*/
public $ajaxResponse = array();
+ /**
+ * Stores info about reference fields for preprocessing
+ * Public so that hooks can access it
+ *
+ * @var array
+ */
+ public $entityReferenceFields = array();
+
/**
* constants for attributes for various form elements
* attempt to standardize on the number of variations that we
* These are not default values
* @param bool is this a required field
*
- * @return object html element, could be an error object
+ * @return HTML_QuickForm_Element could be an error object
* @access public
*
*/
// the user can do both the form and set default values with this hook
CRM_Utils_Hook::buildForm(get_class($this), $this);
+ $this->preprocessReferenceFields();
+
$this->addRules();
}
$this->setDefaults(array($name => $defaultCurrency));
}
+ /**
+ * Create a single or multiple contact ref field
+ * @param string $name
+ * @param string $label
+ * @param array $props mix of html and widget properties, including:
+ * - required
+ * - select - params to give to select2, notably "multiple"
+ * - api - array of data for the api, keys include "entity", "action", "params", "search", "key", "label"
+ * @return HTML_QuickForm_Element
+ */
+ function addContactRef($name, $label, $props = array(), $required = FALSE) {
+ $props['class'] = isset($props['class']) ? $props['class'] . ' crm-select2' : 'crm-select2';
+
+ $props['select'] = CRM_Utils_Array::value('select', $props, array()) + array(
+ 'minimumInputLength' => 1,
+ 'multiple' => !empty($props['multiple']),
+ 'placeholder' => CRM_Utils_Array::value('placeholder', $props, $required ? ts('- select -') : ts('- none -')),
+ 'allowClear' => !$required,
+ // Disabled pending https://github.com/ivaynberg/select2/pull/2092
+ //'formatInputTooShort' => ts('Start typing a name or email address...'),
+ //'formatNoMatches' => ts('No contacts found.'),
+ );
+
+ $props['api'] = CRM_Utils_Array::value('api', $props, array()) + array(
+ 'entity' => 'contact',
+ 'action' => 'getquick',
+ 'search' => 'name',
+ 'label' => 'data',
+ 'key' => 'id',
+ );
+
+ $this->entityReferenceFields[$name] = $props;
+ $this->formatReferenceFieldAttributes($props);
+ return $this->add('text', $name, $label, $props, $required);
+ }
+
+ /**
+ * @param $props
+ */
+ private function formatReferenceFieldAttributes(&$props) {
+ $props['data-select-params'] = json_encode($props['select']);
+ $props['data-api-params'] = json_encode($props['api']);
+ CRM_Utils_Array::remove($props, 'multiple', 'select', 'api');
+ }
+
+ private function preprocessReferenceFields() {
+ foreach ($this->entityReferenceFields as $name => $props) {
+ $val = $this->getElementValue($name);
+ $field = $this->getElement($name);
+ // Support array values
+ if (is_array($val)) {
+ $val = implode(',', $val);
+ $field->setValue($val);
+ }
+ if ($val) {
+ $data = $labels = array();
+ // Support serialized values
+ if (strpos($val, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) {
+ $val = str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($val, CRM_Core_DAO::VALUE_SEPARATOR));
+ $field->setValue($val);
+ }
+ foreach (explode(',', $val) as $v) {
+ $result = civicrm_api3($props['api']['entity'], $props['api']['action'], array('sequential' => 1, $props['api']['key'] => $v));
+ if (!empty($result['values'])) {
+ $data[] = array('id' => $v, 'text' => $result['values'][0][$props['api']['label']]);
+ $labels[] = $result['values'][0][$props['api']['label']];
+ }
+ }
+ if ($field->isFrozen()) {
+ $field->removeAttribute('class');
+ $field->setValue(implode(', ', $labels));
+ }
+ elseif ($data) {
+ if (empty($props['select']['multiple'])) {
+ $data = $data[0];
+ }
+ $field->setAttribute('data-entity-value', json_encode($data));
+ }
+ }
+ }
+ }
+
/**
* Convert all date fields within the params to mysql date ready for the
* BAO layer. In this case fields are checked against the $_datefields defined for the form
functions: []
};
-// Set select2 defaults
-$.fn.select2.defaults.minimumResultsForSearch = 10;
-// https://github.com/ivaynberg/select2/pull/2090
-$.fn.select2.defaults.width = 'resolve';
-
(function ($, undefined) {
"use strict";
+ // Set select2 defaults
+ $.fn.select2.defaults.minimumResultsForSearch = 10;
+ // https://github.com/ivaynberg/select2/pull/2090
+ $.fn.select2.defaults.width = 'resolve';
+
// Initialize widgets
$(document).on('crmLoad', function(e) {
$('table.row-highlight', e.target)
$(this).nextUntil('option[value^=crm_optgroup]').wrapAll('<optgroup label="' + $(this).text() + '" />');
$(this).remove();
});
- var options = $(this).data('select2') || {};
+ var options = $(this).data('select-params') || {};
+ // Api-based searching
+ if ($(this).data('api-params')) {
+ $(this).addClass('crm-ajax-select')
+ options.query = function(info) {
+ var api = $(info.element).data('api-params');
+ var params = api.params || {};
+ params[api.search] = info.term;
+ CRM.api3(api.entity, api.action, params).done(function(data) {
+ var results = {context: info.context, results: []};
+ if (typeof(data.values) === 'object') {
+ $.each(data.values, function(k, v) {
+ results.results.push({id: v[api.key], text: v[api.label]});
+ });
+ }
+ info.callback(results);
+ });
+ };
+ options.initSelection = function(el, callback) {
+ callback(el.data('entity-value'));
+ };
+ }
$(this).select2(options).removeClass('crm-select2');
});
});