Exemple #1
0
/**
 * Displays a popup welcome message, once per session at maximum
 * until the user unchecks the "Display welcome at startup"
 * @param WebPage $oP The current web page for the display
 * @return void
 */
function DisplayWelcomePopup(WebPage $oP)
{
    if (!isset($_SESSION['welcome'])) {
        // Check, only once per session, if the popup should be displayed...
        // If the user did not already ask for hiding it forever
        $bPopup = appUserPreferences::GetPref('welcome_popup', true);
        if ($bPopup) {
            $sTemplate = @file_get_contents('../application/templates/welcome_popup.html');
            if ($sTemplate !== false) {
                $oTemplate = new DisplayTemplate($sTemplate);
                $oP->add("<div id=\"welcome_popup\">");
                $oTemplate->Render($oP, array());
                $oP->add("<p style=\"float:left\"><input type=\"checkbox\" checked id=\"display_welcome_popup\"/><label for=\"display_welcome_popup\">&nbsp;" . Dict::S('UI:DisplayThisMessageAtStartup') . "</label></p>\n");
                $oP->add("<p style=\"float:right\"><input type=\"button\" value=\"" . Dict::S('UI:Button:Ok') . "\" onClick=\"\$('#welcome_popup').dialog('close');\"/>\n");
                $oP->add("</div>\n");
                $sTitle = addslashes(Dict::S('UI:WelcomeMenu:Title'));
                $oP->add_ready_script(<<<EOF
\t\$('#welcome_popup').dialog( { width:'80%', height: 'auto', title: '{$sTitle}', autoOpen: true, modal:true,
\t\t\t\t\t\t\t\t  close: function() {
\t\t\t\t\t\t\t\t  \tvar bDisplay = \$('#display_welcome_popup:checked').length;
\t\t\t\t\t\t\t\t  \tSetUserPreference('welcome_popup', bDisplay, true); 
\t\t\t\t\t\t\t\t  }
\t\t\t\t\t\t\t\t  });
\tif (\$('#welcome_popup').height() > (\$(window).height()-70))
\t{
\t\t\$('#welcome_popup').height(\$(window).height()-70);
\t}
EOF
);
                $_SESSION['welcome'] = 'ok';
            }
        }
    }
}
 public function DisplayFormPart(WebPage $oP, $sPartId)
 {
     switch ($sPartId) {
         case 'xml_options':
             $sNoLocalizeChecked = utils::ReadParam('no_localize', 0) == 1 ? ' checked ' : '';
             $sLinksetChecked = utils::ReadParam('linksets', 0) == 1 ? ' checked ' : '';
             $oP->add('<fieldset><legend>' . Dict::S('Core:BulkExport:XMLOptions') . '</legend>');
             $oP->add('<table>');
             $oP->add('<tr>');
             $oP->add('<td><input type="checkbox" id="xml_no_localize" name="no_localize" value="1"' . $sNoLocalizeChecked . '><label for="xml_no_localize"> ' . Dict::S('Core:BulkExport:OptionNoLocalize') . '</label></td>');
             $oP->add('</tr>');
             $oP->add('<tr>');
             $oP->add('<td><input type="checkbox" id="xml_linksets" name="linksets" value="1"' . $sLinksetChecked . '><label for="xml_linksets"> ' . Dict::S('Core:BulkExport:OptionLinkSets') . '</label></td>');
             $oP->add('</tr>');
             $oP->add('</table>');
             $oP->add('</fieldset>');
             break;
         default:
             return parent::DisplayFormPart($oP, $sPartId);
     }
 }
 public function add($sText)
 {
     if (!$this->m_bPassThrough) {
         parent::add($sText);
     } else {
         if ($this->m_bHeaderSent) {
             echo $sText;
         } else {
             $s_captured_output = $this->ob_get_clean_safe();
             foreach ($this->a_headers as $s_header) {
                 header($s_header);
             }
             echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?" . ">\n";
             echo trim($s_captured_output);
             echo trim($this->s_content);
             echo $sText;
             $this->m_bHeaderSent = true;
         }
     }
 }
 public function Render(WebPage $oPage, $aParams = array())
 {
     $this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
     $iStart = 0;
     $iEnd = strlen($this->m_sTemplate);
     $iCount = 0;
     $iBeforeTagPos = $iStart;
     $iAfterTagPos = $iStart;
     while ($sTag = $this->GetNextTag($iStart, $iEnd)) {
         $sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
         $iAfterTagPos = $iEnd + strlen('</' . $sTag . '>');
         $sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
         $oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
         if ($sTag == DisplayBlock::TAG_BLOCK) {
             try {
                 $oBlock = DisplayBlock::FromTemplate($sOuterTag);
                 if (is_object($oBlock)) {
                     $oBlock->Display($oPage, 'block_' . self::$iBlockCount, $aParams);
                 }
             } catch (OQLException $e) {
                 $oPage->p('Error in template (please contact your administrator) - Invalid query<!--' . $sOuterTag . '-->');
             } catch (Exception $e) {
                 $oPage->p('Error in template (please contact your administrator)<!--' . $e->getMessage() . '--><!--' . $sOuterTag . '-->');
             }
             self::$iBlockCount++;
         } else {
             $aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
             //$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
             $this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
         }
         $iAfterTagPos = $iEnd + strlen('</' . $sTag . '>');
         $iBeforeTagPos = $iAfterTagPos;
         $iStart = $iEnd;
         $iEnd = strlen($this->m_sTemplate);
         $iCount++;
     }
     $oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
 }
 public function RenderContent(WebPage $oPage, $aExtraParams = array())
 {
     if (empty($aExtraParams['currentId'])) {
         $sId = 'sqlblock_' . $oPage->GetUniqueId();
         // Works only if the page is not an Ajax one !
     } else {
         $sId = $aExtraParams['currentId'];
     }
     //		$oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
     $sQuery = $this->BuildQuery();
     $res = CMDBSource::Query($sQuery);
     $aQueryCols = CMDBSource::GetColumns($res);
     // Prepare column definitions (check + give default values)
     //
     foreach ($this->m_aColumns as $sName => $aColumnData) {
         if (!in_array($sName, $aQueryCols)) {
             throw new Exception("Unknown column name '{$sName}' in sqlblock column");
         }
         if (!isset($aColumnData['label'])) {
             $this->m_aColumns[$sName]['label'] = $sName;
         }
         if (isset($aColumnData['drilldown']) && !empty($aColumnData['drilldown'])) {
             // Check if the OQL is valid
             try {
                 $this->m_aColumns[$sName]['filter'] = DBObjectSearch::FromOQL($aColumnData['drilldown']);
             } catch (OQLException $e) {
                 unset($aColumnData['drilldown']);
             }
         }
     }
     if (strlen($this->m_sTitle) > 0) {
         $oPage->add("<h2>" . Dict::S($this->m_sTitle) . "</h2>\n");
     }
     switch ($this->m_sType) {
         case 'bars':
         case 'pie':
             $aColNames = array_keys($this->m_aColumns);
             $sXColName = $aColNames[0];
             $sYColName = $aColNames[1];
             $aData = array();
             $aRows = array();
             while ($aRow = CMDBSource::FetchArray($res)) {
                 $aData[$aRow[$sXColName]] = $aRow[$sYColName];
                 $aRows[$aRow[$sXColName]] = $aRow;
             }
             $this->RenderChart($oPage, $sId, $aData, $this->m_aColumns[$sYColName]['drilldown'], $aRows);
             break;
         default:
         case 'table':
             $oAppContext = new ApplicationContext();
             $sContext = $oAppContext->GetForLink();
             if (!empty($sContext)) {
                 $sContext = '&' . $sContext;
             }
             $aDisplayConfig = array();
             foreach ($this->m_aColumns as $sName => $aColumnData) {
                 $aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
             }
             $aDisplayData = array();
             while ($aRow = CMDBSource::FetchArray($res)) {
                 $aSQLColNames = array_keys($aRow);
                 $aDisplayRow = array();
                 foreach ($this->m_aColumns as $sName => $aColumnData) {
                     if (isset($aColumnData['filter'])) {
                         $sFilter = $aColumnData['drilldown'];
                         $sClass = $aColumnData['filter']->GetClass();
                         $sFilter = str_replace('SELECT ' . $sClass, '', $sFilter);
                         foreach ($aSQLColNames as $sColName) {
                             $sFilter = str_replace(':' . $sColName, "'" . addslashes($aRow[$sColName]) . "'", $sFilter);
                         }
                         $sURL = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=search_oql&search_form=0&oql_class=' . $sClass . '&oql_clause=' . urlencode($sFilter) . '&format=html' . $sContext;
                         $aDisplayRow[$sName] = '<a href="' . $sURL . '">' . $aRow[$sName] . "</a>";
                     } else {
                         $aDisplayRow[$sName] = $aRow[$sName];
                     }
                 }
                 $aDisplayData[] = $aDisplayRow;
             }
             $oPage->table($aDisplayConfig, $aDisplayData);
             break;
     }
 }
    /**
     * Display the history of bulk imports
     */
    static function DisplayImportHistory(WebPage $oPage, $bFromAjax = false, $bShowAll = false)
    {
        $sAjaxDivId = "CSVImportHistory";
        if (!$bFromAjax) {
            $oPage->add('<div id="' . $sAjaxDivId . '">');
        }
        $oPage->p(Dict::S('UI:History:BulkImports+') . ' <span id="csv_history_reload"></span>');
        $oBulkChangeSearch = DBObjectSearch::FromOQL("SELECT CMDBChange WHERE origin IN ('csv-interactive', 'csv-import.php')");
        $iQueryLimit = $bShowAll ? 0 : appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
        $oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), null, $iQueryLimit);
        $oAppContext = new ApplicationContext();
        $bLimitExceeded = false;
        if ($oBulkChanges->Count() > appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit())) {
            $bLimitExceeded = true;
            if (!$bShowAll) {
                $iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
                $oBulkChanges->SetLimit($iMaxObjects);
            }
        }
        $oBulkChanges->Seek(0);
        $aDetails = array();
        while ($oChange = $oBulkChanges->Fetch()) {
            $sDate = '<a href="csvimport.php?step=10&changeid=' . $oChange->GetKey() . '&' . $oAppContext->GetForLink() . '">' . $oChange->Get('date') . '</a>';
            $sUser = $oChange->GetUserName();
            if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches)) {
                $sUser = $aMatches[1];
            } else {
                $sUser = $oChange->Get('userinfo');
            }
            $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpCreate WHERE change = :change_id");
            $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey()));
            $iCreated = $oOpSet->Count();
            // Get the class from the first item found (assumption: a CSV load is done for a single class)
            if ($oCreateOp = $oOpSet->Fetch()) {
                $sClass = $oCreateOp->Get('objclass');
            }
            $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpSetAttribute WHERE change = :change_id");
            $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey()));
            $aModified = array();
            $aAttList = array();
            while ($oModified = $oOpSet->Fetch()) {
                // Get the class (if not done earlier on object creation)
                $sClass = $oModified->Get('objclass');
                $iKey = $oModified->Get('objkey');
                $sAttCode = $oModified->Get('attcode');
                $aAttList[$sClass][$sAttCode] = true;
                $aModified["{$sClass}::{$iKey}"] = true;
            }
            $iModified = count($aModified);
            // Assumption: there is only one class of objects being loaded
            // Then the last class found gives us the class for every object
            if ($iModified > 0 || $iCreated > 0) {
                $aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified);
            }
        }
        $aConfig = array('date' => array('label' => Dict::S('UI:History:Date'), 'description' => Dict::S('UI:History:Date+')), 'user' => array('label' => Dict::S('UI:History:User'), 'description' => Dict::S('UI:History:User+')), 'class' => array('label' => Dict::S('Core:AttributeClass'), 'description' => Dict::S('Core:AttributeClass+')), 'created' => array('label' => Dict::S('UI:History:StatsCreations'), 'description' => Dict::S('UI:History:StatsCreations+')), 'modified' => array('label' => Dict::S('UI:History:StatsModifs'), 'description' => Dict::S('UI:History:StatsModifs+')));
        if ($bLimitExceeded) {
            if ($bShowAll) {
                // Collapsible list
                $oPage->add('<p>' . Dict::Format('UI:CountOfResults', $oBulkChanges->Count()) . '&nbsp;&nbsp;<a class="truncated" onclick="OnTruncatedHistoryToggle(false);">' . Dict::S('UI:CollapseList') . '</a></p>');
            } else {
                // Truncated list
                $iMinDisplayLimit = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
                $sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oBulkChanges->Count());
                $sLinkLabel = Dict::S('UI:DisplayAll');
                $oPage->add('<p>' . $sCollapsedLabel . '&nbsp;&nbsp;<a class="truncated" onclick="OnTruncatedHistoryToggle(true);">' . $sLinkLabel . '</p>');
                $oPage->add_ready_script(<<<EOF
\t\$('#{$sAjaxDivId} table.listResults').addClass('truncated');
\t\$('#{$sAjaxDivId} table.listResults tr:last td').addClass('truncated');
EOF
);
                $sAppContext = $oAppContext->GetForLink();
                $oPage->add_script(<<<EOF
\tfunction OnTruncatedHistoryToggle(bShowAll)
\t{
\t\t\$('#csv_history_reload').html('<img src="../images/indicator.gif"/>');
\t\t\$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
\t\t\t{
\t\t\t\t\$('#{$sAjaxDivId}').html(data);
\t\t\t\tvar table = \$('#{$sAjaxDivId} .listResults');
\t\t\t\ttable.tableHover(); // hover tables
\t\t\t\ttable.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
\t\t\t}
\t\t);
\t}
EOF
);
            }
        } else {
            // Normal display - full list without any decoration
        }
        $oPage->table($aConfig, $aDetails);
        if (!$bFromAjax) {
            $oPage->add('</div>');
        }
    }
    public function RenderContent(WebPage $oPage, $aExtraParams = array())
    {
        $oDashboard = $this->GetDashboard();
        if ($oDashboard != null) {
            $sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $this->sMenuId);
            $oPage->add('<div class="dashboard_contents" id="' . $sDivId . '">');
            $oDashboard->Render($oPage, false, $aExtraParams);
            $oPage->add('</div>');
            $oDashboard->RenderEditionTools($oPage);
            if ($oDashboard->GetAutoReload()) {
                $sId = $this->sMenuId;
                $sExtraParams = json_encode($aExtraParams);
                $iReloadInterval = 1000 * $oDashboard->GetAutoReloadInterval();
                $oPage->add_script(<<<EOF
\t\t\t\t\tsetInterval("ReloadDashboard('{$sDivId}');", {$iReloadInterval});

\t\t\t\t\tfunction ReloadDashboard(sDivId)
\t\t\t\t\t{
\t\t\t\t\t\tvar oExtraParams = {$sExtraParams};
\t\t\t\t\t\t// Do not reload when a dialog box is active
\t\t\t\t\t\tif (!(\$('.ui-dialog:visible').length > 0))
\t\t\t\t\t\t{
\t\t\t\t\t\t\t\$('.dashboard_contents#'+sDivId).block();
\t\t\t\t\t\t\t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
\t\t\t\t\t\t\t   { operation: 'reload_dashboard', dashboard_id: '{$sId}', extra_params: oExtraParams},
\t\t\t\t\t\t\t   function(data){
\t\t\t\t\t\t\t\t \$('.dashboard_contents#'+sDivId).html(data);
\t\t\t\t\t\t\t\t \$('.dashboard_contents#'+sDivId).unblock();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t );
\t\t\t\t\t\t}
\t\t\t\t\t}
EOF
);
            }
            $bEdit = utils::ReadParam('edit', false);
            if ($bEdit) {
                $sId = addslashes($this->sMenuId);
                $oPage->add_ready_script("EditDashboard('{$sId}');");
            }
        } else {
            $oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
        }
    }
