dolibarr 21.0.0-alpha
lib_foot.js.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 * or see https://www.gnu.org/
17 */
18
24if (!defined('NOREQUIRESOC')) {
25 define('NOREQUIRESOC', '1');
26}
27if (!defined('NOCSRFCHECK')) {
28 define('NOCSRFCHECK', 1);
29}
30if (!defined('NOTOKENRENEWAL')) {
31 define('NOTOKENRENEWAL', 1);
32}
33if (!defined('NOLOGIN')) {
34 define('NOLOGIN', 1);
35}
36if (!defined('NOREQUIREMENU')) {
37 define('NOREQUIREMENU', 1);
38}
39if (!defined('NOREQUIREHTML')) {
40 define('NOREQUIREHTML', 1);
41}
42if (!defined('NOREQUIREAJAX')) {
43 define('NOREQUIREAJAX', '1');
44}
45
46session_cache_limiter('public');
47
48require_once '../../main.inc.php';
49
50
51/*
52 * View
53 */
54
55// Define javascript type
56top_httphead('text/javascript; charset=UTF-8');
57// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access.
58if (empty($dolibarr_nocache)) {
59 header('Cache-Control: max-age=10800, public, must-revalidate');
60} else {
61 header('Cache-Control: no-cache');
62}
63
64//var_dump($conf);
65
66
67// Wrapper to show tooltips (html or onclick popup)
68print "\n/* JS CODE TO ENABLE Tooltips on all object with class classfortooltip */
69jQuery(document).ready(function () {\n";
70
71if (empty($conf->dol_no_mouse_hover)) {
72 print '
73 /* for standard tooltip */
74 jQuery(".classfortooltip").tooltip({
75 tooltipClass: "mytooltip",
76 show: { collision: "flipfit", effect:"toggle", delay:50, duration: 20 },
77 hide: { delay: 250, duration: 20 },
78 content: function () {
79 console.log("Return title for popup");
80 return $(this).prop("title"); /* To force to get title as is */
81 }
82 });
83
84 var opendelay = 100;
85 var elemtostoretooltiptimer = jQuery("#dialogforpopup");
86 var currenttoken = jQuery("meta[name=anti-csrf-currenttoken]").attr("content");
87
88 /* for ajax tooltip */
89 target = jQuery(".classforajaxtooltip");
90 target.tooltip({
91 tooltipClass: "mytooltip",
92 show: { collision: "flipfit", effect:"toggle", delay: 0, duration: 20 },
93 hide: { delay: 250, duration: 20 }
94 });
95
96 target.off("mouseover mouseout");
97 target.on("mouseover", function(event) {
98 console.log("we will create timer for ajax call");
99 event.stopImmediatePropagation();
100 clearTimeout(elemtostoretooltiptimer.data("openTimeoutId"));
101
102 var params = JSON.parse($(this).attr("data-params"));
103 params.token = currenttoken;
104 var elemfortooltip = $(this);
105
106 elemtostoretooltiptimer.data("openTimeoutId", setTimeout(function() {
107 target.tooltip("close");
108 $.ajax({
109 url:"'. DOL_URL_ROOT.'/core/ajax/ajaxtooltip.php",
110 type: "post",
111 async: true,
112 data: params,
113 success: function(response){
114 // Setting content option
115 console.log("ajax success");
116 elemfortooltip.tooltip("option","content",response);
117 elemfortooltip.tooltip("open");
118 }
119 });
120 }, opendelay));
121 });
122 target.on("mouseout", function(event) {
123 console.log("mouse out of a .classforajaxtooltip");
124 event.stopImmediatePropagation();
125 clearTimeout(elemtostoretooltiptimer.data("openTimeoutId"));
126 target.tooltip("close");
127 });
128 ';
129}
130
131print '
132 jQuery(".classfortooltiponclicktext").dialog({
133 closeOnEscape: true, classes: { "ui-dialog": "highlight" },
134 maxHeight: window.innerHeight-60, width: '.($conf->browser->layout == 'phone' ? max((empty($_SESSION['dol_screenwidth']) ? 0 : $_SESSION['dol_screenwidth']) - 20, 320) : 700).',
135 modal: true,
136 autoOpen: false
137 }).css("z-index: 5000");
138 jQuery(".classfortooltiponclick").click(function () {
139 console.log("We click on tooltip for element with dolid="+$(this).attr(\'dolid\'));
140 if ($(this).attr(\'dolid\')) {
141 obj=$("#idfortooltiponclick_"+$(this).attr(\'dolid\')); /* obj is a div component */
142 obj.dialog("open");
143 return false;
144 }
145 });
146});
147';
148
149
150// Wrapper to manage dropdown
151if (!defined('JS_JQUERY_DISABLE_DROPDOWN')) {
152 print "\n/* JS CODE TO ENABLE dropdown (hamburger, linkto, ...) */\n";
153 print ' jQuery(document).ready(function () {
154 var lastopendropdown = null;
155
156 // Click onto the link "link to" or "hamburger", toggle dropdown
157 $(document).on(\'click\', \'.dropdown dt a\', function () {
158 console.log("toggle dropdown dt a");
159 setTimeout(() => { $(\'.inputsearch_dropdownselectedfields\').focus(); }, 200);
160
161 //$(this).parent().parent().find(\'dd ul\').slideToggle(\'fast\');
162 $(".ulselectedfields").removeClass("open");
163 $(this).parent().parent().find(\'dd ul\').toggleClass("open");
164
165 if ($(this).parent().parent().find(\'dd ul\').hasClass("open")) {
166 lastopendropdown = $(this).parent().parent().find(\'dd ul\');
167 //console.log(lastopendropdown);
168 } else {
169 // We closed the dropdown for hamburger selectfields
170 if ($("input:hidden[name=formfilteraction]").val() == "listafterchangingselectedfields") {
171 console.log("resubmit the form saved into lastopendropdown after clicking on hamburger");
172 //$(".dropdown dt a").parents(\'form:first\').submit();
173 //$(".dropdown dt a").closest("form").submit();
174 lastopendropdown.closest("form").submit();
175 }
176 }
177
178 // Note: Did not find a way to get exact height (value is update at exit) so i calculate a generic from nb of lines
179 heigthofcontent = 21 * $(this).parent().parent().find(\'dd div ul li\').length;
180 if (heigthofcontent > 300) heigthofcontent = 300; // limited by max-height on css .dropdown dd ul
181 posbottom = $(this).parent().parent().find(\'dd\').offset().top + heigthofcontent + 8;
182 var scrollBottom = $(window).scrollTop() + $(window).height();
183 diffoutsidebottom = (posbottom - scrollBottom);
184 console.log("heigthofcontent="+heigthofcontent+", diffoutsidebottom (posbottom="+posbottom+" - scrollBottom="+scrollBottom+") = "+diffoutsidebottom);
185 if (diffoutsidebottom > 0)
186 {
187 pix = "-"+(diffoutsidebottom+8)+"px";
188 console.log("We reposition top by "+pix);
189 $(this).parent().parent().find(\'dd\').css("top", pix);
190 }
191 });
192
193 // Click on a link into the popup "link to" or other dropdown that ask to close drop down on element click, so close dropdown
194 $(".dropdowncloseonclick").on(\'click\', function () {
195 console.log("Link has class dropdowncloseonclick, so we close/hide the popup ul");
196 //$(this).parent().parent().hide(); // $(this).parent().parent() is ul
197 $(this).parent().parent().removeClass("open"); // $(this).parent().parent() is ul
198 });
199
200 // Click outside of any dropdown
201 $(document).bind(\'click\', function (e) {
202 var $clicked = $(e.target); // This is element we click on
203 if (!$clicked.parents().hasClass("dropdown")) {
204 //console.log("close dropdown dd ul - we click outside");
205 //$(".dropdown dd ul").hide();
206 $(".dropdown dd ul").removeClass("open");
207
208 if ($("input:hidden[name=formfilteraction]").val() == "listafterchangingselectedfields") {
209 console.log("resubmit form saved into lastopendropdown after clicking outside of dropdown and having change selectlist from selectlist field of hamburger dropdown");
210 //$(".dropdown dt a").parents(\'form:first\').submit();
211 //$(".dropdown dt a").closest("form").submit();
212 lastopendropdown.closest("form").submit();
213 }
214 }
215 });
216 });
217 ';
218}
219
220// Wrapper to manage document_preview
221if ($conf->browser->layout != 'phone') {
222 print "\n/* JS CODE TO ENABLE document_preview */\n"; // Function document_preview is into header
223 print ' jQuery(document).ready(function () {
224 // Click on the preview picto
225 jQuery(".documentpreview").click(function () {
226 console.log("We click on preview for element with href="+$(this).attr(\'href\')+" mime="+$(this).attr(\'mime\'));
227 document_preview($(this).attr(\'href\'), $(this).attr(\'mime\'), \''.dol_escape_js($langs->transnoentities("Preview")).'\');
228 return false;
229 });
230 });'."\n";
231}
232
233// Code to manage reposition
234print "\n/* JS CODE TO ENABLE reposition management (does not work if a redirect is done after action of submission) */\n";
235print '
236 jQuery(document).ready(function() {
237 /* If page_y set, we set scrollbar with it */
238 page_y=getParameterByName(\'page_y\', 0); /* search in GET parameter */
239 if (page_y == 0) page_y = jQuery("#page_y").text(); /* search in POST parameter that is filed at bottom of page */
240 if (page_y > 0)
241 {
242 console.log("page_y found is "+page_y);
243 $(\'html, body\').scrollTop(page_y);
244 }
245
246 /* Set handler to add page_y param on output (click on href links or submit button) */
247 jQuery(".reposition").click(function() {
248 var page_y = $(document).scrollTop();
249
250 if (page_y > 0)
251 {
252 if (this.href)
253 {
254 console.log("We click on tag with .reposition class. this.ref was "+this.href);
255 var hrefarray = this.href.split("#", 2);
256 hrefarray[0]=hrefarray[0].replace(/&page_y=(\d+)/, \'\'); /* remove page_y param if already present */
257 this.href=hrefarray[0]+\'&page_y=\'+page_y;
258 console.log("We click on tag with .reposition class. this.ref is now "+this.href);
259 }
260 else
261 {
262 console.log("We click on tag with .reposition class but element is not an <a> html tag, so we try to update input form field with name=page_y with value "+page_y);
263 jQuery("input[type=hidden][name=page_y]").val(page_y);
264 }
265 }
266 });
267 });'."\n";
268
269// Code to manage Copy To Clipboard click
270print "\n/* JS CODE TO ENABLE ClipBoard copy paste */\n";
271print '
272 jQuery(document).ready(function() {
273 jQuery(\'.clipboardCPShowOnHover\').hover(
274 function() {
275 console.log("We hover a value with a copy paste feature");
276 $(this).children(".clipboardCPButton, .clipboardCPText").css("display", "inline-block"); /* better than .show() because the show set the display to "inline" */
277 },
278 function() {
279 console.log("We hover out the value with a copy paste feature");
280 $(this).children(".clipboardCPButton, .clipboardCPText").hide();
281 }
282 );
283
284 jQuery(\'.clipboardCPValue, .clipboardCPButton, .clipboardCPValueToPrint\').click(function() {
285 console.log("We click on a clipboardCPButton or clipboardCPValueToPrint class and we want to copy content of clipboardCPValue class");
286
287 if (window.getSelection) {
288 jqobj=$(this).parent().children(".clipboardCPValue");
289 console.log(jqobj.html());
290
291 selection = window.getSelection(); /* get the object used for selection */
292 selection.removeAllRanges(); /* clear current selection */
293
294 /* We select the value to print using the parentNode.firstChild */
295 /* We should use the class clipboardCPValue but it may have several element with copy/paste so class to select is not enough */
296 range = document.createRange();
297 range.selectNodeContents(this.parentNode.firstChild);
298 selection.addRange(range); /* make the new selection with the value to copy */
299
300 /* copy selection into clipboard */
301 var succeed;
302 try {
303 console.log("We set the style display to unset for the span so the copy will work");
304 jqobj.css("display", "unset"); /* Because copy does not work on "block" object */
305
306 succeed = document.execCommand(\'copy\');
307
308 console.log("We set the style display back to inline-block");
309 jqobj.css("display", "inline-block"); /* better than .show() because the show set the display to "inline" */
310 } catch(e) {
311 succeed = false;
312 }
313
314 /* Remove the selection to avoid to see the hidden field to copy selected */
315 window.getSelection().removeAllRanges();
316 }
317
318 /* Show result - message */
319 var lastparent = $(this).parent(); /* .parent is clipboardCP */
320 var lastchild = this.parentNode.lastChild; /* .parentNode is clipboardCP and last child is clipboardCPText */
321 var tmp = lastchild.innerHTML
322 if (succeed) {
323 $(this).parent().children(".clipboardCPButton").hide();
324 $(this).parent().children(".clipboardCPTick").css("display", "inline-block"); /* better than .show() because the show set the display to "inline" */
325 //lastchild.innerHTML = \'<div class="clipboardCPTextDivInside opacitymedium">'.dol_escape_js($langs->trans('CopiedToClipboard')).'</div>\';
326 } else {
327 lastchild.innerHTML = \'<div class="clipboardCPTextDivInside opacitymedium">'.dol_escape_js($langs->trans('Error')).'</div>\';
328 }
329 setTimeout(() => { lastchild.innerHTML = tmp; lastparent.children(".clipboardCPTick").hide(); }, 2000);
330 });
331 });'."\n";
332
333// Code to manage clicktodial
334print "\n/* JS CODE TO ENABLE clicktodial call of an URL */\n";
335print '
336 jQuery(document).ready(function() {
337 jQuery(".cssforclicktodial").click(function() {
338 event.preventDefault();
339 var currenttoken = jQuery("meta[name=anti-csrf-currenttoken]").attr("content");
340 console.log("We click on a cssforclicktodial class with href="+this.href);
341 $.ajax({
342 url: this.href,
343 type: \'GET\',
344 data: { token: currenttoken }
345 }).done(function(xhr, textStatus, errorThrown) {
346 /* do nothing */
347 }).fail(function(xhr, textStatus, errorThrown) {
348 alert("Error: "+textStatus);
349 });
350 return false;
351 });
352 });'."\n";
353
354
355// Code to manage the confirm dialog box
356print "\n/* JS CODE TO ENABLE DIALOG CONFIRM POPUP ON ACTION BUTTON */\n";
357print '
358 jQuery(document).ready(function() {
359 $(document).on("click", \'.butActionConfirm\', function(event) {
360 event.preventDefault();
361
362 // I don\'t use jquery $(this).data(\'confirm-url\'); to get $(this).attr(\'data-confirm-url\'); because .data() can doesn\'t work with ajax
363 var confirmUrl = $(this).attr(\'data-confirm-url\');
364 var confirmTitle = $(this).attr(\'data-confirm-title\');
365 var confirmContent = $(this).attr(\'data-confirm-content\');
366 var confirmActionBtnLabel = $(this).attr(\'data-confirm-action-btn-label\');
367 var confirmCancelBtnLabel = $(this).attr(\'data-confirm-cancel-btn-label\');
368 var confirmModal = $(this).attr(\'data-confirm-modal\');
369 if(confirmModal == undefined){ confirmModal = false; }
370
371 var confirmId = \'confirm-dialog-box\';
372 if($(this).attr(\'id\') != undefined){ var confirmId = confirmId + "-" + $(this).attr(\'id\'); }
373 if($("#" + confirmId) != undefined) { $(\'#\' + confirmId).remove(); }
374
375 // Create modal box
376
377 var $confirmBox = $(\'<div/>\', {
378 id: confirmId,
379 title: confirmTitle
380 }).appendTo(\'body\');
381
382 $confirmBox.dialog({
383 autoOpen: true,
384 modal: confirmModal,
385 //width: Math.min($( window ).width() - 50, 1700),
386 width: \'auto\',
387 dialogClass: \'confirm-dialog-box\',
388 buttons: [
389 {
390 text: confirmActionBtnLabel,
391 "class": \'ui-state-information\',
392 click: function () {
393 window.location.replace(confirmUrl);
394 }
395 },
396 {
397 text: confirmCancelBtnLabel,
398 "class": \'ui-state-information\',
399 click: function () {
400 $(this).dialog("close");
401 }
402 }
403 ],
404 close: function( event, ui ) {
405 $(\'#\'+confirmBox).remove();
406 },
407 open: function( event, ui ) {
408 $confirmBox.html(confirmContent);
409 }
410 });
411 });
412 });
413'."\n";
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.