N°2847 - Action buttons

This commit is contained in:
Eric
2020-09-25 16:02:18 +02:00
parent 6969e4db1b
commit bfd4ba16d9
22 changed files with 755 additions and 549 deletions

View File

@@ -1,4 +1,7 @@
<?php
use Combodo\iTop\Renderer\BlockRenderer;
/**
* Copyright (C) 2013-2020 Combodo SARL
*
@@ -157,17 +160,17 @@ class DataTable
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$sActionsMenu = '';
$sToolkitMenu = '';
if ($bActionsMenu)
{
if ($bActionsMenu) {
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
}
if ($bToolkitMenu)
{
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
}
// if ($bToolkitMenu)
// {
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
// }
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
@@ -355,9 +358,18 @@ EOF;
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
foreach ($oBlock->GetCssFilesUrlRecursively(true) as $sFileAbsUrl) {
$oPage->add_linked_stylesheet($sFileAbsUrl);
}
// JS files
foreach ($oBlock->GetJsFilesUrlRecursively(true) as $sFileAbsUrl) {
$oPage->add_linked_script($sFileAbsUrl);
}
$oPage->RenderInlineTemplatesRecursively($oBlock);
return BlockRenderer::RenderBlockTemplates($oBlock);
}
/**

File diff suppressed because it is too large Load Diff

View File

@@ -236,14 +236,14 @@ EOF
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\"></select>";
$sJsonOptions=json_encode($aOptions);
$oPage->add_ready_script(
<<<JS
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
oACWidget_{$this->iId}.AddSelectize('$sJsonOptions','$sDisplayValue');
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
JS
EOF
);
}
else
@@ -278,7 +278,7 @@ JS
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<JS
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
@@ -286,7 +286,7 @@ JS
{
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
}
JS
EOF
);
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
@@ -544,13 +544,13 @@ EOF
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
}
$oPage->add_ready_script(
<<<JS
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
JS
EOF
);
} // Switch
}
@@ -586,7 +586,7 @@ JS
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<JS
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
@@ -594,8 +594,8 @@ JS
{
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
}
JS
);
EOF
);
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{
@@ -631,53 +631,55 @@ JS
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
{
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">');
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
if (($oCurrObject != null) && ($this->sAttCode != '')) {
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
/** @var \DBObject $oCurrObject */
$aArgs = $oCurrObject->ToArgsForQuery();
$aParams = array('query_params' => $aArgs);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
$oFilter = $oSet->GetFilter();
}
else
{
} else {
$aParams = array();
$oFilter = new DBObjectSearch($this->sTargetClass);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId,
array(
'menu' => false,
'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}",
'table_inner_id' => "{$this->iId}_results",
'selection_mode' => true,
'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId)
);
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHTML .= "</div>\n";
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
$sHTML .= "<input type=\"hidden\" id=\"count_{$this->iId}\" value=\"0\">";
$sHTML .= "</form>\n";
$sHTML .= '</div></div>';
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, $this->iId,
array(
'menu' => false,
'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}",
'table_inner_id' => "{$this->iId}_results",
'selection_mode' => true,
'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId
)
));
$sCancel = Dict::S('UI:Button:Cancel');
$sOK = Dict::S('UI:Button:Ok');
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$oPage->add(<<<HTML
<form id="fr_{$this->iId}" OnSubmit="return oACWidget_{$this->iId}.DoOk();">
<div id="dr_{$this->iId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="button" id="btn_cancel_{$this->iId}" value="{$sCancel}" onClick="$('#ac_dlg_{$this->iId}').dialog('close');">&nbsp;&nbsp;
<input type="button" id="btn_ok_{$this->iId}" value="{$sOK}" onClick="oACWidget_{$this->iId}.DoOk();">
<input type="hidden" id="count_{$this->iId}" value="0">
</form>
</div></div>
HTML
);
$sDialogTitle = addslashes($sTitle);
$oPage->add_ready_script(
<<<EOF
$oPage->add_ready_script(<<<JS
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
EOF
);
$oPage->add($sHTML);
JS
);
}
/**

View File

@@ -294,20 +294,17 @@ class UILinksWidgetDirect
*/
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass))
{
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) {
// Prevent linking to self if the linked object is of the same family
// and already present in the database
if (!$oCurrentObj->IsNew())
{
if (!$oCurrentObj->IsNew()) {
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
}
}
if (count($aAlreadyLinked) > 0)
{
if (count($aAlreadyLinked) > 0) {
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
}
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
@@ -319,18 +316,14 @@ class UILinksWidgetDirect
if ($valuesDef === null)
{
$oFilter = new DBObjectSearch($this->sLinkedClass);
}
else
{
if (!$valuesDef instanceof ValueSetObjects)
{
} else {
if (!$valuesDef instanceof ValueSetObjects) {
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
}
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
}
if ($oCurrentObj != null)
{
if ($oCurrentObj != null) {
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
@@ -339,7 +332,7 @@ class UILinksWidgetDirect
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
array(
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}",
@@ -349,16 +342,22 @@ class UILinksWidgetDirect
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria,
)
);
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->sInputid}\" value=\"0\"/>";
$sHtml .= "<button type=\"button\" class=\"cancel\">".Dict::S('UI:Button:Cancel')."</button>&nbsp;&nbsp;<button type=\"button\" class=\"ok\" disabled=\"disabled\">".Dict::S('UI:Button:Add')."</button>";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->sInputid}">
<div id="SearchResultsToAdd_{$this->sInputid}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
<button type="button" class="cancel">{$sCancel}</button>&nbsp;&nbsp;<button type="button" class="ok" disabled="disabled">{$sAdd}</button>
</form>
</div>
HTML
);
}
/**

View File

@@ -513,31 +513,27 @@ JS
*/
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
{
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
$oAlreadyLinkedFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
$oAlreadyLinkedExpression = $oAlreadyLinkedFilter->GetCriteria();
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->Render();
}
else
{
} else {
$sAlreadyLinkedExpression = '';
}
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
if(!empty($oCurrentObj))
{
if (!empty($oCurrentObj)) {
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aPrefillFormParam['filter'] = $oFilter;
$aPrefillFormParam['dest_class'] = $this->m_sRemoteClass;
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
@@ -548,16 +544,23 @@ JS
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sAlreadyLinkedExpression,
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"button\" onclick=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
)));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}">
<div id="SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_sAttCode}{$this->m_sNameSuffix}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');">&nbsp;&nbsp;<input id="btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}" disabled="disabled" type="button" onclick="return oWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
</div>
HTML
);
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");

