mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 02:58:43 +02:00
Merge branch 'support/3.2' into develop
This commit is contained in:
127
sources/Application/Helper/CKEditorHelper.php
Normal file
127
sources/Application/Helper/CKEditorHelper.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Application\Helper;
|
||||
|
||||
use UserRights;
|
||||
use MetaModel;
|
||||
use DBSearch;
|
||||
use utils;
|
||||
use appUserPreferences;
|
||||
|
||||
/***
|
||||
*
|
||||
* (34) [
|
||||
* 'blockQuote',
|
||||
* 'bold',
|
||||
* 'link',
|
||||
* 'ckfinder',
|
||||
* 'codeBlock',
|
||||
* 'selectAll',
|
||||
* 'undo',
|
||||
* 'redo',
|
||||
* 'heading',
|
||||
* 'horizontalLine',
|
||||
* 'imageTextAlternative',
|
||||
* 'toggleImageCaption',
|
||||
* 'imageStyle:inline',
|
||||
* 'imageStyle:alignLeft',
|
||||
* 'imageStyle:alignRight',
|
||||
* 'imageStyle:alignCenter',
|
||||
* 'imageStyle:alignBlockLeft',
|
||||
* 'imageStyle:alignBlockRight',
|
||||
* 'imageStyle:block',
|
||||
* 'imageStyle:side',
|
||||
* 'imageStyle:wrapText',
|
||||
* 'imageStyle:breakText',
|
||||
* 'uploadImage',
|
||||
* 'imageUpload',
|
||||
* 'indent',
|
||||
* 'outdent',
|
||||
* 'italic',
|
||||
* 'numberedList',
|
||||
* 'bulletedList',
|
||||
* 'mediaEmbed',
|
||||
* 'insertTable',
|
||||
* 'tableColumn',
|
||||
* 'tableRow',
|
||||
* 'mergeTableCells']
|
||||
*
|
||||
*/
|
||||
|
||||
class CKEditorHelper
|
||||
{
|
||||
/**
|
||||
* Return the CKEditor config as an array
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
static public function GetCkeditorPref()
|
||||
{
|
||||
// extract language from user preferences
|
||||
$sLanguageCountry = trim(UserRights::GetUserLanguage());
|
||||
$sLanguage = strtolower(explode(' ', $sLanguageCountry)[0]);
|
||||
|
||||
$aDefaultConf = array(
|
||||
'language'=> $sLanguage,
|
||||
);
|
||||
|
||||
// mentions
|
||||
$aDefaultConf['mention'] = self::GetMentionConfiguration();
|
||||
|
||||
// rich text config
|
||||
$aRichTextConfig = json_decode(appUserPreferences::GetPref('richtext_config', '{}'), true);
|
||||
|
||||
return array_merge($aDefaultConf, $aRichTextConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|array[]
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
static private function GetMentionConfiguration() : array
|
||||
{
|
||||
// initialize feeds
|
||||
$aMentionConfiguration = ['feeds' => []];
|
||||
|
||||
// retrieve mentions allowed classes
|
||||
$aMentionsAllowedClasses = MetaModel::GetConfig()->Get('mentions.allowed_classes');
|
||||
|
||||
// iterate throw classes...
|
||||
foreach($aMentionsAllowedClasses as $sMentionMarker => $sMentionScope) {
|
||||
|
||||
// Retrieve mention class
|
||||
// - First test if the conf is a simple data model class
|
||||
if (MetaModel::IsValidClass($sMentionScope)) {
|
||||
$sMentionClass = $sMentionScope;
|
||||
}
|
||||
// - Otherwise it must be a valid OQL
|
||||
else {
|
||||
$oTmpSearch = DBSearch::FromOQL($sMentionScope);
|
||||
$sMentionClass = $oTmpSearch->GetClass();
|
||||
unset($oTmpSearch);
|
||||
}
|
||||
|
||||
// append mention configuration
|
||||
$aMentionConfiguration['feeds'][] = [
|
||||
'marker' => $sMentionMarker,
|
||||
'feed' => null,
|
||||
'minimumCharacters' => MetaModel::GetConfig()->Get('min_autocomplete_chars'),
|
||||
'feed_type' => 'ajax',
|
||||
'feed_ajax_options' => [
|
||||
'url' => utils::GetAbsoluteUrlAppRoot(). "pages/ajax.render.php?route=object.search&object_class=$sMentionClass&oql=SELECT $sMentionClass&search=",
|
||||
'throttle' => 500,
|
||||
'marker' => $sMentionMarker,
|
||||
],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return $aMentionConfiguration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,10 +72,8 @@ class WebResourcesHelper
|
||||
public static function GetJSFilesRelPathsForCKEditor(): array
|
||||
{
|
||||
return [
|
||||
'js/ckeditor/ckeditor.js',
|
||||
'js/ckeditor/adapters/jquery.js',
|
||||
'js/ckeditor/plugins/codesnippet/lib/highlight/highlight.pack.js',
|
||||
'js/ckeditor.on-init.js',
|
||||
'js/ckeditor/build/ckeditor.js',
|
||||
'js/highlight/highlight.js',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
namespace Combodo\iTop\Application\UI\Base\Component\Input\RichText;
|
||||
use Combodo\iTop\Application\Helper\CKEditorHelper;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
use Dict;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
@@ -19,13 +21,12 @@ class RichText extends UIBlock
|
||||
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/input/richtext/layout';
|
||||
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'base/components/input/richtext/layout';
|
||||
public const DEFAULT_JS_FILES_REL_PATH = [
|
||||
'js/ckeditor/ckeditor.js',
|
||||
'js/ckeditor/adapters/jquery.js',
|
||||
'js/ckeditor/plugins/codesnippet/lib/highlight/highlight.pack.js',
|
||||
'js/ckeditor.on-init.js',
|
||||
'js/ckeditor/build/ckeditor.js',
|
||||
'js/highlight/highlight.js',
|
||||
];
|
||||
public const DEFAULT_CSS_FILES_REL_PATH = [
|
||||
'js/ckeditor/plugins/codesnippet/lib/highlight/styles/obsidian.css',
|
||||
'js/highlight/styles/obsidian.css',
|
||||
'css/ckeditor/contents.css',
|
||||
];
|
||||
|
||||
/** @var string|null */
|
||||
@@ -42,7 +43,11 @@ class RichText extends UIBlock
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->sValue = null;
|
||||
$this->aConfig = utils::GetCkeditorPref();
|
||||
$this->aConfig = CKEditorHelper::GetCkeditorPref();
|
||||
|
||||
// add CKEditor translations resource
|
||||
$sLanguage = strtolower(explode(' ', Dict::GetUserLanguage())[0]);
|
||||
$this->AddJsFileRelPath('js/ckeditor/build/translations/' . $sLanguage . '.js');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,10 +24,11 @@ class CaseLogEntryForm extends UIContentBlock
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-caselog-entry-form';
|
||||
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/layouts/activity-panel/caselog-entry-form/layout';
|
||||
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'base/layouts/activity-panel/caselog-entry-form/layout';
|
||||
public const DEFAULT_JS_ON_READY_TEMPLATE_REL_PATH = 'base/layouts/activity-panel/caselog-entry-form/layout';
|
||||
public const DEFAULT_JS_FILES_REL_PATH = [
|
||||
'js/layouts/activity-panel/caselog-entry-form.js',
|
||||
];
|
||||
public const REQUIRES_ANCESTORS_DEFAULT_JS_FILES = true;
|
||||
|
||||
/** @var string Form is autonomous and can send data on its own */
|
||||
public const ENUM_SUBMIT_MODE_AUTONOMOUS = 'autonomous';
|
||||
|
||||
@@ -209,6 +209,8 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
|
||||
// Used throughout the app.
|
||||
$this->LinkScriptFromAppRoot('js/pages/backoffice/toolbox.js');
|
||||
$this->LinkScriptFromAppRoot('js/ckeditor.handler.js');
|
||||
$this->LinkScriptFromAppRoot('js/ckeditor.feeds.js');
|
||||
$this->LinkScriptFromAppRoot('js/pages/backoffice/on-ready.js');
|
||||
|
||||
// Used by dashboard editor
|
||||
@@ -270,9 +272,6 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->LinkStylesheetFromAppRoot('css/font-awesome/css/all.min.css');
|
||||
$this->LinkStylesheetFromAppRoot('css/font-combodo/font-combodo.css');
|
||||
|
||||
// Note: CKEditor files can't be moved easily as we need to find a way to init the "disabler" plugin, {@see js/toolbox.js}
|
||||
$this->LinkStylesheetFromAppRoot('js/ckeditor/plugins/codesnippet/lib/highlight/styles/obsidian.css');
|
||||
|
||||
// Used by external keys and other drop down lists
|
||||
$this->LinkStylesheetFromAppRoot('css/selectize.default.css');
|
||||
}
|
||||
|
||||
@@ -803,12 +803,15 @@ JS;
|
||||
// Retrieve query params
|
||||
$sObjectClass = utils::ReadParam('object_class', '', false, utils::ENUM_SANITIZATION_FILTER_STRING);
|
||||
$sOql = utils::ReadParam('oql', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$aFieldsToLoad = json_decode(utils::ReadParam('fields_to_load', '', false, utils::ENUM_SANITIZATION_FILTER_STRING));
|
||||
$aFieldsToLoad = json_decode(utils::ReadParam('fields_to_load', '[]', false, utils::ENUM_SANITIZATION_FILTER_STRING));
|
||||
$sSearch = utils::ReadParam('search', '', false, utils::ENUM_SANITIZATION_FILTER_STRING);
|
||||
|
||||
// Retrieve this reference object (for OQL)
|
||||
$sThisObjectData = utils::ReadPostedParam('this_object_data', null, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$oThisObj = ObjectRepository::GetObjectFromWizardHelperData($sThisObjectData);
|
||||
$oThisObj = null;
|
||||
if($sThisObjectData !== null) {
|
||||
$oThisObj = ObjectRepository::GetObjectFromWizardHelperData($sThisObjectData);
|
||||
}
|
||||
|
||||
// Retrieve data post processor
|
||||
$aDataProcessor = utils::ReadParam('data_post_processor', null, false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Combodo\iTop\Renderer\Bootstrap\FieldRenderer;
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use AttributeText;
|
||||
use Combodo\iTop\Application\Helper\CKEditorHelper;
|
||||
use Combodo\iTop\Form\Field\DateField;
|
||||
use Combodo\iTop\Form\Field\DateTimeField;
|
||||
use Combodo\iTop\Form\Field\Field;
|
||||
@@ -172,17 +173,20 @@ EOF
|
||||
|
||||
// Some additional stuff if we are displaying it with a rich editor
|
||||
if ($bRichEditor) {
|
||||
$aConfig = utils::GetCkeditorPref();
|
||||
$aConfig = CKEditorHelper::GetCkeditorPref();
|
||||
$aConfig['extraPlugins'] = 'codesnippet';
|
||||
$sJsConfig = json_encode($aConfig);
|
||||
|
||||
$oOutput->AddJs(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
$('#{$this->oField->GetGlobalId()}').addClass('htmlEditor');
|
||||
$('#{$this->oField->GetGlobalId()}').ckeditor(function(){}, $sJsConfig).editor.on("change", function(){
|
||||
$('#{$this->oField->GetGlobalId()}').trigger("change");
|
||||
});
|
||||
EOF
|
||||
CombodoCKEditorHandler.CreateInstance('#{$this->oField->GetGlobalId()}').then(( oEditor) => {
|
||||
oEditor.model.document.on('change:data', (event) => {
|
||||
|
||||
$('#{$this->oField->GetGlobalId()}').val(oEditor.getData()).trigger("change");
|
||||
});
|
||||
});
|
||||
JS
|
||||
);
|
||||
if (($this->oField->GetObject() !== null) && ($this->oField->GetTransactionId() !== null)) {
|
||||
$oOutput->AddJs(InlineImage::EnableCKEditorImageUpload($this->oField->GetObject(), utils::GetUploadTempId($this->oField->GetTransactionId())));
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Combodo\iTop\Renderer\Console\FieldRenderer;
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use AttributeDuration;
|
||||
use Combodo\iTop\Application\Helper\CKEditorHelper;
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Field\FieldUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
@@ -162,7 +163,7 @@ class ConsoleSimpleFieldRenderer extends FieldRenderer
|
||||
if ($bRichEditor)
|
||||
{
|
||||
$oText->AddCSSClass('ibo-input-richtext-placeholder');
|
||||
$aConfig = utils::GetCkeditorPref();
|
||||
$aConfig = CKEditorHelper::GetCkeditorPref();
|
||||
$aConfig['extraPlugins'] = 'codesnippet';
|
||||
$sJsConfig = json_encode($aConfig);
|
||||
|
||||
|
||||
@@ -189,14 +189,17 @@ class ObjectRepository
|
||||
{
|
||||
try {
|
||||
|
||||
// object class
|
||||
// Object key
|
||||
$aData['id'] = $oDbObject->GetKey();
|
||||
|
||||
// Object class
|
||||
$aData['class_name'] = get_class($oDbObject);
|
||||
|
||||
// Obsolescence flag
|
||||
$aData['obsolescence_flag'] = $oDbObject->IsObsolete();
|
||||
|
||||
// Additional fields
|
||||
$sFriendlynameForHtml = utils::EscapeHtml($aData['friendlyname']);
|
||||
$sFriendlyNameForHtml = utils::EscapeHtml($aData['friendlyname']);
|
||||
if (count($aComplementAttributeSpec[1]) > 0) {
|
||||
$aData['has_additional_field'] = true;
|
||||
$aArguments = [];
|
||||
@@ -205,9 +208,9 @@ class ObjectRepository
|
||||
}
|
||||
$aData['additional_field'] = vsprintf($aComplementAttributeSpec[0], $aArguments);
|
||||
$sAdditionalFieldForHtml = utils::EscapeHtml($aData['additional_field']);
|
||||
$aData['full_description'] = "{$sFriendlynameForHtml}<br><i><small>{$sAdditionalFieldForHtml}</small></i>";
|
||||
$aData['full_description'] = "{$sFriendlyNameForHtml}<br><i><small>{$sAdditionalFieldForHtml}</small></i>";
|
||||
} else {
|
||||
$aData['full_description'] = $sFriendlynameForHtml;
|
||||
$aData['full_description'] = $sFriendlyNameForHtml;
|
||||
}
|
||||
|
||||
// Image
|
||||
@@ -223,6 +226,9 @@ class ObjectRepository
|
||||
}
|
||||
}
|
||||
|
||||
// Link
|
||||
$aData['link'] = utils::GetAbsoluteUrlAppRoot() . "pages/UI.php?operation=details&class=$sClass&id={$oDbObject->GetKey()}";
|
||||
|
||||
return $aData;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
|
||||
Reference in New Issue
Block a user