1: <?php
2: /*
3: You may not change or alter any portion of this comment or credits
4: of supporting developers from this source code or any supporting source code
5: which is considered copyrighted (c) material of the original comment or credit authors.
6:
7: This program is distributed in the hope that it will be useful,
8: but WITHOUT ANY WARRANTY; without even the implied warranty of
9: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10: */
11:
12: /**
13: * TinyMCE adapter for XOOPS
14: *
15: * @copyright (c) 2000-2016 XOOPS Project (www.xoops.org)
16: * @license GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
17: * @package class
18: * @subpackage editor
19: * @since 2.3.0
20: * @author Taiwen Jiang <phppp@users.sourceforge.net>
21: * @author Lucio Rota <lucio.rota@gmail.com>
22: * @author Laurent JEN <dugris@frxoops.org>
23: */
24: class TinyMCE
25: {
26: public $rootpath;
27: public $config = array();
28: public $setting = array();
29: public $xoopsPlugins = array();
30: public static $LastOfElementsTinymce = '';
31: public static $ListOfElementsTinymce = array();
32:
33: // PHP 5 Constructor
34: /**
35: * @param $config
36: */
37: public function __construct($config)
38: {
39: $this->setConfig($config);
40: $this->rootpath = $this->config['rootpath'] . '/tinymce/jscripts/tiny_mce';
41: $this->xoopsPlugins = $this->get_xoopsPlugins();
42: self::$LastOfElementsTinymce = $this->config['elements'];
43: self::$ListOfElementsTinymce[] = self::$LastOfElementsTinymce;
44: }
45:
46: /**
47: * @param $config
48: *
49: * @return TinyMCE
50: */
51: public function &instance($config)
52: {
53: static $instance;
54: if (!isset($instance)) {
55: $instance = new TinyMCE($config);
56: } else {
57: $instance->setConfig($config);
58: }
59:
60: return $instance;
61: }
62:
63: /**
64: * @param $config
65: */
66: public function setConfig($config)
67: {
68: foreach ($config as $key => $val) {
69: $this->config[$key] = $val;
70: }
71: }
72:
73: /**
74: * @return bool
75: */
76: public function init()
77: {
78: // list of configured options
79: $configured = array();
80:
81: // Load default settings
82: if (file_exists($GLOBALS['xoops']->path('var/configs/tinymce.php')) && is_readable($GLOBALS['xoops']->path('var/configs/tinymce.php'))) {
83: $this->setting = include($GLOBALS['xoops']->path('var/configs/tinymce.php'));
84: } else {
85: $this->setting = include __DIR__ . '/settings.php';
86: }
87:
88:
89: // get editor language (from ...)
90: if (isset($this->config['language']) && is_readable(XOOPS_ROOT_PATH . $this->rootpath . '/langs/' . $this->config['language'] . '.js')) {
91: $this->setting['language'] = $this->config['language'];
92: $configured[] = 'language';
93: }
94:
95: $this->setting['content_css'] = implode(',', $this->loadCss());
96: $configured[] = 'content_css';
97:
98: if (!empty($this->config['theme']) && is_dir(XOOPS_ROOT_PATH . $this->rootpath . '/themes/' . $this->config['theme'])) {
99: $this->setting['theme'] = $this->config['theme'];
100: $configured[] = 'theme';
101: }
102:
103: if (!empty($this->config['mode'])) {
104: $this->setting['mode'] = $this->config['mode'];
105: $configured[] = 'mode';
106: }
107:
108: // load all plugins except the plugins in setting["exclude_plugins"]
109: $this->setting['plugins'] = implode(',', $this->loadPlugins());
110: $configured[] = 'plugins';
111:
112: if ($this->setting['theme'] !== 'simple') {
113: if (empty($this->config['buttons'])) {
114: $this->config['buttons'][] = array(
115: 'before' => '',
116: 'add' => '');
117: $this->config['buttons'][] = array(
118: 'before' => '',
119: 'add' => '');
120: $this->config['buttons'][] = array(
121: 'before' => '',
122: 'add' => '');
123: }
124: $i = 0;
125: foreach ($this->config['buttons'] as $button) {
126: ++$i;
127: if (isset($button['before'])) {
128: $this->setting['theme_' . $this->setting['theme'] . "_buttons{$i}_add_before"] = $button['before'];
129: }
130: if (isset($button['add'])) {
131: $this->setting['theme_' . $this->setting['theme'] . "_buttons{$i}_add"] = $button['add'];
132: }
133: if (isset($button[''])) {
134: $this->setting['theme_' . $this->setting['theme'] . "_buttons{$i}"] = $button[''];
135: }
136: }
137: $configured[] = 'buttons';
138:
139: if (isset($this->config['toolbar_location'])) {
140: $this->setting['theme_' . $this->setting['theme'] . '_toolbar_location'] = $this->config['toolbar_location'];
141: $configured[] = 'toolbar_location';
142: } else {
143: $this->setting['theme_' . $this->setting['theme'] . '_toolbar_location'] = 'top';
144: }
145:
146: if (isset($this->config['toolbar_align'])) {
147: $this->setting['theme_' . $this->setting['theme'] . '_toolbar_align'] = $this->config['toolbar_align'];
148: $configured[] = 'toolbar_align';
149: } else {
150: $this->setting['theme_' . $this->setting['theme'] . '_toolbar_align'] = 'left';
151: }
152:
153: if (isset($this->config['statusbar_location'])) {
154: $this->setting['theme_' . $this->setting['theme'] . '_statusbar_location'] = $this->config['statusbar_location'];
155: $configured[] = 'statusbar_location';
156: }
157:
158: if (isset($this->config['path_location'])) {
159: $this->setting['theme_' . $this->setting['theme'] . '_path_location'] = $this->config['path_location'];
160: $configured[] = 'path_location';
161: }
162:
163: if (isset($this->config['resize_horizontal'])) {
164: $this->setting['theme_' . $this->setting['theme'] . '_resize_horizontal'] = $this->config['resize_horizontal'];
165: $configured[] = 'resize_horizontal';
166: }
167:
168: if (isset($this->config['resizing'])) {
169: $this->setting['theme_' . $this->setting['theme'] . '_resizing'] = $this->config['resizing'];
170: $configured[] = 'resizing';
171: }
172:
173: if (!empty($this->config['fonts'])) {
174: $this->setting['theme_' . $this->setting['theme'] . '_fonts'] = $this->config['fonts'];
175: $configured[] = 'fonts';
176: }
177:
178: for ($i = 1; $i <= 4; ++$i) {
179: $buttons = array();
180: if (isset($this->setting['theme_' . $this->setting['theme'] . "_buttons{$i}"])) {
181: $checklist = explode(',', $this->setting['theme_' . $this->setting['theme'] . "_buttons{$i}"]);
182: foreach ($checklist as $plugin) {
183: if (strpos(strtolower($plugin), 'xoops') != false) {
184: if (in_array($plugin, $this->xoopsPlugins)) {
185: $buttons[] = $plugin;
186: }
187: } else {
188: $buttons[] = $plugin;
189: }
190: }
191: $this->setting['theme_' . $this->setting['theme'] . "_buttons{$i}"] = implode(',', $buttons);
192: }
193: }
194: }
195:
196: $configured = array_unique($configured);
197: foreach ($this->config as $key => $val) {
198: if (isset($this->setting[$key]) || in_array($key, $configured)) {
199: continue;
200: }
201: $this->setting[$key] = $val;
202: }
203:
204: if (!is_dir(XOOPS_ROOT_PATH . $this->rootpath . '/themes/' . $this->setting['theme'] . '/docs/' . $this->setting['language'] . '/')) {
205: $this->setting['docs_language'] = 'en';
206: }
207:
208: unset($this->config, $configured);
209:
210: return true;
211: }
212:
213: // load all plugins execpt the plugins in setting["exclude_plugins"]
214: /**
215: * @return array
216: */
217: public function loadPlugins()
218: {
219: $plugins = array();
220: $plugins_list = XoopsLists::getDirListAsArray(XOOPS_ROOT_PATH . $this->rootpath . '/plugins');
221: if (empty($this->setting['plugins'])) {
222: $plugins = $plugins_list;
223: } else {
224: $plugins = array_intersect(explode(',', $this->setting['plugins']), $plugins_list);
225: }
226: if (!empty($this->setting['exclude_plugins'])) {
227: $plugins = array_diff($plugins, explode(',', $this->setting['exclude_plugins']));
228: }
229: if (!empty($this->config['plugins'])) {
230: $plugins = array_merge($plugins, $this->config['plugins']);
231: }
232:
233: return $plugins;
234: }
235:
236: // return all xoops plugins
237: /**
238: * @return array
239: */
240: public function get_xoopsPlugins()
241: {
242: $xoopsPlugins = array();
243: $allplugins = XoopsLists::getDirListAsArray(XOOPS_ROOT_PATH . $this->rootpath . '/plugins');
244: foreach ($allplugins as $plugin) {
245: if (strpos(strtolower($plugin), 'xoops') != false && file_exists(XOOPS_ROOT_PATH . $this->config['rootpath'] . "/include/$plugin.php")) {
246: if ($right = @include XOOPS_ROOT_PATH . $this->config['rootpath'] . "/include/$plugin.php") {
247: $xoopsPlugins[$plugin] = $plugin;
248: }
249: }
250: }
251:
252: return $xoopsPlugins;
253: }
254:
255: /**
256: * @param string $css_file
257: *
258: * @return array
259: */
260: public function loadCss($css_file = 'style.css')
261: {
262: static $css_url, $css_path;
263:
264: if (!isset($css_url)) {
265: $css_url = dirname(xoops_getcss($GLOBALS['xoopsConfig']['theme_set']));
266: $css_path = str_replace(XOOPS_THEME_URL, XOOPS_THEME_PATH, $css_url);
267: }
268:
269: $css = array();
270: $css[] = $css_url . '/' . $css_file;
271: $css_content = file_get_contents($css_path . '/' . $css_file);
272:
273: // get all import css files
274: if (preg_match_all("~\@import url\((.*\.css)\);~sUi", $css_content, $matches, PREG_PATTERN_ORDER)) {
275: foreach ($matches[1] as $key => $css_import) {
276: $css = array_merge($css, $this->loadCss($css_import));
277: }
278: }
279:
280: return $css;
281: }
282:
283: /**
284: * @return string
285: */
286: public function render()
287: {
288: static $isTinyMceJsLoaded = false;
289:
290: $this->init();
291: if (isset($this->setting['elements']) && self::$LastOfElementsTinymce != $this->setting['elements']) {
292: $ret = "\n<!-- 'tiny_mce.js' SCRIPT NOT YET " . $this->setting['elements'] . " -->\n"; //debug
293:
294: return $ret;
295: } else {
296: $this->setting['elements'] = implode(',', self::$ListOfElementsTinymce);
297: }
298: if (!empty($this->setting['callback'])) {
299: $callback = $this->setting['callback'];
300: unset($this->setting['callback']);
301: } else {
302: $callback = '';
303: }
304: if (!empty($this->setting['file_browser_callback'])) {
305: $fbc_name = XOOPS_ROOT_PATH . '/class/xoopseditor/tinymce/include/' . $this->setting['file_browser_callback'] . '.js';
306: //suis passé la /lesrevespossibles/x244/class/xoopseditor/tinymce/tinymce/jscripts/include/openFinder.js
307: $file_browser_callback = "MyXoopsUrl ='" . XOOPS_URL . "';\n";
308: $file_browser_callback .= file_get_contents($fbc_name);
309: $file_browser_callback .= "\n//suis passé la " . $fbc_name;
310: //unset($this->setting["file_browser_callback"]);
311: } else {
312: $file_browser_callback = '//suis absent';
313: }
314:
315: // create returned string - start
316: $ret = "\n";
317:
318: /*
319: // IE BUG - start
320: // more info here:
321: // http://www.456bereastreet.com/archive/200802/beware_of_id_and_name_attribute_mixups_when_using_getelementbyid_in_internet_explorer/
322: // possible solution here:
323: // http://www.sixteensmallstones.org/ie-javascript-bugs-overriding-internet-explorers-documentgetelementbyid-to-be-w3c-compliant-exposes-an-additional-bug-in-getattributes
324: $ret =<<<EOF
325: <script language='javascript' type='text/javascript'>
326: if (/msie/i.test (navigator.userAgent)) { //only override IE
327: document.nativeGetElementById = document.getElementById;
328: document.getElementById = function(id) {
329: var elem = document.nativeGetElementById(id);
330: if (elem) {
331: //make sure that it is a valid match on id
332: if (elem.attributes['id'].value == id) {
333: return elem;
334: } else {
335: //otherwise find the correct element
336: for (var i=1;i<document.all[id].length;i++) {
337: if (document.all[id][i].attributes['id'].value == id) {
338: return document.all[id][i];
339: }
340: }
341: }
342: }
343:
344: return null;
345: };
346: }
347: </script>
348: \n
349: EOF;
350: // IE BUG - end
351: */
352:
353: $ret .= "<!-- Start TinyMce Rendering -->\n"; //debug
354: if ($isTinyMceJsLoaded) {
355: $ret .= "<!-- 'tiny_mce.js' SCRIPT IS ALREADY LOADED -->\n"; //debug
356: } else {
357: $ret .= "<script type='text/javascript' src='" . XOOPS_URL . $this->rootpath . "/tiny_mce.js'></script>\n";
358: $isTinyMceJsLoaded = true;
359: }
360: $ret .= "<script type='text/javascript'>\n";
361: $ret .= "tinyMCE.init({\n";
362: // set options - start
363: foreach ($this->setting as $key => $val) {
364: $ret .= $key . ':';
365: if ($val === true) {
366: $ret .= 'true,';
367: } elseif ($val === false) {
368: $ret .= 'false,';
369: } else {
370: $ret .= "'{$val}',";
371: }
372: $ret .= "\n";
373: }
374: // set options - end
375: $ret .= "tinymceload: true\n";
376: $ret .= "});\n";
377: $ret .= $callback . "\n";
378: $ret .= $file_browser_callback . "\n";
379: //$ret .= "function toggleEditor(id) {tinyMCE.execCommand('mceToggleEditor',false, id);}\n";
380: $ret .= "</script>\n";
381: $ret .= "<!-- End TinyMce Rendering -->\n";//debug
382: // create returned string - end
383: return $ret;
384: }
385: }
386: