47 function ajax_autocompleter($selected, $htmlname, $url, $urloption =
'', $minLength = 2, $autoselect = 0, $ajaxoptions = array(), $moreparams =
'')
51 if (empty($minLength)) {
55 $dataforrenderITem =
'ui-autocomplete';
56 $dataforitem =
'ui-autocomplete-item';
58 if (defined(
'JS_QUERY_AUTOCOMPLETE_RENDERITEM')) {
59 $dataforrenderITem = constant(
'JS_QUERY_AUTOCOMPLETE_RENDERITEM');
61 if (defined(
'JS_QUERY_AUTOCOMPLETE_ITEM')) {
62 $dataforitem = constant(
'JS_QUERY_AUTOCOMPLETE_ITEM');
65 $htmlnamejquery = str_replace(
'.',
'\\\\.', $htmlname);
69 $script =
'<input type="hidden" name="'.$htmlname.
'" id="'.$htmlname.
'" value="'.$selected.
'" '.($moreparams ? $moreparams :
'').
' />';
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 */
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 loosing 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 */
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("");
87 // Check options for secondary actions when keyup
88 $("input#search_'.$htmlnamejquery.
'").keyup(function() {
89 if ($(this).val().length == 0)
91 $("#search_'.$htmlnamejquery.
'").val("");
92 $("#'.$htmlnamejquery.
'").val("").trigger("change");
93 if (options.option_disabled) {
94 $("#" + options.option_disabled).removeAttr("disabled");
96 if (options.disabled) {
97 $.each(options.disabled, function(key, value) {
98 $("#" + value).removeAttr("disabled");
101 if (options.update) {
102 $.each(options.update, function(key, value) {
103 $("#" + key).val("").trigger("change");
107 $.each(options.show, function(key, value) {
108 $("#" + value).hide().trigger("hide");
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("");
116 $("#" + key).html("");
123 $("input#search_'.$htmlnamejquery.
'").autocomplete({
124 source: function( request, response ) {
125 $.get("'.$url.($urloption ?
'?'.$urloption :
'').
'", { "'.str_replace(
'.',
'_', $htmlname).
'": request.term }, function(data){
128 response($.map( data, function(item) {
129 if (autoselect == 1 && data.length == 1) {
130 $("#search_'.$htmlnamejquery.
'").val(item.value);
131 $("#'.$htmlnamejquery.
'").val(item.key).trigger("change");
134 if (item.label != null) {
135 label = item.label.toString();
138 if (options.update) {
139 $.each(options.update, function(key, value) {
140 update[key] = item[value];
144 if (options.update_textarea) {
145 $.each(options.update_textarea, function(key, value) {
146 textarea[key] = item[value];
150 console.log("Return value from GET to the rest of code");
151 return { label: label,
154 disabled: item.disabled,
160 discount: item.discount,
161 pricebasetype: item.pricebasetype,
162 price_ht: item.price_ht,
163 price_ttc: item.price_ttc,
164 price_unit_ht: item.price_unit_ht,
165 price_unit_ht_locale: item.price_unit_ht_locale,
166 description : item.description,
167 ref_customer: item.ref_customer,
169 default_vat_code: item.default_vat_code
173 console.error("Error: Ajax url '.$url.($urloption ?
'?'.$urloption :
'').
' has returned an empty page. Should be an empty json array.");
178 minLength: '.((
int) $minLength).
',
179 select: function( event, ui ) { // Function ran once new value has been selected into javascript combo
180 console.log("We will trigger change on input '.$htmlname.
' because of the select definition of autocomplete code for input#search_'.$htmlname.
'");
181 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");
183 console.log("Propagate before some properties retrieved by ajax into data-xxx properties of #'.$htmlnamejquery.
' component");
184 //console.log(ui.item);
186 // For supplier price and customer when price by quantity is off
187 $("#'.$htmlnamejquery.
'").attr("data-up", ui.item.price_ht);
188 $("#'.$htmlnamejquery.
'").attr("data-up-locale", ui.item.price_unit_ht_locale);
189 $("#'.$htmlnamejquery.
'").attr("data-base", ui.item.pricebasetype);
190 $("#'.$htmlnamejquery.
'").attr("data-qty", ui.item.qty);
191 $("#'.$htmlnamejquery.
'").attr("data-discount", ui.item.discount);
192 $("#'.$htmlnamejquery.
'").attr("data-description", ui.item.description);
193 $("#'.$htmlnamejquery.
'").attr("data-ref-customer", ui.item.ref_customer);
194 $("#'.$htmlnamejquery.
'").attr("data-tvatx", ui.item.tva_tx);
195 $("#'.$htmlnamejquery.
'").attr("data-default-vat-code", ui.item.default_vat_code);
197 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
199 // For customer price when PRODUIT_CUSTOMER_PRICES_BY_QTY is on
200 console.log("PRODUIT_CUSTOMER_PRICES_BY_QTY is on, propagate also prices by quantity into data-pbqxxx properties");
201 $("#'.$htmlnamejquery.
'").attr("data-pbq", ui.item.pbq);
202 $("#'.$htmlnamejquery.
'").attr("data-pbqup", ui.item.price_ht);
203 $("#'.$htmlnamejquery.
'").attr("data-pbqbase", ui.item.pricebasetype);
204 $("#'.$htmlnamejquery.
'").attr("data-pbqqty", ui.item.qty);
205 $("#'.$htmlnamejquery.
'").attr("data-pbqpercent", ui.item.discount);
209 // A new value has been selected, we trigger the handlers on #htmlnamejquery
210 console.log("Trigger changes on #'.$htmlnamejquery.
'");
211 $("#'.$htmlnamejquery.
'").val(ui.item.id).trigger("change"); // Select new value
213 // Complementary actions
215 // Disable an element
216 if (options.option_disabled) {
217 console.log("Make action option_disabled on #"+options.option_disabled+" with disabled="+ui.item.disabled)
218 if (ui.item.disabled) {
219 $("#" + options.option_disabled).prop("disabled", true);
221 $.jnotify(options.error, "error", true); // Output with jnotify the error message
223 if (options.warning) {
224 $.jnotify(options.warning, "warning", false); // Output with jnotify the warning message
227 $("#" + options.option_disabled).removeAttr("disabled");
231 if (options.disabled) {
232 console.log("Make action disabled on each "+options.option_disabled)
233 $.each(options.disabled, function(key, value) {
234 $("#" + value).prop("disabled", true);
238 console.log("Make action show on each "+options.show)
239 $.each(options.show, function(key, value) {
240 $("#" + value).show().trigger("show");
245 if (ui.item.update) {
246 console.log("Make action update on each ui.item.update (if there is)")
247 // loop on each "update" fields
248 $.each(ui.item.update, function(key, value) {
249 console.log("Set value "+value+" into #"+key);
250 $("#" + key).val(value).trigger("change");
253 if (ui.item.textarea) {
254 console.log("Make action textarea on each ui.item.textarea (if there is)")
255 $.each(ui.item.textarea, function(key, value) {
256 if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances[key] != "undefined") {
257 CKEDITOR.instances[key].setData(value);
258 CKEDITOR.instances[key].focus();
260 $("#" + key).html(value);
261 $("#" + key).focus();
265 console.log("ajax_autocompleter new value selected, we trigger change also on original component so on field #search_'.$htmlname.
'");
267 $("#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.
270 }).data("'.$dataforrenderITem.
'")._renderItem = function( ul, item ) {
272 .data( "'.$dataforitem.
'", item ) // jQuery UI > 1.10.0
273 .append( \'<a><span class="tag">\' + item.label + "</span></a>" )
278 $script .=
'</script>';
299 $script =
'<!-- Autocomplete -->'.
"\n";
300 $script .=
'<script>';
301 $script .=
'jQuery(document).ready(function() {
302 var fields = '.json_encode($fields).
';
303 var nboffields = fields.length;
304 var autoselect = '.$autoselect.
';
305 //alert(fields + " " + nboffields);
307 jQuery("input#'.$htmlname.
'").autocomplete({
309 minLength: '.$minLength.
',
310 source: function( request, response ) {
311 jQuery.getJSON( "'.$url.($option ?
'?'.$option :
'').
'", { '.$htmlname.
': request.term }, function(data){
312 response( jQuery.map( data, function( item ) {
313 if (autoselect == 1 && data.length == 1) {
314 jQuery("#'.$htmlname.
'").val(item.value);
315 // TODO move this to specific request
317 jQuery("#state_id").html(item.states);
319 for (i=0;i<nboffields;i++) {
320 if (item[fields[i]]) { // If defined
321 //alert(item[fields[i]]);
322 jQuery("#" + fields[i]).val(item[fields[i]]);
330 select: function( event, ui ) {
332 for (i=0;i<nboffields;i++) {
333 //alert(fields[i] + " = " + ui.item[fields[i]]);
334 if (fields[i]=="selectcountry_id")
336 if (ui.item[fields[i]] > 0) // Do not erase country if unknown
338 oldvalue=jQuery("#" + fields[i]).val();
339 newvalue=ui.item[fields[i]];
340 //alert(oldvalue+" "+newvalue);
341 jQuery("#" + fields[i]).val(ui.item[fields[i]]);
342 if (oldvalue != newvalue) // To force select2 to refresh visible content
344 needtotrigger="#" + fields[i];
347 // If we set new country and new state, we need to set a new list of state to allow change
348 if (ui.item.states && ui.item["state_id"] != jQuery("#state_id").value) {
349 jQuery("#state_id").html(ui.item.states);
353 else if (fields[i]=="state_id" || fields[i]=="state_id")
355 if (ui.item[fields[i]] > 0) // Do not erase state if unknown
357 oldvalue=jQuery("#" + fields[i]).val();
358 newvalue=ui.item[fields[i]];
359 //alert(oldvalue+" "+newvalue);
360 jQuery("#" + fields[i]).val(ui.item[fields[i]]); // This may fails if not correct country
361 if (oldvalue != newvalue) // To force select2 to refresh visible content
363 needtotrigger="#" + fields[i];
367 else if (ui.item[fields[i]]) { // If defined
368 oldvalue=jQuery("#" + fields[i]).val();
369 newvalue=ui.item[fields[i]];
370 //alert(oldvalue+" "+newvalue);
371 jQuery("#" + fields[i]).val(ui.item[fields[i]]);
372 if (oldvalue != newvalue) // To force select2 to refresh visible content
374 needtotrigger="#" + fields[i];
378 if (needtotrigger != "") // To force select2 to refresh visible content
380 // 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
381 // This is required for example when changing zip with autocomplete that change the country
382 jQuery(needtotrigger).delay(500).queue(function() {
383 jQuery(this).trigger("change");
390 $script .=
'</script>';
409 $msg =
'<div id="dialog-info" title="'.dol_escape_htmltag($newtitle).
'">';
411 $msg .=
'</div>'.
"\n";
414 jQuery("#dialog-info").dialog({
421 jQuery(this).dialog(\'close\');
449 function ajax_combobox($htmlname, $events = array(), $minLengthToAutocomplete = 0, $forcefocus = 0, $widthTypeOfAutocomplete =
'resolve', $idforemptyvalue =
'-1', $morecss =
'')
454 if (!empty($conf->browser->layout) && $conf->browser->layout ==
'phone' && !empty($conf->global->MAIN_DISALLOW_SELECT2_WITH_SMARTPHONE)) {
458 if (!empty($conf->global->MAIN_DISABLE_AJAX_COMBOX)) {
461 if (empty($conf->use_javascript_ajax)) {
464 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined(
'REQUIRE_JQUERY_MULTISELECT')) {
467 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
471 if (empty($minLengthToAutocomplete)) {
472 $minLengthToAutocomplete = 0;
475 $moreselect2theme = ($morecss ?
dol_escape_js(
' '.$morecss) :
'');
476 $moreselect2theme = preg_replace(
'/widthcentpercentminus[^\s]*/',
'', $moreselect2theme);
478 $tmpplugin =
'select2';
479 $msg =
"\n".
'<!-- JS CODE TO ENABLE '.$tmpplugin.
' for id = '.$htmlname.
' -->
481 $(document).ready(function () {
482 $(\''.(preg_match(
'/^\./', $htmlname) ? $htmlname :
'#'.$htmlname).
'\').
'.$tmpplugin.'({
484 if (preg_match(
'/onrightofpage/', $morecss)) {
485 $msg .=
' dropdownAutoWidth: true, dropdownParent: $(\'#'.$htmlname.
'\').parent(),
'."\n";
487 $msg .= ' width: \
''.dol_escape_js($widthTypeOfAutocomplete).
'\',
488 minimumInputLength:
'.((int) $minLengthToAutocomplete).',
489 language: select2arrayoflanguage,
490 matcher:
function (params, data) {
491 if ($.trim(params.term) ===
"") {
494 keywords = (params.term).split(
" ");
495 for (var i = 0; i < keywords.length; i++) {
496 if (((data.text).toUpperCase()).indexOf((keywords[i]).toUpperCase()) == -1) {
502 theme: \
'default'.$moreselect2theme.
'\',
503 containerCssClass: \
':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
504 selectionCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
505 dropdownCssClass: \'ui-dialog\',
506 templateResult: function (data, container) { /* Format visible output into combo list */
507 /* Code to add class of origin OPTION propagated to the new select2 <li> tag */
508 if (data.element) { $(container).addClass($(data.element).attr("class")); }
509 //console.log($(data.element).attr("data-html"));
510 if (data.id == '.((int) $idforemptyvalue).
' && $(data.element).attr("data-html") == undefined) {
513 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
516 templateSelection: function (selection) { /* Format visible output of selected value */
517 if (selection.id == '.((int) $idforemptyvalue).
') return \'<span class="placeholder">\'+selection.text+\'</span>\';
518 return selection.text;
520 escapeMarkup: function(markup) {
525 $msg .=
'.select2(\'focus\')';
529 if (is_array($events) && count($events)) {
531 jQuery("#'.$htmlname.
'").change(function () {
532 var obj = '.json_encode($events).
';
533 $.each(obj, function(key,values) {
534 if (values.method.length) {
535 runJsCodeForEvent'.$htmlname.
'(values);
540 function runJsCodeForEvent'.$htmlname.
'(obj) {
541 var id = $("#'.$htmlname.
'").val();
542 var method = obj.method;
544 var htmlname = obj.htmlname;
545 var showempty = obj.showempty;
546 console.log("Run runJsCodeForEvent-'.$htmlname.
' from ajax_combobox id="+id+" method="+method+" showempty="+showempty+" url="+url+" htmlname="+htmlname);
555 $.each(obj.params, function(key,action) {
557 var num = response.num;
559 $("#" + key).removeAttr(action);
561 $("#" + key).attr(action, action);
565 $("select#" + htmlname).html(response.value);
567 var selecthtml_str = response.value;
568 var selecthtml_dom=$.parseHTML(selecthtml_str);
569 if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
570 $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
573 $("#inputautocomplete"+htmlname).val("");
575 $("select#" + htmlname).change(); /* Trigger event change */
582 $msg .=
"</script>\n";
604 function ajax_constantonoff($code, $input = array(), $entity =
null, $revertonoff = 0, $strict = 0, $forcereload = 0, $marginleftonlyshort = 2, $forcenoajax = 0, $setzeroinsteadofdel = 0, $suffix =
'', $mode =
'', $morecss =
'')
606 global $conf, $langs, $user;
608 $entity = ((isset($entity) && is_numeric($entity) && $entity >= 0) ? $entity : $conf->entity);
609 if (!isset($input)) {
613 if (empty($conf->use_javascript_ajax) || $forcenoajax) {
614 if (empty($conf->global->$code)) {
615 print
'<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>';
617 print
'<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>';
620 $out =
"\n<!-- Ajax code to switch constant ".$code.
" -->".
'
622 $(document).ready(function() {
623 var input = '.json_encode($input).
';
624 var url = \''.DOL_URL_ROOT.
'/core/ajax/constantonoff.php\';
626 var entity = \
''.dol_escape_js($entity).
'\';
627 var strict = \
''.dol_escape_js($strict).
'\';
628 var userid = \
''.dol_escape_js($user->id).
'\';
629 var yesButton = \
''.dol_escape_js($langs->transnoentities(
"Yes")).
'\';
630 var noButton = \
''.dol_escape_js($langs->transnoentities(
"No")).
'\';
631 var token = \
''.currentToken().
'\';
634 $(
"#set_" +
code).click(
function() {
635 if (input.alert && input.alert.set) {
636 if (input.alert.set.yesButton) yesButton = input.alert.set.yesButton;
637 if (input.alert.set.noButton) noButton = input.alert.set.noButton;
638 confirmConstantAction(
"set", url,
code, input, input.alert.set, entity, yesButton, noButton, strict, userid, token);
640 setConstant(url,
code, input, entity, 0,
'.((int) $forcereload).', userid, token);
645 $(
"#del_" +
code).click(
function() {
646 if (input.alert && input.alert.del) {
647 if (input.alert.del.yesButton) yesButton = input.alert.del.yesButton;
648 if (input.alert.del.noButton) noButton = input.alert.del.noButton;
649 confirmConstantAction(
"del", url,
code, input, input.alert.del, entity, yesButton, noButton, strict, userid, token);
651 if (empty($setzeroinsteadofdel)) {
652 $out .=' delConstant(url,
code, input, entity, 0,
'.((int) $forcereload).', userid, token);
';
654 $out .=' setConstant(url,
code, input, entity, 0,
'.((int) $forcereload).', userid, token, 0);
';
661 $out .= '<div
id=
"confirm_'.$code.'" title=
"" style=
"display: none;"></div>
';
662 $out .= '<span
id=
"set_'.$code.'" class=
"valignmiddle linkobject '.(!empty($conf->global->$code) ? 'hideobject' : '').'">
'.($revertonoff ?img_picto($langs->trans("Enabled"), 'switch_on
', '', false, 0, 0, '', '', $marginleftonlyshort) : img_picto($langs->trans("Disabled"), 'switch_off
', '', false, 0, 0, '', '', $marginleftonlyshort)).'</span>
';
663 $out .= '<span
id=
"del_'.$code.'" class=
"valignmiddle linkobject '.(!empty($conf->global->$code) ? '' : 'hideobject').'">
'.($revertonoff ?img_picto($langs->trans("Disabled"), 'switch_off
'.$suffix, '', false, 0, 0, '', '', $marginleftonlyshort) : img_picto($langs->trans("Enabled"), 'switch_on
'.$suffix, '', false, 0, 0, '', '', $marginleftonlyshort)).'</span>
';
684 function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input = array(), $morecss = '', $htmlname = '')
688 if (empty($htmlname)) {
694 var input =
'.json_encode($input).';
697 $(
"#set_'.$htmlname.'_'.$object->id.'").click(
function() {
698 console.log(
"Click managed by ajax_object_onoff");
699 $.get(
"'.DOL_URL_ROOT.'/core/ajax/objectonoff.php", {
701 field: \''.dol_escape_js($field).
'\',
703 element: \''.dol_escape_js($object->element).
'\',
704 id: \
''.$object->id.
'\',
705 token: \
''.currentToken().
'\'
708 $(
"#set_'.$htmlname.'_'.$object->id.'").hide();
709 $(
"#del_'.$htmlname.'_'.$object->id.'").show();
711 if (input.disabled && input.disabled.length > 0) {
712 $.each(input.disabled,
function(key,value) {
713 $(
"#" + value).removeAttr(
"disabled");
714 if ($(
"#" + value).hasClass(
"butActionRefused") ==
true) {
715 $(
"#" + value).removeClass(
"butActionRefused");
716 $(
"#" + value).addClass(
"butAction");
720 }
else if (input.showhide && input.showhide.length > 0) {
721 $.each(input.showhide,
function(key,value) {
722 $(
"#" + value).show();
729 $(
"#del_'.$htmlname.'_'.$object->id.'").click(
function() {
730 console.log(
"Click managed by ajax_object_onoff");
731 $.get(
"'.DOL_URL_ROOT.'/core/ajax/objectonoff.php", {
733 field: \''.dol_escape_js($field).
'\',
735 element: \''.dol_escape_js($object->element).
'\',
736 id: \
''.$object->id.
'\',
737 token: \
''.currentToken().
'\'
740 $(
"#del_'.$htmlname.'_'.$object->id.'").hide();
741 $(
"#set_'.$htmlname.'_'.$object->id.'").show();
743 if (input.disabled && input.disabled.length > 0) {
744 $.each(input.disabled,
function(key,value) {
745 $(
"#" + value).prop(
"disabled",
true);
746 if ($(
"#" + value).hasClass(
"butAction") ==
true) {
747 $(
"#" + value).removeClass(
"butAction");
748 $(
"#" + value).addClass(
"butActionRefused");
752 }
else if (input.showhide && input.showhide.length > 0) {
753 $.each(input.showhide,
function(key,value) {
754 $(
"#" + value).hide();
761 $out .= '<span
id=
"set_'.$htmlname.'_'.$object->id.'" class=
"linkobject '.($object->$code == 1 ? 'hideobject' : '').($morecss ? ' '.$morecss : '').'">
'.img_picto($langs->trans($text_off), 'switch_off
').'</span>
';
762 $out .= '<span
id=
"del_'.$htmlname.'_'.$object->id.'" class=
"linkobject '.($object->$code == 1 ? '' : 'hideobject').($morecss ? ' '.$morecss : '').'">
'.img_picto($langs->trans($text_on), 'switch_on
').'</span>
';