View File

@@ -40,12 +40,12 @@ class UISearchFormForeignKeys
*/
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
@@ -54,16 +54,23 @@ class UISearchFormForeignKeys
'selection_mode' => true,
'cssCount' => "#count_{$this->m_iInputId}",
'query_params' => $oFilter->GetInternalParams(),
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_iInputId}\" disabled=\"disabled\" type=\"button\" onclick=\"return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
)));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->m_iInputId}">
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">&nbsp;&nbsp;<input id="btn_ok_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
</div>
HTML
);
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");

View File

@@ -20,4 +20,5 @@
@import "form";
@import "input";
@import "fieldset";
@import "field";
@import "field";
@import "toolbar";

View File

@@ -303,8 +303,13 @@ $ibo-button-icon--padding-right: 4px !default;
& ~ .ibo-button {
margin-left: 5px;
}
&.ibo-action-button {
float: right;
}
}
.ibo-button-icon {
padding-right: $ibo-button-icon--padding-right;
}
}

View File

@@ -0,0 +1,8 @@
/*!
* copyright Copyright (C) 2010-2020 Combodo SARL
* license http://opensource.org/licenses/AGPL-3.0
*/
.ibo-action-toolbar {
position: relative;
}

View File

@@ -184,6 +184,7 @@ return array(
'Combodo\\iTop\\Application\\UI\\Component\\Title\\Title' => $baseDir . '/sources/application/UI/Component/Title/Title.php',
'Combodo\\iTop\\Application\\UI\\Component\\Title\\TitleFactory' => $baseDir . '/sources/application/UI/Component/Title/TitleFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\Title\\TitleForObjectDetails' => $baseDir . '/sources/application/UI/Component/Title/TitleForObjectDetails.php',
'Combodo\\iTop\\Application\\UI\\Component\\Toolbar\\Toolbar' => $baseDir . '/sources/application/UI/Component/Toolbar/Toolbar.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntry' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/ActivityEntry.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntryFactory' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/ActivityEntryFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpAttachmentAddedFactory' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpAttachmentAddedFactory.php',

View File

@@ -414,6 +414,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\UI\\Component\\Title\\Title' => __DIR__ . '/../..' . '/sources/application/UI/Component/Title/Title.php',
'Combodo\\iTop\\Application\\UI\\Component\\Title\\TitleFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Title/TitleFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\Title\\TitleForObjectDetails' => __DIR__ . '/../..' . '/sources/application/UI/Component/Title/TitleForObjectDetails.php',
'Combodo\\iTop\\Application\\UI\\Component\\Toolbar\\Toolbar' => __DIR__ . '/../..' . '/sources/application/UI/Component/Toolbar/Toolbar.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntry' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/ActivityEntry.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntryFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/ActivityEntryFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpAttachmentAddedFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpAttachmentAddedFactory.php',

View File

@@ -123,21 +123,20 @@ EOF
$oFavoriteOrganizationsBlock = new Panel(Dict::S('UI:FavoriteOrganizations'), array(), 'grey', 'ibo-favorite-organizations');
$sFavoriteOrganizationsHtml = '';
$sFavoriteOrganizationsHtml .= Dict::S('UI:FavoriteOrganizations+');
$sFavoriteOrganizationsHtml .= '<form method="post">';
$oFavoriteOrganizationsBlock->AddHtml(Dict::S('UI:FavoriteOrganizations+'));
$oFavoriteOrganizationsBlock->AddHtml('<form method="post">');
// Favorite organizations: the organizations listed in the drop-down menu
$sOQL = ApplicationMenu::GetFavoriteSiloQuery();
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$sFavoriteOrganizationsHtml .= $oBlock->GetDisplay($oP, 1, array(
$oFavoriteOrganizationsBlock->AddSubBlock($oBlock->GetDisplay($oP, 1, array(
'menu' => false,
'selection_mode' => true,
'selection_type' => 'multiple',
'cssCount' => '.selectedCount',
'table_id' => 'user_prefs',
));
$sFavoriteOrganizationsHtml .= $oAppContext->GetForForm();
)));
$oFavoriteOrganizationsBlock->AddSubBlock($oAppContext->GetForFormBlock());
// - Cancel button
$oFavoriteOrganizationsCancelButton = ButtonFactory::MakeForSecondaryAction(Dict::S('UI:Button:Cancel'));
@@ -202,8 +201,6 @@ EOF
);
}
$oFavoriteOrganizationsHtmlBlock = new Html($sFavoriteOrganizationsHtml);
$oFavoriteOrganizationsBlock->AddSubBlock($oFavoriteOrganizationsHtmlBlock);
$oFavoriteOrganizationsBlock->AddSubBlock($oFavoriteOrganizationsCancelButton);
$oFavoriteOrganizationsBlock->AddSubBlock($oFavoriteOrganizationsSubmitButton);
$oFavoriteOrganizationsBlock->AddSubBlock($oFavoriteOrganizationsEndHtmlBlock);
@@ -217,18 +214,16 @@ EOF
//////////////////////////////////////////////////////////////////////////
$oShortcutsBlock = new Panel(Dict::S('Menu:MyShortcuts'), array(), 'grey', 'ibo-shortcuts');
$sShortcutsHtml = '';
$oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$aExtraParams = array();
$oBlock = new DisplayBlock($oBMSearch, 'list', false, $aExtraParams);
$sShortcutsHtml .= $oBlock->GetDisplay($oP, 'shortcut_list', array('view_link' => false, 'menu' => false, 'toolkit_menu' => false, 'selection_mode' => true, 'selection_type' => 'multiple', 'cssCount'=> '#shortcut_selection_count', 'table_id' => 'user_prefs_shortcuts'));
$sShortcutsHtml .='<p>';
$oShortcutsBlock->AddSubBlock($oBlock->GetDisplay($oP, 'shortcut_list', array('view_link' => false, 'menu' => false, 'toolkit_menu' => false, 'selection_mode' => true, 'selection_type' => 'multiple', 'cssCount' => '#shortcut_selection_count', 'table_id' => 'user_prefs_shortcuts')));
$sShortcutsHtml = '<p>';
$oSet = new DBObjectSet($oBMSearch);
if ($oSet->Count() > 0)
{
if ($oSet->Count() > 0) {
$sButtons = '<img src="../images/tv-item-last.gif">';
$sButtons .= '<button id="shortcut_btn_rename">'.Dict::S('UI:Button:Rename').'</button>';
$sButtons .= '<button id="shortcut_btn_delete">'.Dict::S('UI:Button:Delete').'</button>';

View File

@@ -94,6 +94,8 @@ class Button extends UIBlock
protected $sJsCode;
/** @var string $sOnClickJsCode */
protected $sOnClickJsCode;
/** @var array */
protected $aAdditionalCSSClasses;
/**
* Button constructor.
@@ -127,6 +129,7 @@ class Button extends UIBlock
$this->sJsCode = $sJsCode;
$this->sOnClickJsCode = $sOnClickJsCode;
$this->bIsDisabled = false;
$this->aAdditionalCSSClasses = [];
parent::__construct($sId);
}
@@ -160,7 +163,7 @@ class Button extends UIBlock
/**
* @param string $sType
*
*
* @return $this
*/
public function SetType(string $sType)
@@ -179,7 +182,7 @@ class Button extends UIBlock
/**
* @param string $sName
*
*
* @return $this
*/
public function SetName(string $sName)
@@ -198,7 +201,7 @@ class Button extends UIBlock
/**
* @param string $sValue
*
*
* @return $this
*/
public function SetValue(string $sValue)
@@ -217,7 +220,7 @@ class Button extends UIBlock
/**
* @param string $sTooltip
*
*
* @return $this
*/
public function SetTooltip(string $sTooltip)
@@ -236,7 +239,7 @@ class Button extends UIBlock
/**
* @param string $sIconClass
*
*
* @return $this
*/
public function SetIconClass(string $sIconClass)
@@ -255,7 +258,7 @@ class Button extends UIBlock
/**
* @param string $sActionType
*
*
* @return $this
*/
public function SetActionType(string $sActionType)
@@ -275,7 +278,7 @@ class Button extends UIBlock
/**
* @param string $sColor
*
*
* @return $this
*/
public function SetColor(string $sColor)
@@ -302,6 +305,7 @@ class Button extends UIBlock
$this->bIsDisabled = $bIsDisabled;
return $this;
}
/**
* @return string
*/
@@ -341,4 +345,24 @@ class Button extends UIBlock
return $this;
}
/**
* @return string
*/
public function GetAdditionalCSSClass(): string
{
return implode(' ', $this->aAdditionalCSSClasses);
}
public function AddCSSClasses(string $sCSSClasses): self
{
foreach (explode(' ', $sCSSClasses) as $sCSSClass) {
if (!empty($sCSSClass)) {
$this->aAdditionalCSSClasses[$sCSSClass] = $sCSSClass;
}
}
return $this;
}
}

