X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=js%2FCommon.js;h=c936f4f386c36b87590f357975bc89487468ddcb;hb=58cb13f8bfa693af1dcf19e5eb24e13d77da2d14;hp=6b6fc03faa46e952930a565cad7c652b63bce3a1;hpb=56c5b99f3ed9ef02a8f892fe5ee3008aa9b72cf2;p=civicrm-core.git diff --git a/js/Common.js b/js/Common.js index 6b6fc03faa..c936f4f386 100644 --- a/js/Common.js +++ b/js/Common.js @@ -201,8 +201,9 @@ function showHideRow(index) { /* jshint ignore:end */ -CRM.utils = CRM.utils || {}; -CRM.strings = CRM.strings || {}; +if (!CRM.utils) CRM.utils = {}; +if (!CRM.strings) CRM.strings = {}; +if (!CRM.vars) CRM.vars = {}; (function ($, _, undefined) { "use strict"; @@ -372,6 +373,7 @@ CRM.strings = CRM.strings || {}; return $(this).each(function () { var $el = $(this), + iconClass, settings = {allowClear: !$el.hasClass('required')}; // quickform doesn't support optgroups so here's a hack :( $('option[value^=crm_optgroup]', this).each(function () { @@ -383,6 +385,19 @@ CRM.strings = CRM.strings || {}; // add disabled property for option values $('option[value^=crm_disabled_opt]', this).attr('disabled', 'disabled'); + // Placeholder icon - total hack hikacking the escapeMarkup function but select2 3.5 dosn't have any other callbacks for this :( + if ($el.is('[class*=fa-]')) { + settings.escapeMarkup = function (m) { + var out = _.escape(m), + placeholder = settings.placeholder || $el.data('placeholder') || $el.attr('placeholder') || $('option[value=""]', $el).text(); + if (m.length && placeholder === m) { + iconClass = $el.attr('class').match(/(fa-\S*)/)[1]; + out = ' ' + out; + } + return out; + }; + } + // Defaults for single-selects if ($el.is('select:not([multiple])')) { settings.minimumResultsForSearch = 10; @@ -543,11 +558,12 @@ CRM.strings = CRM.strings || {}; // Once a filter has been chosen, rerender create links and refocus the search box $el.select2('close'); $el.select2('open'); + } else { + $('.crm-entityref-links', '#select2-drop').replaceWith(renderEntityRefCreateLinks($el)); } }) .on('change.crmEntity', 'select.crm-entityref-filter-key', function() { - var filter = $el.data('user-filter') || {}; - filter.key = $(this).val(); + var filter = {key: $(this).val()}; $(this).toggleClass('active', !!filter.key); $el.data('user-filter', filter); loadEntityRefFilterOptions($el); @@ -570,10 +586,12 @@ CRM.strings = CRM.strings || {}; combined = _.cloneDeep(params), filter = $.extend({}, $el.data('user-filter') || {}); if (filter.key && filter.value) { + // Fieldname may be prefixed with joins + var fieldName = _.last(filter.key.split('.')); // Special case for contact type/sub-type combo - if (filter.key === 'contact_type' && (filter.value.indexOf('__') > 0)) { - combined.params.contact_type = filter.value.split('__')[0]; - combined.params.contact_sub_type = filter.value.split('__')[1]; + if (fieldName === 'contact_type' && (filter.value.indexOf('__') > 0)) { + combined.params[filter.key] = filter.value.split('__')[0]; + combined.params[filter.key.replace('contact_type', 'contact_sub_type')] = filter.value.split('__')[1]; } else { // Allow json-encoded api filters e.g. {"BETWEEN":[123,456]} combined.params[filter.key] = filter.value.charAt(0) === '{' ? $.parseJSON(filter.value) : filter.value; @@ -584,7 +602,7 @@ CRM.strings = CRM.strings || {}; function copyAttributes($source, $target, attributes) { _.each(attributes, function(name) { - if ($source.attr(name)) { + if ($source.attr(name) !== undefined) { $target.attr(name, $source.attr(name)); } }); @@ -596,18 +614,28 @@ CRM.strings = CRM.strings || {}; $.fn.crmDatepicker = function(options) { return $(this).each(function() { if ($(this).is('.crm-form-date-wrapper .crm-hidden-date')) { - // Already initialized + // Already initialized - destroy + $(this) + .off('.crmDatepicker') + .css('display', '') + .removeClass('crm-hidden-date') + .siblings().remove(); + $(this).unwrap(); + } + if (options === 'destroy') { return; } var $dataField = $(this).wrap(''), - settings = $.extend({}, $dataField.data('datepicker') || {}, options || {}), + settings = _.cloneDeep(options || {}), $dateField = $(), $timeField = $(), - $clearLink = $(); + $clearLink = $(), + hasDatepicker = settings.date !== false && settings.date !== 'yy', + type = hasDatepicker ? 'text' : 'number'; if (settings.allowClear !== undefined ? settings.allowClear : !$dataField.is('.required, [required]')) { - $clearLink = $('') + $clearLink = $('') .insertAfter($dataField); } if (settings.time !== false) { @@ -623,18 +651,32 @@ CRM.strings = CRM.strings || {}; }); } if (settings.date !== false) { - $dateField = $('').insertAfter($dataField); + // Render "number" field for year-only format, calendar popup for all other formats + $dateField = $('').insertAfter($dataField); copyAttributes($dataField, $dateField, ['placeholder', 'style', 'class', 'disabled']); - $dateField.addClass('crm-form-text crm-form-date'); - settings.date = typeof settings.date === 'string' ? settings.date : CRM.config.dateInputFormat; - settings.changeMonth = _.includes('m', settings.date); - settings.changeYear = _.includes('y', settings.date); - $dateField.datepicker(settings).change(updateDataField); + $dateField.addClass('crm-form-' + type); + settings.minDate = settings.minDate ? CRM.utils.makeDate(settings.minDate) : null; + settings.maxDate = settings.maxDate ? CRM.utils.makeDate(settings.maxDate) : null; + if (hasDatepicker) { + settings.dateFormat = typeof settings.date === 'string' ? settings.date : CRM.config.dateInputFormat; + settings.changeMonth = _.includes(settings.dateFormat, 'm'); + settings.changeYear = _.includes(settings.dateFormat, 'y'); + $dateField.addClass('crm-form-date').datepicker(settings); + } else { + $dateField.attr('min', settings.minDate ? CRM.utils.formatDate(settings.minDate, 'yy') : '1000'); + $dateField.attr('max', settings.maxDate ? CRM.utils.formatDate(settings.maxDate, 'yy') : '4000'); + } + $dateField.change(updateDataField); } // Rudimentary validation. TODO: Roll into use of jQUery validate and ui.datepicker.validation function isValidDate() { + // FIXME: parseDate doesn't work with incomplete date formats; skip validation if no month, day or year in format + var lowerFormat = settings.dateFormat.toLowerCase(); + if (lowerFormat.indexOf('y') < 0 || lowerFormat.indexOf('m') < 0 || lowerFormat.indexOf('d') < 0) { + return true; + } try { - $.datepicker.parseDate(settings.date, $dateField.val()); + $.datepicker.parseDate(settings.dateFormat, $dateField.val()); return true; } catch (e) { return false; @@ -644,8 +686,10 @@ CRM.strings = CRM.strings || {}; var val = $dataField.val(), time = null; if (context !== 'userInput' && context !== 'crmClear') { - if ($dateField.length) { + if (hasDatepicker) { $dateField.datepicker('setDate', _.includes(val, '-') ? $.datepicker.parseDate('yy-mm-dd', val) : null); + } else if ($dateField.length) { + $dateField.val(val.slice(0, 4)); } if ($timeField.length) { if (val.length === 8) { @@ -663,9 +707,11 @@ CRM.strings = CRM.strings || {}; if (context !== 'crmClear') { var val = ''; if ($dateField.val()) { - if (isValidDate()) { + if (hasDatepicker && isValidDate()) { val = $.datepicker.formatDate('yy-mm-dd', $dateField.datepicker('getDate')); $dateField.removeClass('crm-error'); + } else if (!hasDatepicker) { + val = $dateField.val() + '-01-01'; } else { $dateField.addClass('crm-error'); } @@ -676,11 +722,44 @@ CRM.strings = CRM.strings || {}; $dataField.val(val).trigger('change', ['userInput']); } } - $dataField.hide().addClass('crm-hidden-date').on('change', updateInputFields); + $dataField.hide().addClass('crm-hidden-date').on('change.crmDatepicker', updateInputFields); updateInputFields(); }); }; + $.fn.crmAjaxTable = function() { + return $(this).each(function() { + //Declare the defaults for DataTables + var defaults = { + "processing": true, + "serverSide": true, + "aaSorting": [], + "dom": '<"crm-datatable-pager-top"lfp>rt<"crm-datatable-pager-bottom"ip>', + "pageLength": 25, + "drawCallback": function(settings) { + //Add data attributes to cells + $('thead th', settings.nTable).each( function( index ) { + $.each(this.attributes, function() { + if(this.name.match("^cell-")) { + var cellAttr = this.name.substring(5); + var cellValue = this.value; + $('tbody tr', settings.nTable).each( function() { + $('td:eq('+ index +')', this).attr( cellAttr, cellValue ); + }); + } + }); + }); + //Reload table after draw + $(settings.nTable).trigger('crmLoad'); + } + }; + //Include any table specific data + var settings = $.extend(true, defaults, $(this).data('table')); + //Make the DataTables call + $(this).DataTable(settings); + }); + }; + CRM.utils.formatSelect2Result = function (row) { var markup = '
'; if (row.image !== undefined) { @@ -712,9 +791,23 @@ CRM.strings = CRM.strings || {}; createLinks = params.contact_type ? _.where(CRM.config.entityRef.contactCreate, {type: params.contact_type}) : CRM.config.entityRef.contactCreate; } _.each(createLinks, function(link) { + var icon; + switch (link.type) { + case 'Individual': + icon = 'fa-user'; + break; + + case 'Organization': + icon = 'fa-building'; + break; + + case 'Household': + icon = 'fa-home'; + break; + } markup += ' '; - if (link.type) { - markup += ' '; + if (icon) { + markup += ' '; } markup += link.label + ''; }); @@ -781,7 +874,9 @@ CRM.strings = CRM.strings || {}; CRM.utils.setOptions($valField, filterSpec.options, false, filter.value); } else { $valField.prop('disabled', true); - CRM.api3(filterSpec.entity || $el.data('api-entity'), 'getoptions', {field: filter.key, context: 'search', sequential: 1}) + // Fieldname may be prefixed with joins - strip those out + var fieldName = _.last(filter.key.split('.')); + CRM.api3(filterSpec.entity || $el.data('api-entity'), 'getoptions', {field: fieldName, context: 'search', sequential: 1}) .done(function(result) { var entity = $el.data('api-entity').toLowerCase(), globalFilterSpec = _.find(CRM.config.entityRef.filters[entity], {key: filter.key}) || {}; @@ -793,7 +888,7 @@ CRM.strings = CRM.strings || {}; }); } } else { - $valField.hide(); + $valField.hide().val('').change(); } } @@ -843,16 +938,40 @@ CRM.strings = CRM.strings || {}; } }) .find('input.select-row:checked').parents('tr').addClass('crm-row-selected'); + $('table.crm-sortable', e.target).DataTable(); + $('table.crm-ajax-table', e.target).each(function() { + var + $table = $(this), + $accordion = $table.closest('.crm-accordion-wrapper.collapsed, .crm-collapsible.collapsed'); + // For tables hidden by collapsed accordions, wait. + if ($accordion.length) { + $accordion.one('crmAccordion:open', function() { + $table.crmAjaxTable(); + }); + } else { + $table.crmAjaxTable(); + } + }); if ($("input:radio[name=radio_ts]").size() == 1) { $("input:radio[name=radio_ts]").prop("checked", true); } $('.crm-select2:not(.select2-offscreen, .select2-container)', e.target).crmSelect2(); $('.crm-form-entityref:not(.select2-offscreen, .select2-container)', e.target).crmEntityRef(); $('select.crm-chain-select-control', e.target).off('.chainSelect').on('change.chainSelect', chainSelect); + $('.crm-form-text[data-crm-datepicker]', e.target).each(function() { + $(this).crmDatepicker($(this).data('crmDatepicker')); + }); // Cache Form Input initial values $('form[data-warn-changes] :input', e.target).each(function() { $(this).data('crm-initial-value', $(this).is(':checkbox, :radio') ? $(this).prop('checked') : $(this).val()); }); + $('textarea.crm-form-wysiwyg', e.target).each(function() { + if ($(this).hasClass("collapsed")) { + CRM.wysiwyg.createCollapsed(this); + } else { + CRM.wysiwyg.create(this); + } + }); }) .on('dialogopen', function(e) { var $el = $(e.target); @@ -861,9 +980,10 @@ CRM.strings = CRM.strings || {}; $el.addClass('modal-dialog'); $('body').css({overflow: 'hidden'}); } + $el.parent().find('.ui-dialog-titlebar .ui-icon-closethick').removeClass('ui-icon-closethick').addClass('fa-times'); // Add resize button if ($el.parent().hasClass('crm-container') && $el.dialog('option', 'resizable')) { - $el.parent().find('.ui-dialog-titlebar').append($('