Merge pull request #2116 from civicrm/4.4
[civicrm-core.git] / js / Common.js
index 8f5294ef60db3c13e12c62db59dc18e291cfe68b..a3e0b5a3437e23eb8eeff175ddf3e79b5c219561 100644 (file)
@@ -1,6 +1,6 @@
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.3                                                |
+ | CiviCRM version 4.4                                                |
  +--------------------------------------------------------------------+
  | Copyright CiviCRM LLC (c) 2004-2013                                |
  +--------------------------------------------------------------------+
@@ -426,10 +426,6 @@ function popUp(URL) {
   eval("page" + id + " = window.open(URL, '" + id + "', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=0,width=640,height=420,left = 202,top = 184');");
 }
 
-function imagePopUp(path) {
-  window.open(path, 'popupWindow', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,screenX=150,screenY=150,top=150,left=150');
-}
-
 /**
  * Function to show / hide the row in optionFields
  *
@@ -600,9 +596,9 @@ CRM.validate = CRM.validate || {
   });
 
   $.fn.crmtooltip = function () {
-    $('a.crm-summary-link:not(.crm-processed)')
-      .addClass('crm-processed')
-      .on('mouseover', function (e) {
+    $(document)
+      .on('mouseover', 'a.crm-summary-link:not(.crm-processed)', function (e) {
+        $(this).addClass('crm-processed');
         $(this).addClass('crm-tooltip-active');
         var topDistance = e.pageY - $(window).scrollTop();
         if (topDistance < 300 | topDistance < $(this).children('.crm-tooltip-wrapper').height()) {
@@ -615,14 +611,15 @@ CRM.validate = CRM.validate || {
             .load(this.href);
         }
       })
-      .on('mouseout', function () {
+      .on('mouseout', 'a.crm-summary-link', function () {
+        $(this).removeClass('crm-processed');
         $(this).removeClass('crm-tooltip-active crm-tooltip-down');
       })
-      .on('click', false);
+      .on('click', 'a.crm-summary-link', false);
   };
 
   var h;
-  CRM.help = function (title, params) {
+  CRM.help = function (title, params, url) {
     h && h.close && h.close();
     var options = {
       expires: 0
@@ -630,7 +627,7 @@ CRM.validate = CRM.validate || {
     h = CRM.alert('...', title, 'crm-help crm-msg-loading', options);
     params.class_name = 'CRM_Core_Page_Inline_Help';
     params.type = 'page';
-    $.ajax(CRM.url('civicrm/ajax/inline'),
+    $.ajax(url || CRM.url('civicrm/ajax/inline'),
       {
         data: params,
         dataType: 'html',
@@ -714,6 +711,7 @@ CRM.validate = CRM.validate || {
       message: ts('Are you sure you want to continue?'),
       resizable: false,
       modal: true,
+      width: 'auto',
       close: function () {
         $(dialog).remove();
       },
@@ -807,7 +805,12 @@ CRM.validate = CRM.validate || {
       CRM.alert(text, title, type, options);
     });
     // Handle qf form errors
-    $('form :input.error', this).one('blur', function () {
+    $('form :input.error', this).one('blur', function() {
+      // ignore autocomplete fields
+      if ($(this).is('.ac_input')) {
+        return;
+      }
+
       $('.ui-notify-message.error a.ui-notify-close').click();
       $(this).removeClass('error');
       $(this).next('span.crm-error').remove();
@@ -817,13 +820,212 @@ CRM.validate = CRM.validate || {
     });
   }
 
+  $.widget('civicrm.crmSnippet', {
+    options: {
+      url: document.location.href,
+      block: true,
+      crmForm: null
+    },
+    _create: function() {
+      this.refresh();
+      this.element.addClass('crm-ajax-container');
+      if (!this.element.is('.crm-container *')) {
+        this.element.addClass('crm-container');
+      }
+    },
+    _onFailure: function(data) {
+      this.options.block && this.element.unblock();
+      this.element.trigger('crmAjaxFail', data);
+      CRM.alert(ts('Unable to reach the server. Please refresh this page in your browser and try again.'), ts('Network Error'), 'error');
+    },
+    _formatUrl: function(url) {
+      // Add snippet argument to url
+      if (url.search(/[&?]snippet=/) < 0) {
+        url += (url.indexOf('?') < 0 ? '?' : '&') + 'snippet=6';
+      }
+      return url;
+    },
+    refresh: function() {
+      var that = this;
+      var url = this._formatUrl(this.options.url);
+      this.options.block && this.element.block();
+      $.getJSON(url, function(data) {
+        if (typeof(data) != 'object' || typeof(data.content) != 'string') {
+          that._onFailure(data);
+          return;
+        }
+        data.url = url;
+        that.element.html(data.content).trigger('crmLoad', data);
+        // This will also trigger crmFormLoad for forms
+        that.options.crmForm && that.element.trigger('crmFormLoad', data);
+      }).fail(function() {
+          that._onFailure();
+        });
+    }
+  });
+
+  var dialogCount = 0;
+  CRM.loadPage = function(url, options) {
+    var settings = {
+      target: '#crm-ajax-dialog-' + (dialogCount++),
+      dialog: {
+        modal: true,
+        width: '65%',
+        height: parseInt($(window).height() * .75),
+        close: function() {
+          $(this).dialog('destroy');
+          $(this).remove();
+        }
+      }
+    };
+    options && $.extend(true, settings, options);
+    settings.url = url;
+    // Create new dialog
+    if (settings.dialog !== false && settings.target[0] == '#') {
+      $('<div id="'+ settings.target.substring(1) +'"><div class="crm-loading-element">' + ts('Loading') + '...</div></div>').dialog(settings.dialog);
+    }
+    if (settings.dialog && !settings.dialog.title) {
+      $(settings.target).on('crmLoad', function(event, data) {
+        data.title && $(this).dialog('option', 'title', data.title);
+      });
+    }
+    // Automatically open form links as new popups
+    settings.formLinks && $(settings.target).on('click', settings.formLinks, function() {
+      CRM.loadForm(this.href, {
+        dialog: {
+          width: '60%',
+          height: parseInt($(window).height() * .8)
+        }
+      }).on('crmFormSuccess', function() {
+          $(settings.target).crmSnippet('refresh');
+        });
+      return false;
+    });
+    return $(settings.target).crmSnippet(settings);
+  };
+
+  CRM.loadForm = function(url, options) {
+    var settings = {
+      crmForm: {
+        ajaxForm: {},
+        block: true,
+        autoClose: true,
+        validate: true,
+        refreshAction: ['next_new', 'submit_savenext'],
+        cancelButton: '.cancel.form-submit',
+        openInline: 'a.button',
+        onCancel: function(event) {},
+        onError: function(data) {
+          var $el = $(this);
+          $el.html(data.content).trigger('crmLoad', data).trigger('crmFormLoad', data);
+          if (typeof(data.errors) == 'object') {
+            $.each(data.errors, function(formElement, msg) {
+              $('[name="'+formElement+'"]', $el).crmError(msg);
+            });
+          }
+        }
+      }
+    };
+    // Move options that belong to crmForm. Others will be passed through to crmSnippet
+    options && $.each(options, function(key, value) {
+      if (typeof(settings.crmForm[key]) !== 'undefined') {
+        settings.crmForm[key] = value;
+      }
+      else {
+        settings[key] = value;
+      }
+    });
+    settings.type = 'Form';
+
+    var widget = CRM.loadPage(url, settings);
+
+    widget.on('crmFormLoad', function(event, data) {
+      var $el = $(this);
+      var settings = $el.data('crmSnippet').options.crmForm;
+      var dialog = $el.data('dialog');
+      settings.cancelButton && $(settings.cancelButton, this).click(function(event) {
+        var returnVal = settings.onCancel.call($el, event);
+        if (returnVal !== false) {
+          $el.trigger('crmFormCancel', event);
+          dialog && settings.autoClose && $el.dialog('close');
+        }
+        return returnVal === false;
+      });
+      settings.openInline && $(settings.openInline, this).click(function(event) {
+        $el.crmSnippet('option', 'url', this.href).crmSnippet('refresh');
+        return false;
+      });
+      if (settings.validate) {
+        $("form", this).validate(typeof(settings.validate) == 'object' ? settings.validate : CRM.validate.params);
+      }
+      $("form", this).ajaxForm($.extend({
+        url: data.url,
+        dataType: 'json',
+        success: function(response) {
+          if (response.status == 'success') {
+            settings.block && $el.unblock();
+            $el.trigger('crmFormSuccess', response);
+            // Reset form for e.g. "save and new"
+            if (settings.refreshAction && $.inArray(response.buttonName, settings.refreshAction) >= 0) {
+              $el.crmSnippet('option', 'url', response.userContext).crmSnippet('refresh');
+            }
+            else if (dialog && settings.autoClose) {
+              $el.dialog('close');
+            }
+          }
+          else {
+            settings.onError.call($el, response);
+          }
+        },
+        beforeSubmit: function(submission) {
+          settings.block && $el.block();
+          $el.trigger('crmFormSubmit', submission);
+        }
+      }, settings.ajaxForm));
+    });
+    return widget;
+  };
+
+  // Preprocess all cj ajax calls to display messages
+  $(document).ajaxSuccess(function(event, xhr, settings) {
+    try {
+      if ((!settings.dataType || settings.dataType == 'json') && xhr.responseText) {
+        var response = $.parseJSON(xhr.responseText);
+        if (typeof(response.crmMessages) == 'object') {
+          $.each(response.crmMessages, function(n, msg) {
+            CRM.alert(msg.text, msg.title, msg.type, msg.options);
+          })
+        }
+      }
+    }
+    // Suppress errors
+    catch (e) {}
+  });
+
   $(function () {
+    // Trigger crmLoad on initial content for consistency. It will also be triggered for ajax-loaded content.
+    $('#crm-container').trigger('crmLoad');
+
     if ($('#crm-notification-container').length) {
       // Initialize notifications
       $('#crm-notification-container').notify();
       messagesFromMarkup.call($('#crm-container'));
       $('#crm-container').on('crmFormLoad', '*', messagesFromMarkup);
     }
+
+    // bind the event for image popup
+    $('body').on('click', 'a.crm-image-popup', function() {
+      var o = $('<div class="crm-container crm-custom-image-popup"><img src=' + $(this).attr('href') + '></div>');
+
+      CRM.confirm('',
+        {
+          title: ts('Preview'),
+          message: o
+        },
+        ts('Done')
+      );
+      return false;
+    });
   });
 
   $.fn.crmAccordions = function (speed) {
@@ -863,4 +1065,33 @@ CRM.validate = CRM.validate || {
       $(this).toggleClass('collapsed');
     });
   };
+
+  /**
+   * Clientside currency formatting
+   * @param value
+   * @param format - currency representation of the number 1234.56
+   * @return string
+   * @see CRM_Core_Resources::addCoreResources
+   */
+  var currencyTemplate;
+  CRM.formatMoney = function(value, format) {
+    var decimal, separator, sign, i, j, result;
+    if (value === 'init' && format) {
+      currencyTemplate = format;
+      return;
+    }
+    format = format || currencyTemplate;
+    result = /1(.?)234(.?)56/.exec(format);
+    if (result === null) {
+      return 'Invalid format passed to CRM.formatMoney';
+    }
+    separator = result[1];
+    decimal = result[2];
+    sign = (value < 0) ? '-' : '';
+    //extracting the absolute value of the integer part of the number and converting to string
+    i = parseInt(value = Math.abs(value).toFixed(2)) + '';
+    j = ((j = i.length) > 3) ? j % 3 : 0;
+    result = sign + (j ? i.substr(0, j) + separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + separator) + (2 ? decimal + Math.abs(value - i).toFixed(2).slice(2) : '');
+    return format.replace(/1.*234.*56/, result);
+  };
 })(jQuery);