5 * Copyright 1999-2001 (c) VA Linux Systems
6 * Copyright 2010 (c) FusionForge Team
7 * Copyright (C) 2010 Alain Peyrat - Alcatel-Lucent
8 * Copyright 2011, Franck Villaume - Capgemini
9 * Copyright 2011, Franck Villaume - TrivialDev
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * html_feedback_top() - Show the feedback output at the top of the page.
30 * @param string The feedback.
32 function html_feedback_top($feedback) {
34 echo $HTML->feedback($feedback);
38 * html_warning_top() - Show the warning output at the top of the page.
40 * @param string The warning message.
42 function html_warning_top($msg) {
44 echo $HTML->warning_msg($msg);
48 * html_error_top() - Show the error output at the top of the page.
50 * @param string The error message.
52 function html_error_top($msg) {
54 echo $HTML->error_msg($msg);
58 * make_user_link() - Make a username reference into a link to that users User page on SF.
60 * @param string The username of the user to link.
62 function make_user_link($username,$displayname='') {
63 if (empty($displayname))
64 $displayname = $username;
66 if (!strcasecmp($username,'Nobody') || !strcasecmp($username,'None')) {
69 return '<a href="/users/'.$username.'">'.$displayname.'</a>';
74 * html_feedback_bottom() - Show the feedback output at the bottom of the page.
76 * @param string The feedback.
78 function html_feedback_bottom($feedback) {
80 echo $HTML->feedback($feedback);
84 * html_blankimage() - Show the blank spacer image.
86 * @param int The height of the image
87 * @param int The width of the image
89 function html_blankimage($height,$width) {
90 return '<img src="/images/blank.png" width="' . $width . '" height="' . $height . '" alt="" />';
94 * html_abs_image() - Show an image given an absolute URL.
97 * @param int width of the image
98 * @param int height of the image
99 * @param array Any <img> tag parameters (i.e. 'border', 'alt', etc...)
101 function html_abs_image($url, $width, $height, $args) {
102 $return = ('<img src="' . $url . '"');
104 while(list($k,$v) = each($args)) {
105 $return .= ' '.$k.'="'.$v.'"';
108 if (!isset($args['alt'])) {
109 $return .= ' alt=""';
112 // Add image dimensions (if given)
113 $return .= $width ?" width=\"" . $width . "\"": '';
114 $return .= $height? " height=\"" . $height . "\"": '';
121 * html_image() - Build an image tag of an image contained in $src
123 * @param string The source location of the image
124 * @param int The width of the image
125 * @param int The height of the image
126 * @param array Any IMG tag parameters associated with this image (i.e. 'border', 'alt', etc...)
127 * @param bool DEPRECATED
129 function html_image($src, $width='', $height='', $args=array(), $display=1) {
132 if (method_exists($HTML, 'html_image')) {
133 $HTML->html_image($src, $width, $height, $args);
135 $s = ((session_issecure()) ? forge_get_config('images_secure_url') : forge_get_config('images_url') );
136 return html_abs_image($s.$HTML->imgroot.$src, $width, $height, $args);
140 * html_get_language_popup() - Pop up box of supported languages.
142 * @param string The title of the popup box.
143 * @param string Which element of the box is to be selected.
144 * @return string The html select box.
146 function html_get_language_popup($title='language_id', $selected='xzxz') {
147 $res = db_query_params('SELECT * FROM supported_languages ORDER BY name ASC',
149 return html_build_select_box($res, $title, $selected, false);
153 * html_get_theme_popup() - Pop up box of supported themes.
155 * @param string The title of the popup box.
156 * @param string Which element of the box is to be selected.
157 * @return string The html select box.
159 function html_get_theme_popup($title='theme_id', $selected='xzxz') {
160 $res=db_query_params('SELECT theme_id, fullname FROM themes WHERE enabled=true',
162 $nbTheme = db_numrows($res);
167 return html_build_select_box($res, $title, $selected, false);
172 * html_get_ccode_popup() - Pop up box of supported country_codes.
174 * @param string The title of the popup box.
175 * @param string Which element of the box is to be selected.
176 * @return string The html select box.
178 function html_get_ccode_popup($title='ccode', $selected='xzxz') {
179 $res=db_query_params('SELECT ccode,country_name FROM country_code ORDER BY country_name',
181 return html_build_select_box($res, $title, $selected, false);
185 * html_get_timezone_popup() - Pop up box of supported Timezones.
186 * Assumes you have included Timezones array file.
188 * @param string The title of the popup box.
189 * @param string Which element of the box is to be selected.
190 * @return string The html select box.
192 function html_get_timezone_popup($title='timezone', $selected='xzxz') {
194 if ($selected == 'xzxzxzx') {
195 $r = file('/etc/timezone');
196 $selected = str_replace("\n", '', $r[0]);
198 return html_build_select_box_from_arrays($TZs, $TZs, $title, $selected, false);
203 * html_build_select_box_from_assoc() - Takes one assoc array and returns a pop-up box.
205 * @param array An array of items to use.
206 * @param string The name you want assigned to this form element.
207 * @param string The value of the item that should be checked.
208 * @param boolean Whether we should swap the keys / names.
209 * @param bool Whether or not to show the '100 row'.
210 * @param string What to call the '100 row' defaults to none.
212 function html_build_select_box_from_assoc ($arr,$select_name,$checked_val='xzxz',$swap=false,$show_100=false,$text_100='None') {
214 $keys=array_values($arr);
215 $vals=array_keys($arr);
217 $vals=array_values($arr);
218 $keys=array_keys($arr);
220 return html_build_select_box_from_arrays ($keys,$vals,$select_name,$checked_val,$show_100,$text_100);
224 * html_build_select_box_from_array() - Takes one array, with the first array being the "id"
225 * or value and the array being the text you want displayed.
227 * @param array An array of items to use.
228 * @param string The name you want assigned to this form element.
229 * @param string The value of the item that should be checked.
231 function html_build_select_box_from_array ($vals,$select_name,$checked_val='xzxz',$samevals = 0) {
233 <select name="'.$select_name.'">';
235 $rows = count($vals);
237 for ($i = 0; $i < $rows; $i++) {
239 $return .= "\n\t\t<option value=\"" . $vals[$i] . "\"";
240 if ($vals[$i] == $checked_val) {
241 $return .= ' selected="selected"';
244 $return .= "\n\t\t<option value=\"" . $i .'"';
245 if ($i == $checked_val) {
246 $return .= ' selected="selected"';
249 $return .= '>'.htmlspecialchars($vals[$i]).'</option>';
258 * html_build_radio_buttons_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
259 * array being the text you want displayed.
261 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
262 * There must be a related row in users, categories, et , and by default that
263 * row is 100, so almost every pop-up box has 100 as the default
264 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
266 * @param array The ID or value
267 * @param array Text to be displayed
268 * @param string Name to assign to this form element
269 * @param string The item that should be checked
270 * @param bool Whether or not to show the '100 row'
271 * @param string What to call the '100 row' defaults to none
272 * @param bool Whether or not to show the 'Any row'
273 * @param string What to call the 'Any row' defaults to any
275 function html_build_radio_buttons_from_arrays ($vals,$texts,$select_name,$checked_val='xzxz',$show_100=true,$text_100='none',$show_any=false,$text_any='any') {
276 if ($text_100=='none'){
282 if (count($texts) != $rows) {
283 $return .= 'ERROR - uneven row counts';
286 //we don't always want the default Any row shown
289 <input type="radio" name="'.$select_name.'" value=""'.(($checked_val=='') ? ' checked="checked"' : '').' /> '. $text_any .'<br />';
291 //we don't always want the default 100 row shown
294 <input type="radio" name="'.$select_name.'" value="100"'.(($checked_val==100) ? ' checked="checked"' : '').' /> '. $text_100 .'<br />';
297 $checked_found=false;
299 for ($i=0; $i<$rows; $i++) {
300 // uggh - sorry - don't show the 100 row
301 // if it was shown above, otherwise do show it
302 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
304 <input type="radio" name="'.$select_name.'" value="'.$vals[$i].'"';
305 if ((string)$vals[$i] == (string)$checked_val) {
307 $return .= ' checked="checked"';
309 $return .= ' /> '.htmlspecialchars($texts[$i]).'<br />';
313 // If the passed in "checked value" was never "SELECTED"
314 // we want to preserve that value UNLESS that value was 'xzxz', the default value
316 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
318 <input type="radio" value="'.$checked_val.'" checked="checked" /> '._('No Change').'<br />';
324 function html_get_tooltip_description($element_name) {
325 global $use_tooltips;
327 switch( $element_name ) {
329 return( _('This drop-down box represents the person to which a tracker item is assigned.'));
331 return( _('This drop-down box represents the current status of a tracker item.<br /><br />You can set the status to \'Pending\' if you are waiting for a response from the tracker item author. When the author responds the status is automatically reset to that of \'Open\'. Otherwise, if the author doesn\'t respond with an admin-defined amount of time (default is 14 days) then the item is given a status of \'Deleted\'.'));
333 return( _('Tracker category'));
335 return( _('Tracker group'));
337 return( _('The Sort By option allows you to determine how the browse results are sorted.<br /><br /> You can sort by ID, Priority, Summary, Open Date, Close Date, Submitter, or Assignee. You can also have the results sorted in Ascending or Descending order.'));
338 case 'new_artifact_type_id':
339 return( _('The Data Type option determines the type of tracker item this is. Since the tracker rolls into one the bug, patch, support, etc... managers you need to be able to determine which one of these an item should belong.<br /><br />This has the added benefit of enabling an admin to turn a support request into a bug.'));
341 return( _('The priority option allows a user to define a tracker item priority (ranging from 1-Lowest to 5-Highest).<br /><br />This is especially helpful for bugs and support requests where a user might find a critical problem with a project.'));
343 return( _('Resolution'));
345 return( _('The summary text-box represents a short tracker item summary. Useful when browsing through several tracker items.'));
346 case 'canned_response':
347 return( _('The canned response drop-down represents a list of project admin-defined canned responses to common support or bug submission.<br /><br /> If you are a project admin you can click the \'(admin)\' link to define your own canned responses'));
349 return( _('Anyone can add here comments to give additional information, answers and solutions. Please, be as precise as possible to avoid misunderstanding. If relevant, screenshots or documents can be added as attached files.'));
351 return( htmlentities(_('Enter the complete description.').'<br/><br/>'.
352 _("<div align=\"left\"><b>Editing tips:</b><br/><strong>http,https or ftp</strong>: Hyperlinks.<br/><strong>[#NNN]</strong>: Tracker id NNN.<br/><strong>[TNNN]</strong>: Task id NNN.<br/><strong>[wiki:<pagename>]</strong>: Wiki page.<br/><strong>[forum:<msg_id>]</strong>: Forum post.</div>"),
353 ENT_COMPAT, 'UTF-8'));
355 return( _('When you wish to attach a file to a tracker item you must check this checkbox before submitting changes.'));
357 return( htmlentities(_('You can monitor or un-monitor this item by clicking the "Monitor" button. <br /><br /><strong>Note!</strong> this will send you additional email. If you add comments to this item, or submitted, or are assigned this item, you will also get emails for those reasons as well!'),
358 ENT_COMPAT, 'UTF-8'));
367 function html_use_jquery() {
368 use_javascript('/scripts/jquery/jquery-1.4.2.min.js');
371 function html_use_tooltips() {
373 use_javascript('/scripts/jquery-tipsy/src/javascripts/jquery.tipsy.js');
374 use_javascript('/js/jquery-common.js');
375 use_stylesheet('/scripts/jquery-tipsy/src/stylesheets/tipsy.css');
378 function html_use_storage() {
380 use_javascript('/scripts/jquery-storage/jquery.Storage.js');
383 function html_use_simplemenu() {
385 use_javascript('/scripts/jquery-simpletreemenu/js/jquery-simpleTreeMenu-1.1.0.js');
386 use_stylesheet('/scripts/jquery-simpletreemenu/css/jquery-simpleTreeMenu-1.1.0.css');
390 * html_build_select_box_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
391 * array being the text you want displayed.
393 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
394 * There must be a related row in users, categories, et , and by default that
395 * row is 100, so almost every pop-up box has 100 as the default
396 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
398 * @param array The ID or value
399 * @param array Text to be displayed
400 * @param string Name to assign to this form element
401 * @param string The item that should be checked
402 * @param bool Whether or not to show the '100 row'
403 * @param string What to call the '100 row' defaults to none
404 * @param bool Whether or not to show the 'Any row'
405 * @param string What to call the 'Any row' defaults to any
406 * @param array Array of all allowed values from the full list.
408 function html_build_select_box_from_arrays ($vals,$texts,$select_name,$checked_val='xzxz',$show_100=true,$text_100='none',$show_any=false,$text_any='any', $allowed=false) {
409 if ($text_100=='none'){
415 if (count($texts) != $rows) {
416 $return .= 'ERROR - uneven row counts';
419 $title = html_get_tooltip_description($select_name);
422 $id = ' id="tracker-'.$select_name.'"';
423 if (preg_match('/\[\]/', $id)) {
428 $title = html_get_tooltip_description($select_name);
430 <select'.$id.' name="'.$select_name.'" title="'.util_html_secure($title).'">';
432 //we don't always want the default Any row shown
435 <option value=""'.(($checked_val=='') ? ' selected="selected"' : '').'>'. util_html_secure($text_any) .'</option>';
437 //we don't always want the default 100 row shown
440 <option value="100"'.(($checked_val==100) ? ' selected="selected"' : '').'>'. util_html_secure($text_100) .'</option>';
443 $checked_found=false;
445 for ($i=0; $i<$rows; $i++) {
446 // uggh - sorry - don't show the 100 row
447 // if it was shown above, otherwise do show it
448 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
450 <option value="'.util_html_secure($vals[$i]).'"';
451 if ((string)$vals[$i] == (string)$checked_val) {
453 $return .= ' selected="selected"';
455 if (is_array($allowed) && !in_array($vals[$i], $allowed)) {
456 $return .= ' disabled="disabled" class="option_disabled"';
458 $return .= '>'.util_html_secure($texts[$i]).'</option>';
462 // If the passed in "checked value" was never "SELECTED"
463 // we want to preserve that value UNLESS that value was 'xzxz', the default value
465 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
467 <option value="'.util_html_secure($checked_val).'" selected="selected">'._('No Change').'</option>';
476 * html_build_select_box() - Takes a result set, with the first column being the "id" or value and
477 * the second column being the text you want displayed.
479 * @param int The result set
480 * @param string Text to be displayed
481 * @param string The item that should be checked
482 * @param bool Whether or not to show the '100 row'
483 * @param string What to call the '100 row'. Defaults to none.
485 function html_build_select_box ($result, $name, $checked_val="xzxz", $show_100=true, $text_100='none', $show_any=false, $text_any='Select One') {
486 if ($text_100=='none'){
489 return html_build_select_box_from_arrays (util_result_column_to_array($result,0),util_result_column_to_array($result,1),$name,$checked_val,$show_100,$text_100, $show_any, $text_any);
493 * html_build_select_box_sorted() - Takes a result set, with the first column being the "id" or value and
494 * the second column being the text you want displayed.
496 * @param int The result set
497 * @param string Text to be displayed
498 * @param string The item that should be checked
499 * @param bool Whether or not to show the '100 row'
500 * @param string What to call the '100 row'. Defaults to none.
502 function html_build_select_box_sorted ($result, $name, $checked_val="xzxz",$show_100=true,$text_100='none') {
503 if ($text_100=='none'){
506 $vals = util_result_column_to_array($result, 0);
507 $texts = util_result_column_to_array($result, 1);
508 array_multisort($texts, SORT_ASC, SORT_STRING,
510 return html_build_select_box_from_arrays ($vals, $texts, $name, $checked_val, $show_100, $text_100);
514 * html_build_multiple_select_box() - Takes a result set, with the first column being the "id" or value
515 * and the second column being the text you want displayed.
517 * @param int The result set
518 * @param string Text to be displayed
519 * @param string The item that should be checked
520 * @param int The size of this box
521 * @param bool Whether or not to show the '100 row'
523 function html_build_multiple_select_box ($result,$name,$checked_array,$size='8',$show_100=true) {
524 $checked_count=count($checked_array);
526 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
529 Put in the default NONE box
532 <option value="100"';
533 for ($j=0; $j<$checked_count; $j++) {
534 if ($checked_array[$j] == '100') {
535 $return .= ' selected="selected"';
538 $return .= '>'._('None').'</option>';
541 $rows=db_numrows($result);
542 for ($i=0; $i<$rows; $i++) {
543 if ((db_result($result,$i,0) != '100') || (db_result($result,$i,0) == '100' && !$show_100)) {
545 <option value="'.db_result($result,$i,0).'"';
547 Determine if it's checked
549 $val=db_result($result,$i,0);
550 for ($j=0; $j<$checked_count; $j++) {
551 if ($val == $checked_array[$j]) {
552 $return .= ' selected="selected"';
555 $return .= '>'. substr(db_result($result,$i,1),0,35). '</option>';
564 * html_build_multiple_select_box_from_arrays() - Takes two arrays and builds a multi-select box
566 * @param array id of the field
567 * @param array Text to be displayed
568 * @param string id of the items selected
569 * @param string The item that should be checked
570 * @param int The size of this box
571 * @param bool Whether or not to show the '100 row'
573 function html_build_multiple_select_box_from_arrays($ids,$texts,$name,$checked_array,$size='8',$show_100=true,$text_100='none') {
574 $checked_count=count($checked_array);
576 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
578 if ($text_100=='none') {
582 Put in the default NONE box
585 <option value="100"';
586 for ($j=0; $j<$checked_count; $j++) {
587 if ($checked_array[$j] == '100') {
588 $return .= ' selected="selected"';
591 $return .= '>'.$text_100.'</option>';
595 for ($i=0; $i<$rows; $i++) {
596 if (( $ids[$i] != '100') || ($ids[$i] == '100' && !$show_100)) {
598 <option value="'.$ids[$i].'"';
600 Determine if it's checked
603 for ($j=0; $j<$checked_count; $j++) {
604 if ($val == $checked_array[$j]) {
605 $return .= ' selected="selected"';
608 $return .= '>'.$texts[$i].' </option>';
617 * html_build_checkbox() - Render checkbox control
619 * @param name - name of control
620 * @param value - value of control
621 * @param checked - true if control should be checked
622 * @return html code for checkbox control
624 function html_build_checkbox($name, $value, $checked) {
625 return '<input type="checkbox" name="'.$name.'"'
626 .' value="'.$value.'"'
627 .($checked ? 'checked="checked"' : '').'>';
632 * build_priority_select_box() - Wrapper for html_build_priority_select_box()
634 * @see html_build_priority_select_box()
636 function build_priority_select_box ($name='priority', $checked_val='3', $nochange=false) {
637 echo html_build_priority_select_box ($name, $checked_val, $nochange);
641 * html_build_priority_select_box() - Return a select box of standard priorities.
642 * The name of this select box is optional and so is the default checked value.
644 * @param string Name of the select box
645 * @param string The value to be checked
646 * @param bool Whether to make 'No Change' selected.
648 function html_build_priority_select_box ($name='priority', $checked_val='3', $nochange=false) {
650 <select id="tracker-<?php echo $name ?>" name="<?php echo $name; ?>" title="<?php echo util_html_secure(html_get_tooltip_description($name)) ?>">
651 <?php if($nochange) { ?>
652 <option value="100"<?php if ($nochange) {echo " selected=\"selected\"";} ?>><?php echo _('No Change') ?></option>
654 <option value="1"<?php if ($checked_val=="1") {echo " selected=\"selected\"";} ?>>1 - <?php echo _('Lowest') ?></option>
655 <option value="2"<?php if ($checked_val=="2") {echo " selected=\"selected\"";} ?>>2</option>
656 <option value="3"<?php if ($checked_val=="3") {echo " selected=\"selected\"";} ?>>3</option>
657 <option value="4"<?php if ($checked_val=="4") {echo " selected=\"selected\"";} ?>>4</option>
658 <option value="5"<?php if ($checked_val=="5") {echo " selected=\"selected\"";} ?>>5 - <?php echo _('Highest') ?></option>
665 * html_buildcheckboxarray() - Build an HTML checkbox array.
667 * @param array Options array
668 * @param name Checkbox name
669 * @param array Array of boxes to be pre-checked
671 function html_buildcheckboxarray($options,$name,$checked_array) {
672 $option_count=count($options);
673 $checked_count=count($checked_array);
675 for ($i=1; $i<=$option_count; $i++) {
677 <br /><input type="checkbox" name="'.$name.'" value="'.$i.'"';
678 for ($j=0; $j<$checked_count; $j++) {
679 if ($i == $checked_array[$j]) {
680 echo ' checked="checked"';
683 echo ' /> '.$options[$i];
688 * site_header() - everything required to handle security and
689 * add navigation for user pages like /my/ and /account/
691 * @param array Must contain $user_id
693 function site_header($params) {
696 Check to see if active user
697 Check to see if logged in
699 echo $HTML->header($params);
703 * site_footer() - Show the HTML site footer.
705 * @param array Footer params array
707 function site_footer($params) {
709 $HTML->footer($params);
713 * site_project_header() - everything required to handle
714 * security and state checks for a project web page
716 * @param params array() must contain $toptab and $group
718 function site_project_header($params) {
722 Check to see if active
723 Check to see if project rather than foundry
724 Check to see if private (if private check if user_ismember)
727 $group_id=$params['group'];
729 //get the project object
730 $project = group_get_object($group_id);
732 if (!$project || !is_object($project)) {
734 } else if ($project->isError()) {
735 if ($project->isPermissionDeniedError()) {
736 if (!session_get_user()) {
737 $next = '/account/login.php?error_msg='.urlencode($project->getErrorMessage());
738 if (getStringFromServer('REQUEST_METHOD') != 'POST') {
739 $next .= '&return_to='.urlencode(getStringFromServer('REQUEST_URI'));
741 session_redirect($next);
744 exit_error(sprintf(_('Project access problem: %s'),$project->getErrorMessage()),'home');
746 exit_error(sprintf(_('Project Problem: %s'),$project->getErrorMessage()),'home');
749 // Check permissions in case of restricted access
750 session_require_perm ('project_read', $group_id);
752 //for dead projects must be member of admin project
753 if (!$project->isActive()) {
754 session_require_global_perm ('forge_admin');
757 if (isset($params['title'])){
758 $h1=$params['title'];
759 $params['title']=$project->getPublicName().': '.$params['title'];
761 $h1=$project->getPublicName();
762 $params['title']=$project->getPublicName();
764 if (!isset($params['h1'])){
768 site_header($params);
772 * site_project_footer() - currently a simple shim
773 * that should be on every project page, rather than
774 * a direct call to site_footer() or theme_footer()
776 * @param params array() empty
778 function site_project_footer($params) {
779 site_footer($params);
783 * site_user_header() - everything required to handle security and
784 * add navigation for user pages like /my/ and /account/
786 * @param params array() must contain $user_id
788 function site_user_header($params) {
792 Check to see if active user
793 Check to see if logged in
795 site_header($params);
796 echo ($HTML->beginSubMenu());
801 $arr_t[] = _('My Personal Page');
803 $arr_attr[] = array('title' => _('View your personal page, a selection of widgets to follow the informations from projects.'), 'class' => 'tabtitle-nw');
806 $arr_t[] = _('Trackers dashboard');
807 $arr_l[] = '/my/dashboard.php';
808 $arr_attr[] = array('title' => _('View your tasks and artifacts.'), 'class' => 'tabtitle');
811 if (forge_get_config('use_diary')) {
812 $arr_t[] = _('Diary & Notes');
813 $arr_l[] = '/my/diary.php';
814 $arr_attr[] = array('title' => _('Manage your diary. Add, modify or delete your notes.'), 'class' => 'tabtitle');
817 $arr_t[] = _('Account Maintenance');
818 $arr_l[] = '/account/';
819 $arr_attr[] = array('title' => _('Manage your account. Change your password, select your preferences.'), 'class' => 'tabtitle');
821 if (!forge_get_config('project_registration_restricted')
822 || forge_check_global_perm('approve_projects', '')) {
823 $arr_t[] = _('Register Project');
824 $arr_l[] = '/register/';
825 $arr_attr[] = array('title' => _('Register a new project in forge, following the workflow.'), 'class' => 'tabtitle');
828 echo ($HTML->printSubMenu($arr_t, $arr_l, $arr_attr));
829 if ( plugin_hook_listeners("usermenu") > 0 ) {
830 echo $HTML->subMenuSeparator();
832 plugin_hook("usermenu", false);
833 echo ($HTML->endSubMenu());
837 * site_user_footer() - currently a simple shim that should be on every user page,
838 * rather than a direct call to site_footer() or theme_footer()
840 * @param params array() empty
842 function site_user_footer($params) {
843 site_footer($params);
847 * html_clean_hash_string() - Remove noise characters from hex hash string
849 * Thruout SourceForge, URLs with hexadecimal hash string parameters
850 * are being sent via email to request confirmation of user actions.
851 * It was found that some mail clients distort this hash, so we take
852 * special steps to encode it in the way which help to preserve its
853 * recognition. This routine
855 * @param hashstr required hash parameter as received from browser
856 * @return pure hex string
858 function html_clean_hash_string($hashstr) {
860 if (substr($hashstr,0,1)=="_") {
861 $hashstr = substr($hashstr, 1);
864 if (substr($hashstr, strlen($hashstr)-1, 1)==">") {
865 $hashstr = substr($hashstr, 0, strlen($hashstr)-1);
871 function relative_date ($date) {
872 $delta = time() - $date;
874 return sprintf(ngettext('%d second ago', '%d seconds ago', $delta), $delta);
876 $delta = round($delta/60);
878 return sprintf(ngettext('%d minute ago', '%d minutes ago', $delta), $delta);
880 $delta = round($delta/60);
882 return sprintf(ngettext('%d hour ago', '%d hours ago', $delta), $delta);
884 $delta = round($delta/24);
886 return sprintf(ngettext('%d day ago', '%d days ago', $delta), $delta);
888 $delta = round($delta/7);
890 return sprintf(ngettext('%d week ago', '%d weeks ago', $delta), $delta);
892 return date(_('Y-m-d H:i'), $date);
896 // c-file-style: "bsd"