dolibarr 18.0.6
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 *
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 * (at your option) 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 * or see https://www.gnu.org/
18 */
19
31{
32 public $tool; // Store the selected tool
33
34 // If using fckeditor
35 public $editor;
36
37 // If not using fckeditor
38 public $content;
39 public $htmlname;
40 public $toolbarname;
41 public $toolbarstartexpanded;
42 public $rows;
43 public $cols;
44 public $height;
45 public $width;
46 public $uselocalbrowser;
47 public $readonly;
48 public $posx;
49 public $posy;
50
51
72 public function __construct($htmlname, $content, $width = '', $height = 200, $toolbarname = 'Basic', $toolbarlocation = 'In', $toolbarstartexpanded = false, $uselocalbrowser = 1, $okforextendededitor = true, $rows = 0, $cols = 0, $readonly = 0, $poscursor = array())
73 {
74 global $conf, $langs;
75
76 dol_syslog(get_class($this)."::DolEditor htmlname=".$htmlname." width=".$width." height=".$height." toolbarname=".$toolbarname);
77
78 if (!$rows) {
79 $rows = round($height / 20);
80 }
81 if (!$cols) {
82 $cols = ($width ?round($width / 6) : 80);
83 }
84 $shorttoolbarname = preg_replace('/_encoded$/', '', $toolbarname);
85
86 // Name of extended editor to use (FCKEDITOR_EDITORNAME can be 'ckeditor' or 'fckeditor')
87 $defaulteditor = 'ckeditor';
88 $this->tool = empty($conf->global->FCKEDITOR_EDITORNAME) ? $defaulteditor : $conf->global->FCKEDITOR_EDITORNAME;
89 $this->uselocalbrowser = $uselocalbrowser;
90 $this->readonly = $readonly;
91
92 // Check if extended editor is ok. If not we force textarea
93 if ((!isModEnabled('fckeditor') && $okforextendededitor != 'ace') || empty($okforextendededitor)) {
94 $this->tool = 'textarea';
95 }
96 if ($okforextendededitor === 'ace') {
97 $this->tool = 'ace';
98 }
99 //if ($conf->dol_use_jmobile) $this->tool = 'textarea'; // ckeditor and ace seems ok with mobile
100
101 // Define some properties
102 if (in_array($this->tool, array('textarea', 'ckeditor', 'ace'))) {
103 if ($this->tool == 'ckeditor' && !dol_textishtml($content)) { // We force content to be into HTML if we are using an advanced editor if content is not HTML.
104 $this->content = dol_nl2br($content);
105 } else {
106 $this->content = $content;
107 }
108 $this->htmlname = $htmlname;
109 $this->toolbarname = $shorttoolbarname;
110 $this->toolbarstartexpanded = $toolbarstartexpanded;
111 $this->rows = max(ROWS_3, $rows);
112 $this->cols = (preg_match('/%/', $cols) ? $cols : max(40, $cols)); // If $cols is a percent, we keep it, otherwise, we take max
113 $this->height = $height;
114 $this->width = $width;
115 $this->posx = empty($poscursor['x']) ? 0 : $poscursor['x'];
116 $this->posy = empty($poscursor['y']) ? 0 : $poscursor['y'];
117 }
118 }
119
120 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
134 public function Create($noprint = 0, $morejs = '', $disallowAnyContent = true, $titlecontent = '', $option = '', $moreparam = '', $morecss = '')
135 {
136 // phpcs:enable
137 global $conf, $langs;
138
139 $fullpage = false;
140 if (isset($conf->global->FCKEDITOR_ALLOW_ANY_CONTENT)) {
141 $disallowAnyContent = empty($conf->global->FCKEDITOR_ALLOW_ANY_CONTENT); // Only predefined list of html tags are allowed or all
142 }
143
144 $found = 0;
145 $out = '';
146
147 if (in_array($this->tool, array('textarea', 'ckeditor'))) {
148 $found = 1;
149 //$out.= '<textarea id="'.$this->htmlname.'" name="'.$this->htmlname.'" '.($this->readonly?' disabled':'').' rows="'.$this->rows.'"'.(preg_match('/%/',$this->cols)?' style="margin-top: 5px; width: '.$this->cols.'"':' cols="'.$this->cols.'"').' class="flat">';
150 // TODO We do not put the 'disabled' tag because on a read form, it change style with grey.
151 //print $this->content;
152 $out .= '<textarea id="'.$this->htmlname.'" name="'.$this->htmlname.'" rows="'.$this->rows.'"'.(preg_match('/%/', $this->cols) ? ' style="margin-top: 5px; width: '.$this->cols.'"' : ' cols="'.$this->cols.'"').' '.($moreparam ? $moreparam : '').' class="flat '.$morecss.'">';
153 $out .= htmlspecialchars($this->content);
154 $out .= '</textarea>';
155
156 if ($this->tool == 'ckeditor' && !empty($conf->use_javascript_ajax) && isModEnabled('fckeditor')) {
157 if (!defined('REQUIRE_CKEDITOR')) {
158 define('REQUIRE_CKEDITOR', '1');
159 }
160
161 $skin = getDolGlobalString('FCKEDITOR_SKIN', 'moono-lisa'); // default with ckeditor 4.6 : moono-lisa
162
163 $pluginstodisable = 'elementspath,save,flash,div,specialchar,anchor';
164 if (!empty($conf->dol_optimize_smallscreen)) {
165 $pluginstodisable .= ',scayt,wsc,find,undo';
166 }
167 if (empty($conf->global->FCKEDITOR_ENABLE_WSC)) { // spellchecker has end of life december 2021
168 $pluginstodisable .= ',wsc';
169 }
170 if (empty($conf->global->FCKEDITOR_ENABLE_PDF)) {
171 $pluginstodisable .= ',exportpdf';
172 }
173 $scaytautostartup = '';
174 if (!empty($conf->global->FCKEDITOR_ENABLE_SCAYT_AUTOSTARTUP)) {
175 $scaytautostartup = 'scayt_autoStartup: true,';
176 $scaytautostartup .= 'scayt_sLang: \''.dol_escape_js($langs->getDefaultLang()).'\',';
177 } else {
178 $pluginstodisable .= ',scayt';
179 }
180
181 $htmlencode_force = preg_match('/_encoded$/', $this->toolbarname) ? 'true' : 'false';
182
183 $out .= '<!-- Output ckeditor $disallowAnyContent='.dol_escape_htmltag($disallowAnyContent).' toolbarname='.dol_escape_htmltag($this->toolbarname).' -->'."\n";
184 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
185 $(document).ready(function () {
186 /* console.log("Run ckeditor"); */
187 /* if (CKEDITOR.loadFullCore) CKEDITOR.loadFullCore(); */
188 /* should be editor=CKEDITOR.replace but what if there is several editors ? */
189 tmpeditor = CKEDITOR.replace(\''.dol_escape_js($this->htmlname).'\',
190 {
191 /* property:xxx is same than CKEDITOR.config.property = xxx */
192 customConfig: ckeditorConfig,
193 removePlugins: \''.dol_escape_js($pluginstodisable).'\',
194 readOnly: '.($this->readonly ? 'true' : 'false').',
195 htmlEncodeOutput: '.dol_escape_js($htmlencode_force).',
196 allowedContent: '.($disallowAnyContent ? 'false' : 'true').', /* Advanced Content Filter (ACF) is own when allowedContent is false */
197 extraAllowedContent: \'a[target];div{float,display}\', /* Add the style float and display into div to default other allowed tags */
198 disallowedContent: '.($disallowAnyContent ? '\'\'' : '\'\'').', /* Tags that are not allowed */
199 fullPage: '.($fullpage ? 'true' : 'false').', /* if true, the html, header and body tags are kept */
200 toolbar: \''.dol_escape_js($this->toolbarname).'\',
201 toolbarStartupExpanded: '.($this->toolbarstartexpanded ? 'true' : 'false').',
202 width: '.($this->width ? '\''.dol_escape_js($this->width).'\'' : '\'\'').',
203 height: '.dol_escape_js($this->height).',
204 skin: \''.dol_escape_js($skin).'\',
205 '.$scaytautostartup.'
206 language: \''.dol_escape_js($langs->defaultlang).'\',
207 textDirection: \''.dol_escape_js($langs->trans("DIRECTION")).'\',
208 on : {
209 instanceReady : function( ev )
210 {
211 // Output paragraphs as <p>Text</p>.
212 this.dataProcessor.writer.setRules( \'p\', {
213 indent : false,
214 breakBeforeOpen : true,
215 breakAfterOpen : false,
216 breakBeforeClose : false,
217 breakAfterClose : true
218 });
219 }
220 },
221 disableNativeSpellChecker: '.(empty($conf->global->CKEDITOR_NATIVE_SPELLCHECKER) ? 'true' : 'false');
222
223 if ($this->uselocalbrowser) {
224 $out .= ','."\n";
225 // To use filemanager with old fckeditor (GPL)
226 $out .= ' filebrowserBrowseUrl : ckeditorFilebrowserBrowseUrl,';
227 $out .= ' filebrowserImageBrowseUrl : ckeditorFilebrowserImageBrowseUrl,';
228 //$out.= ' filebrowserUploadUrl : \''.DOL_URL_ROOT.'/includes/fckeditor/editor/filemanagerdol/connectors/php/upload.php?Type=File\',';
229 //$out.= ' filebrowserImageUploadUrl : \''.DOL_URL_ROOT.'/includes/fckeditor/editor/filemanagerdol/connectors/php/upload.php?Type=Image\',';
230 $out .= "\n";
231 // To use filemanager with ckfinder (Non free) and ckfinder directory is inside htdocs/includes
232 /* $out.= ' filebrowserBrowseUrl : \''.DOL_URL_ROOT.'/includes/ckfinder/ckfinder.html\',
233 filebrowserImageBrowseUrl : \''.DOL_URL_ROOT.'/includes/ckfinder/ckfinder.html?Type=Images\',
234 filebrowserFlashBrowseUrl : \''.DOL_URL_ROOT.'/includes/ckfinder/ckfinder.html?Type=Flash\',
235 filebrowserUploadUrl : \''.DOL_URL_ROOT.'/includes/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files\',
236 filebrowserImageUploadUrl : \''.DOL_URL_ROOT.'/includes/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Images\',
237 filebrowserFlashUploadUrl : \''.DOL_URL_ROOT.'/includes/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Flash\','."\n";
238 */
239 $out .= ' filebrowserWindowWidth : \'900\',
240 filebrowserWindowHeight : \'500\',
241 filebrowserImageWindowWidth : \'900\',
242 filebrowserImageWindowHeight : \'500\'';
243 }
244 $out .= ' })'.$morejs; // end CKEditor.replace
245 // Show the CKEditor javascript object once loaded is ready 'For debug)
246 //$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]); }); ';
247 $out .= '});'."\n"; // end document.ready
248 $out .= '</script>'."\n";
249 }
250 }
251
252 // Output editor ACE
253 // Warning: ace.js and ext-statusbar.js must be loaded by the parent page.
254 if (preg_match('/^ace/', $this->tool)) {
255 $found = 1;
256 $format = $option;
257
258 $out .= "\n".'<!-- Output Ace editor -->'."\n";
259
260 if ($titlecontent) {
261 $out .= '<div class="aceeditorstatusbar" id="statusBar'.$this->htmlname.'">'.$titlecontent;
262 $out .= ' &nbsp; - &nbsp; <a id="morelines" href="#" class="right morelines'.$this->htmlname.' reposition">'.dol_escape_htmltag($langs->trans("ShowMoreLines")).'</a> &nbsp; &nbsp; ';
263 $out .= '</div>';
264 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
265 $out .= 'jQuery(document).ready(function() {'."\n";
266 $out .= ' var aceEditor = window.ace.edit("'.$this->htmlname.'aceeditorid");
267 aceEditor.moveCursorTo('.($this->posy+1).','.$this->posx.');
268 aceEditor.gotoLine('.($this->posy+1).','.$this->posx.');
269 var StatusBar = window.ace.require("ace/ext/statusbar").StatusBar; // Init status bar. Need lib ext-statusbar
270 var statusBar = new StatusBar(aceEditor, document.getElementById("statusBar'.$this->htmlname.'")); // Init status bar. Need lib ext-statusbar
271
272 var oldNbOfLines = 0;
273 jQuery(".morelines'.$this->htmlname.'").click(function() {
274 var aceEditorClicked = window.ace.edit("'.$this->htmlname.'aceeditorid");
275 currentline = aceEditorClicked.getOption("maxLines");
276 if (oldNbOfLines == 0)
277 {
278 oldNbOfLines = currentline;
279 }
280 console.log("We click on more lines, oldNbOfLines is "+oldNbOfLines+", we have currently "+currentline);
281 if (currentline < 500)
282 {
283 aceEditorClicked.setOptions({ maxLines: 500 });
284 }
285 else
286 {
287 aceEditorClicked.setOptions({ maxLines: oldNbOfLines });
288 }
289 });
290 })';
291 $out .= '</script>'."\n";
292 }
293
294 $out .= '<pre id="'.$this->htmlname.'aceeditorid" style="'.($this->width ? 'width: '.$this->width.'px; ' : '');
295 $out .= ($this->height ? ' height: '.$this->height.'px; ' : '');
296 //$out.=" min-height: 100px;";
297 $out .= '">';
298 $out .= htmlspecialchars($this->content);
299 $out .= '</pre>';
300 $out .= '<input type="hidden" id="'.$this->htmlname.'_x" name="'.$this->htmlname.'_x">';
301 $out .= '<input type="hidden" id="'.$this->htmlname.'_y" name="'.$this->htmlname.'_y">';
302 $out .= '<textarea id="'.$this->htmlname.'" name="'.$this->htmlname.'" style="width:0px; height: 0px; display: none;">';
303 $out .= htmlspecialchars($this->content);
304 $out .= '</textarea>';
305
306 $out .= '<script nonce="'.getNonce().'" type="text/javascript">'."\n";
307 $out .= 'var aceEditor = window.ace.edit("'.$this->htmlname.'aceeditorid");
308
309 aceEditor.session.setMode("ace/mode/'.$format.'");
310 aceEditor.setOptions({
311 enableBasicAutocompletion: true, // the editor completes the statement when you hit Ctrl + Space. Need lib ext-language_tools.js
312 enableLiveAutocompletion: false, // the editor completes the statement while you are typing. Need lib ext-language_tools.js
313 showPrintMargin: false, // hides the vertical limiting strip
314 minLines: 10,
315 maxLines: '.(empty($this->height) ? '34' : (round($this->height / 10))).',
316 fontSize: "110%" // ensures that the editor fits in the environment
317 });
318
319 // defines the style of the editor
320 aceEditor.setTheme("ace/theme/chrome");
321 // hides line numbers (widens the area occupied by error and warning messages)
322 //aceEditor.renderer.setOption("showLineNumbers", false);
323 // ensures proper autocomplete, validation and highlighting of JavaScript code
324 //aceEditor.getSession().setMode("ace/mode/javascript_expression");
325 '."\n";
326
327 $out .= 'jQuery(document).ready(function() {
328 jQuery(".buttonforacesave").click(function() {
329 console.log("We click on savefile button for component '.dol_escape_js($this->htmlname).'");
330 var aceEditor = window.ace.edit("'.dol_escape_js($this->htmlname).'aceeditorid");
331 if (aceEditor) {
332 var cursorPos = aceEditor.getCursorPosition();
333 //console.log(cursorPos);
334 if (cursorPos) {
335 jQuery("#'.dol_escape_js($this->htmlname).'_x").val(cursorPos.column);
336 jQuery("#'.dol_escape_js($this->htmlname).'_y").val(cursorPos.row);
337 }
338 //console.log(aceEditor.getSession().getValue());
339 // Inject content of editor into the original HTML field.
340 jQuery("#'.dol_escape_js($this->htmlname).'").val(aceEditor.getSession().getValue());
341 /*if (jQuery("#'.dol_escape_js($this->htmlname).'").html().length > 0) return true;
342 else return false;*/
343 return true;
344 } else {
345 console.log("Failed to retrieve js object ACE from its name");
346 return false;
347 }
348 });
349 })';
350 $out .= '</script>'."\n";
351 }
352
353 if (empty($found)) {
354 $out .= 'Error, unknown value for tool '.$this->tool.' in DolEditor Create function.';
355 }
356
357 if ($noprint) {
358 return $out;
359 } else {
360 print $out;
361 }
362 }
363}
Class to manage a WYSIWYG editor.
Create($noprint=0, $morejs='', $disallowAnyContent=true, $titlecontent='', $option='', $moreparam='', $morecss='')
Output edit area inside the HTML stream.
__construct($htmlname, $content, $width='', $height=200, $toolbarname='Basic', $toolbarlocation='In', $toolbarstartexpanded=false, $uselocalbrowser=1, $okforextendededitor=true, $rows=0, $cols=0, $readonly=0, $poscursor=array())
Create an object to build an HTML area to edit a large string content.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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...
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120