Merge pull request #2349 from eileenmcnaughton/CRM-14080
[civicrm-core.git] / js / Common.js
index efd5140b2c1f6b796e66bd8d55adb14b394ade16..ed859b28167036994f1cadf7affb6fabf037891f 100644 (file)
@@ -184,12 +184,8 @@ function showHideByValue(trigger_field_id, trigger_value, target_element_id, tar
  * @return
  */
 function toggleCheckboxVals(fldPrefix, object) {
-  if (object.id == 'toggleSelect' && cj(object).is(':checked')) {
-    cj('Input[id*="' + fldPrefix + '"],Input[id*="toggleSelect"]').attr('checked', true);
-  }
-  else {
-    cj('Input[id*="' + fldPrefix + '"],Input[id*="toggleSelect"]').attr('checked', false);
-  }
+  var val = (object.id == 'toggleSelect' && cj(object).is(':checked'));
+  cj('Input[id*="' + fldPrefix + '"],Input[id*="toggleSelect"]').prop('checked', val);
   // change the class of selected rows
   on_load_init_checkboxes(object.form.name);
 }
@@ -293,8 +289,8 @@ function checkPerformAction(fldPrefix, form, taskButton, selection) {
  */
 function checkSelectedBox(chkName) {
   var checkElement = cj('#' + chkName);
-  if (checkElement.attr('checked')) {
-    cj('input[value=ts_sel]:radio').attr('checked', true);
+  if (checkElement.prop('checked')) {
+    cj('input[value=ts_sel]:radio').prop('checked', true);
     checkElement.parents('tr').addClass('crm-row-selected');
   }
   else {
@@ -447,58 +443,6 @@ function showHideRow(index) {
   return false;
 }
 
-/**
- * Function to check activity status in relavent to activity date
- *
- * @param element message JSON object.
- */
-function activityStatus(message) {
-  var d = new Date(), time = [], i;
-  var currentDateTime = d.getTime()
-  var activityTime = cj("input#activity_date_time_time").val().replace(":", "");
-
-  //chunk the time in bunch of 2 (hours,minutes,ampm)
-  for (i = 0; i < activityTime.length; i += 2) {
-    time.push(activityTime.slice(i, i + 2));
-  }
-  var activityDate = new Date(cj("input#activity_date_time_hidden").val());
-
-  d.setFullYear(activityDate.getFullYear());
-  d.setMonth(activityDate.getMonth());
-  d.setDate(activityDate.getDate());
-  var hours = time['0'];
-  var ampm = time['2'];
-
-  if (ampm == "PM" && hours != 0 && hours != 12) {
-    // force arithmetic instead of string concatenation
-    hours = hours * 1 + 12;
-  }
-  else {
-    if (ampm == "AM" && hours == 12) {
-      hours = 0;
-    }
-  }
-  d.setHours(hours);
-  d.setMinutes(time['1']);
-
-  var activity_date_time = d.getTime();
-
-  var activityStatusId = cj('#status_id').val();
-
-  if (activityStatusId == 2 && currentDateTime < activity_date_time) {
-    if (!confirm(message.completed)) {
-      return false;
-    }
-  }
-  else {
-    if (activity_date_time && activityStatusId == 1 && currentDateTime >= activity_date_time) {
-      if (!confirm(message.scheduled)) {
-        return false;
-      }
-    }
-  }
-}
-
 CRM.strings = CRM.strings || {};
 CRM.validate = CRM.validate || {
   params: {},
@@ -521,17 +465,10 @@ CRM.validate = CRM.validate || {
       }
       target.toggleClass('crm-row-selected', $(this).is(':checked'));
     });
-    $('#crm-container').live('click', function (event) {
+    $('body').on('click', function (event) {
+      $('.btn-slide-active').removeClass('btn-slide-active').find('.panel').hide();
       if ($(event.target).is('.btn-slide')) {
-        var currentActive = $('#crm-container .btn-slide-active');
-        currentActive.children().hide();
-        currentActive.removeClass('btn-slide-active');
-        $(event.target).children().show();
-        $(event.target).addClass('btn-slide-active');
-      }
-      else {
-        $('.btn-slide .panel').hide();
-        $('.btn-slide-active').removeClass('btn-slide-active');
+        $(event.target).addClass('btn-slide-active').find('.panel').show();
       }
     });
   });
@@ -820,12 +757,268 @@ CRM.validate = CRM.validate || {
     });
   }
 
+  $.widget('civi.crmSnippet', {
+    options: {
+      url: null,
+      block: true,
+      crmForm: null
+    },
+    _originalContent: null,
+    _originalUrl: null,
+    isOriginalUrl: function() {
+      var 
+        args = {}, 
+        same = true,
+        newUrl = this._formatUrl(this.options.url),
+        oldUrl = this._formatUrl(this._originalUrl);
+      // Compare path
+      if (newUrl.split('?')[0] !== oldUrl.split('?')[0]) {
+        return false;
+      }
+      // Compare arguments
+      $.each(newUrl.split('?')[1].split('&'), function(k, v) {
+        var arg = v.split('=');
+        args[arg[0]] = arg[1];
+      });
+      $.each(oldUrl.split('?')[1].split('&'), function(k, v) {
+        var arg = v.split('=');
+        if (args[arg[0]] !== undefined && arg[1] !== args[arg[0]]) {
+          same = false;
+        }
+      });
+      return same;
+    },
+    resetUrl: function() {
+      this.options.url = this._originalUrl;
+    },
+    _create: function() {
+      this.element.addClass('crm-ajax-container');
+      if (!this.element.is('.crm-container *')) {
+        this.element.addClass('crm-container');
+      }
+      this._handleOrderLinks();
+      // Set default if not supplied
+      this.options.url = this.options.url || document.location.href;
+      this._originalUrl = this.options.url;
+    },
+    _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) {
+      // Strip hash
+      url = url.split('#')[0];
+      // Add snippet argument to url
+      if (url.search(/[&?]snippet=/) < 0) {
+        url += (url.indexOf('?') < 0 ? '?' : '&') + 'snippet=json';
+      } else {
+        url = url.replace(/snippet=[^&]*/, 'snippet=json');
+      }
+      return url;
+    },
+    // Hack to deal with civicrm legacy sort functionality
+    _handleOrderLinks: function() {
+      var that = this;
+      $('a.crm-weight-arrow', that.element).click(function(e) {
+        that.options.block && that.element.block();
+        $.getJSON(that._formatUrl(this.href)).done(function() {
+          that.refresh();
+        });
+        e.stopImmediatePropagation();
+        return false;
+      });
+    },
+    refresh: function() {
+      var that = this;
+      var url = this._formatUrl(this.options.url);
+      this.options.block && $('.blockOverlay', this.element).length < 1 && this.element.block();
+      $.getJSON(url, function(data) {
+        if (typeof(data) != 'object' || typeof(data.content) != 'string') {
+          that._onFailure(data);
+          return;
+        }
+        data.url = url;
+        that.element.trigger('crmBeforeLoad', data);
+        if (that._originalContent === null) {
+          that._originalContent = that.element.contents().detach();
+        }
+        that.element.html(data.content);
+        that._handleOrderLinks();
+        that.element.trigger('crmLoad', data);
+        that.options.crmForm && that.element.trigger('crmFormLoad', data);
+      }).fail(function() {
+          that._onFailure();
+        });
+    },
+    _destroy: function() {
+      this.element.removeClass('crm-ajax-container');
+      if (this._originalContent !== null) {
+        this.element.empty().append(this._originalContent);
+      }
+    }
+  });
+
+  var dialogCount = 0;
+  CRM.loadPage = function(url, options) {
+    var settings = {
+      target: '#crm-ajax-dialog-' + (dialogCount++),
+      dialog: false
+    };
+    if (!options || !options.target) {
+      settings.dialog = {
+        modal: true,
+        width: '65%',
+        height: parseInt($(window).height() * .75),
+        close: function() {
+          $(this).dialog('destroy').remove();
+        }
+      };
+    }
+    options && $.extend(true, settings, options);
+    settings.url = url;
+    // Create new dialog
+    if (settings.dialog) {
+      $('<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);
+      });
+    }
+    $(settings.target).crmSnippet(settings).crmSnippet('refresh');
+    return $(settings.target);
+  };
+
+  CRM.loadForm = function(url, options) {
+    var settings = {
+      crmForm: {
+        ajaxForm: {},
+        autoClose: true,
+        validate: true,
+        refreshAction: ['next_new', 'submit_savenext'],
+        cancelButton: '.cancel.form-submit',
+        openInline: 'a.button:not("[href=#], .no-popup")',
+        onCancel: function(event) {},
+        onError: function(data) {
+          var $el = $(this);
+          $el.html(data.content).trigger('crmLoad', data).trigger('crmFormLoad', data).trigger('crmFormError', data);
+          if (typeof(data.errors) == 'object') {
+            $.each(data.errors, function(formElement, msg) {
+              $('[name="'+formElement+'"]', $el).crmError(msg);
+            });
+          }
+        }
+      }
+    };
+    // Hack to make delete dialogs smaller
+    if (url.indexOf('/delete') > 0 || url.indexOf('action=delete') > 0) {
+      settings.dialog = {
+        width: 400,
+        height: 300
+      };
+    }
+    // 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;
+      }
+    });
+
+    var widget = CRM.loadPage(url, settings);
+
+    widget.on('crmFormLoad', function(event, data) {
+      var $el = $(this);
+      var settings = $el.crmSnippet('option', 'crmForm');
+      settings.cancelButton && $(settings.cancelButton, this).click(function(event) {
+        var returnVal = settings.onCancel.call($el, event);
+        if (returnVal !== false) {
+          $el.trigger('crmFormCancel', event);
+          if ($el.data('uiDialog') && settings.autoClose) {
+            $el.dialog('close');
+          }
+          else if (!settings.autoClose) {
+            $el.crmSnippet('resetUrl').crmSnippet('refresh');
+          }
+        }
+        return returnVal === false;
+      });
+      if (settings.validate) {
+        $("form", this).validate(typeof(settings.validate) == 'object' ? settings.validate : CRM.validate.params);
+      }
+      $("form", this).ajaxForm($.extend({
+        url: data.url.replace(/reset=1[&]?/, ''),
+        dataType: 'json',
+        success: function(response) {
+          if (response.status !== 'form_error') {
+            $el.crmSnippet('option', 'block') && $el.unblock();
+            $el.trigger('crmFormSuccess', response);
+            // Reset form for e.g. "save and new"
+            if (response.userContext && settings.refreshAction && $.inArray(response.buttonName, settings.refreshAction) >= 0) {
+              $el.crmSnippet('option', 'url', response.userContext).crmSnippet('refresh');
+            }
+            else if ($el.data('uiDialog') && settings.autoClose) {
+              $el.dialog('close');
+            }
+            else if (settings.autoClose === false) {
+              $el.crmSnippet('resetUrl').crmSnippet('refresh');
+            }
+          }
+          else {
+            response.url = data.url;
+            settings.onError.call($el, response);
+          }
+        },
+        beforeSerialize: function(form, options) {
+          if (window.CKEDITOR && window.CKEDITOR.instances) {
+            $.each(CKEDITOR.instances, function() {
+              this.updateElement && this.updateElement();
+            });
+          }
+        },
+        beforeSubmit: function(submission) {
+          $el.crmSnippet('option', 'block') && $el.block();
+          $el.trigger('crmFormSubmit', submission);
+        }
+      }, settings.ajaxForm));
+      if (settings.openInline) {
+        settings.autoClose = $el.crmSnippet('isOriginalUrl');
+        $(settings.openInline, this).click(function(event) {
+          $el.crmSnippet('option', 'url', $(this).attr('href')).crmSnippet('refresh');
+          return false;
+        });
+      }
+    });
+    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
@@ -844,19 +1037,15 @@ CRM.validate = CRM.validate || {
   });
 
   $.fn.crmAccordions = function (speed) {
-    var container = $('#crm-container');
-    if (speed === undefined) {
-      speed = 200;
-    }
-    if ($(this).length > 0) {
-      container = $(this);
-    }
-    if (container.length > 0 && !container.hasClass('crm-accordion-processed')) {
+    var container = $(this).length > 0 ? $(this) : $('.crm-container');
+    speed = speed === undefined ? 200 : speed;
+    container
+      .off('click.crmAccordions')
       // Allow normal clicking of links
-      container.on('click', 'div.crm-accordion-header a', function (e) {
+      .on('click.crmAccordions', 'div.crm-accordion-header a', function (e) {
         e.stopPropagation && e.stopPropagation();
-      });
-      container.on('click', '.crm-accordion-header, .crm-collapsible .collapsible-title', function () {
+      })
+      .on('click.crmAccordions', '.crm-accordion-header, .crm-collapsible .collapsible-title', function () {
         if ($(this).parent().hasClass('collapsed')) {
           $(this).next().css('display', 'none').slideDown(speed);
         }
@@ -866,8 +1055,6 @@ CRM.validate = CRM.validate || {
         $(this).parent().toggleClass('collapsed');
         return false;
       });
-      container.addClass('crm-accordion-processed');
-    }
   };
   $.fn.crmAccordionToggle = function (speed) {
     $(this).each(function () {
@@ -884,8 +1071,9 @@ CRM.validate = CRM.validate || {
   /**
    * Clientside currency formatting
    * @param value
-   * @param format
+   * @param format - currency representation of the number 1234.56
    * @return string
+   * @see CRM_Core_Resources::addCoreResources
    */
   var currencyTemplate;
   CRM.formatMoney = function(value, format) {
@@ -904,7 +1092,6 @@ CRM.validate = CRM.validate || {
     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);