diff --git a/application/webpage.class.inc.php b/application/webpage.class.inc.php index bc47c52ea..8a7cd06e7 100644 --- a/application/webpage.class.inc.php +++ b/application/webpage.class.inc.php @@ -31,41 +31,48 @@ Interface Page { public function output(); + public function add($sText); + public function p($sText); + public function pre($sText); + public function add_comment($sText); + public function table($aConfig, $aData, $aParams = array()); } - /** - * Simple helper class to ease the production of HTML pages + *

Simple helper class to ease the production of HTML pages * - * This class provide methods to add content, scripts, includes... to a web page + *

This class provide methods to add content, scripts, includes... to a web page * and renders the full web page by putting the elements in the proper place & order * when the output() method is called. - * Usage: - * $oPage = new WebPage("Title of my page"); - * $oPage->p("Hello World !"); - * $oPage->output(); + * + *

Usage: + * ```php + * $oPage = new WebPage("Title of my page"); + * $oPage->p("Hello World !"); + * $oPage->output(); + * ``` */ class WebPage implements Page { - protected $s_title; - protected $s_content; - protected $s_deferred_content; - protected $a_scripts; - protected $a_dict_entries; - protected $a_dict_entries_prefixes; - protected $a_styles; - protected $a_linked_scripts; - protected $a_linked_stylesheets; - protected $a_headers; - protected $a_base; - protected $iNextId; - protected $iTransactionId; + protected $s_title; + protected $s_content; + protected $s_deferred_content; + protected $a_scripts; + protected $a_dict_entries; + protected $a_dict_entries_prefixes; + protected $a_styles; + protected $a_linked_scripts; + protected $a_linked_stylesheets; + protected $a_headers; + protected $a_base; + protected $iNextId; + protected $iTransactionId; protected $sContentType; protected $sContentDisposition; protected $sContentFileName; @@ -73,241 +80,256 @@ class WebPage implements Page protected $s_sOutputFormat; protected $a_OutputOptions; protected $bPrintable; - - public function __construct($s_title, $bPrintable = false) - { - $this->s_title = $s_title; - $this->s_content = ""; - $this->s_deferred_content = ''; - $this->a_scripts = array(); - $this->a_dict_entries = array(); - $this->a_dict_entries_prefixes = array(); - $this->a_styles = array(); - $this->a_linked_scripts = array(); - $this->a_linked_stylesheets = array(); - $this->a_headers = array(); - $this->a_base = array( 'href' => '', 'target' => ''); - $this->iNextId = 0; - $this->iTransactionId = 0; - $this->sContentType = ''; - $this->sContentDisposition = ''; - $this->sContentFileName = ''; + + public function __construct($s_title, $bPrintable = false) + { + $this->s_title = $s_title; + $this->s_content = ""; + $this->s_deferred_content = ''; + $this->a_scripts = array(); + $this->a_dict_entries = array(); + $this->a_dict_entries_prefixes = array(); + $this->a_styles = array(); + $this->a_linked_scripts = array(); + $this->a_linked_stylesheets = array(); + $this->a_headers = array(); + $this->a_base = array('href' => '', 'target' => ''); + $this->iNextId = 0; + $this->iTransactionId = 0; + $this->sContentType = ''; + $this->sContentDisposition = ''; + $this->sContentFileName = ''; $this->bTrashUnexpectedOutput = false; $this->s_OutputFormat = utils::ReadParam('output_format', 'html'); $this->a_OutputOptions = array(); $this->bPrintable = $bPrintable; - ob_start(); // Start capturing the output - } - + ob_start(); // Start capturing the output + } + /** * Change the title of the page after its creation */ - public function set_title($s_title) - { - $this->s_title = $s_title; - } - + public function set_title($s_title) + { + $this->s_title = $s_title; + } + /** * Specify a default URL and a default target for all links on a page */ - public function set_base($s_href = '', $s_target = '') - { - $this->a_base['href'] = $s_href; - $this->a_base['target'] = $s_target; - } - + public function set_base($s_href = '', $s_target = '') + { + $this->a_base['href'] = $s_href; + $this->a_base['target'] = $s_target; + } + /** * Add any text or HTML fragment to the body of the page */ - public function add($s_html) - { - $this->s_content .= $s_html; - } - + public function add($s_html) + { + $this->s_content .= $s_html; + } + /** * Add any text or HTML fragment (identified by an ID) at the end of the body of the page * This is useful to add hidden content, DIVs or FORMs that should not - * be embedded into each other. + * be embedded into each other. */ - public function add_at_the_end($s_html, $sId = '') - { - $this->s_deferred_content .= $s_html; - } - + public function add_at_the_end($s_html, $sId = '') + { + $this->s_deferred_content .= $s_html; + } + /** * Add a paragraph to the body of the page */ - public function p($s_html) - { - $this->add($this->GetP($s_html)); - } - + public function p($s_html) + { + $this->add($this->GetP($s_html)); + } + /** * Add a pre-formatted text to the body of the page */ - public function pre($s_html) - { - $this->add('

'.$s_html.'
'); - } - + public function pre($s_html) + { + $this->add('
'.$s_html.'
'); + } + /** * Add a comment */ - public function add_comment($sText) - { - $this->add(''); - } + public function add_comment($sText) + { + $this->add(''); + } + /** * Add a paragraph to the body of the page */ - public function GetP($s_html) - { - return "

$s_html

\n"; - } - + public function GetP($s_html) + { + return "

$s_html

\n"; + } + /** - * Adds a tabular content to the web page + * Adds a tabular content to the web page * * @param string[] $aConfig Configuration of the table: hash array of 'column_id' => 'Column Label' - * @param string[] $aData Hash array. Data to display in the table: each row is made of 'column_id' => Data. A column 'pkey' is expected for each row + * @param string[] $aData Hash array. Data to display in the table: each row is made of 'column_id' => Data. A + * column 'pkey' is expected for each row * @param array $aParams Hash array. Extra parameters for the table. * - * @return void - */ + * @return void + */ public function table($aConfig, $aData, $aParams = array()) { $this->add($this->GetTable($aConfig, $aData, $aParams)); } - + public function GetTable($aConfig, $aData, $aParams = array()) { $oAppContext = new ApplicationContext(); - + static $iNbTables = 0; $iNbTables++; $sHtml = ""; $sHtml .= "\n"; $sHtml .= "\n"; $sHtml .= "\n"; - foreach($aConfig as $sName=>$aDef) + foreach ($aConfig as $sName => $aDef) { $sHtml .= "\n"; } $sHtml .= "\n"; $sHtml .= "\n"; $sHtml .= "\n"; - foreach($aData as $aRow) + foreach ($aData as $aRow) { $sHtml .= $this->GetTableRow($aRow, $aConfig); } $sHtml .= "\n"; $sHtml .= "
".$aDef['label']."
\n"; + return $sHtml; } - + public function GetTableRow($aRow, $aConfig) { $sHtml = ''; if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows { - $sHtml .= ""; + $sHtml .= ""; } else { $sHtml .= ""; } - foreach($aConfig as $sName=>$aAttribs) + foreach ($aConfig as $sName => $aAttribs) { $sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : ''; $sValue = ($aRow[$sName] === '') ? ' ' : $aRow[$sName]; $sHtml .= "$sValue"; } $sHtml .= ""; - return $sHtml; + + return $sHtml; } - - /** - * Add some Javascript to the header of the page - */ - public function add_script($s_script) - { - $this->a_scripts[] = $s_script; - } - - /** - * Add some Javascript to the header of the page - */ - public function add_ready_script($s_script) - { - // Do nothing silently... this is not supported by this type of page... - } /** - * Add a dictionary entry for the Javascript side + * Add some Javascript to the header of the page */ - public function add_dict_entry($s_entryId) - { - $this->a_dict_entries[] = $s_entryId; - } - - /** - * Add a set of dictionary entries (based on the given prefix) for the Javascript side - */ - public function add_dict_entries($s_entriesPrefix) - { - $this->a_dict_entries_prefixes[] = $s_entriesPrefix; - } - - protected function get_dict_signature() - { - return str_replace('_', '', Dict::GetUserLanguage()).'-'.md5(implode(',', $this->a_dict_entries).'|'.implode(',', $this->a_dict_entries_prefixes)); - } - - protected function get_dict_file_content() - { - $aEntries = array(); - foreach($this->a_dict_entries as $sCode) - { - $aEntries[$sCode] = Dict::S($sCode); - } - foreach($this->a_dict_entries_prefixes as $sPrefix) - { - $aEntries = array_merge($aEntries, Dict::ExportEntries($sPrefix)); - } - $sJSFile = 'var aDictEntries = '.json_encode($aEntries); - - return $sJSFile; - } - + public function add_script($s_script) + { + $this->a_scripts[] = $s_script; + } + + /** + * Add some Javascript to the header of the page + */ + public function add_ready_script($s_script) + { + // Do nothing silently... this is not supported by this type of page... + } + + /** + * Allow a dictionnary entry to be used client side with Dict.S() + * + * @param string $s_entryId a translation label key + * + * @see \WebPage::add_dict_entries() + * @see utils.js + */ + public function add_dict_entry($s_entryId) + { + $this->a_dict_entries[] = $s_entryId; + } + + /** + * Add a set of dictionary entries (based on the given prefix) for the Javascript side + * + * @param string $s_entriesPrefix translation label prefix (eg 'UI:Button:' to add all keys beginning with this) + * + * @see \WebPage::add_dict_entry() + * @see utils.js + */ + public function add_dict_entries($s_entriesPrefix) + { + $this->a_dict_entries_prefixes[] = $s_entriesPrefix; + } + + protected function get_dict_signature() + { + return str_replace('_', '', Dict::GetUserLanguage()).'-'.md5(implode(',', + $this->a_dict_entries).'|'.implode(',', $this->a_dict_entries_prefixes)); + } + + protected function get_dict_file_content() + { + $aEntries = array(); + foreach ($this->a_dict_entries as $sCode) + { + $aEntries[$sCode] = Dict::S($sCode); + } + foreach ($this->a_dict_entries_prefixes as $sPrefix) + { + $aEntries = array_merge($aEntries, Dict::ExportEntries($sPrefix)); + } + $sJSFile = 'var aDictEntries = '.json_encode($aEntries); + + return $sJSFile; + } + /** * Add some CSS definitions to the header of the page */ - public function add_style($s_style) - { - $this->a_styles[] = $s_style; - } + public function add_style($s_style) + { + $this->a_styles[] = $s_style; + } /** * Add a script (as an include, i.e. link) to the header of the page */ - public function add_linked_script($s_linked_script) - { - $this->a_linked_scripts[$s_linked_script] = $s_linked_script; - } + public function add_linked_script($s_linked_script) + { + $this->a_linked_scripts[$s_linked_script] = $s_linked_script; + } /** * Add a CSS stylesheet (as an include, i.e. link) to the header of the page */ - public function add_linked_stylesheet($s_linked_stylesheet, $s_condition = "") - { - $this->a_linked_stylesheets[] = array( 'link' => $s_linked_stylesheet, 'condition' => $s_condition); - } + public function add_linked_stylesheet($s_linked_stylesheet, $s_condition = "") + { + $this->a_linked_stylesheets[] = array('link' => $s_linked_stylesheet, 'condition' => $s_condition); + } public function add_saas($sSaasRelPath) { $sCssRelPath = utils::GetCSSFromSASS($sSaasRelPath); - $sRootUrl = utils::GetAbsoluteUrlAppRoot(); + $sRootUrl = utils::GetAbsoluteUrlAppRoot(); if ($sRootUrl === '') { // We're running the setup of the first install... @@ -316,22 +338,23 @@ class WebPage implements Page $sCSSUrl = $sRootUrl.$sCssRelPath; $this->add_linked_stylesheet($sCSSUrl); } + /** * Add some custom header to the page */ - public function add_header($s_header) - { - $this->a_headers[] = $s_header; - } + public function add_header($s_header) + { + $this->a_headers[] = $s_header; + } /** * Add needed headers to the page so that it will no be cached */ - public function no_cache() - { - $this->add_header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - $this->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past - } + public function no_cache() + { + $this->add_header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + $this->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past + } /** * Build a special kind of TABLE useful for displaying the details of an object from a hash array of data @@ -340,53 +363,58 @@ class WebPage implements Page { $this->add($this->GetDetails($aFields)); - } - - /** - * Whether or not the page is a PDF page - * @return boolean - */ - public function is_pdf() - { - return false; - } + } + + /** + * Whether or not the page is a PDF page + * + * @return boolean + */ + public function is_pdf() + { + return false; + } /** * Records the current state of the 'html' part of the page output + * * @return mixed The current state of the 'html' output - */ - public function start_capture() - { - return strlen($this->s_content); - } - - /** - * Returns the part of the html output that occurred since the call to start_capture - * and removes this part from the current html output - * @param $offset mixed The value returned by start_capture - * @return string The part of the html output that was added since the call to start_capture - */ - public function end_capture($offset) - { - $sCaptured = substr($this->s_content, $offset); - $this->s_content = substr($this->s_content, 0, $offset); - return $sCaptured; - } - + */ + public function start_capture() + { + return strlen($this->s_content); + } + + /** + * Returns the part of the html output that occurred since the call to start_capture + * and removes this part from the current html output + * + * @param $offset mixed The value returned by start_capture + * + * @return string The part of the html output that was added since the call to start_capture + */ + public function end_capture($offset) + { + $sCaptured = substr($this->s_content, $offset); + $this->s_content = substr($this->s_content, 0, $offset); + + return $sCaptured; + } + /** * Build a special kind of TABLE useful for displaying the details of an object from a hash array of data */ public function GetDetails($aFields) { $sHtml = "
\n"; - foreach($aFields as $aAttrib) + foreach ($aFields as $aAttrib) { $sDataAttCode = isset($aAttrib['attcode']) ? "data-attcode=\"{$aAttrib['attcode']}\"" : ''; $sLayout = isset($aAttrib['layout']) ? $aAttrib['layout'] : 'small'; - $sHtml .= "
\n"; - $sHtml .= "
{$aAttrib['label']}
\n"; + $sHtml .= "
\n"; + $sHtml .= "
{$aAttrib['label']}
\n"; - $sHtml .= "
\n"; + $sHtml .= "
\n"; // By Rom, for csv import, proposed to show several values for column selection if (is_array($aAttrib['value'])) { @@ -399,24 +427,26 @@ class WebPage implements Page // Checking if we should add comments & infos $sComment = (isset($aAttrib['comments'])) ? $aAttrib['comments'] : ''; $sInfo = (isset($aAttrib['infos'])) ? $aAttrib['infos'] : ''; - if($sComment !== '') - { - $sHtml .= "
$sComment
\n"; - } - if($sInfo !== '') - { - $sHtml .= "
$sInfo
\n"; - } + if ($sComment !== '') + { + $sHtml .= "
$sComment
\n"; + } + if ($sInfo !== '') + { + $sHtml .= "
$sInfo
\n"; + } $sHtml .= "
\n"; $sHtml .= "
\n"; } $sHtml .= "
\n"; + return $sHtml; - } + } /** * Build a set of radio buttons suitable for editing a field/attribute of an object (including its validation) + * * @param $aAllowedValues hash Array of value => display_value * @param $value mixed Current value for the field/attribute * @param $iId mixed Unique Id for the input control in the page @@ -424,15 +454,17 @@ class WebPage implements Page * @param $bMandatory bool Whether or not the field is mandatory * @param $bVertical bool Disposition of the radio buttons vertical or horizontal * @param $sValidationField string HTML fragment holding the validation field (exclamation icon...) + * * @return string The HTML fragment corresponding to the radio buttons */ - public function GetRadioButtons($aAllowedValues, $value, $iId, $sFieldName, $bMandatory, $bVertical, $sValidationField) - { + public function GetRadioButtons( + $aAllowedValues, $value, $iId, $sFieldName, $bMandatory, $bVertical, $sValidationField + ) { $idx = 0; $sHTMLValue = ''; - foreach($aAllowedValues as $key => $display_value) + foreach ($aAllowedValues as $key => $display_value) { - if ((count($aAllowedValues) == 1) && ($bMandatory == 'true') ) + if ((count($aAllowedValues) == 1) && ($bMandatory == 'true')) { // When there is only once choice, select it by default $sSelected = ' checked'; @@ -447,25 +479,26 @@ class WebPage implements Page if ($idx == 0) { // Validation icon at the end of the first line - $sHTMLValue .= " {$sValidationField}\n"; + $sHTMLValue .= " {$sValidationField}\n"; } $sHTMLValue .= "
\n"; } $idx++; } $sHTMLValue .= ""; - if (!$bVertical) + if (!$bVertical) { // Validation icon at the end of the line $sHTMLValue .= " {$sValidationField}\n"; } + return $sHTMLValue; } - + /** * Discard unexpected output data (such as PHP warnings) * This is a MUST when the Page output is DATA (download of a document, download CSV export, download ...) - */ + */ public function TrashUnexpectedOutput() { $this->bTrashUnexpectedOutput = true; @@ -475,10 +508,10 @@ class WebPage implements Page * Read the output buffer and deal with its contents: * - trash unexpected output if the flag has been set * - report unexpected behaviors such as the output buffering being stopped - * + * * Possible improvement: I've noticed that several output buffers are stacked, * if they are not empty, the output will be corrupted. The solution would - * consist in unstacking all of them (and concatenate the contents). + * consist in unstacking all of them (and concatenate the contents). */ protected function ob_get_clean_safe() { @@ -511,55 +544,56 @@ class WebPage implements Page $sOutput = ''; } } + return $sOutput; } /** * Outputs (via some echo) the complete HTML page by assembling all its elements */ - public function output() - { - foreach($this->a_headers as $s_header) - { - header($s_header); - } + public function output() + { + foreach ($this->a_headers as $s_header) + { + header($s_header); + } - $s_captured_output = $this->ob_get_clean_safe(); - echo "\n"; - echo "\n"; - echo "\n"; + $s_captured_output = $this->ob_get_clean_safe(); + echo "\n"; + echo "\n"; + echo "\n"; echo "\n"; echo ""; - echo "".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."\n"; - echo $this->get_base_tag(); - - $this->output_dict_entries(); - - foreach($this->a_linked_scripts as $s_script) - { - // Make sure that the URL to the script contains the application's version number - // so that the new script do NOT get reloaded from the cache when the application is upgraded - if (strpos($s_script, '?') === false) - { - $s_script .= "?t=".utils::GetCacheBusterTimestamp(); - } - else - { - $s_script .= "&t=".utils::GetCacheBusterTimestamp(); - } - echo "\n"; - } - if (count($this->a_scripts)>0) - { - echo "\n"; - } - foreach($this->a_linked_stylesheets as $a_stylesheet) - { + echo "".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."\n"; + echo $this->get_base_tag(); + + $this->output_dict_entries(); + + foreach ($this->a_linked_scripts as $s_script) + { + // Make sure that the URL to the script contains the application's version number + // so that the new script do NOT get reloaded from the cache when the application is upgraded + if (strpos($s_script, '?') === false) + { + $s_script .= "?t=".utils::GetCacheBusterTimestamp(); + } + else + { + $s_script .= "&t=".utils::GetCacheBusterTimestamp(); + } + echo "\n"; + } + if (count($this->a_scripts) > 0) + { + echo "\n"; + } + foreach ($this->a_linked_stylesheets as $a_stylesheet) + { if (strpos($a_stylesheet['link'], '?') === false) { $s_stylesheet = $a_stylesheet['link']."?t=".utils::GetCacheBusterTimestamp(); @@ -577,48 +611,48 @@ class WebPage implements Page { echo "\n"; } - } - - if (count($this->a_styles)>0) - { - echo "\n"; - } - if (class_exists('MetaModel') && MetaModel::GetConfig()) - { - echo "\n"; - } - echo "\n"; - echo "\n"; - echo self::FilterXSS($this->s_content); - if (trim($s_captured_output) != "") - { - echo "
".self::FilterXSS($s_captured_output)."
\n"; - } - echo '
'.self::FilterXSS($this->s_deferred_content).'
'; - echo "\n"; - echo "\n"; + } - if (class_exists('DBSearch')) - { - DBSearch::RecordQueryTrace(); - } - if (class_exists('ExecutionKPI')) - { - ExecutionKPI::ReportStats(); - } - } + if (count($this->a_styles) > 0) + { + echo "\n"; + } + if (class_exists('MetaModel') && MetaModel::GetConfig()) + { + echo "\n"; + } + echo "\n"; + echo "\n"; + echo self::FilterXSS($this->s_content); + if (trim($s_captured_output) != "") + { + echo "
".self::FilterXSS($s_captured_output)."
\n"; + } + echo '
'.self::FilterXSS($this->s_deferred_content).'
'; + echo "\n"; + echo "\n"; + + if (class_exists('DBSearch')) + { + DBSearch::RecordQueryTrace(); + } + if (class_exists('ExecutionKPI')) + { + ExecutionKPI::ReportStats(); + } + } /** * Build a series of hidden field[s] from an array */ public function add_input_hidden($sLabel, $aData) { - foreach($aData as $sKey => $sValue) + foreach ($aData as $sKey => $sValue) { // Note: protection added to protect against the Notice 'array to string conversion' that appeared with PHP 5.4 // (this function seems unused though!) @@ -632,24 +666,26 @@ class WebPage implements Page protected function get_base_tag() { $sTag = ''; - if (($this->a_base['href'] != '') || ($this->a_base['target'] != '')) - { - $sTag = 'a_base['href'] != '')) - { - $sTag .= "href =\"{$this->a_base['href']}\" "; + if (($this->a_base['href'] != '') || ($this->a_base['target'] != '')) + { + $sTag = 'a_base['href'] != '')) + { + $sTag .= "href =\"{$this->a_base['href']}\" "; } - if (($this->a_base['target'] != '')) - { - $sTag .= "target =\"{$this->a_base['target']}\" "; + if (($this->a_base['target'] != '')) + { + $sTag .= "target =\"{$this->a_base['target']}\" "; } $sTag .= " />\n"; } + return $sTag; } - + /** * Get an ID (for any kind of HTML tag) that is guaranteed unique in this page + * * @return int The unique ID (in this page) */ public function GetUniqueId() @@ -659,18 +695,22 @@ class WebPage implements Page /** * Set the content-type (mime type) for the page's content + * * @param $sContentType string + * * @return void */ public function SetContentType($sContentType) { $this->sContentType = $sContentType; } - + /** * Set the content-disposition (mime type) for the page's content + * * @param $sDisposition string The disposition: 'inline' or 'attachment' * @param $sFileName string The original name of the file + * * @return void */ public function SetContentDisposition($sDisposition, $sFileName) @@ -678,33 +718,37 @@ class WebPage implements Page $this->sContentDisposition = $sDisposition; $this->sContentFileName = $sFileName; } - + /** * Set the transactionId of the current form + * * @param $iTransactionId integer + * * @return void */ public function SetTransactionId($iTransactionId) { $this->iTransactionId = $iTransactionId; } - + /** * Returns the transactionId of the current form + * * @return integer The current transactionID */ public function GetTransactionId() { return $this->iTransactionId; } - + public static function FilterXSS($sHTML) { return str_ireplace('bPrintable; } - /** + /** * Retrieves the value of a named output option for the given format + * * @param string $sFormat The format: html or pdf * @param string $sOptionName The name of the option + * * @return mixed false if the option was never set or the options's value */ public function GetOutputOption($sFormat, $sOptionName) @@ -754,10 +804,13 @@ class WebPage implements Page { return $this->a_OutputOptions[$sFormat][$sOptionName]; } + return false; } + /** * Sets a named output option for the given format + * * @param string $sFormat The format for which to set the option: html or pdf * @param string $sOptionName the name of the option * @param mixed $sValue The value of the option @@ -773,7 +826,7 @@ class WebPage implements Page $this->a_OutputOptions[$sFormat][$sOptionName] = $sValue; } } - + public function RenderPopupMenuItems($aActions, $aFavoriteActions = array()) { $sPrevUrl = ''; @@ -783,13 +836,14 @@ class WebPage implements Page foreach ($aActions as $aAction) { $sClass = isset($aAction['css_classes']) ? ' class="'.implode(' ', $aAction['css_classes']).'"' : ''; - $sOnClick = isset($aAction['onclick']) ? ' onclick="'.htmlspecialchars($aAction['onclick'], ENT_QUOTES, "UTF-8").'"' : ''; + $sOnClick = isset($aAction['onclick']) ? ' onclick="'.htmlspecialchars($aAction['onclick'], ENT_QUOTES, + "UTF-8").'"' : ''; $sTarget = isset($aAction['target']) ? " target=\"{$aAction['target']}\"" : ""; if (empty($aAction['url'])) { if ($sPrevUrl != '') // Don't output consecutively two separators... { - $sHtml .= "
  • {$aAction['label']}
  • "; + $sHtml .= "
  • {$aAction['label']}
  • "; } $sPrevUrl = ''; } @@ -800,12 +854,13 @@ class WebPage implements Page } } $sHtml .= "
    "; - foreach(array_reverse($aFavoriteActions) as $aAction) + foreach (array_reverse($aFavoriteActions) as $aAction) { $sTarget = isset($aAction['target']) ? " target=\"{$aAction['target']}\"" : ""; - $sHtml .= "
    {$aAction['label']}
    "; + $sHtml .= "
    {$aAction['label']}
    "; } - } + } + return $sHtml; } @@ -824,7 +879,8 @@ class WebPage implements Page file_put_contents($sJSFileName, $this->get_dict_file_content()); } // Load the dictionary as the first javascript file, so that other JS file benefit from the translations - array_unshift($this->a_linked_scripts, utils::GetAbsoluteUrlAppRoot().'pages/ajax.document.php?operation=dict&s='.$sSignature); + array_unshift($this->a_linked_scripts, + utils::GetAbsoluteUrlAppRoot().'pages/ajax.document.php?operation=dict&s='.$sSignature); } } } @@ -840,27 +896,30 @@ interface iTabbedPage public function SetCurrentTabContainer($sTabContainer = ''); public function SetCurrentTab($sTabLabel = ''); - + /** * Add a tab which content will be loaded asynchronously via the supplied URL - * + * * Limitations: - * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server. - * Static content cannot be added inside such tabs. - * + * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to + * pull content from another server. Static content cannot be added inside such tabs. + * * @param string $sTabLabel The (localised) label of the tab * @param string $sUrl The URL to load (on the same server) - * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation. + * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause + * the tab to be reloaded upon each activation. + * * @since 2.0.3 */ public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true); - + public function GetCurrentTab(); public function RemoveTab($sTabLabel, $sTabContainer = null); /** * Finds the tab whose title matches a given pattern + * * @return mixed The name of the tab as a string or false if not found */ public function FindTab($sPattern, $sTabContainer = null); @@ -874,17 +933,18 @@ class TabManager protected $m_aTabs; protected $m_sCurrentTabContainer; protected $m_sCurrentTab; - + public function __construct() { $this->m_aTabs = array(); $this->m_sCurrentTabContainer = ''; $this->m_sCurrentTab = ''; } - + public function AddTabContainer($sTabContainer, $sPrefix = '') { $this->m_aTabs[$sTabContainer] = array('prefix' => $sPrefix, 'tabs' => array()); + return "\$Tabs:$sTabContainer\$"; } @@ -892,37 +952,43 @@ class TabManager { $this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml); } - + public function GetCurrentTabLength($sHtml) { - $iLength = isset($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html']) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html']): 0; + $iLength = isset($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html']) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html']) : 0; + return $iLength; } - + /** * Truncates the given tab to the specifed length and returns the truncated part + * * @param string $sTabContainer The tab container in which to truncate the tab * @param string $sTab The name/identifier of the tab to truncate * @param integer $iLength The length/offset at which to truncate the tab + * * @return string The truncated part */ public function TruncateTab($sTabContainer, $sTab, $iLength) { - $sResult = substr($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'], $iLength); - $this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'] = substr($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'], 0, $iLength); - return $sResult; + $sResult = substr($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'], + $iLength); + $this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'] = substr($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'], + 0, $iLength); + + return $sResult; } - + public function TabExists($sTabContainer, $sTab) { return isset($this->m_aTabs[$sTabContainer]['tabs'][$sTab]); } - + public function TabsContainerCount() { return count($this->m_aTabs); } - + public function AddToTab($sTabContainer, $sTabLabel, $sHtml) { if (!isset($this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel])) @@ -942,6 +1008,7 @@ class TabManager // Append to the content of the tab $this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel]['html'] .= $sHtml; } + return ''; // Nothing to add to the page for now } @@ -949,6 +1016,7 @@ class TabManager { $sPreviousTabContainer = $this->m_sCurrentTabContainer; $this->m_sCurrentTabContainer = $sTabContainer; + return $sPreviousTabContainer; } @@ -956,19 +1024,22 @@ class TabManager { $sPreviousTab = $this->m_sCurrentTab; $this->m_sCurrentTab = $sTabLabel; + return $sPreviousTab; } - + /** * Add a tab which content will be loaded asynchronously via the supplied URL - * + * * Limitations: - * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server. - * Static content cannot be added inside such tabs. - * + * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to + * pull content from another server. Static content cannot be added inside such tabs. + * * @param string $sTabLabel The (localised) label of the tab * @param string $sUrl The URL to load (on the same server) - * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation. + * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause + * the tab to be reloaded upon each activation. + * * @since 2.0.3 */ public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true) @@ -979,15 +1050,16 @@ class TabManager 'url' => $sUrl, 'cache' => $bCache, ); + return ''; // Nothing to add to the page for now } - - + + public function GetCurrentTabContainer() { return $this->m_sCurrentTabContainer; } - + public function GetCurrentTab() { return $this->m_sCurrentTab; @@ -1003,9 +1075,9 @@ class TabManager { // Delete the content of the tab unset($this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel]); - + // If we just removed the active tab, let's reset the active tab - if (($this->m_sCurrentTabContainer == $sTabContainer) && ($this->m_sCurrentTab == $sTabLabel)) + if (($this->m_sCurrentTabContainer == $sTabContainer) && ($this->m_sCurrentTab == $sTabLabel)) { $this->m_sCurrentTab = ''; } @@ -1014,6 +1086,7 @@ class TabManager /** * Finds the tab whose title matches a given pattern + * * @return mixed The actual name of the tab (as a string) or false if not found */ public function FindTab($sPattern, $sTabContainer = null) @@ -1023,7 +1096,7 @@ class TabManager { $sTabContainer = $this->m_sCurrentTabContainer; } - foreach($this->m_aTabs[$sTabContainer]['tabs'] as $sTabLabel => $void) + foreach ($this->m_aTabs[$sTabContainer]['tabs'] as $sTabLabel => $void) { if (preg_match($sPattern, $sTabLabel)) { @@ -1031,6 +1104,7 @@ class TabManager break; } } + return $result; } @@ -1044,11 +1118,11 @@ class TabManager { $container_index = 0; $tab_index = 0; - foreach($this->m_aTabs as $sCurrentTabContainerName => $aTabs) + foreach ($this->m_aTabs as $sCurrentTabContainerName => $aTabs) { if ($sTabContainer == $sCurrentTabContainerName) { - foreach($aTabs['tabs'] as $sCurrentTabLabel => $void) + foreach ($aTabs['tabs'] as $sCurrentTabLabel => $void) { if ($sCurrentTabLabel == $sTabLabel) { @@ -1061,13 +1135,14 @@ class TabManager $container_index++; } $sSelector = '#tabbedContent_'.$container_index.' > ul'; + return "window.setTimeout(\"$('$sSelector').tabs('select', $tab_index);\", 100);"; // Let the time to the tabs widget to initialize } - + public function RenderIntoContent($sContent, WebPage $oPage) { // Render the tabs in the page (if any) - foreach($this->m_aTabs as $sTabContainerName => $aTabs) + foreach ($this->m_aTabs as $sTabContainerName => $aTabs) { $sTabs = ''; $sPrefix = $aTabs['prefix']; @@ -1077,37 +1152,39 @@ class TabManager if ($oPage->IsPrintableVersion()) { $oPage->add_ready_script( -<<< EOF + <<< EOF oHiddeableChapters = {}; EOF ); $sTabs = "\n
    \n"; $i = 0; - foreach($aTabs['tabs'] as $sTabName => $aTabData) + foreach ($aTabs['tabs'] as $sTabName => $aTabData) { $sTabNameEsc = addslashes($sTabName); $sTabId = "tab_{$sPrefix}{$container_index}$i"; - switch($aTabData['type']) + switch ($aTabData['type']) { case 'ajax': - $sTabHtml = ''; - $sUrl = $aTabData['url']; - $oPage->add_ready_script( -<<< EOF + $sTabHtml = ''; + $sUrl = $aTabData['url']; + $oPage->add_ready_script( + <<< EOF $.post('$sUrl', {printable: '1'}, function(data){ $('#$sTabId > .printable-tab-content').append(data); }); EOF - ); - break; - + ); + break; + case 'html': default: - $sTabHtml = $aTabData['html']; + $sTabHtml = $aTabData['html']; } - $sTabs .= "

    ".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."

    ".$sTabHtml."
    \n"; + $sTabs .= "

    ".htmlentities($sTabName, + ENT_QUOTES, + 'UTF-8')."

    ".$sTabHtml."
    \n"; $oPage->add_ready_script( -<<< EOF + <<< EOF oHiddeableChapters['$sTabId'] = '$sTabNameEsc'; EOF ); @@ -1121,34 +1198,36 @@ EOF $sTabs .= "\n"; // Now add the content of the tabs themselves $i = 0; - foreach($aTabs['tabs'] as $sTabName => $aTabData) + foreach ($aTabs['tabs'] as $sTabName => $aTabData) { - switch($aTabData['type']) + switch ($aTabData['type']) { case 'ajax': - // Nothing to add - break; - + // Nothing to add + break; + case 'html': default: - $sTabs .= "
    ".$aTabData['html']."
    \n"; + $sTabs .= "
    ".$aTabData['html']."
    \n"; } $i++; } @@ -1158,6 +1237,7 @@ EOF $sContent = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $sContent); $container_index++; } + return $sContent; } } \ No newline at end of file diff --git a/js/utils.js b/js/utils.js index d9dc291a8..979f4f007 100644 --- a/js/utils.js +++ b/js/utils.js @@ -688,6 +688,10 @@ function Format() { return str; } +/** + * Enable to access translation keys client side. + * The called keys needs to be exported using \WebPage::add_dict_entry + */ var Dict = {}; if (typeof aDictEntries == 'undefined') { Dict._entries = {}; // Entries have not been loaded (we are in the setup ?)