N°634: BrowseBrick Windows 8-style display (tiles). This is still a beta version.

SVN:trunk[4567]
This commit is contained in:
Guillaume Lajarige
2017-03-07 14:25:09 +00:00
parent 6582569150
commit c4d1113bb8
17 changed files with 916 additions and 41 deletions

View File

@@ -87,6 +87,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Brick:Portal:Browse:Name' => 'Procházet položky',
'Brick:Portal:Browse:Mode:List' => 'Seznam',
'Brick:Portal:Browse:Mode:Tree' => 'Strom',
'Brick:Portal:Browse:Mode:Grid' => 'Tiles~~',
'Brick:Portal:Browse:Action:Drilldown' => 'Rozpad',
'Brick:Portal:Browse:Action:View' => 'Podrobnosti',
'Brick:Portal:Browse:Action:Edit' => 'Upravit',

View File

@@ -83,6 +83,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Brick:Portal:Browse:Name' => 'List durchgehen',
'Brick:Portal:Browse:Mode:List' => 'Liste',
'Brick:Portal:Browse:Mode:Tree' => 'Baum',
'Brick:Portal:Browse:Mode:Grid' => 'Tiles~~',
'Brick:Portal:Browse:Action:Drilldown' => 'Drilldown',
'Brick:Portal:Browse:Action:View' => 'Details',
'Brick:Portal:Browse:Action:Edit' => 'Editieren',

View File

@@ -83,6 +83,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Brick:Portal:Browse:Name' => 'Browse throught items',
'Brick:Portal:Browse:Mode:List' => 'List',
'Brick:Portal:Browse:Mode:Tree' => 'Tree',
'Brick:Portal:Browse:Mode:Grid' => 'Tiles',
'Brick:Portal:Browse:Action:Drilldown' => 'Drilldown',
'Brick:Portal:Browse:Action:View' => 'Details',
'Brick:Portal:Browse:Action:Edit' => 'Edit',

View File

@@ -83,6 +83,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Brick:Portal:Browse:Name' => 'Buscar en todos los elementos',
'Brick:Portal:Browse:Mode:List' => 'Lista',
'Brick:Portal:Browse:Mode:Tree' => 'Árbol',
'Brick:Portal:Browse:Mode:Grid' => 'Tiles~~',
'Brick:Portal:Browse:Action:Drilldown' => 'Desglose',
'Brick:Portal:Browse:Action:View' => 'Detalles',
'Brick:Portal:Browse:Action:Edit' => 'Editar',

View File

@@ -82,7 +82,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Brick:Portal:Browse:Name' => 'Navigation dans les éléments',
'Brick:Portal:Browse:Mode:List' => 'Liste',
'Brick:Portal:Browse:Mode:Tree' => 'Hiérarchie',
'Brick:Portal:Browse:Mode:Tree' => 'Hiérarchie',
'Brick:Portal:Browse:Mode:Grid' => 'Tuiles',
'Brick:Portal:Browse:Action:Drilldown' => 'Parcourir',
'Brick:Portal:Browse:Action:View' => 'Détails',
'Brick:Portal:Browse:Action:Edit' => 'Modifier',

View File

