5 * Copyright 1999-2001 (c) VA Linux Systems
6 * Copyright 2010 - Alain Peyrat
7 * Copyright 2010-2011, Franck Villaume - Capgemini
8 * Copyright 2010-2011, Alain Peyrat - Alcatel-Lucent
9 * http://fusionforge.org
11 * This file is part of FusionForge.
13 * FusionForge is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * FusionForge is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with FusionForge; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 * Extends the basic Error class to add HTML functions
31 * for displaying all site dependent HTML, while allowing
32 * extendibility/overriding by themes via the Theme class.
34 * Make sure browser.php is included _before_ you create an instance
39 require_once $gfcommon.'include/constants.php';
40 require_once $gfcommon.'include/FusionForge.class.php';
41 require_once $gfcommon.'include/Navigation.class.php';
43 class Layout extends Error {
46 * Which doctype to use. Can be configured in the
47 * constructor. If set to 'strict', headerHTMLDeclaration will
48 * create a doctype definition that uses the strict doctype,
49 * otherwise it will use the transitional doctype.
50 * @var string $doctype
52 var $doctype = 'transitional';
55 * The default main page content
56 * @var string $rootindex
58 var $rootindex = 'index_std.php';
61 * The base directory of the theme in the servers file system
62 * @var string $themedir
67 * The base url of the theme
68 * @var string $themeurl
73 * The base directory of the image files in the servers file system
79 * The base url of the image files
80 * @var string $imgbaseurl
85 * The base directory of the js files in the servers file system
91 * The base url of the js files
92 * @var string $jsbaseurl
97 * The navigation object that provides the basic links. Should
103 * The color bars in pm reporting
105 var $COLOR_LTBACK1 = '#C0C0C0';
108 var $js_min = array();
109 var $javascripts = array();
111 var $css_min = array();
112 var $stylesheets = array();
115 * Layout() - Constructor
118 // parent constructor
121 $this->navigation = new Navigation();
123 // determine rootindex
124 if ( file_exists(forge_get_config('custom_path') . '/index_std.php') ) {
125 $this->rootindex = forge_get_config('custom_path') . '/index_std.php';
127 $this->rootindex = $GLOBALS['gfwww'].'index_std.php';
130 // determine theme{dir,url}
131 $this->themedir = forge_get_config('themes_root') . '/' . forge_get_config('default_theme') . '/';
132 if (!file_exists ($this->themedir)) {
133 html_error_top(_("Can't find theme directory!"));
136 $this->themeurl = util_make_url('themes/' . forge_get_config('default_theme') . '/');
138 // determine {css,img,js}{url,dir}
139 if (file_exists ($this->themedir . 'images/')) {
140 $this->imgdir = $this->themedir . 'images/';
141 $this->imgbaseurl = $this->themeurl . 'images/';
143 $this->imgdir = $this->themedir;
144 $this->imgbaseurl = $this->themeurl;
147 if (file_exists ($this->themedir . 'js/')) {
148 $this->jsdir = $this->themedir . 'js/';
149 $this->jsbaseurl = $this->themeurl . 'js/';
151 $this->jsdir = $this->themedir;
152 $this->jsbaseurl = $this->themeurl;
155 $this->addStylesheet('/themes/css/fusionforge.css');
160 * Constructs a list of Javascript files followed by some timestamp
162 * TODO document the purpose of this : probably to avoid caching versions updated on the server
163 * @param string $js path to the JS file
165 function addJavascript($js) {
166 // TODO : what's the point of this ? ... unused ?
167 if (isset($this->js_min[$js])) {
168 $js = $this->js_min[$js];
170 if ($js && !isset($this->js[$js])) {
171 $this->js[$js] = true;
172 $filename = $GLOBALS['fusionforge_basedir'].'/www'.$js;
173 if (file_exists($filename)) {
174 $js .= '?'.date ("U", filemtime($filename));
176 $filename = str_replace('/scripts/', $GLOBALS['fusionforge_basedir'].'/lib/vendor/', $js);
177 if (file_exists($filename)) {
178 $js .= '?'.date ("U", filemtime($filename));
181 $this->javascripts[] = $js;
185 function addStylesheet($css, $media='') {
186 if (isset($this->css_min[$css])) {
187 $css = $this->css_min[$css];
189 if (!isset($this->css[$css])) {
190 $this->css[$css] = true;
191 $filename = $GLOBALS['fusionforge_basedir'].'/www'.$css;
192 if (file_exists($filename)) {
193 $css .= '?'.date ("U", filemtime($filename));
195 $filename = str_replace('/scripts/', $GLOBALS['fusionforge_basedir'].'/lib/vendor/', $css);
196 if (file_exists($filename)) {
197 $css .= '?'.date ("U", filemtime($filename));
200 $this->stylesheets[] = array('css' => $css, 'media' => $media);
204 function getJavascripts() {
206 foreach ($this->javascripts as $js) {
207 $code .= ' <script type="text/javascript" src="'.$js.'"></script>'."\n";
212 function getStylesheets() {
214 foreach ($this->stylesheets as $c) {
216 $code .= ' <link rel="stylesheet" type="text/css" href="'.$c['css'].'" media="'.$c['media'].'" />'."\n";
218 $code .= ' <link rel="stylesheet" type="text/css" href="'.$c['css'].'"/>'."\n";
225 * header() - generates the complete header of page by calling
226 * headerStart() and bodyHeader().
228 function header($params) {
229 $this->headerStart($params); ?>
232 $this->bodyHeader($params);
236 * headerStart() - generates the header code for all themes up to the
238 * Override any of the methods headerHTMLDeclaration(), headerTitle(),
239 * headerFavIcon(), headerRSS(), headerSearch(), headerCSS(), or
240 * headerJS() to adapt your theme.
242 * @param array Header parameters array
244 function headerStart($params) {
245 $this->headerHTMLDeclaration();
248 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
250 plugin_hook('htmlhead', array());
251 $this->headerTitle($params);
252 $this->headerFavIcon();
254 $this->headerSearch();
257 $this->headerForgepluckerMeta();
264 * headerHTMLDeclaration() - generates the HTML declaration, i.e. the
265 * XML declaration, the doctype definition, and the opening <html>.
268 function headerHTMLDeclaration() {
269 print '<?xml version="1.0" encoding="utf-8"?>'."\n";
270 if (isset($this->doctype) && $this->doctype=='strict') {
271 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'."\n";
273 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
275 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'
276 . _('en') . '" lang="' . _('en') . '">'."\n";
280 * headerTitle() - creates the <title> header
282 * @param array Header parameters array
284 function headerTitle($params) {
285 echo $this->navigation->getTitle($params);
290 * headerFavIcon() - creates the favicon <link> headers.
293 function headerFavIcon() {
294 echo $this->navigation->getFavIcon();
298 * headerRSS() - creates the RSS <link> headers.
301 function headerRSS() {
302 echo $this->navigation->getRSS();
306 * headerSearch() - creates the search <link> header.
309 function headerSearch() {
310 echo '<link rel="search" title="'
311 . forge_get_config ('forge_name').'" href="'
312 . util_make_url ('/export/search_plugin.php')
313 . '" type="application/opensearchdescription+xml"/>'."\n";
317 * Create the CSS headers for all cssfiles in $cssfiles and
318 * calls the plugin cssfile hook.
320 function headerCSS() {
321 plugin_hook ('cssfile',$this);
322 echo $this->getStylesheets();
326 * headerJS() - creates the JS headers and calls the plugin javascript hook
327 * @todo generalize this
329 function headerJS() {
331 <script type="text/javascript" src="/scripts/prototype/prototype.js"></script>
332 <script type="text/javascript" src="/scripts/scriptaculous/scriptaculous.js"></script>
333 <script type="text/javascript" src="/scripts/codendi/Tooltip.js"></script>
334 <script type="text/javascript" src="/scripts/codendi/LayoutManager.js"></script>
335 <script type="text/javascript" src="/scripts/codendi/ReorderColumns.js"></script>
336 <script type="text/javascript" src="/scripts/codendi/codendi-1236793993.js"></script>
337 <script type="text/javascript" src="/scripts/codendi/validate.js"></script>
338 <script type="text/javascript" src="'. util_make_uri('/js/common.js') .'"></script>';
339 plugin_hook ("javascript_file",false);
340 echo $this->getJavascripts();
342 // invoke the 'javascript' hook for custom javascript addition
343 $params = array('return' => false);
344 plugin_hook("javascript",$params);
345 $javascript = $params['return'];
347 echo '<script type="text/javascript">';
354 function headerForgepluckerMeta() {
356 * Forge-Identification Meta Header, Version 1.0
357 * cf. http://home.gna.org/forgeplucker/forge-identification.html
359 $ff = new FusionForge();
360 return sprintf('<meta name="Forge-Identification" content="%s:%s" />',
362 $ff->software_version) . "\n";
365 function bodyHeader($params){
368 <table border="0" width="100%" cellspacing="0" cellpadding="0" id="headertable">
370 <td><a href="<?php echo util_make_url ('/'); ?>"><?php echo html_image('logo.png',198,52,array('border'=>'0')); ?></a></td>
371 <td><?php $this->searchBox(); ?></td>
372 <td align="right"><?php
373 $items = $this->navigation->getUserLinks();
374 for ($j = 0; $j < count($items['titles']); $j++) {
375 echo util_make_link($items['urls'][$j], $items['titles'][$j], array('class'=>'lnkutility'), true);
378 $params['template'] = ' {menu}';
379 plugin_hook('headermenu', $params);
384 <td> </td>
389 <table border="0" width="100%" cellspacing="0" cellpadding="0">
395 <?php echo $this->outerTabs($params); ?>
402 <td align="left" class="toptab" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/topleft.png" height="9" width="9" alt="" /></td>
403 <td class="toptab" width="30"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="30" height="1" alt="" /></td>
404 <td class="toptab"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="1" height="1" alt="" /></td>
405 <td class="toptab" width="30"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="30" height="1" alt="" /></td>
406 <td align="right" class="toptab" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/topright.png" height="9" width="9" alt="" /></td>
411 <!-- Outer body row -->
413 <td class="toptab"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="10" height="1" alt="" /></td>
414 <td valign="top" width="99%" class="toptab" colspan="3">
416 <!-- Inner Tabs / Shell -->
418 <table border="0" width="100%" cellspacing="0" cellpadding="0">
422 if (isset($params['group']) && $params['group']) {
430 echo $this->projectTabs($params['toptab'],$params['group']);
440 <td align="left" class="projecttab" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/topleft-inner.png" height="9" width="9" alt="" /></td>
441 <td class="projecttab" ><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="1" height="1" alt="" /></td>
442 <td align="right" class="projecttab" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/topright-inner.png" height="9" width="9" alt="" /></td>
446 <td class="projecttab" ><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="10" height="1" alt="" /></td>
447 <td valign="top" width="99%" class="projecttab">
453 function footer($params) {
457 <!-- end main body row -->
460 <td width="10" class="footer3" ><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="2" height="1" alt="" /></td>
463 <td align="left" class="footer1" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/bottomleft-inner.png" height="11" width="11" alt="" /></td>
464 <td class="footer3"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="1" height="1" alt="" /></td>
465 <td align="right" class="footer1" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/bottomright-inner.png" height="11" width="11" alt="" /></td>
469 <!-- end inner body row -->
472 <td width="10" class="footer2"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="2" height="1" alt="" /></td>
475 <td align="left" class="footer2" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/bottomleft.png" height="9" width="9" alt="" /></td>
476 <td class="footer2" colspan="3"><img src="<?php echo $this->imgbaseurl; ?>clear.png" width="1" height="1" alt="" /></td>
477 <td align="right" class="footer2" width="9"><img src="<?php echo $this->imgbaseurl; ?>tabs/bottomright.png" height="9" width="9" alt="" /></td>
481 $this->footerEnd($params);
484 function footerEnd($params) { ?>
486 <!-- PLEASE LEAVE "Powered By FusionForge" on your site -->
488 <?php echo $this->navigation->getPoweredBy(); ?>
491 <?php echo $this->navigation->getShowSource(); ?>
499 function getRootIndex() {
500 return $this->rootindex;
504 * boxTop() - Top HTML box.
506 * @param string Box title
507 * @return string the html code
509 function boxTop($title) {
511 <!-- Box Top Start -->
513 <table cellspacing="0" cellpadding="0" width="100%" border="0" style="background:url('.$this->imgbaseurl.'vert-grad.png)">
514 <tr class="align-center">
515 <td valign="top" align="right" width="10" style="background:url('.$this->imgbaseurl.'box-topleft.png)"><img src="'.$this->imgbaseurl.'clear.png" width="10" height="20" alt="" /></td>
516 <td width="100%" style="background:url('.$this->imgbaseurl.'box-grad.png)"><span class="titlebar">'.$title.'</span></td>
517 <td valign="top" width="10" style="background:url('.$this->imgbaseurl.'box-topright.png)"><img src="'.$this->imgbaseurl.'clear.png" width="10" height="20" alt="" /></td>
521 <table cellspacing="2" cellpadding="2" width="100%" border="0">
525 <!-- Box Top End -->';
529 * boxMiddle() - Middle HTML box.
531 * @param string Box title
532 * @return string The html code
534 function boxMiddle($title) {
536 <!-- Box Middle Start -->
539 <tr class="align-center">
540 <td colspan="2" style="background:url('.$this->imgbaseurl.'box-grad.png)"><span class="titlebar">'.$title.'</span></td>
544 <!-- Box Middle End -->';
548 * boxBottom() - Bottom HTML box.
550 * @return string the html code
552 function boxBottom() {
554 <!-- Box Bottom Start -->
561 <!-- Box Bottom End -->';
565 * boxGetAltRowStyle() - Get an alternating row style for tables.
567 * @param int Row number
568 * @return string the class code
570 function boxGetAltRowStyle($i) {
572 return ' class="altRowStyleEven"';
574 return ' class="altRowStyleOdd"';
579 * listTableTop() - Takes an array of titles and builds the first row of a new table.
581 * @param array The array of titles
582 * @param array The array of title links
583 * @param string The css classes to add (optional)
584 * @param string The id of the table (needed by sortable for example)
585 * @param array specific class for th column
586 * @return string the html code
588 function listTableTop($titleArray, $linksArray=false, $class='', $id='', $thClassArray=array()) {
591 $args .= ' class="listing '.$class.'"';
593 $args .= ' class="listing full"';
596 $args .= ' id="'.$id.'"';
601 if (count($titleArray)) {
602 $return .= '<thead><tr>';
604 $count=count($titleArray);
605 for ($i=0; $i<$count; $i++) {
607 if ($thClassArray && $thClassArray[$i]) {
608 $th .= ' class="'.$thClassArray[$i].'"';
610 $cell = $titleArray[$i];
612 $cell = util_make_link($linksArray[$i],$titleArray[$i]);
614 $return .= "\n".' <th'.$th.'>'.$cell.'</th>';
616 $return .= "\n".'</tr></thead>'."\n";
618 $return .= '<tbody>';
622 function listTableBottom() {
623 return '</tbody>'."\n".'</table>';
626 function outerTabs($params) {
627 $menu = $this->navigation->getSiteMenu();
628 echo $this->tabGenerator($menu['urls'], $menu['titles'], false, $menu['selected'], '');
632 * Prints out the quicknav menu, contained here in case we
633 * want to allow it to be overridden.
635 function quickNav() {
636 if (!session_loggedin()) {
639 // get all projects that the user belongs to
640 $groups = session_get_user()->getGroups();
642 if (count($groups) < 1) {
645 sortProjectList($groups);
648 <form id="quicknavform" name="quicknavform" action=""><div>
649 <select name="quicknav" id="quicknav" onChange="location.href=document.quicknavform.quicknav.value">
650 <option value="">'._('Quick Jump To...').'</option>';
652 foreach ($groups as $g) {
653 $group_id = $g->getID();
654 $menu = $this->navigation->getProjectMenu($group_id);
657 <option value="' . $menu['starturl'] . '">'
658 . $menu['name'] .'</option>';
660 for ($j = 0; $j < count($menu['urls']); $j++) {
662 <option value="' . $menu['urls'][$j] .'"> '
663 . $menu['titles'][$j] . '</option>';
664 if (@$menu['adminurls'][$j]) {
666 <option value="' . $menu['adminurls'][$j]
667 . '"> '
668 . _('Admin') . '</option>';
680 * projectTabs() - Prints out the project tabs, contained here in case
681 * we want to allow it to be overriden.
683 * @param string Is the tab currently selected
684 * @param string Is the group we should look up get title info
686 function projectTabs($toptab, $group_id) {
687 // get group info using the common result set
688 $menu = $this->navigation->getProjectMenu($group_id, $toptab);
689 echo $this->tabGenerator($menu['urls'], $menu['titles'], true, $menu['selected'], 'white');
692 function tabGenerator($TABS_DIRS,$TABS_TITLES,$nested=false,$selected=false,$sel_tab_bgcolor='white',$total_width='100%') {
694 $count=count($TABS_DIRS);
695 $width=intval((100/$count));
700 <table class="tabGenerator" ';
702 if ($total_width != '100%') {
703 $return .= 'style="width:' . $total_width . ';"';
713 for ($i=0; $i<$count; $i++) {
716 // this is the first tab, choose an image with end-name
719 $issel=($selected==$i);
720 $bgimg=(($issel)?'theme-'.$inner.'-selected-bg.png':'theme-'.$inner.'-notselected-bg.png');
721 // $rowspan=(($issel)?'rowspan="2" ' : '');
724 <td '.$rowspan.'valign="top" width="10" style="background:url('.$this->imgbaseurl . 'theme-'.$inner.'-end-'.(($issel) ? '' : 'not').'selected.png)">'.
725 '<img src="'.$this->imgbaseurl . 'clear.png" height="25" width="10" alt="" /></td>'.
726 '<td '.$rowspan.'style="background:url('.$this->imgbaseurl . $bgimg.')" width="'.$width.'%" align="center">'.util_make_link ($TABS_DIRS[$i],$TABS_TITLES[$i],array('class'=>(($issel)?'tabsellink':'tablink')),true).'</td>';
727 } elseif ($i==$count-1) {
729 // this is the last tab, choose an image with name-end
731 $wassel=($selected==$i-1);
732 $issel=($selected==$i);
733 $bgimg=(($issel)?'theme-'.$inner.'-selected-bg.png':'theme-'.$inner.'-notselected-bg.png');
734 // $rowspan=(($issel)?'rowspan="2" ' : '');
736 // Build image between current and prior tab
739 <td '.$rowspan.'colspan="2" valign="top" width="20" style="background:url('.$this->imgbaseurl . 'theme-'.$inner.'-'.(($wassel) ? '' : 'not').'selected-'.(($issel) ? '' : 'not').'selected.png)">'.
740 '<img src="'.$this->imgbaseurl . 'clear.png" height="2" width="20" alt="" /></td>'.
741 '<td '.$rowspan.'style="background:url('.$this->imgbaseurl . $bgimg.')" width="'.$width.'%" align="center">'.util_make_link ($TABS_DIRS[$i],$TABS_TITLES[$i],array('class'=>(($issel)?'tabsellink':'tablink')),true).'</td>';
743 // Last graphic on right-side
746 <td '.$rowspan.'valign="top" width="10" style="background:url('.$this->imgbaseurl . 'theme-'.$inner.'-'.(($issel) ? '' : 'not').'selected-end.png)">'.
747 '<img src="'.$this->imgbaseurl . 'clear.png" height="2" width="10" alt="" /></td>';
753 $wassel=($selected==$i-1);
754 $issel=($selected==$i);
755 $bgimg=(($issel)?'theme-'.$inner.'-selected-bg.png':'theme-'.$inner.'-notselected-bg.png');
756 // $rowspan=(($issel)?'rowspan="2" ' : '');
758 // Build image between current and prior tab
761 <td '.$rowspan.'colspan="2" valign="top" width="20" style="background:url('.$this->imgbaseurl . 'theme-'.$inner.'-'.(($wassel) ? '' : 'not').'selected-'.(($issel) ? '' : 'not').'selected.png)">'.
762 '<img src="'.$this->imgbaseurl . 'clear.png" height="2" width="20" alt="" /></td>'.
763 '<td '.$rowspan.'style="background:url('.$this->imgbaseurl . $bgimg.')" width="'.$width.'%" align="center">'.util_make_link ($TABS_DIRS[$i],$TABS_TITLES[$i],array('class'=>(($issel)?'tabsellink':'tablink')),true).'</td>';
770 // Building a bottom row in this table, which will be darker
772 if ($selected == 0) {
774 $end_cols=((count($TABS_DIRS)*3)-3);
775 } elseif ($selected == (count($TABS_DIRS)-1)) {
776 $beg_cols=((count($TABS_DIRS)*3)-3);
779 $beg_cols=($selected*3);
780 $end_cols=(((count($TABS_DIRS)*3)-3)-$beg_cols);
784 $return .= '<td colspan="'.$beg_cols.'" height="1" class="notSelTab"><img src="'.$this->imgbaseurl.'clear.png" height="1" width="10" alt="" /></td>';
786 $return .= '<td colspan="3" height="1" class="selTab"><img src="'.$this->imgbaseurl.'clear.png" height="1" width="10" alt="" /></td>';
788 $return .= '<td colspan="'.$end_cols.'" height="1" class="notSelTab"><img src="'.$this->imgbaseurl.'clear.png" height="1" width="10" alt="" /></td>';
800 function searchBox() {
801 echo $this->navigation->getSearchBox();
805 * beginSubMenu() - Opening a submenu.
807 * @return string Html to start a submenu.
809 function beginSubMenu() {
816 * endSubMenu() - Closing a submenu.
818 * @return string Html to end a submenu.
820 function endSubMenu() {
821 $return = '</strong></p>';
826 * printSubMenu() - Takes two array of titles and links and builds the contents of a menu.
828 * @param array The array of titles.
829 * @param array The array of title links.
830 * @param array The array of string for title attributes.
831 * @return string Html to build a submenu.
833 function printSubMenu($title_arr, $links_arr, $attr_arr) {
834 $count=count($title_arr);
838 for ($i=0; $i<$count; $i++) {
839 $return .= util_make_link($links_arr[$i],$title_arr[$i],$attr_arr[$i]).' | ';
841 $return .= util_make_link($links_arr[$i],$title_arr[$i],$attr_arr[$i]);
846 * subMenu() - Takes two array of titles and links and build a menu.
848 * @param array The array of titles.
849 * @param array The array of title links.
850 * @param array The array of string for title attributes.
851 * @return string Html to build a submenu.
853 function subMenu($title_arr, $links_arr, $attr_arr = false) {
854 $return = $this->beginSubMenu();
855 $return .= $this->printSubMenu($title_arr, $links_arr, $attr_arr);
856 $return .= $this->endSubMenu();
861 * multiTableRow() - create a mutlilevel row in a table
863 * @param string the row attributes
864 * @param array the array of cell data, each element is an array,
865 * the first item being the text,
866 * the subsequent items are attributes (dont include
867 * the bgcolor for the title here, that will be
868 * handled by $istitle
869 * @param boolean is this row part of the title ?
870 * @return string the html code
872 function multiTableRow($row_attr, $cell_data, $istitle) {
876 $return .=' class="align-center multiTableRowTitle"';
879 for ( $c = 0; $c < count($cell_data); $c++ ) {
881 for ( $a=1; $a < count($cell_data[$c]); $a++) {
882 $return .= $cell_data[$c][$a].' ';
886 $return .='<span class="multiTableRowTitle">';
888 $return .= $cell_data[$c][0];
902 * feedback() - returns the htmlized feedback string when an action is performed.
904 * @param string feedback string
905 * @return string htmlized feedback
907 function feedback($feedback) {
912 <div class="feedback">'.strip_tags($feedback, '<br>').'</div>';
916 * warning_msg() - returns the htmlized warning string when an action is performed.
918 * @param string msg string
919 * @return string htmlized warning
921 function warning_msg($msg) {
926 <div class="warning_msg">'.strip_tags($msg, '<br>').'</div>';
931 * error_msg() - returns the htmlized error string when an action is performed.
933 * @param string msg string
934 * @return string htmlized error
936 function error_msg($msg) {
941 <div class="error">'.strip_tags($msg, '<br>').'</div>';
947 * getThemeIdFromName()
949 * @param string the dirname of the theme
950 * @return integer the theme id
952 function getThemeIdFromName($dirname) {
953 $res = db_query_params ('SELECT theme_id FROM themes WHERE dirname=$1',
955 return db_result($res,0,'theme_id');
958 function confirmBox($msg, $params, $buttons, $image='*none*') {
959 if ($image == '*none*') {
960 $image = html_image('stop.png','48','48',array());
963 foreach ($params as $b => $v) {
964 $prms[] = '<input type="hidden" name="'.$b.'" value="'.$v.'" />'."\n";
966 $prm = join(' ', $prms);
968 foreach ($buttons as $b => $v) {
969 $btns[] = '<input type="submit" name="'.$b.'" value="'.$v.'" />'."\n";
971 $btn = join(' '."\n ", $btns);
974 <div id="infobox" style="margin-top: 15%; margin-left: 15%; margin-right: 15%; text-align: center;">
975 <table align="center">
978 <td>'.$msg.'<br/></td>
981 <td colspan="2" align="center">
983 <form action="' . getStringFromServer('PHP_SELF') . '" method="get" >
994 function html_input($name, $id = '', $label = '', $type = 'text', $value = '', $extra_params = '') {
998 $return = '<div class="field-holder">
1001 $return .= '<label for="' . $id . '">' . $label . '</label>
1004 $return .= '<input id="' . $id . '" type="' . $type . '"';
1005 //if input is a submit then name is not present
1007 $return .= ' name="' . $name . '"';
1010 $return .= ' value="' . $value . '"';
1012 if (is_array($extra_params)) {
1013 foreach ($extra_params as $key => $extra_params_value) {
1014 $return .= $key . '="' . $extra_params_value . '" ';
1022 function html_checkbox($name, $value, $id = '', $label = '', $checked = '', $extra_params = '') {
1026 $return = '<div class="field-holder">
1028 $return .= '<input name="' . $name . '" id="' . $id . '" type="checkbox" value="' . $value . '" ';
1030 $return .= 'checked="checked" ';
1032 if (is_array($extra_params)) {
1033 foreach ($extra_params as $key => $extra_params_value) {
1034 $return .= $key . '="' . $extra_params_value . '" ';
1039 $return .= '<label for="' . $id . '">' . $label . '</label>
1042 $return .= '</div>';
1046 function html_text_input_img_submit($name, $img_src, $id = '', $label = '', $value = '', $img_title = '', $img_alt = '', $extra_params = '', $img_extra_params = '') {
1054 $img_alt = $img_title;
1056 $return = '<div class="field-holder">
1059 $return .= '<label for="' . $id . '">' . $label . '</label>
1062 $return .= '<input id="' . $id . '" type="text" name="' . $name . '"';
1064 $return .= ' value="' . $value . '"';
1066 if (is_array($extra_params)) {
1067 foreach ($extra_params as $key => $extra_params_value) {
1068 $return .= $key . '="' . $extra_params_value . '" ';
1072 <input type="image" id="' . $id . '_submit" src="' . $this->imgbaseurl . $img_src . '" alt="' . $img_alt . '" title="' . $img_title . '"';
1073 if (is_array($img_extra_params)) {
1074 foreach ($img_extra_params as $key => $img_extra_params_value) {
1075 $return .= $key . '="' . $img_extra_params_value . '" ';
1083 function html_select($vals, $name, $label = '', $id = '', $checked_val = '', $text_is_value = false, $extra_params = '') {
1087 $return = '<div class="field-holder">
1090 $return .= '<label for="' . $id . '">' . $label . '</label>
1093 $return .= '<select name="' . $name . '" id="' . $id . '" ';
1094 if (is_array($extra_params)) {
1095 foreach ($extra_params as $key => $extra_params_value) {
1096 $return .= $key . '="' . $extra_params_value . '" ';
1100 $rows = count($vals);
1101 for ($i = 0; $i < $rows; $i++) {
1102 if ( $text_is_value ) {
1104 <option value="' . $vals[$i] . '"';
1105 if ($vals[$i] == $checked_val) {
1106 $return .= ' selected="selected"';
1110 <option value="' . $i . '"';
1111 if ($i == $checked_val) {
1112 $return .= ' selected="selected"';
1115 $return .= '>' . htmlspecialchars($vals[$i]) . '</option>';
1123 function html_textarea($name, $id = '', $label = '', $value = '', $extra_params = '') {
1127 $return = '<div class="field-holder">
1130 $return .= '<label for="' . $id . '">' . $label . '</label>
1133 $return .= '<textarea id="' . $id . '" name="' . $name . '" ';
1134 if (is_array($extra_params)) {
1135 foreach ($extra_params as $key => $extra_params_value) {
1136 $return .= $key . '="' . $extra_params_value . '" ';
1143 $return .= '</textarea>
1149 * @todo use listTableTop and make this function deprecated ?
1151 function html_table_top($cols, $summary = '', $class = '', $extra_params = '') {
1152 $return = '<table summary="' . $summary . '" ';
1154 $return .= 'class="' . $class . '" ';
1156 if (is_array($extra_params)) {
1157 foreach ($extra_params as $key => $extra_params_value) {
1158 $return .= $key . '="' . $extra_params_value . '" ';
1162 $return .= '<thead><tr>';
1163 $nbCols = count($cols);
1164 for ($i = 0; $i < $nbCols; $i++) {
1165 $return .= '<th scope="col">' . $cols[$i] . '</th>';
1167 $return .= '</tr></thead>';
1171 function getMonitorPic($title = '', $alt = '') {
1172 return $this->getPicto('ic/mail16w.png', $title, $alt, '15', '15');
1175 function getReleaseNotesPic($title = '', $alt = '') {
1176 return $this->getPicto('ic/manual16c.png', $title, $alt, '15', '15');
1179 /* no picto for download */
1180 function getDownloadPic($title = '', $alt = '') {
1181 return $this->getPicto('ic/save.png', $title, $alt, '15', '15');
1184 function getHomePic($title = '', $alt = '') {
1185 return $this->getPicto('ic/home16b.png', $title, $alt);
1188 function getFollowPic($title = '', $alt = '') {
1189 return $this->getPicto('ic/tracker20g.png', $title, $alt);
1192 function getForumPic($title = '', $alt = '') {
1193 return $this->getPicto('ic/forum20g.png', $title, $alt);;
1196 function getDocmanPic($title = '', $alt = '') {
1197 return $this->getPicto('ic/docman16b.png', $title, $alt);
1200 function getMailPic($title = '', $alt = '') {
1201 return $this->getPicto('ic/mail16b.png', $title, $alt);
1204 function getPmPic($title = '', $alt = '') {
1205 return $this->getPicto('ic/taskman20g.png', $title, $alt);
1208 function getSurveyPic($title = '', $alt = '') {
1209 return $this->getPicto('ic/survey16b.png', $title, $alt);
1212 function getScmPic($title = '', $alt = '') {
1213 return $this->getPicto('ic/cvs16b.png', $title, $alt);
1216 function getFtpPic($title = '', $alt = '') {
1217 return $this->getPicto('ic/ftp16b.png', $title, $alt);
1220 function getPicto($url, $title, $alt, $width = '20', $height = '20') {
1224 return html_image($url, $width, $height, array('title'=>$title, 'alt'=>$alt));
1228 * toSlug() - protect a string to be used as a link or an anchor
1230 * @param string $string the string used as a link or an anchor
1231 * @param string $space the caracter used as a replacement for a space
1232 * @return a protected string with only alphanumeric caracters
1234 function toSlug($string, $space = "-") {
1235 if (function_exists('iconv')) {
1236 $string = @iconv('UTF-8', 'ASCII//TRANSLIT', $string);
1238 $string = preg_replace("/[^a-zA-Z0-9- ]/", "-", $string);
1239 $string = strtolower($string);
1240 $string = str_replace(" ", $space, $string);
1244 function widget(&$widget, $layout_id, $readonly, $column_id, $is_minimized, $display_preferences, $owner_id, $owner_type) {
1245 $element_id = 'widget_'. $widget->id .'-'. $widget->getInstanceId();
1246 echo '<div class="widget" id="'. $element_id .'">';
1247 echo '<div class="widget_titlebar '. ($readonly?'':'widget_titlebar_handle') .'">';
1248 echo '<div class="widget_titlebar_title">'. $widget->getTitle() .'</div>';
1250 echo '<div class="widget_titlebar_close"><a href="/widgets/updatelayout.php?owner='. $owner_type.$owner_id .'&action=widget&name['. $widget->id .'][remove]='. $widget->getInstanceId() .'&column_id='. $column_id .'&layout_id='. $layout_id .'">'. $this->getPicto('ic/close.png', 'Close','Close') .'</a></div>';
1251 if ($is_minimized) {
1252 echo '<div class="widget_titlebar_maximize"><a href="/widgets/updatelayout.php?owner='. $owner_type.$owner_id .'&action=maximize&name['. $widget->id .']='. $widget->getInstanceId() .'&column_id='. $column_id .'&layout_id='. $layout_id .'">'. $this->getPicto($this->_getTogglePlusForWidgets(), 'Maximize', 'Maximize') .'</a></div>';
1254 echo '<div class="widget_titlebar_minimize"><a href="/widgets/updatelayout.php?owner='. $owner_type.$owner_id .'&action=minimize&name['. $widget->id .']='. $widget->getInstanceId() .'&column_id='. $column_id .'&layout_id='. $layout_id .'">'. $this->getPicto($this->_getToggleMinusForWidgets(), 'Minimize', 'Minimize') .'</a></div>';
1256 if (strlen($widget->hasPreferences())) {
1257 echo '<div class="widget_titlebar_prefs"><a href="/widgets/updatelayout.php?owner='. $owner_type.$owner_id .'&action=preferences&name['. $widget->id .']='. $widget->getInstanceId() .'&layout_id='. $layout_id .'">'. _('Preferences') .'</a></div>';
1260 if ($widget->hasRss()) {
1261 echo '<div class="widget_titlebar_rss"><a href="'.$widget->getRssUrl($owner_id, $owner_type).'">rss</a></div>';
1265 if ($is_minimized) {
1266 $style = 'display:none;';
1268 echo '<div class="widget_content" style="'. $style .'">';
1269 if (!$readonly && $display_preferences) {
1270 echo '<div class="widget_preferences">'. $widget->getPreferencesForm($layout_id, $owner_id, $owner_type) .'</div>';
1272 if ($widget->isAjax()) {
1273 echo '<div id="'. $element_id .'-ajax">';
1274 echo '<noscript><iframe width="99%" frameborder="0" src="'. $widget->getIframeUrl($owner_id, $owner_type) .'"></iframe></noscript>';
1277 echo $widget->getContent();
1280 if ($widget->isAjax()) {
1281 echo '<script type="text/javascript">'."
1282 document.observe('dom:loaded', function () {
1283 $('$element_id-ajax').update('<div style=\"text-align:center\">". $this->getPicto('ic/spinner.gif','spinner','spinner') ."</div>');
1284 new Ajax.Updater('$element_id-ajax',
1285 '". $widget->getAjaxUrl($owner_id, $owner_type) ."'
1293 function _getTogglePlusForWidgets() {
1294 return 'ic/toggle_plus.png';
1297 function _getToggleMinusForWidgets() {
1298 return 'ic/toggle_minus.png';
1301 /* Get the navigation links for the software map pages (trove,
1302 * tag cloud, full project list) according to what's enabled
1304 function printSoftwareMapLinks() {
1305 $subMenuTitle = array();
1306 $subMenuUrl = array();
1308 if (forge_get_config('use_project_tags')) {
1309 $subMenuTitle[] = _('Tag cloud');
1310 $subMenuUrl[] = '/softwaremap/tag_cloud.php';
1313 if (forge_get_config('use_trove')) {
1314 $subMenuTitle[] = _('Project Tree');
1315 $subMenuUrl[] = '/softwaremap/trove_list.php';
1318 if (forge_get_config('use_project_full_list')) {
1319 $subMenuTitle[] = _('Project List');
1320 $subMenuUrl[] = '/softwaremap/full_list.php';
1323 echo $this->subMenu($subMenuTitle, $subMenuUrl);
1329 // c-file-style: "bsd"