1 (function(angular
, $, _
) {
4 angular
.module('searchAdmin').directive('crmSearchValue', function($interval
, searchMeta
, formatForSelect2
) {
7 data
: '=crmSearchValue'
10 link: function (scope
, element
, attrs
, ngModel
) {
11 var ts
= scope
.ts
= CRM
.ts(),
12 multi
= _
.includes(['IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'], scope
.data
.op
),
13 format
= scope
.data
.format
;
15 function destroyWidget() {
17 if ($el
.is('.crm-form-date-wrapper .crm-hidden-date')) {
18 $el
.crmDatepicker('destroy');
20 if ($el
.is('.select2-container + input')) {
21 $el
.crmEntityRef('destroy');
23 $(element
).removeData().removeAttr('type').removeAttr('placeholder').show();
26 function makeWidget(field
, op
, optionKey
) {
28 inputType
= field
.input_type
,
29 dataType
= field
.data_type
;
31 op
= field
.serialize
|| dataType
=== 'Array' ? 'IN' : '=';
33 multi
= _
.includes(['IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'], op
);
34 if (op
=== 'IS NULL' || op
=== 'IS NOT NULL') {
38 if (inputType
=== 'Date') {
39 if (_
.includes(['=', '!=', '>', '>=', '<', '<='], op
)) {
40 $el
.crmDatepicker({time
: (field
.input_attrs
&& field
.input_attrs
.time
) || false});
42 } else if (_
.includes(['=', '!=', 'IN', 'NOT IN', 'CONTAINS'], op
) && (field
.fk_entity
|| field
.options
|| dataType
=== 'Boolean')) {
44 if (field
.options
=== true) {
45 $el
.addClass('loading');
46 var waitForOptions
= $interval(function() {
47 if (field
.options
!== true) {
48 $interval
.cancel(waitForOptions
);
49 $el
.removeClass('loading').crmSelect2({data
: getFieldOptions
, multiple
: multi
});
53 $el
.attr('placeholder', ts('select')).crmSelect2({data
: getFieldOptions
, multiple
: multi
});
54 } else if (field
.fk_entity
) {
55 $el
.crmEntityRef({entity
: field
.fk_entity
, select
:{multiple
: multi
}});
56 } else if (dataType
=== 'Boolean') {
57 $el
.attr('placeholder', ts('- select -')).crmSelect2({allowClear
: false, multiple
: multi
, placeholder
: ts('- select -'), data
: [
58 // FIXME: it would be more correct to use real true/false booleans instead of numbers, but select2 doesn't seem to like them
59 {id
: 1, text
: ts('Yes')},
60 {id
: 0, text
: ts('No')}
63 } else if (dataType
=== 'Integer' && !multi
) {
64 $el
.attr('type', 'number');
67 function getFieldOptions() {
68 return {results
: formatForSelect2(field
.options
, optionKey
, 'label', ['description', 'color', 'icon'])};
72 // Copied from ng-list but applied conditionally if field is multi-valued
73 var parseList = function(viewValue
) {
74 // If the viewValue is invalid (say required but empty) it will be `undefined`
75 if (_
.isUndefined(viewValue
)) return;
78 return format
=== 'json' ? JSON
.stringify(viewValue
) : viewValue
;
84 _
.each(viewValue
.split(','), function(value
) {
85 if (value
) list
.push(_
.trim(value
));
92 // Copied from ng-list
93 ngModel
.$parsers
.push(parseList
);
94 ngModel
.$formatters
.push(function(value
) {
95 return _
.isArray(value
) ? value
.join(', ') : (format
=== 'json' && value
!== '' ? JSON
.parse(value
) : value
);
98 // Copied from ng-list
99 ngModel
.$isEmpty = function(value
) {
100 return !value
|| !value
.length
;
103 scope
.$watchCollection('data', function(data
) {
105 var field
= searchMeta
.parseExpr(data
.field
).field
;
107 var optionKey
= data
.field
.split(':')[1] || 'id';
108 makeWidget(field
, data
.op
, optionKey
);
115 })(angular
, CRM
.$, CRM
._
);