ViewMain::topHtmlHead()   F
last analyzed

Complexity

Conditions 150

Size

Total Lines 409
Code Lines 253

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 150
eloc 253
c 1
b 0
f 0
nop 9
dl 0
loc 409
rs 3.3333

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* Copyright (C) 2024       Rafael San José         <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace Dolibarr\Lib;
20
21
use Dolibarr\Code\Core\Classes\Form;
22
use Dolibarr\Code\Core\Classes\HookManager;
23
24
abstract class ViewMain
25
{
26
    /**
27
     *  Show HTML header HTML + BODY + Top menu + left menu + DIV
28
     *
29
     * @param string $head Optional head lines
30
     * @param string $title HTML title
31
     * @param string $help_url Url links to help page
32
     *                                              Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage|DE:GermanPage
33
     *                                              For other external page: http://server/url
34
     * @param string $target Target to use on links
35
     * @param int $disablejs More content into html header
36
     * @param int $disablehead More content into html header
37
     * @param array|string $arrayofjs Array of complementary js files
38
     * @param array|string $arrayofcss Array of complementary css files
39
     * @param string $morequerystring Query string to add to the link "print" to get same parameters (use only if autodetect fails)
40
     * @param string $morecssonbody More CSS on body tag. For example 'classforhorizontalscrolloftabs'.
41
     * @param string $replacemainareaby Replace call to static::mainArea() by a print of this string
42
     * @param int $disablenofollow Disable the "nofollow" on meta robot header
43
     * @param int $disablenoindex Disable the "noindex" on meta robot header
44
     * @return  void
45
     */
46
    public static function llxHeader($head = '', $title = '', $help_url = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = '', $arrayofcss = '', $morequerystring = '', $morecssonbody = '', $replacemainareaby = '', $disablenofollow = 0, $disablenoindex = 0)
47
    {
48
        global $conf, $hookmanager;
49
50
        $parameters = array(
51
            'head' => & $head,
52
            'title' => & $title,
53
            'help_url' => & $help_url,
54
            'target' => & $target,
55
            'disablejs' => & $disablejs,
56
            'disablehead' => & $disablehead,
57
            'arrayofjs' => & $arrayofjs,
58
            'arrayofcss' => & $arrayofcss,
59
            'morequerystring' => & $morequerystring,
60
            'morecssonbody' => & $morecssonbody,
61
            'replacemainareaby' => & $replacemainareaby,
62
            'disablenofollow' => & $disablenofollow,
63
            'disablenoindex' => & $disablenoindex
64
65
        );
66
        $reshook = $hookmanager->executeHooks('llxHeader', $parameters);
67
        if ($reshook > 0) {
68
            print $hookmanager->resPrint;
69
            return;
70
        }
71
72
        // html header
73
        static::topHtmlHead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow, $disablenoindex);
74
75
        $tmpcsstouse = 'sidebar-collapse' . ($morecssonbody ? ' ' . $morecssonbody : '');
76
        // If theme MD and classic layer, we open the menulayer by default.
77
        if ($conf->theme == 'md' && !in_array($conf->browser->layout, array('phone', 'tablet')) && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
78
            global $mainmenu;
79
            if ($mainmenu != 'website') {
80
                $tmpcsstouse = $morecssonbody; // We do not use sidebar-collpase by default to have menuhider open by default.
81
            }
82
        }
83
84
        if (getDolGlobalString('MAIN_OPTIMIZEFORCOLORBLIND')) {
85
            $tmpcsstouse .= ' colorblind-' . strip_tags($conf->global->MAIN_OPTIMIZEFORCOLORBLIND);
86
        }
87
88
        print '<body id="mainbody" class="' . $tmpcsstouse . '">' . "\n";
89
90
        // top menu and left menu area
91
        if ((empty($conf->dol_hide_topmenu) || GETPOSTINT('dol_invisible_topmenu')) && !GETPOSTINT('dol_openinpopup')) {
92
            static::topMenu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url);
93
        }
94
95
        if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup', 'aZ09')) {
96
            static::leftMenu(array(), $help_url, '', '', 1, $title, 1); // $menumanager is retrieved with a global $menumanager inside this function
97
        }
98
99
        // main area
100
        if ($replacemainareaby) {
101
            print $replacemainareaby;
102
            return;
103
        }
104
        static::mainArea($title);
105
    }
106
107
    /**
108
     *  Show HTTP header. Called by static::topHtmlHead().
109
     *
110
     * @param string $contenttype Content type. For example, 'text/html'
111
     * @param int<0,1> $forcenocache Force disabling of cache for the page
112
     * @return void
113
     */
114
    public static function topHttpHead($contenttype = 'text/html', $forcenocache = 0)
115
    {
116
        global $db, $conf, $hookmanager;
117
118
        if ($contenttype == 'text/html') {
119
            header("Content-Type: text/html; charset=" . $conf->file->character_set_client);
120
        } else {
121
            header("Content-Type: " . $contenttype);
122
        }
123
124
        // Security options
125
126
        // X-Content-Type-Options
127
        header("X-Content-Type-Options: nosniff"); // With the nosniff option, if the server says the content is text/html, the browser will render it as text/html (note that most browsers now force this option to on)
128
129
        // X-Frame-Options
130
        if (!defined('XFRAMEOPTIONS_ALLOWALL')) {
131
            header("X-Frame-Options: SAMEORIGIN"); // By default, frames allowed only if on same domain (stop some XSS attacks)
132
        } else {
133
            header("X-Frame-Options: ALLOWALL");
134
        }
135
136
        if (getDolGlobalString('MAIN_SECURITY_FORCE_ACCESS_CONTROL_ALLOW_ORIGIN')) {
137
            $tmpurl = constant('DOL_MAIN_URL_ROOT');
138
            $tmpurl = preg_replace('/^(https?:\/\/[^\/]+)\/.*$/', '\1', $tmpurl);
139
            header('Access-Control-Allow-Origin: ' . $tmpurl);
140
            header('Vary: Origin');
141
        }
142
143
        // X-XSS-Protection
144
        //header("X-XSS-Protection: 1");            // XSS filtering protection of some browsers (note: use of Content-Security-Policy is more efficient). Disabled as deprecated.
145
146
        // Content-Security-Policy-Report-Only
147
        if (!defined('MAIN_SECURITY_FORCECSPRO')) {
148
            // If CSP not forced from the page
149
150
            // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
151
            // For example: to restrict to only local resources, except for css (cloudflare+google), and js (transifex + google tags) and object/iframe (youtube)
152
            // default-src 'self'; style-src: https://cdnjs.cloudflare.com https://fonts.googleapis.com; script-src: https://cdn.transifex.com https://www.googletagmanager.com; object-src https://youtube.com; frame-src https://youtube.com; img-src: *;
153
            // For example, to restrict everything to itself except img that can be on other servers:
154
            // default-src 'self'; img-src *;
155
            // Pre-existing site that uses too much js code to fix but wants to ensure resources are loaded only over https and disable plugins:
156
            // default-src https: 'unsafe-inline' 'unsafe-eval'; object-src 'none'
157
            //
158
            // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com;";
159
            // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src *; script-src 'self' 'unsafe-inline' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com; style-src 'self' 'unsafe-inline'; connect-src 'self';";
160
            $contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSPRO');
161
162
            if (!is_object($hookmanager)) {
163
                $hookmanager = new HookManager($db);
164
            }
165
            $hookmanager->initHooks(array("main"));
166
167
            $parameters = array('contentsecuritypolicy' => $contentsecuritypolicy, 'mode' => 'reportonly');
168
            $result = $hookmanager->executeHooks('setContentSecurityPolicy', $parameters); // Note that $action and $object may have been modified by some hooks
169
            if ($result > 0) {
170
                $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
171
            } else {
172
                $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
173
            }
174
175
            if (!empty($contentsecuritypolicy)) {
176
                header("Content-Security-Policy-Report-Only: " . $contentsecuritypolicy);
177
            }
178
        } else {
179
            header("Content-Security-Policy: " . constant('MAIN_SECURITY_FORCECSPRO'));
180
        }
181
182
        // Content-Security-Policy
183
        if (!defined('MAIN_SECURITY_FORCECSP')) {
184
            // If CSP not forced from the page
185
186
            // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
187
            // For example: to restrict to only local resources, except for css (cloudflare+google), and js (transifex + google tags) and object/iframe (youtube)
188
            // default-src 'self'; style-src: https://cdnjs.cloudflare.com https://fonts.googleapis.com; script-src: https://cdn.transifex.com https://www.googletagmanager.com; object-src https://youtube.com; frame-src https://youtube.com; img-src: *;
189
            // For example, to restrict everything to itself except img that can be on other servers:
190
            // default-src 'self'; img-src *;
191
            // Pre-existing site that uses too much js code to fix but wants to ensure resources are loaded only over https and disable plugins:
192
            // default-src https: 'unsafe-inline' 'unsafe-eval'; object-src 'none'
193
            //
194
            // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com;";
195
            // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src *; script-src 'self' 'unsafe-inline' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com; style-src 'self' 'unsafe-inline'; connect-src 'self';";
196
            $contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSP');
197
198
            if (!is_object($hookmanager)) {
199
                $hookmanager = new HookManager($db);
200
            }
201
            $hookmanager->initHooks(array("main"));
202
203
            $parameters = array('contentsecuritypolicy' => $contentsecuritypolicy, 'mode' => 'active');
204
            $result = $hookmanager->executeHooks('setContentSecurityPolicy', $parameters); // Note that $action and $object may have been modified by some hooks
205
            if ($result > 0) {
206
                $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
207
            } else {
208
                $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
209
            }
210
211
            if (!empty($contentsecuritypolicy)) {
212
                header("Content-Security-Policy: " . $contentsecuritypolicy);
213
            }
214
        } else {
215
            header("Content-Security-Policy: " . constant('MAIN_SECURITY_FORCECSP'));
216
        }
217
218
        // Referrer-Policy
219
        // Say if we must provide the referrer when we jump onto another web page.
220
        // Default browser are 'strict-origin-when-cross-origin' (only domain is sent on other domain switching), we want more so we use 'same-origin' so browser doesn't send any referrer at all when going into another web site domain.
221
        // Note that we do not use 'strict-origin' as this breaks feature to restore filters when clicking on "back to page" link on some cases.
222
        if (!defined('MAIN_SECURITY_FORCERP')) {
223
            $referrerpolicy = getDolGlobalString('MAIN_SECURITY_FORCERP', "same-origin");
224
225
            header("Referrer-Policy: " . $referrerpolicy);
226
        }
227
228
        if ($forcenocache) {
229
            header("Cache-Control: no-cache, no-store, must-revalidate, max-age=0");
230
        }
231
232
        // No need to add this token in header, we use instead the one into the forms.
233
        //header("anti-csrf-token: ".newToken());
234
    }
235
236
237
    /**
238
     * Output html header of a page. It calls also static::topHttpHead()
239
     * This code is also duplicated into security2.lib.php::dol_loginfunction
240
     *
241
     * @param string $head Optional head lines
242
     * @param string $title HTML title
243
     * @param int<0,1> $disablejs Disable js output
244
     * @param int<0,1> $disablehead Disable head output
245
     * @param string[] $arrayofjs Array of complementary js files
246
     * @param string[] $arrayofcss Array of complementary css files
247
     * @param int<0,1> $disableforlogin Do not load heavy js and css for login pages
248
     * @param int<0,1> $disablenofollow Disable nofollow tag for meta robots
249
     * @param int<0,1> $disablenoindex Disable noindex tag for meta robots
250
     * @return  void
251
     */
252
    public static function topHtmlHead($head, $title = '', $disablejs = 0, $disablehead = 0, $arrayofjs = array(), $arrayofcss = array(), $disableforlogin = 0, $disablenofollow = 0, $disablenoindex = 0)
253
    {
254
        global $db, $conf, $langs, $user, $mysoc, $hookmanager;
255
256
        static::topHttpHead();
257
258
        if (empty($conf->css)) {
259
            $conf->css = '/theme/eldy/style.css.php'; // If not defined, eldy by default
260
        }
261
262
        print '<!doctype html>' . "\n";
263
264
        print '<html lang="' . substr($langs->defaultlang, 0, 2) . '">' . "\n";
265
266
        //print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">'."\n";
267
        if (empty($disablehead)) {
268
            if (!is_object($hookmanager)) {
269
                $hookmanager = new HookManager($db);
270
            }
271
            $hookmanager->initHooks(array("main"));
272
273
            $ext = 'layout=' . (empty($conf->browser->layout) ? '' : $conf->browser->layout) . '&amp;version=' . urlencode(DOL_VERSION);
274
275
            print "<head>\n";
276
277
            if (GETPOST('dol_basehref', 'alpha')) {
278
                print '<base href="' . dol_escape_htmltag(GETPOST('dol_basehref', 'alpha')) . '">' . "\n";
279
            }
280
281
            // Displays meta
282
            print '<meta charset="utf-8">' . "\n";
283
            print '<meta name="robots" content="' . ($disablenoindex ? 'index' : 'noindex') . ($disablenofollow ? ',follow' : ',nofollow') . '">' . "\n"; // Do not index
284
            print '<meta name="viewport" content="width=device-width, initial-scale=1.0">' . "\n"; // Scale for mobile device
285
            print '<meta name="author" content="Dolibarr Development Team">' . "\n";
286
            print '<meta name="anti-csrf-newtoken" content="' . newToken() . '">' . "\n";
287
            print '<meta name="anti-csrf-currenttoken" content="' . currentToken() . '">' . "\n";
288
            if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
289
                print '<meta name="MAIN_FEATURES_LEVEL" content="' . getDolGlobalInt('MAIN_FEATURES_LEVEL') . '">' . "\n";
290
            }
291
            // Favicon
292
            $favicon = constant('DOL_URL_ROOT') . '/theme/alixar_square_logo_256x256_color.png';
293
            if (!empty($mysoc->logo_squarred_mini)) {
294
                $favicon = constant('BASE_URL') . '/viewimage.php?cache=1&modulepart=mycompany&file=' . urlencode('logos/thumbs/' . $mysoc->logo_squarred_mini);
295
            }
296
            if (getDolGlobalString('MAIN_FAVICON_URL')) {
297
                $favicon = getDolGlobalString('MAIN_FAVICON_URL');
298
            }
299
            if (empty($conf->dol_use_jmobile)) {
300
                print '<link rel="shortcut icon" type="image/x-icon" href="' . $favicon . '"/>' . "\n"; // Not required into an Android webview
301
            }
302
303
            // Mobile appli like icon
304
            $manifest = constant('DOL_URL_ROOT') . '/theme/' . $conf->theme . '/manifest.json.php';
305
            $parameters = array('manifest' => $manifest);
306
            $resHook = $hookmanager->executeHooks('hookSetManifest', $parameters); // Note that $action and $object may have been modified by some hooks
307
            if ($resHook > 0) {
308
                $manifest = $hookmanager->resPrint; // Replace manifest.json
309
            } else {
310
                $manifest .= $hookmanager->resPrint; // Concat to actual manifest declaration
311
            }
312
            if (!empty($manifest)) {
313
                print '<link rel="manifest" href="' . $manifest . '" />' . "\n";
314
            }
315
316
            if (getDolGlobalString('THEME_ELDY_TOPMENU_BACK1')) {
317
                // TODO: use auto theme color switch
318
                print '<meta name="theme-color" content="rgb(' . getDolGlobalString('THEME_ELDY_TOPMENU_BACK1') . ')">' . "\n";
319
            }
320
321
            // Auto refresh page
322
            if (GETPOSTINT('autorefresh') > 0) {
323
                print '<meta http-equiv="refresh" content="' . GETPOSTINT('autorefresh') . '">';
324
            }
325
326
            // Displays title
327
            $appli = constant('DOL_APPLICATION_TITLE');
328
            if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
329
                $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
330
            }
