*/
(function($, CRM, undefined) {
/**
- * Almost like {crmURL} but on the client side
- * eg: var url = CRM.url('civicrm/contact/view', {reset:1,cid:42});
- * or: $('a.my-link').crmURL();
+ * @param string path
+ * @param string|object query
+ * @param string mode - optionally specify "front" or "back"
*/
- var tplURL = '/civicrm/example?placeholder';
- var urlInitted = false;
- CRM.url = function (p, params) {
- if (p == "init") {
- tplURL = params;
- urlInitted = true;
- return;
+ var tplURL;
+ CRM.url = function (path, query, mode) {
+ if (typeof path === 'object') {
+ return tplURL = path;
+ }
+ if (!tplURL) {
+ CRM.console('error', 'Error: CRM.url called before initialization');
}
- if (!urlInitted) {
- console && console.log && console.log('Warning: CRM.url called before initialization');
+ if (!mode) {
+ mode = CRM.config && CRM.config.isFrontend ? 'front' : 'back';
}
- params = params || '';
- var frag = p.split ('?');
- var url = tplURL.replace("civicrm/example", frag[0]);
+ query = query || '';
+ var frag = path.split('?');
+ var url = tplURL[mode].replace("*path*", frag[0]);
- if (typeof(params) == 'string') {
- url = url.replace("placeholder", params);
+ if (!query) {
+ url = url.replace(/[?&]\*query\*/, '');
}
else {
- url = url.replace("placeholder", $.param(params));
+ url = url.replace("*query*", typeof query === 'string' ? query : $.param(query));
}
if (frag[1]) {
- url += (url.indexOf('?') === (url.length - 1) ? '' : '&') + frag[1];
- }
- // remove trailing "?"
- if (url.indexOf('?') === (url.length - 1)) {
- url = url.slice(0, (url.length - 1));
+ url += (url.indexOf('?') < 0 ? '?' : '&') + frag[1];
}
return url;
};
- // Backwards compatible with jQuery fn
+ // @deprecated
$.extend ({'crmURL':
function (p, params) {
- console && console.log && console.log('Calling crmURL from jQuery is deprecated. Please use CRM.url() instead.');
+ CRM.console('warn', 'Calling crmURL from jQuery is deprecated. Please use CRM.url() instead.');
return CRM.url(p, params);
}
});
* @deprecated
*/
$.fn.crmAPI = function(entity, action, params, options) {
- console && console.log && console.log('Calling crmAPI from jQuery is deprecated. Please use CRM.api() instead.');
+ CRM.console('warn', 'Calling crmAPI from jQuery is deprecated. Please use CRM.api3() instead.');
return CRM.api.call(this, entity, action, params, options);
};
if (this._originalContent === null) {
this._originalContent = this.element.contents().detach();
}
- this.options.block && $('.blockOverlay', this.element).length < 1 && this.element.block();
+ this.options.block && this.element.block();
$.getJSON(url, function(data) {
+ that.options.block && that.element.unblock();
if (!$.isPlainObject(data)) {
that._onFailure(data);
return;
return;
}
data.url = url;
- that.element.trigger('crmBeforeLoad', data).html(data.content);
+ that.element.trigger('crmUnload').trigger('crmBeforeLoad', data);
+ that._beforeRemovingContent();
+ that.element.html(data.content);
that._handleOrderLinks();
that.element.trigger('crmLoad', data);
that.options.crmForm && that.element.trigger('crmFormLoad', data);
that._onFailure();
});
},
- _destroy: function() {
- this.element.removeClass('crm-ajax-container');
+ // Perform any cleanup needed before removing/replacing content
+ _beforeRemovingContent: function() {
+ var that = this;
+ if (window.tinyMCE && tinyMCE.editors) {
+ $.each(tinyMCE.editors, function(k) {
+ if ($.contains(that.element[0], this.getElement())) {
+ this.remove();
+ }
+ });
+ }
this.options.crmForm && $('form', this.element).ajaxFormUnbind();
+ },
+ _destroy: function() {
+ this.element.removeClass('crm-ajax-container').trigger('crmUnload');
+ this._beforeRemovingContent();
if (this._originalContent !== null) {
this.element.empty().append(this._originalContent);
}
if (typeof settings.dialog.height === 'string' && settings.dialog.height.indexOf('%') > 0) {
settings.dialog.height = parseInt($(window).height() * (parseFloat(settings.dialog.height)/100), 10);
}
+ // Increase percent width on small screens
+ if (typeof settings.dialog.width === 'string' && settings.dialog.width.indexOf('%') > 0) {
+ var screenWidth = $(window).width(),
+ percentage = parseInt(settings.dialog.width.replace('%', ''), 10),
+ gap = 100-percentage;
+ if (screenWidth < 701) {
+ settings.dialog.width = '100%';
+ }
+ else if (screenWidth < 1400) {
+ settings.dialog.width = '' + parseInt(percentage+gap-((screenWidth - 700)/7*(gap)/100), 10) + '%';
+ }
+ }
$('<div id="'+ settings.target.substring(1) +'"><div class="crm-loading-element">' + ts('Loading') + '...</div></div>').dialog(settings.dialog);
$(settings.target)
.on('dialogclose', function() {
}
// Adjust height to fit content (small delay to allow elements to render)
window.setTimeout(function() {
- var currentHeight = $(settings.target).parent().height(),
+ var currentHeight = $(settings.target).parent().outerHeight(),
padding = currentHeight - $(settings.target).height(),
newHeight = $(settings.target).prop('scrollHeight') + padding,
- menuHeight = $('#civicrm-menu').height(),
+ menuHeight = $('#civicrm-menu').outerHeight(),
maxHeight = $(window).height() - menuHeight;
newHeight = newHeight > maxHeight ? maxHeight : newHeight;
if (newHeight > (currentHeight + 15)) {
return $(settings.target);
};
CRM.loadForm = function(url, options) {
- var settings = {
+ var formErrors = [], settings = {
crmForm: {
ajaxForm: {},
autoClose: true,
});
widget.on('crmFormLoad.crmForm', function(event, data) {
- var $el = $(this)
- .attr('data-unsaved-changes', 'false');
- var settings = $el.crmSnippet('option', 'crmForm');
+ var $el = $(this).attr('data-unsaved-changes', 'false'),
+ settings = $el.crmSnippet('option', 'crmForm');
settings.cancelButton && $(settings.cancelButton, this).click(function(e) {
e.preventDefault();
var returnVal = settings.onCancel.call($el, e);
dataType: 'json',
success: function(response) {
if (response.content === undefined) {
- $el.crmSnippet('option', 'block') && $el.unblock();
$el.trigger('crmFormSuccess', response);
// Reset form for e.g. "save and new"
if (response.userContext && (response.status === 'redirect' || (settings.refreshAction && $.inArray(response.buttonName, settings.refreshAction) >= 0))) {
$el.data('civiCrmSnippet')._originalUrl = response.userContext;
$el.crmSnippet('resetUrl').crmSnippet('refresh');
}
- else if ($el.data('uiDialog') && settings.autoClose) {
+ // Close if we are on the original url or the action was "delete" (in which case returning to view may be inappropriate)
+ else if ($el.data('uiDialog') && (settings.autoClose || response.action === 8)) {
$el.dialog('close');
}
else if (settings.autoClose === false) {
}
}
else {
+ $el.crmSnippet('option', 'block') && $el.unblock();
response.url = data.url;
$el.html(response.content).trigger('crmLoad', response).trigger('crmFormLoad', response);
if (response.status === 'form_error') {
+ formErrors = [];
$el.trigger('crmFormError', response);
$.each(response.errors || [], function(formElement, msg) {
- $('[name="'+formElement+'"]', $el).crmError(msg);
+ formErrors.push($('[name="'+formElement+'"]', $el).crmError(msg));
});
}
}
this.updateElement && this.updateElement();
});
}
+ if (window.tinyMCE && tinyMCE.editors) {
+ $.each(tinyMCE.editors, function() {
+ this.save();
+ });
+ }
},
beforeSubmit: function(submission) {
+ $.each(formErrors, function() {
+ this && this.close && this.close();
+ });
$el.crmSnippet('option', 'block') && $el.block();
$el.trigger('crmFormSubmit', submission);
}
return false;
});
}
- // Alow a button to prevent ajax submit
+ // Show form buttons as part of the dialog
+ if ($el.data('uiDialog')) {
+ var buttonContainers = '.crm-submit-buttons, .action-link',
+ buttons = [],
+ added = [];
+ $(buttonContainers, $el).find('input.crm-form-submit, a.button').each(function() {
+ var $el = $(this),
+ label = $el.is('input') ? $el.attr('value') : $el.text(),
+ identifier = $el.attr('name') || $el.attr('href');
+ if (!identifier || identifier === '#' || $.inArray(identifier, added) < 0) {
+ var $icon = $el.find('.icon'),
+ button = {'data-identifier': identifier, text: label, click: function() {
+ $el.click();
+ }};
+ if ($icon.length) {
+ button.icons = {primary: $icon.attr('class')};
+ } else {
+ var action = $el.hasClass('cancel') ? 'close' : (identifier.substr(identifier.length-4) === '_new' ? 'plus' : 'check');
+ button.icons = {primary: 'ui-icon-' + action};
+ }
+ buttons.push(button);
+ added.push(identifier);
+ }
+ // display:none causes the form to not submit when pressing "enter"
+ $el.parents(buttonContainers).css({height: 0, padding: 0, margin: 0, overflow: 'hidden'});
+ });
+ $el.dialog('option', 'buttons', buttons);
+ }
+ // Allow a button to prevent ajax submit
$('input[data-no-ajax-submit=true]').click(function() {
$(this).closest('form').ajaxFormUnbind();
});
return widget;
};
/**
- * Handler for jQuery click event e.g. $('a').click(CRM.popup)
+ * Handler for jQuery click event e.g. $('a').click(CRM.popup);
*/
CRM.popup = function(e) {
var $el = $(this).first(),
else if ($el.hasClass('medium-popup')) {
settings.dialog.width = settings.dialog.height = '50%';
}
- else if ($el.hasClass('huge-popup')) {
- settings.dialog.height = '90%';
- }
var dialog = popup(url, settings);
// Trigger events from the dialog on the original link element
$el.trigger('crmPopupOpen', [dialog]);
};
/**
* An event callback for CRM.popup or a standalone function to refresh the content around a given element
- * @param e event|selector
+ * @param e {event|selector}
*/
CRM.refreshParent = function(e) {
// Use e.target if input smells like an event, otherwise assume it's a jQuery selector
var $el = (e.stopPropagation && e.target) ? $(e.target) : $(e),
$table = $el.closest('.dataTable');
// Call native refresh method on ajax datatables
- if ($table && $.fn.DataTable.fnIsDataTable($table[0]) && $table.dataTable().fnSettings().sAjaxSource) {
+ if ($table.length && $.fn.DataTable.fnIsDataTable($table[0]) && $table.dataTable().fnSettings().sAjaxSource) {
// Refresh ALL datatables - needed for contact relationship tab
$.each($.fn.dataTable.fnTables(), function() {
$(this).dataTable().fnSettings().sAjaxSource && $(this).unblock().dataTable().fnDraw();