@@ -2,7 +2,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-portal-base/1.0.1', array(
'itop-portal-base/1.1.0', array(
// Identification
'label' => 'Portal Development Library',
'category' => 'Portal',

View File

@@ -41,6 +41,7 @@ use \Combodo\iTop\Portal\Brick\BrowseBrick;
class BrowseBrickController extends BrickController
{
const LEVEL_SEPARATOR = '-';
public static $aOptionalAttributes = array('tooltip_att', 'description_att', 'image_att');
public function DisplayAction(Request $oRequest, Application $oApp, $sBrickId, $sBrowseMode = null, $sDataLoading = null)
{
@@ -78,7 +79,7 @@ class BrowseBrickController extends BrickController
// Building DBobjectSearch
$oQuery = null;
// ... In this case only we have to build a specific query for the current level only
if (($sBrowseMode === BrowseBrick::ENUM_BROWSE_MODE_TREE) && ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY))
if (in_array($sBrowseMode, array(BrowseBrick::ENUM_BROWSE_MODE_TREE, BrowseBrick::ENUM_BROWSE_MODE_GRID)) && ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_LAZY))
{
// Will be handled later in the pagination part
}
@@ -231,6 +232,7 @@ class BrowseBrickController extends BrickController
break;
case BrowseBrick::ENUM_BROWSE_MODE_TREE:
case BrowseBrick::ENUM_BROWSE_MODE_GRID:
// Retrieving parameters
$sLevelAlias = $oRequest->get('sLevelAlias');
$sNodeId = $oRequest->get('sNodeId');
@@ -298,7 +300,7 @@ class BrowseBrickController extends BrickController
$aTmpLevelProperties = $aLevelsProperties[$sTmpClassAlias];
// Mandatory main attribute
$aTmpColumnAttrs = array($aTmpLevelProperties['name_att']);
// Optionnal attributes, only if in list mode
// Optional attributes, only if in list mode
if ($sBrowseMode === BrowseBrick::ENUM_BROWSE_MODE_LIST)
{
foreach ($aTmpLevelProperties['fields'] as $aTmpField)
@@ -306,6 +308,15 @@ class BrowseBrickController extends BrickController
$aTmpColumnAttrs[] = $aTmpField['code'];
}
}
// Optional attributes
foreach(static::$aOptionalAttributes as $sOptionalAttribute)
{
if($aTmpLevelProperties[$sOptionalAttribute] !== null)
{
$aTmpColumnAttrs[] = $aTmpLevelProperties[$sOptionalAttribute];
}
}
$aColumnAttrs[$sTmpClassAlias] = $aTmpColumnAttrs;
}
}
@@ -321,6 +332,7 @@ class BrowseBrickController extends BrickController
switch ($sBrowseMode)
{
case BrowseBrick::ENUM_BROWSE_MODE_TREE:
case BrowseBrick::ENUM_BROWSE_MODE_GRID:
static::AddToTreeItems($aItems, $aCurrentRow, $aLevelsProperties);
break;
@@ -381,7 +393,7 @@ class BrowseBrickController extends BrickController
*
* Note : This is not in the BrowseBrick class because the classes should not rely on DBObjectSearch.
*
* @param Silex\Application $oApp
* @param \Silex\Application $oApp
* @param array $aLevels Levels from a BrowseBrick class
* @param array $aLevelsProperties Reference to an array that will contain the flattened levels
* @param string $sLevelAliasPrefix String that will be prefixed to the level ID as an unique path identifier
@@ -409,7 +421,9 @@ class BrowseBrickController extends BrickController
'title' => ($aLevel['title'] !== null) ? Dict::S($aLevel['title']) : MetaModel::GetName($oSearch->GetClass()),
'parent_att' => $aLevel['parent_att'],
'name_att' => $aLevel['name_att'],
'tooltip_att' => $aLevel['tooltip_att'],
'tooltip_att' => $aLevel['tooltip_att'],
'description_att' => $aLevel['description_att'],
'image_att' => $aLevel['image_att'],
'search' => $oSearch,
'fields' => array(),
'actions' => array()
@@ -613,11 +627,29 @@ class BrowseBrickController extends BrickController
'action_rules_token' => static::PrepareActionRulesForItems($aItems, $key, $aLevelsProperties)
);
// Adding tooltip attribute if necessary
if ($aLevelsProperties[$key]['tooltip_att'] !== null)
{
$aRow[$key]['tooltip'] = $value->Get($aLevelsProperties[$key]['tooltip_att']);
}
// Adding optional attributes if necessary
foreach(static::$aOptionalAttributes as $sOptionalAttribute)
{
if ($aLevelsProperties[$key][$sOptionalAttribute] !== null)
{
$sPropertyName = substr($sOptionalAttribute, 0, -4);
$tmpAttValue = $value->Get($aLevelsProperties[$key][$sOptionalAttribute]);
if($sOptionalAttribute === 'image_att')
{
if (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty())
{
$tmpAttValue = $tmpAttValue->GetDisplayURL(get_class($value), $value->GetKey(), $aLevelsProperties[$key][$sOptionalAttribute]);
}
else
{
$tmpAttValue = MetaModel::GetAttributeDef(get_class($value), $aLevelsProperties[$key][$sOptionalAttribute])->Get('default_image');
}
}
$aRow[$key][$sPropertyName] = $tmpAttValue;
}
}
// Adding fields attributes if necessary
if (!empty($aLevelsProperties[$key]['fields']))
{
@@ -687,10 +719,29 @@ class BrowseBrickController extends BrickController
'action_rules_token' => static::PrepareActionRulesForItems($aCurrentRowObjects, $aCurrentRowKeys[0], $aLevelsProperties)
);
if ($aLevelsProperties[$aCurrentRowKeys[0]]['tooltip_att'] !== null)
{
$aItems[$sCurrentIndex]['tooltip'] = $aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]]['tooltip_att']);
}
// Adding optional attributes if necessary
foreach(static::$aOptionalAttributes as $sOptionalAttribute)
{
if ($aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute] !== null)
{
$sPropertyName = substr($sOptionalAttribute, 0, -4);
$tmpAttValue = $aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute]);
if($sOptionalAttribute === 'image_att')
{
if (is_object($tmpAttValue) && !$tmpAttValue->IsEmpty())
{
$tmpAttValue = $tmpAttValue->GetDisplayURL(get_class($aCurrentRowValues[0]), $aCurrentRowValues[0]->GetKey(), $aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute]);
}
else
{
$tmpAttValue = MetaModel::GetAttributeDef(get_class($aCurrentRowValues[0]), $aLevelsProperties[$aCurrentRowKeys[0]][$sOptionalAttribute])->Get('default_image');
}
}
$aItems[$sCurrentIndex][$sPropertyName] = $tmpAttValue;
}
}
}
$aCurrentRowSliced = array_slice($aCurrentRow, 1);

View File

