CRM-14015 CRM-14023 - Extend new enable/disable to acl page (and add acl api)
[civicrm-core.git] / js / jquery / jquery.crmeditable.js
CommitLineData
1fe97a01 1/**
6a488035
TO
2* Copyright (C) 2012 Xavier Dutoit
3* Licensed to CiviCRM under the Academic Free License version 3.0.
4*
5*
6* This offers two features:
2efcf0c2 7* - crmEditable() edit in place of a single field
6a488035
TO
8* (mostly a wrapper that binds jeditable features with the ajax api and replies on crm-entity crmf-{field} html conventions)
9* if you want to add an edit in place on a template:
10* - add a class crm-entity and id {EntityName}-{Entityid} higher in the dom
11* - add a class crm-editable and crmf-{FieldName} around the field (you can add a span if needed)
12* - add data-action=create if you need to specify the api action to call (default setvalue)
13* crmf- stands for crm field
14* - crmForm()
15* this embed a civicrm form and make it in place (load+ajaxForm)
16* 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
17*/
18
6a488035
TO
19(function($) {
20
21 $.fn.crmEditable = function (options) {
22 // for a jquery object (the crm-editable), find the entity name and id to apply the changes to
23 // call result function(entity,id). The caller is responsible to use these params and do the needed
24 var getEntityID = function (field,result) {
25 var domid= $(field).closest('.crm-entity');
26 if (!domid) {
27 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");
28 return false;
29 }
30 // trying to extract using the html5 data
31 if (domid.data('entity')) {
32 result (domid.data('entity'),domid.data('id'));
33 return true;
34 }
35 domid=domid.attr('id');
36 if (!domid) {
37 console && console.log && console.log("FATAL crm-editable: Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
38 return false;
39 }
40 var e=domid.match(/(\S*)-(\S*)/);
41 if (!e) {
42 console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
43 return false;
44 }
45 result(e[1],e[2]);
46 return true;
47 }
48 // param in : a dom object that contains the field name as a class crmf-xxx
49 var getFieldName = function (field) {
1fe97a01 50 var fieldName = $(field).data('field') || field.className.match(/crmf-(\S*)/)[1];
6a488035
TO
51 if (!fieldName) {
52 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}");
6a488035
TO
53 }
54 return fieldName;
55 }
56
6a488035
TO
57 var checkable = function () {
58 $(this).change (function() {
59 var params={sequential:1};
60 var entity = null;
61 var checked = $(this).is(':checked');
62 if (!getEntityID (this,function (e,id) {
63 entity=e;
64 params.id = id;
2efcf0c2 65
6a488035
TO
66 })) { return };
67
68 params['field']=getFieldName(this);
69 if (!params['field'])
70 return false;
71 params['value']=checked?'1':'0';//seems that the ajax backend gets lost with boolean
72
e32d748a
CW
73 CRM.api(entity,'setvalue',params,{
74 context: this,
6a488035 75 error: function (data) {
cc0478c1 76 editableSettings.error.call(this,entity,params.field,checked,data);
6a488035
TO
77 },
78 success: function (data) {
cc0478c1 79 editableSettings.success.call(this,entity,params.field,checked,data);
6a488035
TO
80 }
81 });
82 });
83 };
84
85 var defaults = {
86 form:{},
87 callBack:function(data){
88 if (data.is_error) {
89 editableSettings.error.call (this,data);
90 } else {
91 return editableSettings.success.call (this,data);
92 }
93 },
94 error: function(entity,field,value,data) {
95 $(this).crmError(data.error_message, ts('Error'));
96 $(this).removeClass('crm-editable-saving');
97 },
98 success: function(entity,field,value,data) {
99 var $i = $(this);
100 CRM.alert('', ts('Saved'), 'success');
101 $i.removeClass ('crm-editable-saving crm-error');
102 $i.html(value);
103 }
104 }
105
106 var editableSettings = $.extend({}, defaults, options);
107 return this.each(function() {
108 var $i = $(this);
109 var fieldName = "";
110
111 if (this.nodeName == "INPUT" && this.type=="checkbox") {
112 checkable.call(this,this);
113 return;
114 }
115
6017af4d 116 if (this.nodeName == 'A') {
6a488035
TO
117 if (this.className.indexOf('crmf-') == -1) { // it isn't a jeditable field
118 var formSettings= $.extend({}, editableSettings.form ,
119 {source: $i.attr('href')
120 ,success: function (result) {
121 if ($i.hasClass('crm-dialog')) {
122 $('.ui-dialog').dialog('close').remove();
123 } else
124 $i.next().slideUp().remove();
125 $i.trigger('success',result);
126 }
127 });
128 var id= $i.closest('.crm-entity').attr('id');
129 if (id) {
130 var e=id.match(/(\S*)-(\S*)/);
2efcf0c2 131 if (!e)
6a488035
TO
132 console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
133 formSettings.entity=e[1];
134 formSettings.id=e[2];
e1f05567 135 }
6a488035
TO
136 if ($i.hasClass('crm-dialog')) {
137 $i.click (function () {
138 var $n=$('<div>Loading</div>').appendTo('body');
139 $n.dialog ({modal:true,width:500});
140 $n.crmForm (formSettings);
e1f05567 141 return false;
6a488035
TO
142 });
143 } else {
144 $i.click (function () {
145 var $n=$i.next();
146 if (!$n.hasClass('crm-target')) {
147 $n=$i.after('<div class="crm-target"></div>').next();
148 } else {
149 $n.slideToggle();
150 return false;
151 };
152 $n.crmForm (formSettings);
e1f05567 153 return false;
6a488035
TO
154 });
155 }
156 return;
157 }
158 }
159
160
161 var settings = {
162 tooltip : 'Click to edit...',
163 placeholder : '<span class="crm-editable-placeholder">Click to edit</span>',
164 data: function(value, settings) {
165 return value.replace(/<(?:.|\n)*?>/gm, '');
166 }
167 };
168 if ($i.data('placeholder')) {
169 settings.placeholder = $i.data('placeholder');
170 } else {
171 settings.placeholder = '<span class="crm-editable-placeholder">Click to edit</span>';
172 }
173 if ($i.data('tooltip')) {
174 settings.placeholder = $i.data('tooltip')
175 } else {
176 settings.tooltip = 'Click to edit...';
177 }
178 if ($i.data('type')) {
179 settings.type = $i.data('type');
180 settings.onblur = 'submit';
181 }
182 if ($i.data('options')){
183 settings.data = $i.data('options');
184 }
185 if(settings.type == 'textarea'){
186 $i.addClass ('crm-editable-textarea-enabled');
187 }
188 else{
189 $i.addClass ('crm-editable-enabled');
190 }
191
192 $i.editable(function(value,settings) {
193 //$i.editable(function(value,editableSettings) {
194 parent=$i.closest('.crm-entity');
195 if (!parent) {
196 console && console.log && console.log("crm-editable: you need to define one parent element that has a class .crm-entity");
197 return;
198 }
199
200 $i.addClass ('crm-editable-saving');
201 var params = {};
202 var entity = null;
203 params['field']=getFieldName(this);
204 if (!params['field'])
205 return false;
206 params['value']=value;
207 if (!getEntityID (this,function (e,id) {
208 entity=e;
209 params.id = id;
210 })) {return;}
211
212 if (params.id == "new") {
213 params.id = '';
214 }
215
216 if ($i.data('action')) {
6017af4d 217 var fieldName = params['field'];
e5eb8657 218 delete params['field'];
219 delete params['value'];
6017af4d
XD
220
221 params[fieldName]=value;//format for create at least
222 action=$i.data('action');
6a488035
TO
223 } else {
224 action="setvalue";
225 }
e32d748a
CW
226 CRM.api(entity, action, params, {
227 context: this,
6a488035
TO
228 error: function (data) {
229 editableSettings.error.call(this,entity,fieldName,value,data);
230 },
231 success: function (data) {
232 if ($i.data('options')){
233 value = $i.data('options')[value];
234 }
235 editableSettings.success.call(this,entity,fieldName,value,data);
236 }
237 });
238 },settings);
239 });
240 }
241
242 $.fn.crmForm = function (options ) {
243 var settings = $.extend( {
244 'title':'',
245 'entity':'',
246 'action':'get',
247 'id':0,
248 'sequential':1,
249 'dialog': false,
250 'load' : function (target){},
251 'success' : function (result) {
252 $(this).html(ts('Saved'));
253 }
254 }, options);
255
256
257 return this.each(function() {
258 var formLoaded = function (target) {
259 var $this =$(target);
260 var destination="<input type='hidden' name='civicrmDestination' value='"+CRM.url('civicrm/ajax/rest',{
261 'sequential':settings.sequential,
262 'json':'html',
263 'entity':settings.entity,
264 'action':settings.action,
265 'id':settings.id
266 })+"' />";
267 $this.find('form').ajaxForm({
268 beforeSubmit :function () {
269 $this.html("<div class='crm-editable-saving'>Saving...</div>");
270 return true;
271 },
e1f05567 272 success:function(response) {
6a488035
TO
273 if (response.indexOf('crm-error') >= 0) { // we got an error, re-display the page
274 $this.html(response);
275 formLoaded(target);
276 } else {
277 if (response[0] == '{')
278 settings.success($.parseJSON (response));
279 else
280 settings.success(response);
281 }
282 }
e1f05567 283 }).append('<input type="hidden" name="snippet" value="1"/>'+destination).trigger('load');
6a488035
TO
284
285 settings.load(target);
286 };
287
288 var $this = $(this);
289 if (settings.source && settings.source.indexOf('snippet') == -1) {
290 if (settings.source.indexOf('?') >= 0)
291 settings.source = settings.source + "&snippet=1";
292 else
293 settings.source = settings.source + "?snippet=1";
294 }
295
296
297 $this.html ("Loading...");
298 if (settings.dialog)
299 $this.dialog({width:'auto',minWidth:600});
300 $this.load (settings.source ,function (){formLoaded(this)});
301
302 });
303 };
304
305})(jQuery);