fixing librejs on defectivebydesign.org
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules / civicrm / js / jquery / jquery.crmeditable.js
1 /*
2 +--------------------------------------------------------------------+
3 | CiviCRM version 4.3 |
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 // 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');
50 if (!domid) {
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");
52 return false;
53 }
54 // trying to extract using the html5 data
55 if (domid.data('entity')) {
56 result (domid.data('entity'),domid.data('id'));
57 return true;
58 }
59 domid=domid.attr('id');
60 if (!domid) {
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}'");
62 return false;
63 }
64 var e=domid.match(/(\S*)-(\S*)/);
65 if (!e) {
66 console && console.log && console.log("Couldn't get the entity id. You need to set class='crm-entity' id='{entityName}-{id}'");
67 return false;
68 }
69 result(e[1],e[2]);
70 return true;
71 }
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');
76 }
77 var fieldName=field.className.match(/crmf-(\S*)/)[1];
78 if (!fieldName) {
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}");
80 return false;
81 }
82 return fieldName;
83 }
84
85 var checkable = function () {
86 $(this).change (function() {
87 var params={sequential:1};
88 var entity = null;
89 var checked = $(this).is(':checked');
90 if (!getEntityID (this,function (e,id) {
91 entity=e;
92 params.id = id;
93
94 })) { return };
95
96 params['field']=getFieldName(this);
97 if (!params['field'])
98 return false;
99 params['value']=checked?'1':'0';//seems that the ajax backend gets lost with boolean
100
101 CRM.api(entity,'setvalue',params,{
102 context: this,
103 error: function (data) {
104 editableSettings.error.call(this,entity,params.field,checked,data);
105 },
106 success: function (data) {
107 editableSettings.success.call(this,entity,params.field,checked,data);
108 }
109 });
110 });
111 };
112
113 var defaults = {
114 form:{},
115 callBack:function(data){
116 if (data.is_error) {
117 editableSettings.error.call (this,data);
118 } else {
119 return editableSettings.success.call (this,data);
120 }
121 },
122 error: function(entity,field,value,data) {
123 $(this).crmError(data.error_message, ts('Error'));
124 $(this).removeClass('crm-editable-saving');
125 },
126 success: function(entity,field,value,data) {
127 var $i = $(this);
128 CRM.alert('', ts('Saved'), 'success');
129 $i.removeClass ('crm-editable-saving crm-error');
130 $i.html(value);
131 }
132 }
133
134 var editableSettings = $.extend({}, defaults, options);
135 return this.each(function() {
136 var $i = $(this);
137 var fieldName = "";
138
139 if (this.nodeName == "INPUT" && this.type=="checkbox") {
140 checkable.call(this,this);
141 return;
142 }
143
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();
151 } else
152 $i.next().slideUp().remove();
153 $i.trigger('success',result);
154 }
155 });
156 var id= $i.closest('.crm-entity').attr('id');
157 if (id) {
158 var e=id.match(/(\S*)-(\S*)/);
159 if (!e)
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];
163 }
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);
169 return false;
170 });
171 } else {
172 $i.click (function () {
173 var $n=$i.next();
174 if (!$n.hasClass('crm-target')) {
175 $n=$i.after('<div class="crm-target"></div>').next();
176 } else {
177 $n.slideToggle();
178 return false;
179 };
180 $n.crmForm (formSettings);
181 return false;
182 });
183 }
184 return;
185 }
186 }
187
188
189 var settings = {
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, '');
194 }
195 };
196 if ($i.data('placeholder')) {
197 settings.placeholder = $i.data('placeholder');
198 } else {
199 settings.placeholder = '<span class="crm-editable-placeholder">Click to edit</span>';
200 }
201 if ($i.data('tooltip')) {
202 settings.placeholder = $i.data('tooltip')
203 } else {
204 settings.tooltip = 'Click to edit...';
205 }
206 if ($i.data('type')) {
207 settings.type = $i.data('type');
208 settings.onblur = 'submit';
209 }
210 if ($i.data('options')){
211 settings.data = $i.data('options');
212 }
213 if(settings.type == 'textarea'){
214 $i.addClass ('crm-editable-textarea-enabled');
215 }
216 else{
217 $i.addClass ('crm-editable-enabled');
218 }
219
220 $i.editable(function(value,settings) {
221 //$i.editable(function(value,editableSettings) {
222 parent=$i.closest('.crm-entity');
223 if (!parent) {
224 console && console.log && console.log("crm-editable: you need to define one parent element that has a class .crm-entity");
225 return;
226 }
227
228 $i.addClass ('crm-editable-saving');
229 var params = {};
230 var entity = null;
231 params['field']=getFieldName(this);
232 if (!params['field'])
233 return false;
234 params['value']=value;
235 if (!getEntityID (this,function (e,id) {
236 entity=e;
237 params.id = id;
238 })) {return;}
239
240 if (params.id == "new") {
241 params.id = '';
242 }
243
244 if ($i.data('action')) {
245 var fieldName = params['field'];
246 delete params['field'];
247 delete params['value'];
248
249 params[fieldName]=value;//format for create at least
250 action=$i.data('action');
251 } else {
252 action="setvalue";
253 }
254 CRM.api(entity, action, params, {
255 context: this,
256 error: function (data) {
257 editableSettings.error.call(this,entity,fieldName,value,data);
258 },
259 success: function (data) {
260 if ($i.data('options')){
261 value = $i.data('options')[value];
262 }
263 editableSettings.success.call(this,entity,fieldName,value,data);
264 }
265 });
266 },settings);
267 });
268 }
269
270 $.fn.crmForm = function (options ) {
271 var settings = $.extend( {
272 'title':'',
273 'entity':'',
274 'action':'get',
275 'id':0,
276 'sequential':1,
277 'dialog': false,
278 'load' : function (target){},
279 'success' : function (result) {
280 $(this).html(ts('Saved'));
281 }
282 }, options);
283
284
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,
290 'json':'html',
291 'entity':settings.entity,
292 'action':settings.action,
293 'id':settings.id
294 })+"' />";
295 $this.find('form').ajaxForm({
296 beforeSubmit :function () {
297 $this.html("<div class='crm-editable-saving'>Saving...</div>");
298 return true;
299 },
300 success:function(response) {
301 if (response.indexOf('crm-error') >= 0) { // we got an error, re-display the page
302 $this.html(response);
303 formLoaded(target);
304 } else {
305 if (response[0] == '{')
306 settings.success($.parseJSON (response));
307 else
308 settings.success(response);
309 }
310 }
311 }).append('<input type="hidden" name="snippet" value="1"/>'+destination).trigger('load');
312
313 settings.load(target);
314 };
315
316 var $this = $(this);
317 if (settings.source && settings.source.indexOf('snippet') == -1) {
318 if (settings.source.indexOf('?') >= 0)
319 settings.source = settings.source + "&snippet=1";
320 else
321 settings.source = settings.source + "?snippet=1";
322 }
323
324
325 $this.html ("Loading...");
326 if (settings.dialog)
327 $this.dialog({width:'auto',minWidth:600});
328 $this.load (settings.source ,function (){formLoaded(this)});
329
330 });
331 };
332
333 })(jQuery);