Exemple #8
0
function DisplayForm(WebPage $oP, $sAction = '', $sExpression = '', $sQueryId = '', $sFormat = null)
{
    $oExportSearch = null;
    $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/tabularfieldsselector.js');
    $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.dragtable.js');
    $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot() . 'css/dragtable.css');
    $oP->add('<form id="export-form" action="' . $sAction . '" method="post" data-state="not-yet-started">');
    $bExpressionIsValid = true;
    $sExpressionError = '';
    if ($sExpression === null && $sQueryId === null) {
        $bExpressionIsValid = false;
    } else {
        if ($sExpression !== '') {
            try {
                $oExportSearch = DBObjectSearch::FromOQL($sExpression);
            } catch (OQLException $e) {
                $bExpressionIsValid = false;
                $sExpressionError = $e->getMessage();
            }
        }
    }
    if (!$bExpressionIsValid) {
        DisplayExpressionForm($oP, $sAction, $sExpression, $sExpressionError);
        return;
    }
    if ($sExpression !== '') {
        $oP->add('<input type="hidden" name="expression" value="' . htmlentities($sExpression, ENT_QUOTES, 'UTF-8') . '">');
        $oExportSearch = DBObjectSearch::FromOQL($sExpression);
    } else {
        $oQuery = MetaModel::GetObject('QueryOQL', $sQueryId);
        $oExportSearch = DBObjectSearch::FromOQL($oQuery->Get('oql'));
        $oP->add('<input type="hidden" name="query" value="' . htmlentities($sQueryId, ENT_QUOTES, 'UTF-8') . '">');
    }
    $aFormPartsByFormat = array();
    $aAllFormParts = array();
    if ($sFormat == null) {
        // No specific format chosen
        $sDefaultFormat = utils::ReadParam('format', 'xlsx');
        $oP->add('<p>' . Dict::S('Core:BulkExport:ExportFormatPrompt') . ' <select name="format" id="format_selector">');
        $aSupportedFormats = BulkExport::FindSupportedFormats();
        asort($aSupportedFormats);
        foreach ($aSupportedFormats as $sFormatCode => $sLabel) {
            $sSelected = $sFormatCode == $sDefaultFormat ? 'selected' : '';
            $oP->add('<option value="' . $sFormatCode . '" ' . $sSelected . '>' . htmlentities($sLabel, ENT_QUOTES, 'UTF-8') . '</option>');
            $oExporter = BulkExport::FindExporter($sFormatCode);
            $oExporter->SetObjectList($oExportSearch);
            $aParts = $oExporter->EnumFormParts();
            foreach ($aParts as $sPartId => $void) {
                $aAllFormParts[$sPartId] = $oExporter;
            }
            $aFormPartsByFormat[$sFormatCode] = array_keys($aParts);
        }
        $oP->add('</select></p>');
    } else {
        // One specific format was chosen
        $oP->add('<input type="hidden" name="format" value="' . htmlentities($sFormat, ENT_QUOTES, 'UTF-8') . '">');
        $oExporter = BulkExport::FindExporter($sFormat, $oExportSearch);
        $aParts = $oExporter->EnumFormParts();
        foreach ($aParts as $sPartId => $void) {
            $aAllFormParts[$sPartId] = $oExporter;
        }
        $aFormPartsByFormat[$sFormat] = array_keys($aAllFormParts);
    }
    foreach ($aAllFormParts as $sPartId => $oExport) {
        $oP->add('<div class="form_part" id="form_part_' . $sPartId . '">');
        $oExport->DisplayFormPart($oP, $sPartId);
        $oP->add('</div>');
    }
    $oP->add('</form>');
    $oP->add('<div id="export-feedback" style="display:none;"><p class="export-message" style="text-align:center;">' . Dict::S('ExcelExport:PreparingExport') . '</p><div class="export-progress-bar" style="max-width:30em; margin-left:auto;margin-right:auto;"><div class="export-progress-message" style="text-align:center;"></div></div></div>');
    $oP->add('<button type="button" id="export-btn">' . Dict::S('UI:Button:Export') . '</button>');
    $oP->add('<div id="export_text_result" style="display:none;">');
    $oP->add('<div>' . Dict::S('Core:BulkExport:ExportResult') . '</div>');
    $oP->add('<textarea id="export_content" style="width:100%;min-height:15em;"></textarea>');
    $oP->add('</div>');
    $sJSParts = json_encode($aFormPartsByFormat);
    $sJSCancel = json_encode(Dict::S('UI:Button:Cancel'));
    $sJSClose = json_encode(Dict::S('UI:Button:Done'));
    $oP->add_ready_script(<<<EOF
window.aFormParts = {$sJSParts};
\$('#format_selector').on('change init', function() {
\tExportToggleFormat(\$(this).val());
}).trigger('init');
\t\t
\$('.export-progress-bar').progressbar({
\t value: 0,
\t change: function() {
\t\t\$('.export-progress-message').text( \$(this).progressbar( "value" ) + "%" );
\t },
\t complete: function() {
\t\t \$('.export-progress-message').text( '100 %' );
\t }
});

ExportInitButton('#export-btn');

EOF
);
}
 function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
 {
     if ($bEditMode) {
         return;
     }
     // Not editable
     $oPage->add('<table style="vertical-align:top"><tr style="vertical-align:top"><td>');
     $aDetails = array();
     $sClass = get_class($this);
     $oPage->add('<fieldset>');
     $oPage->add('<legend>' . Dict::S('Core:SynchroReplica:PrivateDetails') . '</legend>');
     $aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
     foreach ($aZList as $sAttCode) {
         $sDisplayValue = $this->GetAsHTML($sAttCode);
         $aDetails[] = array('label' => '<span title="' . MetaModel::GetDescription($sClass, $sAttCode) . '">' . MetaModel::GetLabel($sClass, $sAttCode) . '</span>', 'value' => $sDisplayValue);
     }
     $oPage->Details($aDetails);
     $oPage->add('</fieldset>');
     if (strlen($this->Get('dest_class')) > 0) {
         $oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'), false);
         if (is_object($oDestObj)) {
             $oPage->add('<fieldset>');
             $oPage->add('<legend>' . Dict::Format('Core:SynchroReplica:TargetObject', $oDestObj->GetHyperlink()) . '</legend>');
             $oDestObj->DisplayBareProperties($oPage, false, $sPrefix, $aExtraParams);
             $oPage->add('<fieldset>');
         }
     }
     $oPage->add('</td><td>');
     $oPage->add('<fieldset>');
     $oPage->add('<legend>' . Dict::S('Core:SynchroReplica:PublicData') . '</legend>');
     $oSource = MetaModel::GetObject('SynchroDataSource', $this->Get('sync_source_id'));
     $sSQLTable = $oSource->GetDataTable();
     $aData = $this->LoadExtendedDataFromTable($sSQLTable);
     $aHeaders = array('attcode' => array('label' => 'Attribute Code', 'description' => ''), 'data' => array('label' => 'Value', 'description' => ''));
     $aRows = array();
     foreach ($aData as $sKey => $value) {
         $aRows[] = array('attcode' => $sKey, 'data' => $value);
     }
     $oPage->Table($aHeaders, $aRows);
     $oPage->add('</fieldset>');
     $oPage->add('</td></tr></table>');
 }
 public function RenderContent(WebPage $oPage, $aExtraParams = array())
 {
     if (!isset($aExtraParams['currentId'])) {
         $sId = $oPage->GetUniqueId();
         // Works only if the page is not an Ajax one !
     } else {
         $sId = $aExtraParams['currentId'];
     }
     $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
 }