331
332
            print '<title>';
333
            $titletoshow = '';
334
            if ($title && preg_match('/showapp/', getDolGlobalString('MAIN_HTML_TITLE'))) {
335
                $titletoshow = dol_htmlentities($appli . ' - ' . $title);
336
            } elseif ($title) {
337
                $titletoshow = dol_htmlentities($title);
338
            } else {
339
                $titletoshow = dol_htmlentities($appli);
340
            }
341
342
            $parameters = array('title' => $titletoshow);
343
            $result = $hookmanager->executeHooks('setHtmlTitle', $parameters); // Note that $action and $object may have been modified by some hooks
344
            if ($result > 0) {
345
                $titletoshow = $hookmanager->resPrint; // Replace Title to show
346
            } else {
347
                $titletoshow .= $hookmanager->resPrint; // Concat to Title to show
348
            }
349
350
            print $titletoshow;
351
            print '</title>';
352
353
            print "\n";
354
355
            if (GETPOSTINT('version')) {
356
                $ext = 'version=' . GETPOSTINT('version'); // useful to force no cache on css/js
357
            }
358
            // Refresh value of MAIN_IHM_PARAMS_REV before forging the parameter line.
359
            if (GETPOST('dol_resetcache')) {
360
                dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
361
            }
362
363
            $themeparam = '?lang=' . $langs->defaultlang . '&amp;theme=' . $conf->theme . (GETPOST('optioncss', 'aZ09') ? '&amp;optioncss=' . GETPOST('optioncss', 'aZ09', 1) : '') . (empty($user->id) ? '' : ('&amp;userid=' . $user->id)) . '&amp;entity=' . $conf->entity;
364
365
            $themeparam .= ($ext ? '&amp;' . $ext : '') . '&amp;revision=' . getDolGlobalInt("MAIN_IHM_PARAMS_REV");
366
            if (GETPOSTISSET('dol_hide_topmenu')) {
367
                $themeparam .= '&amp;dol_hide_topmenu=' . GETPOSTINT('dol_hide_topmenu');
368
            }
369
            if (GETPOSTISSET('dol_hide_leftmenu')) {
370
                $themeparam .= '&amp;dol_hide_leftmenu=' . GETPOSTINT('dol_hide_leftmenu');
371
            }
372
            if (GETPOSTISSET('dol_optimize_smallscreen')) {
373
                $themeparam .= '&amp;dol_optimize_smallscreen=' . GETPOSTINT('dol_optimize_smallscreen');
374
            }
375
            if (GETPOSTISSET('dol_no_mouse_hover')) {
376
                $themeparam .= '&amp;dol_no_mouse_hover=' . GETPOSTINT('dol_no_mouse_hover');
377
            }
378
            if (GETPOSTISSET('dol_use_jmobile')) {
379
                $themeparam .= '&amp;dol_use_jmobile=' . GETPOSTINT('dol_use_jmobile');
380
                $conf->dol_use_jmobile = GETPOSTINT('dol_use_jmobile');
381
            }
382
            if (GETPOSTISSET('THEME_DARKMODEENABLED')) {
383
                $themeparam .= '&amp;THEME_DARKMODEENABLED=' . GETPOSTINT('THEME_DARKMODEENABLED');
384
            }
385
            if (GETPOSTISSET('THEME_SATURATE_RATIO')) {
386
                $themeparam .= '&amp;THEME_SATURATE_RATIO=' . GETPOSTINT('THEME_SATURATE_RATIO');
387
            }
388
389
            if (getDolGlobalString('MAIN_ENABLE_FONT_ROBOTO')) {
390
                print '<link rel="preconnect" href="https://fonts.gstatic.com">' . "\n";
391
                print '<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@200;300;400;500;600&display=swap" rel="stylesheet">' . "\n";
392
            }
393
394
            if (!defined('DISABLE_JQUERY') && !$disablejs && $conf->use_javascript_ajax) {
395
                print '<!-- Includes CSS for JQuery (Ajax library) -->' . "\n";
396
                $jquerytheme = 'base';
397
                if (getDolGlobalString('MAIN_USE_JQUERY_THEME')) {
398
                    $jquerytheme = getDolGlobalString('MAIN_USE_JQUERY_THEME');
399
                }
400
                if (constant('JS_JQUERY_UI')) {
401
                    print '<link rel="stylesheet" type="text/css" href="' . JS_JQUERY_UI . 'css/' . $jquerytheme . '/jquery-ui.min.css' . ($ext ? '?' . $ext : '') . '">' . "\n"; // Forced JQuery
402
                } else {
403
                    print '<link rel="stylesheet" type="text/css" href="' . constant('DOL_URL_ROOT') . '/includes/jquery/css/' . $jquerytheme . '/jquery-ui.css' . ($ext ? '?' . $ext : '') . '">' . "\n"; // JQuery
404
                }
405
                if (!defined('DISABLE_JQUERY_JNOTIFY')) {
406
                    print '<link rel="stylesheet" type="text/css" href="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/jnotify/jquery.jnotify-alt.min.css' . ($ext ? '?' . $ext : '') . '">' . "\n"; // JNotify
407
                }
408
                if (!defined('DISABLE_SELECT2') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {     // jQuery plugin "mutiselect", "multiple-select", "select2"...
409
                    $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
410
                    print '<link rel="stylesheet" type="text/css" href="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/' . $tmpplugin . '/dist/css/' . $tmpplugin . '.css' . ($ext ? '?' . $ext : '') . '">' . "\n";
411
                }
412
            }
413
414
            if (!defined('DISABLE_FONT_AWSOME')) {
415
                print '<!-- Includes CSS for font awesome -->' . "\n";
416
                $fontawesome_directory = getDolGlobalString('MAIN_FONTAWESOME_DIRECTORY', '/theme/common/fontawesome-5');
417
                print '<link rel="stylesheet" type="text/css" href="' . constant('DOL_URL_ROOT') . $fontawesome_directory . '/css/all.min.css' . ($ext ? '?' . $ext : '') . '">' . "\n";
418
            }
419
420
            print '<!-- Includes CSS for Dolibarr theme -->' . "\n";
421
            // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
422
            $themepath = dol_buildpath($conf->css, 1);
423
            $themesubdir = '';
424
            if (!empty($conf->modules_parts['theme'])) {    // This slow down
425
                foreach ($conf->modules_parts['theme'] as $reldir) {
426
                    if (file_exists(dol_buildpath($reldir . $conf->css, 0))) {
427
                        $themepath = dol_buildpath($reldir . $conf->css, 1);
428
                        $themesubdir = $reldir;
429
                        break;
430
                    }
431
                }
432
            }
433
434
            //print 'themepath='.$themepath.' themeparam='.$themeparam;exit;
435
            print '<link rel="stylesheet" type="text/css" href="' . $themepath . $themeparam . '">' . "\n";
436
            if (getDolGlobalString('MAIN_FIX_FLASH_ON_CHROME')) {
437
                print '<!-- Includes CSS that does not exists as a workaround of flash bug of chrome -->' . "\n" . '<link rel="stylesheet" type="text/css" href="filethatdoesnotexiststosolvechromeflashbug">' . "\n";
438
            }
439
440
            // LEAFLET AND GEOMAN
441
            if (getDolGlobalString('MAIN_USE_GEOPHP')) {
442
                print '<link rel="stylesheet" href="' . constant('BASE_URL') . '/includes/leaflet/leaflet.css' . ($ext ? '?' . $ext : '') . "\">\n";
443
                print '<link rel="stylesheet" href="' . constant('BASE_URL') . '/includes/leaflet/leaflet-geoman.css' . ($ext ? '?' . $ext : '') . "\">\n";
444
            }
445
446
            // CSS forced by modules (relative url starting with /)
447
            if (!empty($conf->modules_parts['css'])) {
448
                $arraycss = (array)$conf->modules_parts['css'];
449
                foreach ($arraycss as $modcss => $filescss) {
450
                    $filescss = (array)$filescss; // To be sure filecss is an array
451
                    foreach ($filescss as $cssfile) {
452
                        if (empty($cssfile)) {
453
                            dol_syslog("Warning: module " . $modcss . " declared a css path file into its descriptor that is empty.", LOG_WARNING);
454
                        }
455
                        // cssfile is a relative path
456
                        $urlforcss = dol_buildpath($cssfile, 1);
457
                        if ($urlforcss && $urlforcss != '/') {
458
                            print '<!-- Includes CSS added by module ' . $modcss . ' -->' . "\n" . '<link rel="stylesheet" type="text/css" href="' . $urlforcss;
459
                            // We add params only if page is not static, because some web server setup does not return content type text/css if url has parameters, so browser cache is not used.
460
                            if (!preg_match('/\.css$/i', $cssfile)) {
461
                                print $themeparam;
462
                            }
463
                            print '">' . "\n";
464
                        } else {
465
                            dol_syslog("Warning: module " . $modcss . " declared a css path file for a file we can't find.", LOG_WARNING);
466
                        }
467
                    }
468
                }
469
            }
470
            // CSS forced by page in static::topHtmlHead( call (relative url starting with /)
471
            if (is_array($arrayofcss)) {
472
                foreach ($arrayofcss as $cssfile) {
473
                    // $cssfile = '/htdocs' . $cssfile;
474
                    if (preg_match('/^(http|\/\/)/i', $cssfile)) {
475
                        $urltofile = $cssfile;
476
                    } else {
477
                        $urltofile = dol_buildpath($cssfile, 1);
478
                    }
479
                    print '<!-- Includes CSS added by page -->' . "\n" . '<link rel="stylesheet" type="text/css" title="default" href="' . $urltofile;
480
                    // We add params only if page is not static, because some web server setup does not return content type text/css if url has parameters and browser cache is not used.
481
                    if (!preg_match('/\.css$/i', $cssfile)) {
482
                        print $themeparam;
483
                    }
484
                    print '">' . "\n";
485
                }
486
            }
487
488
            // Custom CSS
489
            if (getDolGlobalString('MAIN_IHM_CUSTOM_CSS')) {
490
                // If a custom CSS was set, we add link to the custom css php file
491
                print '<link rel="stylesheet" type="text/css" href="' . constant('DOL_URL_ROOT') . '/theme/custom.css.php' . ($ext ? '?' . $ext : '') . '&amp;revision=' . getDolGlobalInt("MAIN_IHM_PARAMS_REV") . '">' . "\n";
492
            }
493
494
            // Output standard javascript links
495
            if (!defined('DISABLE_JQUERY') && !$disablejs && !empty($conf->use_javascript_ajax)) {
496
                // JQuery. Must be before other includes
497
                print '<!-- Includes JS for JQuery -->' . "\n";
498
                if (defined('JS_JQUERY') && constant('JS_JQUERY')) {
499
                    print '<script nonce="' . getNonce() . '" src="' . JS_JQUERY . 'jquery.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
500
                } else {
501
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/js/jquery.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
502
                }
503
                if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) {
504
                    print '<script nonce="' . getNonce() . '" src="' . JS_JQUERY_UI . 'jquery-ui.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
505
                } else {
506
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/js/jquery-ui.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
507
                }
508
                // jQuery jnotify
509
                if (!getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && !defined('DISABLE_JQUERY_JNOTIFY')) {
510
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/jnotify/jquery.jnotify.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
511
                }
512
                // Table drag and drop lines
513
                if (empty($disableforlogin) && !defined('DISABLE_JQUERY_TABLEDND')) {
514
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/tablednd/jquery.tablednd.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
515
                }
516
                // Chart
517
                if (empty($disableforlogin) && (!getDolGlobalString('MAIN_JS_GRAPH') || getDolGlobalString('MAIN_JS_GRAPH') == 'chart') && !defined('DISABLE_JS_GRAPH')) {
518
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/nnnick/chartjs/dist/chart.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
519
                }
520
521
                // jQuery jeditable for Edit In Place features
522
                if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !defined('DISABLE_JQUERY_JEDITABLE')) {
523
                    print '<!-- JS to manage editInPlace feature -->' . "\n";
524
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/jeditable/jquery.jeditable.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
525
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
526
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
527
                    print '<script>' . "\n";
528
                    print 'var urlSaveInPlace = \'' . constant('DOL_URL_ROOT') . '/core/ajax/saveinplace.php\';' . "\n";
529
                    print 'var urlLoadInPlace = \'' . constant('DOL_URL_ROOT') . '/core/ajax/loadinplace.php\';' . "\n";
530
                    print 'var tooltipInPlace = \'' . $langs->transnoentities('ClickToEdit') . '\';' . "\n"; // Added in title attribute of span
531
                    print 'var placeholderInPlace = \'&nbsp;\';' . "\n"; // If we put another string than $langs->trans("ClickToEdit") here, nothing is shown. If we put empty string, there is error, Why ?
532
                    print 'var cancelInPlace = \'' . $langs->trans("Cancel") . '\';' . "\n";
533
                    print 'var submitInPlace = \'' . $langs->trans('Ok') . '\';' . "\n";
534
                    print 'var indicatorInPlace = \'<img src="' . constant('DOL_URL_ROOT') . "/theme/" . $conf->theme . "/img/working.gif" . '">\';' . "\n";
535
                    print 'var withInPlace = 300;'; // width in pixel for default string edit
536
                    print '</script>' . "\n";
537
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/core/js/editinplace.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
538
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
539
                }
540
                // jQuery Timepicker
541
                if (getDolGlobalString('MAIN_USE_JQUERY_TIMEPICKER') || defined('REQUIRE_JQUERY_TIMEPICKER')) {
542
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
543
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/core/js/timepicker.js.php?lang=' . $langs->defaultlang . ($ext ? '&amp;' . $ext : '') . '"></script>' . "\n";
544
                }
545
                if (!defined('DISABLE_SELECT2') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
546
                    // jQuery plugin "mutiselect", "multiple-select", "select2", ...
547
                    $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
548
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/' . $tmpplugin . '/dist/js/' . $tmpplugin . '.full.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n"; // We include full because we need the support of containerCssClass
549
                }
550
                if (!defined('DISABLE_MULTISELECT')) {     // jQuery plugin "mutiselect" to select with checkboxes. Can be removed once we have an enhanced search tool
551
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/jquery/plugins/multiselect/jquery.multi-select.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
552
                }
553
            }
554
555
            if (!$disablejs && !empty($conf->use_javascript_ajax)) {
556
                // CKEditor
557
                if (empty($disableforlogin) && (isModEnabled('fckeditor') && (!getDolGlobalString('FCKEDITOR_EDITORNAME') || getDolGlobalString('FCKEDITOR_EDITORNAME') == 'ckeditor') && !defined('DISABLE_CKEDITOR')) || defined('FORCE_CKEDITOR')) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (empty($disableforlogin)...fined('FORCE_CKEDITOR'), Probably Intended Meaning: empty($disableforlogin) ...ined('FORCE_CKEDITOR'))
Loading history...
558
                    print '<!-- Includes JS for CKEditor -->' . "\n";
559
                    $pathckeditor = constant('DOL_URL_ROOT') . '/includes/ckeditor/ckeditor/';
560
                    $jsckeditor = 'ckeditor.js';
561
                    if (constant('JS_CKEDITOR')) {
562
                        // To use external ckeditor 4 js lib
563
                        $pathckeditor = constant('JS_CKEDITOR');
564
                    }
565
                    print '<script nonce="' . getNonce() . '">';
566
                    print '/* enable ckeditor by main.inc.php */';
567
                    print 'var CKEDITOR_BASEPATH = \'' . dol_escape_js($pathckeditor) . '\';' . "\n";
568
                    print 'var ckeditorConfig = \'' . dol_escape_js(dol_buildpath('/htdocs' . $themesubdir . '/theme/' . $conf->theme . '/ckeditor/config.js' . ($ext ? '?' . $ext : ''), 1)) . '\';' . "\n"; // $themesubdir='' in standard usage
569
                    print 'var ckeditorFilebrowserBrowseUrl = \'' . constant('DOL_URL_ROOT') . '/core/filemanagerdol/browser/default/browser.php?Connector=' . constant('BASE_URL') . '/core/filemanagerdol/connectors/php/connector.php\';' . "\n";
570
                    print 'var ckeditorFilebrowserImageBrowseUrl = \'' . constant('DOL_URL_ROOT') . '/core/filemanagerdol/browser/default/browser.php?Type=Image&Connector=' . constant('BASE_URL') . '/core/filemanagerdol/connectors/php/connector.php\';' . "\n";
571
                    print '</script>' . "\n";
572
                    print '<script src="' . $pathckeditor . $jsckeditor . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
573
                    print '<script>';
574
                    if (GETPOST('mode', 'aZ09') == 'Full_inline') {
575
                        print 'CKEDITOR.disableAutoInline = false;' . "\n";
576
                    } else {
577
                        print 'CKEDITOR.disableAutoInline = true;' . "\n";
578
                    }
579
                    print '</script>' . "\n";
580
                }
