mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-22 01:58:47 +02:00
Dashboard re-engineering
SVN:trunk[2782]
This commit is contained in:
@@ -34,15 +34,16 @@ abstract class Dashboard
|
||||
protected $oDOMNode;
|
||||
protected $sId;
|
||||
protected $aCells;
|
||||
protected $oMetaModel;
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
$this->sLayoutClass = null;
|
||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||
$this->aCells = array();
|
||||
$this->oDOMNode = null;
|
||||
$this->sId = $sId;
|
||||
}
|
||||
|
||||
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$this->aCells = array(); // reset the content of the dashboard
|
||||
@@ -50,60 +51,83 @@ abstract class Dashboard
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc->loadXML($sXml);
|
||||
restore_error_handler();
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
$oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0);
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
|
||||
$oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0);
|
||||
$this->sTitle = $oTitleNode->textContent;
|
||||
|
||||
$oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0);
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$iCellRank = 0;
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$aDashletList = array();
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
}
|
||||
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$sDashletClass = $oDomNode->getAttribute('xsi:type');
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank)
|
||||
{
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$oNewDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sId);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
||||
}
|
||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
||||
$aDashletList = array();
|
||||
foreach($aDashletOrder as $aItem)
|
||||
{
|
||||
$aDashletList[] = $aItem['dashlet'];
|
||||
}
|
||||
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
|
||||
}
|
||||
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
|
||||
foreach($aCellOrder as $aItem)
|
||||
{
|
||||
$this->aCells[] = $aItem['dashlets'];
|
||||
}
|
||||
|
||||
|
||||
$this->FromDOMDocument($oDoc);
|
||||
}
|
||||
|
||||
public function FromDOMDocument(DOMDocument $oDoc)
|
||||
{
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0))
|
||||
{
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||
}
|
||||
|
||||
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0))
|
||||
{
|
||||
$this->sTitle = $oTitleNode->textContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->sTitle = '';
|
||||
}
|
||||
|
||||
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0))
|
||||
{
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$iCellRank = 0;
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$aDashletList = array();
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
}
|
||||
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
||||
{
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$sDashletClass = $oDomNode->getAttribute('xsi:type');
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank)
|
||||
{
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
||||
}
|
||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
||||
$aDashletList = array();
|
||||
foreach($aDashletOrder as $aItem)
|
||||
{
|
||||
$aDashletList[] = $aItem['dashlet'];
|
||||
}
|
||||
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
|
||||
}
|
||||
}
|
||||
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
|
||||
foreach($aCellOrder as $aItem)
|
||||
{
|
||||
$this->aCells[] = $aItem['dashlets'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->aCells = array();
|
||||
}
|
||||
}
|
||||
|
||||
static function SortOnRank($aItem1, $aItem2)
|
||||
{
|
||||
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
|
||||
@@ -133,14 +157,24 @@ abstract class Dashboard
|
||||
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
$oDoc->appendChild($oMainNode);
|
||||
|
||||
$this->ToDOMNode($oMainNode);
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
public function ToDOMNode($oDefinition)
|
||||
{
|
||||
$oDoc = $oDefinition->ownerDocument;
|
||||
|
||||
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
|
||||
$oMainNode->appendChild($oNode);
|
||||
$oDefinition->appendChild($oNode);
|
||||
|
||||
$oNode = $oDoc->createElement('title', $this->sTitle);
|
||||
$oMainNode->appendChild($oNode);
|
||||
$oDefinition->appendChild($oNode);
|
||||
|
||||
$oCellsNode = $oDoc->createElement('cells');
|
||||
$oMainNode->appendChild($oCellsNode);
|
||||
$oDefinition->appendChild($oCellsNode);
|
||||
|
||||
$iCellRank = 0;
|
||||
foreach ($this->aCells as $aCell)
|
||||
@@ -167,11 +201,9 @@ abstract class Dashboard
|
||||
$oDashlet->ToDOMNode($oNode);
|
||||
}
|
||||
}
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
|
||||
public function FromParams($aParams)
|
||||
{
|
||||
$this->sLayoutClass = $aParams['layout_class'];
|
||||
@@ -184,7 +216,7 @@ abstract class Dashboard
|
||||
{
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
$oNewDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sId);
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
|
||||
$oForm = $oNewDashlet->GetForm();
|
||||
$oForm->SetParamsContainer($sId);
|
||||
@@ -197,7 +229,7 @@ abstract class Dashboard
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function Save()
|
||||
{
|
||||
|
||||
@@ -267,24 +299,43 @@ abstract class Dashboard
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oForm->AddField($oField);
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#select_layout').buttonset();
|
||||
$('#select_layout input').click( function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$(':itop-dashboard').dashboard('option', {layout_class: sLayoutClass});
|
||||
} );
|
||||
$('#row_attr_dashboard_title').property_field('option', {parent_selector: ':itop-dashboard', auto_apply: false, 'do_apply': function() {
|
||||
var sTitle = $('#attr_dashboard_title').val();
|
||||
$(':itop-dashboard').dashboard('option', {title: sTitle});
|
||||
return true;
|
||||
}
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var oDashlet = ui.draggable.data('itopDashlet');
|
||||
oDashlet._remove_dashlet();
|
||||
},
|
||||
});
|
||||
|
||||
$('#event_bus').bind('dashlet-selected', function(event, data){
|
||||
var sDashletId = data.dashlet_id;
|
||||
var sPropId = 'dashlet_properties_'+sDashletId;
|
||||
$('.dashlet_properties').each(function() {
|
||||
var sId = $(this).attr('id');
|
||||
var bShow = (sId == sPropId);
|
||||
if (bShow)
|
||||
{
|
||||
$(this).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
EOF
|
||||
);
|
||||
@@ -319,7 +370,6 @@ EOF
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
$oPage->add_ready_script("$('.layout_cell').droppable({accept:'.dashlet_icon', hoverClass:'dragHover'});");
|
||||
}
|
||||
|
||||
public function RenderDashletsProperties($oPage)
|
||||
@@ -339,7 +389,7 @@ EOF
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
@@ -368,11 +418,12 @@ EOF
|
||||
class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
protected $bCustomized;
|
||||
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->bCustomized = false;
|
||||
$this->oMetaModel = new ModelReflectionRuntime();
|
||||
}
|
||||
|
||||
public function SetCustomFlag($bCustomized)
|
||||
@@ -482,7 +533,28 @@ EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
{
|
||||
parent::RenderProperties($oPage);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#select_layout input').click( function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
|
||||
} );
|
||||
$('#row_attr_dashboard_title').property_field('option', {parent_selector: '.itop-dashboard', auto_apply: false, 'do_apply': function() {
|
||||
var sTitle = $('#attr_dashboard_title').val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {title: sTitle});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function RenderEditor($oPage)
|
||||
{
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
@@ -521,7 +593,7 @@ $('#dashboard_editor').dialog({
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oDashboard = $(':itop-dashboard').data('itopDashboard');
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
if (oDashboard.is_dirty())
|
||||
{
|
||||
if (!confirm('$sAutoApplyConfirmationMessage'))
|
||||
@@ -537,7 +609,7 @@ $('#dashboard_editor').dialog({
|
||||
oDashboard.save();
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
var oDashboard = $(':itop-dashboard').data('itopDashboard');
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
if (oDashboard.is_modified())
|
||||
{
|
||||
if (!confirm('$sCancelConfirmationMessage'))
|
||||
@@ -553,40 +625,13 @@ $('#dashboard_editor').dialog({
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
|
||||
$('#dashboard_editor .ui-layout-center').dashboard({
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var oDashlet = ui.draggable;
|
||||
oDashlet.remove();
|
||||
},
|
||||
});
|
||||
|
||||
$('#event_bus').bind('dashlet-selected', function(event, data){
|
||||
var sDashletId = data.dashlet_id;
|
||||
var sPropId = 'dashlet_properties_'+sDashletId;
|
||||
$('.dashlet_properties').each(function() {
|
||||
var sId = $(this).attr('id');
|
||||
var bShow = (sId == sPropId);
|
||||
if (bShow)
|
||||
{
|
||||
$(this).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
|
||||
$('#dashboard_editor').layout({
|
||||
east: {
|
||||
@@ -607,7 +652,7 @@ $('#dashboard_editor').layout({
|
||||
window.onbeforeunload = function() {
|
||||
if (!window.bLeavingOnUserAction)
|
||||
{
|
||||
var oDashboard = $(':itop-dashboard').data('itopDashboard');
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
if (oDashboard)
|
||||
{
|
||||
if (oDashboard.is_dirty())
|
||||
@@ -688,7 +733,7 @@ EOF
|
||||
foreach($aDashlets as $sDashletClass => $aDashletInfo)
|
||||
{
|
||||
$oSubForm = new DesignerForm();
|
||||
$oDashlet = new $sDashletClass(new ModelReflectionRuntime(), 0);
|
||||
$oDashlet = new $sDashletClass($this->oMetaModel, 0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
||||
|
||||
@@ -107,14 +107,16 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$oPage->add('<table style="width:100%"><tbody>');
|
||||
$iCellIdx = 0;
|
||||
$fColSize = 100 / $this->iNbCols;
|
||||
$sStyle = $bEditMode ? 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode"' : 'style="width: '.$fColSize.'%;" class="dashboard"';
|
||||
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
|
||||
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
|
||||
$iNbRows = ceil(count($aCells) / $this->iNbCols);
|
||||
for($iRows = 0; $iRows < $iNbRows; $iRows++)
|
||||
{
|
||||
$oPage->add('<tr>');
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$oPage->add("<td $sStyle>");
|
||||
$sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass;
|
||||
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-cell-index=\"$iCellIdx\">");
|
||||
if (array_key_exists($iCellIdx, $aCells))
|
||||
{
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
@@ -144,7 +146,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
}
|
||||
if ($bEditMode) // Add one row for extensibility
|
||||
{
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension"';
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
|
||||
$oPage->add('<tr>');
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
|
||||
@@ -87,11 +87,10 @@ abstract class Dashlet
|
||||
{
|
||||
foreach ($this->aProperties as $sProperty => $value)
|
||||
{
|
||||
$this->oDOMNode = $oDOMNode->getElementsByTagName($sProperty)->item(0);
|
||||
if ($this->oDOMNode != null)
|
||||
$oPropNode = $oDOMNode->getElementsByTagName($sProperty)->item(0);
|
||||
if ($oPropNode != null)
|
||||
{
|
||||
$newvalue = $this->Str2Prop($sProperty, $this->oDOMNode->textContent);
|
||||
$this->aProperties[$sProperty] = $newvalue;
|
||||
$this->aProperties[$sProperty] = $this->PropertyFromDOMNode($oPropNode, $sProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,12 +99,26 @@ abstract class Dashlet
|
||||
{
|
||||
foreach ($this->aProperties as $sProperty => $value)
|
||||
{
|
||||
$sXmlValue = $this->Prop2Str($value);
|
||||
$oPropNode = $oDOMNode->ownerDocument->createElement($sProperty, $sXmlValue);
|
||||
$oPropNode = $oDOMNode->ownerDocument->createElement($sProperty);
|
||||
$oDOMNode->appendChild($oPropNode);
|
||||
$this->PropertyToDOMNode($oPropNode, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function PropertyFromDOMNode($oDOMNode, $sProperty)
|
||||
{
|
||||
$res = $this->Str2Prop($sProperty, $oDOMNode->textContent);
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function PropertyToDOMNode($oDOMNode, $sProperty, $value)
|
||||
{
|
||||
$sXmlValue = $this->Prop2Str($value);
|
||||
$oTextNode = $oDOMNode->ownerDocument->createTextNode($sXmlValue);
|
||||
$oDOMNode->appendChild($oTextNode);
|
||||
}
|
||||
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$oDomDoc = new DOMDocument('1.0', 'UTF-8');
|
||||
@@ -139,10 +152,24 @@ abstract class Dashlet
|
||||
$oPage->add('<div class="'.$sCSSClasses.'">');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->aCSSClasses as $sCSSClass)
|
||||
{
|
||||
$oPage->add_ready_script("$('#dashlet_".$sId."').addClass('$sCSSClass');");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime')
|
||||
{
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->RenderNoData($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch(UnknownClassOqlException $e)
|
||||
{
|
||||
@@ -195,6 +222,12 @@ EOF
|
||||
}
|
||||
|
||||
abstract public function Render($oPage, $bEditMode = false, $aExtraParams = array());
|
||||
|
||||
/* Rendering without the real data */
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
|
||||
abstract public function GetPropertiesFields(DesignerForm $oForm);
|
||||
|
||||
@@ -312,7 +345,7 @@ class DashletPlainText extends Dashlet
|
||||
$sText = htmlentities($this->aProperties['text'], ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$sId = 'plaintext_'.($bEditMode? 'edit_' : '').$this->sId;
|
||||
$oPage->add('<div id='.$sId.'" class="dashlet-content">'.$sText.'</div>');
|
||||
$oPage->add('<div id="'.$sId.'" class="dashlet-content">'.$sText.'</div>');
|
||||
}
|
||||
|
||||
public function GetPropertiesFields(DesignerForm $oForm)
|
||||
@@ -365,6 +398,27 @@ class DashletObjectList extends Dashlet
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sQuery = $this->aProperties['query'];
|
||||
$sShowMenu = $this->aProperties['menu'] ? '1' : '0';
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$sHtmlTitle = htmlentities($this->oModelReflection->DictString($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
|
||||
}
|
||||
$oQuery = $this->oModelReflection->GetQuery($sQuery);
|
||||
$sClass = $oQuery->GetClass();
|
||||
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
|
||||
$oPage->p(Dict::S('UI:NoObjectToDisplay'));
|
||||
$oPage->p('<a href="">'.Dict::Format('UI:ClickToCreateNew', $this->oModelReflection->GetName($sClass)).'</a>');
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function GetPropertiesFields(DesignerForm $oForm)
|
||||
{
|
||||
$oField = new DesignerTextField('title', Dict::S('UI:DashletObjectList:Prop-Title'), $this->aProperties['title']);
|
||||
@@ -531,10 +585,74 @@ abstract class DashletGroupBy extends Dashlet
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sQuery = $this->aProperties['query'];
|
||||
$sGroupBy = $this->aProperties['group_by'];
|
||||
$sStyle = $this->aProperties['style'];
|
||||
|
||||
$oQuery = $this->oModelReflection->GetQuery($sQuery);
|
||||
$sClass = $oQuery->GetClass();
|
||||
|
||||
|
||||
$aDisplayValues = array();
|
||||
$sAttLabel = '';
|
||||
if ($this->oModelReflection->IsValidAttCode($sClass, $sGroupBy))
|
||||
{
|
||||
$sAttLabel = $this->oModelReflection->GetLabel($sClass, $sGroupBy);
|
||||
$aAllowed = $this->oModelReflection->GetAllowedValues_att($sClass, $sGroupBy);
|
||||
if ($aAllowed) // null for non enums
|
||||
{
|
||||
$iTotal = 0;
|
||||
foreach ($aAllowed as $sValue => $sValueLabel)
|
||||
{
|
||||
$iCount = (int) rand(2, 100);
|
||||
$iTotal += $iCount;
|
||||
$aDisplayValues[] = array(
|
||||
'label' => $sValueLabel,
|
||||
'count' => $iCount
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">Sorry, grouping by date/time cannot be viewed in the designer</div>');
|
||||
}
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$oPage->add('<div id="'.$sBlockId.'" class="display_block">');
|
||||
$oPage->add('<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>');
|
||||
$oPage->add('<table class="listResults">');
|
||||
$oPage->add('<thead>');
|
||||
$oPage->add('<tr>');
|
||||
$oPage->add('<th class="header" title="">'.$sAttLabel.'</th>');
|
||||
$oPage->add('<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>');
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('</thead>');
|
||||
$oPage->add('<tbody>');
|
||||
foreach($aDisplayValues as $aDisplayData)
|
||||
{
|
||||
$oPage->add('<tr class="even">');
|
||||
$oPage->add('<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>');
|
||||
$oPage->add('<td class=""><a href="">'.$aDisplayData['count'].'</a></td>');
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
$oPage->add('</tbody>');
|
||||
$oPage->add('</table>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
protected function GetGroupByOptions($sOql)
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$sClass = $oSearch->GetClass();
|
||||
$oQuery = $this->oModelReflection->GetQuery($sOql);
|
||||
$sClass = $oQuery->GetClass();
|
||||
$aGroupBy = array();
|
||||
foreach($this->oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType)
|
||||
{
|
||||
@@ -604,11 +722,11 @@ abstract class DashletGroupBy extends Dashlet
|
||||
try
|
||||
{
|
||||
$sCurrQuery = $aValues['query'];
|
||||
$oCurrSearch = DBObjectSearch::FromOQL($sCurrQuery);
|
||||
$oCurrSearch = $this->oModelReflection->GetQuery($sCurrQuery);
|
||||
$sCurrClass = $oCurrSearch->GetClass();
|
||||
|
||||
$sPrevQuery = $this->aProperties['query'];
|
||||
$oPrevSearch = DBObjectSearch::FromOQL($sPrevQuery);
|
||||
$oPrevSearch = $this->oModelReflection->GetQuery($sPrevQuery);
|
||||
$sPrevClass = $oPrevSearch->GetClass();
|
||||
|
||||
if ($sCurrClass != $sPrevClass)
|
||||
@@ -631,15 +749,15 @@ abstract class DashletGroupBy extends Dashlet
|
||||
{
|
||||
// Style changed, mutate to the specified type of chart
|
||||
case 'pie':
|
||||
$oDashlet = new DashletGroupByPie($this->sId);
|
||||
$oDashlet = new DashletGroupByPie($this->oModelReflection, $this->sId);
|
||||
break;
|
||||
|
||||
case 'bars':
|
||||
$oDashlet = new DashletGroupByBars($this->sId);
|
||||
$oDashlet = new DashletGroupByBars($this->oModelReflection, $this->sId);
|
||||
break;
|
||||
|
||||
case 'table':
|
||||
$oDashlet = new DashletGroupByTable($this->sId);
|
||||
$oDashlet = new DashletGroupByTable($this->oModelReflection, $this->sId);
|
||||
break;
|
||||
}
|
||||
$oDashlet->FromParams($aValues);
|
||||
@@ -756,9 +874,8 @@ class DashletHeaderStatic extends Dashlet
|
||||
{
|
||||
parent::__construct($oModelReflection, $sId);
|
||||
$this->aProperties['title'] = Dict::S('UI:DashletHeaderStatic:Prop-Title:Default');
|
||||
$sIcon = $this->oModelReflection->GetClassIcon('Contact', false);
|
||||
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIcon);
|
||||
$this->aProperties['icon'] = $sIcon;
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$this->aProperties['icon'] = $oIconSelect->GetDefaultValue('Contact');
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
@@ -766,13 +883,14 @@ class DashletHeaderStatic extends Dashlet
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sIcon = $this->aProperties['icon'];
|
||||
|
||||
$sIconPath = utils::GetAbsoluteUrlModulesRoot().$sIcon;
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
$oPage->add('<h1>'.Dict::S($sTitle).'</h1>');
|
||||
$oPage->add('<h1>'.$this->oModelReflection->DictString($sTitle).'</h1>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
@@ -783,18 +901,36 @@ class DashletHeaderStatic extends Dashlet
|
||||
$oField = new DesignerTextField('title', Dict::S('UI:DashletHeaderStatic:Prop-Title'), $this->aProperties['title']);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerIconSelectionField('icon', Dict::S('UI:DashletHeaderStatic:Prop-Icon'), $this->aProperties['icon']);
|
||||
$aAllIcons = self::FindIcons(APPROOT.'env-'.utils::GetCurrentEnvironment());
|
||||
ksort($aAllIcons);
|
||||
$aValues = array();
|
||||
foreach($aAllIcons as $sFilePath)
|
||||
{
|
||||
$aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath);
|
||||
}
|
||||
$oField->SetAllowedValues($aValues);
|
||||
$oField = $this->oModelReflection->GetIconSelectionField('icon', Dict::S('UI:DashletHeaderStatic:Prop-Icon'), $this->aProperties['icon']);
|
||||
$oForm->AddField($oField);
|
||||
}
|
||||
|
||||
protected function PropertyFromDOMNode($oDOMNode, $sProperty)
|
||||
{
|
||||
if ($sProperty == 'icon')
|
||||
{
|
||||
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
return $oIconField->ValueFromDOMNode($oDOMNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::PropertyFromDOMNode($oDOMNode, $sProperty);
|
||||
}
|
||||
}
|
||||
|
||||
protected function PropertyToDOMNode($oDOMNode, $sProperty, $value)
|
||||
{
|
||||
if ($sProperty == 'icon')
|
||||
{
|
||||
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$oIconField->ValueToDOMNode($oDOMNode, $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::PropertyToDOMNode($oDOMNode, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
@@ -803,30 +939,6 @@ class DashletHeaderStatic extends Dashlet
|
||||
'description' => Dict::S('UI:DashletHeaderStatic:Description'),
|
||||
);
|
||||
}
|
||||
|
||||
static public function FindIcons($sBaseDir, $sDir = '')
|
||||
{
|
||||
$aResult = array();
|
||||
// Populate automatically the list of icon files
|
||||
if ($hDir = @opendir($sBaseDir.'/'.$sDir))
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
|
||||
{
|
||||
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
|
||||
$aResult = array_merge($aResult, self::FindIcons($sBaseDir, $sDirSubPath));
|
||||
}
|
||||
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
|
||||
{
|
||||
$aResult[$sFile.'_'.$sDir] = $sDir.'/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -836,28 +948,27 @@ class DashletHeaderDynamic extends Dashlet
|
||||
{
|
||||
parent::__construct($oModelReflection, $sId);
|
||||
$this->aProperties['title'] = Dict::S('UI:DashletHeaderDynamic:Prop-Title:Default');
|
||||
$sIcon = $this->oModelReflection->GetClassIcon('Contact', false);
|
||||
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIcon);
|
||||
$this->aProperties['icon'] = $sIcon;
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$this->aProperties['icon'] = $oIconSelect->GetDefaultValue('Contact');
|
||||
$this->aProperties['subtitle'] = Dict::S('UI:DashletHeaderDynamic:Prop-Subtitle:Default');
|
||||
$this->aProperties['query'] = 'SELECT Contact';
|
||||
$this->aProperties['group_by'] = 'status';
|
||||
$this->aProperties['values'] = array('active', 'inactive');
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
|
||||
protected function GetValues()
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sIcon = $this->aProperties['icon'];
|
||||
$sSubtitle = $this->aProperties['subtitle'];
|
||||
$sQuery = $this->aProperties['query'];
|
||||
$sGroupBy = $this->aProperties['group_by'];
|
||||
$aValues = $this->aProperties['values'];
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery);
|
||||
$sClass = $oFilter->GetClass();
|
||||
if (empty($aValues))
|
||||
{
|
||||
$aValues = array();
|
||||
}
|
||||
|
||||
$sIconPath = utils::GetAbsoluteUrlModulesRoot().$sIcon;
|
||||
$oQuery = $this->oModelReflection->GetQuery($sQuery);
|
||||
$sClass = $oQuery->GetClass();
|
||||
|
||||
if ($this->oModelReflection->IsValidAttCode($sClass, $sGroupBy))
|
||||
{
|
||||
@@ -870,6 +981,21 @@ class DashletHeaderDynamic extends Dashlet
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sIcon = $this->aProperties['icon'];
|
||||
$sSubtitle = $this->aProperties['subtitle'];
|
||||
$sQuery = $this->aProperties['query'];
|
||||
$sGroupBy = $this->aProperties['group_by'];
|
||||
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
|
||||
|
||||
$aValues = $this->GetValues();
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
// Stats grouped by <group_by>
|
||||
@@ -897,6 +1023,7 @@ class DashletHeaderDynamic extends Dashlet
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery);
|
||||
$oBlock = new DisplayBlock($oFilter, 'summary');
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
@@ -905,20 +1032,78 @@ class DashletHeaderDynamic extends Dashlet
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sIcon = $this->aProperties['icon'];
|
||||
$sSubtitle = $this->aProperties['subtitle'];
|
||||
$sQuery = $this->aProperties['query'];
|
||||
$sGroupBy = $this->aProperties['group_by'];
|
||||
$aValues = $this->aProperties['values'];
|
||||
|
||||
$oQuery = $this->oModelReflection->GetQuery($sQuery);
|
||||
$sClass = $oQuery->GetClass();
|
||||
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$iTotal = 0;
|
||||
$aValues = $this->GetValues();
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
// Stats grouped by <group_by>
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple stats
|
||||
}
|
||||
|
||||
$oPage->add('<div class="display_block" id="'.$sBlockId.'">');
|
||||
$oPage->add('<div class="summary-details">');
|
||||
$oPage->add('<table><tbody>');
|
||||
$oPage->add('<tr>');
|
||||
foreach ($aValues as $sValue)
|
||||
{
|
||||
$sValueLabel = $this->oModelReflection->GetValueLabel($sClass, $sGroupBy, $sValue);
|
||||
$oPage->add(' <th>'.$sValueLabel.'</th>');
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('<tr>');
|
||||
foreach ($aValues as $sValue)
|
||||
{
|
||||
$iCount = (int) rand(2, 100);
|
||||
$iTotal += $iCount;
|
||||
$oPage->add(' <td>'.$iCount.'</td>');
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('</tbody></table>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sTitle = $this->oModelReflection->DictString($sTitle);
|
||||
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
|
||||
// $sSubtitle = "original: $sSubtitle, S:".$this->oModelReflection->DictString($sSubtitle).", Format: '".$this->oModelReflection->DictFormat($sSubtitle, $iTotal)."'";
|
||||
|
||||
$oPage->add('<h1>'.$sTitle.'</h1>');
|
||||
$oPage->add('<a href="" class="summary">'.$sSubtitle.'</a>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function GetPropertiesFields(DesignerForm $oForm)
|
||||
{
|
||||
$oField = new DesignerTextField('title', Dict::S('UI:DashletHeaderDynamic:Prop-Title'), $this->aProperties['title']);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerIconSelectionField('icon', Dict::S('UI:DashletHeaderDynamic:Prop-Icon'), $this->aProperties['icon']);
|
||||
$aAllIcons = DashletHeaderStatic::FindIcons(APPROOT.'env-'.utils::GetCurrentEnvironment());
|
||||
ksort($aAllIcons);
|
||||
$aValues = array();
|
||||
foreach($aAllIcons as $sFilePath)
|
||||
{
|
||||
$aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath);
|
||||
}
|
||||
$oField->SetAllowedValues($aValues);
|
||||
$oField = $this->oModelReflection->GetIconSelectionField('icon', Dict::S('UI:DashletHeaderDynamic:Prop-Icon'), $this->aProperties['icon']);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerTextField('subtitle', Dict::S('UI:DashletHeaderDynamic:Prop-Subtitle'), $this->aProperties['subtitle']);
|
||||
@@ -931,8 +1116,8 @@ class DashletHeaderDynamic extends Dashlet
|
||||
try
|
||||
{
|
||||
// Group by field: build the list of possible values (attribute codes + ...)
|
||||
$oSearch = DBObjectSearch::FromOQL($this->aProperties['query']);
|
||||
$sClass = $oSearch->GetClass();
|
||||
$oQuery = $this->oModelReflection->GetQuery($this->aProperties['query']);
|
||||
$sClass = $oQuery->GetClass();
|
||||
$aGroupBy = array();
|
||||
foreach($this->oModelReflection->ListAttributes($sClass, 'AttributeEnum,AttributeFinalClass') as $sAttCode => $sAttType)
|
||||
{
|
||||
@@ -975,11 +1160,11 @@ class DashletHeaderDynamic extends Dashlet
|
||||
try
|
||||
{
|
||||
$sCurrQuery = $aValues['query'];
|
||||
$oCurrSearch = DBObjectSearch::FromOQL($sCurrQuery);
|
||||
$oCurrSearch = $this->oModelReflection->GetQuery($sCurrQuery);
|
||||
$sCurrClass = $oCurrSearch->GetClass();
|
||||
|
||||
$sPrevQuery = $this->aProperties['query'];
|
||||
$oPrevSearch = DBObjectSearch::FromOQL($sPrevQuery);
|
||||
$oPrevSearch = $this->oModelReflection->GetQuery($sPrevQuery);
|
||||
$sPrevClass = $oPrevSearch->GetClass();
|
||||
|
||||
if ($sCurrClass != $sPrevClass)
|
||||
@@ -1003,6 +1188,32 @@ class DashletHeaderDynamic extends Dashlet
|
||||
return parent::Update($aValues, $aUpdatedFields);
|
||||
}
|
||||
|
||||
protected function PropertyFromDOMNode($oDOMNode, $sProperty)
|
||||
{
|
||||
if ($sProperty == 'icon')
|
||||
{
|
||||
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
return $oIconField->ValueFromDOMNode($oDOMNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::PropertyFromDOMNode($oDOMNode, $sProperty);
|
||||
}
|
||||
}
|
||||
|
||||
protected function PropertyToDOMNode($oDOMNode, $sProperty, $value)
|
||||
{
|
||||
if ($sProperty == 'icon')
|
||||
{
|
||||
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$oIconField->ValueToDOMNode($oDOMNode, $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::PropertyToDOMNode($oDOMNode, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
@@ -1023,7 +1234,7 @@ class DashletBadge extends Dashlet
|
||||
$this->aCSSClasses[] = 'dashlet-inline';
|
||||
$this->aCSSClasses[] = 'dashlet-badge';
|
||||
}
|
||||
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sClass = $this->aProperties['class'];
|
||||
@@ -1039,52 +1250,63 @@ class DashletBadge extends Dashlet
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
|
||||
$oPage->add('</div>');
|
||||
if ($bEditMode)
|
||||
{
|
||||
// Since the container div is not rendered the same way in edit mode, add the 'inline' style to it
|
||||
$oPage->add_ready_script("$('#dashlet_".$this->sId."').addClass('dashlet-inline');");
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sClass = $this->aProperties['class'];
|
||||
|
||||
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
|
||||
$sClassLabel = $this->oModelReflection->GetName($sClass);
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
|
||||
$oPage->add('<p>');
|
||||
$oPage->add(' <a class="actions" href=""><img src="'.$sIconUrl.'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>');
|
||||
$oPage->add('</p>');
|
||||
$oPage->add('<p>');
|
||||
$oPage->add(' <a href="">'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>');
|
||||
$oPage->add(' <br/>');
|
||||
$oPage->add(' <a href="http://localhost/trunk/pages/UI.php?operation=search_form&class=Server&c[menu]=WelcomeMenuPage">Search for Server objects</a>');
|
||||
$oPage->add('</p>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
static protected $aClassList = null;
|
||||
|
||||
public function GetPropertiesFields(DesignerForm $oForm)
|
||||
{
|
||||
|
||||
$oClassesSet = new ValueSetEnumClasses('bizmodel', array());
|
||||
$aClasses = $oClassesSet->GetValues(array());
|
||||
|
||||
$aLinkClasses = array();
|
||||
|
||||
foreach($this->oModelReflection->GetClasses('bizmodel') as $sClass)
|
||||
{
|
||||
foreach($this->oModelReflection->ListAttributes($sClass, 'AttributeLinkedSetIndirect') as $sAttCode => $sAttType)
|
||||
{
|
||||
$sLinkedClass = $this->oModelReflection->GetAttributeProperty($sClass, $sAttCode, 'linked_class');
|
||||
if ($sLinkedClass != null)
|
||||
{
|
||||
$aLinkClasses[$sLinkedClass] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$oField = new DesignerIconSelectionField('class', Dict::S('UI:DashletBadge:Prop-Class'), $this->aProperties['class']);
|
||||
ksort($aClasses);
|
||||
$aValues = array();
|
||||
foreach($aClasses as $sClass => $sClass)
|
||||
if (is_null(self::$aClassList))
|
||||
{
|
||||
if (!array_key_exists($sClass, $aLinkClasses))
|
||||
// Cache the ordered list of classes (ordered on the label)
|
||||
// (has a significant impact when editing a page with lots of badges)
|
||||
//
|
||||
$aClasses = array();
|
||||
foreach($this->oModelReflection->GetClasses('bizmodel', true /*exclude links*/) as $sClass)
|
||||
{
|
||||
$aClasses[$sClass] = $this->oModelReflection->GetName($sClass);
|
||||
}
|
||||
asort($aClasses);
|
||||
|
||||
self::$aClassList = array();
|
||||
foreach($aClasses as $sClass => $sLabel)
|
||||
{
|
||||
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
|
||||
$sIconFilePath = str_replace(utils::GetAbsoluteUrlAppRoot(), APPROOT, $sIconUrl);
|
||||
if (($sIconUrl == '') || !file_exists($sIconFilePath))
|
||||
if ($sIconUrl == '')
|
||||
{
|
||||
// The icon does not exist, leet's use a transparent one of the same size.
|
||||
// The icon does not exist, let's use a transparent one of the same size.
|
||||
$sIconUrl = utils::GetAbsoluteUrlAppRoot().'images/transparent_32_32.png';
|
||||
}
|
||||
$aValues[] = array('value' => $sClass, 'label' => $this->oModelReflection->GetName($sClass), 'icon' => $sIconUrl);
|
||||
self::$aClassList[] = array('value' => $sClass, 'label' => $sLabel, 'icon' => $sIconUrl);
|
||||
}
|
||||
}
|
||||
$oField->SetAllowedValues($aValues);
|
||||
|
||||
$oField = new DesignerIconSelectionField('class', Dict::S('UI:DashletBadge:Prop-Class'), $this->aProperties['class']);
|
||||
$oField->SetAllowedValues(self::$aClassList);
|
||||
|
||||
$oForm->AddField($oField);
|
||||
}
|
||||
|
||||
@@ -828,19 +828,26 @@ class DesignerHiddenField extends DesignerFormField
|
||||
|
||||
class DesignerIconSelectionField extends DesignerFormField
|
||||
{
|
||||
protected $sUploadUrl;
|
||||
protected $aAllowedValues;
|
||||
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
$this->bAutoApply = true;
|
||||
$this->sUploadUrl = null;
|
||||
}
|
||||
|
||||
public function SetAllowedValues($aAllowedValues)
|
||||
{
|
||||
$this->aAllowedValues = $aAllowedValues;
|
||||
}
|
||||
|
||||
|
||||
public function EnableUpload($sIconUploadUrl)
|
||||
{
|
||||
$this->sUploadUrl = $sIconUploadUrl;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
@@ -868,6 +875,71 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
class RunTimeIconSelectionField extends DesignerIconSelectionField
|
||||
{
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
|
||||
$aAllIcons = self::FindIconsOnDisk(APPROOT.'env-'.utils::GetCurrentEnvironment());
|
||||
ksort($aAllIcons);
|
||||
$aValues = array();
|
||||
foreach($aAllIcons as $sFilePath)
|
||||
{
|
||||
$aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath);
|
||||
}
|
||||
$this->SetAllowedValues($aValues);
|
||||
}
|
||||
|
||||
static protected function FindIconsOnDisk($sBaseDir, $sDir = '')
|
||||
{
|
||||
$aResult = array();
|
||||
// Populate automatically the list of icon files
|
||||
if ($hDir = @opendir($sBaseDir.'/'.$sDir))
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
|
||||
{
|
||||
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
|
||||
$aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath));
|
||||
}
|
||||
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
|
||||
{
|
||||
$aResult[$sFile.'_'.$sDir] = $sDir.'/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function ValueFromDOMNode($oDOMNode)
|
||||
{
|
||||
return $oDOMNode->textContent;
|
||||
}
|
||||
|
||||
public function ValueToDOMNode($oDOMNode, $value)
|
||||
{
|
||||
$oTextNode = $oDOMNode->ownerDocument->createTextNode($value);
|
||||
$oDOMNode->appendChild($oTextNode);
|
||||
}
|
||||
|
||||
public function MakeFileUrl($value)
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot().$value;
|
||||
}
|
||||
|
||||
public function GetDefaultValue($sClass = 'Contact')
|
||||
{
|
||||
$sIconPath = MetaModel::GetClassIcon($sClass, false);
|
||||
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIconPath);
|
||||
return $sIcon;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DesignerSortableField extends DesignerFormField
|
||||
{
|
||||
protected $aAllowedValues;
|
||||
|
||||
@@ -24,25 +24,59 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
interface ModelReflection
|
||||
abstract class ModelReflection
|
||||
{
|
||||
public function GetClassIcon($sClass, $bImgTag = true);
|
||||
public function IsValidAttCode($sClass, $sAttCode);
|
||||
public function GetName($sClass);
|
||||
public function GetLabel($sClass, $sAttCodeEx);
|
||||
public function ListAttributes($sClass, $sScope = null);
|
||||
public function GetAttributeProperty($sClass, $sAttCode, $sPropName, $default = null);
|
||||
public function GetAllowedValues_att($sClass, $sAttCode);
|
||||
public function HasChildrenClasses($sClass);
|
||||
public function GetClasses($sCategories = '');
|
||||
public function IsValidClass($sClass);
|
||||
public function IsSameFamilyBranch($sClassA, $sClassB);
|
||||
public function GetParentClass($sClass);
|
||||
public function GetFiltersList($sClass);
|
||||
public function IsValidFilterCode($sClass, $sFilterCode);
|
||||
abstract public function GetClassIcon($sClass, $bImgTag = true);
|
||||
abstract public function IsValidAttCode($sClass, $sAttCode);
|
||||
abstract public function GetName($sClass);
|
||||
abstract public function GetLabel($sClass, $sAttCodeEx);
|
||||
abstract public function GetValueLabel($sClass, $sAttCode, $sValue);
|
||||
abstract public function ListAttributes($sClass, $sScope = null);
|
||||
abstract public function GetAttributeProperty($sClass, $sAttCode, $sPropName, $default = null);
|
||||
abstract public function GetAllowedValues_att($sClass, $sAttCode);
|
||||
abstract public function HasChildrenClasses($sClass);
|
||||
abstract public function GetClasses($sCategories = '', $bExcludeLinks = false);
|
||||
abstract public function IsValidClass($sClass);
|
||||
abstract public function IsSameFamilyBranch($sClassA, $sClassB);
|
||||
abstract public function GetParentClass($sClass);
|
||||
abstract public function GetFiltersList($sClass);
|
||||
abstract public function IsValidFilterCode($sClass, $sFilterCode);
|
||||
|
||||
abstract public function GetQuery($sOQL);
|
||||
|
||||
abstract public function DictString($sStringCode, $sDefault = null, $bUserLanguageOnly = false);
|
||||
|
||||
public function DictFormat($sFormatCode /*, ... arguments ....*/)
|
||||
{
|
||||
$sLocalizedFormat = $this->DictString($sFormatCode);
|
||||
$aArguments = func_get_args();
|
||||
array_shift($aArguments);
|
||||
|
||||
if ($sLocalizedFormat == $sFormatCode)
|
||||
{
|
||||
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
|
||||
return $sFormatCode.' - '.implode(', ', $aArguments);
|
||||
}
|
||||
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
}
|
||||
|
||||
abstract public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '');
|
||||
}
|
||||
|
||||
class ModelReflectionRuntime implements ModelReflection
|
||||
abstract class QueryReflection
|
||||
{
|
||||
/**
|
||||
* Throws an exception in case of an invalid syntax
|
||||
*/
|
||||
abstract public function __construct($sOQL);
|
||||
|
||||
abstract public function GetClass();
|
||||
abstract public function GetClassAlias();
|
||||
}
|
||||
|
||||
|
||||
class ModelReflectionRuntime extends ModelReflection
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
@@ -68,6 +102,12 @@ class ModelReflectionRuntime implements ModelReflection
|
||||
return MetaModel::GetLabel($sClass, $sAttCodeEx);
|
||||
}
|
||||
|
||||
public function GetValueLabel($sClass, $sAttCode, $sValue)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
return $oAttDef->GetValueLabel($sValue);
|
||||
}
|
||||
|
||||
public function ListAttributes($sClass, $sScope = null)
|
||||
{
|
||||
$aScope = null;
|
||||
@@ -133,9 +173,26 @@ class ModelReflectionRuntime implements ModelReflection
|
||||
return MetaModel::HasChildrenClasses($sClass);
|
||||
}
|
||||
|
||||
public function GetClasses($sCategories = '')
|
||||
public function GetClasses($sCategories = '', $bExcludeLinks = false)
|
||||
{
|
||||
return MetaModel::GetClasses($sCategories);
|
||||
$aClasses = MetaModel::GetClasses($sCategories);
|
||||
if ($bExcludeLinks)
|
||||
{
|
||||
$aExcluded = ProfilesConfig::GetLinkClasses(); // table computed at compile time
|
||||
$aRes = array();
|
||||
foreach ($aClasses as $sClass)
|
||||
{
|
||||
if (!array_key_exists($sClass, $aExcluded))
|
||||
{
|
||||
$aRes[] = $sClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRes = $aClasses;
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function IsValidClass($sClass)
|
||||
@@ -162,4 +219,43 @@ class ModelReflectionRuntime implements ModelReflection
|
||||
{
|
||||
return MetaModel::IsValidFilterCode($sClass, $sFilterCode);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetQuery($sOQL)
|
||||
{
|
||||
return new QueryReflectionRuntime($sOQL);
|
||||
}
|
||||
|
||||
public function DictString($sStringCode, $sDefault = null, $bUserLanguageOnly = false)
|
||||
{
|
||||
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
}
|
||||
|
||||
public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
return new RunTimeIconSelectionField($sCode, $sLabel, $defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class QueryReflectionRuntime extends QueryReflection
|
||||
{
|
||||
protected $oFilter;
|
||||
|
||||
/**
|
||||
* throws an exception in case of a wrong syntax
|
||||
*/
|
||||
public function __construct($sOQL)
|
||||
{
|
||||
$this->oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
}
|
||||
|
||||
public function GetClass()
|
||||
{
|
||||
return $this->oFilter->GetClass();
|
||||
}
|
||||
|
||||
public function GetClassAlias()
|
||||
{
|
||||
return $this->oFilter->GetClassAlias();
|
||||
}
|
||||
}
|
||||
|
||||
271
js/dashboard.js
271
js/dashboard.js
@@ -1,4 +1,9 @@
|
||||
// jQuery UI style "widget" for editing an iTop "dashboard"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// dashboard
|
||||
//
|
||||
$(function()
|
||||
{
|
||||
// the widget definition, where "itop" is the namespace,
|
||||
@@ -25,23 +30,18 @@ $(function()
|
||||
|
||||
this.element
|
||||
.addClass('itop-dashboard')
|
||||
.bind('mark_as_modified.itop-dashboard', function(){me.mark_as_modified();} );
|
||||
.bind('add_dashlet.itop_dashboard', function(event, oParams){
|
||||
me.add_dashlet(oParams);
|
||||
});
|
||||
|
||||
this.ajax_div = $('<div></div>').appendTo(this.element);
|
||||
this.ajax_div = $('<div></div>');
|
||||
this.element.after(this.ajax_div);
|
||||
this._make_draggable();
|
||||
this.bModified = false;
|
||||
|
||||
},
|
||||
|
||||
// called when created, and later when changing options
|
||||
_refresh: function()
|
||||
{
|
||||
var oParams = this._get_state(this.options.render_parameters);
|
||||
var me = this;
|
||||
$.post(this.options.render_to, oParams, function(data){
|
||||
me.element.html(data);
|
||||
me._make_draggable();
|
||||
});
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
@@ -58,7 +58,6 @@ $(function()
|
||||
{
|
||||
// in 1.9 would use _superApply
|
||||
this._superApply(arguments);
|
||||
this._refresh();
|
||||
},
|
||||
// _setOption is called for each individual option that is changing
|
||||
_setOption: function( key, value )
|
||||
@@ -96,6 +95,170 @@ $(function()
|
||||
|
||||
return oState;
|
||||
},
|
||||
_get_new_id: function()
|
||||
{
|
||||
var iMaxId = 0;
|
||||
this.element.find(':itop-dashlet').each(function() {
|
||||
var oDashlet = $(this).data('itopDashlet');
|
||||
if(oDashlet)
|
||||
{
|
||||
var oDashletParams = oDashlet.get_params();
|
||||
var id = parseInt(oDashletParams.dashlet_id, 10);
|
||||
if (id > iMaxId) iMaxId = id;
|
||||
}
|
||||
});
|
||||
return 1 + iMaxId;
|
||||
},
|
||||
_make_draggable: function()
|
||||
{
|
||||
var me = this;
|
||||
this.element.find('.dashlet').draggable({
|
||||
revert: 'invalid', appendTo: 'body', zIndex: 9999,
|
||||
helper: function() {
|
||||
var oDragItem = $(this).dashlet('get_drag_icon');
|
||||
return oDragItem;
|
||||
},
|
||||
cursorAt: { top: 16, left: 16 }
|
||||
});
|
||||
this.element.find('table td').droppable({
|
||||
accept: '.dashlet,.dashlet_icon',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var bRefresh = $(this).hasClass('layout_extension');
|
||||
var oDropped = ui.draggable;
|
||||
if (oDropped.hasClass('dashlet'))
|
||||
{
|
||||
// moving around a dashlet
|
||||
oDropped.detach();
|
||||
oDropped.css({top: 0, left: 0});
|
||||
oDropped.appendTo($(this));
|
||||
|
||||
var oDashlet = ui.draggable.data('itopDashlet');
|
||||
me.on_dashlet_moved(oDashlet, $(this), bRefresh);
|
||||
}
|
||||
else
|
||||
{
|
||||
// inserting a new dashlet
|
||||
var sDashletClass = ui.draggable.attr('dashlet_class');
|
||||
$('.itop-dashboard').trigger('add_dashlet', {dashlet_class: sDashletClass, container: $(this), refresh: bRefresh });
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
add_dashlet: function(options)
|
||||
{
|
||||
// 1) Create empty divs for the dashlet and its properties
|
||||
//
|
||||
var sDashletId = this._get_new_id();
|
||||
var oDashlet = $('<div class="dashlet" id="dashlet_'+sDashletId+'"/>');
|
||||
oDashlet.appendTo(options.container);
|
||||
var oDashletProperties = $('<div class="dashlet_properties" id="dashlet_properties_'+sDashletId+'"/>');
|
||||
oDashletProperties.appendTo($('#dashlet_properties'));
|
||||
|
||||
// 2) Ajax call to fill the divs with default values
|
||||
// => in return, it must call add_dashlet_finalize
|
||||
//
|
||||
this.add_dashlet_ajax(options, sDashletId);
|
||||
},
|
||||
add_dashlet_finalize: function(options, sDashletId, sDashletClass)
|
||||
{
|
||||
$('#dashlet_'+sDashletId)
|
||||
.dashlet({dashlet_id: sDashletId, dashlet_class: sDashletClass})
|
||||
.dashlet('deselect_all')
|
||||
.dashlet('select')
|
||||
.draggable({
|
||||
revert: 'invalid', appendTo: 'body', zIndex: 9999,
|
||||
helper: function() {
|
||||
var oDragItem = $(this).dashlet('get_drag_icon');
|
||||
return oDragItem;
|
||||
},
|
||||
cursorAt: { top: 16, left: 16 }
|
||||
});
|
||||
if (options.refresh)
|
||||
{
|
||||
this._refresh();
|
||||
}
|
||||
},
|
||||
on_dashlet_moved: function(oDashlet, oReceiver, bRefresh)
|
||||
{
|
||||
if (bRefresh)
|
||||
{
|
||||
// The layout was extended... refresh the whole dashboard
|
||||
this._refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// runtimedashboard (extends dashboard)
|
||||
//
|
||||
$(function()
|
||||
{
|
||||
// the widget definition, where "itop" is the namespace,
|
||||
// "dashboard" the widget name
|
||||
$.widget( "itop.runtimedashboard", $.itop.dashboard,
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
dashboard_id: '',
|
||||
layout_class: '',
|
||||
title: '',
|
||||
submit_to: 'index.php',
|
||||
submit_parameters: {},
|
||||
render_to: 'index.php',
|
||||
render_parameters: {},
|
||||
new_dashlet_parameters: {}
|
||||
},
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
var me = this;
|
||||
|
||||
this._superApply(arguments);
|
||||
|
||||
this.element
|
||||
.addClass('itop-runtimedashboard')
|
||||
.bind('mark_as_modified.itop-dashboard', function(){me.mark_as_modified();} );
|
||||
|
||||
this.bModified = false;
|
||||
},
|
||||
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
_destroy: function()
|
||||
{
|
||||
this.element
|
||||
.removeClass('itop-runtimedashboard');
|
||||
|
||||
this._superApply(arguments);
|
||||
},
|
||||
// _setOptions is called with a hash of all options that are changing
|
||||
_setOptions: function()
|
||||
{
|
||||
this._superApply(arguments);
|
||||
this._refresh();
|
||||
},
|
||||
// _setOption is called for each individual option that is changing
|
||||
_setOption: function( key, value )
|
||||
{
|
||||
this._superApply(arguments);
|
||||
},
|
||||
// called when created, and later when changing options
|
||||
_refresh: function()
|
||||
{
|
||||
this._super();
|
||||
|
||||
var oParams = this._get_state(this.options.render_parameters);
|
||||
var me = this;
|
||||
$.post(this.options.render_to, oParams, function(data){
|
||||
me.element.html(data);
|
||||
me._make_draggable();
|
||||
});
|
||||
},
|
||||
// Modified means: at least one change has been applied
|
||||
mark_as_modified: function()
|
||||
{
|
||||
@@ -130,14 +293,8 @@ $(function()
|
||||
me.ajax_div.html(data);
|
||||
});
|
||||
},
|
||||
add_dashlet: function(options)
|
||||
add_dashlet_ajax: function(options, sDashletId)
|
||||
{
|
||||
var sDashletId = this._get_new_id();
|
||||
var oDashlet = $('<div class="dashlet" id="dashlet_'+sDashletId+'"/>');
|
||||
oDashlet.appendTo(options.container);
|
||||
var oDashletProperties = $('<div class="dashlet_properties" id="dashlet_properties_'+sDashletId+'"/>');
|
||||
oDashletProperties.appendTo($('#dashlet_properties'));
|
||||
|
||||
var oParams = this.options.new_dashlet_parameters;
|
||||
var sDashletClass = options.dashlet_class;
|
||||
oParams.dashlet_class = sDashletClass;
|
||||
@@ -145,79 +302,17 @@ $(function()
|
||||
var me = this;
|
||||
$.post(this.options.render_to, oParams, function(data){
|
||||
me.ajax_div.html(data);
|
||||
$('#dashlet_'+sDashletId)
|
||||
.dashlet({dashlet_id: sDashletId, dashlet_class: sDashletClass})
|
||||
.dashlet('deselect_all')
|
||||
.dashlet('select')
|
||||
.draggable({
|
||||
revert: 'invalid', appendTo: 'body', zIndex: 9999,
|
||||
helper: function() {
|
||||
var oDragItem = $(this).dashlet('get_drag_icon');
|
||||
return oDragItem;
|
||||
},
|
||||
cursorAt: { top: 16, left: 16 }
|
||||
});
|
||||
if (options.refresh)
|
||||
{
|
||||
me._refresh();
|
||||
}
|
||||
me.add_dashlet_finalize(options, sDashletId, sDashletClass);
|
||||
});
|
||||
},
|
||||
_get_new_id: function()
|
||||
{
|
||||
var iMaxId = 0;
|
||||
this.element.find(':itop-dashlet').each(function() {
|
||||
var oDashlet = $(this).data('itopDashlet');
|
||||
if(oDashlet)
|
||||
{
|
||||
var oDashletParams = oDashlet.get_params();
|
||||
var id = parseInt(oDashletParams.dashlet_id, 10);
|
||||
if (id > iMaxId) iMaxId = id;
|
||||
}
|
||||
});
|
||||
return 1 + iMaxId;
|
||||
},
|
||||
_make_draggable: function()
|
||||
{
|
||||
var me = this;
|
||||
this.element.find('.dashlet').draggable({
|
||||
revert: 'invalid', appendTo: 'body', zIndex: 9999,
|
||||
helper: function() {
|
||||
var oDragItem = $(this).dashlet('get_drag_icon');
|
||||
return oDragItem;
|
||||
},
|
||||
cursorAt: { top: 16, left: 16 }
|
||||
});
|
||||
this.element.find('table td').droppable({
|
||||
accept: '.dashlet,.dashlet_icon',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var bRefresh = $(this).hasClass('layout_extension');
|
||||
var oDashlet = ui.draggable;
|
||||
if (oDashlet.hasClass('dashlet'))
|
||||
{
|
||||
// moving around a dashlet
|
||||
oDashlet.detach();
|
||||
oDashlet.css({top: 0, left: 0});
|
||||
oDashlet.appendTo($(this));
|
||||
if( bRefresh )
|
||||
{
|
||||
// The layout was extended... refresh the whole dashboard
|
||||
me._refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// inserting a new dashlet
|
||||
var sDashletClass = ui.draggable.attr('dashlet_class');
|
||||
$(':itop-dashboard').dashboard('add_dashlet', {dashlet_class: sDashletClass, container: $(this), refresh: bRefresh });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Helper to upload the file selected in the "import dashboard" dialog
|
||||
//
|
||||
function UploadDashboard(oOptions)
|
||||
{
|
||||
var sFileId = 'dashboard_upload_file';
|
||||
@@ -229,6 +324,10 @@ function UploadDashboard(oOptions)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// dashboard_upload_dlg
|
||||
//
|
||||
//jQuery UI style "widget" for managing a "import dashboard" dialog (file upload)
|
||||
$(function()
|
||||
{
|
||||
|
||||
@@ -123,8 +123,13 @@ $(function()
|
||||
},
|
||||
_remove_dashlet: function()
|
||||
{
|
||||
$('#dashlet_properties_'+this.options.dashlet_id).remove();
|
||||
var iDashletId = this.options.dashlet_id;
|
||||
var sDashletClass = this.options.dashlet_class;
|
||||
var oContainer = this.element.parent();
|
||||
|
||||
$('#dashlet_properties_'+iDashletId).remove();
|
||||
this.element.remove();
|
||||
$('#event_bus').trigger('dashlet-removed', {'dashlet_id': iDashletId, 'dashlet_class': sDashletClass, 'container': oContainer});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -187,7 +187,7 @@ $(function()
|
||||
});
|
||||
this.element.closest('form').find('.itop-property-field').each(function()
|
||||
{
|
||||
var oWidget = $(this).data('property_field');
|
||||
var oWidget = $(this).data('itopProperty_field');
|
||||
if (oWidget && oWidget._is_visible())
|
||||
{
|
||||
var oVal = oWidget._get_committed_value();
|
||||
|
||||
@@ -745,12 +745,11 @@ try
|
||||
$sHtml = addslashes($oPage->end_capture($offset));
|
||||
$sHtml = str_replace("\n", '', $sHtml);
|
||||
$sHtml = str_replace("\r", '', $sHtml);
|
||||
|
||||
$oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml')"); // in ajax web page add_script has the same effect as add_ready_script
|
||||
$oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml');"); // in ajax web page add_script has the same effect as add_ready_script
|
||||
// but is executed BEFORE all 'ready_scripts'
|
||||
$oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
|
||||
$sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, ':itop-dashboard'));
|
||||
$sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, '.itop-dashboard'));
|
||||
$sHtml = str_replace("\n", '', $sHtml);
|
||||
$sHtml = str_replace("\r", '', $sHtml);
|
||||
$oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')"); // in ajax web page add_script has the same effect as add_ready_script // but is executed BEFORE all 'ready_scripts'
|
||||
@@ -803,7 +802,7 @@ try
|
||||
{
|
||||
$oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
|
||||
$sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, ':itop-dashboard'));
|
||||
$sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, '.itop-dashboard'));
|
||||
$sHtml = str_replace("\n", '', $sHtml);
|
||||
$sHtml = str_replace("\r", '', $sHtml);
|
||||
$oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')"); // in ajax web page add_script has the same effect as add_ready_script // but is executed BEFORE all 'ready_scripts'
|
||||
|
||||
@@ -567,42 +567,13 @@ EOF;
|
||||
$aClassParams['display_template'] = "utils::GetAbsoluteUrlModulesRoot().'$sDisplayTemplate'";
|
||||
}
|
||||
|
||||
$this->CompileFiles($oProperties, $sTargetDir.'/'.$sModuleRelativeDir, '');
|
||||
if (($sIcon = $oProperties->GetChildText('icon')) && (strlen($sIcon) > 0))
|
||||
{
|
||||
$sIcon = $sModuleRelativeDir.'/'.$sIcon;
|
||||
$aClassParams['icon'] = "utils::GetAbsoluteUrlModulesRoot().'$sIcon'";
|
||||
}
|
||||
else // si <fileref ref="nnn">
|
||||
{
|
||||
$oIcon = $oProperties->GetOptionalElement('icon');
|
||||
if ($oIcon)
|
||||
{
|
||||
$oFileRef = $oIcon->GetOptionalElement('fileref');
|
||||
if ($oFileRef)
|
||||
{
|
||||
$iFileId = $oFileRef->getAttribute('ref');
|
||||
$sXPath = "/itop_design/files/file[@id='$iFileId']";
|
||||
$oNodes = $this->oFactory->GetNodes($sXPath);
|
||||
if ($oNodes->length == 0)
|
||||
{
|
||||
throw new DOMFormatException('Could not find the file with ref '.$iFileId);
|
||||
}
|
||||
|
||||
$sName = $oNodes->item(0)->GetChildText('name');
|
||||
$sData = base64_decode($oNodes->item(0)->GetChildText('data'));
|
||||
$aPathInfo = pathinfo($sName);
|
||||
$sFile = 'icon-file'.$iFileId.'.'.$aPathInfo['extension'];
|
||||
$sFilePath = $sTargetDir.'/'.$sModuleRelativeDir.'/'.$sFile;
|
||||
file_put_contents($sFilePath, $sData);
|
||||
if (!file_exists($sFilePath))
|
||||
{
|
||||
throw new Exception('Could not write icon file '.$sFilePath);
|
||||
}
|
||||
$aClassParams['icon'] = "utils::GetAbsoluteUrlModulesRoot().'$sModuleRelativeDir/$sFile'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oOrder = $oProperties->GetOptionalElement('order');
|
||||
if ($oOrder)
|
||||
{
|
||||
@@ -1028,6 +999,8 @@ EOF;
|
||||
|
||||
protected function CompileMenu($oMenu, $sTargetDir, $sModuleRelativeDir, $oP)
|
||||
{
|
||||
$this->CompileFiles($oMenu, $sTargetDir.'/'.$sModuleRelativeDir, $sModuleRelativeDir);
|
||||
|
||||
$sMenuId = $oMenu->getAttribute("id");
|
||||
$sMenuClass = $oMenu->getAttribute("xsi:type");
|
||||
|
||||
@@ -1065,11 +1038,11 @@ EOF;
|
||||
}
|
||||
$sFileName = strtolower(str_replace(array(':', '/', '\\', '*'), '_', $sMenuId)).'_dashboard_menu.xml';
|
||||
$sTemplateSpec = $this->PathToPHP($sFileName, $sModuleRelativeDir);
|
||||
|
||||
|
||||
$oXMLDoc = new DOMDocument('1.0', 'UTF-8');
|
||||
$oXMLDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
|
||||
$oXMLDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
|
||||
|
||||
|
||||
$oRootNode = $oXMLDoc->createElement('dashboard'); // make sure that the document is not empty
|
||||
$oRootNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
$oXMLDoc->appendChild($oRootNode);
|
||||
@@ -1325,6 +1298,11 @@ class ProfilesConfig
|
||||
|
||||
protected static \$aLINKTOCLASSES = $sLinkToClasses;
|
||||
|
||||
public static function GetLinkClasses()
|
||||
{
|
||||
return self::\$aLINKTOCLASSES;
|
||||
}
|
||||
|
||||
public static function GetProfileActionGrant(\$iProfileId, \$sClass, \$sAction)
|
||||
{
|
||||
// Search for a grant, starting from the most explicit declaration,
|
||||
@@ -1462,6 +1440,42 @@ EOF;
|
||||
$sDictFile = $sTargetDir.'/dictionaries/'.$sSafeLang.'.dict.php';
|
||||
file_put_contents($sDictFile, $sPHPDict);
|
||||
}
|
||||
|
||||
// Transform the file references into the corresponding filename (and create the file in the relevant directory)
|
||||
//
|
||||
protected function CompileFiles($oNode, $sTargetDir, $sRelativePath)
|
||||
{
|
||||
$oFileRefs = $oNode->GetNodes(".//fileref");
|
||||
foreach ($oFileRefs as $oFileRef)
|
||||
{
|
||||
$iFileId = $oFileRef->getAttribute('ref');
|
||||
if ($iFileId > 0)
|
||||
{
|
||||
$oNodes = $this->oFactory->GetNodes("/itop_design/files/file[@id='$iFileId']");
|
||||
if ($oNodes->length == 0)
|
||||
{
|
||||
throw new DOMFormatException('Could not find the file with ref '.$iFileId);
|
||||
}
|
||||
|
||||
$sName = $oNodes->item(0)->GetChildText('name');
|
||||
$sData = base64_decode($oNodes->item(0)->GetChildText('data'));
|
||||
$aPathInfo = pathinfo($sName);
|
||||
$sFile = 'icon-file'.$iFileId.'.'.$aPathInfo['extension'];
|
||||
$sFilePath = $sTargetDir.'/images/'.$sFile;
|
||||
@mkdir($sTargetDir.'/images');
|
||||
file_put_contents($sFilePath, $sData);
|
||||
if (!file_exists($sFilePath))
|
||||
{
|
||||
throw new Exception('Could not write icon file '.$sFilePath);
|
||||
}
|
||||
$oParentNode = $oFileRef->parentNode;
|
||||
$oParentNode->removeChild($oFileRef);
|
||||
|
||||
$oTextNode = $oParentNode->ownerDocument->createTextNode($sRelativePath.'/images/'.$sFile);
|
||||
$oParentNode->appendChild($oTextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1440,12 +1440,26 @@ class MFElement extends DOMElement
|
||||
return $this->ownerDocument->GetNodes($sXPath, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts some nodes from the DOM (active nodes only !!!)
|
||||
* @param string $sXPath A XPath expression
|
||||
* @return DOMNodeList
|
||||
*/
|
||||
public function GetNodeById($sXPath, $sId)
|
||||
{
|
||||
return $this->ownerDocument->GetNodeById($sXPath, $sId, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging purposes - but this is currently buggy: the whole document is rendered
|
||||
*/
|
||||
public function Dump($bReturnRes = false)
|
||||
{
|
||||
$sXml = $this->ownerDocument->saveXML($this);
|
||||
$oMFDoc = new MFDocument();
|
||||
$oClone = $oMFDoc->importNode($this->cloneNode(true), true);
|
||||
$oMFDoc->appendChild($oClone);
|
||||
|
||||
$sXml = $oMFDoc->saveXML($oClone);
|
||||
if ($bReturnRes)
|
||||
{
|
||||
return $sXml;
|
||||
@@ -1713,6 +1727,9 @@ class MFElement extends DOMElement
|
||||
*/
|
||||
public function AddChildNode(MFElement $oNode)
|
||||
{
|
||||
// First: cleanup any flag behind the new node
|
||||
$oNode->ApplyChanges();
|
||||
|
||||
$oExisting = $this->FindExistingChildNode($oNode);
|
||||
if ($oExisting)
|
||||
{
|
||||
@@ -1740,6 +1757,9 @@ class MFElement extends DOMElement
|
||||
*/
|
||||
public function RedefineChildNode(MFElement $oNode, $sSearchId = null)
|
||||
{
|
||||
// First: cleanup any flag behind the new node
|
||||
$oNode->ApplyChanges();
|
||||
|
||||
$oExisting = $this->FindExistingChildNode($oNode, $sSearchId);
|
||||
if (!$oExisting)
|
||||
{
|
||||
@@ -1906,7 +1926,45 @@ class MFElement extends DOMElement
|
||||
$aCurrentRules = $oRulesNode->GetNodeAsArrayOfItems();
|
||||
}
|
||||
return $aCurrentRules;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List changes below a given node (see also MFDocument::ListChanges)
|
||||
*/
|
||||
public function ListChanges()
|
||||
{
|
||||
// Note: omitting the dot will make the query be global to the whole document!!!
|
||||
return $this->GetNodes('.//*[@_alteration or @_old_id]');
|
||||
}
|
||||
|
||||
/**
|
||||
* List changes below a given node (see also MFDocument::ApplyChanges)
|
||||
*/
|
||||
public function ApplyChanges()
|
||||
{
|
||||
$oNodes = $this->ListChanges();
|
||||
foreach($oNodes as $oNode)
|
||||
{
|
||||
$sOperation = $oNode->GetAttribute('_alteration');
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'added':
|
||||
case 'replaced':
|
||||
// marked as added or modified, just reset the flag
|
||||
$oNode->removeAttribute('_alteration');
|
||||
break;
|
||||
|
||||
case 'removed':
|
||||
// marked as deleted, let's remove the node from the tree
|
||||
$oNode->parentNode->removeChild($oNode);
|
||||
break;
|
||||
}
|
||||
if ($oNode->hasAttribute('_old_id'))
|
||||
{
|
||||
$oNode->removeAttribute('_old_id');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user