CRM-13817 - Migrate simple success messages to mini-notifications
[civicrm-core.git] / js / jquery / jquery.crmeditable.js
index f4a32c0096571ab2b2751b89a2c8d355e74e18c4..b581ec4adc641e58fe311aae56441cfeb7e28d4f 100644 (file)
-/*
- +--------------------------------------------------------------------+
- | CiviCRM version 4.3                                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
-
-*
-* Copyright (C) 2012 Xavier Dutoit
-* Licensed to CiviCRM under the Academic Free License version 3.0.
-*
-*
-* This offers two features:
-* - crmEditable() edit in place of a single field 
-*  (mostly a wrapper that binds jeditable features with the ajax api and replies on crm-entity crmf-{field} html conventions)
-*  if you want to add an edit in place on a template:
-*  - add a class crm-entity and id {EntityName}-{Entityid} higher in the dom
-*  - add a class crm-editable and crmf-{FieldName} around the field (you can add a span if needed)
-*  - add data-action=create if you need to specify the api action to call (default setvalue)
-*  crmf- stands for crm field
-* - crmForm()
-*   this embed a civicrm form and make it in place (load+ajaxForm) 
-*   to make it easier to customize the form (eg. hide a button...) it triggers a 'load' event on the form. you can then catch the load on your code (using the $('#id_of_the_form').on(function(){//do something
-*/
-
-
+/**
+ * Copyright (C) 2012 Xavier Dutoit
+ * Licensed to CiviCRM under the Academic Free License version 3.0.
+ *
+ * @see http://wiki.civicrm.org/confluence/display/CRMDOC/Structure+convention+for+automagic+edit+in+place
+ */
 (function($) {
-
-    $.fn.crmEditable = function (options) {
-      // for a jquery object (the crm-editable), find the entity name and id to apply the changes to
-      // call result function(entity,id). The caller is responsible to use these params and do the needed
-      var getEntityID = function (field,result) {
-        var domid= $(field).closest('.crm-entity');
-        if (!domid) {
-          console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' on a parent element of the field");
-          return false;
-        }
-        // trying to extract using the html5 data
-        if (domid.data('entity')) {
-          result (domid.data('entity'),domid.data('id'));
-          return true;
-        }
-        domid=domid.attr('id');
-        if (!domid) {
-          console && console.log && console.log("FATAL crm-editable: Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
-          return false;
-        }
-        var e=domid.match(/(\S*)-(\S*)/);
-        if (!e) {
-           console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
-           return false;
+  $.fn.crmEditableEntity = function() {
+    var
+      el = this[0],
+      ret = {},
+      $row = this.first().closest('.crm-entity');
+    ret.entity = $row.data('entity') || $row[0].id.split('-')[0];
+    ret.id = $row.data('id') || $row[0].id.split('-')[1];
+    if (!ret.entity || !ret.id) {
+      return false;
+    }
+    $('.crm-editable, [data-field]', $row).each(function() {
+      var fieldName = $(this).data('field') || this.className.match(/crmf-(\S*)/)[1];
+      if (fieldName) {
+        ret[fieldName] = $(this).text();
+        if (this === el) {
+          ret.field = fieldName;
         }
-        result(e[1],e[2]);
-        return true;
       }
-      // param in : a dom object that contains the field name as a class crmf-xxx
-      var getFieldName = function (field) {
-        if ($(field).data('field')) {
-           return $(field).data('field');   
-        }  
-        var fieldName=field.className.match(/crmf-(\S*)/)[1];
-        if (!fieldName) {
-          console && console.log && console.log("Couldn't get the crm-editable field name to modify. You need to set crmf-{field_name} or data-{field_name}");
+    });
+    return ret;
+  };
+
+  $.fn.crmEditable = function(options) {
+    var checkable = function() {
+      $(this).change(function() {
+        var info = $(this).crmEditableEntity();
+        if (!info.field) {
           return false;
         }
-        return fieldName;
-      }
-
-      var checkable = function () {
-        $(this).change (function() {
-          var params={sequential:1};
-          var entity = null;
-          var checked = $(this).is(':checked');
-          if  (!getEntityID (this,function (e,id) {
-            entity=e;
-            params.id = id;
-            
-          })) { return };
-
-          params['field']=getFieldName(this);
-          if (!params['field'])
-            return false;
-          params['value']=checked?'1':'0';//seems that the ajax backend gets lost with boolean
-
-          //CRM.api.call(this,entity,'create',params,{ create is still too buggy & perf
-          CRM.api.call(this,entity,'setvalue',params,{
-            error: function (data) {
-              editableSettings.error.call(this,entity,fieldName,checked,data);
-            },
-            success: function (data) {
-              editableSettings.success.call(this,entity,fieldName,checked,data);
-            }
-          });
-        });
-      };
-
-      var defaults = {
-        form:{},
-        callBack:function(data){
-          if (data.is_error) {
-            editableSettings.error.call (this,data);
-          } else {
-             return editableSettings.success.call (this,data);
+        var checked = $(this).is(':checked');
+        var params = {
+          sequential: 1,
+          id: info.id,
+          field: info.field,
+          value: checked ? 1 : 0
+        };
+        CRM.api(info.entity, 'setvalue', params, {
+          context: this,
+          error: function(data) {
+            editableSettings.error.call(this, info.entity, info.field, checked, data);
+          },
+          success: function(data) {
+            editableSettings.success.call(this, info.entity, info.field, checked, data);
           }
-        },
-        error: function(entity,field,value,data) {
-          $(this).crmError(data.error_message, ts('Error'));
-          $(this).removeClass('crm-editable-saving');
-        },
-        success: function(entity,field,value,data) {
-          var $i = $(this);
-          CRM.alert('', ts('Saved'), 'success');
-          $i.removeClass ('crm-editable-saving crm-error');
-          $i.html(value);
+        });
+      });
+    };
+
+    var defaults = {
+      form: {},
+      callBack: function(data) {
+        if (data.is_error) {
+          editableSettings.error.call(this, data);
+        } else {
+          return editableSettings.success.call(this, data);
         }
-      }
-
-      var editableSettings = $.extend({}, defaults, options);
-      return this.each(function() {
+      },
+      error: function(entity, field, value, data) {
+        $(this).crmError(data.error_message, ts('Error'));
+        $(this).removeClass('crm-editable-saving');
+      },
+      success: function(entity, field, value, data) {
         var $i = $(this);
-        var fieldName = "";
-      
-        if (this.nodeName == "INPUT" && this.type=="checkbox") {
-          checkable.call(this,this);
-          return;
-        }
+        CRM.status(ts('Saved'));
+        $i.removeClass('crm-editable-saving crm-error');
+        $i.html(value);
+      }
+    };
 
-        if (this.nodeName = 'A') {
-          if (this.className.indexOf('crmf-') == -1) { // it isn't a jeditable field
-            var formSettings= $.extend({}, editableSettings.form ,
-              {source: $i.attr('href')
-              ,success: function (result) {
-                if ($i.hasClass('crm-dialog')) {
-                  $('.ui-dialog').dialog('close').remove();
-                } else 
-                  $i.next().slideUp().remove();
-                $i.trigger('success',result);
-              }
-              });
-            var id= $i.closest('.crm-entity').attr('id');
-            if (id) {
-              var e=id.match(/(\S*)-(\S*)/);
-               if (!e) 
-                 console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
-              formSettings.entity=e[1];
-              formSettings.id=e[2];
-            } 
-            if ($i.hasClass('crm-dialog')) {
-              $i.click (function () {
-                var $n=$('<div>Loading</div>').appendTo('body');
-                $n.dialog ({modal:true,width:500});
-                $n.crmForm (formSettings);
-                return false; 
-              });
-            } else {
-              $i.click (function () {
-                var $n=$i.next();
-                if (!$n.hasClass('crm-target')) {
-                  $n=$i.after('<div class="crm-target"></div>').next();
-                } else {
-                  $n.slideToggle();
-                  return false;
-                };
-                $n.crmForm (formSettings);
-                return false; 
-              });
-            }
-            return;
-          }
-        }
+    var editableSettings = $.extend({}, defaults, options);
+    return this.each(function() {
+      var $i = $(this);
+      var fieldName = "";
 
+      if (this.nodeName == "INPUT" && this.type == "checkbox") {
+        checkable.call(this, this);
+        return;
+      }
 
-        var settings = {
-          tooltip   : 'Click to edit...',
-          placeholder  : '<span class="crm-editable-placeholder">Click to edit</span>',
-          data: function(value, settings) {
-            return value.replace(/<(?:.|\n)*?>/gm, '');
-          }
-        };
-        if ($i.data('placeholder')) {
-          settings.placeholder = $i.data('placeholder');
-        } else {
-          settings.placeholder  = '<span class="crm-editable-placeholder">Click to edit</span>';
-        }
-        if ($i.data('tooltip')) {
-          settings.placeholder = $i.data('tooltip')
-        } else {
-          settings.tooltip   = 'Click to edit...';
+      var settings = {
+        tooltip: 'Click to edit...',
+        placeholder: '<span class="crm-editable-placeholder">Click to edit</span>',
+        data: function(value, settings) {
+          return value.replace(/<(?:.|\n)*?>/gm, '');
         }
-        if ($i.data('type')) {
-          settings.type = $i.data('type');
-          settings.onblur = 'submit';
+      };
+      if ($i.data('placeholder')) {
+        settings.placeholder = $i.data('placeholder');
+      } else {
+        settings.placeholder = '<span class="crm-editable-placeholder">Click to edit</span>';
+      }
+      if ($i.data('tooltip')) {
+        settings.placeholder = $i.data('tooltip')
+      } else {
+        settings.tooltip = 'Click to edit...';
+      }
+      if ($i.data('type')) {
+        settings.type = $i.data('type');
+        settings.onblur = 'submit';
+      }
+      if ($i.data('options')) {
+        settings.data = $i.data('options');
+      }
+      if (settings.type == 'textarea') {
+        $i.addClass('crm-editable-textarea-enabled');
+      }
+      else {
+        $i.addClass('crm-editable-enabled');
+      }
+
+      $i.editable(function(value, settings) {
+        $i.addClass('crm-editable-saving');
+        var
+          info = $i.crmEditableEntity(),
+          params = {},
+          action = $i.data('action') || 'setvalue';
+        if (!info.field) {
+          return false;
         }
-        if ($i.data('options')){
-          settings.data = $i.data('options');
+        if (info.id && info.id !== 'new') {
+          params.id = info.id;
         }
-        if(settings.type == 'textarea'){
-          $i.addClass ('crm-editable-textarea-enabled');
+        if (action === 'setvalue') {
+          params.field = info.field;
+          params.value = value;
         }
-        else{
-          $i.addClass ('crm-editable-enabled');
+        else {
+          params[info.field] = value;
         }
-
-        $i.editable(function(value,settings) {
-        //$i.editable(function(value,editableSettings) {
-          parent=$i.closest('.crm-entity');
-          if (!parent) {
-            console && console.log && console.log("crm-editable: you need to define one parent element that has a class .crm-entity");
-            return;
-          }
-
-          $i.addClass ('crm-editable-saving');
-          var params = {};
-          var entity = null;
-          params['field']=getFieldName(this);
-          if (!params['field'])
-            return false;
-          params['value']=value;
-          if  (!getEntityID (this,function (e,id) {
-            entity=e;
-            params.id = id;
-          })) {return;}
-
-          if (params.id == "new") {
-            params.id = '';
-          }
-
-          if ($i.data('action')) {
-            params[params['field']]=value;//format for create at least
-            action=$i.data('action');
-            delete params['field'];
-            delete params['value'];
-          } else {
-            action="setvalue";
-          }
-          CRM.api.call(this,entity,action,params,{
-              error: function (data) {
-                editableSettings.error.call(this,entity,fieldName,value,data);
-              },
-              success: function (data) {
-                if ($i.data('options')){
-                  value = $i.data('options')[value];
-                }
-                editableSettings.success.call(this,entity,fieldName,value,data);
-              }
-            });
-           },settings);
-    });
-  }
-
-  $.fn.crmForm = function (options ) {
-    var settings = $.extend( {
-      'title':'',
-      'entity':'',
-      'action':'get',
-      'id':0,
-      'sequential':1,
-      'dialog': false,
-      'load' : function (target){},
-      'success' : function (result) {
-        $(this).html(ts('Saved'));
-       }
-    }, options);
-
-
-    return this.each(function() {
-      var formLoaded = function (target) {
-        var $this =$(target);
-        var destination="<input type='hidden' name='civicrmDestination' value='"+CRM.url('civicrm/ajax/rest',{
-          'sequential':settings.sequential,
-          'json':'html',
-          'entity':settings.entity,
-          'action':settings.action,
-          'id':settings.id
-          })+"' />";
-        $this.find('form').ajaxForm({
-          beforeSubmit :function () {
-            $this.html("<div class='crm-editable-saving'>Saving...</div>");
-            return true;
+        CRM.api(info.entity, action, params, {
+          context: this,
+          error: function(data) {
+            editableSettings.error.call(this, info.entity, info.field, value, data);
           },
-          success:function(response) { 
-            if (response.indexOf('crm-error') >= 0) { // we got an error, re-display the page
-              $this.html(response);
-              formLoaded(target);
-            } else {
-              if (response[0] == '{')
-                settings.success($.parseJSON (response));
-              else
-                settings.success(response);
+          success: function(data) {
+            if ($i.data('options')) {
+              value = $i.data('options')[value];
             }
+            $i.trigger('crmFormSuccess');
+            editableSettings.success.call(this, info.entity, info.field, value, data);
           }
-        }).append('<input type="hidden" name="snippet" value="1"/>'+destination).trigger('load'); 
-
-        settings.load(target);
-      };
-
-      var $this = $(this);
-       if (settings.source && settings.source.indexOf('snippet') == -1) {
-         if (settings.source.indexOf('?') >= 0)
-           settings.source = settings.source + "&snippet=1";
-         else
-           settings.source = settings.source + "?snippet=1";
-       }
-
-
-       $this.html ("Loading...");
-       if (settings.dialog)
-         $this.dialog({width:'auto',minWidth:600});
-       $this.load (settings.source ,function (){formLoaded(this)});
-
+        });
+      }, settings);
     });
   };