581
582
                // Browser notifications (if NOREQUIREMENU is on, it is mostly a page for popup, so we do not enable notif too. We hide also for public pages).
583
                if (!defined('NOBROWSERNOTIF') && !defined('NOREQUIREMENU') && !defined('NOLOGIN')) {
584
                    $enablebrowsernotif = false;
585
                    if (isModEnabled('agenda') && getDolGlobalString('AGENDA_REMINDER_BROWSER')) {
586
                        $enablebrowsernotif = true;
587
                    }
588
                    if ($conf->browser->layout == 'phone') {
589
                        $enablebrowsernotif = false;
590
                    }
591
                    if ($enablebrowsernotif) {
592
                        print '<!-- Includes JS of Dolibarr (browser layout = ' . $conf->browser->layout . ')-->' . "\n";
593
                        print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/core/js/lib_notification.js.php' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
594
                    }
595
                }
596
597
                // Global js function
598
                print '<!-- Includes JS of Dolibarr -->' . "\n";
599
                print '<script nonce="' . getNonce() . '" src="' . BASE_URL . '/core/js/lib_head.js.php?lang=' . $langs->defaultlang . ($ext ? '&amp;' . $ext : '') . '"></script>' . "\n";
600
601
                // Leaflet TODO use dolibarr files
602
                if (getDolGlobalString('MAIN_USE_GEOPHP')) {
603
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/leaflet/leaflet.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
604
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/includes/leaflet/leaflet-geoman.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
605
                }
606
607
                // JS forced by modules (relative url starting with /)
608
                if (!empty($conf->modules_parts['js'])) {       // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
609
                    $arrayjs = (array)$conf->modules_parts['js'];
610
                    foreach ($arrayjs as $modjs => $filesjs) {
611
                        $filesjs = (array)$filesjs; // To be sure filejs is an array
612
                        foreach ($filesjs as $jsfile) {
613
                            // jsfile is a relative path
614
                            $urlforjs = dol_buildpath($jsfile, 3);
615
                            if ($urlforjs && $urlforjs != '/') {
616
                                print '<!-- Include JS added by module ' . $modjs . '-->' . "\n";
617
                                print '<script nonce="' . getNonce() . '" src="' . $urlforjs . ((strpos($jsfile, '?') === false) ? '?' : '&amp;') . 'lang=' . $langs->defaultlang . '"></script>' . "\n";
618
                            } else {
619
                                dol_syslog("Warning: module " . $modjs . " declared a js path file for a file we can't find.", LOG_WARNING);
620
                            }
621
                        }
622
                    }
623
                }
624
                // JS forced by page in static::topHtmlHead( (relative url starting with /)
625
                if (is_array($arrayofjs)) {
626
                    print '<!-- Includes JS added by page -->' . "\n";
627
                    foreach ($arrayofjs as $jsfile) {
628
                        // $jsfile = '/htdocs' . $jsfile;
629
                        if (preg_match('/^(http|\/\/)/i', $jsfile)) {
630
                            print '<script nonce="' . getNonce() . '" src="' . $jsfile . ((strpos($jsfile, '?') === false) ? '?' : '&amp;') . 'lang=' . $langs->defaultlang . '"></script>' . "\n";
631
                        } else {
632
                            print '<script nonce="' . getNonce() . '" src="' . dol_buildpath($jsfile, 3) . ((strpos($jsfile, '?') === false) ? '?' : '&amp;') . 'lang=' . $langs->defaultlang . '"></script>' . "\n";
633
                        }
634
                    }
635
                }
636
            }
637
638
            //If you want to load custom javascript file from your selected theme directory
639
            if (getDolGlobalString('ALLOW_THEME_JS')) {
640
                $theme_js = dol_buildpath('/theme/' . $conf->theme . '/' . $conf->theme . '.js', 0);
641
                if (file_exists($theme_js)) {
642
                    print '<script nonce="' . getNonce() . '" src="' . constant('DOL_URL_ROOT') . '/theme/' . $conf->theme . '/' . $conf->theme . '.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
643
                }
644
            }
645
646
            if (!empty($head)) {
647
                print $head . "\n";
648
            }
649
            if (getDolGlobalString('MAIN_HTML_HEADER')) {
650
                print getDolGlobalString('MAIN_HTML_HEADER') . "\n";
651
            }
652
653
            $parameters = array();
654
            $result = $hookmanager->executeHooks('addHtmlHeader', $parameters); // Note that $action and $object may have been modified by some hooks
655
            print $hookmanager->resPrint; // Replace Title to show
656
657
            print "</head>\n\n";
658
        }
659
660
        $conf->headerdone = 1; // To tell header was output
661
    }
662
663
664
    /**
665
     *  Show an HTML header + a BODY + The top menu bar
666
     *
667
     * @param string $head Lines in the HEAD
668
     * @param string $title Title of web page
669
     * @param string $target Target to use in menu links (Example: '' or '_top')
670
     * @param int<0,1> $disablejs Do not output links to js (Ex: qd fonction utilisee par sous formulaire Ajax)
671
     * @param int<0,1> $disablehead Do not output head section
672
     * @param string[] $arrayofjs Array of js files to add in header
673
     * @param string[] $arrayofcss Array of css files to add in header
674
     * @param string $morequerystring Query string to add to the link "print" to get same parameters (use only if autodetect fails)
675
     * @param string $helppagename Name of wiki page for help ('' by default).
676
     *                                                  Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage|DE:GermanPage
677
     *                                                  For other external page: http://server/url
678
     * @return     void
679
     */
680
    public static function topMenu($head, $title = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = array(), $arrayofcss = array(), $morequerystring = '', $helppagename = '')
681
    {
682
        global $user, $conf, $langs, $db, $form;
683
        global $dolibarr_main_authentication, $dolibarr_main_demo;
684
        global $hookmanager, $menumanager;
685
686
        $searchform = '';
687
688
        // Instantiate hooks for external modules
689
        $hookmanager->initHooks(array('toprightmenu'));
690
691
        $toprightmenu = '';
692
693
        // For backward compatibility with old modules
694
        if (empty($conf->headerdone)) {
695
            $disablenofollow = 0;
696
            static::topHtmlHead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow);
697
            print '<body id="mainbody">';
698
        }
699
700
        /*
701
         * Top menu
702
         */
703
        if ((empty($conf->dol_hide_topmenu) || GETPOSTINT('dol_invisible_topmenu')) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
704
            if (!isset($form) || !is_object($form)) {
705
                $form = new Form($db);
706
            }
707
708
            print "\n" . '<!-- Start top horizontal -->' . "\n";
709
710
            print '<header id="id-top" class="side-nav-vert' . (GETPOSTINT('dol_invisible_topmenu') ? ' hidden' : '') . '">'; // dol_invisible_topmenu differs from dol_hide_topmenu: dol_invisible_topmenu means we output menu but we make it invisible.
711
712
            // Show menu entries
713
            print '<div id="tmenu_tooltip' . (!getDolGlobalString('MAIN_MENU_INVERT') ? '' : 'invert') . '" class="tmenu">' . "\n";
714
            $menumanager->atarget = $target;
715
            $menumanager->showmenu('top', array('searchform' => $searchform)); // This contains a \n
716
            print "</div>\n";
717
718
            // Define link to login card
719
            $appli = constant('DOL_APPLICATION_TITLE');
720
            if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
721
                $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
722
                if (preg_match('/\d\.\d/', $appli)) {
723
                    if (!preg_match('/' . preg_quote(DOL_VERSION) . '/', $appli)) {
724
                        $appli .= " (" . DOL_VERSION . ")"; // If new title contains a version that is different than core
725
                    }
726
                } else {
727
                    $appli .= " " . DOL_VERSION;
728
                }
729
            } else {
730
                $appli .= " " . DOL_VERSION;
731
            }
732
733
            if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
734
                $appli .= "<br>" . $langs->trans("LevelOfFeature") . ': ' . getDolGlobalInt('MAIN_FEATURES_LEVEL');
735
            }
736
737
            $logouttext = '';
738
            $logouthtmltext = '';
739
            if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
740
                //$logouthtmltext=$appli.'<br>';
741
                $stringforfirstkey = $langs->trans("KeyboardShortcut");
742
                if ($conf->browser->name == 'chrome') {
743
                    $stringforfirstkey .= ' ALT +';
744
                } elseif ($conf->browser->name == 'firefox') {
745
                    $stringforfirstkey .= ' ALT + SHIFT +';
746
                } else {
747
                    $stringforfirstkey .= ' CTL +';
748
                }
749
                if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http') {
750
                    $logouthtmltext .= $langs->trans("Logout") . '<br>';
751
                    $logouttext .= '<a accesskey="l" href="' . constant('BASE_URL') . '/user/logout.php?token=' . newToken() . '">';
752
                    $logouttext .= img_picto($langs->trans('Logout') . ' (' . $stringforfirstkey . ' l)', 'sign-out', '', false, 0, 0, '', 'atoplogin valignmiddle');
753
                    $logouttext .= '</a>';
754
                } else {
755
                    $logouthtmltext .= $langs->trans("NoLogoutProcessWithAuthMode", $_SESSION["dol_authmode"]);
756
                    $logouttext .= img_picto($langs->trans('Logout') . ' (' . $stringforfirstkey . ' l)', 'sign-out', '', false, 0, 0, '', 'atoplogin valignmiddle opacitymedium');
757
                }
758
            }
759
760
            print '<div class="login_block usedropdown">' . "\n";
761
762
            $toprightmenu .= '<div class="login_block_other">';
763
764
            // Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
765
            $parameters = array();
766
            $result = $hookmanager->executeHooks('printTopRightMenu', $parameters); // Note that $action and $object may have been modified by some hooks
767
            if (is_numeric($result)) {
768
                if ($result == 0) {
769
                    $toprightmenu .= $hookmanager->resPrint; // add
770
                } else {
771
                    $toprightmenu = $hookmanager->resPrint; // replace
772
                }
773
            } else {
774
                $toprightmenu .= $result; // For backward compatibility
775
            }
776
777
            // Link to module builder
778
            if (isModEnabled('modulebuilder')) {
779
                $text = '<a href="' . constant('BASE_URL') . '/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="modulebuilder">';
780
                //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
781
                $text .= '<span class="fa fa-bug atoplogin valignmiddle"></span>';
782
                $text .= '</a>';
783
                // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
784
                $toprightmenu .= $form->textwithtooltip('', $langs->trans("ModuleBuilder"), 2, 1, $text, 'login_block_elem', 2);
785
            }
786
787
            // Link to print main content area (optioncss=print)
788
            if (!getDolGlobalString('MAIN_PRINT_DISABLELINK') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
789
                $qs = dol_escape_htmltag($_SERVER["QUERY_STRING"]);
790
791
                if (isset($_POST) && is_array($_POST)) {
792
                    foreach ($_POST as $key => $value) {
793
                        $key = preg_replace('/[^a-z0-9_\.\-\[\]]/i', '', $key);
794
                        if (in_array($key, array('action', 'massaction', 'password'))) {
795
                            continue;
796
                        }
797
                        if (!is_array($value)) {
798
                            if ($value !== '') {
799
                                $qs .= '&' . urlencode($key) . '=' . urlencode($value);
800
                            }
801
                        } else {
802
                            foreach ($value as $value2) {
803
                                if (($value2 !== '') && (!is_array($value2))) {
804
                                    $qs .= '&' . urlencode($key) . '[]=' . urlencode($value2);
805
                                }
806
                            }
807
                        }
808
                    }
809
                }
810
                $qs .= (($qs && $morequerystring) ? '&' : '') . $morequerystring;
811
                $text = '<a href="' . dol_escape_htmltag($_SERVER["PHP_SELF"]) . '?' . $qs . ($qs ? '&' : '') . 'optioncss=print" target="_blank" rel="noopener noreferrer">';
812
                //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
813
                $text .= '<span class="fa fa-print atoplogin valignmiddle"></span>';
814
                $text .= '</a>';
815
                // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
816
                $toprightmenu .= $form->textwithtooltip('', $langs->trans("PrintContentArea"), 2, 1, $text, 'login_block_elem', 2);
817
            }
818
819
            // Link to Dolibarr wiki pages
820
            if (!getDolGlobalString('MAIN_HELP_DISABLELINK') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
821
                $langs->load("help");
822
823
                $helpbaseurl = '';
824
                $helppage = '';
825
                $mode = '';
826
                $helppresent = '';
827
828
                if (empty($helppagename)) {
829
                    $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios|DE:Benutzerdokumentation';
830
                } else {
831
                    $helppresent = 'helppresent';
832
                }
833
834
                // Get helpbaseurl, helppage and mode from helppagename and langs
835
                $arrayres = static::getHelpParamFor($helppagename, $langs);
836
                $helpbaseurl = $arrayres['helpbaseurl'];
837
                $helppage = $arrayres['helppage'];
838
                $mode = $arrayres['mode'];
839
840
                // Link to help pages
841
                if ($helpbaseurl && $helppage) {
842
                    $text = '';
843
                    $title = $langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage' : 'GoToHelpPage') . ', ';
844
                    if ($mode == 'wiki') {
845
                        $title .= '<br>' . img_picto('', 'globe', 'class="pictofixedwidth"') . $langs->trans("PageWiki") . ' ' . dol_escape_htmltag('"' . strtr($helppage, '_', ' ') . '"');
846
                        if ($helppresent) {
847
                            $title .= ' <span class="opacitymedium">(' . $langs->trans("DedicatedPageAvailable") . ')</span>';
848
                        } else {
849
                            $title .= ' <span class="opacitymedium">(' . $langs->trans("HomePage") . ')</span>';
850
                        }
851
                    }
852
                    $text .= '<a class="help" target="_blank" rel="noopener noreferrer" href="';
853
                    if ($mode == 'wiki') {
854
                        // @phan-suppress-next-line PhanPluginPrintfVariableFormatString
855
                        $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage)));
856
                    } else {
857
                        // @phan-suppress-next-line PhanPluginPrintfVariableFormatString
858
                        $text .= sprintf($helpbaseurl, $helppage);
859
                    }
860
                    $text .= '">';
861
                    $text .= '<span class="fa fa-question-circle atoplogin valignmiddle' . ($helppresent ? ' ' . $helppresent : '') . '"></span>';
862
                    $text .= '<span class="fa fa-long-arrow-alt-up helppresentcircle' . ($helppresent ? '' : ' unvisible') . '"></span>';
863
                    $text .= '</a>';
864
                    // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
865
                    $toprightmenu .= $form->textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2);
866
                }
867
868
                // Version
869
                if (getDolGlobalString('MAIN_SHOWDATABASENAMEINHELPPAGESLINK')) {
870
                    $langs->load('admin');
871
                    $appli .= '<br>' . $langs->trans("Database") . ': ' . $db->database_name;
872
                }
873
            }
874
875
            if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
