dolibarr 24.0.0-beta
index.php
1<?php
2/*
3 * Copyright (C) 2025 Anthony Damhet <a.damhet@progiseize.fr>
4 * Copyright (C) 2025 Frédéric France <frederic.france@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20// Load Dolibarr environment
21require '../../../../main.inc.php';
22
30// Protection if external user
31if ($user->socid > 0) {
33}
34
35// Includes
36require_once DOL_DOCUMENT_ROOT . '/admin/tools/ui/class/documentation.class.php';
37
38// Load documentation translations
39$langs->load('uxdocumentation');
40
41//
42$documentation = new Documentation($db);
43$group = 'UxDolibarrContext';
44$experimentName = 'UxDolibarrContextHowItWork';
45
46$js = [
47 '/includes/ace/src/ace.js',
48 '/includes/ace/src/ext-statusbar.js',
49 '/includes/ace/src/ext-language_tools.js',
50];
51$css = [];
52
53// Output html head + body - Param is Title
54$documentation->docHeader($langs->trans($experimentName, $group), $js, $css);
55
56// Set view for menu and breadcrumb
57$documentation->view = [$group, $experimentName];
58
59// Output sidebar
60$documentation->showSidebar(); ?>
61
62<div class="doc-wrapper">
63
64 <?php $documentation->showBreadCrumb(); ?>
65
66 <div class="doc-content-wrapper">
67
68 <h1 class="documentation-title"><?php echo $langs->trans($group); ?> : <?php echo $langs->trans('UxDolibarrContextHowItWork'); ?></h1>
69
70 <?php $documentation->showSummary(); ?>
71
72 <div class="documentation-section">
73 <h2 id="titlesection-basicusage" class="documentation-title">Introduction</h2>
74
75 <p>
76 DolibarrContext is a secure global JavaScript context for Dolibarr.
77 It provides a single global object <code>window.Dolibarr</code>, which cannot be replaced.
78 It allows defining non-replaceable tools and managing hooks/events in a modular and secure way.
79 </p>
80
81 <p>
82 This system is designed to provide long-term flexibility and maintainability. You can define reusable tools
83 that encapsulate functionality such as standardized AJAX requests and responses, ensuring consistent data handling across Dolibarr modules.
84 For example, tools can be created to wrap API calls and automatically process returned data in a uniform format,
85 reducing repetitive code and preventing errors.
86 </p>
87
88 <p>
89 Beyond DOM-based events, DolibarrContext allows monitoring and reacting to business events using a
90 hook-like mechanism. For instance, you can listen to events such as
91 <code>Dolibarr.on('addline:load:productPricesList', function(data) { ... });</code>
92 without relying on DOM changes. This enables creating logic that reacts directly to application state changes.
93 </p>
94
95 <p>
96 Similarly, you can define tools that act as global helpers, like <code>Dolibarr.tools.setEventMessage()</code>.
97 This tool can display notifications (similar to PHP's <code>setEventMessage()</code> in Dolibarr),
98 initially using jNotify or any other library. In the future, the underlying library can change without affecting
99 the way modules or external code call this tool, maintaining compatibility and reducing maintenance.
100 </p>
101
102 <p>
103 In summary, DolibarrContext provides a secure, extensible foundation for adding tools, monitoring business events,
104 and standardizing interactions across Dolibarr's frontend modules.
105 </p>
106 </div>
107
108 <div class="documentation-section">
109 <h2 id="titlesection-console-help" class="documentation-title">Console help</h2>
110
111 <p>
112 Open your browser console with <code>F12</code> to view the available commands.<br/>
113 If the help does not appear automatically, type <code>Dolibarr.tools.showConsoleHelp();</code> in the console to display it.
114 </p>
115 </div>
116
117 <div class="documentation-section">
118 <h2 class="documentation-title">Dolibarr.log() and debugMode()</h2>
119
120 <p>
121 <code>Dolibarr.log()</code> is a lightweight logging utility provided by the Dolibarr JS context.
122 It does <strong>not</strong> replace <code>console.log()</code>, but it gives an important advantage:
123 you can enable or disable all logs globally using <code>Dolibarr.debugMode()</code>.
124 </p>
125
126 <h3>Why use Dolibarr.log() instead of console.log()?</h3>
127 <ul>
128 <li>You can enable or disable logging dynamically from the browser console.</li>
129 <li>Avoid polluting the console for end-users: logs appear only when debug mode is enabled.</li>
130 <li>Ideal for module development: switch between quiet mode and verbose mode instantly.</li>
131 <li>Useful in production debugging: you can activate logs without modifying any code.</li>
132 </ul>
133
134 <h3>How it works</h3>
135 <p>
136 When <code>debugMode</code> is disabled (default state), calls to <code>Dolibarr.log()</code> do nothing.
137 When enabled, <code>Dolibarr.log()</code> behaves like <code>console.log()</code>.
138 </p>
139
140 <?php
141 $lines = array(
142 '<script>',
143 ' // Log something (will only appear if debug mode is ON)',
144 ' Dolibarr.log("My debug message");',
145 '',
146 ' // Enable verbose logs',
147 ' Dolibarr.debugMode(true);',
148 '',
149 ' // Disable logs again',
150 ' Dolibarr.debugMode(false);',
151 '</script>',
152 );
153 $documentation->showCode($lines, 'php');
154 ?>
155
156 <h3>Summary</h3>
157 <ul>
158 <li><code>console.log()</code> → always prints messages, noisy, not controllable, but useful during active development and debugging.</li>
159 <li><code>Dolibarr.log()</code> → prints messages only when debug mode is ON; fully controllable. Ideal for Dolibarr core logs or when you want to keep logs available but silent in production.</li>
160 <li><code>Dolibarr.debugMode(true)</code> → enable verbose logs, activating <code>Dolibarr.log()</code> output.</li>
161 <li><code>Dolibarr.debugMode(false)</code> → disable all <code>Dolibarr.log()</code> output, silencing debug messages.</li>
162 </ul>
163
164 </div>
165
166
167 <div class="documentation-section">
168 <h2 id="titlesection-hooks" class="documentation-title">JS Dolibarr hooks</h2>
169
170 <p>
171 Dolibarr provides a hook system to allow modules and scripts to communicate with each other
172 through named events. There are two ways to listen to these events in JS:
173 <code>Dolibarr.on()</code> and <code>document.addEventListener()</code>.
174 </p>
175
176 <h3>Event listener example</h3>
177 <p>
178 You can use <code>Dolibarr.on()</code> to listen to a hook. The main difference with standard
179 document events is that the callback receives <strong>directly the data object</strong> passed
180 when the hook is executed, without needing to access <code>e.detail</code>.
181 </p>
182 <p>
183 For backward compatibility and standard DOM integration, the same hook can also be caught
184 using <code>document.addEventListener()</code>, but in this case the data is inside
185 <code>e.detail</code> and the event name is prefixed by <code>Dolibarr:</code> so for a hook named A event name is <code>Dolibarr:A</code>
186 </p>
187
188 <?php
189 $lines = array(
190 '<script>',
191 ' // Add a listener to the Dolibarr theEventName event',
192 ' Dolibarr.on(\'theEventName\', function(data) {',
193 ' console.log(\'Dolibarr theEventName\', data);',
194 ' });',
195 '',
196 ' // But this work too on document',
197 ' document.addEventListener(\'Dolibarr:theEventName\', function(e) {',
198 ' console.log(\'Dolibarr theEventName\', e.detail);',
199 ' });',
200 '</script>',
201 );
202 $documentation->showCode($lines, 'php'); ?>
203
204
205 <h3>Practical usage</h3>
206 <p>
207 When Dolibarr is ready (DOM loaded and JS context initialized), you can register your hooks
208 or trigger them. Both <code>Dolibarr.on()</code> and <code>document.addEventListener()</code>
209 are valid, but <code>Dolibarr.on()</code> is simpler and more convenient because you get the
210 data directly.
211 </p>
212 <?php
213 $lines = array(
214 '<script>',
215 ' document.addEventListener(\'Dolibarr:Ready\', function(e) {',
216 ' // the dom is ready and you are sure Dolibarr js context is loaded',
217 ' ...',
218 ' // Do your stuff',
219 ' ...',
220 '',
221 ' // Add a listener to the yourCustomHookName event with dolibarr.on()',
222 ' Dolibarr.on(\'yourCustomHookName\', function(data) {',
223 ' console.log(\'With Dolibarr.on : data will contain { data01: \'stuff\', data02: \'other stuff\' }\', data);',
224 ' });',
225 '',
226 ' // Or you can do : Add a listener to the yourCustomHookName document.addEventListener()',
227 ' document.addEventListener(\'Dolibarr:yourCustomHookName\', function(e) {',
228 ' console.log(\'With document.addEventListener : e.detail will contain { data01: \'stuff\', data02: \'other stuff\' }\', e.detail);',
229 ' });',
230 '',
231 ' // you can trigger js hooks',
232 ' document.getElementById(\'try-event-yourCustomHookName\').addEventListener(\'click\', function(e) {',
233 ' Dolibarr.executeHook(\'yourCustomHookName\', { data01: \'stuff\', data02: \'other stuff\' })',
234 ' });',
235 '',
236 ' ...',
237 ' // Do your stuff',
238 ' ...',
239
240 ' });',
241 '</script>',
242 );
243 $documentation->showCode($lines, 'php'); ?>
244
245 <div class="documentation-example">
246 Open your console <code>F12</code> and click on <button class="button" id="try-event-yourCustomHookName">try</button>
247 <script nonce="<?php print getNonce() ?>" >
248 document.addEventListener('Dolibarr:Ready', function(e) {
249 // the dom is ready and you are sure Dolibarr js context is loaded
250 // Add a listener to the yourCustomHookName event
251 Dolibarr.on('yourCustomHookName', function(data) {
252 console.log('With Dolibarr.on : data will contain { data01: stuff, data02: other stuff }', data);
253 });
254
255 document.addEventListener('Dolibarr:yourCustomHookName', function(e) {
256 console.log('With document.addEventListener : e.detail will contain { data01: stuff, data02: other stuff }', e.detail);
257 });
258
259 document.getElementById('try-event-yourCustomHookName').addEventListener('click', function(e) {
260 // you can create js hooks
261 Dolibarr.executeHook('yourCustomHookName', { data01: 'stuff', data02: 'other stuff' })
262 });
263
264 });
265 </script>
266
267 </div>
268
269 </div>
270
271
272
273 <div id="titlesection-event-init-vs-ready" class="documentation-section">
274 <h2 class="documentation-title">Difference between Dolibarr:Init and Dolibarr:Ready event</h2>
275
276 <p>
277 Dolibarr provides two main initialization events for its JavaScript context: <code>Dolibarr:Init</code> and <code>Dolibarr:Ready</code>.
278 Understanding their difference is important when developing modules or tools.
279 </p>
280
281 <ul>
282 <li>
283 <strong>Dolibarr:Init</strong> is triggered immediately when the Dolibarr context is created.
284 This event is intended for:
285 <ul>
286 <li>Defining or registering new tools via <code>Dolibarr.defineTool()</code>.</li>
287 <li>Setting context variables (<code>Dolibarr.setContextVar()</code> / <code>Dolibarr.setContextVars()</code>).</li>
288 <li>Preparing configuration that must be available before the DOM is fully loaded.</li>
289 </ul>
290 It occurs <em>before</em> <code>Dolibarr:Ready</code>, so it is ideal for setup tasks that other tools may depend on.
291 </li>
292
293 <li>
294 <strong>Dolibarr:Ready</strong> is triggered once the DOM is ready, similar to <code>$(document).ready()</code> in jQuery.
295 This event is intended for:
296 <ul>
297 <li>Running code that interacts with the DOM.</li>
298 <li>Attaching event listeners to elements on the page.</li>
299 <li>Executing functionality that requires all tools and context variables to be fully initialized.</li>
300 </ul>
301 </li>
302 </ul>
303
304 <p>
305 In short, use <code>Dolibarr:Init</code> for setting up tools and context variables, and <code>Dolibarr:Ready</code> for code that needs the DOM and fully initialized context.
306 </p>
307
308 <h3>Examples of usage</h3>
309 <?php
310 $lines = array(
311 '<script>',
312 ' // Example: Dolibarr:Init - define a tool and set context variables early',
313 ' document.addEventListener(\'Dolibarr:Init\', function(e) {',
314 ' console.log("Init event fired, Dolibarr is initialised and receive context vars a tools");',
315 ' });',
316 '',
317 ' // Example: Dolibarr:Ready - interact with DOM and use tools',
318 ' document.addEventListener(\'Dolibarr:Ready\', function(e) {',
319 ' console.log("Ready event fired, DOM is ready");',
320 '',
321 '',
322 ' // Attach event listener to a DOM element',
323 ' const btn = document.getElementById("myButton");',
324 ' if(btn) {',
325 ' btn.addEventListener("click", function() {',
326 ' alert("Button clicked! Context value: " + Dolibarr.getContextVar("mySetting"));',
327 ' });',
328 ' }',
329 ' });',
330 '</script>',
331 );
332 $documentation->showCode($lines, 'php'); ?>
333
334
335 <p>
336 In summary:
337 <ul>
338 <li><code>Dolibarr:Init</code> → early setup, tools, context variables, configuration.</li>
339 <li><code>Dolibarr:Ready</code> → DOM is ready, safe to manipulate elements and use tools defined in Init.</li>
340 </ul>
341 </p>
342 </div>
343
344 <div class="documentation-section">
345 <h2 id="titlesection-await-hooks" class="documentation-title">Async Hooks (Await Hooks) - sequential execution</h2>
346
347 <p>
348 Dolibarr supports <strong>asynchronous hooks</strong> using <code>Dolibarr.onAwait()</code> and <code>Dolibarr.executeHookAwait()</code>.
349 These hooks allow you to register functions that execute <em>in sequence</em> and can modify data before passing it to the next hook.
350 They are useful for complex workflows where multiple modules or scripts need to process or enrich the same data asynchronously.
351 </p>
352
353 <p>
354 Each hook can optionally specify <code>before</code> or <code>after</code> to control the execution order relative to other hooks.
355 Every hook registration returns a unique <code>id</code>, which can be used to reference or unregister the hook later.
356 </p>
357
358 <p>
359 Unlike standard synchronous hooks registered with <code>Dolibarr.on()</code>, await hooks return a <code>Promise</code> when executed.
360 This means you can <code>await</code> their results in your code, and any asynchronous operations inside a hook (e.g., API calls, timers) will be handled correctly before moving to the next hook.
361 </p>
362
363 <?php
364 $lines = array(
365 '<script nonce="<?php print getNonce() ?>">',
366 ' document.addEventListener(\'Dolibarr:Ready\', async function(e) {',
367 '',
368 ' // Register async hooks will be executed in first place',
369 ' Dolibarr.onAwait(\'calculateDiscount\', async function(order) {',
370 ' order.total *= 0.9; // Apply 10% discount',
371 ' return order;',
372 ' }, { id: \'discount10\' });',
373 '',
374 ' // Register async hooks will be executed in third place',
375 ' Dolibarr.onAwait(\'calculateDiscount\', async function(order) {',
376 ' if(order.total > 1000) order.total -= 50; // Extra discount over 1000',
377 ' return order;',
378 ' }, { id: \'discountOver1000\', after: \'discount10\' });',
379 '',
380 ' // Register async hooks will be executed in second place',
381 ' // this hook item as no id so plus10HookItemId will receive a unique random id ',
382 ' let plus10HookItemId = Dolibarr.onAwait(\'calculateDiscount\', async function(order) {',
383 ' order.newObjectAttribute = \'My value\';',
384 ' order.total += 10;',
385 ' return order;',
386 ' }, { before: \'discountOver1000\' });',
387 '',
388 ' document.getElementById(\'try-event-yourCustomAwaitHookName\').addEventListener(\'click\', async function(e) {',
389 ' // Execute all registered await hooks sequentially',
390 ' let order = {total: 1200};',
391 ' order = await Dolibarr.executeHookAwait(\'calculateDiscount\', order);',
392 ' console.log(order); // order.total : 1200 -> 1080 -> 1090 -> 1040',
393 ' });',
394 '',
395 ' });',
396 '</script>',
397 );
398 $documentation->showCode($lines, 'php'); ?>
399
400 <div class="documentation-example">
401 Open your console <code>F12</code> and click on <button class="button" id="try-event-yourCustomAwaitHookName">try</button>
402
403 <script nonce="<?php print getNonce() ?>">
404 document.addEventListener('Dolibarr:Ready', async function(e) {
405
406 // Register async hooks will be executed in first place
407 Dolibarr.onAwait('calculateDiscount', async function(order) {
408 order.total *= 0.9; // Apply 10% discount
409 return order;
410 }, { id: 'discount10' });
411
412 // Register async hooks will be executed in third place
413 Dolibarr.onAwait('calculateDiscount', async function(order) {
414 if(order.total > 1000) order.total -= 50; // Extra discount over 1000
415 return order;
416 }, { id: 'discountOver1000', after: 'discount10' });
417
418 // Register async hooks will be executed in second place
419 Dolibarr.onAwait('calculateDiscount', async function(order) {
420 order.newObjectAttribute = 'My value';
421 order.total+= 10;
422 return order;
423 }, { before: 'discountOver1000' });
424
425 document.getElementById('try-event-yourCustomAwaitHookName').addEventListener('click', async function(e) {
426 // Execute all registered await hooks sequentially
427 let order = {total: 1200};
428 order = await Dolibarr.executeHookAwait('calculateDiscount', order);
429 console.log(order); // order.total : 1200 -> 1080 -> 1090 -> 1040
430 });
431
432 });
433 </script>
434 </div>
435
436 </div>
437
438 <div class="documentation-section">
439 <h2 id="titlesection-dom-initnewcontent" class="documentation-title">
440 initNewContent event system
441 </h2>
442
443 <p>
444 The <strong>initNewContent</strong> event is a standardized Dolibarr mechanism
445 to re-initialize UI components on dynamically added content.
446 Use it whenever you inject new DOM elements via AJAX, templates, or other dynamic updates.
447 </p>
448
449 <h3 id="titlesection-usecase-tooltips" class="documentation-title">
450 Use Case example: Dynamic Tooltips
451 </h3>
452
453 <p>
454 In a typical Dolibarr page, tooltips are initialized on page load for all elements
455 that have the class <code>.classfortooltip</code>. This works perfectly for static content.
456 </p>
457
458 <p>
459 However, when a section of the page is dynamically recreated or loaded via AJAX,
460 the new elements with <code>.classfortooltip</code> do not automatically have tooltips,
461 because the initialization script has already run on the initial DOM and is not rerun for the new elements.
462 </p>
463
464 <p>
465 The <strong>initNewContent</strong> mechanism solves this problem by providing a standardized hook
466 to re-initialize all interactive components on newly added DOM elements.
467 Developers can listen to <code>initNewContent</code> and re-run tooltip initialization
468 (or any other dynamic behavior) only on the new elements or their children, ensuring consistency and avoiding duplication.
469 </p>
470
471 <p>
472 This approach guarantees that tooltips, dialogs, and other interactive components
473 remain functional even when content is injected or updated asynchronously.
474 </p>
475
476 <p>
477 In addition to <code>document.ready</code> or <code>$(document).ready()</code>,
478 listen to <strong>initNewContent</strong> to ensure that tooltips, dialogs, or other interactive components
479 are properly initialized on any new DOM fragment added dynamically.
480 </p>
481
482
483 <div class="documentation-example">
484 <p>
485 <button class="button" id="try-no-initNewContent">Test without event</button>
486 <button class="button" id="try-initNewContent">Test with initNewContent event</button>
487 </p>
488 <div id="initNewContent-test-container"></div>
489
490 <style>
491 /* Animation for highlighting new content */
492 @keyframes highlightfortest {
493 from { background-color: #fffa8d; }
494 to { background-color: transparent; }
495 }
496 .highlightfortest {
497 padding: 10px;
498 animation: highlightfortest 1s ease-out;
499 }
500 </style>
501 <div id="idfortooltiponclick_doc-event-dialog-test" class="classfortooltiponclicktext" title="The title" style="display: none" >Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec elit venenatis, bibendum dui in, tristique dolor. In hac habitasse platea dictumst. Vestibulum consectetur quam non felis fringilla mollis pretium vel nibh. Pellentesque congue risus et laoreet blandit. Aliquam orci ipsum, gravida id leo eget, molestie pulvinar sem. Nulla sed felis et lacus tristique finibus. Cras ornare tincidunt. Aenean hendrerit volutpat efficitur. Integer vestibulum dui eget lectus pulvinar, vel mattis odio facilisis. Etiam convallis scelerisque lobortis. Mauris tristique, quam dignissim sollicitudin sodales, elit ligula venenatis neque, sit amet interdum lacus tellus id tellus. Mauris eu pretium turpis. Proin porta sem eget nisl vulputate vehicula.</div>
502 <script nonce="<?php print getNonce() ?>">
503 document.addEventListener('Dolibarr:Ready', function(e) {
504 const container = document.getElementById('initNewContent-test-container');
505
506 document.getElementById('try-no-initNewContent').addEventListener('click', function() {
507 container.innerHTML = `<span class="classfortooltip highlightfortest" title="this is the title">A text with a tooltip but the tooltip isn't load</span>
508 and <span class="classfortooltiponclick highlightfortest" dolid="doc-event-dialog-test" style="cursor: pointer;" >A text with a tooltip to click but the tooltip isn't load</span>`;
509 });
510
511 document.getElementById('try-initNewContent').addEventListener('click', function() {
512 container.innerHTML = `<span class="classfortooltip highlightfortest" title="this is the title">A text with a tooltip and the tooltip is loaded</span>
513 And <span class="classfortooltiponclick highlightfortest" dolid="doc-event-dialog-test" style="cursor: pointer;" >A text with a tooltip to click and the tooltip is loaded</span>`;
514 Dolibarr.initNewContent(container);
515 });
516 });
517 </script>
518
519
520 </div>
521 <?php
522 $lines = array(
523 '<div id="idfortooltiponclick_doc-event-dialog-test" class="classfortooltiponclicktext" title="The title" >Lorem ipsum .....</div>',
524 '<script nonce="<?php print getNonce() ?>">',
525 'document.addEventListener("Dolibarr:Ready", function(e) {',
526 ' const container = document.getElementById("initNewContent-test-container");',
527 '',
528 ' // Insert content without calling initNewContent',
529 ' document.getElementById("try-no-initNewContent").addEventListener("click", function() {',
530 ' container.innerHTML = `<span class="classfortooltip highlightfortest" title="this is the title">A text with a tooltip but the tooltip isn\'t load</span>',
531 ' and <span class="classfortooltiponclick highlightfortest" dolid="doc-event-dialog-test" style="cursor: pointer;">A text with a tooltip to click but the tooltip isn\'t load</span>`;',
532 ' });',
533 '',
534 ' // Insert content and trigger initNewContent',
535 ' document.getElementById("try-initNewContent").addEventListener("click", function() {',
536 ' container.innerHTML = `<span class="classfortooltip highlightfortest" title="this is the title">A text with a tooltip and the tooltip is loaded</span>',
537 ' and <span class="classfortooltiponclick highlightfortest" dolid="doc-event-dialog-test" style="cursor: pointer;">A text with a tooltip to click and the tooltip is loaded</span>`;',
538 ' Dolibarr.initNewContent(container);',
539 ' });',
540 '});',
541 '</script>',
542 );
543 $documentation->showCode($lines, 'php'); ?>
544
545 <h3 id="titlesection-usecase-tooltips" class="documentation-title">
546 How to use it
547 </h3>
548
549 <p>
550 The event handler receives an object with the property <code>targets</code>,
551 which is an array of DOM elements or jQuery collections to initialize. Each element can be:
552 </p>
553
554 <ul>
555 <li>a container with child elements to initialize</li>
556 <li>or a direct element that needs initialization</li>
557 </ul>
558
559 <h4>Example: Trigger initNewContent manually on a container</h4>
560
561 <?php
562 $lines = array(
563 '<script nonce="<?php print getNonce() ?>">',
564 ' document.addEventListener(\'Dolibarr:Ready\', function(e) {',
565 ' /* [... code that dynamically reloads part of the DOM ...] */',
566 '',
567 ' /**',
568 ' * true: only include the children of each target element',
569 ' * false: include the target elements themselves',
570 ' */',
571 ' const applyToChildrenOnly = true;',
572 '',
573 ' // Trigger initNewContent manually on a jQuery container',
574 ' Dolibarr.initNewContent($("#myContainer"), applyToChildrenOnly);',
575 '',
576 ' // Trigger initNewContent manually on a vanilla JS element',
577 ' const element = document.getElementById("myContainer");',
578 ' Dolibarr.initNewContent(element, applyToChildrenOnly);',
579 ' });',
580 '</script>',
581 );
582 $documentation->showCode($lines, 'php'); ?>
583
584 <p>
585 Dolibarr provides a custom event system to properly initialize dynamic content.
586 Always use <strong>initNewContent</strong> when working with AJAX-injected fragments or
587 dynamically created elements instead of relying solely on jQuery document ready.
588 </p>
589
590
591
592 <h4>Example in pure JS style: listening to initNewContent</h4>
593 <?php
594 $lines = array(
595 '<script nonce="<?php print getNonce() ?>">',
596 ' Dolibarr.on("initNewContent", ({ targets }) => {',
597 ' targets.forEach(root => {',
598 '',
599 ' // Array to store all matching dialog elements',
600 ' const dialogs = [];',
601 '',
602 ' // Include the root element if it matches the selector',
603 ' if (root.matches(".classfortooltiponclicktext")) {',
604 ' dialogs.push(root);',
605 ' }',
606 '',
607 ' // Add all descendants matching the selector',
608 ' dialogs.push(...root.querySelectorAll(".classfortooltiponclicktext"));',
609 '',
610 ' // Initialize each dialog element',
611 ' dialogs.forEach(el => {',
612 ' // Your code to initialize the tooltip/dialog or other stuff',
613 ' });',
614 ' });',
615 ' });',
616 '</script>',
617 );
618 $documentation->showCode($lines, 'php');
619 ?>
620
621 <h4>Compact version in pure JS</h4>
622 <?php
623 $lines = array(
624 '<script nonce="<?php print getNonce() ?>">',
625 ' Dolibarr.on("initNewContent", ({ targets }) => {',
626 ' targets.forEach(root => {',
627 ' const dialogs = [',
628 ' ...(root.matches(".classfortooltiponclicktext") ? [root] : []),',
629 ' ...root.querySelectorAll(".classfortooltiponclicktext")',
630 ' ];',
631 ' dialogs.forEach(el => {',
632 ' // Initialize tooltip/dialog or other stuff here',
633 ' });',
634 ' });',
635 ' });',
636 '</script>',
637 );
638 $documentation->showCode($lines, 'php');
639 ?>
640
641 <h4>Example in jQuery style</h4>
642 <?php
643 $lines = array(
644 '<script nonce="<?php print getNonce() ?>">',
645 ' Dolibarr.on("initNewContent", ({ targets }) => {',
646 ' targets.forEach($root => {',
647 ' const $dialogs = $root',
648 ' .filter(".classfortooltiponclicktext")',
649 ' .add($root.find(".classfortooltiponclicktext"));',
650 ' $dialogs.each(function () {',
651 ' const $el = $(this);',
652 ' // Initialize tooltip/dialog behavior or other stuff here',
653 ' });',
654 ' });',
655 ' });',
656 '</script>',
657 );
658 $documentation->showCode($lines, 'php');
659 ?>
660
661 </div>
662
663
664
665 <div class="documentation-section">
666 <h2 id="titlesection-create-tool-example" class="documentation-title">Example of creating a new context tool</h2>
667
668 <h3>Defining Tools</h3>
669 <p>
670 You can define reusable and protected tools in the Dolibarr context using <code>Dolibarr.defineTool</code>.
671 </p>
672 <p>See also <code>dolibarr-context.mock.js</code> for defining all standard Dolibarr tools and creating mock implementations to improve code completion and editor support.</p>
673 <p><b>Note :</b> a tool can be a class not only a function</p>
674
675 <?php
676 $lines = array(
677 '<script>',
678 'document.addEventListener(\'Dolibarr:Init\', function(e) {',
679 ' // Define a simple tool',
680 ' let overwrite = false; // Once a tool is defined, it cannot be replaced.',
681 ' Dolibarr.defineTool(\'alertUser\', (msg) => alert(\'[Dolibarr] \' + msg), overwrite);',
682 '});',
683 '',
684 'document.addEventListener(\'Dolibarr:Ready\', function(e) {',
685 ' // Use the tool',
686 ' Dolibarr.tools.alertUser(\'hello world\');',
687 '});',
688 '</script>',
689 );
690 $documentation->showCode($lines, 'php'); ?>
691
692 <h3>Protected Tools</h3>
693 <p>
694 Once a tool is defined on overwrite false, it cannot be replaced. Attempting to redefine it without overwrite will throw an error:
695 </p>
696
697 <?php
698 $lines = array(
699 '<script>',
700 ' try {',
701 ' Dolibarr.defineTool(\'alertUser\', () => {});',
702 ' } catch (e) {',
703 ' console.error(e.message);',
704 ' }',
705 '</script>',
706 );
707 $documentation->showCode($lines, 'php'); ?>
708
709 <h3>Reading Tools</h3>
710 <p>
711 You can read the list of available tools using <code>Dolibarr.tools</code>. It returns a frozen copy:
712 </p>
713
714 <?php
715 $lines = array(
716 '<script>',
717 ' console.log(Dolibarr.tools);',
718 ' if(Dolibarr.checkToolExist(\'Tool name to check\')){/* ... */}else{/* ... */}; ',
719 '</script>',
720 );
721 $documentation->showCode($lines, 'php'); ?>
722
723 </div>
724
725 <?php include __DIR__ . '/inc_seteventmessage.php'; ?>
726
727
728 <div class="documentation-section">
729 <h2 id="titlesection-contextvars" class="documentation-title">Set and use context vars</h2>
730
731 <p>
732 The <strong>Context Vars</strong> system allows you to define and manage variables that are globally accessible within the Dolibarr JavaScript context. These variables can store configuration data, URLs, tokens, user IDs, object references, or any other values needed by your frontend code and tools.
733 By using context vars, you can:
734 <ul>
735 <li>Pass server-side data (from PHP) to JavaScript safely and consistently.</li>
736 <li>Provide reusable configuration for Dolibarr tools, widgets, or modules without hardcoding values.</li>
737 <li>Define overridable or non-overridable vars to protect critical values while allowing flexible overrides when necessary.</li>
738 <li>Use <code>Dolibarr.setContextVar</code> for single values or <code>Dolibarr.setContextVars</code> to pass multiple values at once.</li>
739 <li>Access these variables anywhere in your code via <code>Dolibarr.getContextVar(key)</code>.</li>
740 <li>Ensure that all your modules and tools can rely on consistent and up-to-date context information, improving maintainability and interoperability.</li>
741 </ul>
742 This system is particularly useful for setting up base URLs, API endpoints, user-specific information, or runtime data that needs to be shared across multiple Dolibarr frontend tools.
743 </p>
744
745 <h3>Add context var (overridable or not)</h3>
746 <?php
747 $lines = array(
748 '<script nonce="<?php print getNonce() ?>" >',
749 ' document.addEventListener(\'Dolibarr:Init\', function(e) {',
750 ' // Add no overridable context var',
751 ' Dolibarr.setContextVar(\'yourKey\', \'YourValue\');',
752 '',
753 ' // Add overridable context var',
754 ' Dolibarr.setContextVar(\'yourKey2\', \'YourValue\', true);',
755 ' });',
756 '</script>',
757 );
758 $documentation->showCode($lines, 'php');
759 ?>
760
761
762 <h3>Add multiple context vars (overridable or not)</h3>
763 <?php
764 $lines = array(
765 '<?php',
766 ' $contextConst = [',
767 ' \'DOL_URL_ROOT\' => DOL_URL_ROOT,',
768 ' \'token\' => newToken(),',
769 ' \'cardObjectElement\' => $object->element,',
770 ' \'cardObjectId\' => $object->id,',
771 ' \'currentUserId\' => $user->id',
772 ' // ...',
773 ' ];',
774 '',
775 ' $contextVars = [',
776 ' \'lastCardDataRefresh\' => time(),',
777 ' // ...',
778 ' ]',
779 '?>',
780 '<script nonce="<?php print getNonce() ?>" >',
781 ' document.addEventListener(\'Dolibarr:Init\', function(e) {',
782 ' Dolibarr.setContextVars(<?php print json_encode($contextConst); ?>);',
783 ' Dolibarr.setContextVars(<?php print json_encode($contextVars); ?>, true);',
784 ' });',
785 '</script>',
786 );
787 $documentation->showCode($lines, 'php');
788 ?>
789
790 <h3>Get context var</h3>
791 <?php
792 $lines = array(
793 '<script nonce="<?php print getNonce() ?>" >',
794 ' document.addEventListener(\'Dolibarr:Ready\', function(e) {',
795 ' let url = Dolibarr.getContextVar(\'DOL_URL_ROOT\', \'The optional fallback value\'));',
796 ' console.log(url);',
797 ' });',
798 '</script>',
799 );
800 $documentation->showCode($lines, 'php');
801 ?>
802
803 </div>
804
805 </div>
806
807
808
809
810</div>
811
812</div>
813<?php
814// Output close body + html
815$documentation->docFooter();
816?>
Class Context.
Class to manage UI documentation.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
multi select button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
a disabled
editval_textarea active
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:487
$conf db user
Active Directory does not allow anonymous connections.
Definition repair.php:134
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.