/**
     * This basically merges HtmlEditorField::include_js() and HTMLEditorConfig::generateJS() to output all
     * configuration sets to a customTinyMceConfigs javascript array.
     * This is output in addition to the standard ssTinyMceConfig because a) we can't stop the default output
     * with extensions; and b) the default setting is still used for any HTMLEditorField that doesn't specify
     * it's own config.
     *
     * Calls Requirements::javascript() to load the scripts.
     */
    public static function include_js()
    {
        require_once 'tinymce/tiny_mce_gzip.php';
        $availableConfigs = HtmlEditorConfig::get_available_configs_map();
        $pluginsForTag = array();
        $languages = array();
        //$allConfigs = array();
        $settingsJS = '';
        $externalPluginsForJS = array();
        $activeConfig = HtmlEditorConfig::get_active();
        foreach ($availableConfigs as $identifier => $friendlyName) {
            $configObj = CustomHtmlEditorConfig::get($identifier);
            $internalPluginsForJS = array();
            $configObj->getConfig()->setOption('language', i18n::get_tinymce_lang());
            if (!$configObj->getConfig()->getOption('content_css')) {
                $configObj->getConfig()->setOption('content_css', $activeConfig->getOption('content_css'));
            }
            $settings = $configObj->getSettings();
            foreach ($configObj->getPlugins() as $plugin => $path) {
                if (!$path) {
                    $pluginsForTag[$plugin] = $plugin;
                    $internalPluginsForJS[$plugin] = $plugin;
                } else {
                    $internalPluginsForJS[$plugin] = '-' . $plugin;
                    $externalPluginsForJS[$plugin] = sprintf('tinymce.PluginManager.load("%s", "%s");' . "\n", $plugin, $path);
                }
            }
            $language = $configObj->getConfig()->getOption('language');
            if ($language) {
                $languages[$language] = $language;
            }
            $settings['plugins'] = implode(',', $internalPluginsForJS);
            $buttons = $configObj->getButtons();
            foreach ($buttons as $i => $buttons) {
                $settings['theme_advanced_buttons' . $i] = implode(',', $buttons);
            }
            $settingsJS .= "customTinyMceConfigs['" . $identifier . "'] = " . Convert::raw2json($settings) . ";\n";
        }
        if (Config::inst()->get('HtmlEditorField', 'use_gzip')) {
            $tag = TinyMCE_Compressor::renderTag(array('url' => THIRDPARTY_DIR . '/tinymce/tiny_mce_gzip.php', 'plugins' => implode(',', $pluginsForTag), 'themes' => 'advanced', 'languages' => implode(',', $languages)), true);
            preg_match('/src="([^"]*)"/', $tag, $matches);
            Requirements::javascript($matches[1]);
        } else {
            Requirements::javascript(MCE_ROOT . 'tiny_mce_src.js');
        }
        $externalPluginsJS = implode('', $externalPluginsForJS);
        $script = <<<JS
\t\t\tif((typeof tinyMCE != 'undefined')) {
\t\t\t\t{$externalPluginsJS}

\t\t\t\tif (typeof customTinyMceConfigs == 'undefined') {
\t\t\t\t\tvar customTinyMceConfigs = [];
\t\t\t\t}
\t\t\t\t{$settingsJS}
\t\t\t}

JS;
        Requirements::customScript($script, 'htmlEditorConfigs');
    }
 public function updateCMSFields(FieldList $fields)
 {
     Requirements::javascript(TINYMCE4_DIR . "/javascript/HtmlEditorField.js");
     Requirements::css(TINYMCE4_DIR . "/css/HtmlEditorField.css");
     if (Member::currentUser()) {
         CustomHtmlEditorConfig::set_active(Member::currentUser()->getHtmlEditorConfigForCMS());
     }
     $fields->replaceField("Content", CustomHtmlEditorField::create("Content", _t('SiteTree.HTMLEDITORTITLE', "Content", 'HTML editor title'))->addExtraClass('stacked'));
 }
 function init()
 {
     if (Member::currentUser()) {
         CustomHtmlEditorConfig::set_active(Member::currentUser()->getHtmlEditorConfigForCMS());
     }
     Requirements::block(MCE_ROOT . 'tiny_mce_src.js');
     Requirements::block(FRAMEWORK_DIR . "/javascript/HtmlEditorField.js");
     // Set default values in the config if missing.  These things can't be defined in the config
     // file because insufficient information exists when that is being processed
     $htmlEditorConfig = CustomHtmlEditorConfig::get_active();
     $htmlEditorConfig->setOption('language', i18n::get_tinymce_lang());
     if (!$htmlEditorConfig->getOption('content_css')) {
         $cssFiles = array();
         $cssFiles[] = FRAMEWORK_ADMIN_DIR . '/css/editor.css';
         // Use theme from the site config
         if (class_exists('SiteConfig') && ($config = SiteConfig::current_site_config()) && $config->Theme) {
             $theme = $config->Theme;
         } elseif (Config::inst()->get('SSViewer', 'theme_enabled') && Config::inst()->get('SSViewer', 'theme')) {
             $theme = Config::inst()->get('SSViewer', 'theme');
         } else {
             $theme = false;
         }
         if ($theme) {
             $cssFiles[] = THEMES_DIR . "/{$theme}/css/editor.css";
         } else {
             if (project()) {
                 $cssFiles[] = project() . '/css/editor.css';
             }
         }
         // Remove files that don't exist
         foreach ($cssFiles as $k => $cssFile) {
             if (!file_exists(BASE_PATH . '/' . $cssFile)) {
                 unset($cssFiles[$k]);
             }
         }
         $htmlEditorConfig->setOption('content_css', implode(',', $cssFiles));
     }
     CustomHtmlEditorConfig::require_js();
 }
 /**
  * Set the currently active configuration object
  * @param $identifier string - the identifier for the config set
  * @return null
  */
 public static function set_active($identifier = null)
 {
     self::$current = $identifier;
 }
 /**
  * Generate the JavaScript that will set TinyMCE's configuration:
  * - Parse all configurations into JSON objects to be used in JavaScript
  * - Includes TinyMCE and configurations using the {@link Requirements} system
  */
 public static function require_js()
 {
     require_once TINYMCE4_PATH . '/thirdparty/tinymce/tiny_mce_gzip.php';
     $useGzip = Config::inst()->get('CustomHtmlEditorField', 'use_gzip');
     $configs = array();
     $externalPlugins = array();
     $internalPlugins = array();
     $languages = array();
     foreach (self::$configs as $configID => $config) {
         $settings = $config->settings;
         // parse plugins
         $configPlugins = array();
         foreach ($config->plugins as $plugin => $path) {
             if (!$path) {
                 $configPlugins[] = $plugin;
                 $internalPlugins[] = $plugin;
             } else {
                 $configPlugins[] = '-' . $plugin;
                 if (!array_key_exists($plugin, $externalPlugins)) {
                     $externalPlugins[$plugin] = sprintf('tinymce.PluginManager.load("%s", "%s");', $plugin, $path);
                 }
             }
         }
         // save config plugins settings
         $settings['plugins'] = implode(',', $configPlugins);
         // buttons
         foreach ($config->buttons as $i => $buttons) {
             // $settings['theme_advanced_buttons'.$i] = implode(',', $buttons); // tinymce3
             $settings['toolbar' . $i] = implode(',', $buttons);
             // tinymce4
         }
         // languages
         $languages[] = $config->getOption('language');
         // save this config settings
         $configs[$configID] = $settings;
     }
     // tinyMCE JS requirement
     if ($useGzip) {
         $tag = TinyMCE4_Compressor::renderTag(array('url' => TINYMCE4_DIR . '/thirdparty/tinymce/tiny_mce_gzip.php', 'plugins' => implode(',', $internalPlugins), 'themes' => 'advanced', 'languages' => implode(",", array_filter($languages))), true);
         preg_match('/src="([^"]*)"/', $tag, $matches);
         Requirements::javascript(html_entity_decode($matches[1]));
     } else {
         Requirements::javascript(TINYMCE4_DIR . '/thirdparty/tinymce/jquery.tinymce.min.js');
     }
     // block old scripts
     Requirements::block(MCE_ROOT . 'tiny_mce_src.js');
     Requirements::block(FRAMEWORK_DIR . "/javascript/HtmlEditorField.js");
     Requirements::block('htmlEditorConfig');
     // load replacements
     Requirements::javascript(TINYMCE4_DIR . "/javascript/HtmlEditorField.js");
     if (Member::currentUser()) {
         CustomHtmlEditorConfig::set_active(Member::currentUser()->getHtmlEditorConfigForCMS());
     }
     // prepare external plugins js string
     $externalPlugins = array_values($externalPlugins);
     $externalPlugins = implode("\n\t", $externalPlugins);
     // tinyMCE config object and external plugings
     $configsJS = "\nif((typeof tinyMCE != 'undefined')) {\n\t{$externalPlugins}\n\tvar ssTinyMceConfig = " . Convert::raw2json($configs) . ";\n}";
     Requirements::customScript($configsJS, 'customHtmlEditorConfig');
 }
