Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
T
tinymce4_rte
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
TYPO3
tinymce4_rte
Merge requests
!10
Typo3v8compatibility
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Typo3v8compatibility
typo3v8compatibility
into
master
Overview
0
Commits
20
Changes
5
Merged
Fabian Galinski
requested to merge
typo3v8compatibility
into
master
7 years ago
Overview
0
Commits
20
Changes
5
Expand
0
0
Merge request reports
Viewing commit
f3b3342f
Prev
Next
Show latest version
5 files
+
512
−
30
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
5
Search (e.g. *.vue) (Ctrl+P)
f3b3342f
[FEATURE] Integration of the tinyMCE for TYPO3 8
· f3b3342f
Fabian Galinski
authored
7 years ago
Classes/Form/Element/CkEditorRichTextElement.php
0 → 100644
+
376
−
0
Options
<?php
declare
(
strict_types
=
1
);
namespace
SGalinski\Tinymce4Rte\Form\Element
;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use
SGalinski\Tinymce\Loader
;
use
TYPO3\CMS\Backend\Form\Element\AbstractFormElement
;
use
TYPO3\CMS\Backend\Routing\UriBuilder
;
use
TYPO3\CMS\Core\Authentication\BackendUserAuthentication
;
use
TYPO3\CMS\Core\Localization\Locales
;
use
TYPO3\CMS\Core\Utility\GeneralUtility
;
use
TYPO3\CMS\Core\Utility\PathUtility
;
/**
* Render rich text editor in FormEngine
*/
class
CkEditorRichTextElement
extends
AbstractFormElement
{
/**
* Default field wizards enabled for this element.
*
* @var array
*/
protected
$defaultFieldWizard
=
[
'localizationStateSelector'
=>
[
'renderType'
=>
'localizationStateSelector'
,
],
'otherLanguageContent'
=>
[
'renderType'
=>
'otherLanguageContent'
,
'after'
=>
[
'localizationStateSelector'
],
],
'defaultLanguageDifferences'
=>
[
'renderType'
=>
'defaultLanguageDifferences'
,
'after'
=>
[
'otherLanguageContent'
,
],
],
];
/**
* This property contains configuration related to the RTE
* But only the .editor configuration part
*
* @var array
*/
protected
$rteConfiguration
=
[];
/**
* Renders the ckeditor element
*
* @return array
* @throws \UnexpectedValueException
* @throws \BadFunctionCallException
* @throws \InvalidArgumentException
*/
public
function
render
():
array
{
$resultArray
=
$this
->
initializeResultArray
();
$parameterArray
=
$this
->
data
[
'parameterArray'
];
$config
=
$parameterArray
[
'fieldConf'
][
'config'
];
$fieldId
=
$this
->
sanitizeFieldId
(
$parameterArray
[
'itemFormElName'
]);
$itemFormElementName
=
$this
->
data
[
'parameterArray'
][
'itemFormElName'
];
$value
=
$this
->
data
[
'parameterArray'
][
'itemFormElValue'
]
??
''
;
$legacyWizards
=
$this
->
renderWizards
();
$legacyFieldControlHtml
=
implode
(
LF
,
$legacyWizards
[
'fieldControl'
]);
$legacyFieldWizardHtml
=
implode
(
LF
,
$legacyWizards
[
'fieldWizard'
]);
$fieldInformationResult
=
$this
->
renderFieldInformation
();
$fieldInformationHtml
=
$fieldInformationResult
[
'html'
];
$resultArray
=
$this
->
mergeChildReturnIntoExistingResult
(
$resultArray
,
$fieldInformationResult
,
FALSE
);
$fieldControlResult
=
$this
->
renderFieldControl
();
$fieldControlHtml
=
$legacyFieldControlHtml
.
$fieldControlResult
[
'html'
];
$resultArray
=
$this
->
mergeChildReturnIntoExistingResult
(
$resultArray
,
$fieldControlResult
,
FALSE
);
$fieldWizardResult
=
$this
->
renderFieldWizard
();
$fieldWizardHtml
=
$legacyFieldWizardHtml
.
$fieldWizardResult
[
'html'
];
$resultArray
=
$this
->
mergeChildReturnIntoExistingResult
(
$resultArray
,
$fieldWizardResult
,
FALSE
);
// $attributes = [
// 'style' => 'display:none',
// 'data-formengine-validation-rules' => $this->getValidationDataAsJsonString($config),
// 'id' => $fieldId,
// 'name' => htmlspecialchars($itemFormElementName),
// ];
// Modified by fgalinski - Start
$attributes
=
[
'id'
=>
'RTEarea'
.
$fieldId
,
'name'
=>
htmlspecialchars
(
$itemFormElementName
),
'class'
=>
'tinymce4_rte'
,
];
// Modified by fgalinski - End
$html
=
[];
$html
[]
=
'<div class="formengine-field-item t3js-formengine-field-item">'
;
$html
[]
=
$fieldInformationHtml
;
$html
[]
=
'<div class="form-control-wrap">'
;
$html
[]
=
'<div class="form-wizards-wrap">'
;
$html
[]
=
'<div class="form-wizards-element">'
;
$html
[]
=
'<textarea '
.
GeneralUtility
::
implodeAttributes
(
$attributes
,
TRUE
)
.
'>'
;
$html
[]
=
htmlspecialchars
(
$value
);
$html
[]
=
'</textarea>'
;
$html
[]
=
'</div>'
;
$html
[]
=
'<div class="form-wizards-items-aside">'
;
$html
[]
=
'<div class="btn-group">'
;
$html
[]
=
$fieldControlHtml
;
$html
[]
=
'</div>'
;
$html
[]
=
'</div>'
;
$html
[]
=
'<div class="form-wizards-items-bottom">'
;
$html
[]
=
$fieldWizardHtml
;
$html
[]
=
'</div>'
;
$html
[]
=
'</div>'
;
$html
[]
=
'</div>'
;
$html
[]
=
'</div>'
;
$resultArray
[
'html'
]
=
implode
(
LF
,
$html
);
$this
->
rteConfiguration
=
$config
[
'richtextConfiguration'
][
'editor'
];
// Modified by fgalinski - Start
/** @var Loader $tinyMCE */
$tinyMCE
=
GeneralUtility
::
makeInstance
(
Loader
::
class
);
$tinyMCE
->
loadConfiguration
(
$config
[
'richtextConfiguration'
][
'tinymceConfiguration'
]);
$contentCssArray
=
$config
[
'richtextConfiguration'
][
'contentCSS.'
];
if
(
is_array
(
$contentCssArray
)
&&
count
(
$contentCssArray
)
>
0
)
{
$contentCssFileArray
=
[];
foreach
(
$contentCssArray
as
$contentCssKey
=>
$contentCssFile
)
{
$contentCssFileAbs
=
GeneralUtility
::
getFileAbsFileName
(
trim
(
$contentCssFile
));
if
(
is_file
(
$contentCssFileAbs
))
{
$contentCssFileArray
[]
=
GeneralUtility
::
getIndpEnv
(
'TYPO3_SITE_URL'
)
.
PathUtility
::
stripPathSitePrefix
(
$contentCssFileAbs
)
.
'?'
.
filemtime
(
$contentCssFileAbs
);
}
}
$tinyMCE
->
addConfigurationOption
(
'content_css'
,
implode
(
','
,
$contentCssFileArray
));
}
$tinyMCE
->
addConfigurationOption
(
'changeMethod'
,
'function() {
var TBE_EDITOR = window.TBE_EDITOR || null;
if (TBE_EDITOR && TBE_EDITOR.fieldChanged && typeof TBE_EDITOR.fieldChanged === \'function\') {
TBE_EDITOR.fieldChanged();
}
}'
);
$tinyMCE
->
addConfigurationOption
(
'editornumber'
,
$fieldId
);
// IRRE
$resultArray
[
'requireJsModules'
]
=
$tinyMCE
->
loadJsViaRequireJS
();
// Modified by fgalinski - End
return
$resultArray
;
}
/**
* @param string $itemFormElementName
*
* @return string
*/
protected
function
sanitizeFieldId
(
string
$itemFormElementName
):
string
{
$fieldId
=
preg_replace
(
'/[^a-zA-Z0-9_:.-]/'
,
'_'
,
$itemFormElementName
);
return
htmlspecialchars
(
preg_replace
(
'/^[^a-zA-Z]/'
,
'x'
,
$fieldId
));
}
/**
* Gets the JavaScript code for CKEditor module
* Compiles the configuration, and then adds plugins
*
* @param string $fieldId
*
* @return string
*/
protected
function
getCkEditorRequireJsModuleCode
(
string
$fieldId
):
string
{
$configuration
=
$this
->
prepareConfigurationForEditor
();
$externalPlugins
=
''
;
foreach
(
$this
->
getExtraPlugins
()
as
$pluginName
=>
$config
)
{
$configuration
[
$pluginName
]
=
$config
[
'config'
];
$configuration
[
'extraPlugins'
]
.
=
','
.
$pluginName
;
$externalPlugins
.
=
'CKEDITOR.plugins.addExternal('
;
$externalPlugins
.
=
GeneralUtility
::
quoteJSvalue
(
$pluginName
)
.
','
;
$externalPlugins
.
=
GeneralUtility
::
quoteJSvalue
(
$config
[
'resource'
])
.
','
;
$externalPlugins
.
=
'\'\');'
;
}
return
'function(CKEDITOR) {
'
.
$externalPlugins
.
'
$(function(){
CKEDITOR.replace("'
.
$fieldId
.
'", '
.
json_encode
(
$configuration
)
.
');
require([\'jquery\', \'TYPO3/CMS/Backend/FormEngine\'], function($, FormEngine) {
CKEDITOR.instances["'
.
$fieldId
.
'"].on(\'change\', function() {
CKEDITOR.instances["'
.
$fieldId
.
'"].updateElement();
FormEngine.Validation.validate();
FormEngine.Validation.markFieldAsChanged($(\'#'
.
$fieldId
.
'\'));
});
});
});
}'
;
}
/**
* Compiles the configuration set from the outside
* to have it easily injected into the CKEditor.
*
* @return array the configuration
*/
protected
function
prepareConfigurationForEditor
():
array
{
// Ensure custom config is empty so nothing additional is loaded
// Of course this can be overridden by the editor configuration below
$configuration
=
[
'customConfig'
=>
''
,
];
if
(
is_array
(
$this
->
rteConfiguration
[
'config'
]))
{
$configuration
=
array_replace_recursive
(
$configuration
,
$this
->
rteConfiguration
[
'config'
]);
}
// Set the UI language of the editor if not hard-coded by the existing configuration
if
(
empty
(
$configuration
[
'language'
]))
{
$configuration
[
'language'
]
=
$this
->
getBackendUser
()
->
uc
[
'lang'
]
?:
(
$this
->
getBackendUser
()
->
user
[
'lang'
]
?:
'en'
);
}
$configuration
[
'contentsLanguage'
]
=
$this
->
getLanguageIsoCodeOfContent
();
// Replace all label references
$configuration
=
$this
->
replaceLanguageFileReferences
(
$configuration
);
// Replace all paths
$configuration
=
$this
->
replaceAbsolutePathsToRelativeResourcesPath
(
$configuration
);
// there are some places where we define an array, but it needs to be a list in order to work
if
(
is_array
(
$configuration
[
'extraPlugins'
]))
{
$configuration
[
'extraPlugins'
]
=
implode
(
','
,
$configuration
[
'extraPlugins'
]);
}
if
(
is_array
(
$configuration
[
'removePlugins'
]))
{
$configuration
[
'removePlugins'
]
=
implode
(
','
,
$configuration
[
'removePlugins'
]);
}
if
(
is_array
(
$configuration
[
'removeButtons'
]))
{
$configuration
[
'removeButtons'
]
=
implode
(
','
,
$configuration
[
'removeButtons'
]);
}
return
$configuration
;
}
/**
* @return BackendUserAuthentication
*/
protected
function
getBackendUser
()
{
return
$GLOBALS
[
'BE_USER'
];
}
/**
* Determine the contents language iso code
*
* @return string
*/
protected
function
getLanguageIsoCodeOfContent
():
string
{
$currentLanguageUid
=
$this
->
data
[
'databaseRow'
][
'sys_language_uid'
];
if
(
is_array
(
$currentLanguageUid
))
{
$currentLanguageUid
=
$currentLanguageUid
[
0
];
}
$contentLanguageUid
=
(
int
)
max
(
$currentLanguageUid
,
0
);
if
(
$contentLanguageUid
)
{
$contentLanguage
=
$this
->
data
[
'systemLanguageRows'
][
$currentLanguageUid
][
'iso'
];
}
else
{
$contentLanguage
=
$this
->
rteConfiguration
[
'config'
][
'defaultContentLanguage'
]
??
'en_US'
;
$languageCodeParts
=
explode
(
'_'
,
$contentLanguage
);
$contentLanguage
=
strtolower
(
$languageCodeParts
[
0
])
.
(
$languageCodeParts
[
1
]
?
'_'
.
strtoupper
(
$languageCodeParts
[
1
])
:
''
);
// Find the configured language in the list of localization locales
$locales
=
GeneralUtility
::
makeInstance
(
Locales
::
class
);
// If not found, default to 'en'
if
(
!
in_array
(
$contentLanguage
,
$locales
->
getLocales
(),
TRUE
))
{
$contentLanguage
=
'en'
;
}
}
return
$contentLanguage
;
}
/**
* Add configuration to replace LLL: references with the translated value
*
* @param array $configuration
*
* @return array
*/
protected
function
replaceLanguageFileReferences
(
array
$configuration
):
array
{
foreach
(
$configuration
as
$key
=>
$value
)
{
if
(
is_array
(
$value
))
{
$configuration
[
$key
]
=
$this
->
replaceLanguageFileReferences
(
$value
);
}
elseif
(
is_string
(
$value
)
&&
stripos
(
$value
,
'LLL:'
)
===
0
)
{
$configuration
[
$key
]
=
$this
->
getLanguageService
()
->
sL
(
$value
);
}
}
return
$configuration
;
}
/**
* Add configuration to replace absolute EXT: paths with relative ones
*
* @param array $configuration
*
* @return array
*/
protected
function
replaceAbsolutePathsToRelativeResourcesPath
(
array
$configuration
):
array
{
foreach
(
$configuration
as
$key
=>
$value
)
{
if
(
is_array
(
$value
))
{
$configuration
[
$key
]
=
$this
->
replaceAbsolutePathsToRelativeResourcesPath
(
$value
);
}
elseif
(
is_string
(
$value
)
&&
stripos
(
$value
,
'EXT:'
)
===
0
)
{
$configuration
[
$key
]
=
$this
->
resolveUrlPath
(
$value
);
}
}
return
$configuration
;
}
/**
* Resolves an EXT: syntax file to an absolute web URL
*
* @param string $value
*
* @return string
*/
protected
function
resolveUrlPath
(
string
$value
):
string
{
$value
=
GeneralUtility
::
getFileAbsFileName
(
$value
);
return
PathUtility
::
getAbsoluteWebPath
(
$value
);
}
/**
* Get configuration of external/additional plugins
*
* @return array
*/
protected
function
getExtraPlugins
():
array
{
$urlParameters
=
[
'P'
=>
[
'table'
=>
$this
->
data
[
'tableName'
],
'uid'
=>
$this
->
data
[
'databaseRow'
][
'uid'
],
'fieldName'
=>
$this
->
data
[
'fieldName'
],
'recordType'
=>
$this
->
data
[
'recordTypeValue'
],
'pid'
=>
$this
->
data
[
'effectivePid'
],
]
];
$pluginConfiguration
=
[];
if
(
isset
(
$this
->
rteConfiguration
[
'externalPlugins'
])
&&
is_array
(
$this
->
rteConfiguration
[
'externalPlugins'
]))
{
$uriBuilder
=
GeneralUtility
::
makeInstance
(
UriBuilder
::
class
);
foreach
(
$this
->
rteConfiguration
[
'externalPlugins'
]
as
$pluginName
=>
$configuration
)
{
$pluginConfiguration
[
$pluginName
]
=
[
'resource'
=>
$this
->
resolveUrlPath
(
$configuration
[
'resource'
])
];
unset
(
$configuration
[
'resource'
]);
if
(
$configuration
[
'route'
])
{
$configuration
[
'routeUrl'
]
=
(
string
)
$uriBuilder
->
buildUriFromRoute
(
$configuration
[
'route'
],
$urlParameters
);
}
$pluginConfiguration
[
$pluginName
][
'config'
]
=
$configuration
;
}
}
return
$pluginConfiguration
;
}
}
Loading