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