Exemple #11
0
                    do {
                        $aStatus = $oExporter->Run();
                        // process one chunk
                    } while ($aStatus['code'] != 'done' && $aStatus['code'] != 'error');
                    if ($aStatus['code'] == 'done') {
                        $oP->SetContentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
                        $oP->SetContentDisposition('attachment', $oFilter->GetClass() . '.xlsx');
                        $oP->add(file_get_contents($oExporter->GetExcelFilePath()));
                        $oExporter->Cleanup();
                    } else {
                        $oP->add('Error, xlsx export failed: ' . $aStatus['message']);
                    }
                    break;
                default:
                    $oP = new WebPage("iTop - Export");
                    $oP->add("Unsupported format '{$sFormat}'. Possible values are: html, csv, spreadsheet or xml.");
            }
        }
    } catch (Exception $e) {
        $oP = new WebPage("iTop - Export");
        $oP->p("Error the query can not be executed.");
        if ($e instanceof CoreException) {
            $oP->p($e->GetHtmlDesc());
        } else {
            $oP->p($e->getMessage());
        }
    }
}
if (!$oP) {
    // Display a short message about how to use this page
    $bModeCLI = utils::IsModeCLI();
Exemple #12
0
/**
 * Create form to apply a stimulus
 * @param WebPage $oP The current web page
 * @param Object $oObj The target object
 * @param String $sStimulusCode Stimulus that will be applied
 * @param Array $aEditAtt List of attributes to edit
 * @return void
 */
function MakeStimulusForm(WebPage $oP, $oObj, $sStimulusCode, $aEditAtt)
{
    static $bHasStimulusForm = false;
    $sDialogId = $sStimulusCode . "_dialog";
    $sFormId = $sStimulusCode . "_form";
    $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
    $oP->add('<div id="' . $sDialogId . '" style="display: none;">');
    $sClass = get_class($oObj);
    $oP->add('<form id="' . $sFormId . '" method="post">');
    $sTransactionId = utils::GetNewTransactionId();
    $oP->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"{$sTransactionId}\">\n");
    $oP->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">");
    $oP->add("<input type=\"hidden\" name=\"id\" value=\"" . $oObj->GetKey() . "\">");
    $oP->add("<input type=\"hidden\" name=\"operation\" value=\"update_request\">");
    $oP->add("<input type=\"hidden\" id=\"stimulus_to_apply\" name=\"apply_stimulus\" value=\"{$sStimulusCode}\">\n");
    foreach ($aEditAtt as $sAttCode) {
        $sValue = $oObj->Get($sAttCode);
        $sDisplayValue = $oObj->GetEditValue($sAttCode);
        $aArgs = array('this' => $oObj, 'formPrefix' => '');
        $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
        $sInputId = 'input_' . $sAttCode;
        $sHTMLValue = "<span id=\"field_{$sStimulusCode}_{$sInputId}\">" . cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', 0, $aArgs) . '</span>';
        $oP->add('<h1>' . MetaModel::GetLabel($sClass, $sAttCode) . '</h1>');
        $oP->add($sHTMLValue);
    }
    $oP->add('</form>');
    $oP->add('</div>');
    if (!$bHasStimulusForm) {
        $bHasStimulusForm = true;
        $oP->add_script(<<<EOF

function RunStimulusDialog(sStimulusCode, sTitle, sOkButtonLabel)
{
\tvar sWidth = 'auto';
\tif (sStimulusCode == 'ev_reopen')
\t{
\t\t// Avoid having a dialog spanning the complete width of the window
\t\t// just because it contains a CaseLog entry
\t\tsWidth = '80%';
\t}
\t\t\t\t
\t\$('#'+sStimulusCode+'_dialog').dialog({
\t\theight: 'auto',
\t\twidth: sWidth,
\t\tmodal: true,
\t\ttitle: sTitle,
\t\tbuttons: [
\t\t{ text: sOkButtonLabel, click: function() {
\t\t\t\$(this).find('#'+sStimulusCode+'_form').submit();
\t\t} },
\t\t{ text: "{$sCancelButtonLabel}", click: function() {
\t\t\t\$(this).dialog( "close" );
\t\t} }
\t\t]
\t});
\t// Start the validation
\tCheckFields(sStimulusCode+'_form', false);
\t\$('#'+sStimulusCode+'_form').submit( function() {
\t\treturn OnSubmit(sStimulusCode+'_form');
\t});
}
EOF
);
    }
}
 public function DoAddObjects(WebPage $oP, $oFullSetFilter)
 {
     $aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
     foreach ($aLinkedObjectIds as $iObjectId) {
         $oLinkObj = MetaModel::GetObject($this->sLinkedClass, $iObjectId);
         $oP->add($this->GetObjectRow($oP, $oLinkObj, $oLinkObj->GetKey()));
     }
 }
 public function DisplayFormPart(WebPage $oP, $sPartId)
 {
     switch ($sPartId) {
         case 'pdf_options':
             $oP->add('<fieldset><legend>' . Dict::S('Core:BulkExport:PDFOptions') . '</legend>');
             $oP->add('<table>');
             $oP->add('<tr>');
             $oP->add('<td>' . Dict::S('Core:BulkExport:PDFPageSize') . '</td>');
             $oP->add('<td>' . $this->GetSelectCtrl('page_size', array('A3', 'A4', 'Letter'), 'Core:BulkExport:PageSize-', 'A4') . '</td>');
             $oP->add('</tr>');
             $oP->add('<td>' . Dict::S('Core:BulkExport:PDFPageOrientation') . '</td>');
             $oP->add('<td>' . $this->GetSelectCtrl('page_orientation', array('P', 'L'), 'Core:BulkExport:PageOrientation-', 'L') . '</td>');
             $oP->add('</tr>');
             $oP->add('</table>');
             $oP->add('</fieldset>');
             break;
         default:
             return parent::DisplayFormPart($oP, $sPartId);
     }
 }
