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