Commit | Line | Data |
---|---|---|
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); |