mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #4259 from tractorcow/pulls/3/multi-htmleditor-config
API Support for multiple HTMLEditorConfig per page
This commit is contained in:
commit
ad04eeb5c4
@ -339,8 +339,6 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
||||
|
||||
if (Director::isDev()) Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/leaktools.js');
|
||||
|
||||
HTMLEditorField::include_js();
|
||||
|
||||
$leftAndMainIncludes = array_unique(array_merge(
|
||||
array(
|
||||
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Layout.js',
|
||||
|
@ -31,6 +31,34 @@ functionality. It is usually added through the `[api:DataObject->getCMSFields()]
|
||||
}
|
||||
}
|
||||
|
||||
### Specify which configuration to use
|
||||
|
||||
By default, a config named 'cms' is used in any new `[api:HTMLEditorField]`.
|
||||
|
||||
If you have created your own `[api:HtmlEditorConfig]` and would like to use it,
|
||||
you can call `HtmlEditorConfig::set_active('myConfig')` and all subsequently created `[api:HTMLEditorField]`
|
||||
will use the configuration with the name 'myConfig'.
|
||||
|
||||
You can also specify which `[api:HtmlEditorConfig]` to use on a per field basis via the construct argument.
|
||||
This is particularly useful if you need different configurations for multiple `[api:HTMLEditorField]` on the same page or form.
|
||||
|
||||
:::php
|
||||
class MyObject extends DataObject {
|
||||
private static $db = array(
|
||||
'Content' => 'HTMLText',
|
||||
'OtherContent' => 'HTMLText'
|
||||
);
|
||||
|
||||
public function getCMSFields() {
|
||||
return new FieldList(array(
|
||||
new HTMLEditorField('Content'),
|
||||
new HTMLEditorField('OtherContent', 'Other content', $this->OtherContent, 'myConfig')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
In the above example, the 'Content' field will use the default 'cms' config while 'OtherContent' will be using 'myConfig'.
|
||||
|
||||
## Configuration
|
||||
|
||||
To keep the JavaScript editor configuration manageable and extensible, we've wrapped it in a PHP class called
|
||||
@ -41,7 +69,6 @@ There can be multiple configs, which should always be created / accessed using `
|
||||
then set the currently active config using `set_active()`.
|
||||
|
||||
<div class="info" markdown="1">
|
||||
By default, a config named 'cms' is used in any field created throughout the CMS interface.
|
||||
</div>
|
||||
|
||||
<div class="notice" markdown='1'>
|
||||
|
@ -19,6 +19,7 @@
|
||||
* `FormField::validate` now requires an instance of `Validator`
|
||||
* Implementation of new "Archive" concept for page removal, which supercedes "delete". Where deletion removed
|
||||
pages only from draft, archiving removes from both draft and live simultaneously.
|
||||
* Support for multiple HtmlEditorConfigs on the same page.
|
||||
|
||||
#### Deprecated classes/methods removed
|
||||
|
||||
|
@ -39,12 +39,20 @@ class HtmlEditorConfig {
|
||||
self::$current = $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently active configuration identifier
|
||||
* @return String - the active configuration identifier
|
||||
*/
|
||||
public static function get_active_identifier() {
|
||||
$identifier = self::$current ? self::$current : 'default';
|
||||
return $identifier;
|
||||
}
|
||||
/**
|
||||
* Get the currently active configuration object
|
||||
* @return HtmlEditorConfig - the active configuration object
|
||||
*/
|
||||
public static function get_active() {
|
||||
$identifier = self::$current ? self::$current : 'default';
|
||||
$identifier = self::get_active_identifier();
|
||||
return self::get($identifier);
|
||||
}
|
||||
|
||||
@ -291,38 +299,81 @@ class HtmlEditorConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the javascript that will set tinyMCE's configuration to that of the current settings of this object
|
||||
* @return string - the javascript
|
||||
* 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 function generateJS() {
|
||||
$config = $this->settings;
|
||||
public static function require_js() {
|
||||
require_once 'tinymce/tiny_mce_gzip.php';
|
||||
$useGzip = Config::inst()->get('HtmlEditorField', 'use_gzip');
|
||||
|
||||
// plugins
|
||||
$configs = array();
|
||||
$externalPlugins = array();
|
||||
$internalPlugins = array();
|
||||
$externalPluginsJS = '';
|
||||
foreach($this->plugins as $plugin => $path) {
|
||||
if(!$path) {
|
||||
$internalPlugins[] = $plugin;
|
||||
} else {
|
||||
$internalPlugins[] = '-' . $plugin;
|
||||
$externalPluginsJS .= sprintf(
|
||||
'tinymce.PluginManager.load("%s", "%s");' . "\n",
|
||||
$plugin,
|
||||
$path
|
||||
);
|
||||
$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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$config['plugins'] = implode(',', $internalPlugins);
|
||||
|
||||
foreach ($this->buttons as $i=>$buttons) {
|
||||
$config['theme_advanced_buttons'.$i] = implode(',', $buttons);
|
||||
// save config plugins settings
|
||||
$settings['plugins'] = implode(',', $configPlugins);
|
||||
|
||||
// buttons
|
||||
foreach ($config->buttons as $i=>$buttons) {
|
||||
$settings['theme_advanced_buttons'.$i] = implode(',', $buttons);
|
||||
}
|
||||
|
||||
// languages
|
||||
$languages[] = $config->getOption('language');
|
||||
|
||||
// save this config settings
|
||||
$configs[$configID] = $settings;
|
||||
}
|
||||
|
||||
return "
|
||||
// tinyMCE JS requirement
|
||||
if ( $useGzip )
|
||||
{
|
||||
$tag = TinyMCE_Compressor::renderTag(array(
|
||||
'url' => THIRDPARTY_DIR . '/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(MCE_ROOT . 'tiny_mce_src.js');
|
||||
}
|
||||
|
||||
// prepare external plugins js string
|
||||
$externalPlugins = array_values($externalPlugins);
|
||||
$externalPlugins = implode("\n ", $externalPlugins);
|
||||
|
||||
// tinyMCE config object and external plugings
|
||||
$configsJS = "
|
||||
if((typeof tinyMCE != 'undefined')) {
|
||||
$externalPluginsJS
|
||||
var ssTinyMceConfig = " . Convert::raw2json($config) . ";
|
||||
}
|
||||
";
|
||||
$externalPlugins
|
||||
var ssTinyMceConfig = " . Convert::raw2json($configs) . ";
|
||||
}";
|
||||
Requirements::customScript($configsJS, 'htmlEditorConfig');
|
||||
}
|
||||
}
|
||||
|
@ -27,41 +27,31 @@ class HtmlEditorField extends TextareaField {
|
||||
private static $sanitise_server_side = false;
|
||||
|
||||
protected $rows = 30;
|
||||
|
||||
|
||||
/**
|
||||
* Includes the JavaScript neccesary for this field to work using the {@link Requirements} system.
|
||||
* @deprecated since version 3.2
|
||||
*/
|
||||
public static function include_js() {
|
||||
require_once 'tinymce/tiny_mce_gzip.php';
|
||||
|
||||
$configObj = HtmlEditorConfig::get_active();
|
||||
|
||||
if(Config::inst()->get('HtmlEditorField', 'use_gzip')) {
|
||||
$internalPlugins = array();
|
||||
foreach($configObj->getPlugins() as $plugin => $path) if(!$path) $internalPlugins[] = $plugin;
|
||||
$tag = TinyMCE_Compressor::renderTag(array(
|
||||
'url' => THIRDPARTY_DIR . '/tinymce/tiny_mce_gzip.php',
|
||||
'plugins' => implode(',', $internalPlugins),
|
||||
'themes' => 'advanced',
|
||||
'languages' => $configObj->getOption('language')
|
||||
), true);
|
||||
preg_match('/src="([^"]*)"/', $tag, $matches);
|
||||
Requirements::javascript(html_entity_decode($matches[1]));
|
||||
|
||||
} else {
|
||||
Requirements::javascript(MCE_ROOT . 'tiny_mce_src.js');
|
||||
}
|
||||
|
||||
Requirements::customScript($configObj->generateJS(), 'htmlEditorConfig');
|
||||
Deprecation::notice('4.0', 'Use HtmlEditorConfig::require_js() instead');
|
||||
HtmlEditorConfig::require_js();
|
||||
}
|
||||
|
||||
|
||||
protected $editorConfig = null;
|
||||
|
||||
/**
|
||||
* Creates a new HTMLEditorField.
|
||||
* @see TextareaField::__construct()
|
||||
*/
|
||||
public function __construct($name, $title = null, $value = '') {
|
||||
*
|
||||
* @param string $name The internal field name, passed to forms.
|
||||
* @param string $title The human-readable field label.
|
||||
* @param mixed $value The value of the field.
|
||||
* @param string $config HTMLEditorConfig identifier to be used. Default to the active one.
|
||||
*/
|
||||
public function __construct($name, $title = null, $value = '', $config = null) {
|
||||
parent::__construct($name, $title, $value);
|
||||
|
||||
self::include_js();
|
||||
$this->editorConfig = $config ? $config : HtmlEditorConfig::get_active_identifier();
|
||||
}
|
||||
|
||||
public function getAttributes() {
|
||||
@ -71,6 +61,7 @@ class HtmlEditorField extends TextareaField {
|
||||
'tinymce' => 'true',
|
||||
'style' => 'width: 97%; height: ' . ($this->rows * 16) . 'px', // prevents horizontal scrollbars
|
||||
'value' => null,
|
||||
'data-config' => $this->editorConfig
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -185,6 +176,8 @@ class HtmlEditorField_Toolbar extends RequestHandler {
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/ssui.core.js');
|
||||
|
||||
HtmlEditorConfig::require_js();
|
||||
Requirements::javascript(FRAMEWORK_DIR ."/javascript/HtmlEditorField.js");
|
||||
|
||||
Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
|
||||
|
@ -332,8 +332,8 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
|
||||
},
|
||||
|
||||
redraw: function() {
|
||||
// Using a global config (generated through HTMLEditorConfig PHP logic)
|
||||
var config = ssTinyMceConfig, self = this, ed = this.getEditor();
|
||||
// Using textarea config ID from global config object (generated through HTMLEditorConfig PHP logic)
|
||||
var config = ssTinyMceConfig[this.data('config')], self = this, ed = this.getEditor();
|
||||
|
||||
ed.init(config);
|
||||
|
||||
|
@ -67,12 +67,26 @@ class HtmlEditorConfigTest extends SapphireTest {
|
||||
$this->assertNotContains('plugin2', array_keys($plugins));
|
||||
}
|
||||
|
||||
public function testGenerateJSWritesPlugins() {
|
||||
$c = new HtmlEditorConfig();
|
||||
$c->enablePlugins(array('plugin1'));
|
||||
public function testRequireJSIncludesAllExternalPlugins() {
|
||||
$c = HtmlEditorConfig::get('config');
|
||||
$c->enablePlugins(array('plugin1' => '/mypath/plugin1'));
|
||||
$c->enablePlugins(array('plugin2' => '/mypath/plugin2'));
|
||||
|
||||
$this->assertContains('plugin1', $c->generateJS());
|
||||
$this->assertContains('tinymce.PluginManager.load("plugin2", "/mypath/plugin2");', $c->generateJS());
|
||||
HtmlEditorConfig::require_js();
|
||||
$js = Requirements::get_custom_scripts();
|
||||
|
||||
$this->assertContains('tinymce.PluginManager.load("plugin1", "/mypath/plugin1");', $js);
|
||||
$this->assertContains('tinymce.PluginManager.load("plugin2", "/mypath/plugin2");', $js);
|
||||
}
|
||||
|
||||
public function testRequireJSIncludesAllConfigs() {
|
||||
$c = HtmlEditorConfig::get('configA');
|
||||
$c = HtmlEditorConfig::get('configB');
|
||||
|
||||
HtmlEditorConfig::require_js();
|
||||
$js = Requirements::get_custom_scripts();
|
||||
|
||||
$this->assertContains('"configA":{', $js);
|
||||
$this->assertContains('"configB":{', $js);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user