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 | ||
d4838efc CW |
21 | $.fn.crmEditableEntity = function() { |
22 | var | |
23 | el = this[0], | |
24 | ret = {}, | |
25 | $row = this.first().closest('.crm-entity'); | |
7d644ac8 CW |
26 | ret.entity = $row.data('entity') || $row[0].id.split('-')[0]; |
27 | ret.id = $row.data('id') || $row[0].id.split('-')[1]; | |
d4838efc CW |
28 | if (!ret.entity || !ret.id) { |
29 | return false; | |
30 | } | |
60158442 | 31 | $('.crm-editable, [data-field]', $row).each(function() { |
d4838efc CW |
32 | var fieldName = $(this).data('field') || this.className.match(/crmf-(\S*)/)[1]; |
33 | if (fieldName) { | |
34 | ret[fieldName] = $(this).text(); | |
35 | if (this === el) { | |
36 | ret.field = fieldName; | |
6a488035 | 37 | } |
6a488035 | 38 | } |
d4838efc CW |
39 | }); |
40 | return ret; | |
41 | }; | |
6a488035 | 42 | |
d4838efc | 43 | $.fn.crmEditable = function (options) { |
6a488035 TO |
44 | var checkable = function () { |
45 | $(this).change (function() { | |
d4838efc CW |
46 | var info = $(this).crmEditableEntity(); |
47 | if (!info.field) { | |
6a488035 | 48 | return false; |
d4838efc CW |
49 | } |
50 | var checked = $(this).is(':checked'); | |
51 | var params = { | |
52 | sequential: 1, | |
53 | id: info.id, | |
54 | field: info.field, | |
55 | value: checked ? 1 : 0 | |
56 | }; | |
57 | CRM.api(info.entity, 'setvalue', params, { | |
e32d748a | 58 | context: this, |
6a488035 | 59 | error: function (data) { |
d4838efc | 60 | editableSettings.error.call(this, info.entity, info.field, checked, data); |
6a488035 TO |
61 | }, |
62 | success: function (data) { | |
d4838efc | 63 | editableSettings.success.call(this, info.entity, info.field, checked, data); |
6a488035 TO |
64 | } |
65 | }); | |
66 | }); | |
67 | }; | |
68 | ||
69 | var defaults = { | |
70 | form:{}, | |
71 | callBack:function(data){ | |
72 | if (data.is_error) { | |
73 | editableSettings.error.call (this,data); | |
74 | } else { | |
75 | return editableSettings.success.call (this,data); | |
76 | } | |
77 | }, | |
78 | error: function(entity,field,value,data) { | |
79 | $(this).crmError(data.error_message, ts('Error')); | |
80 | $(this).removeClass('crm-editable-saving'); | |
81 | }, | |
82 | success: function(entity,field,value,data) { | |
83 | var $i = $(this); | |
84 | CRM.alert('', ts('Saved'), 'success'); | |
85 | $i.removeClass ('crm-editable-saving crm-error'); | |
86 | $i.html(value); | |
87 | } | |
88 | } | |
89 | ||
90 | var editableSettings = $.extend({}, defaults, options); | |
91 | return this.each(function() { | |
92 | var $i = $(this); | |
93 | var fieldName = ""; | |
94 | ||
95 | if (this.nodeName == "INPUT" && this.type=="checkbox") { | |
96 | checkable.call(this,this); | |
97 | return; | |
98 | } | |
99 | ||
6017af4d | 100 | if (this.nodeName == 'A') { |
6a488035 TO |
101 | if (this.className.indexOf('crmf-') == -1) { // it isn't a jeditable field |
102 | var formSettings= $.extend({}, editableSettings.form , | |
103 | {source: $i.attr('href') | |
104 | ,success: function (result) { | |
105 | if ($i.hasClass('crm-dialog')) { | |
106 | $('.ui-dialog').dialog('close').remove(); | |
107 | } else | |
108 | $i.next().slideUp().remove(); | |
109 | $i.trigger('success',result); | |
110 | } | |
111 | }); | |
112 | var id= $i.closest('.crm-entity').attr('id'); | |
113 | if (id) { | |
114 | var e=id.match(/(\S*)-(\S*)/); | |
2efcf0c2 | 115 | if (!e) |
6a488035 TO |
116 | console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'"); |
117 | formSettings.entity=e[1]; | |
118 | formSettings.id=e[2]; | |
e1f05567 | 119 | } |
6a488035 TO |
120 | if ($i.hasClass('crm-dialog')) { |
121 | $i.click (function () { | |
122 | var $n=$('<div>Loading</div>').appendTo('body'); | |
123 | $n.dialog ({modal:true,width:500}); | |
124 | $n.crmForm (formSettings); | |
e1f05567 | 125 | return false; |
6a488035 TO |
126 | }); |
127 | } else { | |
128 | $i.click (function () { | |
129 | var $n=$i.next(); | |
130 | if (!$n.hasClass('crm-target')) { | |
131 | $n=$i.after('<div class="crm-target"></div>').next(); | |
132 | } else { | |
133 | $n.slideToggle(); | |
134 | return false; | |
135 | }; | |
136 | $n.crmForm (formSettings); | |
e1f05567 | 137 | return false; |
6a488035 TO |
138 | }); |
139 | } | |
140 | return; | |
141 | } | |
142 | } | |
143 | ||
144 | ||
145 | var settings = { | |
146 | tooltip : 'Click to edit...', | |
147 | placeholder : '<span class="crm-editable-placeholder">Click to edit</span>', | |
148 | data: function(value, settings) { | |
149 | return value.replace(/<(?:.|\n)*?>/gm, ''); | |
150 | } | |
151 | }; | |
152 | if ($i.data('placeholder')) { | |
153 | settings.placeholder = $i.data('placeholder'); | |
154 | } else { | |
155 | settings.placeholder = '<span class="crm-editable-placeholder">Click to edit</span>'; | |
156 | } | |
157 | if ($i.data('tooltip')) { | |
158 | settings.placeholder = $i.data('tooltip') | |
159 | } else { | |
160 | settings.tooltip = 'Click to edit...'; | |
161 | } | |
162 | if ($i.data('type')) { | |
163 | settings.type = $i.data('type'); | |
164 | settings.onblur = 'submit'; | |
165 | } | |
166 | if ($i.data('options')){ | |
167 | settings.data = $i.data('options'); | |
168 | } | |
169 | if(settings.type == 'textarea'){ | |
170 | $i.addClass ('crm-editable-textarea-enabled'); | |
171 | } | |
172 | else{ | |
173 | $i.addClass ('crm-editable-enabled'); | |
174 | } | |
175 | ||
176 | $i.editable(function(value,settings) { | |
6a488035 | 177 | $i.addClass ('crm-editable-saving'); |
d4838efc CW |
178 | var |
179 | info = $i.crmEditableEntity(), | |
180 | params= {}, | |
181 | action = $i.data('action') || 'setvalue'; | |
182 | if (!info.field) { | |
6a488035 | 183 | return false; |
6a488035 | 184 | } |
d4838efc CW |
185 | if (info.id && info.id !== 'new') { |
186 | params.id = info.id; | |
187 | } | |
188 | if (action === 'setvalue') { | |
189 | params.field = info.field; | |
190 | params.value = value; | |
191 | } | |
192 | else { | |
193 | params[info.field] = value; | |
6a488035 | 194 | } |
d4838efc | 195 | CRM.api(info.entity, action, params, { |
e32d748a | 196 | context: this, |
6a488035 | 197 | error: function (data) { |
d4838efc | 198 | editableSettings.error.call(this, info.entity, info.field, value, data); |
6a488035 TO |
199 | }, |
200 | success: function (data) { | |
201 | if ($i.data('options')){ | |
202 | value = $i.data('options')[value]; | |
203 | } | |
d4838efc | 204 | editableSettings.success.call(this, info.entity, info.field, value, data); |
6a488035 TO |
205 | } |
206 | }); | |
207 | },settings); | |
208 | }); | |
209 | } | |
210 | ||
211 | $.fn.crmForm = function (options ) { | |
212 | var settings = $.extend( { | |
213 | 'title':'', | |
214 | 'entity':'', | |
215 | 'action':'get', | |
216 | 'id':0, | |
217 | 'sequential':1, | |
218 | 'dialog': false, | |
219 | 'load' : function (target){}, | |
220 | 'success' : function (result) { | |
221 | $(this).html(ts('Saved')); | |
222 | } | |
223 | }, options); | |
224 | ||
225 | ||
226 | return this.each(function() { | |
227 | var formLoaded = function (target) { | |
228 | var $this =$(target); | |
229 | var destination="<input type='hidden' name='civicrmDestination' value='"+CRM.url('civicrm/ajax/rest',{ | |
230 | 'sequential':settings.sequential, | |
231 | 'json':'html', | |
232 | 'entity':settings.entity, | |
233 | 'action':settings.action, | |
234 | 'id':settings.id | |
235 | })+"' />"; | |
236 | $this.find('form').ajaxForm({ | |
237 | beforeSubmit :function () { | |
238 | $this.html("<div class='crm-editable-saving'>Saving...</div>"); | |
239 | return true; | |
240 | }, | |
e1f05567 | 241 | success:function(response) { |
6a488035 TO |
242 | if (response.indexOf('crm-error') >= 0) { // we got an error, re-display the page |
243 | $this.html(response); | |
244 | formLoaded(target); | |
245 | } else { | |
246 | if (response[0] == '{') | |
247 | settings.success($.parseJSON (response)); | |
248 | else | |
249 | settings.success(response); | |
250 | } | |
251 | } | |
e1f05567 | 252 | }).append('<input type="hidden" name="snippet" value="1"/>'+destination).trigger('load'); |
6a488035 TO |
253 | |
254 | settings.load(target); | |
255 | }; | |
256 | ||
257 | var $this = $(this); | |
258 | if (settings.source && settings.source.indexOf('snippet') == -1) { | |
259 | if (settings.source.indexOf('?') >= 0) | |
260 | settings.source = settings.source + "&snippet=1"; | |
261 | else | |
262 | settings.source = settings.source + "?snippet=1"; | |
263 | } | |
264 | ||
265 | ||
266 | $this.html ("Loading..."); | |
267 | if (settings.dialog) | |
268 | $this.dialog({width:'auto',minWidth:600}); | |
269 | $this.load (settings.source ,function (){formLoaded(this)}); | |
270 | ||
271 | }); | |
272 | }; | |
273 | ||
274 | })(jQuery); |