]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/Web/UI/WebControls/THtmlArea.php
6c2985f83e17754e1cdf87cf39bdabd79eff5563
[bacula/bacula] / gui / baculum / framework / Web / UI / WebControls / THtmlArea.php
1 <?php
2 /**
3  * THtmlArea class file.
4  *
5  * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
6  * @link http://www.pradosoft.com/
7  * @copyright Copyright &copy; 2005-2014 PradoSoft
8  * @license http://www.pradosoft.com/license/
9  * @package System.Web.UI.WebControls
10  */
11
12 /**
13  * Includes TTextBox class
14  */
15 Prado::using('System.Web.UI.WebControls.TTextBox');
16
17 /**
18  * THtmlArea class
19  *
20  * THtmlArea wraps the visual editting functionalities provided by the
21  * TinyMCE project {@link http://tinymce.moxiecode.com/}.
22  *
23  * THtmlArea displays a WYSIWYG text area on the Web page for user input
24  * in the HTML format. The text displayed in the THtmlArea component is
25  * specified or determined by using the <b>Text</b> property.
26  *
27  * To enable the visual editting on the client side, set the property
28  * <b>EnableVisualEdit</b> to true (which is default value).
29  * To set the size of the editor when the visual editting is enabled,
30  * set the <b>Width</b> and <b>Height</b> properties instead of
31  * <b>Columns</b> and <b>Rows</b> because the latter has no meaning
32  * under the situation.
33  *
34  * The default editor gives only the basic tool bar. To change or add
35  * additional tool bars, use the {@link setOptions Options} property to add additional
36  * editor options with each options on a new line.
37  * See http://tinymce.moxiecode.com/tinymce/docs/index.html
38  * for a list of options. The options can be change/added as shown in the
39  * following example.
40  * <code>
41  * <com:THtmlArea>
42  *      <prop:Options>
43  *           plugins : "contextmenu,paste"
44  *           language : "zh_cn"
45  *      </prop:Options>
46  * </com:THtmlArea>
47  * </code>
48  *
49  * Compatibility
50  * The client-side visual editting capability is supported by
51  * Internet Explorer 5.0+ for Windows and Gecko-based browser.
52  * If the browser does not support the visual editting,
53  * a traditional textarea will be displayed.
54  *
55  * Browser support
56  *
57  * <code>
58  *                    Windows XP        MacOS X 10.4
59  * ----------------------------------------------------
60  * MSIE 6                  OK
61  * MSIE 5.5 SP2            OK
62  * MSIE 5.0                OK
63  * Mozilla 1.7.x           OK              OK
64  * Firefox 1.0.x           OK              OK
65  * Firefox 1.5b2           OK              OK
66  * Safari 2.0 (412)                        OK(1)
67  * Opera 9 Preview 1       OK(1)           OK(1)
68  * ----------------------------------------------------
69  *    * (1) - Partialy working
70  * ----------------------------------------------------
71  * </code>
72  *
73  * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
74  * @package System.Web.UI.WebControls
75  * @since 3.0
76  */
77 class THtmlArea extends TTextBox
78 {
79         /**
80          * @var array list of locale => language file pairs.
81          */
82         private static $_langs = array(
83                         'ar' => 'ar',
84                         'az' => 'az',
85                         'be' => 'be',
86                         'bg' => 'bg',
87                         'bn' => 'bn',
88                         'br' => 'br',
89                         'bs' => 'bs',
90                         'ca' => 'ca',
91                         'ch' => 'ch',
92                         'cn' => 'cn',
93                         'cs' => 'cs',
94                         'cy' => 'cy',
95                         'da' => 'da',
96                         'de' => 'de',
97                         'dv' => 'dv',
98                         'el' => 'el',
99                         'en' => 'en',
100                         'eo' => 'eo',
101                         'es' => 'es',
102                         'et' => 'et',
103                         'eu' => 'eu',
104                         'fa' => 'fa',
105                         'fi' => 'fi',
106                         'fr' => 'fr',
107                         'gl' => 'gl',
108                         'gu' => 'gu',
109                         'he' => 'he',
110                         'hi' => 'hi',
111                         'hr' => 'hr',
112                         'hu' => 'hu',
113                         'hy' => 'hy',
114                         'ia' => 'ia',
115                         'id' => 'id',
116                         'is' => 'is',
117                         'it' => 'it',
118                         'ja' => 'ja',
119                         'ka' => 'ka',
120                         'kl' => 'kl',
121                         'km' => 'km',
122                         'ko' => 'ko',
123                         'lb' => 'lb',
124                         'lt' => 'lt',
125                         'lv' => 'lv',
126                         'mk' => 'mk',
127                         'ml' => 'ml',
128                         'mn' => 'mn',
129                         'ms' => 'ms',
130                         'my' => 'my',
131                         'nb' => 'nb',
132                         'nl' => 'nl',
133                         'nn' => 'nn',
134                         'no' => 'no',
135                         'pl' => 'pl',
136                         'ps' => 'ps',
137                         'pt' => 'pt',
138                         'ro' => 'ro',
139                         'ru' => 'ru',
140                         'sc' => 'sc',
141                         'se' => 'se',
142                         'si' => 'si',
143                         'sk' => 'sk',
144                         'sl' => 'sl',
145                         'sq' => 'sq',
146                         'sr' => 'sr',
147                         'sv' => 'sv',
148                         'ta' => 'ta',
149                         'te' => 'te',
150                         'th' => 'th',
151                         'tn' => 'tn',
152                         'tr' => 'tr',
153                         'tt' => 'tt',
154                         'tw' => 'tw',
155                         'uk' => 'vi',
156                         'ur' => 'vi',
157                         'vi' => 'vi',
158                         'zh_CN' => 'zh-cn',
159                         'zh_TW' => 'zh-tw',
160                         'zh' => 'zh',
161                         'zu' => 'zu',
162                 );
163
164         /**
165          * @var array list of default plugins to load, override using getAvailablePlugins();
166          */
167         private static $_plugins = array(
168                 'advhr',
169                 'advimage',
170                 'advlink',
171                 'advlist',
172                 'autolink',
173                 'autoresize',
174                 'autosave',
175                 'bbcode',
176                 'contextmenu',
177                 'directionality',
178                 'emotions',
179                 'example',
180                 'fullpage',
181                 'fullscreen',
182                 'iespell',
183                 'inlinepopups',
184                 'insertdatetime',
185                 'layer',
186                 'legacyoutput',
187                 'lists',
188                 'media',
189                 'nonbreaking',
190                 'noneditable',
191                 'pagebreak',
192                 'paste',
193                 'preview',
194                 'print',
195                 'save',
196                 'searchreplace',
197                 'spellchecker',
198                 'style',
199                 'tabfocus',
200                 'table',
201                 'template',
202                 'visualchars',
203                 'wordc',
204                 'wordcount',
205                 'xhtmlxtras'
206         );
207
208         /**
209          * @var array default themes to load
210          */
211         private static $_themes = array(
212                 'simple',
213                 'advanced'
214         );
215
216         /**
217          * Constructor.
218          * Sets default width and height.
219          */
220         public function __construct()
221         {
222                 $this->setWidth('470px');
223                 $this->setHeight('250px');
224         }
225
226         /**
227          * Overrides the parent implementation.
228          * TextMode for THtmlArea control is always 'MultiLine'
229          * @return string the behavior mode of the THtmlArea component.
230          */
231         public function getTextMode()
232         {
233                 return 'MultiLine';
234         }
235
236         /**
237          * Overrides the parent implementation.
238          * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others.
239          * @param string the text mode
240          */
241         public function setTextMode($value)
242         {
243                 throw new TInvalidOperationException("htmlarea_textmode_readonly");
244         }
245
246         /**
247          * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true.
248          */
249         public function getAutoPostBack()
250         {
251                 return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack();
252         }
253
254         /**
255          * @return boolean whether to show WYSIWYG text editor. Defaults to true.
256          */
257         public function getEnableVisualEdit()
258         {
259                 return $this->getViewState('EnableVisualEdit',true);
260         }
261
262         /**
263          * Sets whether to show WYSIWYG text editor.
264          * @param boolean whether to show WYSIWYG text editor
265          */
266         public function setEnableVisualEdit($value)
267         {
268                 $this->setViewState('EnableVisualEdit',TPropertyValue::ensureBoolean($value),true);
269         }
270
271         /**
272          * Gets the current culture.
273          * @return string current culture, e.g. en_AU.
274          */
275         public function getCulture()
276         {
277                 return $this->getViewState('Culture', '');
278         }
279
280         /**
281          * Sets the culture/language for the html area
282          * @param string a culture string, e.g. en_AU.
283          */
284         public function setCulture($value)
285         {
286                 $this->setViewState('Culture', $value, '');
287         }
288
289         /**
290          * Gets the list of options for the WYSIWYG (TinyMCE) editor
291          * @see http://tinymce.moxiecode.com/tinymce/docs/index.html
292          * @return string options
293          */
294         public function getOptions()
295         {
296                 return $this->getViewState('Options', '');
297         }
298
299         /**
300          * Sets the list of options for the WYSIWYG (TinyMCE) editor
301          * @see http://tinymce.moxiecode.com/tinymce/docs/index.html
302          * @param string options
303          */
304         public function setOptions($value)
305         {
306                 $this->setViewState('Options', $value, '');
307         }
308
309         /**
310          * @param string path to custom plugins to be copied.
311          */
312         public function setCustomPluginPath($value)
313         {
314                 $this->setViewState('CustomPluginPath', $value);
315         }
316
317         /**
318          * @return string path to custom plugins to be copied.
319          */
320         public function getCustomPluginPath()
321         {
322                 return $this->getViewState('CustomPluginPath');
323         }
324
325         /**
326          * @return boolean enable compression of the javascript files, default is true.
327          */
328         public function getEnableCompression()
329         {
330                 return $this->getViewState('EnableCompression', true);
331         }
332
333         /**
334          * @param boolean enable compression of the javascript files, default is true.
335          */
336         public function setEnableCompression($value)
337         {
338                 $this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value));
339         }
340
341         /**
342          * Adds attribute name-value pairs to renderer.
343          * This method overrides the parent implementation by registering
344          * additional javacript code.
345          * @param THtmlWriter the writer used for the rendering purpose
346          */
347         protected function addAttributesToRender($writer)
348         {
349                 if($this->getEnableVisualEdit() && $this->getEnabled(true))
350                 {
351                         $writer->addAttribute('id',$this->getClientID());
352                         $this->registerEditorClientScript($writer);
353                 }
354
355                 parent::addAttributesToRender($writer);
356         }
357
358         /**
359          * Returns a list of plugins to be loaded.
360          * Override this method to customize.
361          * @return array list of plugins to be loaded
362          */
363         public function getAvailablePlugins()
364         {
365                 return self::$_plugins;
366         }
367
368         /**
369          * @return array list of available themese
370          */
371         public function getAvailableThemes()
372         {
373                 return self::$_themes;
374         }
375
376         protected function getCompressionOptions()
377         {
378                 return array(
379                         'plugins' => implode(',', $this->getAvailablePlugins()),
380                         'themes' => implode(',', $this->getAvailableThemes()),
381                         'languages' => $this->getLanguageSuffix($this->getCulture()),
382                         'disk_cache' => true,
383                         'debug' => false
384                 );
385         }
386
387         protected function loadJavascriptLibrary()
388         {
389                 $scripts = $this->getPage()->getClientScript();
390                 $scripts->registerPradoScript('htmlarea');
391                 $scripts->registerScriptFile('prado:THtmlArea', $this->getScriptUrl());
392         }
393
394         /**
395          * Registers the editor javascript file and code to initialize the editor.
396          */
397         protected function registerEditorClientScript($writer)
398         {
399                 $this->loadJavascriptLibrary();
400                 $scripts = $this->getPage()->getClientScript();
401                 $options = array(
402                         'EditorOptions' => $this->getEditorOptions()
403                 );
404                 if($this->getEnableCompression())
405                         $options['CompressionOptions'] = $this->getCompressionOptions();
406
407                 $options = TJavaScript::encode($options,true,true);
408                 $script = "new Prado.WebUI.THtmlArea($options)";
409                 $scripts->registerEndScript('prado:THtmlArea'.$this->ClientID,$script);
410         }
411
412         /**
413          * @return string editor script URL.
414          */
415         protected function getScriptUrl()
416         {
417                 if($this->getEnableCompression())
418                         return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce_gzip.js';
419                 else
420                         return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce.js';
421         }
422
423         /**
424          * Gets the editor script base URL by publishing the tarred source via TTarAssetManager.
425          * @return string URL base path to the published editor script
426          */
427         protected function getScriptDeploymentPath()
428         {
429                 $tarfile = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.tar');
430                 $md5sum = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.md5');
431                 if($tarfile===null || $md5sum===null)
432                         throw new TConfigurationException('htmlarea_tarfile_invalid');
433                 $url = $this->getApplication()->getAssetManager()->publishTarFile($tarfile, $md5sum);
434                 $this->copyCustomPlugins($url);
435                 return $url;
436         }
437
438         protected function copyCustomPlugins($url)
439         {
440                 if($plugins = $this->getCustomPluginPath())
441                 {
442                         $assets = $this->getApplication()->getAssetManager();
443                         $path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins);
444                         $dest = $assets->getBasePath().'/'.basename($url).'/tiny_mce/plugins/';
445                         if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance)
446                                 $assets->copyDirectory($path, $dest);
447                 }
448         }
449
450         /**
451          * Default editor options gives basic tool bar only.
452          * @return array editor initialization options.
453          */
454         protected function getEditorOptions()
455         {
456                 $options['mode'] = 'exact';
457                 $options['elements'] = $this->getClientID();
458                 $options['language'] = $this->getLanguageSuffix($this->getCulture());
459                 $options['theme'] = 'advanced';
460
461                 //make it basic advanced to fit into 1 line of buttons.
462                 //$options['theme_advanced_buttons1'] = 'bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,separator,undo,redo,separator,link,unlink,separator,charmap,separator,code,help';
463                 //$options['theme_advanced_buttons2'] = ' ';
464                 $options['theme_advanced_buttons1'] = 'formatselect,fontselect,fontsizeselect,separator,bold,italic,underline,strikethrough,sub,sup';
465                 $options['theme_advanced_buttons2'] = 'justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,outdent,indent,separator,forecolor,backcolor,separator,hr,link,unlink,image,charmap,separator,removeformat,code,help';
466                 $options['theme_advanced_buttons3'] = '';
467
468                 $options['theme_advanced_toolbar_location'] = 'top';
469                 $options['theme_advanced_toolbar_align'] = 'left';
470                 $options['theme_advanced_path_location'] = 'bottom';
471                 $options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]';
472                 if($this->getReadOnly())
473                         $options['readonly'] = true;
474
475                 $options = array_merge($options, $this->parseEditorOptions($this->getOptions()));
476                 return $options;
477         }
478
479         /**
480          * Parse additional options set in the Options property.
481          * @return array additional custom options
482          */
483         protected function parseEditorOptions($string)
484         {
485                 $options = array();
486                 $substrings = preg_split('/,\s*\n|\n/', trim($string));
487                 foreach($substrings as $bits)
488                 {
489                         $option = explode(":",$bits,2);
490
491                         if(count($option) == 2)
492                         {
493                                 $value=trim(trim($option[1]),"'\"");
494                                 if (($s=strtolower($value))==='false')
495                                         $value=false;
496                                 elseif ($s==='true')
497                                         $value=true;
498                                 $options[trim($option[0])] = $value;
499                         }
500                 }
501                 return $options;
502         }
503
504         /**
505          * @return string localized editor interface language extension.
506          */
507         protected function getLanguageSuffix($culture)
508         {
509                 $app = $this->getApplication()->getGlobalization();
510                 if(empty($culture) && ($app!==null))
511                         $culture = $app->getCulture();
512                 $variants = array();
513                 if($app!==null)
514                         $variants = $app->getCultureVariants($culture);
515
516                 foreach($variants as $variant)
517                 {
518                         if(isset(self::$_langs[$variant]))
519                                 return self::$_langs[$variant];
520                 }
521
522                 return 'en';
523         }
524
525         /**
526          * Gets the name of the javascript class responsible for performing postback for this control.
527          * This method overrides the parent implementation.
528          * @return string the javascript class name
529          */
530         protected function getClientClassName()
531         {
532                 return 'Prado.WebUI.THtmlArea';
533         }
534 }
535