876
                $text = '<span class="aversion"><span class="hideonsmartphone small">' . DOL_VERSION . '</span></span>';
877
                // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
878
                $toprightmenu .= $form->textwithtooltip('', $appli, 2, 1, $text, 'login_block_elem', 2);
879
            }
880
881
            // Logout link
882
            $toprightmenu .= $form->textwithtooltip('', $logouthtmltext, 2, 1, $logouttext, 'login_block_elem logout-btn', 2);
883
884
            $toprightmenu .= '</div>'; // end div class="login_block_other"
885
886
887
            // Add login user link
888
            $toprightmenu .= '<div class="login_block_user">';
889
890
            // Login name with photo and tooltip
891
            $mode = -1;
892
            $toprightmenu .= '<div class="inline-block login_block_elem login_block_elem_name nowrap centpercent" style="padding: 0px;">';
893
894
            if (getDolGlobalString('MAIN_USE_TOP_MENU_SEARCH_DROPDOWN')) {
895
                // Add search dropdown
896
                $toprightmenu .= static::topSearchMenu();
897
            }
898
899
            if (getDolGlobalString('MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN')) {
900
                // Add search dropdown
901
                $toprightmenu .= static::topMenuQuickAdd();
902
            }
903
904
            // Add bookmark dropdown
905
            $toprightmenu .= static::topMenuBookmark();
906
907
            // Add user dropdown
908
            $toprightmenu .= static::topMenuUser();
909
910
            $toprightmenu .= '</div>';
911
912
            $toprightmenu .= '</div>' . "\n";
913
914
915
            print $toprightmenu;
916
917
            print "</div>\n"; // end div class="login_block"
918
919
            print '</header>';
920
            //print '<header class="header2">&nbsp;</header>';
921
922
            print '<div style="clear: both;"></div>';
923
            print "<!-- End top horizontal menu -->\n\n";
924
        }
925
926
        if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
927
            print '<!-- Begin div id-container --><div id="id-container" class="id-container">';
928
        }
929
    }
930
931
    /**
932
     * Build the tooltip on user login
933
     *
934
     * @param int<0,1> $hideloginname Hide login name. Show only the image.
935
     * @param string $urllogout URL for logout (Will use DOL_URL_ROOT.'/user/logout.php?token=...' if empty)
936
     * @return  string                          HTML content
937
     */
938
    public static function topMenuUser($hideloginname = 0, $urllogout = '')
939
    {
940
        global $langs, $conf, $db, $hookmanager, $user, $mysoc;
941
        global $dolibarr_main_authentication, $dolibarr_main_demo;
942
        global $menumanager;
943
944
        $langs->load('companies');
945
946
        $userImage = $userDropDownImage = '';
947
        if (!empty($user->photo)) {
948
            $userImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'photouserphoto userphoto', 'small', 0, 1);
949
            $userDropDownImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'dropdown-user-image', 'small', 0, 1);
950
        } else {
951
            $nophoto = '/public/theme/common/user_anonymous.png';
952
            if ($user->gender == 'man') {
953
                $nophoto = '/public/theme/common/user_man.png';
954
            }
955
            if ($user->gender == 'woman') {
956
                $nophoto = '/public/theme/common/user_woman.png';
957
            }
958
959
            $userImage = '<img class="photo photouserphoto userphoto" alt="" src="' . constant('DOL_URL_ROOT') . $nophoto . '">';
960
            $userDropDownImage = '<img class="photo dropdown-user-image" alt="" src="' . constant('DOL_URL_ROOT') . $nophoto . '">';
961
        }
962
963
        $dropdownBody = '';
964
        $dropdownBody .= '<span id="topmenulogincompanyinfo-btn"><i class="fa fa-caret-right"></i> ' . $langs->trans("ShowCompanyInfos") . '</span>';
965
        $dropdownBody .= '<div id="topmenulogincompanyinfo" >';
966
967
        $dropdownBody .= '<br><b>' . $langs->trans("Company") . '</b>: <span>' . dol_escape_htmltag($mysoc->name) . '</span>';
968
        if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-') {
969
            $dropdownBody .= '<br><b>' . $langs->transcountry("ProfId1", $mysoc->country_code) . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_SIREN"), 1) . '</span>';
970
        }
971
        if ($langs->transcountry("ProfId2", $mysoc->country_code) != '-') {
972
            $dropdownBody .= '<br><b>' . $langs->transcountry("ProfId2", $mysoc->country_code) . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_SIRET"), 2) . '</span>';
973
        }
974
        if ($langs->transcountry("ProfId3", $mysoc->country_code) != '-') {
975
            $dropdownBody .= '<br><b>' . $langs->transcountry("ProfId3", $mysoc->country_code) . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_APE"), 3) . '</span>';
976
        }
977
        if ($langs->transcountry("ProfId4", $mysoc->country_code) != '-') {
978
            $dropdownBody .= '<br><b>' . $langs->transcountry("ProfId4", $mysoc->country_code) . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_RCS"), 4) . '</span>';
979
        }
980
        if ($langs->transcountry("ProfId5", $mysoc->country_code) != '-') {
981
            $dropdownBody .= '<br><b>' . $langs->transcountry("ProfId5", $mysoc->country_code) . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID5"), 5) . '</span>';
982
        }
983
        if ($langs->transcountry("ProfId6", $mysoc->country_code) != '-') {
984
            $dropdownBody .= '<br><b>' . $langs->transcountry("ProfId6", $mysoc->country_code) . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID6"), 6) . '</span>';
985
        }
986
        $dropdownBody .= '<br><b>' . $langs->trans("VATIntraShort") . '</b>: <span>' . dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT') . '</span>';
987
        $dropdownBody .= '<br><b>' . $langs->trans("Country") . '</b>: <span>' . ($mysoc->country_code ? $langs->trans("Country" . $mysoc->country_code) : '') . '</span>';
988
        if (isModEnabled('multicurrency')) {
989
            $dropdownBody .= '<br><b>' . $langs->trans("Currency") . '</b>: <span>' . $conf->currency . '</span>';
990
        }
991
        $dropdownBody .= '</div>';
992
993
        $dropdownBody .= '<br>';
994
        $dropdownBody .= '<span id="topmenuloginmoreinfo-btn"><i class="fa fa-caret-right"></i> ' . $langs->trans("ShowMoreInfos") . '</span>';
995
        $dropdownBody .= '<div id="topmenuloginmoreinfo" >';
996
997
        // login infos
998
        if (!empty($user->admin)) {
999
            $dropdownBody .= '<br><b>' . $langs->trans("Administrator") . '</b>: ' . yn($user->admin);
1000
        }
1001
        if (!empty($user->socid)) { // Add thirdparty for external users
1002
            $thirdpartystatic = new Societe($db);
1003
            $thirdpartystatic->fetch($user->socid);
1004
            $companylink = ' ' . $thirdpartystatic->getNomUrl(2); // picto only of company
1005
            $company = ' (' . $langs->trans("Company") . ': ' . $thirdpartystatic->name . ')';
1006
        }
1007
        $type = ($user->socid ? $langs->trans("External") . $company : $langs->trans("Internal"));
1008
        $dropdownBody .= '<br><b>' . $langs->trans("Type") . ':</b> ' . $type;
1009
        $dropdownBody .= '<br><b>' . $langs->trans("Status") . '</b>: ' . $user->getLibStatut(0);
1010
        $dropdownBody .= '<br>';
1011
1012
        $dropdownBody .= '<br><u>' . $langs->trans("Session") . '</u>';
1013
        $dropdownBody .= '<br><b>' . $langs->trans("IPAddress") . '</b>: ' . dol_escape_htmltag($_SERVER["REMOTE_ADDR"]);
1014
        if (getDolGlobalString('MAIN_MODULE_MULTICOMPANY')) {
1015
            $dropdownBody .= '<br><b>' . $langs->trans("ConnectedOnMultiCompany") . ':</b> ' . $conf->entity . ' (user entity ' . $user->entity . ')';
1016
        }
1017
        $dropdownBody .= '<br><b>' . $langs->trans("AuthenticationMode") . ':</b> ' . $_SESSION["dol_authmode"] . (empty($dolibarr_main_demo) ? '' : ' (demo)');
1018
        $dropdownBody .= '<br><b>' . $langs->trans("ConnectedSince") . ':</b> ' . dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
1019
        $dropdownBody .= '<br><b>' . $langs->trans("PreviousConnexion") . ':</b> ' . dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
1020
        $dropdownBody .= '<br><b>' . $langs->trans("CurrentTheme") . ':</b> ' . $conf->theme;
1021
        $dropdownBody .= '<br><b>' . $langs->trans("CurrentMenuManager") . ':</b> ' . (isset($menumanager) ? $menumanager->name : 'unknown');
1022
        $langFlag = picto_from_langcode($langs->getDefaultLang());
1023
        $dropdownBody .= '<br><b>' . $langs->trans("CurrentUserLanguage") . ':</b> ' . ($langFlag ? $langFlag . ' ' : '') . $langs->getDefaultLang();
1024
1025
        $tz = (int)$_SESSION['dol_tz'] + (int)$_SESSION['dol_dst'];
1026
        $dropdownBody .= '<br><b>' . $langs->trans("ClientTZ") . ':</b> ' . ($tz ? ($tz >= 0 ? '+' : '') . $tz : '');
1027
        $dropdownBody .= ' (' . $_SESSION['dol_tz_string'] . ')';
1028
        //$dropdownBody .= ' &nbsp; &nbsp; &nbsp; '.$langs->trans("DaylingSavingTime").': ';
1029
        //if ($_SESSION['dol_dst'] > 0) $dropdownBody .= yn(1);
1030
        //else $dropdownBody .= yn(0);
1031
1032
        $dropdownBody .= '<br><b>' . $langs->trans("Browser") . ':</b> ' . $conf->browser->name . ($conf->browser->version ? ' ' . $conf->browser->version : '') . ' <small class="opacitymedium">(' . dol_escape_htmltag($_SERVER['HTTP_USER_AGENT']) . ')</small>';
1033
        $dropdownBody .= '<br><b>' . $langs->trans("Layout") . ':</b> ' . $conf->browser->layout;
1034
        $dropdownBody .= '<br><b>' . $langs->trans("Screen") . ':</b> ' . $_SESSION['dol_screenwidth'] . ' x ' . $_SESSION['dol_screenheight'];
1035
        if ($conf->browser->layout == 'phone') {
1036
            $dropdownBody .= '<br><b>' . $langs->trans("Phone") . ':</b> ' . $langs->trans("Yes");
1037
        }
1038
        if (!empty($_SESSION["disablemodules"])) {
1039
            $dropdownBody .= '<br><b>' . $langs->trans("DisabledModules") . ':</b> <br>' . implode(', ', explode(',', $_SESSION["disablemodules"]));
1040
        }
1041
        $dropdownBody .= '</div>';
1042
1043
        // Execute hook
1044
        $parameters = array('user' => $user, 'langs' => $langs);
1045
        $result = $hookmanager->executeHooks('printTopRightMenuLoginDropdownBody', $parameters); // Note that $action and $object may have been modified by some hooks
1046
        if (is_numeric($result)) {
1047
            if ($result == 0) {
1048
                $dropdownBody .= $hookmanager->resPrint; // add
1049
            } else {
1050
                $dropdownBody = $hookmanager->resPrint; // replace
1051
            }
1052
        }
1053
1054
        if (empty($urllogout)) {
1055
            $urllogout = BASE_URL . '/user/logout.php?token=' . newToken();
1056
        }
1057
1058
        // accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
1059
        // accesskey is for Mac:               CTRL + key for all browsers
1060
        $stringforfirstkey = $langs->trans("KeyboardShortcut");
1061
        if ($conf->browser->name == 'chrome') {
1062
            $stringforfirstkey .= ' ALT +';
1063
        } elseif ($conf->browser->name == 'firefox') {
1064
            $stringforfirstkey .= ' ALT + SHIFT +';
1065
        } else {
1066
            $stringforfirstkey .= ' CTL +';
1067
        }
1068
1069
        // Defined the links for bottom of card
1070
        $profilLink = '<a accesskey="u" href="' . BASE_URL . '/user/card.php?id=' . $user->id . '" class="button-top-menu-dropdown" title="' . dol_escape_htmltag($langs->trans("YourUserFile") . ' (' . $stringforfirstkey . ' u)') . '"><i class="fa fa-user"></i>  ' . $langs->trans("Card") . '</a>';
1071
        $urltovirtualcard = '/user/virtualcard.php?id=' . ((int)$user->id);
1072
        $virtuelcardLink = dolButtonToOpenUrlInDialogPopup('publicvirtualcardmenu', $langs->transnoentitiesnoconv("PublicVirtualCardUrl") . (is_object($user) ? ' - ' . $user->getFullName($langs) : '') . ' (' . $stringforfirstkey . ' v)', img_picto($langs->trans("PublicVirtualCardUrl") . ' (' . $stringforfirstkey . ' v)', 'card', ''), $urltovirtualcard, '', 'button-top-menu-dropdown marginleftonly nohover', "closeTopMenuLoginDropdown()", '', 'v');
1073
        $logoutLink = '<a accesskey="l" href="' . $urllogout . '" class="button-top-menu-dropdown" title="' . dol_escape_htmltag($langs->trans("Logout") . ' (' . $stringforfirstkey . ' l)') . '"><i class="fa fa-sign-out-alt padingright"></i><span class="hideonsmartphone">' . $langs->trans("Logout") . '</span></a>';
1074
1075
        $profilName = $user->getFullName($langs) . ' (' . $user->login . ')';
1076
        if (!empty($user->admin)) {
1077
            $profilName = '<i class="far fa-star classfortooltip" title="' . $langs->trans("Administrator") . '" ></i> ' . $profilName;
1078
        }
1079
1080
        // Define version to show
1081
        $appli = constant('DOL_APPLICATION_TITLE');
1082
        if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
1083
            $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
1084
            if (preg_match('/\d\.\d/', $appli)) {
1085
                if (!preg_match('/' . preg_quote(DOL_VERSION) . '/', $appli)) {
1086
                    $appli .= " (" . DOL_VERSION . ")"; // If new title contains a version that is different than core
1087
                }
1088
            } else {
1089
                $appli .= " " . DOL_VERSION;
1090
            }
1091
        } else {
1092
            $appli .= " " . DOL_VERSION;
1093
        }
1094
1095
        if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1096
            $btnUser = '<!-- div for user link -->
1097
	    <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
1098
	        <a href="' . constant('BASE_URL') . '/user/card.php?id=' . $user->id . '" class="dropdown-toggle login-dropdown-a valignmiddle" data-toggle="dropdown">
1099
	            ' . $userImage . (empty($user->photo) ? '<!-- no photo so show also the login --><span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone paddingleft valignmiddle small">' . dol_trunc($user->firstname ? $user->firstname : $user->login, 10) . '</span>' : '') . '
1100
	        </a>
1101
	        <div class="dropdown-menu">
1102
	            <!-- User image -->
1103
	            <div class="user-header">
1104
	                ' . $userDropDownImage . '
1105
	                <p>
1106
	                    ' . $profilName . '<br>';
1107
            if ($user->datelastlogin) {
1108
                $title = $langs->trans("ConnectedSince") . ' : ' . dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
1109
                if ($user->datepreviouslogin) {
1110
                    $title .= '<br>' . $langs->trans("PreviousConnexion") . ' : ' . dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
1111
                }
1112
            }
1113
            $btnUser .= '<small class="classfortooltip" title="' . dol_escape_htmltag($title) . '" ><i class="fa fa-user-clock"></i> ' . dol_print_date($user->datelastlogin, "dayhour", 'tzuser') . '</small><br>';
1114
            if ($user->datepreviouslogin) {
1115
                $btnUser .= '<small class="classfortooltip" title="' . dol_escape_htmltag($title) . '" ><i class="fa fa-user-clock opacitymedium"></i> ' . dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser') . '</small><br>';
1116
            }
1117
1118
            //$btnUser .= '<small class="classfortooltip"><i class="fa fa-cog"></i> '.$langs->trans("Version").' '.$appli.'</small>';
1119
            $btnUser .= '
1120
	                </p>
1121
	            </div>
1122
1123
	            <!-- Menu Body user-->
1124
	            <div class="user-body">' . $dropdownBody . '</div>
1125
1126
	            <!-- Menu Footer-->
1127
	            <div class="user-footer">
1128
	                <div class="pull-left">
1129
	                    ' . $profilLink . '
1130
	                </div>
1131
	                <div class="pull-left">
1132
	                    ' . $virtuelcardLink . '
1133
	                </div>
1134
	                <div class="pull-right">
1135
	                    ' . $logoutLink . '
1136
	                </div>
1137
	                <div class="clearboth"></div>
1138
	            </div>
1139
1140
	        </div>
1141
	    </div>';
1142
        } else {
1143
            $btnUser = '<!-- div for user link text browser -->
1144
	    <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
1145
	    	<a href="' . constant('BASE_URL') . '/user/card.php?id=' . $user->id . '" class="valignmiddle" alt="' . $langs->trans("MyUserCard") . '">
1146
	    	' . $userImage . (empty($user->photo) ? '<span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone paddingleft small">' . dol_trunc($user->firstname ? $user->firstname : $user->login, 10) . '</span>' : '') . '
1147
	    	</a>
1148
		</div>';
1149
        }
1150
1151
        if (!defined('JS_JQUERY_DISABLE_DROPDOWN') && !empty($conf->use_javascript_ajax)) {    // This may be set by some pages that use different jquery version to avoid errors
1152
            $btnUser .= '
1153
        <!-- Code to show/hide the user drop-down -->
1154
        <script>
1155
		function closeTopMenuLoginDropdown() {
1156
			//console.log("close login dropdown");	// This is call at each click on page, so we disable the log
1157
			// Hide the menus.
1158
            jQuery("#topmenu-login-dropdown").removeClass("open");
1159
		}
1160
        jQuery(document).ready(function() {
1161
            jQuery(document).on("click", function(event) {
1162
				// console.log("Click somewhere on screen");
1163
                if (!$(event.target).closest("#topmenu-login-dropdown").length) {
1164
					closeTopMenuLoginDropdown();
1165
                }
1166
            });
1167
		';
1168
1169
1170
            //if ($conf->theme != 'md') {
1171
            $btnUser .= '
1172
	            jQuery("#topmenu-login-dropdown .dropdown-toggle").on("click", function(event) {
1173
					console.log("Click on #topmenu-login-dropdown .dropdown-toggle");
1174
					event.preventDefault();
1175
	                jQuery("#topmenu-login-dropdown").toggleClass("open");
1176
	            });
1177
1178
	            jQuery("#topmenulogincompanyinfo-btn").on("click", function() {
1179
					console.log("Click on #topmenulogincompanyinfo-btn");
1180
	                jQuery("#topmenulogincompanyinfo").slideToggle();
1181
	            });
1182
1183
	            jQuery("#topmenuloginmoreinfo-btn").on("click", function() {
1184
					console.log("Click on #topmenuloginmoreinfo-btn");
1185
	                jQuery("#topmenuloginmoreinfo").slideToggle();
1186
	            });';
1187
            //}
1188
1189
            $btnUser .= '
1190
        });
1191
        </script>
1192
        ';
1193
        }
1194
1195
        return $btnUser;
1196
    }
1197
1198
    /**
1199
     * Build the tooltip on top menu quick add
1200
     *
1201
     * @return  string                  HTML content
1202
     */
1203
    public static function topMenuQuickAdd()
1204
    {
1205
        global $conf, $langs;
1206
1207
        // Button disabled on text browser
1208
        if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1209
            return '';
1210
        }
1211
1212
        $html = '';
1213
1214
        // accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
1215
        // accesskey is for Mac:               CTRL + key for all browsers
1216
        $stringforfirstkey = $langs->trans("KeyboardShortcut");
1217
        if ($conf->browser->os === 'macintosh') {
1218
            $stringforfirstkey .= ' CTL +';
1219
        } else {
1220
            if ($conf->browser->name == 'chrome') {
1221
                $stringforfirstkey .= ' ALT +';
1222
            } elseif ($conf->browser->name == 'firefox') {
1223
                $stringforfirstkey .= ' ALT + SHIFT +';
1224
            } else {
1225
                $stringforfirstkey .= ' CTL +';
1226
            }
1227
        }
1228
1229
        if (!empty($conf->use_javascript_ajax)) {
1230
            $html .= '<!-- div for quick add link -->
1231
    <div id="topmenu-quickadd-dropdown" class="atoplogin dropdown inline-block">
1232
        <a accesskey="a" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="' . $langs->trans('QuickAdd') . ' (' . $stringforfirstkey . ' a)"><i class="fa fa-plus-circle"></i></a>
1233
        <div class="dropdown-menu">' . static::printDropdownQuickadd() . '</div>
1234
    </div>';
1235
            if (!defined('JS_JQUERY_DISABLE_DROPDOWN')) {    // This may be set by some pages that use different jquery version to avoid errors
1236
                $html .= '
1237
        <!-- Code to show/hide the user drop-down for the quick add -->
1238
        <script>
1239
        jQuery(document).ready(function() {
1240
            jQuery(document).on("click", function(event) {
1241
                if (!$(event.target).closest("#topmenu-quickadd-dropdown").length) {
1242
                    // Hide the menus.
1243
                    $("#topmenu-quickadd-dropdown").removeClass("open");
1244
                }
1245
            });
1246
            $("#topmenu-quickadd-dropdown .dropdown-toggle").on("click", function(event) {
1247
				console.log("Click on #topmenu-quickadd-dropdown .dropdown-toggle");
1248
                openQuickAddDropDown(event);
1249
            });
1250
1251
            // Key map shortcut
1252
            $(document).keydown(function(event){
1253
				var ostype = \'' . dol_escape_js($conf->browser->os) . '\';
1254
				if (ostype === "macintosh") {
1255
					if ( event.which === 65 && event.ctrlKey ) {
1256
						console.log(\'control + a : trigger open quick add dropdown\');
1257
						openQuickAddDropDown(event);
1258
					}
1259
				} else {
1260
					if ( event.which === 65 && event.ctrlKey && event.shiftKey ) {
1261
						console.log(\'control + shift + a : trigger open quick add dropdown\');
1262
						openQuickAddDropDown(event);
1263
					}
1264
				}
1265
            });
1266
1267
            var openQuickAddDropDown = function(event) {
1268
                event.preventDefault();
1269
                $("#topmenu-quickadd-dropdown").toggleClass("open");
1270
                //$("#top-quickadd-search-input").focus();
1271
            }
1272
        });
1273
        </script>
1274
        ';
1275
            }
1276
        }
1277
1278
        return $html;
1279
    }
1280
1281
    /**
1282
     * Generate list of quickadd items
1283
     *
1284
     * @return string HTML output
1285
     */
1286
    public static function printDropdownQuickadd()
1287
    {
1288
        global $user, $langs, $hookmanager;
1289
1290
        $items = array(
1291
            'items' => array(
1292
                array(
1293
                    "url" => "/adherents/card.php?action=create&amp;mainmenu=members",
1294
                    "title" => "MenuNewMember@members",
1295
                    "name" => "Adherent@members",
1296
                    "picto" => "object_member",
1297
                    "activation" => isModEnabled('member') && $user->hasRight("adherent", "write"), // vs hooking
1298
                    "position" => 5,
1299
                ),
1300
                array(
1301
                    "url" => "/societe/card.php?action=create&amp;mainmenu=companies",
1302
                    "title" => "MenuNewThirdParty@companies",
1303
                    "name" => "ThirdParty@companies",
1304
                    "picto" => "object_company",
1305
                    "activation" => isModEnabled("societe") && $user->hasRight("societe", "write"), // vs hooking
1306
                    "position" => 10,
1307
                ),
1308
                array(
1309
                    "url" => "/contact/card.php?action=create&amp;mainmenu=companies",
1310
                    "title" => "NewContactAddress@companies",
1311
                    "name" => "Contact@companies",
1312
                    "picto" => "object_contact",
1313
                    "activation" => isModEnabled("societe") && $user->hasRight("societe", "contact", "write"), // vs hooking
1314
                    "position" => 20,
1315
                ),
1316
                array(
1317
                    "url" => "/comm/propal/card.php?action=create&amp;mainmenu=commercial",
1318
                    "title" => "NewPropal@propal",
1319
                    "name" => "Proposal@propal",
1320
                    "picto" => "object_propal",
1321
                    "activation" => isModEnabled("propal") && $user->hasRight("propal", "write"), // vs hooking
1322
                    "position" => 30,
1323
                ),
1324
1325
                array(
1326
                    "url" => "/commande/card.php?action=create&amp;mainmenu=commercial",
1327
                    "title" => "NewOrder@orders",
1328
                    "name" => "Order@orders",
1329
                    "picto" => "object_order",
1330
                    "activation" => isModEnabled('order') && $user->hasRight("commande", "write"), // vs hooking
1331
                    "position" => 40,
1332
                ),
1333
                array(
1334
                    "url" => "/compta/facture/card.php?action=create&amp;mainmenu=billing",
1335
                    "title" => "NewBill@bills",
1336
                    "name" => "Bill@bills",
1337
                    "picto" => "object_bill",
1338
                    "activation" => isModEnabled('invoice') && $user->hasRight("facture", "write"), // vs hooking
1339
                    "position" => 50,
1340
                ),
1341
                array(
1342
                    "url" => "/contrat/card.php?action=create&amp;mainmenu=commercial",
1343
                    "title" => "NewContractSubscription@contracts",
1344
                    "name" => "Contract@contracts",
1345
                    "picto" => "object_contract",
1346
                    "activation" => isModEnabled('contract') && $user->hasRight("contrat", "write"), // vs hooking
1347
                    "position" => 60,
1348
                ),
1349
                array(
1350
                    "url" => "/supplier_proposal/card.php?action=create&amp;mainmenu=commercial",
1351
                    "title" => "SupplierProposalNew@supplier_proposal",
1352
                    "name" => "SupplierProposal@supplier_proposal",
1353
                    "picto" => "supplier_proposal",
1354
                    "activation" => isModEnabled('supplier_proposal') && $user->hasRight("supplier_invoice", "write"), // vs hooking
1355
                    "position" => 70,
1356
                ),
1357
                array(
1358
                    "url" => "/fourn/commande/card.php?action=create&amp;mainmenu=commercial",
1359
                    "title" => "NewSupplierOrderShort@orders",
1360
                    "name" => "SupplierOrder@orders",
1361
                    "picto" => "supplier_order",
1362
                    "activation" => (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "commande", "write")) || (isModEnabled("supplier_order") && $user->hasRight("supplier_invoice", "write")), // vs hooking
1363
                    "position" => 80,
1364
                ),
1365
                array(
1366
                    "url" => "/fourn/facture/card.php?action=create&amp;mainmenu=billing",
1367
                    "title" => "NewBill@bills",
1368
                    "name" => "SupplierBill@bills",
1369
                    "picto" => "supplier_invoice",
1370
                    "activation" => (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "write")) || (isModEnabled("supplier_invoice") && $user->hasRight("supplier_invoice", "write")), // vs hooking
1371
                    "position" => 90,
1372
                ),
1373
                array(
1374
                    "url" => "/ticket/card.php?action=create&amp;mainmenu=ticket",
1375
                    "title" => "NewTicket@ticket",
1376
                    "name" => "Ticket@ticket",
1377
                    "picto" => "ticket",
1378
                    "activation" => isModEnabled('ticket') && $user->hasRight("ticket", "write"), // vs hooking
1379
                    "position" => 100,
1380
                ),
1381
                array(
1382
                    "url" => "/fichinter/card.php?action=create&mainmenu=commercial",
1383
                    "title" => "NewIntervention@interventions",
1384
                    "name" => "Intervention@interventions",
1385
                    "picto" => "intervention",
1386
                    "activation" => isModEnabled('intervention') && $user->hasRight("ficheinter", "creer"), // vs hooking
1387
                    "position" => 110,
1388
                ),
1389
                array(
1390
                    "url" => "/product/card.php?action=create&amp;type=0&amp;mainmenu=products",
1391
                    "title" => "NewProduct@products",
1392
                    "name" => "Product@products",
1393
                    "picto" => "object_product",
1394
                    "activation" => isModEnabled("product") && $user->hasRight("produit", "write"), // vs hooking
1395
                    "position" => 400,
1396
                ),
1397
                array(
1398
                    "url" => "/product/card.php?action=create&amp;type=1&amp;mainmenu=products",
1399
                    "title" => "NewService@products",
1400
                    "name" => "Service@products",
1401
                    "picto" => "object_service",
1402
                    "activation" => isModEnabled("service") && $user->hasRight("service", "write"), // vs hooking
1403
                    "position" => 410,
1404
                ),
1405
                array(
1406
                    "url" => "/user/card.php?action=create&amp;type=1&amp;mainmenu=home",
1407
                    "title" => "AddUser@users",
1408
                    "name" => "User@users",
1409
                    "picto" => "user",
1410
                    "activation" => $user->hasRight("user", "user", "write"), // vs hooking
1411
                    "position" => 500,
1412
                ),
1413
            ),
1414
        );
1415
1416
        $dropDownQuickAddHtml = '';
1417
1418
        // Define $dropDownQuickAddHtml
1419
        $dropDownQuickAddHtml .= '<div class="quickadd-body dropdown-body">';
1420
        $dropDownQuickAddHtml .= '<div class="dropdown-quickadd-list">';
1421
1422
        // Allow the $items of the menu to be manipulated by modules
1423
        $parameters = array();
1424
        $hook_items = $items;
1425
        $reshook = $hookmanager->executeHooks('menuDropdownQuickaddItems', $parameters, $hook_items); // Note that $action and $object may have been modified by some hooks
1426
        if (is_numeric($reshook) && !empty($hookmanager->resArray) && is_array($hookmanager->resArray)) {
1427
            if ($reshook == 0) {
1428
                $items['items'] = array_merge($items['items'], $hookmanager->resArray); // add
1429
            } else {
1430
                $items = $hookmanager->resArray; // replace
1431
            }
1432
1433
            // Sort menu items by 'position' value
1434
            $position = array();
1435
            foreach ($items['items'] as $key => $row) {
1436
                $position[$key] = $row['position'];
1437
            }
1438
            $array1_sort_order = SORT_ASC;
1439
            array_multisort($position, $array1_sort_order, $items['items']);
1440
        }
1441
1442
        foreach ($items['items'] as $item) {
1443
            if (!$item['activation']) {
1444
                continue;
1445
            }
1446
            $langs->load(explode('@', $item['title'])[1]);
1447
            $langs->load(explode('@', $item['name'])[1]);
1448
            $dropDownQuickAddHtml .= '
1449
			<a class="dropdown-item quickadd-item" href="' . constant('DOL_URL_ROOT') . $item['url'] . '" title="' . $langs->trans(explode('@', $item['title'])[0]) . '">
1450
			' . img_picto('', $item['picto'], 'style="width:18px;"') . ' ' . $langs->trans(explode('@', $item['name'])[0]) . '</a>
1451
		';
1452
        }
1453
1454
        $dropDownQuickAddHtml .= '</div>';
1455
        $dropDownQuickAddHtml .= '</div>';
1456
1457
        return $dropDownQuickAddHtml;
1458
    }
1459
1460
    /**
1461
     * Build the tooltip on top menu bookmark
1462
     *
1463
     * @return  string                  HTML content
1464
     */
1465
    public static function topMenuBookmark()