@@ -33,7 +33,8 @@ class BrowseBrick extends PortalBrick
const DEFAULT_HOME_ICON_CLASS = 'fa fa-map';
const DEFAULT_NAVIGATION_MENU_ICON_CLASS = 'fa fa-map fa-2x';
const ENUM_BROWSE_MODE_LIST = 'list';
const ENUM_BROWSE_MODE_TREE = 'tree';
const ENUM_BROWSE_MODE_TREE = 'tree';
const ENUM_BROWSE_MODE_GRID = 'grid';
const ENUM_ACTION_VIEW = 'view';
const ENUM_ACTION_EDIT = 'edit';
const ENUM_ACTION_DRILLDOWN = 'drilldown';
@@ -289,6 +290,8 @@ class BrowseBrick extends PortalBrick
$aLevel = array(
'parent_att' => null,
'tooltip_att' => null,
'description_att' => null,
'image_att' => null,
'title' => null,
'name_att' => static::DEFAULT_LEVEL_NAME_ATT,
'fields' => array(),
@@ -331,6 +334,8 @@ class BrowseBrick extends PortalBrick
case 'parent_att':
case 'tooltip_att':
case 'description_att':
case 'image_att':
case 'title':
$aLevel[$oLevelPropertyNode->nodeName] = $oLevelPropertyNode->GetText(null);
break;
@@ -458,5 +463,3 @@ class BrowseBrick extends PortalBrick
}
}
?>

View File

