dolibarr  7.0.0-beta
ajax.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2007-2010 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2007-2015 Regis Houssin <regis.houssin@capnetworks.com>
4  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  * or see http://www.gnu.org/
19  */
20 
46 function ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array())
47 {
48  if (empty($minLength)) $minLength=1;
49 
50  $dataforrenderITem='ui-autocomplete';
51  $dataforitem='ui-autocomplete-item';
52  // Allow two constant to use other values for backward compatibility
53  if (defined('JS_QUERY_AUTOCOMPLETE_RENDERITEM')) $dataforrenderITem=constant('JS_QUERY_AUTOCOMPLETE_RENDERITEM');
54  if (defined('JS_QUERY_AUTOCOMPLETE_ITEM')) $dataforitem=constant('JS_QUERY_AUTOCOMPLETE_ITEM');
55 
56  // Input search_htmlname is original field
57  // Input htmlname is a second input field used when using ajax autocomplete.
58  $script = '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.$selected.'" />';
59 
60  $script.= '<!-- Javascript code for autocomplete of field '.$htmlname.' -->'."\n";
61  $script.= '<script type="text/javascript">'."\n";
62  $script.= '$(document).ready(function() {
63  var autoselect = '.$autoselect.';
64  var options = '.json_encode($ajaxoptions).';
65 
66  /* Remove selected id as soon as we type or delete a char (it means old selection is wrong). Use keyup/down instead of change to avoid loosing the product id. This is needed only for select of predefined product */
67  $("input#search_'.$htmlname.'").keydown(function(e) {
68  if (e.keyCode != 9) /* If not "Tab" key */
69  {
70  console.log("Clear id previously selected for field '.$htmlname.'");
71  $("#'.$htmlname.'").val("");
72  }
73  });
74 
75  // Check options for secondary actions when keyup
76  $("input#search_'.$htmlname.'").keyup(function() {
77  if ($(this).val().length == 0)
78  {
79  $("#search_'.$htmlname.'").val("");
80  $("#'.$htmlname.'").val("").trigger("change");
81  if (options.option_disabled) {
82  $("#" + options.option_disabled).removeAttr("disabled");
83  }
84  if (options.disabled) {
85  $.each(options.disabled, function(key, value) {
86  $("#" + value).removeAttr("disabled");
87  });
88  }
89  if (options.update) {
90  $.each(options.update, function(key, value) {
91  $("#" + key).val("").trigger("change");
92  });
93  }
94  if (options.show) {
95  $.each(options.show, function(key, value) {
96  $("#" + value).hide().trigger("hide");
97  });
98  }
99  if (options.update_textarea) {
100  $.each(options.update_textarea, function(key, value) {
101  if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances[key] != "undefined") {
102  CKEDITOR.instances[key].setData("");
103  } else {
104  $("#" + key).html("");
105  }
106  });
107  }
108  }
109  });
110  $("input#search_'.$htmlname.'").autocomplete({
111  source: function( request, response ) {
112  $.get("'.$url.($urloption?'?'.$urloption:'').'", { '.$htmlname.': request.term }, function(data){
113  if (data != null)
114  {
115  response($.map( data, function(item) {
116  if (autoselect == 1 && data.length == 1) {
117  $("#search_'.$htmlname.'").val(item.value);
118  $("#'.$htmlname.'").val(item.key).trigger("change");
119  }
120  var label = item.label.toString();
121  var update = {};
122  if (options.update) {
123  $.each(options.update, function(key, value) {
124  update[key] = item[value];
125  });
126  }
127  var textarea = {};
128  if (options.update_textarea) {
129  $.each(options.update_textarea, function(key, value) {
130  textarea[key] = item[value];
131  });
132  }
133  return { label: label, value: item.value, id: item.key, update: update, textarea: textarea, disabled: item.disabled }
134  }));
135  }
136  else console.error("Error: Ajax url '.$url.($urloption?'?'.$urloption:'').' has returned an empty page. Should be an empty json array.");
137  }, "json");
138  },
139  dataType: "json",
140  minLength: '.$minLength.',
141  select: function( event, ui ) { // Function ran once new value has been selected into javascript combo
142  console.log("Call change on input '.$htmlname.' because of select definition of autocomplete select call on input#search_'.$htmlname.'");
143  console.log("Selected id = "+ui.item.id+" - If this value is null, it means you select a record with key that is null so selection is not effective");
144  $("#'.$htmlname.'").val(ui.item.id).trigger("change"); // Select new value
145  // Disable an element
146  if (options.option_disabled) {
147  console.log("Make action option_disabled on #"+options.option_disabled+" with disabled="+ui.item.disabled)
148  if (ui.item.disabled) {
149  $("#" + options.option_disabled).prop("disabled", true);
150  if (options.error) {
151  $.jnotify(options.error, "error", true); // Output with jnotify the error message
152  }
153  if (options.warning) {
154  $.jnotify(options.warning, "warning", false); // Output with jnotify the warning message
155  }
156  } else {
157  $("#" + options.option_disabled).removeAttr("disabled");
158  }
159  }
160  if (options.disabled) {
161  console.log("Make action disabled on each "+options.option_disabled)
162  $.each(options.disabled, function(key, value) {
163  $("#" + value).prop("disabled", true);
164  });
165  }
166  if (options.show) {
167  console.log("Make action show on each "+options.show)
168  $.each(options.show, function(key, value) {
169  $("#" + value).show().trigger("show");
170  });
171  }
172  // Update an input
173  if (ui.item.update) {
174  console.log("Make action update on each ui.item.update")
175  // loop on each "update" fields
176  $.each(ui.item.update, function(key, value) {
177  $("#" + key).val(value).trigger("change");
178  });
179  }
180  if (ui.item.textarea) {
181  console.log("Make action textarea on each ui.item.textarea")
182  $.each(ui.item.textarea, function(key, value) {
183  if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances[key] != "undefined") {
184  CKEDITOR.instances[key].setData(value);
185  CKEDITOR.instances[key].focus();
186  } else {
187  $("#" + key).html(value);
188  $("#" + key).focus();
189  }
190  });
191  }
192  console.log("ajax_autocompleter new value selected, we trigger change on original component so field #search_'.$htmlname.'");
193 
194  $("#search_'.$htmlname.'").trigger("change"); // We have changed value of the combo select, we must be sure to trigger all js hook binded on this event. This is required to trigger other javascript change method binded on original field by other code.
195  }
196  ,delay: 500
197  }).data("'.$dataforrenderITem.'")._renderItem = function( ul, item ) {
198  return $("<li>")
199  .data( "'.$dataforitem.'", item ) // jQuery UI > 1.10.0
200  .append( \'<a><span class="tag">\' + item.label + "</span></a>" )
201  .appendTo(ul);
202  };
203 
204  });';
205  $script.= '</script>';
206 
207  return $script;
208 }
209 
224 function ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
225 {
226  $script = '<!-- Autocomplete -->'."\n";
227  $script.= '<script type="text/javascript">';
228  $script.= 'jQuery(document).ready(function() {
229  var fields = '.json_encode($fields).';
230  var nboffields = fields.length;
231  var autoselect = '.$autoselect.';
232  //alert(fields + " " + nboffields);
233 
234  jQuery("input#'.$htmlname.'").autocomplete({
235  dataType: "json",
236  minLength: '.$minLength.',
237  source: function( request, response ) {
238  jQuery.getJSON( "'.$url.($option?'?'.$option:'').'", { '.$htmlname.': request.term }, function(data){
239  response( jQuery.map( data, function( item ) {
240  if (autoselect == 1 && data.length == 1) {
241  jQuery("#'.$htmlname.'").val(item.value);
242  // TODO move this to specific request
243  if (item.states) {
244  jQuery("#state_id").html(item.states);
245  }
246  for (i=0;i<nboffields;i++) {
247  if (item[fields[i]]) { // If defined
248  //alert(item[fields[i]]);
249  jQuery("#" + fields[i]).val(item[fields[i]]);
250  }
251  }
252  }
253  return item
254  }));
255  });
256  },
257  select: function( event, ui ) {
258  needtotrigger = "";
259  for (i=0;i<nboffields;i++) {
260  //alert(fields[i] + " = " + ui.item[fields[i]]);
261  if (fields[i]=="selectcountry_id")
262  {
263  if (ui.item[fields[i]] > 0) // Do not erase country if unknown
264  {
265  oldvalue=jQuery("#" + fields[i]).val();
266  newvalue=ui.item[fields[i]];
267  //alert(oldvalue+" "+newvalue);
268  jQuery("#" + fields[i]).val(ui.item[fields[i]]);
269  if (oldvalue != newvalue) // To force select2 to refresh visible content
270  {
271  needtotrigger="#" + fields[i];
272  }
273 
274  // If we set new country and new state, we need to set a new list of state to allow change
275  if (ui.item.states && ui.item["state_id"] != jQuery("#state_id").value) {
276  jQuery("#state_id").html(ui.item.states);
277  }
278  }
279  }
280  else if (fields[i]=="state_id" || fields[i]=="state_id")
281  {
282  if (ui.item[fields[i]] > 0) // Do not erase state if unknown
283  {
284  oldvalue=jQuery("#" + fields[i]).val();
285  newvalue=ui.item[fields[i]];
286  //alert(oldvalue+" "+newvalue);
287  jQuery("#" + fields[i]).val(ui.item[fields[i]]); // This may fails if not correct country
288  if (oldvalue != newvalue) // To force select2 to refresh visible content
289  {
290  needtotrigger="#" + fields[i];
291  }
292  }
293  }
294  else if (ui.item[fields[i]]) { // If defined
295  oldvalue=jQuery("#" + fields[i]).val();
296  newvalue=ui.item[fields[i]];
297  //alert(oldvalue+" "+newvalue);
298  jQuery("#" + fields[i]).val(ui.item[fields[i]]);
299  if (oldvalue != newvalue) // To force select2 to refresh visible content
300  {
301  needtotrigger="#" + fields[i];
302  }
303  }
304 
305  if (needtotrigger != "") // To force select2 to refresh visible content
306  {
307  // We introduce a delay so hand is back to js and all other js change can be done before the trigger that may execute a submit is done
308  // This is required for example when changing zip with autocomplete that change the country
309  jQuery(needtotrigger).delay(500).queue(function() {
310  jQuery(this).trigger("change");
311  });
312  }
313  }
314  }
315  });
316  });';
317  $script.= '</script>';
318 
319  return $script;
320 }
321 
331 function ajax_dialog($title,$message,$w=350,$h=150)
332 {
333  global $langs;
334 
336  $msg= '<div id="dialog-info" title="'.dol_escape_htmltag($newtitle).'">';
337  $msg.= $message;
338  $msg.= '</div>'."\n";
339  $msg.= '<script type="text/javascript">
340  jQuery(function() {
341  jQuery("#dialog-info").dialog({
342  resizable: false,
343  height:'.$h.',
344  width:'.$w.',
345  modal: true,
346  buttons: {
347  Ok: function() {
348  jQuery(this).dialog(\'close\');
349  }
350  }
351  });
352  });
353  </script>';
354 
355  $msg.= "\n";
356 
357  return $msg;
358 }
359 
360 
367 function ajax_autoselect($htmlname, $addlink='')
368 {
369  global $langs;
370  $out = '<script type="text/javascript">
371  jQuery(document).ready(function () {
372  jQuery("#'.$htmlname.'").click(function() { jQuery(this).select(); } );
373  });
374  </script>';
375  if ($addlink) $out.=' <a href="'.$addlink.'" target="_blank">'.$langs->trans("Link").'</a>';
376  return $out;
377 }
378 
392 function ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve')
393 {
394  global $conf;
395 
396  // select2 disabled for smartphones with standard browser.
397  // TODO With select2 v4, it seems ok, except that responsive style on table become crazy when scrolling at end of array)
398  if (! empty($conf->browser->phone)) return '';
399 
400  if (! empty($conf->global->MAIN_DISABLE_AJAX_COMBOX)) return '';
401  if (empty($conf->use_javascript_ajax)) return '';
402  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && ! defined('REQUIRE_JQUERY_MULTISELECT')) return '';
403 
404  if (empty($minLengthToAutocomplete)) $minLengthToAutocomplete=0;
405 
406  $tmpplugin='select2';
407  $msg="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id = '.$htmlname.' -->
408  <script type="text/javascript">
409  $(document).ready(function () {
410  $(\''.(preg_match('/^\./',$htmlname)?$htmlname:'#'.$htmlname).'\').'.$tmpplugin.'({
411  dir: \'ltr\',
412  width: \''.$widthTypeOfAutocomplete.'\', /* off or resolve */
413  minimumInputLength: '.$minLengthToAutocomplete.',
414  language: select2arrayoflanguage,
415  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
416  templateResult: function (data, container) { /* Format visible output into combo list */
417  /* Code to add class of origin OPTION propagated to the new select2 <li> tag */
418  if (data.element) { $(container).addClass($(data.element).attr("class")); }
419  //console.log(data.html);
420  if ($(data.element).attr("data-html") != undefined) return htmlEntityDecodeJs($(data.element).attr("data-html")); // If property html set, we decode html entities and use this
421  return data.text;
422  },
423  templateSelection: function (selection) { /* Format visible output of selected value */
424  return selection.text;
425  },
426  escapeMarkup: function(markup) {
427  return markup;
428  }
429  })';
430  if ($forcefocus) $msg.= '.select2(\'focus\')';
431  $msg.= ';'."\n";
432 
433  if (is_array($events) && count($events)) // If an array of js events to do were provided.
434  {
435  $msg.= '
436  jQuery("#'.$htmlname.'").change(function () {
437  var obj = '.json_encode($events).';
438  $.each(obj, function(key,values) {
439  if (values.method.length) {
440  runJsCodeForEvent'.$htmlname.'(values);
441  }
442  });
443  });
444 
445  function runJsCodeForEvent'.$htmlname.'(obj) {
446  var id = $("#'.$htmlname.'").val();
447  var method = obj.method;
448  var url = obj.url;
449  var htmlname = obj.htmlname;
450  var showempty = obj.showempty;
451  console.log("Run runJsCodeForEvent-'.$htmlname.' from ajax_combobox id="+id+" method="+method+" showempty="+showempty+" url="+url+" htmlname="+htmlname);
452  $.getJSON(url,
453  {
454  action: method,
455  id: id,
456  htmlname: htmlname,
457  showempty: showempty
458  },
459  function(response) {
460  $.each(obj.params, function(key,action) {
461  if (key.length) {
462  var num = response.num;
463  if (num > 0) {
464  $("#" + key).removeAttr(action);
465  } else {
466  $("#" + key).attr(action, action);
467  }
468  }
469  });
470  $("select#" + htmlname).html(response.value);
471  if (response.num) {
472  var selecthtml_str = response.value;
473  var selecthtml_dom=$.parseHTML(selecthtml_str);
474  $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
475  } else {
476  $("#inputautocomplete"+htmlname).val("");
477  }
478  $("select#" + htmlname).change(); /* Trigger event change */
479  }
480  );
481  }';
482  }
483 
484  $msg.= '});'."\n";
485  $msg.= "</script>\n";
486 
487  return $msg;
488 }
489 
500 function ajax_constantonoff($code, $input=array(), $entity=null, $revertonoff=0, $strict=0)
501 {
502  global $conf, $langs;
503 
504  $entity = ((isset($entity) && is_numeric($entity) && $entity >= 0) ? $entity : $conf->entity);
505 
506  if (empty($conf->use_javascript_ajax))
507  {
508  if (empty($conf->global->$code)) print '<a href="'.$_SERVER['PHP_SELF'].'?action=set_'.$code.'&entity='.$entity.'">'.img_picto($langs->trans("Disabled"),'off').'</a>';
509  else print '<a href="'.$_SERVER['PHP_SELF'].'?action=del_'.$code.'&entity='.$entity.'">'.img_picto($langs->trans("Enabled"),'on').'</a>';
510  }
511  else
512  {
513  $out= "\n<!-- Ajax code to switch constant ".$code." -->".'
514  <script type="text/javascript">
515  $(document).ready(function() {
516  var input = '.json_encode($input).';
517  var url = \''.DOL_URL_ROOT.'/core/ajax/constantonoff.php\';
518  var code = \''.$code.'\';
519  var entity = \''.$entity.'\';
520  var strict = \''.$strict.'\';
521  var yesButton = "'.dol_escape_js($langs->transnoentities("Yes")).'";
522  var noButton = "'.dol_escape_js($langs->transnoentities("No")).'";
523 
524  // Set constant
525  $("#set_" + code).click(function() {
526  if (input.alert && input.alert.set) {
527  if (input.alert.set.yesButton) yesButton = input.alert.set.yesButton;
528  if (input.alert.set.noButton) noButton = input.alert.set.noButton;
529  confirmConstantAction("set", url, code, input, input.alert.set, entity, yesButton, noButton, strict);
530  } else {
531  setConstant(url, code, input, entity);
532  }
533  });
534 
535  // Del constant
536  $("#del_" + code).click(function() {
537  if (input.alert && input.alert.del) {
538  if (input.alert.del.yesButton) yesButton = input.alert.del.yesButton;
539  if (input.alert.del.noButton) noButton = input.alert.del.noButton;
540  confirmConstantAction("del", url, code, input, input.alert.del, entity, yesButton, noButton, strict);
541  } else {
542  delConstant(url, code, input, entity);
543  }
544  });
545  });
546  </script>'."\n";
547 
548  $out.= '<div id="confirm_'.$code.'" title="" style="display: none;"></div>';
549  $out.= '<span id="set_'.$code.'" class="linkobject '.(! empty($conf->global->$code)?'hideobject':'').'">'.($revertonoff?img_picto($langs->trans("Enabled"),'switch_on'):img_picto($langs->trans("Disabled"),'switch_off')).'</span>';
550  $out.= '<span id="del_'.$code.'" class="linkobject '.(! empty($conf->global->$code)?'':'hideobject').'">'.($revertonoff?img_picto($langs->trans("Disabled"),'switch_off'):img_picto($langs->trans("Enabled"),'switch_on')).'</span>';
551  $out.="\n";
552  }
553 
554  return $out;
555 }
556 
568 function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array())
569 {
570  global $langs;
571 
572  $out= '<script type="text/javascript">
573  $(function() {
574  var input = '.json_encode($input).';
575 
576  // Set constant
577  $("#set_'.$code.'_'.$object->id.'").click(function() {
578  $.get( "'.DOL_URL_ROOT.'/core/ajax/objectonoff.php", {
579  action: \'set\',
580  field: \''.$field.'\',
581  value: \'1\',
582  element: \''.$object->element.'\',
583  id: \''.$object->id.'\'
584  },
585  function() {
586  $("#set_'.$code.'_'.$object->id.'").hide();
587  $("#del_'.$code.'_'.$object->id.'").show();
588  // Enable another element
589  if (input.disabled && input.disabled.length > 0) {
590  $.each(input.disabled, function(key,value) {
591  $("#" + value).removeAttr("disabled");
592  if ($("#" + value).hasClass("butActionRefused") == true) {
593  $("#" + value).removeClass("butActionRefused");
594  $("#" + value).addClass("butAction");
595  }
596  });
597  // Show another element
598  } else if (input.showhide && input.showhide.length > 0) {
599  $.each(input.showhide, function(key,value) {
600  $("#" + value).show();
601  });
602  }
603  });
604  });
605 
606  // Del constant
607  $("#del_'.$code.'_'.$object->id.'").click(function() {
608  $.get( "'.DOL_URL_ROOT.'/core/ajax/objectonoff.php", {
609  action: \'set\',
610  field: \''.$field.'\',
611  value: \'0\',
612  element: \''.$object->element.'\',
613  id: \''.$object->id.'\'
614  },
615  function() {
616  $("#del_'.$code.'_'.$object->id.'").hide();
617  $("#set_'.$code.'_'.$object->id.'").show();
618  // Disable another element
619  if (input.disabled && input.disabled.length > 0) {
620  $.each(input.disabled, function(key,value) {
621  $("#" + value).prop("disabled", true);
622  if ($("#" + value).hasClass("butAction") == true) {
623  $("#" + value).removeClass("butAction");
624  $("#" + value).addClass("butActionRefused");
625  }
626  });
627  // Hide another element
628  } else if (input.showhide && input.showhide.length > 0) {
629  $.each(input.showhide, function(key,value) {
630  $("#" + value).hide();
631  });
632  }
633  });
634  });
635  });
636  </script>';
637  $out.= '<span id="set_'.$code.'_'.$object->id.'" class="linkobject '.($object->$code==1?'hideobject':'').'">'.img_picto($langs->trans($text_off),'switch_off').'</span>';
638  $out.= '<span id="del_'.$code.'_'.$object->id.'" class="linkobject '.($object->$code==1?'':'hideobject').'">'.img_picto($langs->trans($text_on),'switch_on').'</span>';
639 
640  return $out;
641 }
642 
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:392
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it's its name (generic function)
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition: ajax.lib.php:224
ajax_autoselect($htmlname, $addlink='')
Make content of an input box selected when we click into input field.
Definition: ajax.lib.php:367
select2arrayoflanguage
Set array used for select2 translations.
if($_POST["cancel"]==$langs->trans("Cancel")&&!$id) if($action== 'setdatev'&&$user->rights->tax->charges->creer) if($action== 'add'&&$_POST["cancel"]<> $langs->trans("Cancel")) if($action== 'delete') $title
Actions.
Definition: card.php:183
ajax_dialog($title, $message, $w=350, $h=150)
Show an ajax dialog.
Definition: ajax.lib.php:331
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8')
Clean a string from all HTML tags and entities.
print
Draft customers invoices.
Definition: index.php:91
ajax_constantonoff($code, $input=array(), $entity=null, $revertonoff=0, $strict=0)
On/off button for constant.
Definition: ajax.lib.php:500
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array())
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition: ajax.lib.php:46
type
Definition: viewcat.php:283
dol_textishtml($msg, $option=0)
Return if a text is a html content.