praiadeseselle/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCESettings.php

838 lines
26 KiB
PHP
Raw Normal View History

<?php namespace ProcessWire;
/**
* InputfieldTinyMCETools
*
* Helper for managing TinyMCE settings and defaults
*
* ProcessWire 3.x, Copyright 2023 by Ryan Cramer
* https://processwire.com
*
*/
class InputfieldTinyMCESettings extends InputfieldTinyMCEClass {
/**
* Runtime caches shared among all instances
*
* @var array
*
*/
static protected $caches = array(
'defaults' => array(),
'settings' => array(),
'alignClasses' => array(),
'renderReadyInline' => array(),
'langSettings' => array(),
'addDefaults' => array(),
'originalDefaults' => array(),
);
/**
* Get settings from Inputfield vary from the $defaults
*
* @param array|null $defaults Default settings Default settings or omit to pull automatically
* @param string $cacheKey Optionally cache with this key
* @return array
*
*/
public function getSettings($defaults = null, $cacheKey = '') {
$inputfield = $this->inputfield;
if($cacheKey && isset(self::$caches['settings'][$cacheKey])) return self::$caches['settings'][$cacheKey];
if($defaults === null) $defaults = $this->getDefaults();
$settings = array();
$features = $inputfield->features;
$formats = $this->formats();
foreach($defaults as $name => $defaultValue) {
if($name === 'menubar') {
if(in_array($name, $features)) {
$value = $inputfield->get('menubar');
if(empty($value) || $value === 'default') $value = $defaultValue;
} else {
$value = false;
}
} else if($name === 'statusbar') {
$value = true;
} else if($name === 'browser_spellcheck') {
$value = in_array('spellcheck', $features);
} else if($name === 'toolbar') {
$value = in_array($name, $features) ? $inputfield->get($name) : '';
} else if($name === 'toolbar_sticky') {
$value = in_array('stickybars', $features);
} else if($name === 'content_css') {
$value = $inputfield->get($name);
if($value === 'custom') {
$value = $inputfield->get('content_css_url');
if(empty($value)) continue;
}
} else if($name === 'directionality') {
$value = $inputfield->getDirectionality();
} else if($name === 'style_formats') {
$value = $formats->getStyleFormats($defaults);
} else if($name === 'block_formats') {
$value = $formats->getBlockFormats();
} else if($name === 'invalid_styles') {
$value = $formats->getInvalidStyles($inputfield->invalid_styles, $defaultValue);
} else if($name === 'formats') {
// overlaps with native formats property so use data rather than get
$value = $inputfield->data('formats');
} else if($name === 'templates') {
// overlaps with API variable
$value = $inputfield->data($name);
} else {
$value = $inputfield->get($name);
if($value === 'default') $value = $defaultValue;
}
if($name === 'removed_menuitems' && strpos($value, 'print') === false) {
// the print option is not useful in inline mode
if($inputfield->inlineMode) $value = trim("$value print");
}
if($value !== null && $value != $defaultValue) {
$settings[$name] = $value;
}
}
$this->applySkin($settings, $defaults);
$this->applyPlugins($settings, $defaults);
if(isset($defaults['style_formats'])) {
$styleFormatsCSS = $inputfield->get('styleFormatsCSS');
if($styleFormatsCSS) {
$formats->applyStyleFormatsCSS($styleFormatsCSS, $settings, $defaults);
}
}
if($cacheKey) self::$caches['settings'][$cacheKey] = $settings;
return $settings;
}
/**
* Default settings for ProcessWire.config.InputfieldTinyMCE
*
* This should have no field-specific settings (no dynamic values)
*
* @property string $key
* @return array
*
*/
public function getDefaults($key = '') {
if(!empty(self::$caches['defaults'])) {
if($key) return isset(self::$caches['defaults'][$key]) ? self::$caches['defaults'][$key] : null;
return self::$caches['defaults'];
}
$config = $this->wire()->config;
$root = $config->urls->root;
$url = $config->urls($this->inputfield);
$tools = $this->tools();
// root relative, i.e. '/site/modules/InputfieldTinyMCE/'
$url = substr($url, strlen($root)-1);
$alignClasses = $this->getAlignClasses();
$mceSettingNames = $this->inputfield->getSettingNames('tinymce');
$optionalSettingNames = $this->inputfield->getSettingNames('optionals');
$optionals = $this->inputfield->optionals;
// selector of elements that can be used with align commands
$replacements = array(
'{url}' => $url,
'{alignleft}' => $alignClasses['left'],
'{aligncenter}' => $alignClasses['center'],
'{alignright}' => $alignClasses['right'],
'{alignfull}' => $alignClasses['full'],
);
$json = file_get_contents(__DIR__ . '/defaults.json');
$json = str_replace(array_keys($replacements), array_values($replacements), $json);
$defaults = $tools->jsonDecode($json, 'defaults.json');
// defaults JSON file
$file = $this->inputfield->defaultsFile;
if($file) {
$file = $config->paths->root . ltrim($file, '/');
$data = $tools->jsonDecodeFile($file, 'default settings file for module');
if(is_array($data) && !empty($data)) $defaults = array_merge($defaults, $data);
}
// defaults JSON text
$json = $this->inputfield->defaultsJSON;
if($json) {
$data = $tools->jsonDecode($json, 'defaults JSON module setting');
if(is_array($data) && !empty($data)) $defaults = array_merge($defaults, $data);
}
// extra CSS module setting
$extraCSS = $this->inputfield->extraCSS;
if(strlen($extraCSS)) {
$contentStyle = isset($defaults['content_style']) ? $defaults['content_style'] : '';
$contentStyle .= "\n$extraCSS";
$defaults['content_style'] = $contentStyle;
}
// optionals
foreach($optionalSettingNames as $name) {
if(in_array($name, $optionals)) continue; // configured with field (not module)
if(!in_array($name, $mceSettingNames)) continue; // not a direct TinyMCE setting
$value = $this->inputfield->get($name);
if($value === 'default' || $value === null) continue;
if($name === 'invalid_styles' && is_string($value)) {
$value = $this->formats()->invalidStylesStrToArray($value);
}
if(isset($defaults[$name]) && $defaults[$name] !== $value) {
self::$caches['originalDefaults'][$name] = $defaults[$name];
}
$defaults[$name] = $value;
}
$languageSettings = $this->getLanguageSettings();
if(!empty($languageSettings)) $defaults = array_merge($defaults, $languageSettings);
foreach($defaults as $k => $value) {
if(strpos($k, 'add_') === 0 || strpos($k, 'append_') === 0 || strpos($k, 'replace_') === 0) {
self::$caches['addDefaults'][$k] = $value;
unset($defaults[$k]);
}
}
self::$caches['defaults'] = $defaults;
if($key) return isset($defaults[$key]) ? $defaults[$key] : null;
return $defaults;
}
/**
* Get original defaults from source JSON, prior to being overriden by module default settings
*
* @param string $key
* @return array|mixed|null
*
*/
public function getOriginalDefaults($key = '') {
$defaults = $this->getDefaults();
if($key) {
if(isset(self::$caches['originalDefaults'][$key])) {
return self::$caches['originalDefaults'][$key];
} else {
return isset($defaults[$key]) ? $defaults[$key] : null;
}
}
return array_merge($defaults, self::$caches['originalDefaults']);
}
/**
* Get 'add_' or 'replace_' default settings
*
* @return array|mixed
*
*/
public function getAddDefaults() {
return self::$caches['addDefaults'];
}
/**
* Apply plugins settings
*
* @param array $settings
* @param array $defaults
*
*/
protected function applyPlugins( array &$settings, array $defaults) {
$extPlugins = $this->inputfield->get('extPlugins');
if(!empty($extPlugins)) {
$value = $defaults['external_plugins'];
foreach($extPlugins as $url) {
$name = basename($url, '.js');
$value[$name] = $url;
}
$settings['external_plugins'] = $value;
}
if(isset($defaults['plugins'])) {
$plugins = $this->inputfield->get('plugins');
if(empty($plugins) && !empty($defaults['plugins'])) $plugins = $defaults['plugins'];
if(!is_array($plugins)) $plugins = explode(' ', $plugins);
if(!in_array('pwlink', $plugins)) {
unset($settings['external_plugins']['pwlink']);
if(isset($settings['menu'])) {
$settings['menu']['insert']['items'] = str_replace('pwlink', 'link', $settings['menu']['insert']['items']);
}
}
if(!in_array('pwimage', $plugins)) {
unset($settings['external_plugins']['pwimage']);
if(isset($settings['menu'])) {
$settings['menu']['insert']['items'] = str_replace('pwimage', 'image', $settings['menu']['insert']['items']);
}
}
$settings['plugins'] = implode(' ', $plugins);
if($settings['plugins'] === $defaults['plugins']) unset($settings['plugins']);
}
}
/**
* Apply skin or skin_url directly to given settings/defaults
*
* @param array $settings
* @param array $defaults
*
*/
protected function applySkin(&$settings, $defaults) {
$skin = $this->inputfield->skin;
if($skin === 'custom') {
$skinUrl = rtrim($this->inputfield->skin_url, '/');
if(strlen($skinUrl)) {
if(strpos($skinUrl, '//') === false) {
$skinUrl = $this->wire()->config->urls->root . ltrim($skinUrl, '/');
}
if(!isset($defaults['skin_url']) || $defaults['skin_url'] != $skinUrl) {
$settings['skin_url'] = $skinUrl;
}
unset($settings['skin']);
}
} else {
if(isset($defaults['skin']) && $defaults['skin'] != $skin) {
$settings['skin'] = $skin;
}
unset($settings['skin_url']);
}
}
/**
* Get image alignment classes
*
* @return array
*
*/
public function getAlignClasses() {
if(empty(self::$caches['alignClasses'])) {
$data = $this->wire()->modules->getModuleConfigData('ProcessPageEditImageSelect');
self::$caches['alignClasses'] = array(
'left' => (empty($data['alignLeftClass']) ? 'align_left' : $data['alignLeftClass']),
'right' => (empty($data['alignRightClass']) ? 'align_right' : $data['alignRightClass']),
'center' => (empty($data['alignCenterClass']) ? 'align_center' : $data['alignCenterClass']),
'full' => 'align_full',
);
}
return self::$caches['alignClasses'];
}
/**
* Get settings from custom settings file
*
* @return array
*
*/
protected function getFromSettingsFile() {
$file = $this->inputfield->get('settingsFile');
if(empty($file)) return array();
$file = $this->wire()->config->paths->root . ltrim($file, '/');
return $this->tools()->jsonDecodeFile($file, 'settingsFile');
}
/**
* Get settings from custom JSON
*
* @return array
*
*/
protected function getFromSettingsJSON() {
$json = trim((string) $this->inputfield->get('settingsJSON'));
if(empty($json)) return array();
return $this->tools()->jsonDecode($json, 'settingsJSON');
}
/**
* Get content_css URL
*
* @param string $content_css
* @return string
*
*/
public function getContentCssUrl($content_css = '') {
$config = $this->wire()->config;
$rootUrl = $config->urls->root;
$defaultUrl = $config->urls($this->inputfield) . 'content_css/wire.css';
if($this->inputfield->useFeature('document')) {
$content_css = 'document';
}
if(empty($content_css)) {
if($this->inputfield->useFeature('document')) {
$content_css = 'document';
} else {
$content_css = $this->inputfield->content_css;
}
}
if($content_css === 'wire' || empty($content_css)) {
// default
$url = $defaultUrl;
} else if(strpos($content_css, '/') !== false) {
// custom file
$url = $rootUrl . ltrim($content_css, '/');
} else if($content_css === 'custom') {
// custom file (alternate/fallback)
$content_css_url = $this->inputfield->content_css_url;
if(empty($content_css_url) || strpos($content_css_url, '/') === false) {
$url = $defaultUrl;
} else {
$url = $rootUrl . ltrim($content_css_url, '/');
}
} else if($content_css) {
// defined
$content_css = basename($content_css, '.css');
$url = $config->urls($this->inputfield) . "content_css/$content_css.css";
} else {
$url = $defaultUrl;
}
return $url;
}
/**
* Prepare given settings ready for output
*
* This converts relative URLs to absolute, etc.
*
* @param array $settings
* @return array
*
*/
public function prepareSettingsForOutput(array $settings) {
$config = $this->wire()->config;
$rootUrl = $config->urls->root;
//$inline = $this->inputfield->inlineMode > 0;
/*
if($inline) {
// content_css not loaded here
//$settings['content_css'] = '';
*/
if(isset($settings['content_css'])) {
// convert content_css setting to URL
$settings['content_css'] = $this->getContentCssUrl($settings['content_css']);
}
if(!empty($settings['external_plugins'])) {
foreach($settings['external_plugins'] as $name => $url) {
$settings['external_plugins'][$name] = $rootUrl . ltrim($url, '/');
}
}
if(isset($settings['height'])) {
$settings['height'] = "$settings[height]px";
}
if(isset($settings['toolbar']) && is_string($settings['toolbar'])) {
$splitTools = array('styles', 'blocks');
foreach($splitTools as $name) {
$settings['toolbar'] = str_replace("$name ", "$name | ", $settings['toolbar']);
}
}
if(empty($settings['invalid_styles'])) {
// for empty invalid_styles use blank string rather than blank array
$settings['invalid_styles'] = '';
}
if(!empty($settings['content_style'])) {
// namespace content_style for .mce_content_body
$contentStyle = $settings['content_style'];
$contentStyle = str_replace('}', "}\n", $contentStyle);
$contentStyle = preg_replace('![\s\r\n]+\{!', '{', $contentStyle);
$lines = explode("\n", $contentStyle);
foreach($lines as $k => $line) {
$line = trim($line);
if(empty($line)) {
unset($lines[$k]);
} else if(strpos($line, '.mce-content-body') !== false) {
continue;
} else if(strpos($line, '{')) {
$lines[$k] = ".mce-content-body $line";
}
}
$contentStyle = implode(' ', $lines);
while(strpos($contentStyle, ' ') !== false) $contentStyle = str_replace(' ', ' ', $contentStyle);
$contentStyle = str_replace(['{ ', ' }'], ['{', '}'], $contentStyle);
$contentStyle = str_replace('@', "\\@", $contentStyle);
$settings['content_style'] = $contentStyle;
}
/*
if(isset($settings['plugins']) && is_array($settings['plugins'])) {
$settings['plugins'] = implode(' ', $settings['plugins']);
}
*/
// ensure blank object properties resolve to {} in JSON rather than []
foreach($this->tools()->jsonBlankObjectProperties as $name) {
if(!isset($settings[$name]) || !empty($settings[$name]) || !is_array($settings[$name])) continue;
$settings[$name] = (object) $settings[$name];
}
return $settings;
}
/**
* Get language pack code
*
* @return string
*
*/
public function getLanguagePackCode() {
$default = 'en_US';
$languages = $this->wire()->languages;
$sanitizer = $this->wire()->sanitizer;
$path = __DIR__ . '/langs/';
if(!$languages) return $default;
$language = $this->wire()->user->language;
// attempt to get from module setting
$value = $this->inputfield->get("lang_$language->name");
if($value) return $value;
// attempt to get from non-default language name
if(!$language->isDefault() && is_file("$path$language->name.js")) {
return $language->name;
}
// attempt to get from admin theme
$adminTheme = $this->wire()->adminTheme;
if($adminTheme) {
$value = $sanitizer->name($adminTheme->_('en'));
if($value !== 'en' && is_file("$path$value.js")) return $value;
}
$value = $languages->getLocale();
// attempt to get from locale setting
if($value !== 'C') {
if(strpos($value, '.')) list($value,) = explode('.', $value, 2);
if(is_file("$path$value.js")) return $value;
if(strpos($value, '_')) {
list($value,) = explode('_', $value, 2);
if(is_file("$path$value.js")) return $value;
}
}
// attempt to get from CKEditor static translation
$textdomain = '/wire/modules/Inputfield/InputfieldCKEditor/InputfieldCKEditor.module';
if(is_file($this->wire()->config->paths->root . ltrim($textdomain, '/'))) {
$value = _x('en', 'language-pack', $textdomain);
if($value !== 'en') {
$value = $sanitizer->name($value);
if($value && is_file("$path$value.js")) return $value;
}
}
return $default;
}
/**
* Get language pack settings
*
* @return array
*
*/
public function getLanguageSettings() {
if(!$this->wire()->languages) return array();
$language = $this->wire()->user->language;
if(isset(self::$caches['langSettings'][$language->id])) {
return self::$caches['langSettings'][$language->id];
}
$code = $this->getLanguagePackCode();
if($code === 'en_US') {
$value = array();
} else {
$value = array(
'language' => $code,
'language_url' => $this->wire()->config->urls($this->inputfield) . "langs/$code.js"
);
}
self::$caches['langSettings'][$language->id] = $value;
return $value;
}
/**
* Apply 'add_*' settings in $addSettings, plus merge all $addSettings into given $settings
*
* This updates the $settings and $addSettings variables directly
*
* @param array $settings
* @param array $addSettings
* @param array $defaults
*
*/
protected function applyAddSettings(array &$settings, array &$addSettings, array $defaults) {
// apply add_style_formats when present
if(isset($addSettings['add_style_formats'])) {
$styleFormats = isset($settings['style_formats']) ? $settings['style_formats'] : $defaults['style_formats'];
$settings['style_formats'] = $this->formats()->mergeStyleFormats($styleFormats, $addSettings['add_style_formats']);
unset($addSettings['add_style_formats']);
}
// find other add_* properties, i.e. 'add_formats', 'add_invalid_styles', 'add_plugins'
// these append rather than replace, i.e. 'add_formats' appends to 'formats'
// also find any replace_* properties and replace setting values rather than append
foreach($addSettings as $key => $addValue) {
if(strpos($key, 'replace_') === 0) {
list(,$k) = explode('replace_', $key, 2);
if(!isset($addSettings[$k]) && $addValue !== null) $addSettings[$k] = $addValue;
unset($addSettings[$key]);
continue;
}
if(strpos($key, 'append_') === 0) {
unset($addSettings[$key]);
$key = str_replace('append_', 'add_', $key);
}
if(strpos($key, 'add_') !== 0) continue;
list(,$name) = explode('add_', $key, 2);
unset($addSettings[$key]);
if(isset($settings[$name])) {
// present in settings
$value = $settings[$name];
} else if(isset($defaults[$name])) {
// present in defaults
$value = $defaults[$name];
} else {
// not present, add it to settings
$addSettings[$name] = $addValue;
continue;
}
$addSettings[$name] = $this->mergeSetting($value, $addValue);
}
$settings = array_merge($settings, $addSettings);
}
/**
* Merge two setting values into one that combines them
*
* @param string|array|mixed $value
* @param string|array|mixed $addValue
* @return string|array|mixed
*
*/
protected function mergeSetting($value, $addValue) {
if(is_string($value) && is_string($addValue)) {
$value .= " $addValue";
} else if(is_array($addValue) && is_array($value)) {
foreach($addValue as $k => $v) {
if(is_int($k)) {
// append
$value[] = $v;
} else {
// append or replace
$value[$k] = $v;
}
}
} else {
$value = $addValue;
}
return $value;
}
/**
* Merge all settings in given array and combine those with "add_" prefix
*
* @param array $settings1
* @param array $settings2 Optionally specify this to merge/combine with those in $settings1
* @return array
*
*/
protected function mergeSettings(array $settings1, array $settings2 = array()) {
$settings = array_merge($settings1, $settings2);
$addSettings = array();
foreach($settings1 as $key => $value) {
if(strpos($key, 'add_') !== 0) continue;
$addSettings[$key] = $value;
}
foreach($settings2 as $key => $value) {
if(strpos($key, 'add_') !== 0) continue;
if(isset($addSettings[$key])) {
$addSettings[$key] = $this->mergeSetting($addSettings[$key], $value);
} else {
$addSettings[$key] = $value;
}
}
if(count($addSettings)) $settings = array_merge($settings, $addSettings);
return $settings;
}
/**
* Determine which settings go where and apply to Inputfield
*
* @param array $addSettings Optionally add this settings on top of those that would otherwise be used
*
*/
public function applyRenderReadySettings(array $addSettings = array()) {
$config = $this->wire()->config;
$inputfield = $this->inputfield;
$configName = $inputfield->getConfigName();
// default settings
$defaults = $this->getDefaults();
$addDefaults = $this->getAddDefaults();
$fileSettings = $this->getFromSettingsFile();
$jsonSettings = $this->getFromSettingsJSON();
if(count($fileSettings)) $addDefaults = $this->mergeSettings($addDefaults, $fileSettings);
if(count($jsonSettings)) $addDefaults = $this->mergeSettings($addDefaults, $jsonSettings);
if(count($addSettings)) $addDefaults = $this->mergeSettings($addDefaults, $addSettings);
$addSettings = $addDefaults;
if($configName && $configName !== 'default') {
$js = $config->js($inputfield->className());
// get settings that differ between field and defaults, then set to new named config
$diffSettings = $this->getSettings($defaults, $configName);
$mergedSettings = array_merge($defaults, $diffSettings);
//$contentStyle = isset($mergedSettings['content_style']) ? $mergedSettings['content_style'] : '';
if(count($addSettings)) {
// merges $addSettings into $diffSettings
$this->applyAddSettings($diffSettings, $addSettings, $defaults);
}
if(!isset($js['settings'][$configName])) {
$js['settings'][$configName] = $this->prepareSettingsForOutput($diffSettings);
$config->js($inputfield->className(), $js);
}
// get settings that will go in data-settings attribute
// remove settings that cannot be set for field/template context
unset($mergedSettings['style_formats'], $mergedSettings['content_style'], $mergedSettings['content_css']);
$dataSettings = $this->getSettings($mergedSettings);
} else {
// no configName in use, data-settings attribute will hold all non-default settings
$dataSettings = $this->getSettings($defaults);
//$contentStyle = isset($dataSettings['content_style']) ? $dataSettings['content_style'] : '';
if(count($addSettings)) {
$this->applyAddSettings($dataSettings, $addSettings, $defaults);
}
}
if($inputfield->inlineMode) {
if($inputfield->inlineMode < 2) unset($dataSettings['height']);
$dataSettings['inline'] = true;
/*
if($contentStyle && $adminTheme) {
$cssName = $configName;
if(empty($cssName)) {
$cssName = substr(md5($contentStyle), 0, 4) . strlen($contentStyle);
}
$inputfield->addClass("tmcei-$cssName", 'wrapClass');
if(!isset(self::$caches['renderReadyInline'][$cssName])) {
// inline mode content_style settings, ensure they are visible before inline init
//$ns = ".tmcei-$cssName .mce-content-body ";
//$contentStyle = $ns . str_replace('}', "} $ns", $contentStyle) . '{}';
//$adminTheme->addExtraMarkup('head', "<style>$contentStyle</style>");
self::$caches['renderReadyInline'][$cssName] = $cssName;
}
}
*/
}
$dataSettings = count($dataSettings) ? $this->prepareSettingsForOutput($dataSettings) : array();
if($inputfield->renderValueMode) $dataSettings['readonly'] = true;
$features = array('imgUpload', 'imgResize', 'pasteFilter');
foreach($features as $key => $feature) {
if(!$inputfield->useFeature($feature)) unset($features[$key]);
}
if($inputfield->lazyMode) $features[] = "lazyMode$inputfield->lazyMode";
$inputfield->wrapAttr('data-configName', $configName);
$inputfield->wrapAttr('data-settings', $this->tools()->jsonEncode($dataSettings, 'data-settings', false));
$inputfield->wrapAttr('data-features', implode(',', $features));
}
/**
* Apply settings settings to $this->inputfield to inherit from another field
*
* This is called from the main InputfieldTinyMCE class.
*
* @param string $fieldName Field name or 'fieldName:id' string
* @return bool|Field Returns false or field inherited from
*
*/
public function applySettingsField($fieldName) {
$fieldId = 0;
$error = '';
$hasField = $this->inputfield->hasField;
$hasPage = $this->inputfield->hasPage;
if(strpos($fieldName, ':')) {
list($fieldName, $fieldId) = explode(':', $fieldName);
} else if(ctype_digit("$fieldName")) {
$fieldName = (int) $fieldName; // since fields.get also accepts IDs
}
// no need to inherit from oneself
if("$fieldName" === "$hasField") return false;
$field = $this->wire()->fields->get($fieldName);
if(!$field) {
$error = "Cannot find settings field '$fieldName'";
} else if(!$field->type instanceof FieldtypeTextarea) {
$error = "Settings field '$fieldName' is not of type FieldtypeTextarea";
$field = null;
} else if(!wireInstanceOf($field->get('inputfieldClass'), $this->inputfield->className())) {
$error = "Settings field '$fieldName' is not using TinyMCE";
$field = null;
}
if(!$field && $fieldId && $fieldName) {
// try again with field ID only, which won't go recursive again
return $this->applySettingsField($fieldId);
}
if(!$field) {
if($error) $this->error($this->inputfield->attr('name') . ": $error");
return false;
}
if($field->flags & Field::flagFieldgroupContext) {
// field already in fieldgroup context
} else if($hasPage && $hasPage->template->fieldgroup->hasFieldContext($field)) {
// get in context of current page templates fieldgroup, if applicable
$field = $hasPage->template->fieldgroup->getFieldContext($field->id);
}
// identify settings to apply
$data = array();
foreach($this->inputfield->getSettingNames(array('tinymce', 'field')) as $name) {
$value = $field->get($name);
if($value !== null) $data[$name] = $value;
}
// apply settings
$this->inputfield->data($data);
return $field;
}
}