<?php

// TinyMCE Tweaks
HtmlEditorConfig::get('cms')->setOption('theme_advanced_disable', 'underline,justifyfull,pasteword,spellchecker');
HtmlEditorConfig::get('cms')->setOption('valid_styles', array('*' => 'text-align'));
HtmlEditorConfig::get('cms')->setOption('extended_valid_elements', '+article,aside,audio[src|preload<none?metadata?auto|autoplay<autoplay|loop<loop|controls<controls|mediagroup],canvas[width,height],' . 'datalist[data],details[open<open],eventsource[src],fieldset[disabled<disabled|form|name],header,mark,menu[type<context?toolbar?list|label],' . 'meter[value|min|low|high|max|optimum],nav,progress[value,max],script[src|async<async|defer<defer|type|charset],section,time[datetime],' . 'video[preload<none?metadata?auto|src|crossorigin|poster|autoplay<autoplay|mediagroup|loop<loop|muted<muted|controls<controls|width|height],wbr,#span,' . 'form[id|method|onsubmit|onreset|action],input[id|name|style|type|placeholder],label[for]')->setOptions(array('paste_remove_spans' => true, 'paste_remove_styles' => true, 'paste_remove_styles_if_webkit' => true, 'force_br_newlines' => true, 'force_p_newlines' => false, 'paste_text_linebreaktype' => "br", 'paste_auto_cleanup_on_paste' => true));
// Create Simple HTMLEditor Config for use with nathancox/customhtmleditorfield
if (class_exists('CustomHtmlEditorConfig')) {
    $simpleConfig = CustomHtmlEditorConfig::copy('simple', 'cms');
    $simpleConfig->setOption('friendly_name', 'Simple WYSIWYG');
    $simpleConfig->setOption('width', '60%');
    $simpleConfig->setOption('theme_advanced_statusbar_location', 'none');
    $simpleConfig->setButtonsForLine(1, array("bold", "italic", 'formatselect', 'bullist', 'numlist', 'outdent', 'indent', 'pastetext', 'ssmedia', 'sslink', 'unlink', 'code'));
    $simpleConfig->setButtonsForLine(2, array());
    $simpleConfig->setButtonsForLine(3, array());
    $simpleConfig->setOption('theme_advanced_disable', "sub,sup");
    $simpleConfig->setOption('theme_advanced_blockformats', 'p,Heading=h3');
}
// Changes Image backend to GD (required for SilverStripe Optimised Image module)
if (class_exists('OptimisedGDBackend')) {
    Image::set_backend("OptimisedGDBackend");
}
// Remove any extensions via the mysite/_config.php, eg.:
// Page::remove_extension('PageHideExtraMetaData');
// Page::remove_extension('PageSettingsHideSearch');
// Page::remove_extension('PageSettingsHidePermissions');
// Member::remove_extension('MemberTidy');
// UserDefinedForm::remove_extension('HideUserDefinedForm');
<?php