1466
    {
1467
        global $langs, $conf, $db, $user;
1468
1469
        $html = '';
1470
1471
        // Define $bookmarks
1472
        if (!isModEnabled('bookmark') || !$user->hasRight('bookmark', 'lire')) {
1473
            return $html;
1474
        }
1475
1476
        // accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
1477
        // accesskey is for Mac:               CTRL + key for all browsers
1478
        $stringforfirstkey = $langs->trans("KeyboardShortcut");
1479
        if ($conf->browser->os === 'macintosh') {
1480
            $stringforfirstkey .= ' CTL +';
1481
        } else {
1482
            if ($conf->browser->name == 'chrome') {
1483
                $stringforfirstkey .= ' ALT +';
1484
            } elseif ($conf->browser->name == 'firefox') {
1485
                $stringforfirstkey .= ' ALT + SHIFT +';
1486
            } else {
1487
                $stringforfirstkey .= ' CTL +';
1488
            }
1489
        }
1490
1491
        if (!defined('JS_JQUERY_DISABLE_DROPDOWN') && !empty($conf->use_javascript_ajax)) {     // This may be set by some pages that use different jquery version to avoid errors
1492
            include_once DOL_DOCUMENT_ROOT . '/bookmarks/lib/bookmarks.lib.php';
1493
            $langs->load("bookmarks");
1494
1495
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1496
                $html .= '<div id="topmenu-bookmark-dropdown" class="dropdown inline-block">';
1497
                $html .= printDropdownBookmarksList();
1498
                $html .= '</div>';
1499
            } else {
1500
                $html .= '<!-- div for bookmark link -->
1501
	        <div id="topmenu-bookmark-dropdown" class="dropdown inline-block">
1502
	            <a accesskey="b" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="' . $langs->trans('Bookmarks') . ' (' . $stringforfirstkey . ' b)"><i class="fa fa-star"></i></a>
1503
	            <div class="dropdown-menu">
1504
	                ' . printDropdownBookmarksList() . '
1505
	            </div>
1506
	        </div>';
1507
1508
                $html .= '
1509
	        <!-- Code to show/hide the bookmark drop-down -->
1510
	        <script>
1511
	        jQuery(document).ready(function() {
1512
	            jQuery(document).on("click", function(event) {
1513
	                if (!$(event.target).closest("#topmenu-bookmark-dropdown").length) {
1514
						//console.log("close bookmark dropdown - we click outside");
1515
	                    // Hide the menus.
1516
	                    $("#topmenu-bookmark-dropdown").removeClass("open");
1517
	                }
1518
	            });
1519
1520
	            jQuery("#topmenu-bookmark-dropdown .dropdown-toggle").on("click", function(event) {
1521
					console.log("Click on #topmenu-bookmark-dropdown .dropdown-toggle");
1522
					openBookMarkDropDown(event);
1523
	            });
1524
1525
	            // Key map shortcut
1526
	            jQuery(document).keydown(function(event) {
1527
					var ostype = \'' . dol_escape_js($conf->browser->os) . '\';
1528
					if (ostype === "macintosh") {
1529
						if ( event.which === 66 && event.ctrlKey ) {
1530
							console.log("Click on control + b : trigger open bookmark dropdown");
1531
							openBookMarkDropDown(event);
1532
						}
1533
					} else {
1534
						if ( event.which === 66 && event.ctrlKey && event.shiftKey ) {
1535
							console.log("Click on control + shift + b : trigger open bookmark dropdown");
1536
							openBookMarkDropDown(event);
1537
						}
1538
					}
1539
	            });
1540
1541
	            var openBookMarkDropDown = function(event) {
1542
	                event.preventDefault();
1543
	                jQuery("#topmenu-bookmark-dropdown").toggleClass("open");
1544
	                jQuery("#top-bookmark-search-input").focus();
1545
	            }
1546
1547
	        });
1548
	        </script>
1549
	        ';
1550
            }
1551
        }
1552
        return $html;
1553
    }
1554
1555
    /**
1556
     * Build the tooltip on top menu tsearch
1557
     *
1558
     * @return  string                  HTML content
1559
     */
1560
    public static function topSearchMenu()
