Merge remote-tracking branch 'origin/support/3.2' into develop

This commit is contained in:
Molkobain
2024-07-10 11:39:14 +02:00
12 changed files with 109 additions and 45 deletions

View File

@@ -1330,7 +1330,8 @@ class DesignerComboField extends DesignerFormField
{
if ($this->bMultipleSelection)
{
$sHtml = "<span><select $sCSSClasses multiple size=\"8\"id=\"$sId\" name=\"$sName\">";
$iSize = max(1, min(8, count($this->aAllowedValues)));
$sHtml = "<span><select $sCSSClasses multiple size=\"$iSize\" id=\"$sId\" name=\"$sName\">";
}
else
{

View File

@@ -4491,6 +4491,9 @@
<attribute id="name"/>
</attributes>
</naming>
<fields_semantic>
<image_attribute>logo</image_attribute>
</fields_semantic>
<style>
<icon/>
</style>
@@ -4509,6 +4512,13 @@
</uniqueness_rules>
</properties>
<fields>
<field id="logo" xsi:type="AttributeImage">
<display_max_width>96</display_max_width>
<display_max_height>96</display_max_height>
<storage_max_width>128</storage_max_width>
<storage_max_height>128</storage_max_height>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="physicaldevices_list" xsi:type="AttributeLinkedSet">
<linked_class>PhysicalDevice</linked_class>
<ext_key_to_me>brand_id</ext_key_to_me>
@@ -4525,9 +4535,12 @@
<item id="name">
<rank>10</rank>
</item>
<item id="physicaldevices_list">
<item id="logo">
<rank>20</rank>
</item>
<item id="physicaldevices_list">
<rank>30</rank>
</item>
</items>
</details>
<search>
@@ -4544,6 +4557,13 @@
</item>
</items>
</list>
<summary>
<items>
<item id="name">
<rank>10</rank>
</item>
</items>
</summary>
</presentation>
</class>
<class id="Model" _delta="define">
@@ -4564,6 +4584,9 @@
<attribute id="type"/>
</complementary_attributes>
</naming>
<fields_semantic>
<image_attribute>picture</image_attribute>
</fields_semantic>
<style>
<icon/>
</style>
@@ -4596,6 +4619,13 @@
<extkey_attcode>brand_id</extkey_attcode>
<target_attcode>name</target_attcode>
</field>
<field id="picture" xsi:type="AttributeImage">
<display_max_width>256</display_max_width>
<display_max_height>256</display_max_height>
<storage_max_width>512</storage_max_width>
<storage_max_height>512</storage_max_height>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="type" xsi:type="AttributeEnum">
<sort_type>label</sort_type>
<values>
@@ -4678,12 +4708,15 @@
<item id="brand_id">
<rank>20</rank>
</item>
<item id="type">
<item id="picture">
<rank>30</rank>
</item>
<item id="physicaldevices_list">
<item id="type">
<rank>40</rank>
</item>
<item id="physicaldevices_list">
<rank>50</rank>
</item>
</items>
</details>
<search>
@@ -4717,6 +4750,9 @@
<item id="type">
<rank>20</rank>
</item>
<item id="picture">
<rank>30</rank>
</item>
</items>
</summary>
</presentation>

View File

@@ -1092,6 +1092,8 @@ Dict::Add('EN US', 'English', 'English', array(
Dict::Add('EN US', 'English', 'English', array(
'Class:Brand' => 'Brand',
'Class:Brand+' => '',
'Class:Brand/Attribute:logo' => 'Logo',
'Class:Brand/Attribute:logo+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices',
'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand',
'Class:Brand/UniquenessRule:name+' => 'The name must be unique',
@@ -1110,6 +1112,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:Model/Attribute:brand_id+' => '',
'Class:Model/Attribute:brand_name' => 'Brand name',
'Class:Model/Attribute:brand_name+' => '',
'Class:Model/Attribute:picture' => 'Picture',
'Class:Model/Attribute:picture+' => '',
'Class:Model/Attribute:type' => 'Device type',
'Class:Model/Attribute:type+' => '',
'Class:Model/Attribute:type/Value:PowerSource' => 'Power Source',

View File

@@ -28,6 +28,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:ApplicationSolution/Attribute:status/Value:inactive+' => '',
'Class:Brand' => 'Marque',
'Class:Brand+' => '',
'Class:Brand/Attribute:logo' => 'Logo',
'Class:Brand/Attribute:logo+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Matériels',
'Class:Brand/Attribute:physicaldevices_list+' => 'Tous les matériels correspondant à cette marque',
'Class:Brand/Attribute:physicaldevices_list/UI:Links:Create:Button+' => 'Créer un %4$s',
@@ -355,6 +357,8 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Model/Attribute:brand_id+' => '',
'Class:Model/Attribute:brand_name' => 'Nom marque',
'Class:Model/Attribute:brand_name+' => '',
'Class:Model/Attribute:picture' => 'Image',
'Class:Model/Attribute:picture+' => '',
'Class:Model/Attribute:physicaldevices_list' => 'Matériels',
'Class:Model/Attribute:physicaldevices_list+' => 'Tous les matériels correspondant à ce modèle',
'Class:Model/Attribute:physicaldevices_list/UI:Links:Create:Button+' => 'Créer un %4$s',

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -33,7 +33,8 @@
"@ckeditor/ckeditor5-table": "~41.4",
"@ckeditor/ckeditor5-typing": "~41.4",
"@ckeditor/ckeditor5-ui": "~41.4",
"@ckeditor/ckeditor5-undo": "~41.4"
"@ckeditor/ckeditor5-undo": "~41.4",
"ws": ">=7.5.10"
},
"devDependencies": {
"@ckeditor/ckeditor5-core": "~41.4",
@@ -3117,6 +3118,26 @@
}
}
},
"node_modules/jsdom/node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -5499,15 +5520,15 @@
"dev": true
},
"node_modules/ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=8.3.0"
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {

View File

@@ -32,7 +32,8 @@
"@ckeditor/ckeditor5-table": "~41.4",
"@ckeditor/ckeditor5-typing": "~41.4",
"@ckeditor/ckeditor5-ui": "~41.4",
"@ckeditor/ckeditor5-undo": "~41.4"
"@ckeditor/ckeditor5-undo": "~41.4",
"ws": ">=7.5.10"
},
"devDependencies": {
"@ckeditor/ckeditor5-core": "~41.4",

View File

@@ -95,20 +95,7 @@ $(function()
value = $(oElem).val();
}
}
else if( $(oElem).is(':radio'))
{
let nameRadioButton= $(oElem).prop('name');
let radioCheckProp = $('[name='+nameRadioButton+']:checked');
if(radioCheckProp.length === 1)
{
value = radioCheckProp.val();
}
else
{
value = "";
}
}
else if($(oElem).is(':checkbox'))
else if($(oElem).is(':checkbox') || $(oElem).is(':radio'))
{
if(value === null)
{

View File

@@ -57,6 +57,7 @@ $(function() {
// the constructor
_create: function () {
const me = this;
const aMandatoryOptions = ['object_class', 'object_id', 'attribute_code'];
for (let sOption of aMandatoryOptions) {
if (null === this.options[sOption]) {
@@ -66,19 +67,22 @@ $(function() {
}
}
this._UpdateState();
if (this._IsSubmitAutonomous()) {
this._ShowMainActions();
} else {
this._AddBridgeInput();
this._HideMainActions();
}
// Ensure the CKEditor instance is ready before proceding
this._GetCKEditorInstance(true).then((oCKEditorInstance) => {
me._UpdateState();
if (me._IsSubmitAutonomous()) {
me._ShowMainActions();
} else {
me._AddBridgeInput();
me._HideMainActions();
}
this._bindEvents();
me._bindEvents();
this.element.trigger('ready.caselog_entry_form.itop');
me.element.trigger('ready.caselog_entry_form.itop');
});
},
_bindEvents: async function () {
_bindEvents: function () {
let me = this;
let CKEditorInstance = this._GetCKEditorInstance();
// Handlers for the CKEditor itself
@@ -198,8 +202,8 @@ $(function() {
this.element.trigger('requested_submission.caselog_entry_form.itop', oData);
},
// - Form
_GetCKEditorInstance: function () {
return CombodoCKEditorHandler.GetInstanceSynchronous('#'+this.options.text_input_id);
_GetCKEditorInstance: function (bAsync = false) {
return bAsync ? CombodoCKEditorHandler.GetInstance('#'+this.options.text_input_id) : CombodoCKEditorHandler.GetInstanceSynchronous('#'+this.options.text_input_id);
},
_ShowEntryForm: function () {
this.element.closest(this.js_selectors.activity_panel).find(this.js_selectors.form).removeClass(this.css_classes.is_closed);

View File

@@ -39,7 +39,8 @@ $.widget( "itop.scrollabletabs", $.ui.tabs, {
this._super(this.options);
// Initialize the vertical scroll offset
this.scroll_offset_y = this.element.find('#' + this.tabs.eq(0).attr('data-tab-id')).offset().top;
let oFirstPanel = this.element.find('#' + this.tabs.eq(0).attr('data-tab-id'));
this.scroll_offset_y = oFirstPanel.length > 0 ? oFirstPanel.offset().top : this.element.find(this.js_selectors.tab_container_list).offset().top;
// Add every other tab to the controller
$(this.js_selectors.tab_toggler).each(function(){
@@ -53,14 +54,17 @@ $.widget( "itop.scrollabletabs", $.ui.tabs, {
// Set active tab, tab-container gives us a tab based on url hash or 0
this.setTab(this._findActive(this.options.active));
// If not on the first tab, we scroll directly to it
// Note: We don't want to scroll if we are on the first one, otherwise it will looks buggy because the page will be a bit scrolled and it doesn't feel right
// Note: We don't want to scroll if we are on the first one, otherwise it will look buggy because the page will be a bit scrolled and it doesn't feel right
if(this.options.active > 0) {
const oActiveTab = this.tabs.eq(this.options.active);
const oActivePanel = this.element.find('#' + oActiveTab.attr('data-tab-id'));
// Remove from scroll length the initial space between the top of the first panel and the top of the screen; this is to avoid scrolling too far
// That being said, as lists are fetched / updated asynchroniously, once they got their responses, the layout will change/shift and the current tab won't be the good one anymore 😕
this.controller.scrollTo(oActivePanel.offset().top - this.scroll_offset_y);
// That being said, as lists are fetched / updated asynchronously, once they got their responses, the layout will change/shift and the current tab won't be the good one anymore 😕
// We check if the active panel is loaded as we may try to scroll to it before it is loaded, and it doesn't exist yet
if(oActivePanel.length > 0) {
this.controller.scrollTo(oActivePanel.offset().top-this.scroll_offset_y);
}
}
},
// Create a new scene to be added to the controller

View File

@@ -1167,6 +1167,7 @@ EOF
*/
protected function QuoteForPHP($sStr, $bSimpleQuotes = false)
{
$sStr = $sStr ?? '';
if ($bSimpleQuotes)
{
$sEscaped = str_replace(array('\\', "'"), array('\\\\', "\\'"), $sStr);
@@ -3230,10 +3231,11 @@ EOF;
$aEntriesPHP = array();
$oEntries = $oDictionaryNode->GetUniqueElement('entries');
/** @var MFElement $oEntry */
foreach ($oEntries->getElementsByTagName('entry') as $oEntry)
{
$sStringCode = $oEntry->getAttribute('id');
$sValue = $oEntry->GetText();
$sValue = $oEntry->GetText('');
$aEntriesPHP[] = "\t'$sStringCode' => ".self::QuoteForPHP(self::FilterDictString($sValue), true).",";
}
$sEntriesPHP = implode("\n", $aEntriesPHP);
@@ -3268,7 +3270,7 @@ EOF;
file_put_contents($sLanguagesFile, $sLanguagesFileContent);
}
protected static function FilterDictString($s)
protected static function FilterDictString(string $s): string
{
if (strpos($s, '~') !== false)
{