View File

@@ -285,4 +285,40 @@ class ButtonFactory
return $oButton;
}
/**
* Make a basis Button component for any purpose
*
* @param string $sLabel
* @param string $sName See Button::$sName
* @param string $sIconClass
* @param string $sURL
* @param string $sTarget
* @param string|null $sId
*
* @return \Combodo\iTop\Application\UI\Component\Button\Button
*/
public static function MakeAlternativeNeutralActionButton(string $sLabel, string $sName, string $sIconClass = '', string $sURL = '', string $sTarget = '', ?string $sId = null): Button
{
$oButton = new Button($sLabel, $sId);
$oButton->SetActionType(Button::ENUM_ACTION_TYPE_ALTERNATIVE)
->SetColor(Button::ENUM_COLOR_NEUTRAL)
->SetName($sName);
if (!empty($sIconClass)) {
$oButton->SetIconClass($sIconClass);
}
if (!empty($sURL)) {
if (empty($sTarget)) {
$sJS = "window.location='{$sURL}';";
} else {
$sJS = "window.open('{$sURL}', '{$sTarget}');";
}
$oButton->SetOnClickJsCode($sJS);
}
return $oButton;
}
}

View File

@@ -21,10 +21,8 @@ namespace Combodo\iTop\Application\UI\Component\PopoverMenu;
use appUserPreferences;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItemFactory;
use Dict;
use iNewsroomProvider;
use JSPopupMenuItem;
use MetaModel;
use URLPopupMenuItem;
@@ -198,4 +196,51 @@ class PopoverMenuFactory
return $aItems;
}
public static function MakeMenuForActions(string $sId, array $aMenuItems): PopoverMenu
{
$oMenu = new PopoverMenu($sId);
$bFirst = true;
foreach ($aMenuItems as $sSection => $aActions) {
$aItems = [];
if (!$bFirst) {
$aItems[] = PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem(
new \SeparatorPopupMenuItem()
);
}
foreach ($aActions as $aAction) {
if (!empty($aAction['on_click'])) {
// JS
$oPopoverMenuItem = PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem(
new JSPopupMenuItem(
$aAction['uid'],
$aAction['label'],
$aAction['on_click'])
);
} else {
// URL
$oPopoverMenuItem = PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem(
new URLPopupMenuItem(
$aAction['uid'],
$aAction['label'],
$aAction['url'],
$aAction['target'])
);
}
if (!empty($aAction['css_classes'])) {
$oPopoverMenuItem->SetCssClasses($aAction['css_classes']);
}
$aItems[] = $oPopoverMenuItem;
}
$oMenu->AddSection($sSection)
->SetItems($sSection, $aItems);
$bFirst = false;
}
return $oMenu;
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Component\Toolbar;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
/**
* Class Toolbar
*
* @package Combodo\iTop\Application\UI\Component\Toolbar
*/
class Toolbar extends UIContentBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-toolbar';
public const HTML_TEMPLATE_REL_PATH = 'components/toolbar/layout';
}