1561
    {
1562
        global $langs, $conf, $db, $user, $hookmanager;
1563
1564
        $html = '';
1565
1566
        $usedbyinclude = 1;
1567
        $arrayresult = array();
1568
        include DOL_DOCUMENT_ROOT . '/core/ajax/selectsearchbox.php'; // This sets $arrayresult
1569
1570
        // accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
1571
        // accesskey is for Mac:               CTRL + key for all browsers
1572
        $stringforfirstkey = $langs->trans("KeyboardShortcut");
1573
        if ($conf->browser->name == 'chrome') {
1574
            $stringforfirstkey .= ' ALT +';
1575
        } elseif ($conf->browser->name == 'firefox') {
1576
            $stringforfirstkey .= ' ALT + SHIFT +';
1577
        } else {
1578
            $stringforfirstkey .= ' CTL +';
1579
        }
1580
1581
        $searchInput = '<input type="search" name="search_all"' . ($stringforfirstkey ? ' title="' . dol_escape_htmltag($stringforfirstkey . ' s') . '"' : '') . ' id="top-global-search-input" class="dropdown-search-input search_component_input" placeholder="' . $langs->trans('Search') . '" autocomplete="off">';
1582
1583
        $defaultAction = '';
1584
        $buttonList = '<div class="dropdown-global-search-button-list" >';
1585
        // Menu with all searchable items
1586
        foreach ($arrayresult as $keyItem => $item) {
1587
            if (empty($defaultAction)) {
1588
                $defaultAction = $item['url'];
1589
            }
1590
            $buttonList .= '<button class="dropdown-item global-search-item tdoverflowmax300" data-target="' . dol_escape_htmltag($item['url']) . '" >';
1591
            $buttonList .= $item['text'];
1592
            $buttonList .= '</button>';
1593
        }
1594
        $buttonList .= '</div>';
1595
1596
        $dropDownHtml = '<form role="search" id="top-menu-action-search" name="actionsearch" method="GET" action="' . $defaultAction . '">';
1597
1598
        $dropDownHtml .= '
1599
        <!-- search input -->
1600
        <div class="dropdown-header search-dropdown-header">
1601
            ' . $searchInput . '
1602
        </div>
1603
    ';
1604
1605
        $dropDownHtml .= '
1606
        <!-- Menu Body search -->
1607
        <div class="dropdown-body search-dropdown-body">
1608
        ' . $buttonList . '
1609
        </div>
1610
        ';
1611
1612
        $dropDownHtml .= '</form>';
1613
1614
        // accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
1615
        // accesskey is for Mac:               CTRL + key for all browsers
1616
        $stringforfirstkey = $langs->trans("KeyboardShortcut");
1617
        if ($conf->browser->name == 'chrome') {
1618
            $stringforfirstkey .= ' ALT +';
1619
        } elseif ($conf->browser->name == 'firefox') {
1620
            $stringforfirstkey .= ' ALT + SHIFT +';
1621
        } else {
1622
            $stringforfirstkey .= ' CTL +';
1623
        }
1624
1625
        $html .= '<!-- div for Global Search -->
1626
    <div id="topmenu-global-search-dropdown" class="atoplogin dropdown inline-block">
1627
        <a accesskey="s" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="' . $langs->trans('Search') . ' (' . $stringforfirstkey . ' s)">
1628
            <i class="fa fa-search" aria-hidden="true" ></i>
1629
        </a>
1630
        <div class="dropdown-menu dropdown-search">
1631
            ' . $dropDownHtml . '
1632
        </div>
1633
    </div>';
1634
1635
        $html .= '
1636
    <!-- Code to show/hide the user drop-down -->
1637
    <script>
1638
    jQuery(document).ready(function() {
1639
1640
        // prevent submitting form on press ENTER
1641
        jQuery("#top-global-search-input").keydown(function (e) {
1642
            if (e.keyCode == 13 || e.keyCode == 40) {
1643
                var inputs = $(this).parents("form").eq(0).find(":button");
1644
                if (inputs[inputs.index(this) + 1] != null) {
1645
                    inputs[inputs.index(this) + 1].focus();
1646
					 if (e.keyCode == 13){
1647
						 inputs[inputs.index(this) + 1].trigger("click");
1648
					 }
1649
1650
                }
1651
                e.preventDefault();
1652
                return false;
1653
            }
1654
        });
1655
1656
        // arrow key nav
1657
        jQuery(document).keydown(function(e) {
1658
			// Get the focused element:
1659
			var $focused = $(":focus");
1660
			if($focused.length && $focused.hasClass("global-search-item")){
1661
1662
           		// UP - move to the previous line
1663
				if (e.keyCode == 38) {
1664
				    e.preventDefault();
1665
					$focused.prev().focus();
1666
				}
1667
1668
				// DOWN - move to the next line
1669
				if (e.keyCode == 40) {
1670
				    e.preventDefault();
1671
					$focused.next().focus();
1672
				}
1673
			}
1674
        });
1675
1676
1677
        // submit form action
1678
        jQuery(".dropdown-global-search-button-list .global-search-item").on("click", function(event) {
1679
            jQuery("#top-menu-action-search").attr("action", $(this).data("target"));
1680
            jQuery("#top-menu-action-search").submit();
1681
        });
1682
1683
        // close drop down
1684
        jQuery(document).on("click", function(event) {
1685
			if (!$(event.target).closest("#topmenu-global-search-dropdown").length) {
1686
				console.log("click close search - we click outside");
1687
                // Hide the menus.
1688
                jQuery("#topmenu-global-search-dropdown").removeClass("open");
1689
            }
1690
        });
1691
1692
        // Open drop down
1693
        jQuery("#topmenu-global-search-dropdown .dropdown-toggle").on("click", function(event) {
1694
			console.log("click on toggle #topmenu-global-search-dropdown .dropdown-toggle");
1695
            openGlobalSearchDropDown();
1696
        });
1697
1698
        // Key map shortcut
1699
        jQuery(document).keydown(function(e){
1700
              if ( e.which === 70 && e.ctrlKey && e.shiftKey ) {
1701
                 console.log(\'control + shift + f : trigger open global-search dropdown\');
1702
                 openGlobalSearchDropDown();
1703
              }
1704
              if ( e.which === 70 && e.alKey ) {
1705
                 console.log(\'alt + f : trigger open global-search dropdown\');
1706
                 openGlobalSearchDropDown();
1707
              }
1708
        });
1709
1710
        var openGlobalSearchDropDown = function() {
1711
            jQuery("#topmenu-global-search-dropdown").toggleClass("open");
1712
            jQuery("#top-global-search-input").focus();
1713
        }
1714
1715
    });
1716
    </script>
1717
    ';
1718
1719
        return $html;
1720
    }
1721
1722
    /**
1723
     *  Show left menu bar
1724
     *
1725
     * @param string $menu_array_before Table of menu entries to show before entries of menu handler. This param is deprecated and must be provided to ''.
1726
     * @param string $helppagename Name of wiki page for help ('' by default).
1727
     *                                                  Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage|DE:GermanPage
1728
     *                                                  For other external page: http://server/url
1729
     * @param string $notused Deprecated. Used in past to add content into left menu. Hooks can be used now.
1730
     * @param array $menu_array_after Table of menu entries to show after entries of menu handler
1731
     * @param int $leftmenuwithoutmainarea Must be set to 1. 0 by default for backward compatibility with old modules.
1732
     * @param string $title Title of web page
1733
     * @param int<0,1> $acceptdelayedhtml 1 if caller request to have html delayed content not returned but saved into global $delayedhtmlcontent (so caller can show it at end of page to avoid flash FOUC effect)
1734
     * @return void
1735
     */
1736
    public static function leftMenu($menu_array_before, $helppagename = '', $notused = '', $menu_array_after = array(), $leftmenuwithoutmainarea = 0, $title = '', $acceptdelayedhtml = 0)
1737
    {
1738
        global $user, $conf, $langs, $db, $form;
1739
        global $hookmanager, $menumanager;
1740
1741
        $searchform = '';
1742
1743
        if (!empty($menu_array_before)) {
1744
            dol_syslog("Deprecated parameter menu_array_before was used when calling main::left_menu function. Menu entries of module should now be defined into module descriptor and not provided when calling left_menu.", LOG_WARNING);
1745
        }
1746
1747
        if (empty($conf->dol_hide_leftmenu) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
1748
            // Instantiate hooks for external modules
1749
            $hookmanager->initHooks(array('leftblock'));
1750
1751
            print "\n" . '<!-- Begin side-nav id-left -->' . "\n" . '<div class="side-nav"><div id="id-left">' . "\n";
1752
            print "\n";
1753
1754
            if (!is_object($form)) {
1755
                $form = new Form($db);
1756
            }
1757
            $selected = -1;
1758
            if (!getDolGlobalString('MAIN_USE_TOP_MENU_SEARCH_DROPDOWN')) {
1759
                // Select with select2 is awful on smartphone. TODO Is this still true with select2 v4 ?
1760
                if ($conf->browser->layout == 'phone') {
1761
                    $conf->global->MAIN_USE_OLD_SEARCH_FORM = 1;
1762
                }
1763
1764
                $usedbyinclude = 1;
1765
                $arrayresult = array();
1766
                include DOL_DOCUMENT_ROOT . '/core/ajax/selectsearchbox.php'; // This make initHooks('searchform') then set $arrayresult
1767
1768
                if ($conf->use_javascript_ajax && !getDolGlobalString('MAIN_USE_OLD_SEARCH_FORM')) {
1769
                    // accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
1770
                    // accesskey is for Mac:               CTRL + key for all browsers
1771
                    $stringforfirstkey = $langs->trans("KeyboardShortcut");
1772
                    if ($conf->browser->name == 'chrome') {
1773
                        $stringforfirstkey .= ' ALT +';
1774
                    } elseif ($conf->browser->name == 'firefox') {
1775
                        $stringforfirstkey .= ' ALT + SHIFT +';
1776
                    } else {
1777
                        $stringforfirstkey .= ' CTL +';
1778
                    }
1779
1780
                    //$textsearch = $langs->trans("Search");
1781
                    $textsearch = '<span class="fa fa-search paddingright pictofixedwidth"></span>' . $langs->trans("Search");
1782
                    $searchform .= $form->selectArrayFilter('searchselectcombo', $arrayresult, $selected, 'accesskey="s"', 1, 0, (!getDolGlobalString('MAIN_SEARCHBOX_CONTENT_LOADED_BEFORE_KEY') ? 1 : 0), 'vmenusearchselectcombo', 1, $textsearch, 1, $stringforfirstkey . ' s');
1783
                } else {
1784
                    if (is_array($arrayresult)) {
1785
                        foreach ($arrayresult as $key => $val) {
1786
                            $searchform .= static::printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth125', 'search_all', (empty($val['shortcut']) ? '' : $val['shortcut']), 'searchleft' . $key, $val['img']);
1787
                        }
1788
                    }
1789
                }
1790
1791
                // Execute hook printSearchForm
1792
                $parameters = array('searchform' => $searchform);
1793
                $reshook = $hookmanager->executeHooks('printSearchForm', $parameters); // Note that $action and $object may have been modified by some hooks
1794
                if (empty($reshook)) {
1795
                    $searchform .= $hookmanager->resPrint;
1796
                } else {
1797
                    $searchform = $hookmanager->resPrint;
1798
                }
1799
1800
                // Force special value for $searchform for text browsers or very old search form
1801
                if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') || empty($conf->use_javascript_ajax)) {
1802
                    $urltosearch = constant('BASE_URL') . '/core/search_page.php?showtitlebefore=1';
1803
                    $searchform = '<div class="blockvmenuimpair blockvmenusearchphone"><div id="divsearchforms1"><a href="' . $urltosearch . '" accesskey="s" alt="' . dol_escape_htmltag($langs->trans("ShowSearchFields")) . '">' . $langs->trans("Search") . '...</a></div></div>';
1804
                } elseif ($conf->use_javascript_ajax && getDolGlobalString('MAIN_USE_OLD_SEARCH_FORM')) {
1805
                    $searchform = '<div class="blockvmenuimpair blockvmenusearchphone"><div id="divsearchforms1"><a href="#" alt="' . dol_escape_htmltag($langs->trans("ShowSearchFields")) . '">' . $langs->trans("Search") . '...</a></div><div id="divsearchforms2" style="display: none">' . $searchform . '</div>';
1806
                    $searchform .= '<script>
1807
            	jQuery(document).ready(function () {
1808
            		jQuery("#divsearchforms1").click(function(){
1809
	                   jQuery("#divsearchforms2").toggle();
1810
	               });
1811
            	});
1812
                </script>' . "\n";
1813
                    $searchform .= '</div>';
1814
                }
1815
1816
                // Key map shortcut
1817
                $searchform .= '<script>
1818
				jQuery(document).keydown(function(e){
1819
					if( e.which === 70 && e.ctrlKey && e.shiftKey ){
1820
						console.log(\'control + shift + f : trigger open global-search dropdown\');
1821
		                openGlobalSearchDropDown();
1822
		            }
1823
		            if( (e.which === 83 || e.which === 115) && e.altKey ){
1824
		                console.log(\'alt + s : trigger open global-search dropdown\');
1825
		                openGlobalSearchDropDown();
1826
		            }
1827
		        });
1828
1829
		        var openGlobalSearchDropDown = function() {
1830
		            jQuery("#searchselectcombo").select2(\'open\');
1831
		        }
1832
			</script>';
1833
            }
1834
1835
            // Left column
1836
            print '<!-- Begin left menu -->' . "\n";
1837
1838
            print '<div class="vmenu"' . (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') ? ' alt="Left menu"' : '') . '>' . "\n\n";
1839
1840
            // Show left menu with other forms
1841
            $menumanager->menu_array = $menu_array_before;
1842
            $menumanager->menu_array_after = $menu_array_after;
1843
            $menumanager->showmenu('left', array('searchform' => $searchform)); // output menu_array and menu found in database
1844
1845
            // Dolibarr version + help + bug report link
1846
            print "\n";
1847
            print "<!-- Begin Help Block-->\n";
1848
            print '<div id="blockvmenuhelp" class="blockvmenuhelp">' . "\n";
1849
1850
            // Version
1851
            if (getDolGlobalString('MAIN_SHOW_VERSION')) {    // Version is already on help picto and on login page.
1852
                $doliurl = 'https://www.dolibarr.org';
1853
                //local communities
1854
                if (preg_match('/fr/i', $langs->defaultlang)) {
1855
                    $doliurl = 'https://www.dolibarr.fr';
1856
                }
1857
                if (preg_match('/es/i', $langs->defaultlang)) {
1858
                    $doliurl = 'https://www.dolibarr.es';
1859
                }
1860
                if (preg_match('/de/i', $langs->defaultlang)) {
1861
                    $doliurl = 'https://www.dolibarr.de';
1862
                }
1863
                if (preg_match('/it/i', $langs->defaultlang)) {
1864
                    $doliurl = 'https://www.dolibarr.it';
1865
                }
1866
                if (preg_match('/gr/i', $langs->defaultlang)) {
1867
                    $doliurl = 'https://www.dolibarr.gr';
1868
                }
1869
1870
                $appli = constant('DOL_APPLICATION_TITLE');
1871
                if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
1872
                    $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
1873
                    $doliurl = '';
1874
                    if (preg_match('/\d\.\d/', $appli)) {
1875
                        if (!preg_match('/' . preg_quote(DOL_VERSION) . '/', $appli)) {
1876
                            $appli .= " (" . DOL_VERSION . ")"; // If new title contains a version that is different than core
1877
                        }
1878
                    } else {
1879
                        $appli .= " " . DOL_VERSION;
1880
                    }
1881
                } else {
1882
                    $appli .= " " . DOL_VERSION;
1883
                }
1884
                print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
1885
                if ($doliurl) {
1886
                    print '<a class="help" target="_blank" rel="noopener noreferrer" href="' . $doliurl . '">';
1887
                } else {
1888
                    print '<span class="help">';
1889
                }
1890
                print $appli;
1891
                if ($doliurl) {
1892
                    print '</a>';
1893
                } else {
1894
                    print '</span>';
1895
                }
1896
                print '</div>' . "\n";
1897
            }
1898
1899
            // Link to bugtrack
1900
            if (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK')) {
1901
                require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/functions2.lib.php';
1902
1903
                if (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK') == 'github') {
1904
                    $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new?labels=Bug';
1905
                    $bugbaseurl .= '&title=';
1906
                    $bugbaseurl .= urlencode("Bug: ");
1907
                    $bugbaseurl .= '&body=';
1908
                    $bugbaseurl .= urlencode("# Instructions\n");
1909
                    $bugbaseurl .= urlencode("*This is a template to help you report good issues. You may use [Github Markdown](https://help.github.com/articles/getting-started-with-writing-and-formatting-on-github/) syntax to format your issue report.*\n");
1910
                    $bugbaseurl .= urlencode("*Please:*\n");
1911
                    $bugbaseurl .= urlencode("- *replace the bracket enclosed texts with meaningful information*\n");
1912
                    $bugbaseurl .= urlencode("- *remove any unused sub-section*\n");
1913
                    $bugbaseurl .= urlencode("\n");
1914
                    $bugbaseurl .= urlencode("\n");
1915
                    $bugbaseurl .= urlencode("# Bug\n");
1916
                    $bugbaseurl .= urlencode("[*Short description*]\n");
1917
                    $bugbaseurl .= urlencode("\n");
1918
                    $bugbaseurl .= urlencode("## Environment\n");
1919
                    $bugbaseurl .= urlencode("- **Version**: " . DOL_VERSION . "\n");
1920
                    $bugbaseurl .= urlencode("- **OS**: " . php_uname('s') . "\n");
1921
                    $bugbaseurl .= urlencode("- **Web server**: " . $_SERVER["SERVER_SOFTWARE"] . "\n");
1922
                    $bugbaseurl .= urlencode("- **PHP**: " . php_sapi_name() . ' ' . phpversion() . "\n");
1923
                    $bugbaseurl .= urlencode("- **Database**: " . $db::LABEL . ' ' . $db->getVersion() . "\n");
1924
                    $bugbaseurl .= urlencode("- **URL(s)**: " . $_SERVER["REQUEST_URI"] . "\n");
1925
                    $bugbaseurl .= urlencode("\n");
1926
                    $bugbaseurl .= urlencode("## Expected and actual behavior\n");
1927
                    $bugbaseurl .= urlencode("[*Verbose description*]\n");
1928
                    $bugbaseurl .= urlencode("\n");
1929
                    $bugbaseurl .= urlencode("## Steps to reproduce the behavior\n");
1930
                    $bugbaseurl .= urlencode("[*Verbose description*]\n");
1931
                    $bugbaseurl .= urlencode("\n");
1932
                    $bugbaseurl .= urlencode("## [Attached files](https://help.github.com/articles/issue-attachments) (Screenshots, screencasts, alixar.log, debugging information…)\n");
1933
                    $bugbaseurl .= urlencode("[*Files*]\n");
1934
                    $bugbaseurl .= urlencode("\n");
1935
1936
                    $bugbaseurl .= urlencode("\n");
1937
                    $bugbaseurl .= urlencode("## Report\n");
1938
                } elseif (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK')) {
1939
                    $bugbaseurl = getDolGlobalString('MAIN_BUGTRACK_ENABLELINK');
1940
                } else {
1941
                    $bugbaseurl = "";
1942
                }
1943
1944
                // Execute hook printBugtrackInfo
1945
                $parameters = array('bugbaseurl' => $bugbaseurl);
1946
                $reshook = $hookmanager->executeHooks('printBugtrackInfo', $parameters); // Note that $action and $object may have been modified by some hooks
1947
                if (empty($reshook)) {
1948
                    $bugbaseurl .= $hookmanager->resPrint;
1949
                } else {
1950
                    $bugbaseurl = $hookmanager->resPrint;
1951
                }
1952
1953
                print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
1954
                print '<a class="help" target="_blank" rel="noopener noreferrer" href="' . $bugbaseurl . '"><i class="fas fa-bug"></i> ' . $langs->trans("FindBug") . '</a>';
1955
                print '</div>';
1956
            }
1957
1958
            print "</div>\n";
1959
            print "<!-- End Help Block-->\n";
1960
            print "\n";
1961
1962
            print "</div>\n";
1963
            print "<!-- End left menu -->\n";
1964
            print "\n";
1965
1966
            // Execute hook printLeftBlock
1967
            $parameters = array();
1968
            $reshook = $hookmanager->executeHooks('printLeftBlock', $parameters); // Note that $action and $object may have been modified by some hooks
1969
            print $hookmanager->resPrint;
1970
1971
            print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
1972
        }
1973
1974
        print "\n";
1975
        print '<!-- Begin right area -->' . "\n";
1976
1977
        if (empty($leftmenuwithoutmainarea)) {
1978
            static::mainArea($title);
1979
        }
1980
    }
1981
1982
    /**
1983
     *  Begin main area
1984
     *
1985
     * @param string $title Title
1986
     * @return void
1987
     */
1988
    public static function mainArea($title = '')
1989
    {
1990
        global $conf, $langs, $hookmanager;
1991
1992
        if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup')) {
1993
            print '<div id="id-right">';
1994
        }
1995
1996
        print "\n";
1997
1998
        print '<!-- Begin div class="fiche" -->' . "\n" . '<div class="fiche">' . "\n";
1999
2000
        $hookmanager->initHooks(array('main'));
2001
        $parameters = array();
2002
        $reshook = $hookmanager->executeHooks('printMainArea', $parameters); // Note that $action and $object may have been modified by some hooks
2003
        print $hookmanager->resPrint;
2004
2005
        if (getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED')) {
2006
            print info_admin($langs->trans("WarningYouAreInMaintenanceMode", getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED')), 0, 0, 1, 'warning maintenancemode');
2007
        }
2008
2009
        // Permit to add user company information on each printed document by setting SHOW_SOCINFO_ON_PRINT
2010
        if (getDolGlobalString('SHOW_SOCINFO_ON_PRINT') && GETPOST('optioncss', 'aZ09') == 'print' && empty(GETPOST('disable_show_socinfo_on_print', 'aZ09'))) {
2011
            $parameters = array();
2012
            $reshook = $hookmanager->executeHooks('showSocinfoOnPrint', $parameters);
2013
            if (empty($reshook)) {
2014
                print '<!-- Begin show mysoc info header -->' . "\n";
2015
                print '<div id="mysoc-info-header">' . "\n";
2016
                print '<table class="centpercent div-table-responsive">' . "\n";
2017
                print '<tbody>';
2018
                print '<tr><td rowspan="0" class="width20p">';
2019
                if (getDolGlobalString('MAIN_SHOW_LOGO') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && getDolGlobalString('MAIN_INFO_SOCIETE_LOGO')) {
2020
                    print '<img id="mysoc-info-header-logo" style="max-width:100%" alt="" src="' . constant('BASE_URL') . '/viewimage.php?cache=1&modulepart=mycompany&file=' . urlencode('logos/' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_LOGO'))) . '">';
2021
                }
2022
                print '</td><td  rowspan="0" class="width50p"></td></tr>' . "\n";
2023
                print '<tr><td class="titre bold">' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_NOM')) . '</td></tr>' . "\n";
2024
                print '<tr><td>' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS')) . '<br>' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_ZIP')) . ' ' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_TOWN')) . '</td></tr>' . "\n";
2025
                if (getDolGlobalString('MAIN_INFO_SOCIETE_TEL')) {
2026
                    print '<tr><td style="padding-left: 1em" class="small">' . $langs->trans("Phone") . ' : ' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_TEL')) . '</td></tr>';
2027
                }
2028
                if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
2029
                    print '<tr><td style="padding-left: 1em" class="small">' . $langs->trans("Email") . ' : ' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) . '</td></tr>';
2030
                }
2031
                if (getDolGlobalString('MAIN_INFO_SOCIETE_WEB')) {
2032
                    print '<tr><td style="padding-left: 1em" class="small">' . $langs->trans("Web") . ' : ' . dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_WEB')) . '</td></tr>';
2033
                }
2034
                print '</tbody>';
2035
                print '</table>' . "\n";
2036
                print '</div>' . "\n";
2037
                print '<!-- End show mysoc info header -->' . "\n";
2038
            }
2039
        }
2040
    }
2041
2042
    /**
2043
     *  Return helpbaseurl, helppage and mode
2044
     *
2045
     * @param string $helppagename Page name ('EN:xxx,ES:eee,FR:fff,DE:ddd...' or 'http://localpage')
2046
     * @param Translate $langs Language
2047
     * @return array{helpbaseurl:string,helppage:string,mode:string}   Array of help urls
2048
     */
2049
    public static function getHelpParamFor($helppagename, $langs)
2050
    {
2051
        $helpbaseurl = '';
2052
        $helppage = '';
2053
        $mode = '';
2054
2055
        if (preg_match('/^http/i', $helppagename)) {
2056
            // If complete URL
2057
            $helpbaseurl = '%s';
2058
            $helppage = $helppagename;
2059
            $mode = 'local';
2060
        } else {
2061
            // If WIKI URL
2062
            $reg = array();
2063
            if (preg_match('/^es/i', $langs->defaultlang)) {
2064
                $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
2065
                if (preg_match('/ES:([^|]+)/i', $helppagename, $reg)) {
2066
                    $helppage = $reg[1];
2067
                }
2068
            }
2069
            if (preg_match('/^fr/i', $langs->defaultlang)) {
2070
                $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
2071
                if (preg_match('/FR:([^|]+)/i', $helppagename, $reg)) {
2072
                    $helppage = $reg[1];
2073
                }
2074
            }
2075
            if (preg_match('/^de/i', $langs->defaultlang)) {
2076
                $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
2077
                if (preg_match('/DE:([^|]+)/i', $helppagename, $reg)) {
2078
                    $helppage = $reg[1];
2079
                }
2080
            }
2081
            if (empty($helppage)) { // If help page not already found
2082
                $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
2083
                if (preg_match('/EN:([^|]+)/i', $helppagename, $reg)) {
2084
                    $helppage = $reg[1];
2085
                }
2086
            }
2087
            $mode = 'wiki';
2088
        }
2089
        return array('helpbaseurl' => $helpbaseurl, 'helppage' => $helppage, 'mode' => $mode);
2090
    }
2091
2092
    /**
2093
     *  Show a search area.
2094
     *  Used when the javascript quick search is not used.
2095
     *
2096
     * @param string $urlaction Url post
2097
     * @param string $urlobject Url of the link under the search box
2098
     * @param string $title Title search area
2099
     * @param string $htmlmorecss Add more css
2100
     * @param string $htmlinputname Field Name input form
2101
     * @param string $accesskey Accesskey
2102
     * @param string $prefhtmlinputname Complement for id to avoid multiple same id in the page
2103
     * @param string $img Image to use
2104
     * @param int $showtitlebefore Show title before input text instead of into placeholder. This can be set when output is dedicated for text browsers.
2105
     * @param int $autofocus Set autofocus on field
2106
     * @return string
2107
     */
2108
    public static function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey = '', $prefhtmlinputname = '', $img = '', $showtitlebefore = 0, $autofocus = 0)
2109
    {
2110
        global $langs, $user;
2111
2112
        $ret = '';
2113
        $ret .= '<form action="' . $urlaction . '" method="post" class="searchform nowraponall tagtr">';
2114
        $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
2115
        $ret .= '<input type="hidden" name="savelogin" value="' . dol_escape_htmltag($user->login) . '">';
2116
        if ($showtitlebefore) {
2117
            $ret .= '<div class="tagtd left">' . $title . '</div> ';
2118
        }
2119
        $ret .= '<div class="tagtd">';
2120
        $ret .= img_picto('', $img, '', false, 0, 0, '', 'paddingright width20');
2121
        $ret .= '<input type="text" class="flat ' . $htmlmorecss . '"';
2122
        $ret .= ' style="background-repeat: no-repeat; background-position: 3px;"';
2123
        $ret .= ($accesskey ? ' accesskey="' . $accesskey . '"' : '');
2124
        $ret .= ' placeholder="' . strip_tags($title) . '"';
2125
        $ret .= ($autofocus ? ' autofocus' : '');
2126
        $ret .= ' name="' . $htmlinputname . '" id="' . $prefhtmlinputname . $htmlinputname . '" />';
2127
        $ret .= '<button type="submit" class="button bordertransp" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
2128
        $ret .= '<span class="fa fa-search"></span>';
2129
        $ret .= '</button>';
2130
        $ret .= '</div>';
2131
        $ret .= "</form>\n";
2132
        return $ret;
2133
    }
2134
2135
    /**
2136
     * Show HTML footer
2137
     * Close div /DIV class=fiche + /DIV id-right + /DIV id-container + /BODY + /HTML.
2138
     * If global var $delayedhtmlcontent was filled, we output it just before closing the body.
2139
     *
2140
     * @param string $comment A text to add as HTML comment into HTML generated page
2141
     * @param string $zone 'private' (for private pages) or 'public' (for public pages)
2142
     * @param int $disabledoutputofmessages Clear all messages stored into session without displaying them
2143
     * @return  void
2144
     */
2145
    public static function llxFooter($comment = '', $zone = 'private', $disabledoutputofmessages = 0)
2146
    {
2147
        global $conf, $db, $langs, $user, $mysoc, $object, $hookmanager, $action;
2148
        global $delayedhtmlcontent;
2149
        global $contextpage, $page, $limit, $mode;
2150
        global $dolibarr_distrib;
2151
2152
        $ext = 'layout=' . urlencode($conf->browser->layout) . '&version=' . urlencode(DOL_VERSION);
2153
2154
        // Hook to add more things on all pages within fiche DIV
2155
        $llxfooter = '';
2156
        $parameters = array();
2157
        $reshook = $hookmanager->executeHooks('llxFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2158
        if (empty($reshook)) {
2159
            $llxfooter .= $hookmanager->resPrint;
2160
        } elseif ($reshook > 0) {
2161
            $llxfooter = $hookmanager->resPrint;
2162
        }
2163
        if ($llxfooter) {
2164
            print $llxfooter;
2165
        }
2166
2167
        // Global html output events ($mesgs, $errors, $warnings)
2168
        dol_htmloutput_events($disabledoutputofmessages);
2169
2170
        // Code for search criteria persistence.
2171
        // $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
2172
        if (is_object($user) && !empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp)) {
2173
            // Clean and save data
2174
            foreach ($user->lastsearch_values_tmp as $key => $val) {
2175
                unset($_SESSION['lastsearch_values_tmp_' . $key]); // Clean array to rebuild it just after
2176
                if (count($val) && empty($_POST['button_removefilter']) && empty($_POST['button_removefilter_x'])) {
2177
                    if (empty($val['sortfield'])) {
2178
                        unset($val['sortfield']);
2179
                    }
2180
                    if (empty($val['sortorder'])) {
2181
                        unset($val['sortorder']);
2182
                    }
2183
                    dol_syslog('Save lastsearch_values_tmp_' . $key . '=' . json_encode($val, 0) . " (systematic recording of last search criteria)");
2184
                    $_SESSION['lastsearch_values_tmp_' . $key] = json_encode($val);
2185
                    unset($_SESSION['lastsearch_values_' . $key]);
2186
                }
2187
            }
2188
        }
2189
2190
2191
        $relativepathstring = $_SERVER["PHP_SELF"];
2192
        // Clean $relativepathstring
2193
        if (constant('DOL_URL_ROOT')) {
2194
            $relativepathstring = preg_replace('/^' . preg_quote(constant('DOL_URL_ROOT'), '/') . '/', '', $relativepathstring);
2195
        }
2196
        $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
2197
        $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
2198
        if (preg_match('/list\.php$/', $relativepathstring)) {
2199
            unset($_SESSION['lastsearch_contextpage_tmp_' . $relativepathstring]);
2200
            unset($_SESSION['lastsearch_page_tmp_' . $relativepathstring]);
2201
            unset($_SESSION['lastsearch_limit_tmp_' . $relativepathstring]);
2202
            unset($_SESSION['lastsearch_mode_tmp_' . $relativepathstring]);
2203
2204
            if (!empty($contextpage)) {
2205
                $_SESSION['lastsearch_contextpage_tmp_' . $relativepathstring] = $contextpage;
2206
            }
2207
            if (!empty($page) && $page > 0) {
2208
                $_SESSION['lastsearch_page_tmp_' . $relativepathstring] = $page;
2209
            }
2210
            if (!empty($limit) && $limit != $conf->liste_limit) {
2211
                $_SESSION['lastsearch_limit_tmp_' . $relativepathstring] = $limit;
2212
            }
2213
            if (!empty($mode)) {
2214
                $_SESSION['lastsearch_mode_tmp_' . $relativepathstring] = $mode;
2215
            }
2216
2217
            unset($_SESSION['lastsearch_contextpage_' . $relativepathstring]);
2218
            unset($_SESSION['lastsearch_page_' . $relativepathstring]);
2219
            unset($_SESSION['lastsearch_limit_' . $relativepathstring]);
2220
            unset($_SESSION['lastsearch_mode_' . $relativepathstring]);
2221
        }
2222
2223
        // Core error message
2224
        if (getDolGlobalString('MAIN_CORE_ERROR')) {
2225
            // Ajax version
2226
            if ($conf->use_javascript_ajax) {
2227
                $title = img_warning() . ' ' . $langs->trans('CoreErrorTitle');
2228
                print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
2229
            } else {
2230
                // html version
2231
                $msg = img_warning() . ' ' . $langs->trans('CoreErrorMessage');
2232
                print '<div class="error">' . $msg . '</div>';
2233
            }
2234
2235
            //define("MAIN_CORE_ERROR",0);      // Constant was defined and we can't change value of a constant
2236
        }
2237
2238
        print "\n\n";
2239
2240
        print '</div> <!-- End div class="fiche" -->' . "\n"; // End div fiche
2241
2242
        if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup')) {
2243
            print '</div> <!-- End div id-right -->' . "\n"; // End div id-right
2244
        }
2245
2246
        if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
2247
            print '</div> <!-- End div id-container -->' . "\n"; // End div container
2248
        }
