diff options
| author | tzur <tzur@ccwn.org> | 2012-04-15 15:30:09 +0200 |
|---|---|---|
| committer | tzur <tzur@ccwn.org> | 2012-04-15 15:30:09 +0200 |
| commit | 5b2095abddf9d0596a7715879357e8d9a3b786b2 (patch) | |
| tree | 0c2b6fdc1484b697b1a3740582a906fb51c1d64f /protected/extensions/tinymce/ETinyMce.php | |
Initial version
Diffstat (limited to 'protected/extensions/tinymce/ETinyMce.php')
| -rw-r--r-- | protected/extensions/tinymce/ETinyMce.php | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/protected/extensions/tinymce/ETinyMce.php b/protected/extensions/tinymce/ETinyMce.php new file mode 100644 index 0000000..fe86b23 --- /dev/null +++ b/protected/extensions/tinymce/ETinyMce.php @@ -0,0 +1,892 @@ +<?php +/** + * @copyright Copyright (c) 2009-2011 Rodolfo Gonzalez <metayii.framework@gmail.com> + * + * @version 2.0 + * @license LGPL 2.1 + * + * {@link http://www.gnu.org/licenses/lgpl-2.1.txt} + */ + +/** + * ETinyMce is an input widget based on TinyMCE and the jQuery TinyMCE plugin. + * + * Example: + * + * <code> + * <?php $this->widget('application.extensions.tinymce.ETinyMce', + * array('name'=>'html')); ?> + * </code> + * + * This extension includes TinyMCE 3.4.3.2 Jquery, Compressor 2.0.4 PHP and the + * full language sets. This is included under the LGPL 2.1 license: + * + * @license http://tinymce.moxiecode.com/js/tinymce/jscripts/tiny_mce/license.txt + * + * @author Rodolfo Gonzalez <metayii.framework@gmail.com> + */ +class ETinyMce extends CInputWidget +{ + /** + * These are useful defaults in case you forget to set htmlOptions['cols'] + * and htmlOptions['rows']. However, since width and heigth are defined + * below, the cols and rows don't actually matter (they're here just for + * XHTML compliance) + */ + const COLS = 40; + const ROWS = 10; + + /** + * Don't change these unless you're having name conflicts. They should be the + * same as the used in the jquery.tinymce.js plugin file + */ + const COOKIE_SUFFIX = '_editorMode'; + const SWITCH_SUFFIX = '_switch'; + + //************************************************************************** + // Widget properties + //************************************************************************** + + /** + * The mode for this editor: html or text + */ + private $mode = 'html'; + + /** + * The editor's language + * + * @var string + */ + private $language = 'en'; + + /** + * You can use one of these predefined setups for the editor: + * + * - simple: This page shows you the simple theme and it's core functionality. + * - full: This includes shows all available buttons and plugins that are + * included in the TinyMCE core package. + * + * @var string + */ + private $editorTemplate = 'simple'; + + /** + * The width of the editor. + * This will be overriden if you set htmlOptions['style'] = 'width:...'; + * + * @var string + */ + private $width = '100%'; + + /** + * The heigth of the editor. + * This will be overriden if you set htmlOptions['style'] = 'heigth:...'; + * + * @var integer + */ + private $height = '400px'; + + /** + * This option enables you to specify make editor instances in readonly mode. + * When they are in readonly mode nothing can be changed and the contents is + * just presented to the user. + * + * @var boolean + */ + private $readOnly = false; + + /** + * The TinyMCE options. It is an associative array. Follow this example: + * + * $options['theme_advanced_toolbar_location'] = 'top'; + * + * The keys and the corresponding values are the configuration options from + * this page: + * + * @link http://wiki.moxiecode.com/index.php/TinyMCE:Configuration + * + * You can control the toolbars following these instructions: + * + * @link http://wiki.moxiecode.com/index.php/TinyMCE:Control_reference + * + * @var array + */ + private $options = array(); + + /** + * Plugins to load. The more you load the slower is the first load. + * You may want to extend the class and redefine this property to your needs. + * + * For an almost full editor: + * + * array('spellchecker','table','save','emotions','insertdatetime','preview','searchreplace','print','contextmenu','paste','fullscreen','noneditable','layer','visualchars'); + * + * This variable is significative only if $this->options == array() + * + * @var array + */ + private $plugins = array(); + + /** + * Font families to display on the font list. + * You may want to redefine this property to your needs. + * Notice that the only useful values are the most comon: Arial, Times New + * Romn and Helvetica, since they have equivalents in most operating systems. + * + * This variable is significative only if $this->options == array() + * + * @var string + */ + private $fontFamilies = array( + 'Andale Mono'=>'andale mono', + 'Arial'=>'arial,helvetica,sans-serif', + 'Arial Black'=>'arial black', + 'Book Antiqua'=>'book antiqua', + 'Comic Sans MS'=>'comic sans ms', + 'Courier New'=>'courier new,courier,monospace', + 'Georgia'=>'georgia', + 'Helvetica'=>'helvetica', + 'Impact'=>'impact', + 'Symbol'=>'symbol', + 'Tahoma'=>'tahoma', + 'Terminal'=>'terminal', + 'Times New Roman'=>'times new roman,roman,serif', + 'Trebuchet MS'=>'trebuchet ms', + 'Verdana'=>'verdana', + 'Webdings'=>'webdings', + 'Wingdings'=>'wingdings' + ); + + /** + * Font sizes to display in the font size list. This is a list of comma separated integers. + * You may want to redefine this property to your needs. + * + * This variable is significative only if $this->options == array() + * + * @var string + */ + private $fontSizes = array('1','2','3','4','5','6','7'); + + /** + * If you include an URL pointing to a CSS file, this will be used by the + * editor to try to present the content as if it were on the target page. + * + * @var string + */ + private $contentCSS = ''; + + /** + * The CSS style of the label tab + * + * @var string + */ + private $labelStyle = 'color:navy;font-family:sans-serif;font-size:8pt;background-color:#F0F0EE;border-style:solid;border-width:0px 1px 1px 1px;border-color:#CCCCCC;text-decoration:none;padding:1px 3px 3px 3px;margin:2px 0 0 0;'; + + /** + * The CSS class of the label tab. A sample CSS file is provided inside the + * css directory. Simple registerCssFile in your view and use mceSwitchLabel. + * Or define your own. + * + * @var string + */ + private $labelClass = ''; + + /** + * The labels for the HTML->plain text mode switch. The first element is the + * "text to plain" label, and the second element is the "html to text" label + * + * @var array + */ + private $switchLabels = array(0=>'Text mode', 1=>'HTML mode'); + + /** + * Wheter to use the HTML->plain text mode switch. + * + * Note: if useSwitch==true then the editor will be inside a <div> tag. Else + * it will be a normal <textarea> tag. Take this in account when designing + * your form. + * + * @var boolean + */ + private $useSwitch = true; + + /** + * Use cookies to "learn" the editor's mode? + * + * @var boolean + */ + private $useCookies = true; + + /** + * Whetever to use the PHP compressor code. You must check if your server is + * already using zlib. If it is using zlib for output compression, and you + * set this to true, the editor won't work and you'll get javascript errors. + * Be careful. + * + * @link http://wiki.moxiecode.com/index.php/TinyMCE:Compressor/PHP + * + * @var boolean + */ + private $useCompression = true; + + //*************************************************************************** + // Local properties + //*************************************************************************** + + /** + * Valid bundled languages. + * + * @var array + */ + private $validLanguages = array( + 'ar', 'bg', 'bs', 'cn', 'da', 'el', 'es', 'fa', 'gl', 'hi', 'hy', 'is', + 'ka', 'ko', 'lv', 'mn', 'nb', 'no', 'pt', 'sc', 'sk', 'sr', 'te', 'tr', + 'uk', 'zh-cn', 'zu', 'az', 'bn', 'ca', 'cs', 'de', 'en', 'et', 'fi', + 'gu', 'hr', 'ia', 'it', 'kl', 'lb', 'mk', 'ms', 'nl', 'pl', 'ro', 'se', + 'sl', 'sv', 'th', 'tt', 'ur', 'zh', 'be', 'br', 'ch', 'cy', 'dv', 'eo', + 'eu', 'fr', 'he', 'hu', 'id', 'ja', 'km', 'lt', 'ml', 'my', 'nn', 'ps', + 'ru', 'si', 'sq', 'ta', 'tn', 'tw', 'vi', 'zh-tw', + ); + + /** + * Valid predefined editor templates + * + * @var array + */ + private $validEditorTemplates = array('simple', 'full'); + + //*************************************************************************** + // Constructor + //*************************************************************************** + + public function __construct($owner=null) + { + parent::__construct($owner); + $this->setLanguage(Yii::app()->language); + } + + //*************************************************************************** + // Setters and getters + //*************************************************************************** + + /** + * Setter + * + * @param array $value + */ + public function setOptions($value) + { + if (!is_array($value)) + throw new CException(Yii::t('ETinyMce', 'options must be an array')); + $this->options = $value; + } + + /** + * Getter + * + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * Setter + * + * @param string $value the heigth + */ + public function setHeight($value) + { + if (!preg_match("/[\d]+[px|\%]/", $value)) + throw new CException(Yii::t('ETinyMce', 'height must be a string of digits terminated by "%" or "px"')); + $this->height = $value; + } + + /** + * Getter + * + * @return string + */ + public function getHeight() + { + return $this->height; + } + + /** + * Setter + * + * @param string $value the width + */ + public function setWidth($value) + { + if (!preg_match("/[\d]+[px|\%]/", $value)) + throw new CException(Yii::t('ETinyMce', 'width must be a string of digits terminated by "%" or "px"')); + $this->width = $value; + } + + /** + * Getter + * + * @return <type> + */ + public function getWidth() + { + return $this->width; + } + + /** + * Setter + * + * @param string $value the template + */ + public function setEditorTemplate($value) + { + if (!in_array($value, $this->validEditorTemplates)) + throw new CException(Yii::t('ETinyMce', 'editorTemplate must be one of {temp}', array('{temp}'=>implode(',', $this->validEditorTemplates)))); + $this->editorTemplate = $value; + } + + /** + * Getter + * + * @return string + */ + public function getEditorTemplate() + { + return $this->editorTemplate; + } + + /** + * Setter + * + * @param string $value the style string + */ + public function setLabelStyle($value) + { + $this->labelStyle = $value; + } + + /** + * Getter + * + * @return string + */ + public function getLabelStyle() + { + return $this->labelStyle; + } + + /** + * Setter + * + * @param string $value the class name + */ + public function setLabelClass($value) + { + $this->labelClass = $value; + } + + /** + * Getter + * + * @return string + */ + public function getLabelClass() + { + return $this->labelClass; + } + + /** + * Setter + * + * @param bolean $value + */ + public function setUseCompression($value) + { + if (!is_bool($value)) + throw new CException(Yii::t('EWebFeed', 'useCompression must be boolean')); + $this->useCompression = $value; + } + + /** + * Getter + * + * @return boolean + */ + public function getUseCompression() + { + return $this->useCompression; + } + + /** + * Set the switch labels + * + * @param unknown_type $value + */ + public function setSwitchLabels($value) + { + if (!is_array($value) || count($value) != 2) + throw new CException(Yii::t('ETinyMCE', 'The switch labels must be provided as array(text_mode_label, html_mode_label) array')); + $this->switchLabels = $value; + } + + /** + * Returns the labels + * + * @return array + */ + public function getSwitchLabels() + { + return $this->switchLabels; + } + + /** + * Will we use the mode switch? + * + * @param boolean $value + */ + public function setUseSwitch($value) + { + if (!is_bool($value)) + throw new CException(Yii::t('ETinyMCE', 'useSwitch must be boolean')); + $this->useSwitch = $value; + } + + /** + * Will we use the mode switch? + * + * @return boolean + */ + public function getUseSwitch() + { + return $this->useSwitch; + } + + /** + * Will we use cookies? + * + * @param boolean $value + */ + public function setUseCookies($value) + { + if (!is_bool($value)) + throw new CException(Yii::t('ETinyMCE', 'useCookies must be boolean')); + $this->useCookies = $value; + } + + /** + * Enter description here... + * + * @return unknown + */ + public function getUseCookies() + { + return $this->useCookies; + } + + /** + * Set the language for TinyMCE. Please check the langs directory to know + * which languages are available. + * + * @param string $value + */ + public function setLanguage($value) + { + $lang = (($p = strpos($value, '_')) !== false) ? str_replace('_', '-', $value) : $value; + if (in_array($lang, $this->validLanguages)) { + $this->language = $lang; + } + else { + $suffix = empty($lang) ? 'en' : ($p !== false) ? strtolower(substr($lang, 0, $p)) : strtolower($lang); + if (in_array($suffix, $this->validLanguages)) $this->language = $suffix; + } + } + + /** + * Getter + * + * @return string + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Set the mode (values can be 'HTML' or 'Plain') + * + * @param string $value + */ + public function setMode($value) + { + if ($value !== 'html' && $value !== 'text') + throw new CException(Yii::t('ETinyMCE', 'mode must be "html" or "text"')); + $this->mode = $value; + } + + /** + * Returns the editor mode + * + * @return string + */ + public function getMode() + { + return $this->mode; + } + + /** + * The plugins which will be installed + * + * @param array $value + */ + public function setPlugins($value) + { + if (!is_array($value)) + throw new CException(Yii::t('ETinyMCE', 'plugins must be an array of strings')); + $this->plugins = $value; + } + + /** + * Returns the plugins + * + * @return array + */ + public function getPlugins() + { + return $this->plugins; + } + + /** + * Sets the font families. + * Format: Title=>font families + * + * @param array $value + */ + public function setFontFamilies($value) + { + if (!is_array($value)) + throw new CException(Yii::t('ETinyMCE', 'fontFamilies must be an array of strings')); + $this->fontFamilies = $value; + } + + /** + * Returns the font families + * + * @return array + */ + public function getFontFamilies() + { + return $this->fontFamilies; + } + + /** + * Setter + * + * @param array $value the font sizes array + */ + public function setFontSizes($value) + { + if (!is_array($value)) + throw new CException(Yii::t('ETinyMCE', 'fontSizes must be an array of integers')); + $this->fontSizes = $value; + } + + /** + * Getter + * + * @return array + */ + public function getFontSizes() + { + return $this->fontSizes; + } + + /** + * Setter + * + * @param string $value the URL + */ + public function setContentCSS($value) + { + if (!is_string($value)) + throw new CException(Yii::t('ETinyMCE', 'contentCSS must be an URL')); + $this->contentCSS = $value; + } + + /** + * Getter + * + * @return string + */ + public function getContentCSS() + { + return $this->contentCSS; + } + + /** + * Setter + * + * @param boolean $value + */ + public function setReadOnly($value) + { + if (!is_bool($value)) + throw new CException(Yii::t('ETinyMce', 'readOnly must be boolean')); + $this->readOnly = $value; + } + + /** + * Getter + * + * @return boolean + */ + public function getReadOnly() + { + return $this->readOnly; + } + + //*************************************************************************** + // Some useful templates + //*************************************************************************** + + /** + * A simple editor, minimal options + * + * @link http://tinymce.moxiecode.com/examples/simple.php + * + * @return array + */ + protected function makeSimpleEditor() + { + $options = array(); + + $options['theme'] = 'simple'; + + return $options; + } + + /** + * A full editor (example modified to make it more logic) + * + * @link http://tinymce.moxiecode.com/examples/full.php + * + * @param string $url the base URL for tinymce in assets + * @return array + */ + protected function makeFullEditor($url='') + { + $options = array(); + + $this->plugins = array('safari','pagebreak','style','layer','table','save','advhr','advimage','advlink','emotions','spellchecker','inlinepopups','insertdatetime','preview','media','searchreplace','print','contextmenu','paste','directionality','fullscreen','noneditable','visualchars','nonbreaking','xhtmlxtras','template'); + + if ($this->contentCSS !== '') { + $sc = "styleselect,"; + $c1 = ''; + $c2 = 'cite,abbr,acronym,|,'; + } + else { + $sc = ''; + $c1 = ',|,cite,abbr,acronym'; + $c2 = ''; + } + + if (!empty($this->fontFamilies)) { + $options['theme_advanced_fonts'] = implode(',', $this->fontFamilies); + } + if (!empty($this->fontSizes)) { + $options['theme_advanced_font_sizes'] = implode(',', $this->fontSizes); + } + + $options['theme'] = 'advanced'; + $options['theme_advanced_toolbar_location'] = 'top'; + $options['theme_advanced_toolbar_align'] = 'left'; + $options['theme_advanced_path_location'] = 'bottom'; + $options['theme_advanced_buttons1'] = "save,newdocument,print,|,cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo,|,removeformat,cleanup,|,spellchecker,|,visualaid,visualchars,|,ltr,rtl,|,code,preview,fullscreen,|,help"; + $options['theme_advanced_buttons2'] = "{$sc}formatselect,fontselect,fontsizeselect,|,forecolor,backcolor,|,bold,italic,underline,strikethrough,|,sub,sup{$c1}"; + $options['theme_advanced_buttons3'] = "justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,|,hr,advhr,nonbreaking,pagebreak,blockquote,|,charmap,emotions,media,image,|,link,unlink,anchor,|,insertdate,inserttime"; + $options['theme_advanced_buttons4'] = "{$c2}tablecontrols,|,insertlayer,moveforward,movebackward,absolute,|,styleprops,del,ins,attribs,|,template"; + $options['theme_advanced_toolbar_location'] = "'top'"; + $options['theme_advanced_toolbar_align'] = "'left'"; + $options['theme_advanced_statusbar_location'] = "bottom"; + $options['theme_advanced_toolbar_location'] = 'top'; + $options['theme_advanced_toolbar_align'] = 'left'; + $options['theme_advanced_path_location'] = 'bottom'; + $options['theme_advanced_resize_horizontal'] = true; + $options['theme_advanced_resizing'] = true; + $options['spellchecker_languages'] = '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv'; + if ($url !== '') { + $options['spellchecker_rpc_url'] = $url . '/plugins/spellchecker/rpc.php'; + } + + return $options; + } + + // ************************************************************************** + // Options creators + // ************************************************************************** + + protected function makeCompressor() + { + $options = array(); + + $options['plugins'] = implode(',', $this->plugins); + $options['themes'] = ($this->editorTemplate==='simple') ? 'simple' : 'advanced'; + $options['languages'] = $this->language; + $options['disk_cache'] = true; + $options['debug'] = false; + + return CJavaScript::encode($options); + } + + /** + * Get the options for the TinyMCE editor. You may want to extend the class + * and to override this method to customize globally the options, so every + * editor will have the same l&f and the same behavior. Set 'options'=>array() + * in the view to get the defaults, otherwise you won't have editor :-) + * + * @param array $value + */ + protected function makeOptions($url='') + { + list($name,$id) = $this->resolveNameID(); + + if ($this->mode === 'html') { + $options['mode'] = 'exact'; + $options['elements'] = $id; + } + else { + $options['mode'] = 'none'; + } + + $options['language'] = $this->language; + $options['readonly'] = $this->readOnly; + + // avoid URL headaches + $options['relative_urls'] = false; + $options['remove_script_host'] = false; + + // XHTML compliance + $options['convert_fonts_to_spans'] = true; + + // avoid problems with browser tabs + $options['fullscreen_new_window'] = true; + + // avoid problems with HTMLPurifier (see README.TXT) + $options['media_use_script'] = true; + + // to make the content look like if it were in your target page + if ($this->contentCSS !== '') { + $options['content_css'] = $this->contentCSS; + } + + if ($this->editorTemplate !== '') { + switch ($this->editorTemplate) { + case 'simple': + $template = $this->makeSimpleEditor(); + break; + case 'full': + $template = $this->makeFullEditor($url); + break; + } + $options = array_merge($options, $template); + } + + if (!empty($this->plugins) && is_array($this->plugins)) { + $options['plugins'] = implode(',', $this->plugins); + } + + // here any option is overriden by user's options + if (is_array($this->options)) { + $options = array_merge($options, $this->options); + } + + return CJavaScript::encode($options); + } + + //*************************************************************************** + // Run Lola Run + //*************************************************************************** + + /** + * Executes the widget. + * This method registers all needed client scripts and renders + * the text field. + */ + public function run() + { + list($name, $id) = $this->resolveNameID(); + + if ($this->useCookies) { + if (isset($_COOKIE[$id.self::COOKIE_SUFFIX]) && in_array($_COOKIE[$id.self::COOKIE_SUFFIX], array('text', 'html'))) { + $this->setMode($_COOKIE[$id.self::COOKIE_SUFFIX]); + } + } + + $baseDir = dirname(__FILE__); + $assets = Yii::app()->getAssetManager()->publish($baseDir.DIRECTORY_SEPARATOR.'assets'); + + $tinyOptions = $this->makeOptions($baseDir); + + $jsUseCookies = ($this->useCookies) ? 'true' : 'false'; + $jsMode = strval($this->mode); + $jsToggleLabels = CJavaScript::encode($this->switchLabels); + + $cs = Yii::app()->getClientScript(); + $cs->registerCoreScript('jquery'); + + if ($this->useCompression) { + $cs->registerScriptFile($assets.'/tiny_mce/tiny_mce_gzip.js'); + $gzOptions = $this->makeCompressor(); + $js =<<<EOP +tinyMCE_GZ.init({$gzOptions}); +EOP; + $cs->registerScript('Yii.'.get_class($this).'#'.$id.'_gz', $js, CClientScript::POS_HEAD); + } + else { + $cs->registerScriptFile($assets.'/tiny_mce/tiny_mce.js'); + } + + $cs->registerScriptFile($assets.'/jquery/jquery.tinymce.js'); + $cs->registerScriptFile($assets.'/embedmedia/embed.js'); + + $this->htmlOptions['id'] = $id; + if (!array_key_exists('style', $this->htmlOptions)) { + $this->htmlOptions['style'] = "width:{$this->width};height:{$this->height};"; + } + if (!array_key_exists('cols', $this->htmlOptions)) { + $this->htmlOptions['cols'] = self::COLS; + } + if (!array_key_exists('rows', $this->htmlOptions)) { + $this->htmlOptions['rows'] = self::ROWS; + } + + $js =<<<EOP +jQuery("#{$id}").tinymce({$tinyOptions}, '{$jsMode}', {$jsUseCookies}); +EOP; + $cs->registerScript('Yii.'.get_class($this).'#'.$id, $js, CClientScript::POS_LOAD); + + if($this->hasModel()) { + $textarea = CHtml::activeTextArea($this->model, $this->attribute, $this->htmlOptions); + } + else { + $textarea = CHtml::textArea($name, $this->value, $this->htmlOptions); + } + + $html = ''; + if ($this->useSwitch && !$this->readOnly) { + $label = $this->switchLabels[($this->mode=='html'?0:1)]; + $css = ($this->labelClass !== '') ? array('class'=>$this->labelClass) : array('style'=>$this->labelStyle); + $switchOptions = array_merge(array('id'=>$id.self::SWITCH_SUFFIX), $css); + $uri = rawurlencode('$("#'.$id.'").toggleModeTinyMCE('.$jsToggleLabels.')'); + $link = CHtml::link($label, 'javascript:'.$uri, $switchOptions); + $switch = CHtml::tag('div', array(), CHtml::tag('span', array(), $link)); + $html = CHtml::tag('div', array(), $textarea.$switch); + } + else { + $html = $textarea; + } + + echo $html; + } +}
\ No newline at end of file |
