Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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