define('TINYMCE4_PATH', dirname(__FILE__));
define('TINYMCE4_DIR', basename(TINYMCE4_PATH));
Object::useCustomClass('HtmlEditorField', 'CustomHtmlEditorField');
Config::inst()->update('HtmlEditorField', 'use_gzip', false);
// Default CMS HTMLEditorConfig
CustomHtmlEditorConfig::get('cms')->setOptions(array('friendly_name' => 'Default CMS', 'priority' => '50', 'body_class' => 'typography', 'document_base_url' => isset($_SERVER['HTTP_HOST']) ? Director::absoluteBaseURL() : null, 'cleanup_callback' => "sapphiremce_cleanup", 'use_native_selects' => false, 'valid_elements' => "@[id|class|style|title],a[id|rel|rev|dir|tabindex|accesskey|type|name|href|target|title" . "|class],-strong/-b[class],-em/-i[class],-strike[class],-u[class],#p[id|dir|class|align|style],-ol[class]," . "-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align|data*]," . "-sub[class],-sup[class],-blockquote[dir|class],-cite[dir|class|id|title]," . "-table[cellspacing|cellpadding|width|height|class|align|summary|dir|id|style]," . "-tr[id|dir|class|rowspan|width|height|align|valign|bgcolor|background|bordercolor|style]," . "tbody[id|class|style],thead[id|class|style],tfoot[id|class|style]," . "#td[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style]," . "-th[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],caption[id|dir|class]," . "-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align],address[class|align]," . "-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style]," . "-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class]," . "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir],@[id,style,class]", 'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name" . "|usemap|data*],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling]," . "object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]"));
CustomHtmlEditorConfig::get('cms')->disablePlugins('contextmenu');
CustomHtmlEditorConfig::get('cms')->enablePlugins('media', 'fullscreen', 'colorpicker', 'importcss');
CustomHtmlEditorConfig::get('cms')->enablePlugins(array('ssbuttons' => '/' . TINYMCE4_DIR . '/thirdparty/tinymce_ssbuttons/editor_plugin_src.js'));
CustomHtmlEditorConfig::get('cms')->addButtonsToLine(1, 'unlink', 'anchor', '|', 'code', 'fullscreen', '|');
CustomHtmlEditorConfig::get('cms')->insertButtonsBefore('undo', 'menubtn', '|');
CustomHtmlEditorConfig::get('cms')->insertButtonsBefore('bold', 'formatselect', '|');
// Menubar options, remove file (and others)
CustomHtmlEditorConfig::get('cms')->setOption('menubar', 'edit view format table tools');
 public function saveInto(DataObjectInterface $record)
 {
     if ($record->hasField($this->name) && $record->escapeTypeForField($this->name) != 'xml') {
         throw new Exception('HtmlEditorField->saveInto(): This field should save into a HTMLText or HTMLVarchar field.');
     }
     $htmlValue = Injector::inst()->create('HTMLValue', $this->value);
     // Sanitise if requested
     if ($this->config()->sanitise_server_side) {
         $santiser = Injector::inst()->create('HtmlEditorSanitiser', CustomHtmlEditorConfig::get_active());
         $santiser->sanitise($htmlValue);
     }
     // Resample images and add default attributes
     if ($images = $htmlValue->getElementsByTagName('img')) {
         foreach ($images as $img) {
             // strip any ?r=n data from the src attribute
             $img->setAttribute('src', preg_replace('/([^\\?]*)\\?r=[0-9]+$/i', '$1', $img->getAttribute('src')));
             // Resample the images if the width & height have changed.
             if ($image = File::find(urldecode(Director::makeRelative($img->getAttribute('src'))))) {
                 $width = $img->getAttribute('width');
                 $height = $img->getAttribute('height');
                 if ($width && $height && ($width != $image->getWidth() || $height != $image->getHeight())) {
                     //Make sure that the resized image actually returns an image:
                     $resized = $image->ResizedImage($width, $height);
                     if ($resized) {
                         $img->setAttribute('src', $resized->getRelativePath());
                     }
                 }
             }
             // Add default empty title & alt attributes.
             if (!$img->getAttribute('alt')) {
                 $img->setAttribute('alt', '');
             }
             if (!$img->getAttribute('title')) {
                 $img->setAttribute('title', '');
             }
         }
     }
     // Store into record
     $record->{$this->name} = $htmlValue->getContent();
 }