@@ -0,0 +1,385 @@
{# itop-portal-base/portal/src/views/bricks/browse/mode_grid.html.twig #}
{# Browse brick grid mode layout #}
{% extends 'itop-portal-base/portal/src/views/bricks/browse/layout.html.twig' %}
{% block bBrowseMainContent %}
<div id="brick_content_grid">
{% block bBrowseGridContent %}
<div class="grid-group" data-level-id="L">
</div>
{% endblock %}
</div>
<div id="brick_content_empty" class="text-center">
{% block bBrowseGridEmpty %}
{{ 'Brick:Portal:Browse:Filter:NoData'|dict_s }}
{% endblock %}
</div>
<div id="brick_grid_overlay">
{% block bBrowseGridOverlay %}
<div class="overlay_content">
{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
</div>
{% endblock %}
</div>
{% endblock %}
{% block pPageLiveScripts %}
{{ parent() }}
<script type="text/javascript">
var sBrowseMode = '{{ sBrowseMode }}';
var oLevelsProperties = {{ aLevelsProperties|raw }};
var oRawDatas = {{ aItems|raw }};
var sGridEffectName = 'fade';
var oGridEffectOptions = {};
var iGridEffectDuration = 200;
// Show a loader over the grid
var showGridLoader = function()
{
$("#brick_content_grid").hide();
$('#brick_grid_overlay').show();
};
// Hide the loader over the tree
var hideGridLoader = function()
{
$('#brick_grid_overlay').hide();
$("#brick_content_grid").show();
}
// Registers the toggle listeners on the tree nodes. Used after every AJAX calls.
var registerToggleListeners = function()
{
$('#brick_content_grid .grid-drilldown').off('click').on('click', function (oEvent) {
oEvent.preventDefault();
var me = this;
// Retrieving sublevel
var sublevelId = $(this).attr('data-level-alias') + '::' + $(this).attr('data-item-id');
var sublevelElem = $('#brick_content_grid .grid-group[data-level-id="'+sublevelId+'"]');
// Hidding current level
if(sublevelElem.length === 0)
{
showGridLoader();
}
$(this).closest('.grid-group').hide(
sGridEffectName,
oGridEffectOptions,
iGridEffectDuration,
function(){
// Showing sublevel
if(sublevelElem.length === 0)
{
loadChildNodes($(me).attr('data-level-alias'), $(me).attr('data-item-id'));
}
else
{
sublevelElem.show(sGridEffectName, oGridEffectOptions, iGridEffectDuration);
}
}
);
});
$('#brick_content_grid .grid-rollup').off('click').on('click', function (oEvent) {
oEvent.preventDefault();
// Retrieving upper level
var upperlevelId = $(this).attr('data-level-id');
var upperlevelElem = $('#brick_content_grid .grid-group[data-level-id="'+upperlevelId+'"]');
// Hidding current level
$(this).closest('.grid-group').hide(
sGridEffectName,
oGridEffectOptions,
iGridEffectDuration,
function(){
// Showing upper level
if(upperlevelElem.length === 0)
{
var upperlevelIdParts = upperlevelId.split('::');
loadChildNodes(upperlevelIdParts[0], upperlevelIdParts[1]);
}
else
{
upperlevelElem.show(sGridEffectName, oGridEffectOptions, iGridEffectDuration);
}
}
);
});
};
// Registers the filter listeners on the tree.
var registerFilterListeners = function()
{
/*$('#brick_search_field').treeListFilter('#brick_content_grid', iSearchDelay, filterResultsHandler);*/
};
// Load current node childnodes throught AJAX
var loadChildNodes = function(sLevelAlias, sNodeId)
{
var sUrl = '{{ app.url_generator.generate('p_browse_brick_mode_tree', {'sBrickId': sBrickId, 'sBrowseMode': sBrowseMode, 'sLevelAlias': '-sLevelAlias-', 'sNodeId': '-sNodeId-'})|raw }}';
sUrl = sUrl.replace(/-sLevelAlias-/, sLevelAlias).replace(/-sNodeId-/, sNodeId);
$.ajax(sUrl)
.done(function(data) {
// Building child nodes
for(index in data.data)
{
var sublevel = data.data[index];
var sublevelData = {};
sublevelData[sublevel.level_alias+"::"+sublevel.id] = sublevel;
buildGrid(sublevelData, sLevelAlias+"::"+sNodeId, false);
}
// Showing sublevel
$('#brick_content_grid .grid-group[data-level-id="'+sLevelAlias+"::"+sNodeId+'"]').show(sGridEffectName, oGridEffectOptions, iGridEffectDuration);
registerToggleListeners();
})
.fail(function() {
alert('{{ 'Error:XHR:Fail'|dict_s }}');
})
.always(function(){
hideGridLoader();
});
};
// Build tree nodes from data under the nodeId
var buildGrid = function(data, nodeId, isRootLevel)
{
var iItemIndex;
var oItemFlowLastOfLineIndex = {
sm: 3,
md: 3,
lg: 4,
};
if(nodeId === undefined)
{
// We are on the root node
nodeId = 'L';
}
if(isRootLevel === undefined)
{
isRootLevel = true;
}
// Building node if necessary
if($('div[data-level-id="'+nodeId+'"]').length === 0)
{
$('#brick_content_grid').append( $('<div></div>').addClass('grid-group').attr('data-level-id', nodeId) );
}
// - Initializing item index
iItemIndex = $('div[data-level-id="'+nodeId+'"] .grid-item').length;
if(!isRootLevel)
{
// Retrieving upper level id
var levelIdParts = nodeId.split('::');
var upperlevelId = $('.grid-item[data-level-alias="'+levelIdParts[0]+'"][data-item-id="'+levelIdParts[1]+'"]').closest('.grid-group').attr('data-level-id');
// Building back button
if( $('div[data-level-id="'+nodeId+'"] .grid-group-back').length === 0 ) {
var backElem = $('<div></div>').addClass('grid-group-back');
var aElem = $('<a></a>').addClass('grid-item').addClass('grid-rollup').attr('href', '#').attr('data-level-id', upperlevelId).html('<div class="grid-item-text"><span class="glyphicon glyphicon-arrow-left"></span></div>');
iItemIndex++;
backElem.append(aElem);
$('div[data-level-id="' + nodeId + '"]').append(backElem);
}
}
else
{
$('div[data-level-id="'+nodeId+'"]').html('');
}
$.each(data, function(i, item){
var levelId = item.level_alias+'::'+item.id;
var levelAltId = item.level_alias+'_'+item.id;
var levelActions = oLevelsProperties[item.level_alias].actions;
var levelActionsKeys = Object.keys(levelActions);
var levelPrimaryAction = levelActions[levelActionsKeys[0]];
var url = '';
// Building node
var itemElem = $('<div></div>').addClass('grid-group-item');
var aElem = $('<a></a>').addClass('grid-item').attr('data-item-id', item.id).attr('href', '#').attr('data-level-alias', item.level_alias);
var iItemFlags = 0;
iItemIndex++;
// - Adding stub div
var textElem = $('<div></div>').addClass('grid-item-text');
// - Adding image
if( (item.image !== undefined) && (item.image !== '') )
{
iItemFlags += 4;
aElem.append( $('<div></div>').addClass('grid-item-image').append( $('<img />').attr('src', item.image) ) );
}
// - Adding name
if( (item.name !== undefined) && (item.name !== '') )
{
iItemFlags += 1;
textElem.append( $('<div></div>').addClass('grid-item-name').text(item.name) );
}
// - Adding description
if( (item.description !== undefined) && (item.description !== '') )
{
iItemFlags += 2;
textElem.append( $('<div></div>').addClass('grid-item-description').text(item.description) );
}
aElem.append( textElem );
// - Adding CSS class to adjust the layout regarding which properties are available
aElem.addClass('grid-item-layout-'+iItemFlags);
// - Adding CSS class to adjust items flow regarding the screen size
for(var i in oItemFlowLastOfLineIndex)
{
if(iItemIndex % oItemFlowLastOfLineIndex[i] === 0)
{
itemElem.addClass('ggi-last-'+i);
}
}
// - Appending element
$('div[data-level-id="'+nodeId+'"]').append(itemElem);
itemElem.append(aElem);
// Building tooltip for the node
if( (item.tooltip !== undefined) && (item.tooltip !== '') )
{
aElem.attr('title', item.tooltip).attr('data-toggle', 'tooltip').tooltip({html: true, trigger: 'hover', placement: 'top'});
}
// Building actions for that node
switch(levelPrimaryAction.type)
{
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_DRILLDOWN') }}':
aElem.addClass('grid-drilldown');
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}':
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
aElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_EDIT') }}':
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
aElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = levelPrimaryAction.url.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
url = AddParameterToUrl(url, 'ar_token', item.action_rules_token[levelPrimaryAction.type]);
aElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+levelPrimaryAction.type+'" not implemented for primary action');
break;
}
if(levelActionsKeys.length > 1)
{
// Retrieving secondary action
var actionsButtons = {};
for(j = 1; j < levelActionsKeys.length; j++)
{
actionsButtons[levelActionsKeys[j]] = levelActions[levelActionsKeys[j]];
}
// Preparing secondary actions container
var actionsElem = $('<div></div>').addClass('grid-group-item-actions');
itemElem.append(actionsElem);
// Checking if a menu is necessary
var bHasSeveralSecondaryActions = (Object.keys(actionsButtons).length > 1);
// Preparing secondary actions menu
if(bHasSeveralSecondaryActions)
{
var actionsSSTogglerElem = $('<a class="glyphicon glyphicon-menu-hamburger" data-toggle="collapse" data-target="#item-actions-menu-'+levelAltId+'"></a>');
var actionsSSMenuElem = $('<div id="item-actions-menu-'+levelAltId+'" class="item-action-wrapper panel panel-default"></div>');
var actionsSSMenuContainerElem = $('<div class="panel-body"></div>');
actionsSSMenuElem.append(actionsSSMenuContainerElem);
actionsElem.append(actionsSSTogglerElem);
actionsElem.append(actionsSSMenuElem);
}
// Adding secondary actions
for(j in actionsButtons)
{
var action = actionsButtons[j];
var actionElem = $('<a></a>');
var actionIconElem = $('<span></span>').appendTo(actionElem);
switch(action.type)
{
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}':
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
actionElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_EDIT') }}':
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
actionElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = action.url.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
url = AddParameterToUrl(url, 'ar_token', item.action_rules_token[action.type]);
actionElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+action.type+'" not implemented for secondary action');
break;
}
// Adding title if present
if(action.title !== undefined)
{
actionElem.attr('title', action.title);
}
// Adding icon class if present
if(action.icon_class !== undefined)
{
actionIconElem.addClass(action.icon_class);
}
if(bHasSeveralSecondaryActions)
{
actionElem.append(action.title);
actionsSSMenuContainerElem.append( $('<p></p>').append(actionElem) );
}
else
{
actionsElem.append(actionElem);
}
}
}
// Building subnodes if necessary
if(item.subitems.length !== 0)
{
var subitemsElem;
if($('div[data-level-id="'+levelId+'"]').length > 0)
{
subitemsElem = $('div[data-level-id="'+levelId+'"]');
}
else
{
subitemsElem = $('<div></div>').addClass('grid-group').attr('data-level-id', levelId);
$('div[data-level-id="'+nodeId+'"]').after(subitemsElem);
}
buildGrid(item.subitems, levelId, false);
}
});
// Update listeners
if(isRootLevel)
{
registerToggleListeners();
}
};
$(document).ready(function(){
// Auto collapse item actions popup
$('body').click(function(){
$('#brick_content_grid .item-action-wrapper.collapse.in').collapse('hide');
});
// Build the tree (collapsed)
showGridLoader();
buildGrid(oRawDatas);
hideGridLoader();
registerFilterListeners();
});
</script>
{% endblock %}