View File

@@ -18,19 +18,23 @@ class UIContentBlock extends UIBlock implements iUIContentBlock
public const BLOCK_CODE = 'ibo-contentblock';
public const HTML_TEMPLATE_REL_PATH = 'layouts/contentblock/layout';
public const JS_TEMPLATE_REL_PATH = 'layouts/contentblock/layout';
/** @var array */
protected $aCSSClasses;
/** @var array */
protected $aSubBlocks;
/**
* UIContentBlock constructor.
*
* @param string|null $sName
* @param string $sContainerClass
*/
public function __construct(string $sName = null)
public function __construct(string $sName = null, string $sContainerClass = '')
{
parent::__construct($sName);
$this->aSubBlocks = [];
$this->SetCSSClasses($sContainerClass);
}
public function AddHtml(string $sHtml): iUIBlock
@@ -110,4 +114,40 @@ class UIContentBlock extends UIBlock implements iUIContentBlock
{
return array_key_exists($sId, $this->aSubBlocks);
}
/**
* @return string
*/
public function GetCSSClasses(): string
{
return implode(' ', $this->aCSSClasses);
}
/**
* @param string $sCSSClasses
*
* @return UIContentBlock
*/
public function SetCSSClasses(string $sCSSClasses): UIContentBlock
{
$this->aCSSClasses = [];
$this->AddCSSClasses($sCSSClasses);
return $this;
}
/**
* @param string $sCSSClasses
*
* @return $this
*/
public function AddCSSClasses(string $sCSSClasses): UIContentBlock
{
foreach (explode(' ', $sCSSClasses) as $sCSSClass) {
if (!empty($sCSSClass)) {
$this->aCSSClasses[$sCSSClass] = $sCSSClass;
}
}
return $this;
}
}