require_once APPROOT . '/application/ajaxwebpage.class.inc.php';
require_once APPROOT . '/application/startup.inc.php';
$operation = utils::ReadParam('operation', '');
require_once APPROOT . '/application/loginwebpage.class.inc.php';
LoginWebPage::DoLogin();
// Check user rights and prompt if needed
$oP = new WebPage('Replay queries.log');
ini_set('memory_limit', '512M');
require_once APPROOT . '/data/queries.log';
$iCount = count($aQueriesLog);
$oP->p("Nombre de requêtes: " . $iCount);
$sOperation = utils::ReadParam('operation', '');
switch ($sOperation) {
    case '':
    default:
        $oP->add("<ol>\n");
        foreach ($aQueriesLog as $sQueryId => $aOqlData) {
            $sOql = $aOqlData['oql'];
            $sOqlHtml = htmlentities($sOql, ENT_QUOTES, 'UTF-8');
            $oP->add("<li>{$sOqlHtml} <a href=\"?operation=zoom&query={$sQueryId}\">zoom</a></li>\n");
        }
        $oP->add("</ol>\n");
        $oP->add("<form action=\"?operation=benchmark&repeat=3\" method=\"post\">\n");
        $oP->add("<input type=\"submit\" value=\"Benchmark (3 repeats)!\">\n");
        $oP->add("</form>\n");
        $oP->add("<form action=\"?operation=check\" method=\"post\">\n");
        $oP->add("<input type=\"submit\" value=\"Check!\">\n");
        $oP->add("</form>\n");
        break;
    case 'zoom':
        $sQueryId = utils::ReadParam('query', '', false, 'raw_data');
 public function AsyncAction(WebPage $oPage, $sCode, $aParameters)
 {
     $oParameters = new PHPParameters();
     // For security reasons: add the extension now so that this action can be used to read *only* .zip files from the disk...
     $sBackupFile = $aParameters['backup'] . '.zip';
     if (file_exists($sBackupFile)) {
         // Make sure there is NO output at all before our content, otherwise the document will be corrupted
         $sPreviousContent = ob_get_clean();
         $oPage->SetContentType('application/zip');
         $oPage->SetContentDisposition('attachment', basename($sBackupFile));
         $oPage->add(file_get_contents($sBackupFile));
     }
 }
 public function DisplayAddForm(WebPage $oP)
 {
     $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
     $sTargetClass = $oAttDef->GetTargetClass();
     $oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
     $oP->add("<div class=\"wizContainer\">\n");
     //$oP->add("<div class=\"page_header\">\n");
     //$oP->add("<h1>".Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."</h1>\n");
     //$oP->add("</div>\n");
     $oFilter = new DBObjectSearch($this->m_sLinkedClass);
     $oSet = new CMDBObjectSet($oFilter);
     $oBlock = new DisplayBlock($oFilter, 'search', false);
     $oBlock->Display($oP, 'SearchFormToAdd', array('open' => true));
     $oP->Add("<form id=\"ObjectsAddForm\" OnSubmit=\"return DoAddObjects(this.id);\">\n");
     $oP->Add("<div id=\"SearchResultsToAdd\">\n");
     $oP->Add("<div style=\"height: 100px; background: #fff;border-color:#F6F6F1 #E6E6E1 #E6E6E1 #F6F6F1; border-style:solid; border-width:3px; text-align: center; vertical-align: center;\"><p>" . Dict::S('UI:Message:EmptyList:UseSearchForm') . "</p></div>\n");
     $oP->Add("</div>\n");
     $oP->add("<input type=\"button\" value=\"" . Dict::S('UI:Button:Cancel') . "\" onClick=\"\$('#ModalDlg').dialog('close');\">&nbsp;&nbsp;<input type=\"submit\" value=\"" . Dict::S('UI:Button:Add') . "\">");
     $oP->Add("</div>\n");
     $oP->Add("</form>\n");
     $oP->add_ready_script("\$('#ModalDlg').dialog('option', {title:'" . Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">" . $oTargetObj->GetHyperlink() . "</span>") . "'});");
     $oP->add_ready_script("\$('div#SearchFormToAdd form').bind('submit.uilinksWizard', SubmitHook);");
 }
} else {
    if (filter_input(INPUT_POST, "addNewWebPage") != NULL && filter_input(INPUT_POST, "addNewWebPage") == "addNewWebPage") {
        $postVars = array('name', 'title', 'description', 'keywords');
        // Form fields names
        foreach ($postVars as $postVar) {
            switch ($postVar) {
                default:
                    $webPage->{$postVar} = filter_input(INPUT_POST, $postVar) ? mysqli_real_escape_string($dbObj->connection, filter_input(INPUT_POST, $postVar)) : '';
                    if ($webPage->{$postVar} === "") {
                        array_push($errorArr, "Please enter {$postVar} ");
                    }
                    break;
            }
        }
        if (count($errorArr) < 1) {
            echo $webPage->add();
        } else {
            $json = array("status" => 0, "msg" => $errorArr);
            $dbObj->close();
            //Close Database Connection
            header('Content-type: application/json');
            echo json_encode($json);
        }
    }
    if (filter_input(INPUT_POST, "fetchWebpages") != NULL) {
        $requestData = $_REQUEST;
        $columns = array(0 => 'id', 1 => 'id', 2 => 'name', 3 => 'title', 4 => 'description', 5 => 'keywords');
        // getting total number records without any search
        $query = $dbObj->query("SELECT * FROM webpage ");
        $totalData = mysqli_num_rows($query);
        $totalFiltered = $totalData;
Exemple #19
0
 /**
  * Simulate the load of the CSV data and display the results
  * @param WebPage $oPage The web page to display the wizard
  * @return void
  */
 function Preview(WebPage $oPage)
 {
     $oPage->add('<h2>' . Dict::S('UI:Title:CSVImportStep4') . '</h2>');
     ProcessCSVData($oPage, true);
 }
 /**
  * Display the hierarchy of the 'target' class
  */
 public function DisplayHierarchy(WebPage $oPage, $sFilter, $currValue, $oObj)
 {
     $sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass)));
     $oPage->add('<div id="dlg_tree_' . $this->iId . '"><div class="wizContainer" style="vertical-align:top;"><div style="overflow:auto;background:#fff;margin-bottom:5px;" id="tree_' . $this->iId . '">');
     $oPage->add('<table style="width:100%"><tr><td>');
     if (is_null($sFilter)) {
         throw new Exception('Implementation: null value for allowed values definition');
     }
     try {
         $oFilter = DBObjectSearch::FromOQL($sFilter);
         $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
         $oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
     } catch (MissingQueryArgument $e) {
         // When used in a search form the $this parameter may be missing, in this case return all possible values...
         // TODO check if we can improve this behavior...
         $sOQL = 'SELECT ' . $this->m_sTargetClass;
         $oFilter = DBObjectSearch::FromOQL($sOQL);
         $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
         $oSet = new DBObjectSet($oFilter);
     }
     $sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
     $this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
     $oPage->add('</td></tr></table>');
     $oPage->add('</div>');
     $oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"" . Dict::S('UI:Button:Cancel') . "\" onClick=\"\$('#dlg_tree_{$this->iId}').dialog('close');\">&nbsp;&nbsp;");
     $oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"" . Dict::S('UI:Button:Ok') . "\"  onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
     $oPage->add('</div></div>');
     $oPage->add_ready_script("\$('#tree_{$this->iId} ul').treeview();\n");
     $oPage->add_ready_script("\$('#dlg_tree_{$this->iId}').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '{$sDialogTitle}', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
 }
    protected function GetInteractiveFieldsWidget(WebPage $oP, $sWidgetId)
    {
        $oSet = new DBObjectSet($this->oSearch);
        $aSelectedClasses = $this->oSearch->GetSelectedClasses();
        $aAuthorizedClasses = array();
        foreach ($aSelectedClasses as $sAlias => $sClassName) {
            if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) {
                $aAuthorizedClasses[$sAlias] = $sClassName;
            }
        }
        $aAllFieldsByAlias = array();
        $aAllAttCodes = array();
        foreach ($aAuthorizedClasses as $sAlias => $sClass) {
            $aAllFields = array();
            if (count($aAuthorizedClasses) > 1) {
                $sShortAlias = $sAlias . '.';
            } else {
                $sShortAlias = '';
            }
            if ($this->IsExportableField($sClass, 'id')) {
                $sFriendlyNameAttCode = MetaModel::GetFriendlyNameAttributeCode($sClass);
                if (is_null($sFriendlyNameAttCode)) {
                    // The friendly name is made of several attribute
                    $aSubAttr = array(array('attcodeex' => 'id', 'code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('UI:CSVImport:idField'), 'label' => $sShortAlias . 'id'), array('attcodeex' => 'friendlyname', 'code' => $sShortAlias . 'friendlyname', 'unique_label' => $sShortAlias . Dict::S('Core:FriendlyName-Label'), 'label' => $sShortAlias . Dict::S('Core:FriendlyName-Label')));
                } else {
                    // The friendly name has no added value
                    $aSubAttr = array();
                }
                $aAllFields[] = array('attcodeex' => 'id', 'code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('UI:CSVImport:idField'), 'label' => Dict::S('UI:CSVImport:idField'), 'subattr' => $aSubAttr);
            }
            foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
                if ($this->IsSubAttribute($sClass, $sAttCode, $oAttDef)) {
                    continue;
                }
                if ($this->IsExportableField($sClass, $sAttCode, $oAttDef)) {
                    $sShortLabel = $oAttDef->GetLabel();
                    $sLabel = $sShortAlias . $oAttDef->GetLabel();
                    $aSubAttr = $this->GetSubAttributes($sClass, $sAttCode, $oAttDef);
                    $aValidSubAttr = array();
                    foreach ($aSubAttr as $aSubAttDef) {
                        $aValidSubAttr[] = array('attcodeex' => $aSubAttDef['code'], 'code' => $sShortAlias . $aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $sShortAlias . $aSubAttDef['unique_label']);
                    }
                    $aAllFields[] = array('attcodeex' => $sAttCode, 'code' => $sShortAlias . $sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr);
                }
            }
            usort($aAllFields, array(get_class($this), 'SortOnLabel'));
            if (count($aAuthorizedClasses) > 1) {
                $sKey = MetaModel::GetName($sClass) . ' (' . $sAlias . ')';
            } else {
                $sKey = MetaModel::GetName($sClass);
            }
            $aAllFieldsByAlias[$sKey] = $aAllFields;
            foreach ($aAllFields as $aFieldSpec) {
                $sAttCode = $aFieldSpec['attcodeex'];
                if (count($aFieldSpec['subattr']) > 0) {
                    foreach ($aFieldSpec['subattr'] as $aSubFieldSpec) {
                        $aAllAttCodes[$sAlias][] = $aSubFieldSpec['attcodeex'];
                    }
                } else {
                    $aAllAttCodes[$sAlias][] = $sAttCode;
                }
            }
        }
        $oP->add('<div id="' . $sWidgetId . '"></div>');
        $JSAllFields = json_encode($aAllFieldsByAlias);
        // First, fetch only the ids - the rest will be fetched by an object reload
        $oSet = new DBObjectSet($this->oSearch);
        $iCount = $oSet->Count();
        foreach ($this->oSearch->GetSelectedClasses() as $sAlias => $sClass) {
            $aColumns[$sAlias] = array();
        }
        $oSet->OptimizeColumnLoad($aColumns);
        $iPreviewLimit = 3;
        $oSet->SetLimit($iPreviewLimit);
        $aSampleData = array();
        while ($aRow = $oSet->FetchAssoc()) {
            $aSampleRow = array();
            foreach ($aAuthorizedClasses as $sAlias => $sClass) {
                if (count($aAuthorizedClasses) > 1) {
                    $sShortAlias = $sAlias . '.';
                } else {
                    $sShortAlias = '';
                }
                foreach ($aAllAttCodes[$sAlias] as $sAttCodeEx) {
                    $oObj = $aRow[$sAlias];
                    $aSampleRow[$sShortAlias . $sAttCodeEx] = $oObj ? $this->GetSampleData($oObj, $sAttCodeEx) : '';
                }
            }
            $aSampleData[] = $aSampleRow;
        }
        $sJSSampleData = json_encode($aSampleData);
        $aLabels = array('preview_header' => Dict::S('Core:BulkExport:DragAndDropHelp'), 'empty_preview' => Dict::S('Core:BulkExport:EmptyPreview'), 'columns_order' => Dict::S('Core:BulkExport:ColumnsOrder'), 'columns_selection' => Dict::S('Core:BulkExport:AvailableColumnsFrom_Class'), 'check_all' => Dict::S('Core:BulkExport:CheckAll'), 'uncheck_all' => Dict::S('Core:BulkExport:UncheckAll'), 'no_field_selected' => Dict::S('Core:BulkExport:NoFieldSelected'));
        $sJSLabels = json_encode($aLabels);
        $oP->add_ready_script(<<<EOF
\$('#{$sWidgetId}').tabularfieldsselector({fields: {$JSAllFields}, value_holder: '#tabular_fields', advanced_holder: '#tabular_advanced', sample_data: {$sJSSampleData}, total_count: {$iCount}, preview_limit: {$iPreviewLimit}, labels: {$sJSLabels} });
EOF
);
    }
Exemple #22
0
/**
 * Downloads a document to the browser, either as 'inline' or 'attachment'
 *  
 * @param WebPage $oPage The web page for the output
 * @param string $sClass Class name of the object
 * @param mixed $id Identifier of the object
 * @param string $sAttCode Name of the attribute containing the document to download
 * @param string $sContentDisposition Either 'inline' or 'attachment'
 * @return none
 */
function DownloadDocument(WebPage $oPage, $sClass, $id, $sAttCode, $sContentDisposition = 'attachment')
{
    try {
        $oObj = MetaModel::GetObject($sClass, $id, false, false);
        if (!is_object($oObj)) {
            throw new Exception("Invalid id ({$id}) for class '{$sClass}' - the object does not exist or you are not allowed to view it");
        }
        $oDocument = $oObj->Get($sAttCode);
        if (is_object($oDocument)) {
            $oPage->TrashUnexpectedOutput();
            $oPage->SetContentType($oDocument->GetMimeType());
            $oPage->SetContentDisposition($sContentDisposition, $oDocument->GetFileName());
            $oPage->add($oDocument->GetData());
        }
    } catch (Exception $e) {
        $oPage->p($e->getMessage());
    }
}
    protected function GetInteractiveFieldsWidget(WebPage $oP, $sWidgetId)
    {
        $oSet = new DBObjectSet($this->oSearch);
        $aSelectedClasses = $this->oSearch->GetSelectedClasses();
        $aAuthorizedClasses = array();
        foreach ($aSelectedClasses as $sAlias => $sClassName) {
            if (UserRights::IsActionAllowed($sClassName, UR_ACTION_BULK_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) {
                $aAuthorizedClasses[$sAlias] = $sClassName;
            }
        }
        $aAllFieldsByAlias = array();
        foreach ($aAuthorizedClasses as $sAlias => $sClass) {
            $aAllFields = array();
            if (count($aAuthorizedClasses) > 1) {
                $sShortAlias = $sAlias . '.';
            } else {
                $sShortAlias = '';
            }
            if ($this->IsValidField($sClass, 'id')) {
                $aAllFields[] = array('code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias . 'id', 'subattr' => array(array('code' => $sShortAlias . 'id', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias . 'id'), array('code' => $sShortAlias . 'friendlyname', 'unique_label' => $sShortAlias . Dict::S('Core:BulkExport:Friendlyname'), 'label' => $sShortAlias . Dict::S('Core:BulkExport:Friendlyname'))));
            }
            foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
                if ($this->IsSubAttribute($sClass, $sAttCode, $oAttDef)) {
                    continue;
                }
                if ($this->IsValidField($sClass, $sAttCode, $oAttDef)) {
                    $sShortLabel = $oAttDef->GetLabel();
                    $sLabel = $sShortAlias . $oAttDef->GetLabel();
                    $aSubAttr = $this->GetSubAttributes($sClass, $sAttCode, $oAttDef);
                    $aValidSubAttr = array();
                    foreach ($aSubAttr as $aSubAttDef) {
                        if ($this->IsValidField($sClass, $aSubAttDef['code'], $aSubAttDef['attdef'])) {
                            $aValidSubAttr[] = array('code' => $sShortAlias . $aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $aSubAttDef['unique_label']);
                        }
                    }
                    $aAllFields[] = array('code' => $sShortAlias . $sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr);
                }
            }
            usort($aAllFields, array(get_class($this), 'SortOnLabel'));
            if (count($aAuthorizedClasses) > 1) {
                $sKey = MetaModel::GetName($sClass) . ' (' . $sAlias . ')';
            } else {
                $sKey = MetaModel::GetName($sClass);
            }
            $aAllFieldsByAlias[$sKey] = $aAllFields;
        }
        $oP->add('<div id="' . $sWidgetId . '"></div>');
        $JSAllFields = json_encode($aAllFieldsByAlias);
        $oSet = new DBObjectSet($this->oSearch);
        $iCount = $oSet->Count();
        $iPreviewLimit = 3;
        $oSet->SetLimit($iPreviewLimit);
        $aSampleData = array();
        while ($aRow = $oSet->FetchAssoc()) {
            $aSampleRow = array();
            foreach ($aAuthorizedClasses as $sAlias => $sClass) {
                if (count($aAuthorizedClasses) > 1) {
                    $sShortAlias = $sAlias . '.';
                } else {
                    $sShortAlias = '';
                }
                if ($this->IsValidField($sClass, 'id')) {
                    $aSampleRow[$sShortAlias . 'id'] = $this->GetSampleKey($aRow[$sAlias]);
                }
                foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
                    if ($this->IsValidField($sClass, $sAttCode, $oAttDef)) {
                        $aSampleRow[$sShortAlias . $sAttCode] = $this->GetSampleData($aRow[$sAlias], $sAttCode);
                    }
                }
            }
            $aSampleData[] = $aSampleRow;
        }
        $sJSSampleData = json_encode($aSampleData);
        $aLabels = array('preview_header' => Dict::S('Core:BulkExport:DragAndDropHelp'), 'empty_preview' => Dict::S('Core:BulkExport:EmptyPreview'), 'columns_order' => Dict::S('Core:BulkExport:ColumnsOrder'), 'columns_selection' => Dict::S('Core:BulkExport:AvailableColumnsFrom_Class'), 'check_all' => Dict::S('Core:BulkExport:CheckAll'), 'uncheck_all' => Dict::S('Core:BulkExport:UncheckAll'), 'no_field_selected' => Dict::S('Core:BulkExport:NoFieldSelected'));
        $sJSLabels = json_encode($aLabels);
        $oP->add_ready_script(<<<EOF
\$('#{$sWidgetId}').tabularfieldsselector({fields: {$JSAllFields}, value_holder: '#tabular_fields', advanced_holder: '#tabular_advanced', sample_data: {$sJSSampleData}, total_count: {$iCount}, preview_limit: {$iPreviewLimit}, labels: {$sJSLabels} });
EOF
);
    }
    public function DisplayAttachments($oObject, WebPage $oPage, $bEditMode = false)
    {
        // Exit here if the class is not allowed
        if (!$this->IsTargetObject($oObject)) {
            return;
        }
        $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id");
        $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey()));
        if ($this->GetAttachmentsPosition() == 'relations') {
            $sTitle = $oSet->Count() > 0 ? Dict::Format('Attachments:TabTitle_Count', $oSet->Count()) : Dict::S('Attachments:EmptyTabTitle');
            $oPage->SetCurrentTab($sTitle);
        }
        $oPage->add_style(<<<EOF
.attachment {
\tdisplay: inline-block;
\ttext-align:center;
\tfloat:left;
\tpadding:5px;\t
}
.attachment:hover {
\tbackground-color: #e0e0e0;
}
.attachment img {
\tborder: 0;
}
.attachment a {
\ttext-decoration: none;
\tcolor: #1C94C4;
}
.btn_hidden {
\tdisplay: none;
}
.drag_in {
\t-webkit-box-shadow:inset 0 0 10px 2px #1C94C4;
\tbox-shadow:inset 0 0 10px 2px #1C94C4;
}
#history .attachment-history-added {
\tpadding: 0;
\tfloat: none;
}
EOF
);
        $oPage->add('<fieldset>');
        $oPage->add('<legend>' . Dict::S('Attachments:FieldsetTitle') . '</legend>');
        if ($bEditMode) {
            $sIsDeleteEnabled = $this->m_bDeleteEnabled ? 'true' : 'false';
            $iTransactionId = $oPage->GetTransactionId();
            $sClass = get_class($oObject);
            $sTempId = session_id() . '_' . $iTransactionId;
            $sDeleteBtn = Dict::S('Attachments:DeleteBtn');
            $oPage->add_script(<<<EOF
\tfunction RemoveAttachment(att_id)
\t{
\t\t\$('#attachment_'+att_id).attr('name', 'removed_attachments[]');
\t\t\$('#display_attachment_'+att_id).hide();
\t\t\$('#attachment_plugin').trigger('remove_attachment', [att_id]);
\t\treturn false; // Do not submit the form !
\t}
EOF
);
            $oPage->add('<span id="attachments">');
            while ($oAttachment = $oSet->Fetch()) {
                $iAttId = $oAttachment->GetKey();
                $oDoc = $oAttachment->Get('contents');
                $sFileName = $oDoc->GetFileName();
                $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName);
                $sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false';
                $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents';
                $oPage->add('<div class="attachment" id="display_attachment_' . $iAttId . '"><a data-preview="' . $sPreview . '" href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input id="attachment_' . $iAttId . '" type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/>&nbsp;<input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment(' . $iAttId . ');"/>&nbsp;</div>');
            }
            // Suggested attachments are listed here but treated as temporary
            $aDefault = utils::ReadParam('default', array(), false, 'raw_data');
            if (array_key_exists('suggested_attachments', $aDefault)) {
                $sSuggestedAttachements = $aDefault['suggested_attachments'];
                if (is_array($sSuggestedAttachements)) {
                    $sSuggestedAttachements = implode(',', $sSuggestedAttachements);
                }
                $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id IN({$sSuggestedAttachements})");
                $oSet = new DBObjectSet($oSearch, array());
                if ($oSet->Count() > 0) {
                    while ($oAttachment = $oSet->Fetch()) {
                        // Mark the attachments as temporary attachments for the current object/form
                        $oAttachment->Set('temp_id', $sTempId);
                        $oAttachment->DBUpdate();
                        // Display them
                        $iAttId = $oAttachment->GetKey();
                        $oDoc = $oAttachment->Get('contents');
                        $sFileName = $oDoc->GetFileName();
                        $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName);
                        $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents';
                        $sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false';
                        $oPage->add('<div class="attachment" id="display_attachment_' . $iAttId . '"><a data-preview="' . $sPreview . '" href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input id="attachment_' . $iAttId . '" type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/>&nbsp;<input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment(' . $iAttId . ');"/>&nbsp;</div>');
                        $oPage->add_ready_script("\$('#attachment_plugin').trigger('add_attachment', [{$iAttId}, '" . addslashes($sFileName) . "']);");
                    }
                }
            }
            $oPage->add('</span>');
            $oPage->add('<div style="clear:both"></div>');
            $sMaxUpload = $this->GetMaxUpload();
            $oPage->p(Dict::S('Attachments:AddAttachment') . '<input type="file" name="file" id="file"><span style="display:none;" id="attachment_loading">&nbsp;<img src="../images/indicator.gif"></span> ' . $sMaxUpload);
            $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.iframe-transport.js');
            $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.fileupload.js');
            $oPage->add_ready_script(<<<EOF
    \$('#file').fileupload({
\t\turl: GetAbsoluteUrlModulesRoot()+'itop-attachments/ajax.attachment.php',
\t\tformData: { operation: 'add', temp_id: '{$sTempId}', obj_class: '{$sClass}' },
        dataType: 'json',
\t\tpasteZone: null, // Don't accept files via Chrome's copy/paste
        done: function (e, data) {
\t\t\tif(typeof(data.result.error) != 'undefined')
\t\t\t{
\t\t\t\tif(data.result.error != '')
\t\t\t\t{
\t\t\t\t\talert(data.result.error);
\t\t\t\t}
\t\t\t\telse
\t\t\t\t{
\t\t\t\t\tvar sDownloadLink = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=download_document&class=Attachment&id='+data.result.att_id+'&field=contents';
\t\t\t\t\t\$('#attachments').append('<div class="attachment" id="display_attachment_'+data.result.att_id+'"><a data-preview="'+data.result.preview+'" href="'+sDownloadLink+'"><img src="'+data.result.icon+'"><br/>'+data.result.msg+'<input id="attachment_'+data.result.att_id+'" type="hidden" name="attachments[]" value="'+data.result.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveAttachment('+data.result.att_id+');"/></div>');
\t\t\t\t\tif({$sIsDeleteEnabled})
\t\t\t\t\t{
\t\t\t\t\t\t\$('#display_attachment_'+data.result.att_id).hover( function() { \$(this).children(':button').toggleClass('btn_hidden'); } );
\t\t\t\t\t}
\t\t\t\t\t\$('#attachment_plugin').trigger('add_attachment', [data.result.att_id, data.result.msg]);
\t\t\t\t}
\t\t\t}
        },
        start: function() {
        \t\$('#attachment_loading').show();
\t\t},
        stop: function() {
        \t\$('#attachment_loading').hide();
\t\t}
    });

\t\$(document).bind('dragover', function (e) {
\t\tvar bFiles = false;
\t\tif (e.dataTransfer && e.dataTransfer.types)
\t\t{
\t\t\tfor (var i = 0; i < e.dataTransfer.types.length; i++)
\t\t\t{
\t\t\t\tif (e.dataTransfer.types[i] == "application/x-moz-nativeimage")
\t\t\t\t{
\t\t\t\t\tbFiles = false; // mozilla contains "Files" in the types list when dragging images inside the page, but it also contains "application/x-moz-nativeimage" before
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (e.dataTransfer.types[i] == "Files")
\t\t\t\t{
\t\t\t\t\tbFiles = true;
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t}
\t
\t\tif (!bFiles) return; // Not dragging files
\t\t
\t\tvar dropZone = \$('#file').closest('fieldset');
\t\tif (!dropZone.is(':visible'))
\t\t{
\t\t\t// Hidden, but inside an inactive tab? Higlight the tab
\t\t\tvar sTabId = dropZone.closest('.ui-tabs-panel').attr('aria-labelledby');
\t\t\tdropZone = \$('#'+sTabId).closest('li');
\t\t}
\t    timeout = window.dropZoneTimeout;
\t    if (!timeout) {
\t        dropZone.addClass('drag_in');
\t    } else {
\t        clearTimeout(timeout);
\t    }
\t    window.dropZoneTimeout = setTimeout(function () {
\t        window.dropZoneTimeout = null;
\t        dropZone.removeClass('drag_in');
\t    }, 300);
\t});   
EOF
);
            $oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>');
            $oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
            if ($this->m_bDeleteEnabled) {
                $oPage->add_ready_script('$(".attachment").hover( function() {$(this).children(":button").toggleClass("btn_hidden"); } );');
            }
        } else {
            $oPage->add('<span id="attachments">');
            if ($oSet->Count() == 0) {
                $oPage->add(Dict::S('Attachments:NoAttachment'));
            } else {
                while ($oAttachment = $oSet->Fetch()) {
                    $iAttId = $oAttachment->GetKey();
                    $oDoc = $oAttachment->Get('contents');
                    $sFileName = $oDoc->GetFileName();
                    $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName);
                    $sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false';
                    $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents';
                    $oPage->add('<div class="attachment" id="attachment_' . $iAttId . '"><a data-preview="' . $sPreview . '" href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '</a><input type="hidden" name="attachments[]" value="' . $iAttId . '"/><br/>&nbsp;&nbsp;</div>');
                }
            }
            $oPage->add('</span>');
        }
        $oPage->add('</fieldset>');
        $sPreviewNotAvailable = addslashes(Dict::S('Attachments:PreviewNotAvailable'));
        $iMaxWidth = MetaModel::GetModuleSetting('itop-attachments', 'preview_max_width', 290);
        $oPage->add_ready_script("\$(document).tooltip({ items: '.attachment a',  position: { my: 'left top', at: 'right top', using: function( position, feedback ) { \$( this ).css( position ); }}, content: function() { if (\$(this).attr('data-preview') == 'true') { return('<img style=\"max-width:{$iMaxWidth}px\" src=\"'+\$(this).attr('href')+'\"></img>');} else { return '{$sPreviewNotAvailable}'; }}});");
    }
 public function add($sHtml)
 {
     if ($this->m_oTabs->GetCurrentTabContainer() != '' && $this->m_oTabs->GetCurrentTab() != '') {
         $this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
     } else {
         parent::add($sHtml);
     }
 }
    public function DisplayAttachments($oObject, WebPage $oPage, $bEditMode = false)
    {
        // Exit here if the class is not allowed
        if (!$this->IsTargetObject($oObject)) {
            return;
        }
        $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id");
        $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey()));
        if ($this->GetAttachmentsPosition() == 'relations') {
            $sTitle = $oSet->Count() > 0 ? Dict::Format('Attachments:TabTitle_Count', $oSet->Count()) : Dict::S('Attachments:EmptyTabTitle');
            $oPage->SetCurrentTab($sTitle);
        }
        $oPage->add_style(<<<EOF
.attachment {
\tdisplay: inline-block;
\ttext-align:center;
\tfloat:left;
\tpadding:5px;\t
}
.attachment:hover {
\tbackground-color: #e0e0e0;
}
.attachment img {
\tborder: 0;
}
.attachment a {
\ttext-decoration: none;
\tcolor: #1C94C4;
}
.btn_hidden {
\tdisplay: none;
}
EOF
);
        $oPage->add('<fieldset>');
        $oPage->add('<legend>' . Dict::S('Attachments:FieldsetTitle') . '</legend>');
        if ($bEditMode) {
            $sIsDeleteEnabled = $this->m_bDeleteEnabled ? 'true' : 'false';
            $iTransactionId = $oPage->GetTransactionId();
            $sClass = get_class($oObject);
            $sTempId = session_id() . '_' . $iTransactionId;
            $sDeleteBtn = Dict::S('Attachments:DeleteBtn');
            $oPage->add_script(<<<EOF
\tfunction RemoveNewAttachment(att_id)
\t{
\t\t\$('#attachment_'+att_id).attr('name', 'removed_attachments[]');
\t\t\$('#display_attachment_'+att_id).hide();
\t\t\$('#attachment_plugin').trigger('remove_attachment', [att_id]);
\t\treturn false; // Do not submit the form !
\t}
\tfunction ajaxFileUpload()
\t{
\t\t//starting setting some animation when the ajax starts and completes
\t\t\$("#attachment_loading").ajaxStart(function(){
\t\t\t\$(this).show();
\t\t}).ajaxComplete(function(){
\t\t\t\$(this).hide();
\t\t});
\t\t
\t\t/*
\t\t\tprepareing ajax file upload
\t\t\turl: the url of script file handling the uploaded files
                        fileElementId: the file type of input element id and it will be the index of  \$_FILES Array()
\t\t\tdataType: it support json, xml
\t\t\tsecureuri:use secure protocol
\t\t\tsuccess: call back function when the ajax complete
\t\t\terror: callback function when the ajax failed
\t\t\t
                */
\t\t\$.ajaxFileUpload
\t\t(
\t\t\t{
\t\t\t\turl: GetAbsoluteUrlModulesRoot()+'itop-attachments/ajax.attachment.php?obj_class={$sClass}&temp_id={$sTempId}&operation=add', 
\t\t\t\tsecureuri:false,
\t\t\t\tfileElementId:'file',
\t\t\t\tdataType: 'json',
\t\t\t\tsuccess: function (data, status)
\t\t\t\t{
\t\t\t\t\tif(typeof(data.error) != 'undefined')
\t\t\t\t\t{
\t\t\t\t\t\tif(data.error != '')
\t\t\t\t\t\t{
\t\t\t\t\t\t\talert(data.error);
\t\t\t\t\t\t}
\t\t\t\t\t\telse
\t\t\t\t\t\t{
\t\t\t\t\t\t\tvar sDownloadLink = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=download_document&class=Attachment&id='+data.att_id+'&field=contents';
\t\t\t\t\t\t\t\$('#attachments').append('<div class="attachment" id="display_attachment_'+data.att_id+'"><a href="'+sDownloadLink+'"><img src="'+data.icon+'"><br/>'+data.msg+'<input id="attachment_'+data.att_id+'" type="hidden" name="attachments[]" value="'+data.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveNewAttachment('+data.att_id+');"/></div>');
\t\t\t\t\t\t\tif({$sIsDeleteEnabled})
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\$('#display_attachment_'+data.att_id).hover( function() { \$(this).children(':button').toggleClass('btn_hidden'); } );
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\$('#attachment_plugin').trigger('add_attachment', [data.att_id, data.msg]);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t//alert(data.msg);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\terror: function (data, status, e)
\t\t\t\t{
\t\t\t\t\talert(e);
\t\t\t\t}
\t\t\t}
\t\t)
\t\t
\t\treturn false;

\t}
EOF
);
            $oPage->add('<span id="attachments">');
            while ($oAttachment = $oSet->Fetch()) {
                $iAttId = $oAttachment->GetKey();
                $oDoc = $oAttachment->Get('contents');
                $sFileName = $oDoc->GetFileName();
                $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName);
                $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents';
                $oPage->add('<div class="attachment" id="attachment_' . $iAttId . '"><a href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/>&nbsp;<input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="$(\'#attachment_' . $iAttId . '\').remove();"/>&nbsp;</div>');
            }
            // Suggested attachments are listed here but treated as temporary
            $aDefault = utils::ReadParam('default', array(), false, 'raw_data');
            if (array_key_exists('suggested_attachments', $aDefault)) {
                $sSuggestedAttachements = $aDefault['suggested_attachments'];
                if (is_array($sSuggestedAttachements)) {
                    $sSuggestedAttachements = implode(',', $sSuggestedAttachements);
                }
                $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id IN({$sSuggestedAttachements})");
                $oSet = new DBObjectSet($oSearch, array());
                if ($oSet->Count() > 0) {
                    while ($oAttachment = $oSet->Fetch()) {
                        // Mark the attachments as temporary attachments for the current object/form
                        $oAttachment->Set('temp_id', $sTempId);
                        $oAttachment->DBUpdate();
                        // Display them
                        $iAttId = $oAttachment->GetKey();
                        $oDoc = $oAttachment->Get('contents');
                        $sFileName = $oDoc->GetFileName();
                        $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName);
                        $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents';
                        $oPage->add('<div class="attachment" id="display_attachment_' . $iAttId . '"><a href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/>&nbsp;<input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="RemoveNewAttachment(' . $iAttId . ');"/>&nbsp;</div>');
                        $oPage->add_ready_script("\$('#attachment_plugin').trigger('add_attachment', [{$iAttId}, '" . addslashes($sFileName) . "']);");
                    }
                }
            }
            $oPage->add('</span>');
            $oPage->add('<div style="clear:both"></div>');
            $sMaxUpload = $this->GetMaxUpload();
            $oPage->p(Dict::S('Attachments:AddAttachment') . '<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading">&nbsp;<img src="../images/indicator.gif"></span> ' . $sMaxUpload);
            $oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>');
            $oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
            $oPage->add('</fieldset>');
            if ($this->m_bDeleteEnabled) {
                $oPage->add_ready_script('$(".attachment").hover( function() {$(this).children(":button").toggleClass("btn_hidden"); } );');
            }
        } else {
            $oPage->add('<span id="attachments">');
            if ($oSet->Count() == 0) {
                $oPage->add(Dict::S('Attachments:NoAttachment'));
            } else {
                while ($oAttachment = $oSet->Fetch()) {
                    $iAttId = $oAttachment->GetKey();
                    $oDoc = $oAttachment->Get('contents');
                    $sFileName = $oDoc->GetFileName();
                    $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName);
                    $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents';
                    $oPage->add('<div class="attachment" id="attachment_' . $iAttId . '"><a href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '</a><input type="hidden" name="attachments[]" value="' . $iAttId . '"/><br/>&nbsp;&nbsp;</div>');
                }
            }
        }
    }
    /**
     * Display the graph inside the given page, with the "filter" drawer above it
     * @param WebPage $oP
     * @param hash $aResults
     * @param string $sRelation
     * @param ApplicationContext $oAppContext
     * @param array $aExcludedObjects
     */
    function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects = array(), $sObjClass = null, $iObjKey = null, $sContextKey, $aContextParams = array())
    {
        $aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
        $aExcludedByClass = array();
        foreach ($aExcludedObjects as $oObj) {
            if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
                $aExcludedByClass[get_class($oObj)] = array();
            }
            $aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
        }
        $oP->add("<div class=\"not-printable\">\n");
        $oP->add("<div id=\"ds_flash\" class=\"SearchDrawer\" style=\"display:none;\">\n");
        if (!$oP->IsPrintableVersion()) {
            $oP->add_ready_script(<<<EOF
\t\$( "#tabbedContent_0" ).tabs({ heightStyle: "fill" });
EOF
);
        }
        $oP->add_ready_script(<<<EOF
\t\$("#dh_flash").click( function() {
\t\t\$("#ds_flash").slideToggle('normal', function() { \$("#ds_flash").parent().resize(); \$("#dh_flash").trigger('toggle_complete'); } );
\t\t\$("#dh_flash").toggleClass('open');
\t});
    \$('#ReloadMovieBtn').button().button('disable');
EOF
);
        $aSortedElements = array();
        foreach ($aResults as $sClassIdx => $aObjects) {
            foreach ($aObjects as $oCurrObj) {
                $sSubClass = get_class($oCurrObj);
                $aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
            }
        }
        asort($aSortedElements);
        $idx = 0;
        foreach ($aSortedElements as $sSubClass => $sClassName) {
            $oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_{$idx}\" name=\"excluded[]\" value=\"{$sSubClass}\" checked onChange=\"\$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_{$idx}\">&nbsp;" . MetaModel::GetClassIcon($sSubClass) . "&nbsp;{$sClassName}</label></span> ");
            $idx++;
        }
        $oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"DoReload()\">" . Dict::S('UI:Button:Refresh') . "</button></p>");
        $oP->add("</div>\n");
        $oP->add("<div class=\"HRDrawer\"></div>\n");
        $oP->add("<div id=\"dh_flash\" class=\"DrawerHandle\">" . Dict::S('UI:ElementsDisplayed') . "</div>\n");
        $oP->add("</div>\n");
        // class="not-printable"
        $aAdditionalContexts = array();
        foreach ($aContextDefs as $sKey => $aDefinition) {
            $aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => array_key_exists('default', $aDefinition) && $aDefinition['default'] == 'yes');
        }
        $sDirection = utils::ReadParam('d', 'horizontal');
        $iGroupingThreshold = utils::ReadParam('g', 5);
        $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/fraphael.js');
        $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot() . 'css/jquery.contextMenu.css');
        $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.contextMenu.js');
        $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/simple_graph.js');
        try {
            $this->InitFromGraphviz();
            $sExportAsPdfURL = '';
            $sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=relation_pdf&relation=' . $sRelation . '&direction=' . ($this->bDirectionDown ? 'down' : 'up');
            $oAppcontext = new ApplicationContext();
            $sContext = $oAppContext->GetForLink();
            $sDrillDownURL = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=details&class=%1$s&id=%2$s&' . $sContext;
            $sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=relation_attachment&relation=' . $sRelation . '&direction=' . ($this->bDirectionDown ? 'down' : 'up');
            $sLoadFromURL = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=relation_json&relation=' . $sRelation . '&direction=' . ($this->bDirectionDown ? 'down' : 'up');
            $sAttachmentExportTitle = '';
            if ($sObjClass != null && $iObjKey != null) {
                $oTargetObj = MetaModel::GetObject($sObjClass, $iObjKey, false);
                if ($oTargetObj) {
                    $sAttachmentExportTitle = Dict::Format('UI:Relation:AttachmentExportOptions_Name', $oTargetObj->GetName());
                }
            }
            $sId = 'graph';
            $sStyle = '';
            if ($oP->IsPrintableVersion()) {
                // Optimize for printing on A4/Letter vertically
                $sStyle = 'margin-left:auto; margin-right:auto;';
                $oP->add_ready_script("\$('.simple-graph').width(18/2.54*96).resizable({ stop: function() { \$(window).trigger('resized'); }});");
                // Default width about 18 cm, since most browsers assume 96 dpi
            }
            $oP->add('<div id="' . $sId . '" class="simple-graph" style="' . $sStyle . '"></div>');
            $aParams = array('source_url' => $sLoadFromURL, 'sources' => $this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects, 'excluded' => $aExcludedByClass, 'grouping_threshold' => $iGroupingThreshold, 'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')), 'export_as_attachment' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsAttachment'), 'obj_class' => $sObjClass, 'obj_key' => $iObjKey), 'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')), 'labels' => array('export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'), 'export_as_attachment_title' => $sAttachmentExportTitle, 'export' => Dict::S('UI:Button:Export'), 'cancel' => Dict::S('UI:Button:Cancel'), 'title' => Dict::S('UI:RelationOption:Title'), 'untitled' => Dict::S('UI:RelationOption:Untitled'), 'include_list' => Dict::S('UI:RelationOption:IncludeList'), 'comments' => Dict::S('UI:RelationOption:Comments'), 'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'), 'refresh' => Dict::S('UI:Button:Refresh'), 'check_all' => Dict::S('UI:SearchValue:CheckAll'), 'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'), 'none_selected' => Dict::S('UI:Relation:NoneSelected'), 'nb_selected' => Dict::S('UI:SearchValue:NbSelected'), 'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'), 'zoom' => Dict::S('UI:Relation:Zoom'), 'loading' => Dict::S('UI:Loading')), 'page_format' => array('label' => Dict::S('UI:Relation:PDFExportPageFormat'), 'values' => array('A3' => Dict::S('UI:PageFormat_A3'), 'A4' => Dict::S('UI:PageFormat_A4'), 'Letter' => Dict::S('UI:PageFormat_Letter'))), 'page_orientation' => array('label' => Dict::S('UI:Relation:PDFExportPageOrientation'), 'values' => array('P' => Dict::S('UI:PageOrientation_Portrait'), 'L' => Dict::S('UI:PageOrientation_Landscape'))), 'additional_contexts' => $aAdditionalContexts, 'context_key' => $sContextKey);
            if (!extension_loaded('gd')) {
                // PDF export requires GD
                unset($aParams['export_as_pdf']);
            }
            if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey)) {
                // Export as Attachment requires GD (for building the PDF) AND a valid objclass/objkey couple
                unset($aParams['export_as_attachment']);
            }
            $oP->add_ready_script("\$('#{$sId}').simple_graph(" . json_encode($aParams) . ");");
        } catch (Exception $e) {
            $oP->add('<div>' . $e->getMessage() . '</div>');
        }
        $oP->add_script(<<<EOF
\t\t
\tfunction DoReload()
\t{
\t\t\$('#ReloadMovieBtn').button('disable');
\t\ttry
\t\t{
\t\t\tvar aExcluded = [];
\t\t\t\$('input[name^=excluded]').each( function() {
\t\t\t\tif (!\$(this).prop('checked'))
\t\t\t\t{
\t\t\t\t\taExcluded.push(\$(this).val());
\t\t\t\t}
\t\t\t} );
\t\t\t\$('#graph').simple_graph('option', {excluded_classes: aExcluded});
\t\t\t\$('#graph').simple_graph('reload');
\t\t}
\t\tcatch(err)
\t\t{
\t\t\talert(err);
\t\t}
\t}
EOF
);
    }
 /**
  * Perform all the needed checks to delete one (or more) objects
  */
 public static function DeleteObjects(WebPage $oP, $sClass, $aObjects, $bPreview, $sCustomOperation, $aContextData = array())
 {
     $oDeletionPlan = new DeletionPlan();
     foreach ($aObjects as $oObj) {
         if ($bPreview) {
             $oObj->CheckToDelete($oDeletionPlan);
         } else {
             $oObj->DBDeleteTracked(CMDBObject::GetCurrentChange(), null, $oDeletionPlan);
         }
     }
     if ($bPreview) {
         if (count($aObjects) == 1) {
             $oObj = $aObjects[0];
             $oP->add("<h1>" . Dict::Format('UI:Delete:ConfirmDeletionOf_Name', $oObj->GetName()) . "</h1>\n");
         } else {
             $oP->add("<h1>" . Dict::Format('UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)) . "</h1>\n");
         }
         // Explain what should be done
         //
         $aDisplayData = array();
         foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) {
             foreach ($aDeletes as $iId => $aData) {
                 $oToDelete = $aData['to_delete'];
                 $bAutoDel = $aData['mode'] == DEL_SILENT || $aData['mode'] == DEL_AUTO;
                 if (array_key_exists('issue', $aData)) {
                     if ($bAutoDel) {
                         if (isset($aData['requested_explicitely'])) {
                             $sConsequence = Dict::Format('UI:Delete:CannotDeleteBecause', $aData['issue']);
                         } else {
                             $sConsequence = Dict::Format('UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible', $aData['issue']);
                         }
                     } else {
                         $sConsequence = Dict::Format('UI:Delete:MustBeDeletedManuallyButNotPossible', $aData['issue']);
                     }
                 } else {
                     if ($bAutoDel) {
                         if (isset($aData['requested_explicitely'])) {
                             $sConsequence = '';
                             // not applicable
                         } else {
                             $sConsequence = Dict::S('UI:Delete:WillBeDeletedAutomatically');
                         }
                     } else {
                         $sConsequence = Dict::S('UI:Delete:MustBeDeletedManually');
                     }
                 }
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToDelete)), 'object' => $oToDelete->GetHyperLink(), 'consequence' => $sConsequence);
             }
         }
         foreach ($oDeletionPlan->ListUpdates() as $sRemoteClass => $aToUpdate) {
             foreach ($aToUpdate as $iId => $aData) {
                 $oToUpdate = $aData['to_reset'];
                 if (array_key_exists('issue', $aData)) {
                     $sConsequence = Dict::Format('UI:Delete:CannotUpdateBecause_Issue', $aData['issue']);
                 } else {
                     $sConsequence = Dict::Format('UI:Delete:WillAutomaticallyUpdate_Fields', $aData['attributes_list']);
                 }
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToUpdate)), 'object' => $oToUpdate->GetHyperLink(), 'consequence' => $sConsequence);
             }
         }
         $iImpactedIndirectly = $oDeletionPlan->GetTargetCount() - count($aObjects);
         if ($iImpactedIndirectly > 0) {
             if (count($aObjects) == 1) {
                 $oObj = $aObjects[0];
                 $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencing_Object', $iImpactedIndirectly, $oObj->GetName()));
             } else {
                 $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencingTheObjects', $iImpactedIndirectly));
             }
             $oP->p(Dict::S('UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity'));
         }
         if ($iImpactedIndirectly > 0 || $oDeletionPlan->FoundStopper()) {
             $aDisplayConfig = array();
             $aDisplayConfig['class'] = array('label' => 'Class', 'description' => '');
             $aDisplayConfig['object'] = array('label' => 'Object', 'description' => '');
             $aDisplayConfig['consequence'] = array('label' => 'Consequence', 'description' => Dict::S('UI:Delete:Consequence+'));
             $oP->table($aDisplayConfig, $aDisplayData);
         }
         if ($oDeletionPlan->FoundStopper()) {
             if ($oDeletionPlan->FoundSecurityIssue()) {
                 $oP->p(Dict::S('UI:Delete:SorryDeletionNotAllowed'));
             } elseif ($oDeletionPlan->FoundManualOperation()) {
                 $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations'));
             } else {
                 $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations'));
             }
             $oAppContext = new ApplicationContext();
             $oP->add("<form method=\"post\">\n");
             $oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"" . utils::ReadParam('transaction_id') . "\">\n");
             $oP->add("<input type=\"button\" onclick=\"window.history.back();\" value=\"" . Dict::S('UI:Button:Back') . "\">\n");
             $oP->add("<input DISABLED type=\"submit\" name=\"\" value=\"" . Dict::S('UI:Button:Delete') . "\">\n");
             $oP->add($oAppContext->GetForForm());
             $oP->add("</form>\n");
         } else {
             if (count($aObjects) == 1) {
                 $oObj = $aObjects[0];
                 $id = $oObj->GetKey();
                 $oP->p('<h1>' . Dict::Format('UI:Delect:Confirm_Object', $oObj->GetHyperLink()) . '</h1>');
             } else {
                 $oP->p('<h1>' . Dict::Format('UI:Delect:Confirm_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)) . '</h1>');
             }
             foreach ($aObjects as $oObj) {
                 $aKeys[] = $oObj->GetKey();
             }
             $oFilter = new DBObjectSearch($sClass);
             $oFilter->AddCondition('id', $aKeys, 'IN');
             $oSet = new CMDBobjectSet($oFilter);
             $oP->add('<div id="0">');
             CMDBAbstractObject::DisplaySet($oP, $oSet, array('display_limit' => false, 'menu' => false));
             $oP->add("</div>\n");
             $oP->add("<form method=\"post\">\n");
             foreach ($aContextData as $sKey => $value) {
                 $oP->add("<input type=\"hidden\" name=\"{$sKey}\" value=\"{$value}\">\n");
             }
             $oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"" . utils::GetNewTransactionId() . "\">\n");
             $oP->add("<input type=\"hidden\" name=\"operation\" value=\"{$sCustomOperation}\">\n");
             $oP->add("<input type=\"hidden\" name=\"filter\" value=\"" . $oFilter->Serialize() . "\">\n");
             $oP->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n");
             foreach ($aObjects as $oObj) {
                 $oP->add("<input type=\"hidden\" name=\"selectObject[]\" value=\"" . $oObj->GetKey() . "\">\n");
             }
             $oP->add("<input type=\"button\" onclick=\"window.history.back();\" value=\"" . Dict::S('UI:Button:Back') . "\">\n");
             $oP->add("<input type=\"submit\" name=\"\" value=\"" . Dict::S('UI:Button:Delete') . "\">\n");
             $oAppContext = new ApplicationContext();
             $oP->add($oAppContext->GetForForm());
             $oP->add("</form>\n");
         }
     } else {
         // Execute the deletion
         //
         if (count($aObjects) == 1) {
             $oObj = $aObjects[0];
             $oP->add("<h1>" . Dict::Format('UI:Title:DeletionOf_Object', $oObj->GetName()) . "</h1>\n");
         } else {
             $oP->add("<h1>" . Dict::Format('UI:Title:BulkDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)) . "</h1>\n");
         }
         // Security - do not allow the user to force a forbidden delete by the mean of page arguments...
         if ($oDeletionPlan->FoundSecurityIssue()) {
             throw new CoreException(Dict::S('UI:Error:NotEnoughRightsToDelete'));
         }
         if ($oDeletionPlan->FoundManualOperation()) {
             throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseManualOpNeeded'));
         }
         if ($oDeletionPlan->FoundManualDelete()) {
             throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseOfDepencies'));
         }
         // Report deletions
         //
         $aDisplayData = array();
         foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) {
             foreach ($aDeletes as $iId => $aData) {
                 $oToDelete = $aData['to_delete'];
                 if (isset($aData['requested_explicitely'])) {
                     $sMessage = Dict::S('UI:Delete:Deleted');
                 } else {
                     $sMessage = Dict::S('UI:Delete:AutomaticallyDeleted');
                 }
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToDelete)), 'object' => $oToDelete->GetName(), 'consequence' => $sMessage);
             }
         }
         // Report updates
         //
         foreach ($oDeletionPlan->ListUpdates() as $sTargetClass => $aToUpdate) {
             foreach ($aToUpdate as $iId => $aData) {
                 $oToUpdate = $aData['to_reset'];
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToUpdate)), 'object' => $oToUpdate->GetHyperLink(), 'consequence' => Dict::Format('UI:Delete:AutomaticResetOf_Fields', $aData['attributes_list']));
             }
         }
         // Report automatic jobs
         //
         if ($oDeletionPlan->GetTargetCount() > 0) {
             if (count($aObjects) == 1) {
                 $oObj = $aObjects[0];
                 $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Object', $oObj->GetName()));
             } else {
                 $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)));
             }
             $aDisplayConfig = array();
             $aDisplayConfig['class'] = array('label' => 'Class', 'description' => '');
             $aDisplayConfig['object'] = array('label' => 'Object', 'description' => '');
             $aDisplayConfig['consequence'] = array('label' => 'Done', 'description' => Dict::S('UI:Delete:Done+'));
             $oP->table($aDisplayConfig, $aDisplayData);
         }
     }
 }
 public function DisplayDetails(WebPage $oPage, $bEditMode = false)
 {
     $oPage->add('<h1>' . MetaModel::GetName(get_class($this)) . ': ' . $this->GetName() . '</h1>');
     $aValues = array();
     $aList = MetaModel::FlattenZList(MetaModel::GetZListItems(get_class($this), 'details'));
     if (empty($aList)) {
         $aList = array_keys(MetaModel::ListAttributeDefs(get_class($this)));
     }
     foreach ($aList as $sAttCode) {
         $aValues[$sAttCode] = array('label' => MetaModel::GetLabel(get_class($this), $sAttCode), 'value' => $this->GetAsHTML($sAttCode));
     }
     $oPage->details($aValues);
 }