dolibarr 24.0.0-beta
doleditor.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2006-2008 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2021 Gaëtan MAISON <gm@ilad.org>
4 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * or see https://www.gnu.org/
20 */
21
33{
37 public $tool; // Store the selected tool
38
39 // If using fckeditor
43 public $editor;
44
45 // If not using fckeditor
49 public $content;
53 public $htmlname;
57 public $toolbarname;
61 public $toolbarstartexpanded;
65 public $rows;
69 public $cols;
73 public $height;
77 public $width;
81 public $uselocalbrowser;
85 public $readonly;
89 public $posx;
93 public $posy;
94
95
115 public function __construct($htmlname, $content, $width = '', $height = 200, $toolbarname = 'Basic', $notused = '', $toolbarstartexpanded = false, $uselocalbrowser = -1, $okforextendededitor = true, $rows = 0, $cols = '', $readonly = 0, $poscursor = array()) // @phpstan-ignore constructor.unusedParameter
116 {
117 global $conf;
118
119 dol_syslog(get_class($this)."::DolEditor htmlname=".$htmlname." width=".$width." height=".$height." toolbarname=".$toolbarname." uselocalbrowser=".$uselocalbrowser);
120
121 if ($uselocalbrowser) {
122 // This may not be supported by new generation of WYSIWYG editors.
123 $uselocalbrowser = getDolGlobalInt("WYSIWYG_ALLOW_UPLOAD_MEDIA_FILES");
124 }
125
126 if (!$rows) {
127 $rows = round($height / 20);
128 }
129 if (!$cols) {
130 $cols = ($width ? round($width / 6) : 80);
131 }
132 $shorttoolbarname = preg_replace('/_encoded$/', '', $toolbarname);
133
134 // Name of extended editor to use (FCKEDITOR_EDITORNAME can be 'ckeditor' or 'fckeditor')
135 $defaulteditor = 'ckeditor';
136 $this->tool = getDolGlobalString('FCKEDITOR_EDITORNAME', $defaulteditor);
137 $this->uselocalbrowser = $uselocalbrowser;
138 $this->readonly = $readonly;
139
140 // Check if extended editor is ok. If not we force textarea
141 if ((!isModEnabled('fckeditor') && $okforextendededitor !== 'ace') || empty($okforextendededitor)) {
142 $this->tool = 'textarea';
143 }
144 if ($okforextendededitor === 'ace') {
145 $this->tool = 'ace';
146 }
147 //if ($conf->dol_use_jmobile) $this->tool = 'textarea'; // ckeditor and ace seems ok with mobile
148 if (empty($conf->use_javascript_ajax)) { // If no javascript, we force use of textarea
149 $this->tool = 'textarea';
150 }
151
152 if (isset($poscursor['find'])) {
153 $posy = 0;
154 $lines = explode("\n", $content);
155 $nblines = count($lines);
156 for ($i = 0 ; $i < $nblines ; $i++) {
157 if (preg_match('/'.$poscursor['find'].'/', $lines[$i])) {
158 $posy = $i;
159 break;
160 }
161 }
162 if ($posy != 0) {
163 $poscursor['y'] = $posy;
164 }
165 }
166
167 // Define some properties
168 if (in_array($this->tool, array('textarea', 'ckeditor', 'tinymce', 'ace'))) {
169 if (in_array($this->tool, array('ckeditor', 'tinymce')) && !dol_textishtml($content)) { // We force content to be into HTML if we are using an advanced editor if content is not HTML.
170 $this->content = dol_nl2br($content);
171 } else {
172 $this->content = $content;
173 }
174 $this->htmlname = $htmlname;
175 $this->toolbarname = $shorttoolbarname;
176 $this->toolbarstartexpanded = $toolbarstartexpanded;
177 $this->rows = max(ROWS_3, $rows);
178 $this->cols = (preg_match('/%/', $cols) ? $cols : max(40, $cols)); // If $cols is a percent, we keep it, otherwise, we take max
179 $this->height = $height;
180 $this->width = $width;
181 $this->posx = empty($poscursor['x']) ? 0 : $poscursor['x'];
182 $this->posy = empty($poscursor['y']) ? 0 : $poscursor['y'];
183 }
184 }
185
186 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
203 public function Create($noprint = 0, $morejs = '', $restrictContent = true, $titlecontent = '', $option = '', $moreparam = '', $morecss = '')
204 {
205 // phpcs:enable
206 global $conf, $langs;
207
208 $fullpage = false;
209
210 // syntax is [] for attributes and {} for value inside style
211 $extraAllowedContent = 'a[target];';
212 $extraAllowedContent .= 'section[contenteditable,id];';
213 $extraAllowedContent .= 'table{border-spacing};';
214 $extraAllowedContent .= 'td{padding};';
215 $extraAllowedContent .= 'p{margin-left,margin-right,margin-top,margin-bottom,padding,line-height};';
216 $extraAllowedContent .= 'div{background-color,color,display,float,height,margin,margin-top,margin-bottom,padding,padding-left,padding-right,padding-top,padding-bottom,width,border-top-left-radius,border-top-right-radius,border-bottom-left-radius,border-bottom-right-radius,box-shadow}';
217
218 if (is_string($restrictContent)) {
219 $extraAllowedContent = $restrictContent;
220 }
221 if (isset($conf->global->FCKEDITOR_ALLOW_ANY_CONTENT)) {
222 $restrictContent = !getDolGlobalString('FCKEDITOR_ALLOW_ANY_CONTENT'); // Only predefined list of html tags are allowed or all
223 }
224
225 $found = 0;
226 $out = '';
227
228 $this->content = (string) $this->content; // to avoid htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated
229
230 if (in_array($this->tool, array('textarea', 'ckeditor', 'tinymce'))) {
231 $found = 1;
232
233 $out .= "\n".'<!-- Output textarea '.dol_string_nohtmltag($this->tool).' '.dol_string_nohtmltag($this->htmlname).' toolbarname = '.dol_string_nohtmltag($this->toolbarname).' -->'."\n";
234
235 // Note: We do not put the attribute 'disabled' tag because on a read form, it change style with grey.
236 $out .= '<textarea id="'.$this->htmlname.'" name="'.$this->htmlname.'"';
237 $out .= ' rows="'.$this->rows.'"';
238 if (preg_match('/%/', $this->cols)) { // ->cols is a percent
239 $out .= ' style="margin-top: 5px; width: ';
240 if ($this->tool == 'tinymce') {
241 $out .= $this->cols;
242 } else {
243 $out .= 'calc('.$this->cols.' - 20px)'; // The with in percent minus the margin.
244 }
245 $out .= '"';
246 } else {
247 $out .= ' cols="'.$this->cols.'"';
248 }
249 $out .= ' '.($moreparam ? $moreparam : '');
250 $out .= ' class="flat '.dol_string_nohtmltag($this->toolbarname).' '.$morecss.'">';
251 $out .= htmlspecialchars($this->content);
252 $out .= '</textarea>';
253
254 if ($this->tool == 'ckeditor' && !empty($conf->use_javascript_ajax) && isModEnabled('fckeditor')) {
255 if (!defined('REQUIRE_CKEDITOR')) {
256 define('REQUIRE_CKEDITOR', '1');
257 }
258
259 $skin = getDolGlobalString('FCKEDITOR_SKIN', 'moono-lisa'); // default with ckeditor 4.6 : moono-lisa
260
261 $pluginstodisable = 'elementspath,save,flash,div,anchor';
262 if (!getDolGlobalString('FCKEDITOR_ENABLE_SPECIALCHAR')) {
263 $pluginstodisable .= ',specialchar';
264 }
265 if (!empty($conf->dol_optimize_smallscreen)) {
266 $pluginstodisable .= ',scayt,wsc,find,undo';
267 }
268 if (!getDolGlobalString('FCKEDITOR_ENABLE_WSC')) { // spellchecker has end of life december 2021
269 $pluginstodisable .= ',wsc';
270 }
271 if (!getDolGlobalString('FCKEDITOR_ENABLE_PDF')) {
272 $pluginstodisable .= ',exportpdf';
273 }
274 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2) {
275 $this->uselocalbrowser = 0; // Can't use browser to navigate into files. Only links with "<img src=data:..." are allowed.
276 }
277 $scaytautostartup = '';
278 if (getDolGlobalString('FCKEDITOR_ENABLE_SCAYT_AUTOSTARTUP')) {
279 $scaytautostartup = 'scayt_autoStartup: true,';
280 $scaytautostartup .= 'scayt_sLang: \''.dol_escape_js($langs->getDefaultLang()).'\',';
281 } else {
282 $pluginstodisable .= ',scayt';
283 }
284
285 $htmlencode_force = preg_match('/_encoded$/', $this->toolbarname) ? 'true' : 'false';
286
287 $out .= '<!-- Output ckeditor disallowAnyContent='.dol_escape_htmltag((string) $restrictContent).' toolbarname='.dol_escape_htmltag($this->toolbarname).' -->'."\n";
288 //$out .= '<style>#cke_1_top { height: 34px !important; }</style>';
289 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
290 $(document).ready(function () {
291 /* console.log("Run ckeditor"); */
292 /* if (CKEDITOR.loadFullCore) CKEDITOR.loadFullCore(); */
293 /* should be editor=CKEDITOR.replace but what if there is several editors ? */
294 tmpeditor = CKEDITOR.replace(\''.dol_escape_js($this->htmlname).'\',
295 {
296 /* property: xxx is same than CKEDITOR.config.property = xxx */
297 customConfig: ckeditorConfig,
298 removePlugins: \''.dol_escape_js($pluginstodisable).'\',
299 versionCheck: false,
300 readOnly: '.($this->readonly ? 'true' : 'false').',
301 htmlEncodeOutput: '.dol_escape_js($htmlencode_force).',
302 allowedContent: '.($restrictContent ? 'false' : 'true').', /* Advanced Content Filter (ACF) is on when allowedContent is false */
303 extraAllowedContent: \''.dol_escape_js($extraAllowedContent).'\', /* Allow a tag with attribute target, allow section tag and allow the style float and display into div to default other allowed tags */
304 disallowedContent: \'\', /* Tags that are not allowed */
305 fullPage: '.($fullpage ? 'true' : 'false').', /* if true, the html, header and body tags are kept */
306 toolbar: \''.dol_escape_js($this->toolbarname).'\',
307 toolbarStartupExpanded: '.($this->toolbarstartexpanded ? 'true' : 'false').',
308 width: '.($this->width ? '\''.dol_escape_js($this->width).'\'' : '\'\'').',
309 height: '.dol_escape_js((string) $this->height).',
310 skin: \''.dol_escape_js($skin).'\',
311 '.$scaytautostartup.'
312 language: \''.dol_escape_js($langs->defaultlang).'\',
313 textDirection: \''.dol_escape_js($langs->trans("DIRECTION")).'\',
314 on : {
315 instanceReady : function(ev) {
316 console.log(\'ckeditor '.dol_escape_js($this->htmlname).' instanceReady\');
317
318 /* If we found the attribute required on source div, we remove it (not compatible with ckeditor) */
319 /* Disabled, because attribute "required" should never be used on fields for doleditor */
320 /* jQuery("#'.dol_escape_js($this->htmlname).'").attr("required", false); */
321
322 // Output paragraphs as <p>Text</p>.
323 this.dataProcessor.writer.setRules( \'p\', {
324 indent : false,
325 breakBeforeOpen : true,
326 breakAfterOpen : false,
327 breakBeforeClose : false,
328 breakAfterClose : true
329 });
330 },
331 },
332 disableNativeSpellChecker: '.(getDolGlobalString('CKEDITOR_NATIVE_SPELLCHECKER') ? 'false' : 'true');
333
334 if ($this->uselocalbrowser) {
335 $out .= ','."\n";
336 // To use filemanager with old fckeditor (GPL)
337 // Note: ckeditorFilebrowserBrowseUrl and ckeditorFilebrowserImageBrowseUrl are defined in header by main.inc.php. They include url to browser with url of upload connector in parameter
338 $out .= ' filebrowserBrowseUrl : ckeditorFilebrowserBrowseUrl,';
339 $out .= ' filebrowserImageBrowseUrl : ckeditorFilebrowserImageBrowseUrl,';
340 $out .= "\n";
341 $out .= ' filebrowserWindowWidth : \'900\',
342 filebrowserWindowHeight : \'500\',
343 filebrowserImageWindowWidth : \'900\',
344 filebrowserImageWindowHeight : \'500\'';
345 }
346 $out .= ' })'.$morejs; // end CKEditor.replace
347 // Show the CKEditor javascript object once loaded is ready (For debug)
348 //$out .= '; CKEDITOR.on(\'instanceReady\', function(ck) { ck.editor.removeMenuItem(\'maximize\'); ck.editor.removeMenuItem(\'Undo\'); ck.editor.removeMenuItem(\'undo\'); console.log(ck.editor); console.log(ck.editor.toolbar[0]); }); ';
349 $out .= '});'."\n"; // end document.ready
350 $out .= '</script>'."\n";
351 }
352
353 if ($this->tool == 'tinymce' && !empty($conf->use_javascript_ajax) && isModEnabled('fckeditor')) {
354 if (!defined('REQUIRE_TINYMCE')) {
355 define('REQUIRE_TINYMCE', '1');
356 }
357
358 $htmlencode_force = preg_match('/_encoded$/', $this->toolbarname) ? 'true' : 'false';
359 $pickerenabled = $this->uselocalbrowser ? 'true' : 'false';
360
361 $out .= '<!-- Output tinymce toolbarname='.dol_escape_htmltag($this->toolbarname).' -->'."\n";
362 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
363 $out .= '$(document).ready(function () {'."\n";
364 $out .= ' if (typeof tinymce === "undefined") {'."\n";
365 $out .= ' console.error("TinyMCE library not loaded. Check that .../includes/tinymce/tinymce/tinymce.min.js exists and FCKEDITOR_EDITORNAME=tinymce.");'."\n";
366 $out .= ' return;'."\n";
367 $out .= ' }'."\n";
368 $out .= ' var toolbarName = "'.dol_escape_js($this->toolbarname).'";'."\n";
369 $out .= ' var toolbars = (window.dolTinymceToolbars || {});'."\n";
370 $out .= ' var toolbarStr = toolbars[toolbarName] || toolbars["dolibarr_details"] || "undo redo | bold italic | link | code";'."\n";
371 $out .= ' var pluginsStr = (typeof window.dolTinymcePluginsFor === "function") ? window.dolTinymcePluginsFor(toolbarName) : "advlist autolink lists link image charmap preview anchor searchreplace visualblocks code fullscreen table help wordcount";'."\n";
372 if (!getDolGlobalString('FCKEDITOR_ENABLE_SPECIALCHAR')) {
373 $out .= 'pluginsStr = pluginsStr.replace(\' charmap\', \'\');'."\n";
374 }
375 $out .= ' var tinyLang = "'.dol_escape_js($langs->defaultlang).'";'."\n";
376 $out .= ' var tinyConf = {'."\n";
377 $out .= ' selector: "textarea#'.dol_escape_js($this->htmlname).'",'."\n";
378 $out .= ' toolbar: toolbarStr,'."\n";
379 $out .= ' plugins: pluginsStr,'."\n";
380 $out .= ' menubar: false,'."\n";
381 if (!getDolGlobalString('WYSIWYG_TINYMCE_ENABLE_STATUS_BAR')) {
382 $out .= ' statusbar: false,'."\n";
383 }
384 $out .= ' branding: false,'."\n";
385 $out .= ' promotion: false,'."\n";
386 $out .= ' license_key: "gpl",'."\n";
387 $out .= ' readonly: '.($this->readonly ? 'true' : 'false').','."\n";
388 $out .= ' height: '.((int) $this->height + 80).','."\n";
389 if ($this->width) {
390 $out .= ' width: "'.dol_escape_js($this->width).'",'."\n";
391 }
392 $out .= ' directionality: "'.dol_escape_js(strtolower($langs->trans("DIRECTION")) === 'rtl' ? 'rtl' : 'ltr').'",'."\n";
393 $out .= ' forced_root_block: false,'."\n"; // equivalent of CKEDITOR.ENTER_BR
394 $out .= ' convert_urls: false,'."\n";
395 $out .= ' relative_urls: false,'."\n";
396 $out .= ' entity_encoding: "raw",'."\n";
397 $out .= ' protect: [/<\?[\s\S]*?\?>/g],'."\n"; // protect PHP tags like CKEditor did
398 $out .= ' paste_data_images: true,'."\n";
399 $fontlist = 'arial,tahoma,verdana,helvetica';
400 if (getDolGlobalString('THEME_FONT_FAMILY')) {
401 $fontlist = getDolGlobalString('THEME_FONT_FAMILY').', '.$fontlist;
402 }
403
404 $out .= ' content_style: \'p { margin: 6px 0 6px 0; line-height: 1.4em; } .mce-content-body { font-size: 0.94em; margin: 10px; font-family: '.$fontlist.' } \',';
405 $out .= ' toolbar_mode: "sliding",'."\n";
406 $out .= ' browser_spellcheck: '.(getDolGlobalString('CKEDITOR_NATIVE_SPELLCHECKER') ? 'true' : 'false').','."\n";
407 $out .= ' language: (tinyLang && tinyLang.indexOf("en") === 0) ? "en" : tinyLang,'."\n";
408 $out .= ' htmlEncodeOutput: '.dol_escape_js($htmlencode_force).','."\n";
409 if ($pickerenabled === 'true') {
410 $out .= ' file_picker_types: "file image media",'."\n";
411 $out .= ' file_picker_callback: function (cb, value, meta) {'."\n";
412 $out .= ' var url = (meta.filetype === "image") ? window.tinymceFilebrowserImageBrowseUrl : window.tinymceFilebrowserBrowseUrl;'."\n";
413 $out .= ' if (!url) { return; }'."\n";
414 $out .= ' var w = window.open(url, "tinymcePicker", "width=900,height=500");'."\n";
415 $out .= ' window.dolTinymcePickerCb = function (picked) { if (picked) { cb(picked); } if (w) { w.close(); } };'."\n";
416 $out .= ' },'."\n";
417 }
418 $out .= ' setup: function (editor) {'."\n";
419 $out .= ' editor.on("init", function () {'."\n";
420 $out .= ' console.log("tinymce '.dol_escape_js($this->htmlname).' instanceReady");'."\n";
421 $out .= ' });'."\n";
422 $out .= ' }'."\n";
423 $out .= ' };'."\n";
424 $out .= ' tinymce.init(tinyConf)'.$morejs.';'."\n";
425 $out .= '});'."\n";
426 $out .= '</script>'."\n";
427 }
428 }
429
430 // Output editor ACE
431 // Warning: ace.js and ext-statusbar.js must be loaded by the parent page.
432 if (preg_match('/^ace/', $this->tool)) {
433 $found = 1;
434 $format = $option;
435
436 $out .= "\n".'<!-- Output Ace editor '.dol_string_nohtmltag($this->htmlname).' -->'."\n";
437
438 if ($titlecontent) {
439 $out .= '<div class="aceeditorstatusbar" id="statusBar'.$this->htmlname.'">'.$titlecontent;
440 $out .= ' &nbsp; - &nbsp; <span id="morelines" class="right classlink cursorpointer morelines'.$this->htmlname.'">'.dol_escape_htmltag($langs->trans("ShowMoreLines")).'</span> &nbsp; &nbsp; ';
441 $out .= '</div>';
442 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
443 $out .= 'jQuery(document).ready(function() {'."\n";
444 $out .= ' var aceEditor = window.ace.edit("'.dol_escape_all($this->htmlname).'aceeditorid");
445 aceEditor.moveCursorTo('.($this->posy + 1).','.$this->posx.');
446 aceEditor.gotoLine('.($this->posy + 1).','.$this->posx.');
447 var StatusBar = window.ace.require("ace/ext/statusbar").StatusBar; // Init status bar. Need lib ext-statusbar
448 var statusBar = new StatusBar(aceEditor, document.getElementById("statusBar'.dol_escape_all($this->htmlname).'")); // Init status bar. Need lib ext-statusbar
449
450 var oldNbOfLines = 0;
451 jQuery(".morelines'.dol_escape_all($this->htmlname).'").click(function() {
452 var aceEditorClicked = window.ace.edit("'.$this->htmlname.'aceeditorid");
453 currentline = aceEditorClicked.getOption("maxLines");
454 if (oldNbOfLines == 0)
455 {
456 oldNbOfLines = currentline;
457 }
458 console.log("We click on more lines, oldNbOfLines is "+oldNbOfLines+", we have currently "+currentline);
459 if (currentline < 500)
460 {
461 aceEditorClicked.setOptions({ maxLines: 500 });
462 }
463 else
464 {
465 aceEditorClicked.setOptions({ maxLines: oldNbOfLines });
466 }
467 });
468 })';
469 $out .= '</script>'."\n";
470 }
471
472 $out .= '<pre id="'.$this->htmlname.'aceeditorid" style="'.($this->width ? 'width: '.$this->width.'px; ' : '');
473 $out .= ($this->height ? ' height: '.$this->height.'px; ' : '');
474 //$out.=" min-height: 100px;";
475 $out .= '">';
476 $out .= htmlspecialchars($this->content);
477 $out .= '</pre>';
478 $out .= '<input type="hidden" id="'.$this->htmlname.'_x" name="'.$this->htmlname.'_x">';
479 $out .= '<input type="hidden" id="'.$this->htmlname.'_y" name="'.$this->htmlname.'_y">';
480 $out .= '<textarea id="'.$this->htmlname.'" name="'.$this->htmlname.'" style="width:0px; height: 0px; display: none;">';
481 $out .= htmlspecialchars($this->content);
482 $out .= '</textarea>';
483
484 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
485 $out .= 'var aceEditor = window.ace.edit("'.$this->htmlname.'aceeditorid");
486
487 aceEditor.session.setMode("ace/mode/'.$format.'");
488 aceEditor.setReadOnly('.($this->readonly ? 'true' : 'false').');
489 aceEditor.setOptions({
490 enableBasicAutocompletion: true, // the editor completes the statement when you hit Ctrl + Space. Need lib ext-language_tools.js
491 enableLiveAutocompletion: false, // the editor completes the statement while you are typing. Need lib ext-language_tools.js
492 //enableSnippets: true, // ???
493 showPrintMargin: false, // hides the vertical limiting strip
494 minLines: 10,
495 maxLines: '.(empty($this->height) ? '34' : (round(($this->height - 60) / 19))).', // we remove 60 for the ace toolbar + bottom status line. 19 seems the height in px required for 1 line.
496 fontSize: "110%" // ensures that the editor fits in the environment
497 });
498
499 // defines the style of the editor
500 aceEditor.setTheme("ace/theme/chrome");
501
502 // hides line numbers (widens the area occupied by error and warning messages)
503 //aceEditor.renderer.setOption("showLineNumbers", false);
504 // ensures proper autocomplete, validation and highlighting of JavaScript code
505 //aceEditor.getSession().setMode("ace/mode/javascript_expression");'."\n";
506
507 // If page is PAGE_CONTENT to edit HTML web page in web site module, we add some autocompletion
508 if ($this->htmlname == 'PAGE_CONTENT') {
509 $out .= '
510 // Add custom function in the autocompletion
511 var customCompleter = {
512 getCompletions: function(editor, session, pos, prefix, callback) {
513 var wordList = [
514 { caption: \'dol_escape_all\', value: \'dol_escape_all(string)\', meta: \'custom\' },
515 { caption: \'dol_escape_js\', value: \'dol_escape_js(string)\', meta: \'custom\' },
516 { caption: \'includeContainer\', value: \'includeContainer(alias_of_container_to_include)\', meta: \'custom\' },
517 { caption: \'redirectToContainer\', value: \'redirectToContainer(alias_of_container_to_redirect_to)\', meta: \'custom\' },
518 { caption: \'getImageFromHtmlContent\', value: \'getImageFromHtmlContent(websitepage->htmlcontent)\', meta: \'custom\' },
519 ];
520 callback(null, wordList.map(function(word) {
521 return {
522 caption: word.caption,
523 value: word.value,
524 meta: word.meta
525 };
526 }));
527 }
528 };
529 aceEditor.completers = [customCompleter];
530 '."\n";
531 }
532
533 $out .= 'jQuery(document).ready(function() {';
534 $out .= ' jQuery(".buttonforacesave").click(function() {
535 console.log("We click on button (with class .buttonforacesave) that must fill ace fields for component '.dol_escape_js($this->htmlname).'");
536 var aceEditor = window.ace.edit("'.dol_escape_js($this->htmlname).'aceeditorid");
537 if (aceEditor) {
538 var cursorPos = aceEditor.getCursorPosition();
539 //console.log(cursorPos);
540 if (cursorPos) {
541 jQuery("#'.dol_escape_js($this->htmlname).'_x").val(cursorPos.column);
542 jQuery("#'.dol_escape_js($this->htmlname).'_y").val(cursorPos.row);
543 }
544 //console.log(aceEditor.getSession().getValue());
545 // Inject content of editor into the original HTML field.
546 jQuery("#'.dol_escape_js($this->htmlname).'").val(aceEditor.getSession().getValue());
547 /*if (jQuery("#'.dol_escape_js($this->htmlname).'").html().length > 0) return true;
548 else return false;*/
549 return true;
550 } else {
551 console.log("Failed to retrieve js object ACE from its name");
552 return false;
553 }
554 });
555 })';
556 $out .= '</script>'."\n";
557 }
558
559 if (empty($found)) {
560 $out .= 'Error, unknown value for tool '.$this->tool.' in DolEditor Create function.';
561 }
562
563 if ($noprint) {
564 return $out;
565 } else {
566 print $out;
567 }
568 }
569}
Class to manage a WYSIWYG editor.
Create($noprint=0, $morejs='', $restrictContent=true, $titlecontent='', $option='', $moreparam='', $morecss='')
Output edit area inside the HTML stream.
__construct($htmlname, $content, $width='', $height=200, $toolbarname='Basic', $notused='', $toolbarstartexpanded=false, $uselocalbrowser=-1, $okforextendededitor=true, $rows=0, $cols='', $readonly=0, $poscursor=array())
Create an object to build an HTML area to edit a large string content.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into JavaScript code.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
dol_escape_all($stringtoescape)
Returns text escaped for all protocols (so only alpha chars and numbers)
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
$fontlist
Definition style.css.php:75
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