diff --git a/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCESettings.php b/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCESettings.php index 2766cb83..72d3d1f4 100644 --- a/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCESettings.php +++ b/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCESettings.php @@ -475,6 +475,12 @@ class InputfieldTinyMCESettings extends InputfieldTinyMCEClass { $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; } @@ -755,7 +761,7 @@ class InputfieldTinyMCESettings extends InputfieldTinyMCEClass { if($inputfield->lazyMode) $features[] = "lazyMode$inputfield->lazyMode"; $inputfield->wrapAttr('data-configName', $configName); - $inputfield->wrapAttr('data-settings', json_encode($dataSettings)); + $inputfield->wrapAttr('data-settings', $this->tools()->jsonEncode($dataSettings, 'data-settings', false)); $inputfield->wrapAttr('data-features', implode(',', $features)); } @@ -827,4 +833,4 @@ class InputfieldTinyMCESettings extends InputfieldTinyMCEClass { return $field; } -} \ No newline at end of file +} diff --git a/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCETools.php b/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCETools.php index 96a558df..cf373260 100644 --- a/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCETools.php +++ b/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCETools.php @@ -5,8 +5,10 @@ * * Helper tools for InputfieldTinyMCE module. * - * ProcessWire 3.x, Copyright 2022 by Ryan Cramer + * ProcessWire 3.x, Copyright 2023 by Ryan Cramer * https://processwire.com + * + * @property array $jsonBlankObjectProperties * */ class InputfieldTinyMCETools extends InputfieldTinyMCEClass { @@ -32,6 +34,14 @@ class InputfieldTinyMCETools extends InputfieldTinyMCEClass { * */ static protected $purifier = null; + + /** + * Properties found in decoded JSON that were blank objects and should remain when encoded + * + * @var array + * + */ + protected $jsonBlankObjectProperties = array(); /** * Sanitize toolbar or plugin names @@ -245,6 +255,13 @@ class InputfieldTinyMCETools extends InputfieldTinyMCEClass { $propertyName, json_last_error_msg() )); $a = array(); + } else if(strpos($json, '{}') !== false) { + if(preg_match_all('/"([_a-z0-9]+)":\s*[{][}]/i', $json, $matches)) { + foreach($matches[1] as $name) { + $this->jsonBlankObjectProperties[$name] = $name; + } + } + } return $a; } @@ -275,12 +292,17 @@ class InputfieldTinyMCETools extends InputfieldTinyMCEClass { * * @param array $a * @param string $propertyName Name of property JSON is for + * @param bool $pretty * @return string * */ - public function jsonEncode($a, $propertyName) { + public function jsonEncode($a, $propertyName, $pretty = true) { if(!is_array($a)) return ''; - $json = json_encode($a, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + if($pretty) { + $json = json_encode($a, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + } else { + $json = json_encode($a); + } if($json === false) { $this->warning(sprintf( $this->_('Error encoding JSON for TinyMCE property "%1$s" - %2$s'), @@ -288,6 +310,12 @@ class InputfieldTinyMCETools extends InputfieldTinyMCEClass { )); $json = ''; } + if(count($this->jsonBlankObjectProperties) && strpos($json, '[]') !== false) { + // convert JSON arrays [] to objects {} + foreach($this->jsonBlankObjectProperties as $name) { + $json = str_replace(array("\"$name\": []", "\"$name\":[]"), "\"$name\": {}", $json); + } + } return (string) $json; } @@ -380,4 +408,14 @@ class InputfieldTinyMCETools extends InputfieldTinyMCEClass { } */ -} \ No newline at end of file + /** + * @param string $name + * @return array|mixed|string|null + * + */ + public function __get($name) { + if($name === 'jsonBlankObjectProperties') return $this->jsonBlankObjectProperties; + return parent::__get($name); + } + +}