2 +--------------------------------------------------------------------+
3 | CiviCRM version 4.3 |
4 +--------------------------------------------------------------------+
5 | This file is a part of CiviCRM. |
7 | CiviCRM is free software; you can copy, modify, and distribute it |
8 | under the terms of the GNU Affero General Public License |
9 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
11 | CiviCRM is distributed in the hope that it will be useful, but |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
14 | See the GNU Affero General Public License for more details. |
16 | You should have received a copy of the GNU Affero General Public |
17 | License and the CiviCRM Licensing Exception along |
18 | with this program; if not, contact CiviCRM LLC |
19 | at info[AT]civicrm[DOT]org. If you have questions about the |
20 | GNU Affero General Public License or the licensing of CiviCRM, |
21 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
22 +--------------------------------------------------------------------+
25 * Copyright (C) 2012 Xavier Dutoit
26 * Licensed to CiviCRM under the Academic Free License version 3.0.
29 * This offers two features:
30 * - crmEditable() edit in place of a single field
31 * (mostly a wrapper that binds jeditable features with the ajax api and replies on crm-entity crmf-{field} html conventions)
32 * if you want to add an edit in place on a template:
33 * - add a class crm-entity and id {EntityName}-{Entityid} higher in the dom
34 * - add a class crm-editable and crmf-{FieldName} around the field (you can add a span if needed)
35 * - add data-action=create if you need to specify the api action to call (default setvalue)
36 * crmf- stands for crm field
38 * this embed a civicrm form and make it in place (load+ajaxForm)
39 * 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
45 $.fn
.crmEditable = function (options
) {
46 // for a jquery object (the crm-editable), find the entity name and id to apply the changes to
47 // call result function(entity,id). The caller is responsible to use these params and do the needed
48 var getEntityID = function (field
,result
) {
49 var domid
= $(field
).closest('.crm-entity');
51 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");
54 // trying to extract using the html5 data
55 if (domid
.data('entity')) {
56 result (domid
.data('entity'),domid
.data('id'));
59 domid
=domid
.attr('id');
61 console
&& console
.log
&& console
.log("FATAL crm-editable: Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
64 var e
=domid
.match(/(\S*)-(\S*)/);
66 console
&& console
.log
&& console
.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
72 // param in : a dom object that contains the field name as a class crmf-xxx
73 var getFieldName = function (field
) {
74 if ($(field
).data('field')) {
75 return $(field
).data('field');
77 var fieldName
=field
.className
.match(/crmf-(\S*)/)[1];
79 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}");
85 var checkable = function () {
86 $(this).change (function() {
87 var params
={sequential
:1};
89 var checked
= $(this).is(':checked');
90 if (!getEntityID (this,function (e
,id
) {
96 params
['field']=getFieldName(this);
99 params
['value']=checked
?'1':'0';//seems that the ajax backend gets lost with boolean
101 CRM
.api(entity
,'setvalue',params
,{
103 error: function (data
) {
104 editableSettings
.error
.call(this,entity
,params
.field
,checked
,data
);
106 success: function (data
) {
107 editableSettings
.success
.call(this,entity
,params
.field
,checked
,data
);
115 callBack:function(data
){
117 editableSettings
.error
.call (this,data
);
119 return editableSettings
.success
.call (this,data
);
122 error: function(entity
,field
,value
,data
) {
123 $(this).crmError(data
.error_message
, ts('Error'));
124 $(this).removeClass('crm-editable-saving');
126 success: function(entity
,field
,value
,data
) {
128 CRM
.alert('', ts('Saved'), 'success');
129 $i
.removeClass ('crm-editable-saving crm-error');
134 var editableSettings
= $.extend({}, defaults
, options
);
135 return this.each(function() {
139 if (this.nodeName
== "INPUT" && this.type
=="checkbox") {
140 checkable
.call(this,this);
144 if (this.nodeName
== 'A') {
145 if (this.className
.indexOf('crmf-') == -1) { // it isn't a jeditable field
146 var formSettings
= $.extend({}, editableSettings
.form
,
147 {source
: $i
.attr('href')
148 ,success: function (result
) {
149 if ($i
.hasClass('crm-dialog')) {
150 $('.ui-dialog').dialog('close').remove();
152 $i
.next().slideUp().remove();
153 $i
.trigger('success',result
);
156 var id
= $i
.closest('.crm-entity').attr('id');
158 var e
=id
.match(/(\S*)-(\S*)/);
160 console
&& console
.log
&& console
.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
161 formSettings
.entity
=e
[1];
162 formSettings
.id
=e
[2];
164 if ($i
.hasClass('crm-dialog')) {
165 $i
.click (function () {
166 var $n
=$('<div>Loading</div>').appendTo('body');
167 $n
.dialog ({modal
:true,width
:500});
168 $n
.crmForm (formSettings
);
172 $i
.click (function () {
174 if (!$n
.hasClass('crm-target')) {
175 $n
=$i
.after('<div class="crm-target"></div>').next();
180 $n
.crmForm (formSettings
);
190 tooltip
: 'Click to edit...',
191 placeholder
: '<span class="crm-editable-placeholder">Click to edit</span>',
192 data: function(value
, settings
) {
193 return value
.replace(/<(?:.|\n)*?>/gm, '');
196 if ($i
.data('placeholder')) {
197 settings
.placeholder
= $i
.data('placeholder');
199 settings
.placeholder
= '<span class="crm-editable-placeholder">Click to edit</span>';
201 if ($i
.data('tooltip')) {
202 settings
.placeholder
= $i
.data('tooltip')
204 settings
.tooltip
= 'Click to edit...';
206 if ($i
.data('type')) {
207 settings
.type
= $i
.data('type');
208 settings
.onblur
= 'submit';
210 if ($i
.data('options')){
211 settings
.data
= $i
.data('options');
213 if(settings
.type
== 'textarea'){
214 $i
.addClass ('crm-editable-textarea-enabled');
217 $i
.addClass ('crm-editable-enabled');
220 $i
.editable(function(value
,settings
) {
221 //$i.editable(function(value,editableSettings) {
222 parent
=$i
.closest('.crm-entity');
224 console
&& console
.log
&& console
.log("crm-editable: you need to define one parent element that has a class .crm-entity");
228 $i
.addClass ('crm-editable-saving');
231 params
['field']=getFieldName(this);
232 if (!params
['field'])
234 params
['value']=value
;
235 if (!getEntityID (this,function (e
,id
) {
240 if (params
.id
== "new") {
244 if ($i
.data('action')) {
245 var fieldName
= params
['field'];
246 delete params
['field'];
247 delete params
['value'];
249 params
[fieldName
]=value
;//format for create at least
250 action
=$i
.data('action');
254 CRM
.api(entity
, action
, params
, {
256 error: function (data
) {
257 editableSettings
.error
.call(this,entity
,fieldName
,value
,data
);
259 success: function (data
) {
260 if ($i
.data('options')){
261 value
= $i
.data('options')[value
];
263 editableSettings
.success
.call(this,entity
,fieldName
,value
,data
);
270 $.fn
.crmForm = function (options
) {
271 var settings
= $.extend( {
278 'load' : function (target
){},
279 'success' : function (result
) {
280 $(this).html(ts('Saved'));
285 return this.each(function() {
286 var formLoaded = function (target
) {
287 var $this =$(target
);
288 var destination
="<input type='hidden' name='civicrmDestination' value='"+CRM
.url('civicrm/ajax/rest',{
289 'sequential':settings
.sequential
,
291 'entity':settings
.entity
,
292 'action':settings
.action
,
295 $this.find('form').ajaxForm({
296 beforeSubmit :function () {
297 $this.html("<div class='crm-editable-saving'>Saving...</div>");
300 success:function(response
) {
301 if (response
.indexOf('crm-error') >= 0) { // we got an error, re-display the page
302 $this.html(response
);
305 if (response
[0] == '{')
306 settings
.success($.parseJSON (response
));
308 settings
.success(response
);
311 }).append('<input type="hidden" name="snippet" value="1"/>'+destination
).trigger('load');
313 settings
.load(target
);
317 if (settings
.source
&& settings
.source
.indexOf('snippet') == -1) {
318 if (settings
.source
.indexOf('?') >= 0)
319 settings
.source
= settings
.source
+ "&snippet=1";
321 settings
.source
= settings
.source
+ "?snippet=1";
325 $this.html ("Loading...");
327 $this.dialog({width
:'auto',minWidth
:600});
328 $this.load (settings
.source
,function (){formLoaded(this)});