2249
2250
        print "\n";
2251
        if ($comment) {
2252
            print '<!-- ' . $comment . ' -->' . "\n";
2253
        }
2254
2255
        printCommonFooter($zone);
2256
2257
        if (!empty($delayedhtmlcontent)) {
2258
            print $delayedhtmlcontent;
2259
        }
2260
2261
        if (!empty($conf->use_javascript_ajax)) {
2262
            print "\n" . '<!-- Includes JS Footer of Dolibarr -->' . "\n";
2263
            print '<script src="' . constant('BASE_URL') . '/core/js/lib_foot.js.php?lang=' . $langs->defaultlang . ($ext ? '&' . $ext : '') . '"></script>' . "\n";
2264
        }
2265
2266
        // Wrapper to add log when clicking on download or preview
2267
        if (isModEnabled('blockedlog') && is_object($object) && !empty($object->id) && $object->id > 0) {
2268
            if (in_array($object->element, array('facture')) && $object->statut > 0) {       // Restrict for the moment to element 'facture'
2269
                print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
2270
                ?>
2271
                <script>
2272
                    jQuery(document).ready(function () {
2273
                        $('a.documentpreview').click(function () {
2274
                            console.log("Call /blockedlog/ajax/block-add on a.documentpreview");
2275
                            $.post('<?php echo DOL_URL_ROOT . "/blockedlog/ajax/block-add.php" ?>'
2276
                                , {
2277
                                    id:<?php echo $object->id; ?>
2278
                                    , element: '<?php echo dol_escape_js($object->element) ?>'
2279
                                    , action: 'DOC_PREVIEW'
2280
                                    , token: '<?php echo currentToken(); ?>'
2281
                                }
2282
                            );
2283
                        });
2284
                        $('a.documentdownload').click(function () {
2285
                            console.log("Call /blockedlog/ajax/block-add a.documentdownload");
2286
                            $.post('<?php echo DOL_URL_ROOT . "/blockedlog/ajax/block-add.php" ?>'
2287
                                , {
2288
                                    id:<?php echo $object->id; ?>
2289
                                    , element: '<?php echo dol_escape_js($object->element) ?>'
2290
                                    , action: 'DOC_DOWNLOAD'
2291
                                    , token: '<?php echo currentToken(); ?>'
2292
                                }
2293
                            );
2294
                        });
2295
                    });
2296
                </script>
2297
                <?php
2298
            }
2299
        }
2300
2301
        // A div for the address popup
2302
        print "\n<!-- A div to allow dialog popup by jQuery('#dialogforpopup').dialog() -->\n";
2303
        print '<div id="dialogforpopup" style="display: none;"></div>' . "\n";
2304
2305
        // Add code for the asynchronous anonymous first ping (for telemetry)
2306
        // You can use &forceping=1 in parameters to force the ping if the ping was already sent.
2307
        $forceping = GETPOST('forceping', 'alpha');
2308
        if (($_SERVER["PHP_SELF"] == constant('BASE_URL') . '/index.php') || $forceping) {
2309
            //print '<!-- instance_unique_id='.$conf->file->instance_unique_id.' MAIN_FIRST_PING_OK_ID='.$conf->global->MAIN_FIRST_PING_OK_ID.' -->';
2310
            $hash_unique_id = dol_hash('dolibarr' . $conf->file->instance_unique_id, 'sha256');   // Note: if the global salt changes, this hash changes too so ping may be counted twice. We don't mind. It is for statistics purpose only.
2311
2312
            if (
2313
                !getDolGlobalString('MAIN_FIRST_PING_OK_DATE')
2314
                || (!empty($conf->file->instance_unique_id) && ($hash_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) && (getDolGlobalString('MAIN_FIRST_PING_OK_ID') != 'disabled'))
2315
                || $forceping
2316
            ) {
2317
                // No ping done if we are into an alpha version
2318
                if (strpos('alpha', DOL_VERSION) > 0 && !$forceping) {
2319
                    print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It is an alpha version -->\n";
2320
                } elseif (empty($_COOKIE['DOLINSTALLNOPING_' . $hash_unique_id]) || $forceping) { // Cookie is set when we uncheck the checkbox in the installation wizard.
2321
                    // MAIN_LAST_PING_KO_DATE
2322
                    // Disable ping if MAIN_LAST_PING_KO_DATE is set and is recent (this month)
2323
                    if (getDolGlobalString('MAIN_LAST_PING_KO_DATE') && substr($conf->global->MAIN_LAST_PING_KO_DATE, 0, 6) == dol_print_date(dol_now(), '%Y%m') && !$forceping) {
2324
                        print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. An error already occurred this month, we will try later. -->\n";
2325
                    } else {
2326
                        include_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
2327
2328
                        print "\n" . '<!-- Includes JS for Ping of Dolibarr forceping=' . $forceping . ' MAIN_FIRST_PING_OK_DATE=' . getDolGlobalString("MAIN_FIRST_PING_OK_DATE") . ' MAIN_FIRST_PING_OK_ID=' . getDolGlobalString("MAIN_FIRST_PING_OK_ID") . ' MAIN_LAST_PING_KO_DATE=' . getDolGlobalString("MAIN_LAST_PING_KO_DATE") . ' -->' . "\n";
2329
                        print "\n<!-- JS CODE TO ENABLE the anonymous Ping -->\n";
2330
                        $url_for_ping = getDolGlobalString('MAIN_URL_FOR_PING', "https://ping.dolibarr.org/");
2331
                        // Try to guess the distrib used
2332
                        $distrib = 'standard';
2333
                        if ($_SERVER["SERVER_ADMIN"] == 'doliwamp@localhost') {
2334
                            $distrib = 'doliwamp';
2335
                        }
2336
                        if (!empty($dolibarr_distrib)) {
2337
                            $distrib = $dolibarr_distrib;
2338
                        }
2339
                        ?>
2340
                        <script>
2341
                            jQuery(document).ready(function (tmp) {
2342
                                console.log("Try Ping with hash_unique_id is dol_hash('dolibarr'+instance_unique_id, 'sha256')");
2343
                                $.ajax({
2344
                                    method: "POST",
2345
                                    url: "<?php echo $url_for_ping ?>",
2346
                                    timeout: 500,     // timeout milliseconds
2347
                                    cache: false,
2348
                                    data: {
2349
                                        hash_algo: 'dol_hash-sha256',
2350
                                        hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
2351
                                        action: 'dolibarrping',
2352
                                        version: '<?php echo (float)DOL_VERSION; ?>',
2353
                                        entity: '<?php echo (int)$conf->entity; ?>',
2354
                                        dbtype: '<?php echo dol_escape_js($db->type); ?>',
2355
                                        country_code: '<?php echo $mysoc->country_code ? dol_escape_js($mysoc->country_code) : 'unknown'; ?>',
2356
                                        php_version: '<?php echo dol_escape_js(phpversion()); ?>',
2357
                                        os_version: '<?php echo dol_escape_js(version_os('smr')); ?>',
2358
                                        db_version: '<?php echo dol_escape_js(version_db()); ?>',
2359
                                        distrib: '<?php echo $distrib ? dol_escape_js($distrib) : 'unknown'; ?>',
2360
                                        token: 'notrequired'
2361
                                    },
2362
                                    success: function (data, status, xhr) {   // success callback function (data contains body of response)
2363
                                        console.log("Ping ok");
2364
                                        $.ajax({
2365
                                            method: 'GET',
2366
                                            url: '<?php echo constant('BASE_URL') . '/core/ajax/pingresult.php'; ?>',
2367
                                            timeout: 500,     // timeout milliseconds
2368
                                            cache: false,
2369
                                            data: {
2370
                                                hash_algo: 'dol_hash-sha256',
2371
                                                hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
2372
                                                action: 'firstpingok',
2373
                                                token: '<?php echo currentToken(); ?>'
2374
                                            }, // for update
2375
                                        });
2376
                                    },
2377
                                    error: function (data, status, xhr) {   // error callback function
2378
                                        console.log("Ping ko: " + data);
2379
                                        $.ajax({
2380
                                            method: 'GET',
2381
                                            url: '<?php echo constant('BASE_URL') . '/core/ajax/pingresult.php'; ?>',
2382
                                            timeout: 500,     // timeout milliseconds
2383
                                            cache: false,
2384
                                            data: {
2385
                                                hash_algo: 'dol_hash-sha256',
2386
                                                hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
2387
                                                action: 'firstpingko',
2388
                                                token: '<?php echo currentToken(); ?>'
2389
                                            },
2390
                                        });
2391
                                    }
2392
                                });
2393
                            });
2394
                        </script>
2395
                        <?php
2396
                    }
2397
                } else {
2398
                    $now = dol_now();
2399
                    print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It was disabled -->\n";
2400
                    include_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
2401
                    dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_DATE', dol_print_date($now, 'dayhourlog', 'gmt'), 'chaine', 0, '', $conf->entity);
2402
                    dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_ID', 'disabled', 'chaine', 0, '', $conf->entity);
2403
                }
2404
            }
2405
        }
2406
2407
        $parameters = array();
2408
        $reshook = $hookmanager->executeHooks('beforeBodyClose', $parameters); // Note that $action and $object may have been modified by some hooks
2409
        if ($reshook > 0) {
2410
            print $hookmanager->resPrint;
2411
        }
2412
2413
        print "</body>\n";
2414
        print "</html>\n";
2415
    }
2416
}