dolibarr 21.0.0-beta
lib_head.js.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005-2018 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024 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
29if (!defined('NOREQUIRESOC')) {
30 define('NOREQUIRESOC', '1');
31}
32if (!defined('NOCSRFCHECK')) {
33 define('NOCSRFCHECK', 1);
34}
35if (!defined('NOTOKENRENEWAL')) {
36 define('NOTOKENRENEWAL', 1);
37}
38if (!defined('NOLOGIN')) {
39 define('NOLOGIN', 1);
40}
41if (!defined('NOREQUIREMENU')) {
42 define('NOREQUIREMENU', 1);
43}
44if (!defined('NOREQUIREHTML')) {
45 define('NOREQUIREHTML', 1);
46}
47if (!defined('NOREQUIREAJAX')) {
48 define('NOREQUIREAJAX', '1');
49}
50
51session_cache_limiter('public');
52
53require_once '../../main.inc.php';
59/*
60 * View
61 */
62
63// Define javascript type
64top_httphead('text/javascript; charset=UTF-8');
65// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access.
66if (empty($dolibarr_nocache)) {
67 header('Cache-Control: max-age=10800, public, must-revalidate');
68} else {
69 header('Cache-Control: no-cache');
70}
71
72
73
74// Define tradMonths javascript array (we define this in datepicker AND in parent page to avoid errors with IE8)
75$tradMonths = array(
76dol_escape_js($langs->transnoentitiesnoconv("Month01")),
77dol_escape_js($langs->transnoentitiesnoconv("Month02")),
78dol_escape_js($langs->transnoentitiesnoconv("Month03")),
79dol_escape_js($langs->transnoentitiesnoconv("Month04")),
80dol_escape_js($langs->transnoentitiesnoconv("Month05")),
81dol_escape_js($langs->transnoentitiesnoconv("Month06")),
82dol_escape_js($langs->transnoentitiesnoconv("Month07")),
83dol_escape_js($langs->transnoentitiesnoconv("Month08")),
84dol_escape_js($langs->transnoentitiesnoconv("Month09")),
85dol_escape_js($langs->transnoentitiesnoconv("Month10")),
86dol_escape_js($langs->transnoentitiesnoconv("Month11")),
87dol_escape_js($langs->transnoentitiesnoconv("Month12"))
88);
89
90$tradMonthsShort = array(
91$langs->trans("MonthShort01"),
92$langs->trans("MonthShort02"),
93$langs->trans("MonthShort03"),
94$langs->trans("MonthShort04"),
95$langs->trans("MonthShort05"),
96$langs->trans("MonthShort06"),
97$langs->trans("MonthShort07"),
98$langs->trans("MonthShort08"),
99$langs->trans("MonthShort09"),
100$langs->trans("MonthShort10"),
101$langs->trans("MonthShort11"),
102$langs->trans("MonthShort12")
103);
104
105$tradDays = array(
106$langs->trans("Sunday"),
107$langs->trans("Monday"),
108$langs->trans("Tuesday"),
109$langs->trans("Wednesday"),
110$langs->trans("Thursday"),
111$langs->trans("Friday"),
112$langs->trans("Saturday")
113);
114
115$tradDaysShort = array(
116$langs->trans("ShortSunday"),
117$langs->trans("ShortMonday"),
118$langs->trans("ShortTuesday"),
119$langs->trans("ShortWednesday"),
120$langs->trans("ShortThursday"),
121$langs->trans("ShortFriday"),
122$langs->trans("ShortSaturday")
123);
124
125$tradDaysMin = array(
126$langs->trans("SundayMin"),
127$langs->trans("MondayMin"),
128$langs->trans("TuesdayMin"),
129$langs->trans("WednesdayMin"),
130$langs->trans("ThursdayMin"),
131$langs->trans("FridayMin"),
132$langs->trans("SaturdayMin")
133);
134
135
136$dec = ',';
137$thousand = ' ';
138if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
139 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
140}
141if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
142 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
143}
144if ($thousand == 'Space') {
145 $thousand = ' ';
146}
147
148?>
149// Javascript libraries for Dolibarr ERP CRM (https://www.dolibarr.org)
150
151// For jQuery date picker
152var tradMonths = <?php echo json_encode($tradMonths) ?>;
153var tradMonthsShort = <?php echo json_encode($tradMonthsShort) ?>;
154var tradDays = <?php echo json_encode($tradDays) ?>;
155var tradDaysShort = <?php echo json_encode($tradDaysShort) ?>;
156var tradDaysMin = <?php echo json_encode($tradDaysMin) ?>;
157var currencyCache = <?php echo json_encode($langs->cache_currencies) ?>;
158
159// For JQuery date picker
160$(document).ready(function() {
161 $.datepicker.setDefaults({
162 autoSize: true,
163 changeMonth: true,
164 changeYear: true,
165 altField: '#timestamp',
166 altFormat: '@' // Gives a timestamp dateformat
167 });
168});
169
170jQuery(function($){
171 $.datepicker.regional['<?php echo $langs->defaultlang ?>'] = {
172 closeText: '<?php echo $langs->trans("Close2") ?>',
173 prevText: '<?php echo $langs->trans("Previous") ?>',
174 nextText: '<?php echo $langs->trans("Next") ?>',
175 currentText: '<?php echo $langs->trans("Now") ?>',
176 monthNames: tradMonths,
177 monthNamesShort: tradMonthsShort,
178 dayNames: tradDays,
179 dayNamesShort: tradDaysShort,
180 dayNamesMin: tradDaysMin,
181 weekHeader: '<?php echo $langs->trans("Week"); ?>',
182 dateFormat: '<?php echo $langs->trans("FormatDateShortJQuery"); ?>', /* Note dd/mm/yy means year on 4 digit in jquery format */
183 firstDay: <?php echo(isset($conf->global->MAIN_START_WEEK) ? $conf->global->MAIN_START_WEEK : '1'); ?>,
184 isRTL: <?php echo($langs->trans("DIRECTION") == 'rtl' ? 'true' : 'false'); ?>,
185 showMonthAfterYear: false, /* TODO add specific to country */
186 yearSuffix: '' /* TODO add specific to country */
187 };
188 $.datepicker.setDefaults($.datepicker.regional['<?php echo $langs->defaultlang ?>']);
189});
190
191
192
197var select2arrayoflanguage = {
198 matches: function (matches) { return matches + " <?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2ResultFoundUseArrows")); ?>"; },
199 noResults: function () { return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2NotFound")); ?>"; },
200 inputTooShort: function (input) {
201 var n = input.minimum;
202 /*console.log(input); console.log(input.minimum);*/
203 if (n > 1) return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2Enter")); ?> " + n + " <?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2MoreCharacters")); ?>";
204 else return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2Enter")); ?> " + n + " <?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2MoreCharacter")); ?>"
205 },
206 loadMore: function (pageNumber) { return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2LoadingMoreResults")); ?>"; },
207 searching: function () { return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2SearchInProgress")); ?>"; }
208};
209
210
215// Returns an object given an id
216function getObjectFromID(id){
217 var theObject;
218 if(document.getElementById)
219 theObject=document.getElementById(id);
220 else
221 theObject=document.all[id];
222 return theObject;
223}
224
225// Called after the selection or typing of a date to save details into detailed fields
226function dpChangeDay(dateFieldID, format)
227{
228 //showDP.datefieldID=dateFieldID;
229 console.log("Call dpChangeDay, we save date into detailed fields from format = "+format);
230
231 var thefield = getObjectFromID(dateFieldID);
232 var thefieldday = getObjectFromID(dateFieldID+"day");
233 var thefieldmonth = getObjectFromID(dateFieldID+"month");
234 var thefieldyear = getObjectFromID(dateFieldID+"year");
235
236 var date = getDateFromFormat(thefield.value, format);
237 //console.log(date);
238 if (date)
239 {
240 thefieldday.value = date.getDate();
241 if (thefieldday.onchange) thefieldday.onchange.call(thefieldday);
242 thefieldmonth.value = date.getMonth()+1;
243 if (thefieldmonth.onchange) thefieldmonth.onchange.call(thefieldmonth);
244 thefieldyear.value = date.getFullYear();
245 if (thefieldyear.onchange) thefieldyear.onchange.call(thefieldyear);
246
247 return 1;
248 }
249
250 // Replace yyyy into yy
251 newformat = format.replace(/yyyy/g, 'yy');
252 if (newformat != format) {
253 console.log("dpChangeDay, we try now from format = "+newformat);
254
255 var date = getDateFromFormat(thefield.value, newformat);
256 //console.log(date);
257 if (date)
258 {
259 thefieldday.value = date.getDate();
260 if (thefieldday.onchange) thefieldday.onchange.call(thefieldday);
261 thefieldmonth.value = date.getMonth()+1;
262 if (thefieldmonth.onchange) thefieldmonth.onchange.call(thefieldmonth);
263 thefieldyear.value = date.getFullYear();
264 if (thefieldyear.onchange) thefieldyear.onchange.call(thefieldyear);
265
266 return 2;
267 }
268 }
269
270 thefieldday.value = '';
271 if (thefieldday.onchange) thefieldday.onchange.call(thefieldday);
272 thefieldmonth.value = '';
273 if (thefieldmonth.onchange) thefieldmonth.onchange.call(thefieldmonth);
274 thefieldyear.value = '';
275 if (thefieldyear.onchange) thefieldyear.onchange.call(thefieldyear);
276
277 return 0;
278}
279
280/*
281 * =================================================================
282 * Function: formatDate(javascript object Date(), format)
283 * Purpose: Returns a date in the output format specified. The format string can use the following tags:
284 * Year | yyyy (4 digits), yy (2 digits)
285 * Month | MM (2 digits)
286 * Day of Month | dd (2 digits)
287 * Hour (1-12) | hh (2 digits) Hour (0-23) | HH (2 digits)
288 * Minute | mm (2 digits)
289 * Second | ss (2 digits)
290 * Author: Laurent Destailleur Author: Matelli (see http://matelli.fr/showcases/patchs-dolibarr/update-date-input-in-action-form.html)
291 * Licence: GPL
292 * ==================================================================
293 */
294function formatDate(date,format)
295{
296 // alert('formatDate date='+date+' format='+format);
297
298 // Force parameters en chaine
299 format=format+"";
300
301 var result="";
302
303 var year=date.getFullYear();
304 var month=date.getMonth()+1;
305 var day=date.getDate();
306 var hour=date.getHours();
307 var minute=date.getMinutes();
308 var seconde=date.getSeconds();
309
310 var i=0;
311 while (i < format.length)
312 {
313 c=format.charAt(i); // Recupere char du format
314 var substr = '';
315 j=i;
316 while ((format.charAt(j)==c) && (j < format.length)) // Recupere char successif identiques
317 {
318 substr += format.charAt(j++);
319 }
320
321 // alert('substr='+substr);
322 if (substr == 'yyyy') { result=result+year; }
323 else if (substr == 'yy') { result=result+year.substring(2,4); }
324 else if (substr == 'M') { result=result+month; }
325 else if (substr == 'MM') { result=result+(month<1||month>9?"":"0")+month; }
326 else if (substr == 'd') { result=result+day; }
327 else if (substr == 'dd') { result=result+(day<1||day>9?"":"0")+day; }
328 else if (substr == 'hh') { if (hour > 12) hour-=12; result=result+(hour<0||hour>9?"":"0")+hour; }
329 else if (substr == 'HH') { result=result+(hour<0||hour>9?"":"0")+hour; }
330 else if (substr == 'mm') { result=result+(minute<0||minute>9?"":"0")+minute; }
331 else if (substr == 'ss') { result=result+(seconde<0||seconde>9?"":"0")+seconde; }
332 else { result=result+substr; }
333
334 i+=substr.length;
335 }
336
337 // alert(result);
338 return result;
339}
340
341
342/*
343 * =================================================================
344 * Function: getDateFromFormat(date_string, format_string)
345 * Purpose: This function takes a date string and a format string.
346 * It parses the date string with format and it
347 * returns the date as a javascript Date() object. If date does not match
348 * format, it returns 0. The format string can use the following tags:
349 * Field | Tags
350 * -------------+-----------------------------------
351 * Year | yyyy (4 digits), yy (2 digits)
352 * Month | MM (2 digits)
353 * Day of Month | dd (2 digits)
354 * Hour (1-12) | hh (2 digits)
355 * Hour (0-23) | HH (2 digits)
356 * Minute | mm (2 digits)
357 * Second | ss (2 digits)
358 * Author: Laurent Destailleur
359 * Licence: GPL
360 * ==================================================================
361 */
362function getDateFromFormat(val, format)
363{
364 // alert('getDateFromFormat val='+val+' format='+format);
365
366 // Force parameters en chaine
367 val = val+"";
368 format = format+"";
369
370 if (val == '') return 0;
371
372 var now=new Date();
373 var year=now.getFullYear();
374 var month=now.getMonth()+1;
375 var day=now.getDate();
376 var hour=now.getHours();
377 var minute=now.getMinutes();
378 var seconde=now.getSeconds();
379
380 var i=0;
381 var d=0; // -d- follows the date string while -i- follows the format string
382
383 while (i < format.length)
384 {
385 c=format.charAt(i); // Recupere char du format
386 substr="";
387 j=i;
388 while ((format.charAt(j)==c) && (j < format.length)) // Get successive similar characters
389 {
390 substr += format.charAt(j++);
391 }
392
393 // alert('substr='+substr);
394 if (substr == "yyyy") year=getIntegerInString(val,d,4,4);
395 if (substr == "yy") year=""+(getIntegerInString(val,d,2,2)-0+2000); /* #28334 */
396 if (substr == "MM" ||substr == "M")
397 {
398 month=getIntegerInString(val,d,1,2);
399 if (month) d -= 2- month.length;
400 }
401 if (substr == "dd")
402 {
403 day=getIntegerInString(val,d,1,2);
404 if (day) d -= 2- day.length;
405 }
406 if (substr == "HH" ||substr == "hh" )
407 {
408 hour=getIntegerInString(val,d,1,2);
409 if (dhouray) d -= 2- hour.length;
410 }
411 if (substr == "mm"){
412 minute=getIntegerInString(val,d,1,2);
413 if (minute) d -= 2- minute.length;
414 }
415 if (substr == "ss")
416 {
417 seconde=getIntegerInString(val,d,1,2);
418 if (seconde) d -= 2- seconde.length;
419 }
420
421 i+=substr.length;
422 d+=substr.length;
423 }
424
425 // Check if format param are ok
426 if (year==null||year<1) { return 0; }
427 if (month==null||(month<1)||(month>12)) { return 0; }
428 if (day==null||(day<1)||(day>31)) { return 0; }
429 if (hour==null||(hour<0)||(hour>24)) { return 0; }
430 if (minute==null||(minute<0)||(minute>60)) { return 0; }
431 if (seconde==null||(seconde<0)||(seconde>60)) { return 0; }
432
433 // alert(year+' '+month+' '+day+' '+hour+' '+minute+' '+seconde);
434 return new Date(year,month-1,day,hour,minute,seconde);
435}
436
437/*
438 * =================================================================
439 * Function: stringIsInteger(string)
440 * Purpose: Return true if string is an integer
441 * ==================================================================
442 */
443function stringIsInteger(str)
444{
445 var digits="1234567890";
446 for (var i=0; i < str.length; i++)
447 {
448 if (digits.indexOf(str.charAt(i))==-1)
449 {
450 return false;
451 }
452 }
453 return true;
454}
455
456/*
457 * =================================================================
458 * Function: getIntegerInString(string,pos,minlength,maxlength)
459 * Purpose: Return part of string from position i that is integer
460 * ==================================================================
461 */
462function getIntegerInString(str,i,minlength,maxlength)
463{
464 for (var x=maxlength; x>=minlength; x--)
465 {
466 var substr=str.substring(i,i+x);
467 if (substr.length < minlength) { return null; }
468 if (stringIsInteger(substr)) { return substr; }
469 }
470 return null;
471}
472
473
474/*
475 * =================================================================
476 * Purpose: Clean string to have it url encoded
477 * Input: s
478 * Author: Laurent Destailleur
479 * Licence: GPL
480 * ==================================================================
481 */
482function urlencode(s) {
483 var news = s;
484 news = news.replace(/\+/gi,'%2B');
485 news = news.replace(/&/gi,'%26');
486 return news;
487}
488
489/*
490 * =================================================================
491 * Purpose: Clean string to get a HTML coded string.
492 * Input: s
493 * Author: Laurent Destailleur
494 * Licence: GPL
495 * ==================================================================
496 */
497function htmlEntityDecodeJs(inp){
498 var replacements = {'&lt;':'<','&gt;':'>','&sol;':'/','&quot;':'"','&apos;':'\'','&amp;':'&','&nbsp;':' '};
499 if (inp) {
500 for(var r in replacements){
501 inp = inp.replace(new RegExp(r,'g'),replacements[r]);
502 }
503 return inp.replace(/&#(\d+);/g, function(match, dec) {
504 return String.fromCharCode(dec);
505 });
506 } else {
507 return '';
508 }
509}
510
511
512/*
513 * =================================================================
514 * Purpose: Applique un delai avant execution. Used for autocompletion of companies.
515 * Input: funct, delay
516 * Author: Regis Houssin
517 * Licence: GPL
518 * ==================================================================
519 */
520 function ac_delay(funct,delay) {
521 // delay before start of action
522 setTimeout(funct,delay);
523}
524
525
526/*
527 * =================================================================
528 * Purpose:
529 * Clean values of a "Sortable.serialize". Used by drag and drop.
530 * Input: expr
531 * Author: Regis Houssin
532 * Licence: GPL
533 * ==================================================================
534 */
535function cleanSerialize(expr) {
536 if (typeof(expr) != 'string') {
537 return '';
538 }
539 var reg = new RegExp("(&)", "g");
540 var reg2 = new RegExp("[^A-Z0-9,]", "g");
541 var liste1 = expr.replace(reg, ",");
542 return liste1.replace(reg2, "");
543}
544
545
546/*
547 * =================================================================
548 * Purpose: Display a temporary message in input text fields (For showing help message on
549 * input field).
550 * Input: fieldId
551 * Input: message
552 * Author: Regis Houssin
553 * Licence: GPL
554 * ==================================================================
555 */
556function displayMessage(fieldId,message) {
557 var textbox = document.getElementById(fieldId);
558 if (textbox.value == '') {
559 textbox.style.color = 'grey';
560 textbox.value = message;
561 }
562}
563
564/*
565 * =================================================================
566 * Purpose: Hide a temporary message in input text fields (For showing help message on
567 * input field).
568 * Input: fiedId
569 * Input: message
570 * Author: Regis Houssin
571 * Licence: GPL
572 * ==================================================================
573 */
574function hideMessage(fieldId,message) {
575 var textbox = document.getElementById(fieldId);
576 textbox.style.color = 'black';
577 if (textbox.value == message) textbox.value = '';
578}
579
580
581/*
582 * Used by button to set on/off.
583 * Call url then make complementary action (like show/hide, enable/disable or set another option).
584 *
585 * @param string url Url (warning: as any url called in ajax mode, the url called here must not renew the token)
586 * @param string code Code
587 * @param string input Array of complementary actions to do if success
588 * @param int entity Entity
589 * @param int strict Strict (0=?, 1=?)
590 * @param int forcereload Force reload
591 * @param int userid User id
592 * @param string token Token
593 * @param int value Value to set
594 * @param int userconst 1=On/Off of user constant instead of global const
595 * @return boolean
596 */
597function setConstant(url, code, input, entity, strict, forcereload, userid, token, value, userconst) {
598 var saved_url = url; /* avoid undefined url */
599
600 $.post( url, {
601 action: "set",
602 name: code,
603 entity: entity,
604 token: token,
605 value: value,
606 userconst: userconst
607 },
608 function() { /* handler for success of post */
609 console.log("Ajax url request to set constant is a success. Make complementary actions and then forcereload="+forcereload+" value="+value);
610 if (value == 0) {
611 $("#set_" + code).show();
612 $("#del_" + code).hide();
613 } else {
614 $("#set_" + code).hide();
615 $("#del_" + code).show();
616 }
617 $.each(input, function(type, data) {
618 // Enable another element
619 if (type == "disabled" && strict != 1) {
620 $.each(data, function(key, value) {
621 var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
622 $(newvalue).removeAttr("disabled");
623 if ($(newvalue).hasClass("butActionRefused") == true) {
624 $(newvalue).removeClass("butActionRefused");
625 $(newvalue).addClass("butAction");
626 }
627 });
628 } else if (type == "enabled") {
629 $.each(data, function(key, value) {
630 var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
631 if (strict == 1)
632 $(newvalue).removeAttr("disabled");
633 else
634 $(newvalue).attr("disabled", true);
635 if ($(newvalue).hasClass("butAction") == true) {
636 $(newvalue).removeClass("butAction");
637 $(newvalue).addClass("butActionRefused");
638 }
639 });
640 // Show another element
641 } else if (type == "showhide" || type == "show") {
642 $.each(data, function(key, value) {
643 var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
644 $(newvalue).show();
645 });
646 // Set another constant
647 } else if (type == "set") {
648 $.each(data, function(key, value) {
649 $("#set_" + key).hide();
650 $("#del_" + key).show();
651 $.post( saved_url, {
652 action: "set",
653 name: key,
654 value: value,
655 entity: entity,
656 token: token
657 });
658 });
659 }
660 });
661 if (forcereload) {
662 var url = window.location.href;
663 if (url.indexOf('dol_resetcache') < 0) {
664 if (url.indexOf('?') > -1) {
665 url = url + "&dol_resetcache=1";
666 } else {
667 url = url + "?dol_resetcache=1";
668 }
669 }
670 var page_y = $(document).scrollTop();
671 url = url.replace(/page_y=\d+/g, '');
672 if (page_y > 0) {
673 if (url.indexOf('?') > -1) {
674 url = url + "&page_y="+page_y;
675 } else {
676 url = url + "?page_y="+page_y;
677 }
678 }
679 url = url.replace(/&&+/, '&');
680 console.log("url ro redirect = "+url);
681
682 window.location.href = url;
683 //location.reload();
684 return false;
685 }
686 }).fail(function(error) { console.log("Error, we force reload"); location.reload(); }); /* When it fails, we always force reload to have setEventErrorMessages in session visible */
687
688 return true;
689}
690
691/*
692 * Used by button to set on/off
693 * Call url then make complementary action (like show/hide, enable/disable or set another option).
694 *
695 * @param string url Url (warning: as any url called in ajax mode, the url called here must not renew the token)
696 * @param string code Code
697 * @param string input Array of complementary actions to do if success
698 * @param int entity Entity
699 * @param int strict Strict
700 * @param int forcereload Force reload
701 * @param int userid User id
702 * @param string token Token
703 * @param int userconst 1=On/Off of user constant instead of global const
704 * @return boolean
705 */
706function delConstant(url, code, input, entity, strict, forcereload, userid, token, userconst) {
707 var saved_url = url; /* avoid undefined url */
708
709 $.post( url, {
710 action: "del",
711 name: code,
712 entity: entity,
713 token: token,
714 userconst: userconst
715 },
716 function() {
717 console.log("Ajax url request to delete constant is success. Make complementary actions and then forcereload="+forcereload);
718 $("#del_" + code).hide();
719 $("#set_" + code).show();
720 $.each(input, function(type, data) {
721 // Disable another element
722 if (type == "disabled") {
723 $.each(data, function(key, value) {
724 var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
725 $(newvalue).attr("disabled", true);
726 if ($(newvalue).hasClass("butAction") == true) {
727 $(newvalue).removeClass("butAction");
728 $(newvalue).addClass("butActionRefused");
729 }
730 });
731 } else if (type == "enabled" && strict != 1) {
732 $.each(data, function(key, value) {
733 var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
734 $(newvalue).removeAttr("disabled");
735 if ($(newvalue).hasClass("butActionRefused") == true) {
736 $(newvalue).removeClass("butActionRefused");
737 $(newvalue).addClass("butAction");
738 }
739 });
740 // Hide another element
741 } else if (type == "showhide" || type == "hide") {
742 $.each(data, function(key, value) {
743 var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
744 $(newvalue).hide();
745 });
746 // Delete another constant
747 } else if (type == "del") {
748 $.each(data, function(key, value) {
749 $("#del_" + value).hide();
750 $("#set_" + value).show();
751 $.post( saved_url, {
752 action: "del",
753 name: value,
754 entity: entity,
755 token: token
756 });
757 });
758 }
759 });
760 if (forcereload) {
761 var url = window.location.href;
762 if (url.indexOf('dol_resetcache') < 0) {
763 if (url.indexOf('?') > -1) {
764 url = url + "&dol_resetcache=1";
765 } else {
766 url = url + "?dol_resetcache=1";
767 }
768 }
769 var page_y = $(document).scrollTop();
770 url = url.replace(/page_y=\d+/g, '');
771 if (page_y > 0) {
772 if (url.indexOf('?') > -1) {
773 url = url + "&page_y="+page_y;
774 } else {
775 url = url + "?page_y="+page_y;
776 }
777 }
778 url = url.replace(/&&+/, '&');
779 console.log("url ro redirect = "+url);
780
781 window.location.href = url;
782 //location.reload();
783 return false;
784 }
785 }).fail(function(error) { console.log("Error, we force reload"); location.reload(); }); /* When it fails, we always force reload to have setEventErrorMessages in session visible */
786
787 return true;
788}
789
790/*
791 * Call the setConstant or delConstant but with a confirmation before.
792 * Used by button to set on/off.
793 *
794 * @param string action Action
795 * @param string url Url
796 * @param string code Code
797 * @param string input Array of complementary actions to do if success
798 * @param string box Box
799 * @param int entity Entity
800 * @param int yesButton yesButton
801 * @param int noButton noButton
802 * @param int strict Strict
803 * @param int userid User id
804 * @param string token Token
805 * @return boolean
806 */
807function confirmConstantAction(action, url, code, input, box, entity, yesButton, noButton, strict, userid, token) {
808 var boxConfirm = box;
809 $("#confirm_" + code)
810 .attr("title", boxConfirm.title)
811 .html(boxConfirm.content)
812 .dialog({
813 resizable: false,
814 height: 170,
815 width: 500,
816 modal: true,
817 buttons: [
818 {
819 id : 'yesButton_' + code,
820 text : yesButton,
821 click : function() {
822 if (action == "set") {
823 setConstant(url, code, input, entity, strict, 0, userid, token, 1);
824 } else if (action == "del") {
825 delConstant(url, code, input, entity, strict, 0, userid, token);
826 }
827 // Close dialog
828 $(this).dialog("close");
829 // Execute another method
830 if (boxConfirm.method) {
831 var fnName = boxConfirm.method;
832 if (window.hasOwnProperty(fnName)) {
833 window[fnName]();
834 }
835 }
836 }
837 },
838 {
839 id : 'noButton_' + code,
840 text : noButton,
841 click : function() {
842 $(this).dialog("close");
843 }
844 }
845 ]
846 });
847 // For information dialog box only, hide the noButton
848 if (boxConfirm.info) {
849 $("#noButton_" + code).button().hide();
850 }
851
852 return true;
853}
854
855
856/*
857 * =================================================================
858 * This is to allow to transform all select box into ajax autocomplete box
859 * with just one line:
860 * $(function() { $( "#idofmylist" ).combobox(); });
861 * Do not use it on large combo boxes
862 * =================================================================
863 */
864(function( $ ) {
865 $.widget( "ui.combobox", {
866 options: {
867 minLengthToAutocomplete: 0
868 },
869 _create: function() {
870 var savMinLengthToAutocomplete = this.options.minLengthToAutocomplete;
871 var self = this,
872 select = this.element.hide(),
873 selected = select.children( ":selected" ),
874 value = selected.val() ? selected.text() : "";
875 var input = this.input = $( "<input>" )
876 .insertAfter( select )
877 .val( value )
878 .attr('id', 'inputautocomplete'+select.attr('id'))
879 .autocomplete({
880 delay: 0,
881 minLength: this.options.minLengthToAutocomplete,
882 source: function( request, response ) {
883 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
884 response( select.children( "option:enabled" ).map(function() {
885 var text = $( this ).text();
886 if ( this.value && ( !request.term || matcher.test(text) ) )
887 return {
888 label: text.replace(
889 new RegExp(
890 "(?![^&;]+;)(?!<[^<>]*)(" +
891 $.ui.autocomplete.escapeRegex(request.term) +
892 ")(?![^<>]*>)(?![^&;]+;)", "gi"
893 ), "<strong>$1</strong>" ),
894 value: text,
895 option: this
896 };
897 }) );
898 },
899 select: function( event, ui ) {
900 ui.item.option.selected = true;
901 self._trigger( "selected", event, {
902 item: ui.item.option
903 });
904 },
905 change: function( event, ui ) {
906 if ( !ui.item ) {
907 var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( $(this).val() ) + "$", "i" ),
908 valid = false;
909 select.children( "option" ).each(function() {
910 if ( $( this ).text().match( matcher ) ) {
911 this.selected = valid = true;
912 return false;
913 }
914 });
915 if ( !valid ) {
916 // remove invalid value, as it didn't match anything
917 $( this ).val( "" );
918 select.val( "" );
919 input.data("ui-autocomplete").term = "";
920 return false;
921 }
922 }
923 }
924 })
925 .addClass( "ui-widget ui-widget-content ui-corner-left dolibarrcombobox" );
926
927 input.data("ui-autocomplete")._renderItem = function( ul, item ) {
928 return $("<li>")
929 .data( "ui-autocomplete-item", item ) // jQuery UI > 1.10.0
930 .append( "<a>" + item.label + "</a>" )
931 .appendTo( ul );
932 };
933
934 this.button = $( "<button type=\'button\'>&nbsp;</button>" )
935 .attr( "tabIndex", -1 )
936 .attr( "title", "Show All Items" )
937 .insertAfter( input )
938 .button({
939 icons: {
940 primary: "ui-icon-triangle-1-s"
941 },
942 text: false
943 })
944 .removeClass( "ui-corner-all" )
945 .addClass( "ui-corner-right ui-button-icon" )
946 .click(function() {
947 // close if already visible
948 if ( input.autocomplete( "widget" ).is( ":visible" ) ) {
949 input.autocomplete( "close" );
950 return;
951 }
952
953 // pass empty string as value to search for, displaying all results
954 input.autocomplete({ minLength: 0 });
955 input.autocomplete( "search", "" );
956 input.autocomplete({ minLength: savMinLengthToAutocomplete });
957 input.focus();
958 });
959 },
960
961 destroy: function() {
962 this.input.remove();
963 this.button.remove();
964 this.element.show();
965 $.Widget.prototype.destroy.call( this );
966 }
967 });
968})( jQuery );
969
970
971
978function copyToClipboard(text,text2)
979{
980 text = text.replace(/<br>/g,"\n");
981 var newElem = '<textarea id="coordsforpopup" style="border: none; width: 90%; height: 120px;">'+text+'</textarea><br><br>'+text2;
982 /* alert(newElem); */
983 $("#dialogforpopup").html(newElem);
984 $("#dialogforpopup").dialog();
985 $("#coordsforpopup").select();
986
987 return false;
988}
989
990
999function newpopup(url, title) {
1000 var argv = newpopup.arguments;
1001 var argc = newpopup.arguments.length;
1002 var tmp = url;
1003 console.log("newpopup "+argv[2]+" "+argv[3]);
1004 var l = (argc > 2) ? argv[2] : 600;
1005 var h = (argc > 3) ? argv[3] : 400;
1006 var left = (screen.width - l)/2;
1007 var top = (screen.height - h)/2;
1008 var wfeatures = "directories=0,menubar=0,status=0,resizable=0,scrollbars=1,toolbar=0,location=0,width=" + l +",height=" + h + ",left=" + left + ",top=" + top;
1009 fen = window.open(tmp, title, wfeatures);
1010
1011 return false;
1012}
1013
1024function document_preview(file, type, title)
1025{
1026 var ValidImageTypes = ["image/gif", "image/jpeg", "image/png", "image/webp"];
1027 var showOriginalSizeButton = false;
1028
1029 console.log("document_preview A click was done: file="+file+", type="+type+", title="+title);
1030
1031 if ($.inArray(type, ValidImageTypes) < 0) {
1032 /* Not an image */
1033 var width='85%';
1034 var object_width='100%';
1035 var height = ($( window ).height() - 60) * 0.90;
1036 var object_height='98%';
1037
1038 show_preview('notimage');
1039
1040 } else {
1041 /* This is an image */
1042 var object_width=0;
1043 var object_height=0;
1044
1045 var img = new Image();
1046
1047 img.onload = function() {
1048 object_width = this.width;
1049 object_height = this.height;
1050
1051 width = $( window ).width()*0.90;
1052 console.log("object_width="+object_width+" window width="+width);
1053 if(object_width < width){
1054 console.log("Object width is small, we set width of popup according to image width.");
1055 width = object_width + 30
1056 }
1057 height = $( window ).height()*0.85;
1058 console.log("object_height="+object_height+" window height="+height);
1059 if(object_height < height){
1060 console.log("Object height is small, we set height of popup according to image height.");
1061 height = object_height + 80
1062 }
1063 else
1064 {
1065 showOriginalSizeButton = true;
1066 }
1067
1068 show_preview('image');
1069
1070 };
1071 img.src = file;
1072 }
1073
1074 /* This function is local to document_preview. Variables like file, type, title, object_width and object_height are global inside this function */
1075 function show_preview(mode) {
1076 /* console.log("mode="+mode+" file="+file+" type="+type+" title=title+" width="+width+" height="+height); */
1077 var newElem = '<object name="objectpreview" data="'+file+'" type="'+type+'" width="'+object_width+'" height="'+object_height+'" param="noparam"></object>';
1078
1079 optionsbuttons = {}
1080 if (mode == 'image' && showOriginalSizeButton)
1081 {
1082 var curRot = 0;
1083 optionsbuttons = {
1084 "<?php echo dol_escape_js($langs->transnoentitiesnoconv("OriginalSize")); ?>": function() { console.log("Click on original size"); jQuery(".ui-dialog-content.ui-widget-content > object").css({ "max-height": "none" }); },
1085 "<?php echo dol_escape_js($langs->transnoentitiesnoconv("RotateImage")); ?>": function() { curRot += 90; jQuery(".ui-dialog-content.ui-widget-content > object").css("transform","rotate(" + curRot + "deg)"); },
1086 "<?php echo dol_escape_js($langs->transnoentitiesnoconv("CloseWindow")); ?>": function() { $( this ).dialog( "close" ); }
1087 };
1088 }
1089
1090 $("#dialogforpopup").html(newElem);
1091
1092 $("#dialogforpopup").dialog({
1093 closeOnEscape: true,
1094 resizable: true,
1095 width: width,
1096 height: height,
1097 modal: true,
1098 title: title,
1099 buttons: optionsbuttons
1100 });
1101
1102 if (showOriginalSizeButton)
1103 {
1104 jQuery(".ui-dialog-content.ui-widget-content > object").css({ "max-height": "100%", "width": "auto", "margin-left": "auto", "margin-right": "auto", "display": "block" });
1105 }
1106 }
1107}
1108
1109/*
1110 * Provide a function to get an URL GET parameter in javascript
1111 *
1112 * @param name Name of parameter
1113 * @param valueifnotfound Value if not found
1114 * @return string Value
1115 */
1116function getParameterByName(name, valueifnotfound)
1117{
1118 name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
1119 var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
1120 results = regex.exec(location.search);
1121 return results === null ? valueifnotfound : decodeURIComponent(results[1].replace(/\+/g, " "));
1122}
1123
1127function getOperatorsForFieldType(type, maybenull = 0) {
1128 // Define the list of operators for each general field category
1129 const operatorList = {
1130 selectlink: {
1131 Is: '<?php print dol_escape_js($langs->trans('Is')); ?>',
1132 IsNot: '<?php print dol_escape_js($langs->trans('IsNot')); ?>',
1133 },
1134 text: {
1135 Contains: '<?php print dol_escape_js($langs->trans('Contains')); ?>',
1136 DoesNotContain: '<?php print dol_escape_js($langs->trans('DoesNotContain')); ?>',
1137 Is: '<?php print dol_escape_js($langs->trans('Is')); ?>',
1138 IsNot: '<?php print dol_escape_js($langs->trans('IsNot')); ?>',
1139 StartsWith: '<?php print dol_escape_js($langs->trans('StartsWith')); ?>',
1140 EndsWith: '<?php print dol_escape_js($langs->trans('EndsWith')); ?>'
1141 },
1142 number: {
1143 '=': '<?php print dol_escape_js($langs->trans('Is')); ?>',
1144 '!=': '<?php print dol_escape_js($langs->trans('IsNot')); ?>',
1145 '<': '<?php print dol_escape_js($langs->trans('IsLowerThan')); ?>',
1146 '>': '<?php print dol_escape_js($langs->trans('IsHigherThan')); ?>',
1147 '<=': '<?php print dol_escape_js($langs->trans('IsLowerThanOrEqual')); ?>',
1148 '>=': '<?php print dol_escape_js($langs->trans('IsHigherThanOrEqual')); ?>',
1149 },
1150 date: {
1151 Is: '<?php print dol_escape_js($langs->trans('Is')); ?>',
1152 IsNot: '<?php print dol_escape_js($langs->trans('IsNot')); ?>',
1153 IsBefore: '<?php print dol_escape_js($langs->trans('IsBefore')); ?>',
1154 IsAfter: '<?php print dol_escape_js($langs->trans('IsAfter')); ?>',
1155 IsOnOrBefore: '<?php print dol_escape_js($langs->trans('IsOnOrBefore')); ?>',
1156 IsOnOrAfter: '<?php print dol_escape_js($langs->trans('IsOnOrAfter')); ?>'
1157 },
1158 html: {
1159 Contains: '<?php print $langs->trans('Contains'); ?>'
1160 }
1161 };
1162
1163
1164 // Determine the general category for the given type using regex
1165 let generalType = "";
1166
1167 console.log('Get list of operators for type='+type);
1168
1169 if (/^select$/i.test(type) || /^link$/i.test(type)) {
1170 generalType = "selectlink";
1171 } else if (/^(varchar|char|text|blob|nchar|mediumtext|longtext)\(\d+\)$/i.test(type) || /^varchar$/i.test(type)) {
1172 generalType = "text";
1173 } else if (/^(int|integer|float|double|decimal|numeric)(\(\d+,\d+\))?$/i.test(type)) {
1174 generalType = "number";
1175 } else if (/^(date|datetime|timestamp)$/i.test(type)) {
1176 generalType = "date";
1177 } else if (/^(tinyint|smallint)\(\d+\)$/i.test(type)) {
1178 generalType = "number";
1179 } else if (/^html$/i.test(type)) {
1180 generalType = "html";
1181 } else {
1182 // Handle unknown or unsupported types
1183 console.log("The type of field "+type+" is not supported");
1184 return [];
1185 }
1186
1187 // If maybenull is true, then append the "IsDefined" and "IsNotDefined" operators
1188 if (maybenull === 1) {
1189 operatorList[generalType]["IsDefined"] = '<?php print dol_escape_js($langs->trans('IsDefined')); ?>';
1190 operatorList[generalType]["IsNotDefined"] = '<?php print dol_escape_js($langs->trans('IsNotDefined')); ?>';
1191 }
1192
1193 // Return the operators for the general type, or an empty array if not found
1194 return operatorList[generalType] || [];
1195}
1196
1200function generateFilterString(column, operator, context, fieldType) {
1201 let filter = "";
1202
1203 switch (operator) {
1204 case "Contains":
1205 filter = column + " like \'%" + context + "%\'";
1206 break;
1207 case "DoesNotContain":
1208 filter = column + " notlike \'%" + context + "%\'";
1209 break;
1210 case "Is":
1211 filter = column + " = \'" + context + "\'";
1212 break;
1213 case "IsNot":
1214 filter = column + " != \'" + context + "\'";
1215 break;
1216 case "StartsWith":
1217 filter = column + " like \'" + context + "%\'";
1218 break;
1219 case "EndsWith":
1220 filter = column + " like \'%" + context + "\'";
1221 break;
1222 case "IsDefined":
1223 filter = column + ":isnot:null";
1224 break;
1225 case "IsNotDefined":
1226 filter = column + ":is:null";
1227 break;
1228 case "=":
1229 filter = column + " = \'" + context + "\'";
1230 break;
1231 case "!=":
1232 filter = column + " != \'" + context + "\'";
1233 break;
1234 case "<":
1235 filter = column + " < \'" + context + "\'";
1236 break;
1237 case ">":
1238 filter = column + " > \'" + context + "\'";
1239 break;
1240 case "<=":
1241 filter = column + " <= \'" + context + "\'";
1242 break;
1243 case ">=":
1244 filter = column + " >= \'" + context + "\'";
1245 break;
1246 case "IsBefore":
1247 filter = column + " < \'" + context + "\'";
1248 break;
1249 case "IsAfter":
1250 filter = column + " > \'" + context + "\'";
1251 break;
1252 case "IsOnOrBefore":
1253 filter = column + " <= \'" + context + "\'";
1254 break;
1255 case "IsOnOrAfter":
1256 filter = column + " >= \'" + context + "\'";
1257 break;
1258 default:
1259 filter = "";
1260 }
1261
1262 return filter;
1263}
1264
1265// Code in the public domain from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
1266(function() {
1275 function decimalAdjust(type, value, exp) {
1276 // If the exp is undefined or zero...
1277 if (typeof exp === 'undefined' || +exp === 0) {
1278 return Math[type](value);
1279 }
1280 value = +value;
1281 exp = +exp;
1282 // If the value is not a number or the exp is not an integer...
1283 if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
1284 return NaN;
1285 }
1286 // Shift
1287 value = value.toString().split('e');
1288 value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
1289 // Shift back
1290 value = value.toString().split('e');
1291 return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
1292 }
1293
1294 // Decimal round
1295 if (!Math.round10) {
1296 Math.round10 = function(value, exp) {
1297 return decimalAdjust('round', value, exp);
1298 };
1299 }
1300 // Decimal floor
1301 if (!Math.floor10) {
1302 Math.floor10 = function(value, exp) {
1303 return decimalAdjust('floor', value, exp);
1304 };
1305 }
1306 // Decimal ceil
1307 if (!Math.ceil10) {
1308 Math.ceil10 = function(value, exp) {
1309 return decimalAdjust('ceil', value, exp);
1310 };
1311 }
1312})();
1313
1314// Another solution, easier, to build a javascript rounding function
1315function dolroundjs(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
1316
1334function pricejs(amount, mode = 'MT', currency_code = '', force_locale = '') {
1335 var main_max_dec_shown = <?php echo (int) str_replace('.', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN')); ?>;
1336 var main_rounding_unit = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT'); ?>;
1337 var main_rounding_tot = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_TOT'); ?>;
1338 var main_decimal_separator = <?php echo json_encode($dec) ?>;
1339 var main_thousand_separator = <?php echo json_encode($thousand) ?>;
1340 var locale_code = force_locale || <?php echo json_encode($langs->defaultlang) ?>;
1341 var amountAsLocalizedString;
1342 var useIntl = Boolean(Intl && Intl.NumberFormat);
1343 var nDigits;
1344 if (currency_code === 'auto') currency_code = <?php echo json_encode($conf->currency) ?>;
1345
1346 if (mode === 'MU') nDigits = main_rounding_unit;
1347 else if (mode === 'MT') nDigits = main_rounding_tot;
1348 else return 'Bad value for parameter mode';
1349
1350 if (useIntl) {
1351 // simple version: let the browser decide how to format the number using the provided language / currency
1352 // parameters
1353 var formattingOptions = {
1354 minimumFractionDigits: nDigits,
1355 maximumFractionDigits: nDigits
1356 };
1357 if (currency_code) {
1358 formattingOptions['style'] = 'currency';
1359 formattingOptions['currency'] = currency_code;
1360 }
1361 return Intl.NumberFormat(locale_code.replace('_', '-'), formattingOptions).format(amount);
1362 }
1363
1364 // No Intl -> attempt to format the number in a way similar to Dolibarr PHP's `price()` function
1365 amountAsLocalizedString = amount.toFixed(nDigits).replace(
1366 /((?!^)(?:\d{3})*)(?:\.(\d+))?$/,
1367 (fullMatch, digitsByThree, decimals) =>
1368 digitsByThree.replace(
1369 /\d{3}/g,
1370 (groupOfThree) => main_thousand_separator + groupOfThree
1371 ) + (decimals !== undefined ? main_decimal_separator + decimals : '')
1372 ).replace(/ /, ' ');
1373 if (!currency_code) return amountAsLocalizedString;
1374
1375 // print with currency
1376 var currency_symbol = currency_code;
1377
1378 // codes of languages / currencies where the symbol must be placed before the amount
1379 var currencyBeforeAmountCodes = {
1380 currency: ['AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD'],
1381 language: ['nl_NL']
1382 };
1383
1384 if (currencyCache[currency_code]
1385 && currencyCache[currency_code]['unicode']
1386 && currencyCache[currency_code]['unicode'].length) {
1387 currency_symbol = currencyCache[currency_code]['unicode'].reduce(function (res, cur) {return res + cur}, '');
1388 }
1389
1390 if (currencyBeforeAmountCodes.currency.indexOf(currency_code) >= 0
1391 || currencyBeforeAmountCodes.language.indexOf(locale_code)) {
1392 // if we use a language or a currency where the symbol is placed before the amount
1393 return currency_symbol + amountAsLocalizedString;
1394 }
1395
1396 // by default: currency symbol after the amount
1397 return amountAsLocalizedString + ' ' + currency_symbol;
1398}
1399
1407function price2numjs(amount) {
1408 if (amount == '') return '';
1409
1410 var dec = <?php echo json_encode($dec) ?>;
1411 var thousand = <?php echo json_encode($thousand) ?>;
1412
1413 var main_max_dec_shown = <?php echo (int) str_replace('.', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN')); ?>;
1414 var main_rounding_unit = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT'); ?>;
1415 var main_rounding_tot = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_TOT'); ?>;
1416
1417 var amount = amount.toString();
1418
1419 // rounding for unit price
1420 var rounding = main_rounding_unit;
1421 var pos = amount.indexOf(dec);
1422 var decpart = '';
1423 if (pos >= 0) {
1424 decpart = amount.substring(pos + 1).replace('/0+$/i', ''); // Remove 0 for decimal part
1425 }
1426 var nbdec = decpart.length;
1427 if (nbdec > rounding) {
1428 rounding = nbdec;
1429 }
1430 // If rounding higher than max shown
1431 if (rounding > main_max_dec_shown) rounding = main_max_dec_shown;
1432 if (thousand != ',' && thousand != '.') amount = amount.replace(',', '.');
1433 amount = amount.replace(' ', ''); // To avoid spaces
1434 amount = amount.replace(thousand, ''); // Replace of thousand before replace of dec to avoid pb if thousand is .
1435 amount = amount.replace(dec, '.');
1436
1437 //console.log("amount before="+amount+" rounding="+rounding)
1438 var res = Math.round10(amount, - rounding);
1439 // Other solution is
1440 // var res = dolroundjs(amount, rounding)
1441
1442 console.log("price2numjs text="+amount+" return="+res);
1443
1444 return res;
1445}
1446
1447
1448<?php
1449if (!getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && !defined('DISABLE_JQUERY_JNOTIFY')) {
1450 ?>
1451// Defined properties for JNotify
1452$(document).ready(function() {
1453 if (typeof $.jnotify == 'function') {
1454 $.jnotify.setup({
1455 delay: 3000 // the default time to show each notification (in milliseconds)
1456 , sticky: false // determines if the message should be considered "sticky" (user must manually close notification)
1457 , closeLabel: "&times;" // the HTML to use for the "Close" link
1458 , showClose: true // determines if the "Close" link should be shown if notification is also sticky
1459 , fadeSpeed: 1000 // the speed to fade messages out (in milliseconds)
1460 , slideSpeed: 250 // the speed used to slide messages out (in milliseconds)
1461 , classContainer: "jnotify-container"
1462 , classNotification: "jnotify-notification"
1463 , classBackground: "jnotify-background"
1464 , classClose: "jnotify-close"
1465 , classMessage: "jnotify-message"
1466 , init: null // callback that occurs when the main jnotify container is created
1467 , create: null // callback that occurs when when the note is created (occurs just before appearing in DOM)
1468 , beforeRemove: null // callback that occurs when before the notification starts to fade away
1469 });
1470 }
1471});
1472 <?php
1473} ?>
1474
1475
1476
1477jQuery(document).ready(function() {
1478 // Force to hide menus when page is inside an iFrame so we can show any page into a dialog popup
1479 if (window.location && window.location.pathname.indexOf("externalsite/frametop.php") == -1 && window.location !== window.parent.location ) {
1480 console.log("Page is detected to be into an iframe, we hide by CSS the menus");
1481 // The page is in an iframe
1482 jQuery(".side-nav-vert, .side-nav, .websitebar").hide();
1483 jQuery(".id-container").css('width', '100%');
1484
1485 }
1486
1487 // Code to set tooltip on search field
1488 jQuery('table.liste tr.liste_titre_filter td.liste_titre input[name^="search"][type=text]:not(".maxwidthdate")').attr('title', '<?php echo dol_escape_js($langs->transnoentities("SearchSyntaxTooltipForStringOrNum")) ?>');
1489});
1490
1491
1492jQuery(document).ready(function() {
1493 jQuery(document).on("click", ".butAction.dropdown-toggle", function(event) {
1494 console.log("Click on .butAction.dropdown-toggle");
1495 let parentHolder = jQuery(event.target).parent();
1496 let dropDownContent = parentHolder.children(".dropdown-content");
1497 let offset = parentHolder.offset();
1498 let widthDocument = $(document).width();
1499 let heightDocument = $(document).height();
1500 let right = widthDocument - offset.left - parentHolder.width();
1501 let widthPopup = parentHolder.children(".dropdown-content").width();
1502 if (widthPopup + right >= widthDocument) {
1503 //right = 10;
1504 }
1505
1506 parentHolder.toggleClass("open"); /* If open, it closes, if closed, it opens */
1507
1508 // Check tooltip is in viewport
1509 let dropDownContentTop = dropDownContent.offset().top;
1510 let dropDownContentLeft = dropDownContent.offset().left;
1511 let dropDownContentHeight = dropDownContent.outerHeight();
1512 let dropDownContentBottom = dropDownContentTop + dropDownContentHeight;
1513 let viewportBottom = $(window).scrollTop() + $(window).height();
1514
1515 // Change dropdown Up/Down orientation if dropdown is close to bottom viewport
1516 if(parentHolder.hasClass('open')
1517 && dropDownContentBottom > viewportBottom // Check bottom of dropdown is behind viewport
1518 && dropDownContentTop - dropDownContentHeight > 0 // check if set dropdown to --up will not go over the top of document
1519 ){
1520 parentHolder.addClass("--up");
1521 }else{
1522 parentHolder.removeClass("--up");
1523 }
1524
1525 // Change dropdown left/right offset if dropdown is close to left viewport
1526 if(parentHolder.hasClass('open') && dropDownContentLeft < 0){
1527 parentHolder.addClass("--left");
1528 }else{
1529 parentHolder.removeClass("--left");
1530 }
1531 });
1532
1533 // Close drop down
1534 jQuery(document).on("click", function(event) {
1535 // search if click was outside drop down
1536 if (!$(event.target).closest('.butAction.dropdown-toggle').length) {
1537 /* console.log("click close butAction - we click outside"); */
1538 let parentholder = jQuery(".butAction.dropdown-toggle").closest(".dropdown.open");
1539 if (parentholder){
1540 // Hide the menus.
1541 parentholder.removeClass("open --up --left");
1542 }
1543 }
1544 });
1545});
1546
1547
1548<?php
1549if (!getDolGlobalString('MAIN_DISABLE_SELECT2_FOCUS_PROTECTION') && !defined('DISABLE_SELECT2_FOCUS_PROTECTION')) {
1550 ?>
1551/*
1552 * Hacky fix for a bug in select2 with jQuery 3.6.4's new nested-focus "protection"
1553 * This fix needs to click a second time when clicking into a combo with ajax (see Test4d and Test5a in test_forms.php
1554 * see: https://github.com/select2/select2/issues/5993
1555 * see: https://github.com/jquery/jquery/issues/4382
1556 *
1557 * TODO: Recheck with the select2 GH issue and remove once this is fixed on their side
1558 */
1559$(document).on('select2:open', (e) => {
1560 console.log("Execute the focus (click on combo or use space when on component)");
1561 const target = $(e.target);
1562 if (target && target.length) {
1563 let id = target[0].id || target[0].name;
1564 if (id.substr(-2) == "[]") {
1565 id = id.substr(0,id.length-2);
1566 }
1567 document.querySelector('input[aria-controls*='+id+']').focus();
1568 }
1569});
1570 <?php
1571}
1572?>
1573
1574
1575// End of lib_head.js.php
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
getOperatorsForFieldType(type, maybenull=0)
Get the list of operators for a given field type.
copyToClipboard(text, text2)
Function to output a dialog box for copy/paste.
document_preview(file, type, title)
Function show document preview.
pricejs(amount, mode='MT', currency_code='', force_locale='')
Function similar to PHP price()
generateFilterString(column, operator, context, fieldType)
Generate a filter string based on the given column, operator, context and field type.
newpopup(url, title)
Show a popup HTML page.
price2numjs(amount)
Function similar to PHP price2num()
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:149
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:152
fail($message)
Abort invoice creation with a given error message.
Definition invoice.php:101