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