dolibarr 23.0.3
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@inodbox.com>
4 * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
5 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * or see https://www.gnu.org/
21 */
22
49function ajax_autocompleter($selected, $htmlname, $url, $urloption = '', $minLength = 2, $autoselect = 0, $ajaxoptions = array(), $moreparams = '')
50{
51 if (empty($minLength)) {
52 $minLength = 1;
53 }
54
55 $dataforrenderITem = 'ui-autocomplete';
56 $dataforitem = 'ui-autocomplete-item';
57 // Allow two constant to use other values for backward compatibility
58 if (defined('JS_QUERY_AUTOCOMPLETE_RENDERITEM')) {
59 $dataforrenderITem = constant('JS_QUERY_AUTOCOMPLETE_RENDERITEM');
60 }
61 if (defined('JS_QUERY_AUTOCOMPLETE_ITEM')) {
62 $dataforitem = constant('JS_QUERY_AUTOCOMPLETE_ITEM');
63 }
64
65 $htmlnamejquery = str_replace('.', '\\\\.', $htmlname);
66
67 // Input search_htmlname is original field
68 // Input htmlname is a second input field used when using ajax autocomplete.
69 $script = '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.$selected.'" '.($moreparams ? $moreparams : '').' />';
70
71 $script .= '<!-- Javascript code for autocomplete of field '.$htmlname.' -->'."\n";
72 $script .= '<script>'."\n";
73 $script .= '$(document).ready(function() {
74 var autoselect = '.((int) $autoselect).';
75 var options = '.json_encode($ajaxoptions).'; /* Option of actions to do after keyup, or after select */
76
77 /* 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 losing the product id. This is needed only for select of predefined product */
78 $("input#search_'.$htmlnamejquery.'").keydown(function(e) {
79 if (e.keyCode != 9) /* If not "Tab" key */
80 {
81 if (e.keyCode == 13) { return false; } /* disable "ENTER" key useful for barcode readers */
82 console.log("Clear id previously selected for field '.$htmlname.'");
83 $("#'.$htmlnamejquery.'").val("");
84 }
85 });
86
87 // Check options for secondary actions when keyup
88 $("input#search_'.$htmlnamejquery.'").keyup(function() {
89 if ($(this).val().length == 0)
90 {
91 $("#search_'.$htmlnamejquery.'").val("");
92 $("#'.$htmlnamejquery.'").val("").trigger("change");
93 if (options.option_disabled) {
94 $("#" + options.option_disabled).removeAttr("disabled");
95 }
96 if (options.disabled) {
97 $.each(options.disabled, function(key, value) {
98 $("#" + value).removeAttr("disabled");
99 });
100 }
101 if (options.update) {
102 $.each(options.update, function(key, value) {
103 $("#" + key).val("").trigger("change");
104 });
105 }
106 if (options.show) {
107 $.each(options.show, function(key, value) {
108 $("#" + value).hide().trigger("hide");
109 });
110 }
111 if (options.update_textarea) {
112 $.each(options.update_textarea, function(key, value) {
113 if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances[key] != "undefined") {
114 CKEDITOR.instances[key].setData("");
115 } else {
116 $("#" + key).html("");
117 }
118 });
119 }
120 }
121 });
122
123 // Activate the autocomplete to execute the GET
124 $("input#search_'.$htmlnamejquery.'").autocomplete({
125 source: function( request, response ) {
126 $.get("'.$url.($urloption ? '?'.$urloption : '').'", { "'.str_replace('.', '_', $htmlname).'": request.term }, function(data){
127 if (data != null)
128 {
129 response($.map( data, function(item) {
130 console.log("Received answer from ajax GET, we populate array to return to the jquery autocomplete");
131 if (autoselect == 1 && data.length == 1) {
132 $("#search_'.$htmlnamejquery.'").val(item.value);
133 ';
134 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
135 $script .= '
136 // When product has only one price by qty and 1 result, must set data attributes before triggering change
137 $("#'.$htmlname.'").attr("data-pbq", item.pbq);
138 $("#'.$htmlname.'").attr("data-pbqup", item.price_ht);
139 $("#'.$htmlname.'").attr("data-pbqbase", item.pricebasetype);
140 $("#'.$htmlname.'").attr("data-pbqqty", item.qty);
141 $("#'.$htmlname.'").attr("data-pbqpercent", item.discount);
142 ';
143 }
144 $script .= '
145 $("#'.$htmlnamejquery.'").val(item.key).trigger("change");
146 }
147 var label = "";
148 if (item.labelhtml != null) {
149 label = item.labelhtml.toString();
150 } else if (item.label != null) {
151 label = item.label.toString();
152 }
153 var update = {};
154 if (options.update) {
155 $.each(options.update, function(key, value) {
156 update[key] = item[value];
157 });
158 }
159 var textarea = {};
160 if (options.update_textarea) {
161 $.each(options.update_textarea, function(key, value) {
162 textarea[key] = item[value];
163 });
164 }
165
166 return { label: label,
167 value: item.value,
168 id: item.key,
169 disabled: item.disabled,
170 update: update,
171 textarea: textarea,
172 pbq: item.pbq,
173 type: item.type,
174 qty: item.qty,
175 discount: item.discount,
176 pricebasetype: item.pricebasetype,
177 price_ht: item.price_ht,
178 price_ttc: item.price_ttc,
179 price_unit_ht: item.price_unit_ht,
180 price_unit_ht_locale: item.price_unit_ht_locale,
181 multicurrency_code: item.multicurrency_code,
182 multicurrency_unitprice: item.multicurrency_unitprice,
183 description : item.description,
184 ref_customer: item.ref_customer,
185 tva_tx: item.tva_tx,
186 default_vat_code: item.default_vat_code,
187 supplier_ref: item.supplier_ref
188 }
189 }));
190 } else {
191 console.error("Error: Ajax url '.$url.($urloption ? '?'.$urloption : '').' has returned an empty page. Should be an empty json array.");
192 }
193 }, "json");
194 },
195 dataType: "json",
196 minLength: '.((int) $minLength).',
197 select: function( event, ui ) { // Function ran once a new value has been selected into the javascript combo
198 console.log("We will trigger change on input '.$htmlname.' because of the select definition of autocomplete code for input#search_'.$htmlname.'");
199 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");
200
201 console.log("Before, we propagate some properties, retrieved by the ajax of the get, into the data-xxx properties of the component #'.$htmlnamejquery.'");
202 //console.log(ui.item);
203
204 // For supplier price and customer when price by quantity is off
205 $("#'.$htmlnamejquery.'").attr("data-up", ui.item.price_ht);
206 $("#'.$htmlnamejquery.'").attr("data-up-locale", ui.item.price_unit_ht_locale);
207 $("#'.$htmlnamejquery.'").attr("data-base", ui.item.pricebasetype);
208 $("#'.$htmlnamejquery.'").attr("data-qty", ui.item.qty);
209 $("#'.$htmlnamejquery.'").attr("data-discount", ui.item.discount);
210 $("#'.$htmlnamejquery.'").attr("data-description", ui.item.description);
211 $("#'.$htmlnamejquery.'").attr("data-ref-customer", ui.item.ref_customer);
212 $("#'.$htmlnamejquery.'").attr("data-tvatx", ui.item.tva_tx);
213 $("#'.$htmlnamejquery.'").attr("data-default-vat-code", ui.item.default_vat_code);
214 $("#'.$htmlnamejquery.'").attr("data-supplier-ref", ui.item.supplier_ref); // supplier_ref of price
215
216 // For multi-currency values
217 $("#'.$htmlnamejquery.'").attr("data-multicurrency-code", ui.item.multicurrency_code);
218 $("#'.$htmlnamejquery.'").attr("data-multicurrency-unitprice", ui.item.multicurrency_unitprice);
219 ';
220 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
221 $script .= '
222 // For customer price when PRODUIT_CUSTOMER_PRICES_BY_QTY is on
223 console.log("PRODUIT_CUSTOMER_PRICES_BY_QTY is on, so we propagate also prices by quantity into data-pbqxxx properties");
224 $("#'.$htmlnamejquery.'").attr("data-pbq", ui.item.pbq);
225 $("#'.$htmlnamejquery.'").attr("data-pbqup", ui.item.price_ht);
226 $("#'.$htmlnamejquery.'").attr("data-pbqbase", ui.item.pricebasetype);
227 $("#'.$htmlnamejquery.'").attr("data-pbqqty", ui.item.qty);
228 $("#'.$htmlnamejquery.'").attr("data-pbqpercent", ui.item.discount);
229 ';
230 }
231 $script .= '
232 // A new value has been selected, we trigger the handlers on #htmlnamejquery
233 console.log("Now, we trigger changes on #'.$htmlnamejquery.'");
234 $("#'.$htmlnamejquery.'").val(ui.item.id).trigger("change"); // Select new value
235
236 // Complementary actions
237
238 // Disable an element
239 if (options.option_disabled) {
240 console.log("Make action option_disabled on #"+options.option_disabled+" with disabled="+ui.item.disabled)
241 if (ui.item.disabled) {
242 $("#" + options.option_disabled).prop("disabled", true);
243 if (options.error) {
244 $.jnotify(options.error, "error", true); // Output with jnotify the error message
245 }
246 if (options.warning) {
247 $.jnotify(options.warning, "warning", false); // Output with jnotify the warning message
248 }
249 } else {
250 $("#" + options.option_disabled).removeAttr("disabled");
251 }
252 }
253
254 if (options.disabled) {
255 console.log("Make action \'disabled\' on each "+options.option_disabled)
256 $.each(options.disabled, function(key, value) {
257 $("#" + value).prop("disabled", true);
258 });
259 }
260 if (options.show) {
261 console.log("Make action \'show\' on each "+options.show)
262 $.each(options.show, function(key, value) {
263 $("#" + value).show().trigger("show");
264 });
265 }
266
267 // Update an input
268 if (ui.item.update) {
269 console.log("Make action \'update\' on each ui.item.update (if there is)")
270 // loop on each "update" fields
271 $.each(ui.item.update, function(key, value) {
272 console.log("Set value "+value+" into #"+key);
273 $("#" + key).val(value).trigger("change");
274 });
275 }
276 if (ui.item.textarea) {
277 console.log("Make action \'textarea\' on each ui.item.textarea (if there is)")
278 $.each(ui.item.textarea, function(key, value) {
279 if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances[key] != "undefined") {
280 CKEDITOR.instances[key].setData(value);
281 CKEDITOR.instances[key].focus();
282 } else {
283 $("#" + key).html(value);
284 $("#" + key).focus();
285 }
286 });
287 }
288 console.log("ajax_autocompleter new value selected, we trigger change also on original component so on field #search_'.$htmlname.'");
289
290 $("#search_'.$htmlnamejquery.'").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.
291 }
292 ,delay: 500
293 });
294 const widgetData = $("input#search_'.$htmlnamejquery.'").data("'.$dataforrenderITem.'");
295 if (widgetData) {
296 widgetData._renderItem = function( ul, item ) {
297 return $("<li>")
298 .data( "'.$dataforitem.'", item ) // jQuery UI > 1.10.0
299 .append( \'<a><span class="tag">\' + item.label + "</span></a>" )
300 .appendTo(ul);
301 };
302 }
303
304 });';
305 $script .= '</script>';
306
307 return $script;
308}
309
324function ajax_multiautocompleter($htmlname, $fields, $url, $option = '', $minLength = 2, $autoselect = 0)
325{
326 $script = '<!-- Autocomplete -->'."\n";
327 $script .= '<script>';
328 $script .= 'jQuery(document).ready(function() {
329 var fields = '.json_encode($fields).';
330 var nboffields = fields.length;
331 var autoselect = '.$autoselect.';
332 //alert(fields + " " + nboffields);
333
334 // Activate the autocomplete to execute the GET
335 jQuery("input#'.$htmlname.'").autocomplete({
336 dataType: "json",
337 minLength: '.$minLength.',
338 source: function( request, response ) {
339 jQuery.getJSON( "'.$url.($option ? '?'.$option : '').'", { '.$htmlname.': request.term }, function(data){
340 response( jQuery.map( data, function( item ) {
341 if (autoselect == 1 && data.length == 1) {
342 jQuery("#'.$htmlname.'").val(item.value);
343 // TODO move this to specific request
344 if (item.states) {
345 jQuery("#state_id").html(item.states);
346 }
347 for (i=0;i<nboffields;i++) {
348 if (item[fields[i]]) { // If defined
349 //alert(item[fields[i]]);
350 jQuery("#" + fields[i]).val(item[fields[i]]);
351 }
352 }
353 }
354 return item
355 }));
356 });
357 },
358 select: function( event, ui ) {
359 needtotrigger = "";
360 for (i=0;i<nboffields;i++) {
361 //alert(fields[i] + " = " + ui.item[fields[i]]);
362 if (fields[i]=="selectcountry_id")
363 {
364 if (ui.item[fields[i]] > 0) // Do not erase country if unknown
365 {
366 oldvalue=jQuery("#" + fields[i]).val();
367 newvalue=ui.item[fields[i]];
368 //alert(oldvalue+" "+newvalue);
369 jQuery("#" + fields[i]).val(ui.item[fields[i]]);
370 if (oldvalue != newvalue) // To force select2 to refresh visible content
371 {
372 needtotrigger="#" + fields[i];
373 }
374
375 // If we set new country and new state, we need to set a new list of state to allow change
376 if (ui.item.states && ui.item["state_id"] != jQuery("#state_id").value) {
377 jQuery("#state_id").html(ui.item.states);
378 }
379 }
380 }
381 else if (fields[i]=="state_id" || fields[i]=="state_id")
382 {
383 if (ui.item[fields[i]] > 0) // Do not erase state if unknown
384 {
385 oldvalue=jQuery("#" + fields[i]).val();
386 newvalue=ui.item[fields[i]];
387 //alert(oldvalue+" "+newvalue);
388 jQuery("#" + fields[i]).val(ui.item[fields[i]]); // This may fails if not correct country
389 if (oldvalue != newvalue) // To force select2 to refresh visible content
390 {
391 needtotrigger="#" + fields[i];
392 }
393 }
394 }
395 else if (ui.item[fields[i]]) { // If defined
396 oldvalue=jQuery("#" + fields[i]).val();
397 newvalue=ui.item[fields[i]];
398 //alert(oldvalue+" "+newvalue);
399 jQuery("#" + fields[i]).val(ui.item[fields[i]]);
400 if (oldvalue != newvalue) // To force select2 to refresh visible content
401 {
402 needtotrigger="#" + fields[i];
403 }
404 }
405
406 if (needtotrigger != "") // To force select2 to refresh visible content
407 {
408 // 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
409 // This is required for example when changing zip with autocomplete that change the country
410 jQuery(needtotrigger).delay(500).queue(function() {
411 jQuery(this).trigger("change");
412 });
413 }
414 }
415 }
416 });
417 });';
418 $script .= '</script>';
419
420 return $script;
421}
422
432function ajax_dialog($title, $message, $w = 350, $h = 150)
433{
434 $newtitle = dol_textishtml($title) ? dol_string_nohtmltag($title, 1) : $title;
435 $msg = '<div id="dialog-info" title="'.dol_escape_htmltag($newtitle).'">';
436 $msg .= $message;
437 $msg .= '</div>'."\n";
438 $msg .= '<script>
439 jQuery(function() {
440 jQuery("#dialog-info").dialog({
441 resizable: false,
442 height:'.$h.',
443 width:'.$w.',
444 modal: true,
445 buttons: {
446 Ok: function() {
447 jQuery(this).dialog(\'close\');
448 }
449 }
450 });
451 });
452 </script>';
453
454 $msg .= "\n";
455
456 return $msg;
457}
458
459
475function ajax_combobox($htmlname, $events = array(), $minLengthToAutocomplete = 0, $forcefocus = 0, $widthTypeOfAutocomplete = 'resolve', $idforemptyvalue = '-1', $morecss = '')
476{
477 global $conf;
478
479 // select2 can be disabled for smartphones
480 if (!empty($conf->browser->layout) && $conf->browser->layout == 'phone' && getDolGlobalString('MAIN_DISALLOW_SELECT2_WITH_SMARTPHONE')) {
481 return '';
482 }
483
484 if (getDolGlobalString('MAIN_DISABLE_AJAX_COMBOX')) {
485 return '';
486 }
487 if (empty($conf->use_javascript_ajax)) {
488 return '';
489 }
490 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
491 return '';
492 }
493 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
494 return '';
495 }
496
497 if (empty($minLengthToAutocomplete)) {
498 $minLengthToAutocomplete = 0;
499 }
500
501 $moreselect2theme = ($morecss ? dol_escape_js(' '.$morecss) : '');
502 $moreselect2theme = preg_replace('/widthcentpercentminus[^\s]*/', '', $moreselect2theme);
503
504 $tmpplugin = 'select2';
505 $msg = "\n";
506 $msg .= '<!-- JS CODE TO ENABLE '.$tmpplugin.' for id = '.$htmlname.' -->'."\n";
507 $msg .= "<script>\n";
508 $msg .= '$(document).ready(function () {
509 $(\''.(dol_escape_js(preg_match('/^\./', $htmlname) ? $htmlname : '#'.$htmlname)).'\').'.$tmpplugin.'({';
510 if (preg_match('/onrightofpage/', $morecss)) { // when $morecss contains 'onrightofpage', the select2 component must also be inside a parent with class="parentonrightofpage"
511 $msg .= ' dropdownAutoWidth: true, dropdownParent: $(\'#'.$htmlname.'\').parent(), '."\n";
512 }
513 $msg .= '
514 dir: \'ltr\',
515 width: \''.dol_escape_js($widthTypeOfAutocomplete).'\', /* off or resolve */
516 minimumInputLength: '.((int) $minLengthToAutocomplete).',
517 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
518 matcher: function (params, data) {
519 if ($.trim(params.term) === "") { return data; }';
520 if (getDolGlobalString('MAIN_ENABLE_ACCENT_INSENSITIVE_SEARCH')) { // lowercase + remove accents
521 $msg .= '
522 var term = params.term.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase()
523 var text = (data.text || "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase() || "";';
524 } else { // lowercase only (accent kept)
525 $msg .= '
526 var term = params.term.toLowerCase();
527 var text = (data.text || "").toLowerCase();';
528 }
529 $msg .= '
530 var keywords = term.split(" ");
531 for (var i = 0; i < keywords.length; i++) {
532 if (text.indexOf(keywords[i]) === -1) {
533 return null;
534 }
535 }
536 return data;
537 },
538 theme: \'default'.dol_escape_js($moreselect2theme).'\', /* to add css on generated html components */
539 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
540 selectionCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
541 dropdownCssClass: \'ui-dialog\',
542 templateResult: function (data, container) { /* Format visible output into combo list */
543 /* Code to add class of origin OPTION propagated to the new select2 <li> tag */
544 if (data.element) { $(container).addClass($(data.element).attr("class")); }
545 /* console.log("data html is "+$(data.element).attr("data-html")); */
546 if (data.id == \''.(dol_escape_js($idforemptyvalue)).'\' && $(data.element).attr("data-html") == undefined) {
547 return \'&nbsp;\';
548 }
549 if ($(data.element).attr("data-html") != undefined) {
550 /* If property html set, we decode html entities and use this. */
551 /* Note that HTML content must have been sanitized against js injection with dol_escape_htmltag(xxx, 0, 0, \'\', 0, 1) when building the select option. */
552 if (typeof htmlEntityDecodeJs === "function") {
553 return htmlEntityDecodeJs($(data.element).attr("data-html"));
554 }
555 }
556 return data.text;
557 },
558 templateSelection: function (selection) { /* Format visible output of selected value */
559 if (selection.id == \''.(dol_escape_js($idforemptyvalue)).'\') return \'<span class="placeholder">\'+selection.text+\'</span>\';
560 return selection.text;
561 },
562 escapeMarkup: function(markup) {
563 return markup;
564 }
565 })';
566 if ($forcefocus) {
567 $msg .= '.select2(\'focus\')';
568 }
569 $msg .= ';'."\n";
570
571 $msg .= '});'."\n";
572 $msg .= "</script>\n";
573
574 $msg .= ajax_event($htmlname, $events);
575
576 return $msg;
577}
578
579
588function ajax_event($htmlname, $events)
589{
590 $out = '';
591
592 if (is_array($events) && count($events)) { // If an array of js events to do were provided.
593 $out = '<!-- JS code to manage event for id = ' . $htmlname . ' -->
594 <script>
595 $(document).ready(function () {
596 jQuery("#'.$htmlname.'").change(function () {
597 var obj = '.json_encode($events) . ';
598 $.each(obj, function(key,values) {
599 if (values.method.length) {
600 runJsCodeForEvent'.$htmlname.'(values);
601 }
602 });
603 });
604 function runJsCodeForEvent'.$htmlname.'(obj) {
605 var id = $("#'.$htmlname.'").val();
606 var method = obj.method;
607 var url = obj.url;
608 var htmlname = obj.htmlname;
609 var showempty = obj.showempty;
610 console.log("Run runJsCodeForEvent-'.$htmlname.' from ajax_combobox id="+id+" method="+method+" showempty="+showempty+" url="+url+" htmlname="+htmlname);
611 $.getJSON(url,
612 {
613 action: method,
614 id: id,
615 htmlname: htmlname,
616 showempty: showempty
617 },
618 function(response) {
619 $.each(obj.params, function(key,action) {
620 if (key.length) {
621 var num = response.num;
622 if (num > 0) {
623 $("#" + key).removeAttr(action);
624 } else {
625 $("#" + key).attr(action, action);
626 }
627 }
628 });
629
630 console.log("Replace HTML content of select#"+htmlname);
631 $("select#" + htmlname).html(response.value);
632 if (response.num) {
633 var selecthtml_str = response.value; /* response.value is the HTML string with list of options */
634 var selecthtml_dom=$.parseHTML(selecthtml_str);
635 if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
636 $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
637 }
638 } else {
639 $("#inputautocomplete"+htmlname).val("");
640 }
641 $("select#" + htmlname).change(); /* Trigger event change */
642 }
643 );
644 }
645 });
646 </script>';
647 }
648
649 return $out;
650}
651
652
674function ajax_constantonoff($code, $input = array(), $entity = null, $revertonoff = 0, $strict = 0, $forcereload = 0, $marginleftonlyshort = 2, $forcenoajax = 0, $setzeroinsteadofdel = 0, $suffix = '', $mode = '', $morecss = 'inline-block', $userconst = 0, $showwarning = '', $disabled = 0)
675{
676 global $conf, $langs, $user, $db;
677
678 $entity = ((isset($entity) && is_numeric($entity) && $entity >= 0) ? $entity : $conf->entity);
679 if (!isset($input)) {
680 $input = array();
681 }
682
683 $out = '';
684
685 if (empty($conf->use_javascript_ajax) || $forcenoajax) {
686 if (!getDolGlobalString($code)) {
687 $out = '<a '.($morecss ? 'class="'.$morecss.'" ' : '').'href="'.$_SERVER['PHP_SELF'].'?action=set_'.$code.'&token='.newToken().'&entity='.$entity.($mode ? '&mode='.$mode : '').($forcereload ? '&dol_resetcache=1' : '').'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';
688 } else {
689 $out = '<a '.($morecss ? 'class="'.$morecss.'" ' : '').' href="'.$_SERVER['PHP_SELF'].'?action=del_'.$code.'&token='.newToken().'&entity='.$entity.($mode ? '&mode='.$mode : '').($forcereload ? '&dol_resetcache=1' : '').'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';
690 }
691 } else {
692 $userconstid = 0;
693 if (is_object($userconst)) {
694 $userconstid = $userconst->id;
695 } elseif (is_numeric($userconst) && $userconst > 0) {
696 $userconstid = $userconst;
697 $userconst = new User($db);
698 $userconst->fetch($userconstid);
699 }
700
701 if ($disabled) {
702 $morecss .= ' disabled opacitymedium';
703 } else {
704 $out = "\n<!-- Ajax code to switch constant ".$code." -->".'
705 <script>
706 $(document).ready(function() {
707 var input = '.json_encode($input).';
708 var url = \''.DOL_URL_ROOT.'/core/ajax/constantonoff.php\';
709 var code = \''.dol_escape_js($code).'\';
710 var entity = \''.dol_escape_js((string) $entity).'\';
711 var strict = \''.dol_escape_js((string) $strict).'\';
712 var userid = \''.dol_escape_js((string) $user->id).'\';
713 var userconst = '.((int) $userconstid).';
714 var yesButton = \''.dol_escape_js($langs->transnoentities("Yes")).'\';
715 var noButton = \''.dol_escape_js($langs->transnoentities("No")).'\';
716 var token = \''.currentToken().'\';
717 var warning = \''.dol_escape_js($showwarning).'\';
718
719 // Set constant
720 $("#set_" + code).click(function() {
721 if (warning) {
722 alert(warning);
723 }
724
725 if (input.alert && input.alert.set) {
726 if (input.alert.set.yesButton) yesButton = input.alert.set.yesButton;
727 if (input.alert.set.noButton) noButton = input.alert.set.noButton;
728 confirmConstantAction("set", url, code, input, input.alert.set, entity, yesButton, noButton, strict, userid, token);
729 } else {
730 setConstant(url, code, input, entity, 0, '.((int) $forcereload).', userid, token, 1, userconst);
731 }
732 });
733
734 // Del constant
735 $("#del_" + code).click(function() {
736 if (input.alert && input.alert.del) {
737 if (input.alert.del.yesButton) yesButton = input.alert.del.yesButton;
738 if (input.alert.del.noButton) noButton = input.alert.del.noButton;
739 confirmConstantAction("del", url, code, input, input.alert.del, entity, yesButton, noButton, strict, userid, token);
740 } else {';
741 if (empty($setzeroinsteadofdel)) {
742 $out .= ' delConstant(url, code, input, entity, 0, '.((int) $forcereload).', userid, token, userconst);';
743 } else {
744 $out .= ' setConstant(url, code, input, entity, 0, '.((int) $forcereload).', userid, token, 0, userconst);';
745 }
746 $out .= ' }
747 });
748 });
749 </script>'."\n";
750 }
751
752 if (!empty($userconst) && $userconst instanceof User) {
753 $value = getDolUserString($code, '', $userconst);
754 } else {
755 $value = getDolGlobalString($code);
756 }
757
758 if (is_array($suffix)) {
759 $suffixon = $suffix['ifon'];
760 $suffixoff = $suffix['ifoff'];
761 } else { // old mode deprecated
762 $suffixon = (string) $suffix;
763 $suffixoff = '';
764 }
765
766 $out .= '<div id="confirm_'.$code.'" title="" style="display: none;"></div>';
767 $out .= '<span id="set_'.$code.'" class="valignmiddle inline-block linkobject '.($value ? 'hideobject' : '').($morecss ? ' '.$morecss : '').'">'.($revertonoff ? img_picto($langs->trans("Enabled"), 'switch_on'.$suffixoff, '', 0, 0, 0, '', '', $marginleftonlyshort) : img_picto($langs->trans("Disabled"), 'switch_off'.$suffixoff, '', 0, 0, 0, '', '', $marginleftonlyshort)).'</span>';
768 $out .= '<span id="del_'.$code.'" class="valignmiddle inline-block linkobject '.($value ? '' : 'hideobject').($morecss ? ' '.$morecss : '').'">'.($revertonoff ? img_picto($langs->trans("Disabled"), 'switch_off'.$suffixon, '', 0, 0, 0, '', '', $marginleftonlyshort) : img_picto($langs->trans("Enabled"), 'switch_on'.$suffixon, '', 0, 0, 0, '', '', $marginleftonlyshort)).'</span>';
769 $out .= "\n";
770 }
771
772 return $out;
773}
774
793function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input = array(), $morecss = '', $htmlname = '', $forcenojs = 0, $moreparam = '', $readonly = 0)
794{
795 global $conf, $langs;
796
797 if (empty($htmlname)) {
798 $htmlname = $code;
799 }
800
801 $out = '';
802
803 if (!empty($conf->use_javascript_ajax) && empty($forcenojs) && empty($readonly)) {
804 $out .= '<script>
805 $(function() {
806 var input = '.json_encode($input).';
807
808 // Set constant
809 $("#set_'.$htmlname.'_'.$object->id.'").click(function() {
810 console.log("Click managed by ajax_object_onoff");
811 $.get( "'.DOL_URL_ROOT.'/core/ajax/objectonoff.php", {
812 action: \'set\',
813 field: \''.dol_escape_js($field).'\',
814 value: \'1\',
815 element: \''.dol_escape_js((empty($object->module) || $object->module == $object->element) ? $object->element : $object->element.'@'.$object->module).'\',
816 id: \''.((int) $object->id).'\',
817 token: \''.currentToken().'\'
818 }).done(
819 function(response) {
820 try {
821 var data = JSON.parse(response);
822 console.log(data);
823 } catch (e) {
824 console.log(response);
825 }
826
827 $("#set_'.$htmlname.'_'.$object->id.'").hide();
828 $("#del_'.$htmlname.'_'.$object->id.'").show();
829 // Enable another element
830 if (input.disabled && input.disabled.length > 0) {
831 $.each(input.disabled, function(key,value) {
832 $("#" + value).removeAttr("disabled");
833 if ($("#" + value).hasClass("butActionRefused") == true) {
834 $("#" + value).removeClass("butActionRefused");
835 $("#" + value).addClass("butAction");
836 }
837 });
838 // Show another element
839 } else if (input.showhide && input.showhide.length > 0) {
840 $.each(input.showhide, function(key,value) {
841 $("#" + value).show();
842 });
843 }
844 }).fail(
845 function(response) {
846 //alert(response.responseText);
847 console.warn(response.responseText);
848 Dolibarr.tools.setEventMessage(response.responseText, "errors");
849 }
850 );
851 });
852
853 // Del constant
854 $("#del_'.$htmlname.'_'.$object->id.'").click(function() {
855 console.log("Click managed by ajax_object_onoff");
856 $.get( "'.DOL_URL_ROOT.'/core/ajax/objectonoff.php", {
857 action: \'set\',
858 field: \''.dol_escape_js($field).'\',
859 value: \'0\',
860 element: \''.dol_escape_js((empty($object->module) || $object->module == $object->element) ? $object->element : $object->element.'@'.$object->module).'\',
861 id: \''.((int) $object->id).'\',
862 token: \''.currentToken().'\'
863 }).done(
864 function(response) {
865 try {
866 var data = JSON.parse(response);
867 console.log(data);
868 } catch (e) {
869 console.log(response);
870 }
871
872 $("#del_'.$htmlname.'_'.$object->id.'").hide();
873 $("#set_'.$htmlname.'_'.$object->id.'").show();
874 // Disable another element
875 if (input.disabled && input.disabled.length > 0) {
876 $.each(input.disabled, function(key,value) {
877 $("#" + value).prop("disabled", true);
878 if ($("#" + value).hasClass("butAction") == true) {
879 $("#" + value).removeClass("butAction");
880 $("#" + value).addClass("butActionRefused");
881 }
882 });
883 // Hide another element
884 } else if (input.showhide && input.showhide.length > 0) {
885 $.each(input.showhide, function(key,value) {
886 $("#" + value).hide();
887 });
888 }
889 }).fail(
890 function(response) {
891 //alert(response.responseText);
892 console.warn(response.responseText);
893 Dolibarr.tools.setEventMessage(response.responseText, "errors");
894 }
895 );
896 });
897 });
898 </script>';
899 }
900
901 $switchon = 'switch_on';
902 $switchoff = 'switch_off';
903 $cssswitchon = '';
904 $cssswitchoff = '';
905 $tmparray = explode(':', $text_on);
906 if (!empty($tmparray[1])) {
907 $text_on = $tmparray[0];
908 $switchon = $tmparray[1];
909 if (!empty($tmparray[2])) {
910 $cssswitchon = $tmparray[2];
911 }
912 }
913 $tmparray = explode(':', $text_off);
914 if (!empty($tmparray[1])) {
915 $text_off = $tmparray[0];
916 $switchoff = $tmparray[1];
917 if (!empty($tmparray[2])) {
918 $cssswitchoff = $tmparray[2];
919 }
920 }
921
922 if (empty($conf->use_javascript_ajax) || $forcenojs) {
923 $url = DOL_URL_ROOT.'/core/ajax/objectonoff.php?action=set&token='.newToken().'&id='.((int) $object->id).'&element='.urlencode($object->element).'&field='.urlencode($field).'&value=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?id='.$object->id.($moreparam ? '&'.$moreparam : ''));
924 if ($readonly) {
925 $url ='#';
926 }
927 $out .= '<a id="set_'.$htmlname.'_'.$object->id.'" class="linkobject '.($object->$code == 1 ? 'hideobject' : '').($morecss ? ' '.$morecss : '').'" href="'.$url.'">'.img_picto($langs->trans($text_off), $switchoff, '', 0, 0, 0, '', $cssswitchoff).'</a>';
928 $url = DOL_URL_ROOT.'/core/ajax/objectonoff.php?action=set&token='.newToken().'&id='.((int) $object->id).'&element='.urlencode($object->element).'&field='.urlencode($field).'&value=0&backtopage='.urlencode($_SERVER["PHP_SELF"].'?id='.$object->id.($moreparam ? '&'.$moreparam : ''));
929 if ($readonly) {
930 $url ='#';
931 }
932 $out .= '<a id="del_'.$htmlname.'_'.$object->id.'" class="linkobject '.($object->$code == 1 ? '' : 'hideobject').($morecss ? ' '.$morecss : '').'" href="'.$url.'">'.img_picto($langs->trans($text_on), $switchon, '', 0, 0, 0, '', $cssswitchon).'</a>';
933 } else {
934 $out .= '<span id="set_'.$htmlname.'_'.$object->id.'" class="linkobject '.($object->$code == 1 ? 'hideobject' : '').($morecss ? ' '.$morecss : '').'">'.img_picto($langs->trans($text_off), $switchoff, '', 0, 0, 0, '', $cssswitchoff).'</span>';
935 $out .= '<span id="del_'.$htmlname.'_'.$object->id.'" class="linkobject '.($object->$code == 1 ? '' : 'hideobject').($morecss ? ' '.$morecss : '').'">'.img_picto($langs->trans($text_on), $switchon, '', 0, 0, 0, '', $cssswitchon).'</span>';
936 }
937
938 return $out;
939}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to transform a common input text or select field into ...
Definition ajax.lib.php:49
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:475
ajax_dialog($title, $message, $w=350, $h=150)
Show an ajax dialog.
Definition ajax.lib.php:432
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 text field into ...
Definition ajax.lib.php:324
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:588
Class to manage Dolibarr users.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.