View File

@@ -18,6 +18,8 @@
*/
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuFactory;
use Combodo\iTop\Application\UI\iUIBlock;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
use Combodo\iTop\Renderer\BlockRenderer;
@@ -313,8 +315,11 @@ class WebPage implements Page
* @return \Combodo\iTop\Application\UI\iUIBlock block added
* @since 2.8.0
*/
public function AddUiBlock(iUIBlock $oBlock): iUIBlock
public function AddUiBlock(?iUIBlock $oBlock): ?iUIBlock
{
if (is_null($oBlock)) {
return null;
}
$this->oContentLayout->AddSubBlock($oBlock);
return $oBlock;
}
@@ -703,7 +708,7 @@ class WebPage implements Page
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
protected function RenderInlineTemplatesRecursively(iUIBlock $oBlock): void
public function RenderInlineTemplatesRecursively(iUIBlock $oBlock): void
{
$oBlockRenderer = new BlockRenderer($oBlock);
$sInlineScript = trim($oBlockRenderer->RenderJsInline());
@@ -978,32 +983,26 @@ class WebPage implements Page
{
$sPrevUrl = '';
$sHtml = '';
if (!$this->IsPrintableVersion())
{
foreach ($aActions as $sActionId => $aAction)
{
if (!$this->IsPrintableVersion()) {
foreach ($aActions as $sActionId => $aAction) {
$sDataActionId = 'data-action-id="'.$sActionId.'"';
$sClass = isset($aAction['css_classes']) ? 'class="'.implode(' ', $aAction['css_classes']).'"' : '';
$sOnClick = isset($aAction['onclick']) ? 'onclick="'.htmlspecialchars($aAction['onclick'], ENT_QUOTES,
"UTF-8").'"' : '';
$sTarget = isset($aAction['target']) ? "target=\"{$aAction['target']}\"" : "";
if (empty($aAction['url']))
{
if (empty($aAction['url'])) {
if ($sPrevUrl != '') // Don't output consecutively two separators...
{
$sHtml .= "<li $sDataActionId>{$aAction['label']}</li>";
}
$sPrevUrl = '';
}
else
{
} else {
$sHtml .= "<li $sDataActionId><a $sTarget href=\"{$aAction['url']}\" $sClass $sOnClick>{$aAction['label']}</a></li>";
$sPrevUrl = $aAction['url'];
}
}
$sHtml .= "</ul></li></ul></div>";
foreach (array_reverse($aFavoriteActions) as $sActionId => $aAction)
{
foreach (array_reverse($aFavoriteActions) as $sActionId => $aAction) {
$sTarget = isset($aAction['target']) ? " target=\"{$aAction['target']}\"" : "";
$sHtml .= "<div class=\"actions_button\" data-action-id=\"$sActionId\"><a $sTarget href='{$aAction['url']}'>{$aAction['label']}</a></div>";
}
@@ -1012,6 +1011,39 @@ class WebPage implements Page
return $sHtml;
}
/**
* @param string $sId
* @param array $aActions
*
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu|null
*/
public function GetPopoverMenu(string $sId, array $aActions): ?PopoverMenu
{
if ($this->IsPrintableVersion()) {
return null;
}
$iSectionIndex = 0;
$aMenuItems = [];
foreach ($aActions as $sActionId => $aAction) {
if (empty($aAction['url'])) {
$iSectionIndex++;
continue;
}
$aMenuItems["{$sId}_section_{$iSectionIndex}"][] = [
'uid' => $sActionId,
'css_classes' => isset($aAction['css_classes']) ? $aAction['css_classes'] : [],
'on_click' => isset($aAction['onclick']) ? $aAction['onclick'] : '',
'target' => isset($aAction['target']) ? $aAction['target'] : '',
'url' => $aAction['url'],
'label' => $aAction['label'],
];
}
return PopoverMenuFactory::MakeMenuForActions($sId, $aMenuItems);
}
/**
* @param bool $bReturnOutput
*
@@ -1019,16 +1051,13 @@ class WebPage implements Page
*/
protected function output_dict_entries($bReturnOutput = false)
{
if ((count($this->a_dict_entries) > 0) || (count($this->a_dict_entries_prefixes) > 0))
{
if (class_exists('Dict'))
{
if ((count($this->a_dict_entries) > 0) || (count($this->a_dict_entries_prefixes) > 0)) {
if (class_exists('Dict')) {
// The dictionary may not be available for example during the setup...
// Create a specific dictionary file and load it as a JS script
$sSignature = $this->get_dict_signature();
$sJSFileName = utils::GetCachePath().$sSignature.'.js';
if (!file_exists($sJSFileName) && is_writable(utils::GetCachePath()))
{
if (!file_exists($sJSFileName) && is_writable(utils::GetCachePath())) {
file_put_contents($sJSFileName, $this->get_dict_file_content());
}
// Load the dictionary as the first javascript file, so that other JS file benefit from the translations

View File

@@ -893,7 +893,7 @@ EOF;
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
protected function RenderInlineTemplatesRecursively(iUIBlock $oBlock): void
public function RenderInlineTemplatesRecursively(iUIBlock $oBlock): void
{
$oBlockRenderer = new BlockRenderer($oBlock);
$this->add_init_script($oBlockRenderer->RenderJsInline());
@@ -1326,8 +1326,11 @@ EOF;
return null;
}
public function AddUiBlock(iUIBlock $oBlock): iUIBlock
public function AddUiBlock(?iUIBlock $oBlock): ?iUIBlock
{
if (is_null($oBlock)) {
return null;
}
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != '')) {
return $this->m_oTabs->AddUIBlockToCurrentTab($oBlock);
}

View File

@@ -1,5 +1,5 @@
<button id="{{ oUIBlock.GetId() }}"
class="ibo-button ibo-is-{{ oUIBlock.GetActionType() }} ibo-is-{{ oUIBlock.GetColor() }}"
class="ibo-button ibo-is-{{ oUIBlock.GetActionType() }} ibo-is-{{ oUIBlock.GetColor() }} {{ oUIBlock.GetAdditionalCSSClass() }}"
type="{{ oUIBlock.GetType() }}"
name="{{ oUIBlock.GetName() }}"
value="{{ oUIBlock.GetValue() }}"

View File

@@ -0,0 +1 @@
{% extends 'layouts/contentblock/layout.html.twig' %}

View File

@@ -1,7 +1,17 @@
{% apply spaceless %}
{% block iboContentBlockContainer %}
{% if oUIBlock.GetCSSClasses() %}
<div id="{{ oUIBlock.GetId() }}" class="{{ oUIBlock.GetCSSClasses() }}">
{% endif %}
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
{{ render_block(oSubBlock, {aPage: aPage}) }}
{% endfor %}
{% if oUIBlock.GetCSSClasses() %}
</div>
{% endif %}
{% endblock %}
{% endapply %}