Jump to content

[Solved] Use TinyMCE with HelperOptions?


tesial

Recommended Posts

Does anybody know how  to use TinyMCE (the wysiwyg editor) with the HelperOptions on a Textarea to allow HTML.
 
Here is a concrete example based on a random AdminController:
 

class AdminXYZController extends AdminXYZControllerCore
{
	public function __construct()
	{
		parent::__construct();

		$this->fields_options['content'] = array(
			'title' =>	$this->l('My field set'),
			'icon' =>	'icon-bullhorn',
			'fields' => array(
				// ... some fields definition ...
				'PS_TESIAL_MM_TEXT' => array(
					'title' => $this->l('Field title'),
					'desc' => $this->l('Field description'),
					'validation' => 'isCleanHtml',	// Don't know if it's actually working
					'type' => 'textarea',			// Telling it's a textarea
					'cols' => '30',
					'rows' => '5',
					'tinymce' => true				// not taken into account
				),
				// ... other fields definition ...
			),
			'submit' => array(
				'title' => $this->l('Save')
			)
		);
	}
}

For the sake of simplicity, let's say that this controller is well installed into the override and so on. It is working and is displayed properly.
 
Two issues:

  • HTML is stripped from the textarea on submit. This is the default behavior of the parent.
  • TinyMCE cannot be enabled (the code is simply not present in the parent at all).
Edited by tesial (see edit history)
Link to comment
Share on other sites

I've already tryed that, that's how it's done with the HelperForm but it doesn't work with HelperOptions.

 

Moreover, the code that include the js and css + tpl_var related to the tinymce is not present in the HelperOptions and the JS call to tinySetup() is not writted either. I'm trying to figuring out the proper way to do it but i think i might have to bypass everything and do it manually (add the JS, CSS and the JS call in my template).

Link to comment
Share on other sites

Ok i've find the way to do it.

 

  • Support multi-lang
  • Default behavior kept
  • No core change, modification in an override file

 

Here is the solution for future use:

<?php

class AdminXYZController extends AdminXYZControllerCore
{
	public function __construct()
	{
		parent::__construct();

		// Define your fields
		$this->fields_options['content'] = array(
			'title' =>	$this->l('Page content'),
			'icon' =>	'icon-bullhorn',
			'fields' => array(
				'FIELD_KEY' => array(
					// ...
					'type' => 'textarea',
					'html' => true,			// flag this textarea as being HTML, used below
					// ..
				)
			),
			// ...
		);
	}

	public function renderOptions()
	{
		// Using tpl_option_vars doesn't add them properly
		/*
		$iso = $this->context->language->iso_code;
		$this->tpl_option_vars['iso'] = file_exists(_PS_CORE_DIR_.'/js/tiny_mce/langs/'.$iso.'.js') ? $iso : 'en';
		$this->tpl_option_vars['path_css'] = _THEME_CSS_DIR_;
		$this->tpl_option_vars['ad'] = __PS_BASE_URI__.basename(_PS_ADMIN_DIR_);
		$this->tpl_option_vars['tinymce'] = true;
		*/

		// Manually assign the required var
		$iso = $this->context->language->iso_code;
		$this->context->smarty->assign(array(
			'iso' => file_exists(_PS_CORE_DIR_.'/js/tiny_mce/langs/'.$iso.'.js') ? $iso : 'en',
			'path_css' => _THEME_CSS_DIR_,
			'ad' => __PS_BASE_URI__.basename(_PS_ADMIN_DIR_),
			'tinymce' => true
		));

		// Adding js and css
		$this->context->controller->addJS(_PS_JS_DIR_.'tiny_mce/tiny_mce.js');
		$this->context->controller->addJS(_PS_JS_DIR_.'tinymce.inc.js');

		return parent::renderOptions();
	}

	/**
	 * Update options and preferences
	 * Note: this is a copy/past of the same method in the AdminController
	 * just to add the "true" parameter to Configuration::updateValue() for textarea
	 */
	protected function processUpdateOptions()
	{
		// First process the default behavior
		parent::processUpdateOptions();

		// Then, if no error were found, re-process the list to find 'html' data
		if (!count($this->errors)) {
			$languages = Language::getLanguages(false);
			$hide_multishop_checkbox = (Shop::getTotalShops(false, null) < 2) ? true : false;

			foreach ($this->fields_options as $category_data)
			{
				if (!isset($category_data['fields']))
					continue;

				$fields = $category_data['fields'];

				foreach ($fields as $field => $values)
				{
					if (isset($values['type']) && $values['type'] == 'selectLang')
					{
						foreach ($languages as $lang)
							if (Tools::getValue($field.'_'.strtoupper($lang['iso_code'])))
								$fields[$field.'_'.strtoupper($lang['iso_code'])] = array(
									'type' => 'select',
									'cast' => 'strval',
									'identifier' => 'mode',
									'list' => $values['list']
								);
					}
				}

				// Field post-processing for HTML
				// This code is the same as in AdminController (after validation)
				foreach ($fields as $key => $options)
				{
					if (array_key_exists('html', $values) && $values['html']) {
						// This field is an html field, override the saved value
						if (!$hide_multishop_checkbox && Shop::isFeatureActive() && isset($options['visibility']) && $options['visibility'] > Shop::getContext())
							continue;

						if (!$hide_multishop_checkbox && Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_ALL && empty($options['no_multishop_checkbox']) && empty($_POST['multishopOverrideOption'][$key]))
						{
							Configuration::deleteFromContext($key);
							continue;
						}

						// check if a method updateOptionFieldName is available
						$method_name = 'updateOption'.Tools::toCamelCase($key, true);
						if (method_exists($this, $method_name))
							$this->$method_name(Tools::getValue($key));
						elseif (isset($options['type']) && in_array($options['type'], array('textLang', 'textareaLang')))
						{
							$list = array();
							foreach ($languages as $language)
							{
								$key_lang = Tools::getValue($key.'_'.$language['id_lang']);
								$val = (isset($options['cast']) ? $options['cast']($key_lang) : $key_lang);
								if ($this->validateField($val, $options))
								{
									// No validation required, already done
									$list[$language['id_lang']] = $val;
								}
							}
							// Add the "true" flag to updateValue
							Configuration::updateValue($key, $list, true);
						}
						else
						{
							$val = (isset($options['cast']) ? $options['cast'](Tools::getValue($key)) : Tools::getValue($key));
							if ($this->validateField($val, $options))
							{
								// No validation required, already done
								// Add the "true" flag to updateValue
								Configuration::updateValue($key, $val, true);
							}
						}
					}
				}
			}
		}
	}
	
	// ...
}

The template part: an options.tpl which override you're AdminXYZController's template

{extends file="controllers/xyz/helpers/options/options.tpl"}

{block name="defaultOptions"}
	<script type="text/javascript">
		var iso = '{$iso}';
		var pathCSS = '{$path_css}';
		var ad = '{$ad}';

		$(document).ready(function(){
			$('textarea').addClass('rte autoload_rte'); // Not good, i know
			tinySetup({
				editor_selector :"autoload_rte"
			});
		});
	</script>

	{$smarty.block.parent}
{/block}
 

Thanks for your help.

 

Edit:

Instead of overriding processUpdateOptions, it is possible to define a method updateOption[FieldNameInCamelCase] to store the field value in html.

Edited by tesial (see edit history)
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...