View File

@@ -36,12 +36,7 @@
</div>
<div id="brick_tree_overlay">
<div class="overlay_content">
<div class="content_loader">
<div class="icon glyphicon glyphicon-refresh"></div>
<div class="message">
{{ 'Page:PleaseWait'|dict_s }}
</div>
</div>
{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
</div>
</div>
{% endblock %}
@@ -206,6 +201,11 @@
{
aElem.attr('title', item.tooltip).attr('data-toggle', 'tooltip').tooltip({html: true, trigger: 'hover', placement: 'right'});
}
// Building description for the node
if( (item.description !== undefined) && (item.description !== '') )
{
liElem.append( $('<span class="list-group-item-description">'+item.description+'</span>') );
}
// Building actions for that node
switch(levelPrimaryAction.type)

View File

@@ -11,7 +11,7 @@
{% endif %}
{% endblock %}
{% block pPageBodyClass %}{{ parent() }} page_brick_of_id_{{ oBrick.GetId() }}{% endblock %}
{% block pPageBodyClass %}{{ parent() }} {% if oBrick is defined and oBrick is not null %}page_brick_of_id_{{ oBrick.GetId() }}{% endif %}{% endblock %}
{% block pMainHeader %}
<div class="col-xs-12">

View File

@@ -60,7 +60,7 @@
{% endblock %}
{% block pPageScripts %}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/jquery/jquery-1.11.3.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery-ui-1.10.3.custom.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/jquery-ui/jquery-ui-1.11.4.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.magnific-popup.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.iframe-transport.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.fileupload.js'|add_itop_version }}"></script>

View File

@@ -553,10 +553,10 @@ footer {
top: 10px;
right: 10px;
}
.list-group-item:hover > .list-group-item-actions {
.list-group-item:hover > .list-group-item-actions, .grid-group-item:hover > .grid-group-item-actions {
display: block;
}
.list-group-item .list-group-item-actions a:not(:first-child) {
.list-group-item .list-group-item-actions a:not(:first-child), .grid-group-item .grid-group-item-actions a:not(:first-child) {
margin-left: 10px;
}
.list-group-item .keep-spinning {
@@ -565,15 +565,20 @@ footer {
-moz-animation: spin 1s linear infinite;
-ms-animation: spin 1s linear infinite;
}
.list-group.tree .list-group-item .list-group-item-description {
display: block;
margin-top: 3px;
font-size: 0.8em;
}
/* Secondary actions */
table .group-actions {
position: relative;
}
.list-group-item-actions a.glyphicon-menu-hamburger, table .group-actions a.glyphicon-menu-hamburger {
.list-group-item-actions a.glyphicon-menu-hamburger, .grid-group-item-actions a.glyphicon-menu-hamburger, table .group-actions a.glyphicon-menu-hamburger {
cursor: pointer;
text-decoration: none;
}
.list-group-item-actions .item-action-wrapper, table .group-actions .item-action-wrapper {
.list-group-item-actions .item-action-wrapper, .grid-group-item-actions .item-action-wrapper, table .group-actions .item-action-wrapper {
display: none;
position: absolute;
z-index: 5;
@@ -583,16 +588,16 @@ table .group-actions {
-moz-box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15);
}
.list-group-item-actions .item-action-wrapper .glyphicon, table .group-actions .item-action-wrapper .glyphicon {
.list-group-item-actions .item-action-wrapper .glyphicon, .grid-group-item-actions .item-action-wrapper .glyphicon, table .group-actions .item-action-wrapper .glyphicon {
margin-right: 0.6em;
}
.list-group-item-actions .item-action-wrapper.collapse.in, table .group-actions .item-action-wrapper.collapse.in {
.list-group-item-actions .item-action-wrapper.collapse.in, .grid-group-item-actions .item-action-wrapper.collapse.in, table .group-actions .item-action-wrapper.collapse.in {
display: block;
}
.list-group-item-actions .item-action-wrapper .panel-body > p, table .group-actions .item-action-wrapper .panel-body > p {
.list-group-item-actions .item-action-wrapper .panel-body > p, .grid-group-item-actions .item-action-wrapper .panel-body > p, table .group-actions .item-action-wrapper .panel-body > p {
white-space: nowrap;
}
.list-group-item-actions .item-action-wrapper .panel-body > p:last-child, table .group-actions .item-action-wrapper .panel-body > p:last-child {
.list-group-item-actions .item-action-wrapper .panel-body > p:last-child, .grid-group-item-actions .item-action-wrapper .panel-body > p:last-child, table .group-actions .item-action-wrapper .panel-body > p:last-child {
margin-bottom: 0px;
}
#brick_content_empty {
@@ -602,13 +607,197 @@ table .group-actions {
font-style: italic;
}
/* Loader */
#brick_tree_overlay {
#brick_tree_overlay, #brick_grid_overlay {
display: none;
padding: 8% 0px;
border-radius: 0px 0px 4px 4px;
font-size: 1em;
}
/****************/
/* - Grid mode */
/* Note: Some of the CSS is factorised in the "Tree mode" part */
/****************/
#brick_content_grid {
position: relative;
padding: 10px 10px 1px 10px;
}
.grid-group {
display: none;
}
/* Only the first level is showed by default */
.grid-group:first-child {
display: block;
}
.grid-group-back, .grid-group-item {
position: relative;
height: 55px;
margin-bottom: 10px;
text-align: center;
color: #fff;
}
.grid-group-back {
font-size: 25px;
}
.grid-item {
display: table;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #585653;
transition: background-color linear 0.3s;
}
.grid-item, .grid-item:hover, .grid-item:active, .grid-item:focus, .grid-item:visited {
color: #fff;
text-decoration: none;
}
.grid-item:active {
background-color: #9e510f;
}
.grid-item-image, .grid-item-text {
display: table-cell;
text-align: center;
vertical-align: middle;
}
.grid-item-image > img {
max-width: 100%;
}
.grid-group-item > .grid-group-item-actions {
position: absolute;
top: 5px;
right: 5px;
}
.grid-group-item-actions > a {
color: #fff;
text-decoration: none;
}
.grid-group-item-actions > a:hover, .grid-group-item-actions > a:focus {
color: #eee;
}
.ggi-last-xs, .ggi-last-sm, .ggi-last-md, .ggi-last-lg {
margin-right: 0px;
}
@media (max-width: 768px) {
/* All layout */
/* Layout 2 */
/* Layout 5/7 */
.grid-group-item > .grid-group-item-actions {
top: 12px;
right: 6px;
}
.grid-group-item > .grid-group-item-actions > .glyphicon {
margin-top: 5px;
}
.grid-group-item-actions > a {
font-size: 20px;
}
.grid-item-image {
width: 55px;
padding: 10px;
}
.grid-item-image > img {
max-height: 30px;
}
.grid-item-name {
font-size: 14px;
}
.grid-item-description {
display: none;
}
.grid-item-layout-2 .grid-item-description {
display: block;
}
.grid-item-layout-5 .grid-item-name, .grid-item-layout-7 .grid-item-name {
padding-right: 40px;
}
}
@media (min-width: 768px) {
/* All layout */
/* Layout 1 */
/* Layout 7 */
.grid-group-back, .grid-group-item {
display: inline-block;
width: 32%;
height: 120px;
margin-right: 1.95%;
/* We don't put 2% to keep a margin in case of a bad browser rendering */
}
.grid-item {
padding: 10px;
}
.grid-item:hover, .grid-item:focus {
background-color: #ea7d1e;
}
.grid-item-name {
font-weight: 600;
font-size: 12px;
}
.grid-item-description {
overflow: hidden;
}
.grid-item-layout-1 .grid-item-name {
font-weight: inherit;
font-size: 14px;
}
.grid-item-layout-7 .grid-item-image {
display: none;
}
.grid-item-layout-3 .grid-item-description, .grid-item-layout-7 .grid-item-description {
margin-top: 10px;
max-height: 40px;
font-size: 10px;
}
}
@media (min-width: 992px) {
/* Layout 7 */
.grid-item {
padding: 10px 15px;
}
.grid-group-back {
font-size: 40px;
}
.grid-item-layout-7 .grid-item-image {
display: table-cell;
width: 105px;
padding-left: 5px;
padding-right: 18px;
}
.grid-item-layout-7 .grid-item-image > img {
max-width: 100%;
}
.grid-item-layout-7 .grid-item-name {
font-size: 12px;
}
}
@media (min-width: 1200px) {
/* Layout 7 */
.grid-group-back, .grid-group-item {
width: 24%;
height: 140px;
margin-right: 1.3%;
}
}
/* Helper classes to remove margin depending on the screen size */
@media (max-width: 992px) {
.ggi-last-xs {
margin-right: 0px;
}
}
@media (min-width: 768px) and (max-width: 992px) {
.ggi-last-sm {
margin-right: 0px;
}
}
@media (min-width: 992px) and (max-width: 1200px) {
.ggi-last-md {
margin-right: 0px;
}
}
@media (min-width: 1200px) {
.ggi-last-lg {
margin-right: 0px;
}
}
/****************/
/* - List mode */
/****************/
/*********/

View File

@@ -580,10 +580,12 @@ footer{
top: 10px;
right: 10px;
}
.list-group-item:hover > .list-group-item-actions{
.list-group-item:hover > .list-group-item-actions,
.grid-group-item:hover > .grid-group-item-actions{
display: block;
}
.list-group-item .list-group-item-actions a:not(:first-child){
.list-group-item .list-group-item-actions a:not(:first-child),
.grid-group-item .grid-group-item-actions a:not(:first-child){
margin-left: 10px;
}
.list-group-item .keep-spinning{
@@ -592,17 +594,24 @@ footer{
-moz-animation: spin 1s linear infinite;
-ms-animation: spin 1s linear infinite;
}
.list-group.tree .list-group-item .list-group-item-description{
display: block;
margin-top: 3px;
font-size: 0.8em;
}
/* Secondary actions */
table .group-actions{
position: relative;
}
.list-group-item-actions a.glyphicon-menu-hamburger,
.grid-group-item-actions a.glyphicon-menu-hamburger,
table .group-actions a.glyphicon-menu-hamburger{
cursor: pointer;
text-decoration: none;
}
.list-group-item-actions .item-action-wrapper,
.grid-group-item-actions .item-action-wrapper,
table .group-actions .item-action-wrapper
{
display: none;
@@ -615,18 +624,22 @@ table .group-actions .item-action-wrapper
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);
}
.list-group-item-actions .item-action-wrapper .glyphicon,
.grid-group-item-actions .item-action-wrapper .glyphicon,
table .group-actions .item-action-wrapper .glyphicon{
margin-right: 0.6em;
}
.list-group-item-actions .item-action-wrapper.collapse.in,
.grid-group-item-actions .item-action-wrapper.collapse.in,
table .group-actions .item-action-wrapper.collapse.in{
display: block;
}
.list-group-item-actions .item-action-wrapper .panel-body > p,
.grid-group-item-actions .item-action-wrapper .panel-body > p,
table .group-actions .item-action-wrapper .panel-body > p{
white-space: nowrap;
}
.list-group-item-actions .item-action-wrapper .panel-body > p:last-child,
.grid-group-item-actions .item-action-wrapper .panel-body > p:last-child,
table .group-actions .item-action-wrapper .panel-body > p:last-child{
margin-bottom: 0px;
}
@@ -639,12 +652,220 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
}
/* Loader */
#brick_tree_overlay{
#brick_tree_overlay,
#brick_grid_overlay{
display: none;
padding: 8% 0px;
border-radius: 0px 0px 4px 4px;
font-size: 1em;
}
/****************/
/* - Grid mode */
/* Note: Some of the CSS is factorised in the "Tree mode" part */
/****************/
#brick_content_grid{
position: relative;
padding: 10px 10px 1px 10px;
}
.grid-group{
display: none;
}
/* Only the first level is showed by default */
.grid-group:first-child{
display: block;
}
.grid-group-back,
.grid-group-item{
position: relative;
height: 55px;
margin-bottom: 10px;
text-align: center;
color: $white;
}
.grid-group-back{
font-size: 25px;
}
.grid-item{
display: table;
width: 100%;
height: 100%;
overflow: hidden;
background-color: $combodo-dark-gray;
transition: background-color linear 0.3s;
}
.grid-item,
.grid-item:hover,
.grid-item:active,
.grid-item:focus,
.grid-item:visited{
color: $white;
text-decoration: none;
}
.grid-item:active{
background-color: $combodo-orange-darker;
}
.grid-item-image,
.grid-item-text{
display: table-cell;
text-align: center;
vertical-align: middle;
}
.grid-item-image > img{
max-width: 100%;
}
.grid-group-item > .grid-group-item-actions{
position: absolute;
top: 5px;
right: 5px;
}
.grid-group-item-actions > a{
color: $white;
text-decoration: none;
}
.grid-group-item-actions > a:hover,
.grid-group-item-actions > a:focus{
color: #EEEEEE;
}
.ggi-last-xs, .ggi-last-sm, .ggi-last-md, .ggi-last-lg{
margin-right: 0px;
}
@media (max-width: 768px) {
.grid-group-item > .grid-group-item-actions{
top: 12px;
right: 6px;
}
.grid-group-item > .grid-group-item-actions > .glyphicon{
margin-top: 5px;
}
.grid-group-item-actions > a{
font-size: 20px;
}
/* All layout */
.grid-item-image{
width: 55px;
padding: 10px;
}
.grid-item-image > img{
max-height: 30px;
}
.grid-item-name{
font-size: 14px;
}
.grid-item-description{
display: none;
}
/* Layout 2 */
.grid-item-layout-2 .grid-item-description{
display: block;
}
/* Layout 5/7 */
.grid-item-layout-5 .grid-item-name,
.grid-item-layout-7 .grid-item-name{
padding-right: 40px;
}
}
@media (min-width: 768px) {
.grid-group-back,
.grid-group-item{
display: inline-block;
width: 32%;
height: 120px;
margin-right: 1.95%; /* We don't put 2% to keep a margin in case of a bad browser rendering */
}
.grid-item{
padding: 10px;
}
.grid-item:hover,
.grid-item:focus{
background-color: $combodo-orange;
}
/* All layout */
.grid-item-name{
font-weight: 600;
font-size: 12px;
}
.grid-item-description{
overflow: hidden;
}
/* Layout 1 */
.grid-item-layout-1 .grid-item-name{
font-weight: inherit;
font-size: 14px;
}
/* Layout 7 */
.grid-item-layout-7 .grid-item-image{
display: none;
}
.grid-item-layout-3 .grid-item-description,
.grid-item-layout-7 .grid-item-description{
margin-top: 10px;
max-height: 40px;
font-size: 10px;
}
}
@media (min-width: 992px) {
.grid-item{
padding: 10px 15px;
}
.grid-group-back{
font-size: 40px;
}
/* Layout 7 */
.grid-item-layout-7 .grid-item-image{
display: table-cell;
width: 105px;
padding-left: 5px;
padding-right: 18px;
}
.grid-item-layout-7 .grid-item-image > img{
max-width: 100%;
}
.grid-item-layout-7 .grid-item-name{
font-size: 12px;
}
}
@media (min-width: 1200px) {
.grid-group-back,
.grid-group-item{
width: 24%;
height: 140px;
margin-right: 1.3%;
}
/* Layout 7 */
//.grid-item-layout-7 .grid-item-image{
// width: 100px;
// padding: 60px 15px;
//}
}
/* Helper classes to remove margin depending on the screen size */
@media (max-width: 992px) {
.ggi-last-xs{
margin-right: 0px;
}
}
@media (min-width: 768px) and (max-width: 992px) {
.ggi-last-sm{
margin-right: 0px;
}
}
@media (min-width: 992px) and (max-width: 1200px) {
.ggi-last-md{
margin-right: 0px;
}
}
@media (min-width: 1200px) {
.ggi-last-lg{
margin-right: 0px;
}
}
/****************/
/* - List mode */
/****************/

File diff suppressed because one or more lines are too long

View File

@@ -65,6 +65,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Brick:Portal:Browse:Name' => 'Просмотр элементов',
'Brick:Portal:Browse:Mode:List' => 'Список',
'Brick:Portal:Browse:Mode:Tree' => 'Дерево',
'Brick:Portal:Browse:Mode:Grid' => 'Tiles~~',
'Brick:Portal:Browse:Action:Drilldown' => 'Детализация',
'Brick:Portal:Browse:Action:View' => 'Подробно',
'Brick:Portal:Browse:Action:Edit' => 'Изменить',

View File

@@ -1051,12 +1051,18 @@
<level id="1">
<!-- Can be either a class tag with the class name or an oql tag with the query -->
<class>Service</class>
<!-- Attribute code of the above class that point to the upper level class -->
<!-- Attribute code of the above class [from the OQL] that point to the upper level class -->
<parent_att>servicefamily_id</parent_att>
<!-- Attribute code to use to display the object name, default is 'name'. -->
<!-- Attribute code of the above class [from the OQL] used to display the object name, default is 'name'. -->
<name_att/>
<!-- Description text from attribute of above class [from the OQL] -->
<!-- Attribute code of the above class [from the OQL] used to display in a tooltip when mouse is over the object -->
<tooltip_att>description</tooltip_att>
<!-- Attribute code of the above class [from the OQL] used to display a small text beside the object's name -->
<!-- Note: This is not used in "list" mode -->
<description_att/>
<!-- Attribute code of the above class [from the OQL] used to display a image beside the object's name -->
<!-- Note: This is used in "grid" mode only for now -->
<!--<image_att/>-->
<!-- Title of the level, will be display in lists and others browse modes -->
<title>Class:Service</title>
<!-- Optional tag to add attributes to the table by their code, can be specified for each level -->
@@ -1101,6 +1107,7 @@
<availables>
<mode id="list"/>
<mode id="tree"/>
<mode id="grid"/>
</availables>
<default>list</default>
</browse_modes>