Version: current

      1 <?php
      2
      3 /**
      4  * A PHP version of TinyMCE's configuration, to allow various parameters to be configured on a site or section basis
      5  *
      6  * There can be multiple HtmlEditorConfig's, which should always be created / accessed using HtmlEditorConfig::get. You can then set
      7  * the currently active config using set_active. Whichever config is active when HtmlEditorField#Field is called wins.
      8  *
      9  * @author "Hamish Friedlander" <hamish@silverstripe.com>
     10  * @package forms
     11  * @subpackage fields-formattedinput
     12  */
     13 class HtmlEditorConfig {
     14
     15     static $configs = array();
     16     static $current = null;
     17
     18     /**
     19      * Get the HtmlEditorConfig object for the given identifier. This is a correct way to get an HtmlEditorConfig instance - do not call 'new'
     20      * @param $identifier string - the identifier for the config set
     21      * @return HtmlEditorConfig - the configuration object. This will be created if it does not yet exist for that identifier
     22      */
     23     static function get($identifier = 'default') {
     24         if (!array_key_exists($identifier, self::$configs)) self::$configs[$identifier] = new HtmlEditorConfig();
     25         return self::$configs[$identifier];
     26     }
     27
     28     /**
     29      * Set the currently active configuration object
     30      * @param $identifier string - the identifier for the config set
     31      * @return null
     32      */
     33     static function set_active($identifier = null) {
     34         self::$current = $identifier;
     35     }
     36
     37     /**
     38      * Get the currently active configuration object
     39      * @return HtmlEditorConfig - the active configuration object
     40      */
     41     static function get_active() {
     42         $identifier = self::$current ? self::$current : 'default';
     43         return self::get($identifier);
     44     }
     45
     46     /**
     47      * Get the available configurations as a map of friendly_name to
     48      * configuration name.
     49      * @return array
     50      */
     51     static function get_available_configs_map() {
     52         $configs = array();
     53
     54         foreach(self::$configs as $identifier => $config) {
     55             $configs[$identifier] = $config->getOption('friendly_name');
     56         }
     57
     58         return $configs;
     59     }
     60
     61     /**
     62      * Holder for all TinyMCE settings _except_ plugins and buttons
     63      */
     64     protected $settings = array(
     65         'friendly_name' => '(Please set a friendly name for this config)',
     66         'priority' => 0,
     67         'mode' => 'none',
     68         'width' => '100%',
     69         'theme' => 'advanced',
     70
     71         'table_inline_editing' => true,
     72
     73         'relative_urls' => true,
     74         'verify_html' => true,
     75     );
     76
     77     /**
     78      * Holder list of enabled plugins
     79      */
     80     protected $plugins = array(
     81         'contextmenu' => null,
     82         'table' => null,
     83         'paste' => null,
     84         'inlinepopups' => null,
     85 //      'advcode' => '../../../sapphire/thirdparty/tinymce-advcode/editor_plugin_src.js',
     86 //      'spellchecker' => null
     87     );
     88
     89     /**
     90      * Holder list of buttons, organised by line
     91      */
     92     protected $buttons = array(
     93         1 => array('bold','italic','underline','strikethrough','separator','justifyleft','justifycenter','justifyright','justifyfull','formatselect','separator','bullist','numlist','outdent','indent','blockquote','hr','charmap'),
     94         2 => array('undo','redo','separator','cut','copy','paste','pastetext','pasteword','spellchecker','separator','code','search','replace','selectall','visualaid','separator','tablecontrols'),
     95         3 => array()
     96     );
     97
     98     /**
     99      * Get the current value of an option
    100      * @param $k string - The key of the option to get
    101      * @return mixed - The value of the specified option
    102      */
    103     function getOption($k) {
    104         if(isset($this->settings[$k])) return $this->settings[$k];
    105     }
    106
    107     /**
    108      * Set the value of one option
    109      * @param $k string - The key of the option to set
    110      * @param $v mixed - The value of the option to set
    111      * @return mixed - $v returned for chaining
    112      */
    113     function setOption($k,$v) {
    114         return $this->settings[$k] = $v;
    115     }
    116
    117     /**
    118      * Set multiple options
    119      * @param $a array - The options to set, as keys and values of the array
    120      * @return null
    121      */
    122     function setOptions($a) {
    123         foreach ($a as $k=>$v) {
    124             $this->settings[$k] = $v;
    125         }
    126     }
    127
    128     /**
    129      * get multiple options
    130      * @return $a array - The options to set, as keys and values of the array
    131      */
    132     function getOptions() {
    133         return $this->settings;
    134     }
    135
    136     /**
    137      * Enable one or several plugins. Will maintain unique list if already
    138      * enabled plugin is re-passed. If passed in as a map of plugin-name to path,
    139      * the plugin will be loaded by tinymce.PluginManager.load() instead of through tinyMCE.init().
    140      * Keep in mind that these externals plugins require a dash-prefix in their name.
    141      *
    142      * @see http://wiki.moxiecode.com/index.php/TinyMCE:API/tinymce.PluginManager/load
    143      *
    144      * @param String [0..] a string, or several strings, or a single array of strings - The plugins to enable
    145      * @return null
    146      */
    147     function enablePlugins() {
    148         $plugins = func_get_args();
    149         if (is_array(current($plugins))) $plugins = current($plugins);
    150         foreach ($plugins as $plugin => $path) {
    151             // if plugins are passed without a path
    152             if(is_numeric($plugin)) {
    153                 $plugin = $path;
    154                 $path = null;
    155             }
    156             if (!array_key_exists($plugin, $this->plugins)) $this->plugins[$plugin] = $path;
    157         }
    158     }
    159
    160     /**
    161      * Enable one or several plugins. Will properly handle being passed a plugin that is already disabled
    162      * @param String [0..] a string, or several strings, or a single array of strings - The plugins to disable
    163      * @return null
    164      */
    165     function disablePlugins() {
    166         $plugins = func_get_args();
    167         if (is_array(current($plugins))) $plugins = current($plugins);
    168
    169         foreach ($plugins as $plugin) {
    170             if(array_key_exists($plugin, $this->plugins)) {
    171                 unset($this->plugins[$plugin]);
    172             }
    173         }
    174     }
    175
    176     /**
    177      * @return Array
    178      */
    179     function getPlugins() {
    180         return $this->plugins;
    181     }
    182
    183     /**
    184      * Totally re-set the buttons on a given line
    185      *
    186      * @param integer from 1..3 - The line number to redefine
    187      * @param string  a string or several strings, or a single array of strings - The button names to make this line contain
    188      * @return null
    189      */
    190     function setButtonsForLine() {
    191         if (func_num_args() == 2) {
    192             list($line, $buttons) = func_get_args();
    193         }
    194         else {
    195             $buttons = func_get_args();
    196             $line = array_shift($buttons);
    197         }
    198         $this->buttons[$line] = is_array($buttons) ? $buttons : array($buttons);
    199     }
    200
    201     /**
    202      * Add buttons to the end of a line
    203      * @param integer from 1..3
    204      * @param string a string, or several strings, or a single array of strings - The button names to add to the end of this line
    205      * @return null
    206      */
    207     function addButtonsToLine() {
    208         $inserts = func_get_args();
    209         $line = array_shift($inserts);
    210         if (is_array($inserts[0])) $inserts = $inserts[0];
    211
    212         foreach ($inserts as $button) {
    213             $this->buttons[$line][] = $button;
    214         }
    215     }
    216
    217     /**
    218      * Internal function for adding and removing buttons related to another button
    219      * @param $name string - the name of the button to modify
    220      * @param $offset integer - the offset relative to that button to perform an array_splice at - 0 for before $name, 1 for after
    221      * @param $del integer - the number of buttons to remove at the position given by index(string) + offset
    222      * @param $add mixed - an array or single item to insert at the position given by index(string) + offset, or null for no insertion
    223      * @return boolean - true if $name matched a button, false otherwise
    224      */
    225     protected function modifyButtons($name, $offset, $del=0, $add=null) {
    226         foreach ($this->buttons as &$buttons) {
    227             if (($idx = array_search($name, $buttons)) !== false) {
    228                 if ($add) array_splice($buttons, $idx+$offset, $del, $add);
    229                 else     array_splice($buttons, $idx+$offset, $del, $add);
    230                 return true;
    231             }
    232         }
    233         return false;
    234     }
    235
    236     /**
    237      * Insert buttons before the first occurance of another button
    238      * @param string - the name of the button to insert other buttons before
    239      * @param string a string, or several strings, or a single array of strings - the button names to insert before that button
    240      * @return boolean - true if insertion occured, false if it did not (because the given button name was not found)
    241      */
    242     function insertButtonsBefore() {
    243         $inserts = func_get_args();
    244         $before = array_shift($inserts);
    245         return $this->modifyButtons($before, 0, 0, $inserts);
    246     }
    247
    248     /**
    249      * Insert buttons after the first occurance of another button
    250      * @param string - the name of the button to insert other buttons after
    251      * @param string a string, or several strings, or a single array of strings - the button names to insert after that button
    252      * @return boolean - true if insertion occured, false if it did not (because the given button name was not found)
    253      */
    254     function insertButtonsAfter() {
    255         $inserts = func_get_args();
    256         $after = array_shift($inserts);
    257         return $this->modifyButtons($after, 1, 0, $inserts);
    258     }
    259
    260     /**
    261      * Remove the first occurance of buttons
    262      * @param string one or more strings - the name of the buttons to remove
    263      * @return null
    264      */
    265     function removeButtons() {
    266         $removes = func_get_args();
    267         foreach ($removes as $button) {
    268             $this->modifyButtons($button, 0, 1);
    269         }
    270     }
    271
    272     /**
    273      * Generate the javascript that will set tinyMCE's configuration to that of the current settings of this object
    274      * @return string - the javascript
    275      */
    276     function generateJS() {
    277         $config = $this->settings;
    278
    279         // plugins
    280         $internalPlugins = array();
    281         $externalPluginsJS = '';
    282         foreach($this->plugins as $plugin => $path) {
    283             if(!$path) {
    284                 $internalPlugins[] = $plugin;
    285             } else {
    286                 $internalPlugins[] = '-' . $plugin;
    287                 $externalPluginsJS .= sprintf(
    288                     'tinymce.PluginManager.load("%s", "%s");' . "\n",
    289                     $plugin,
    290                     $path
    291                 );
    292             }
    293         }
    294         $config['plugins'] = implode(',', $internalPlugins);
    295
    296         foreach ($this->buttons as $i=>$buttons) {
    297             $config['theme_advanced_buttons'.$i] = implode(',', $buttons);
    298         }
    299
    300         return "
    301 if((typeof tinyMCE != 'undefined')) {
    302     $externalPluginsJS
    303     tinyMCE.init(" . Convert::raw2json($config) . ");
    304 }
    305 ";
    306     }
    307 }
    308

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -