X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=js%2Fcrm.ajax.js;h=276d02ddfd729d9ebaf9574c37d2baeba7fdd29c;hb=deb6ebbb7ecab1b5dbd94ce13e52da02c19bf689;hp=b647e370c8bfd5a604da392944e2c9e3211b4b1a;hpb=10c5b975bac2283796e1461ceebc2c7888e9f1e6;p=civicrm-core.git
diff --git a/js/crm.ajax.js b/js/crm.ajax.js
index b647e370c8..276d02ddfd 100644
--- a/js/crm.ajax.js
+++ b/js/crm.ajax.js
@@ -5,45 +5,41 @@
*/
(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);
}
});
@@ -160,7 +156,7 @@
* @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);
};
@@ -249,8 +245,9 @@
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;
@@ -260,7 +257,9 @@
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);
@@ -268,9 +267,21 @@
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);
}
@@ -300,25 +311,52 @@
if (typeof settings.dialog.height === 'string' && settings.dialog.height.indexOf('%') > 0) {
settings.dialog.height = parseInt($(window).height() * (parseFloat(settings.dialog.height)/100), 10);
}
- $('
').dialog(settings.dialog);
- $(settings.target).on('dialogclose', function() {
- if ($(this).attr('data-unsaved-changes') !== 'true') {
- $(this).crmSnippet('destroy').dialog('destroy').remove();
+ // 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%';
}
- });
- }
- if (settings.dialog && !settings.dialog.title) {
- $(settings.target).on('crmLoad', function(e, data) {
- if (e.target === $(settings.target)[0] && data && data.title) {
- $(this).dialog('option', 'title', data.title);
+ else if (screenWidth < 1400) {
+ settings.dialog.width = '' + parseInt(percentage+gap-((screenWidth - 700)/7*(gap)/100), 10) + '%';
}
- });
+ }
+ $('').dialog(settings.dialog);
+ $(settings.target)
+ .on('dialogclose', function() {
+ if ($(this).attr('data-unsaved-changes') !== 'true') {
+ $(this).crmSnippet('destroy').dialog('destroy').remove();
+ }
+ })
+ .on('crmLoad', function(e, data) {
+ // Set title
+ if (e.target === $(settings.target)[0] && data && !settings.dialog.title && data.title) {
+ $(this).dialog('option', 'title', data.title);
+ }
+ // Adjust height to fit content (small delay to allow elements to render)
+ window.setTimeout(function() {
+ var currentHeight = $(settings.target).parent().outerHeight(),
+ padding = currentHeight - $(settings.target).height(),
+ newHeight = $(settings.target).prop('scrollHeight') + padding,
+ menuHeight = $('#civicrm-menu').outerHeight(),
+ maxHeight = $(window).height() - menuHeight;
+ newHeight = newHeight > maxHeight ? maxHeight : newHeight;
+ if (newHeight > (currentHeight + 15)) {
+ $(settings.target).dialog('option', {
+ position: {my: 'center', at: 'center center+' + (menuHeight / 2), of: window},
+ height: newHeight
+ });
+ }
+ }, 500);
+ });
}
$(settings.target).crmSnippet(settings).crmSnippet('refresh');
return $(settings.target);
};
CRM.loadForm = function(url, options) {
- var settings = {
+ var formErrors = [], settings = {
crmForm: {
ajaxForm: {},
autoClose: true,
@@ -344,9 +382,7 @@
// CRM-14353 - Warn of unsaved changes for all forms except those which have opted out
function cancelAction() {
var dirty = CRM.utils.initialValueChanged($('form:not([data-warn-changes=false])', widget));
- widget
- .attr('data-unsaved-changes', dirty ? 'true' : 'false')
- .dialog('close');
+ widget.attr('data-unsaved-changes', dirty ? 'true' : 'false');
if (dirty) {
var id = widget.attr('id') + '-unsaved-alert',
title = widget.dialog('option', 'title'),
@@ -357,15 +393,17 @@
});
}
}
- if (widget.data('uiDialog')) {
- // CRM-14353 - This is a bit harsh but we are removing jQuery UI's event handler from the close button and adding our own
- widget.parent().find('.ui-dialog-titlebar-close').first().off().click(cancelAction);
- }
+
+ widget.data('uiDialog') && widget.on('dialogbeforeclose', function(e) {
+ // CRM-14353 - Warn unsaved changes if user clicks close button or presses "esc"
+ if (e.originalEvent) {
+ cancelAction();
+ }
+ });
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);
@@ -373,6 +411,7 @@
$el.trigger('crmFormCancel', e);
if ($el.data('uiDialog') && settings.autoClose) {
cancelAction();
+ $el.dialog('close');
}
else if (!settings.autoClose) {
$el.crmSnippet('resetUrl').crmSnippet('refresh');
@@ -387,7 +426,6 @@
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))) {
@@ -395,7 +433,8 @@
$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) {
@@ -403,12 +442,14 @@
}
}
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));
});
}
}
@@ -419,8 +460,16 @@
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);
}
@@ -432,7 +481,35 @@
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();
});
@@ -442,7 +519,7 @@
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(),
@@ -462,9 +539,6 @@
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]);
@@ -482,14 +556,14 @@
};
/**
* 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();