5 * Copyright 1999-2001 (c) VA Linux Systems
6 * Copyright 2010 (c) FusionForge Team
7 * Copyright (C) 2010 Alain Peyrat - Alcatel-Lucent
9 * This file is part of FusionForge. FusionForge is free software;
10 * you can redistribute it and/or modify it under the terms of the
11 * GNU General Public License as published by the Free Software
12 * Foundation; either version 2 of the Licence, or (at your option)
15 * FusionForge is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * html_feedback_top() - Show the feedback output at the top of the page.
28 * @param string The feedback.
30 function html_feedback_top($feedback) {
32 echo $HTML->feedback($feedback);
36 * html_warning_top() - Show the warning output at the top of the page.
38 * @param string The warning message.
40 function html_warning_top($msg) {
42 echo $HTML->warning_msg($msg);
46 * html_error_top() - Show the error output at the top of the page.
48 * @param string The error message.
50 function html_error_top($msg) {
52 echo $HTML->error_msg($msg);
56 * make_user_link() - Make a username reference into a link to that users User page on SF.
58 * @param string The username of the user to link.
60 function make_user_link($username,$displayname='') {
61 if (empty($displayname))
62 $displayname = $username;
64 if (!strcasecmp($username,'Nobody') || !strcasecmp($username,'None')) {
67 return '<a href="/users/'.$username.'">'.$displayname.'</a>' ;
72 * html_feedback_bottom() - Show the feedback output at the bottom of the page.
74 * @param string The feedback.
76 function html_feedback_bottom($feedback) {
78 echo $HTML->feedback($feedback);
82 * html_blankimage() - Show the blank spacer image.
84 * @param int The height of the image
85 * @param int The width of the image
87 function html_blankimage($height,$width) {
88 return '<img src="/images/blank.png" width="' . $width . '" height="' . $height . '" alt="" />';
92 * html_abs_image() - Show an image given an absolute URL.
95 * @param int width of the image
96 * @param int height of the image
97 * @param array Any <img> tag parameters (i.e. 'border', 'alt', etc...)
99 function html_abs_image($url, $width, $height, $args) {
100 $return = ('<img src="' . $url . '"');
102 while(list($k,$v) = each($args)) {
103 $return .= ' '.$k.'="'.$v.'"';
106 if (!isset($args['alt'])) {
107 $return .= ' alt=""';
110 // Add image dimensions (if given)
111 $return .= $width ?" width=\"" . $width . "\"": '';
112 $return .= $height? " height=\"" . $height . "\"": '';
119 * html_image() - Build an image tag of an image contained in $src
121 * @param string The source location of the image
122 * @param int The width of the image
123 * @param int The height of the image
124 * @param array Any IMG tag parameters associated with this image (i.e. 'border', 'alt', etc...)
125 * @param bool DEPRECATED
127 function html_image($src,$width='',$height='',$args=array(),$display=1) {
130 if (method_exists($HTML, 'html_image')) {
131 $HTML->html_image($src, $width, $height, $args);
133 $s = ((session_issecure()) ? forge_get_config('images_secure_url') : forge_get_config('images_url') );
134 return html_abs_image($s.$HTML->imgroot.$src, $width, $height, $args);
138 * html_get_language_popup() - Pop up box of supported languages.
140 * @param string The title of the popup box.
141 * @param string Which element of the box is to be selected.
142 * @return string The html select box.
144 function html_get_language_popup ($title='language_id',$selected='xzxz') {
145 $res = db_query_params ('SELECT * FROM supported_languages ORDER BY name ASC',
147 return html_build_select_box ($res,$title,$selected,false);
151 * html_get_theme_popup() - Pop up box of supported themes.
153 * @param string The title of the popup box.
154 * @param string Which element of the box is to be selected.
155 * @return string The html select box.
157 function html_get_theme_popup ($title='theme_id',$selected='xzxz') {
158 $res=db_query_params ('SELECT theme_id, fullname FROM themes WHERE enabled=true',
160 $nbTheme = db_numrows($res);
162 $thetheme = db_result($res, 0, 'fullname');
163 return util_html_secure($thetheme) . html_e('input', array(
166 'value' => db_result($res, 0, 'theme_id'),
168 } else if ($nbTheme < 1) {
171 return html_build_select_box($res,$title,$selected,false);
176 * html_get_ccode_popup() - Pop up box of supported country_codes.
178 * @param string The title of the popup box.
179 * @param string Which element of the box is to be selected.
180 * @return string The html select box.
182 function html_get_ccode_popup ($title='ccode',$selected='xzxz') {
183 $res=db_query_params ('SELECT ccode,country_name FROM country_code ORDER BY country_name',
185 return html_build_select_box ($res,$title,$selected,false);
189 * html_get_timezone_popup() - Pop up box of supported Timezones.
190 * Assumes you have included Timezones array file.
192 * @param string The title of the popup box.
193 * @param string Which element of the box is to be selected.
194 * @return string The html select box.
196 function html_get_timezone_popup ($title='timezone',$selected='xzxz') {
198 if ($selected == 'xzxzxzx') {
199 $r = file ('/etc/timezone');
200 $selected = str_replace ("\n", '', $r[0]);
202 return html_build_select_box_from_arrays ($TZs,$TZs,$title,$selected,false);
207 * html_build_select_box_from_assoc() - Takes one assoc array and returns a pop-up box.
209 * @param array An array of items to use.
210 * @param string The name you want assigned to this form element.
211 * @param string The value of the item that should be checked.
212 * @param boolean Whether we should swap the keys / names.
213 * @param bool Whether or not to show the '100 row'.
214 * @param string What to call the '100 row' defaults to none.
216 function html_build_select_box_from_assoc ($arr,$select_name,$checked_val='xzxz',$swap=false,$show_100=false,$text_100='None') {
218 $keys=array_values($arr);
219 $vals=array_keys($arr);
221 $vals=array_values($arr);
222 $keys=array_keys($arr);
224 return html_build_select_box_from_arrays ($keys,$vals,$select_name,$checked_val,$show_100,$text_100);
228 * html_build_select_box_from_array() - Takes one array, with the first array being the "id"
229 * or value and the array being the text you want displayed.
231 * @param array An array of items to use.
232 * @param string The name you want assigned to this form element.
233 * @param string The value of the item that should be checked.
235 function html_build_select_box_from_array ($vals,$select_name,$checked_val='xzxz',$samevals = 0) {
237 <select name="'.$select_name.'">';
241 for ($i=0; $i<$rows; $i++) {
243 $return .= "\n\t\t<option value=\"" . $vals[$i] . "\"";
244 if ($vals[$i] == $checked_val) {
245 $return .= ' selected="selected"';
248 $return .= "\n\t\t<option value=\"" . $i .'"';
249 if ($i == $checked_val) {
250 $return .= ' selected="selected"';
253 $return .= '>'.htmlspecialchars($vals[$i]).'</option>';
262 * html_build_radio_buttons_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
263 * array being the text you want displayed.
265 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
266 * There must be a related row in users, categories, et , and by default that
267 * row is 100, so almost every pop-up box has 100 as the default
268 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
270 * @param array The ID or value
271 * @param array Text to be displayed
272 * @param string Name to assign to this form element
273 * @param string The item that should be checked
274 * @param bool Whether or not to show the '100 row'
275 * @param string What to call the '100 row' defaults to none
276 * @param bool Whether or not to show the 'Any row'
277 * @param string What to call the 'Any row' defaults to any
279 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') {
280 if ($text_100=='none'){
286 if (count($texts) != $rows) {
287 $return .= 'ERROR - uneven row counts';
290 //we don't always want the default Any row shown
293 <input type="radio" name="'.$select_name.'" value=""'.(($checked_val=='') ? ' checked="checked"' : '').' /> '. $text_any .'<br />';
295 //we don't always want the default 100 row shown
298 <input type="radio" name="'.$select_name.'" value="100"'.(($checked_val==100) ? ' checked="checked"' : '').' /> '. $text_100 .'<br />';
301 $checked_found=false;
303 for ($i=0; $i<$rows; $i++) {
304 // uggh - sorry - don't show the 100 row
305 // if it was shown above, otherwise do show it
306 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
308 <input type="radio" name="'.$select_name.'" value="'.$vals[$i].'"';
309 if ((string)$vals[$i] == (string)$checked_val) {
311 $return .= ' checked="checked"';
313 $return .= ' /> '.htmlspecialchars($texts[$i]).'<br />';
317 // If the passed in "checked value" was never "SELECTED"
318 // we want to preserve that value UNLESS that value was 'xzxz', the default value
320 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
322 <input type="radio" value="'.$checked_val.'" checked="checked" /> '._('No Change').'<br />';
328 function html_get_tooltip_description($element_name) {
329 switch( $element_name ) {
331 return( _('This drop-down box represents the person to which a tracker item is assigned.'));
333 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\'.'));
335 return( _('Tracker category'));
337 return( _('Tracker group'));
339 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.'));
340 case 'new_artifact_type_id':
341 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.'));
343 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.'));
345 return( _('Resolution'));
347 return( _('The summary text-box represents a short tracker item summary. Useful when browsing through several tracker items.'));
348 case 'canned_response':
349 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'));
351 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.'));
353 return( htmlentities(_('Enter the complete description.').'<br/><br/>'.
354 _("<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>"),
355 ENT_COMPAT, 'UTF-8'));
357 return( _('When you wish to attach a file to a tracker item you must check this checkbox before submitting changes.'));
359 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!'),
360 ENT_COMPAT, 'UTF-8'));
366 function html_use_jquery() {
367 use_javascript('/scripts/jquery/jquery-1.4.2.min.js');
370 function html_use_tooltips() {
372 use_javascript('/scripts/jquery-tipsy/src/javascripts/jquery.tipsy.js');
373 use_javascript('/js/tooltips.js');
374 use_stylesheet('/scripts/jquery-tipsy/src/stylesheets/tipsy.css');
378 * html_build_select_box_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
379 * array being the text you want displayed.
381 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
382 * There must be a related row in users, categories, et , and by default that
383 * row is 100, so almost every pop-up box has 100 as the default
384 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
386 * @param array The ID or value
387 * @param array Text to be displayed
388 * @param string Name to assign to this form element
389 * @param string The item that should be checked
390 * @param bool Whether or not to show the '100 row'
391 * @param string What to call the '100 row' defaults to none
392 * @param bool Whether or not to show the 'Any row'
393 * @param string What to call the 'Any row' defaults to any
394 * @param array Array of all allowed values from the full list.
396 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) {
397 $have_a_subelement = false;
399 if ($text_100=='none'){
405 if (count($texts) != $rows) {
406 $return .= 'ERROR - uneven row counts';
409 $title = html_get_tooltip_description($select_name);
412 $id = ' id="tracker-'.$select_name.'"';
413 if (preg_match('/\[\]/', $id)) {
418 $title = html_get_tooltip_description($select_name);
420 <select'.$id.' name="'.$select_name.'" title="'.util_html_secure($title).'">';
422 //we don't always want the default Any row shown
425 <option value=""'.(($checked_val=='') ? ' selected="selected"' : '').'>'. util_html_secure($text_any) .'</option>';
426 $have_a_subelement = true;
428 //we don't always want the default 100 row shown
431 <option value="100"'.(($checked_val==100) ? ' selected="selected"' : '').'>'. util_html_secure($text_100) .'</option>';
432 $have_a_subelement = true;
435 $checked_found=false;
437 for ($i=0; $i<$rows; $i++) {
438 // uggh - sorry - don't show the 100 row
439 // if it was shown above, otherwise do show it
440 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
442 <option value="'.util_html_secure($vals[$i]).'"';
443 if ((string)$vals[$i] == (string)$checked_val) {
445 $return .= ' selected="selected"';
447 if (is_array($allowed) && !in_array($vals[$i], $allowed)) {
448 $return .= ' disabled="disabled" class="option_disabled"';
450 $return .= '>'.util_html_secure($texts[$i]).'</option>';
451 $have_a_subelement = true;
455 // If the passed in "checked value" was never "SELECTED"
456 // we want to preserve that value UNLESS that value was 'xzxz', the default value
458 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
460 <option value="'.util_html_secure($checked_val).'" selected="selected">'._('No Change').'</option>';
461 $have_a_subelement = true;
464 if (!$have_a_subelement) {
465 /* <select></select> without <option/> in between is invalid */
466 return '<!-- select without options -->';
475 * html_build_select_box() - Takes a result set, with the first column being the "id" or value and
476 * the second column being the text you want displayed.
478 * @param int The result set
479 * @param string Text to be displayed
480 * @param string The item that should be checked
481 * @param bool Whether or not to show the '100 row'
482 * @param string What to call the '100 row'. Defaults to none.
484 function html_build_select_box ($result, $name, $checked_val="xzxz",$show_100=true,$text_100='none',$show_any=false,$text_any='Select One') {
485 if ($text_100=='none'){
488 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);
492 * html_build_select_box_sorted() - Takes a result set, with the first column being the "id" or value and
493 * the second column being the text you want displayed.
495 * @param int The result set
496 * @param string Text to be displayed
497 * @param string The item that should be checked
498 * @param bool Whether or not to show the '100 row'
499 * @param string What to call the '100 row'. Defaults to none.
501 function html_build_select_box_sorted ($result, $name, $checked_val="xzxz",$show_100=true,$text_100='none') {
502 if ($text_100=='none'){
505 $vals = util_result_column_to_array($result, 0);
506 $texts = util_result_column_to_array($result, 1);
507 array_multisort($texts, SORT_ASC, SORT_STRING,
509 return html_build_select_box_from_arrays ($vals, $texts, $name, $checked_val, $show_100, $text_100);
513 * html_build_multiple_select_box() - Takes a result set, with the first column being the "id" or value
514 * and the second column being the text you want displayed.
516 * @param int The result set
517 * @param string Text to be displayed
518 * @param string The item that should be checked
519 * @param int The size of this box
520 * @param bool Whether or not to show the '100 row'
522 function html_build_multiple_select_box ($result,$name,$checked_array,$size='8',$show_100=true) {
523 $checked_count=count($checked_array);
525 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
528 Put in the default NONE box
531 <option value="100"';
532 for ($j=0; $j<$checked_count; $j++) {
533 if ($checked_array[$j] == '100') {
534 $return .= ' selected="selected"';
537 $return .= '>'._('None').'</option>';
540 $rows=db_numrows($result);
541 for ($i=0; $i<$rows; $i++) {
542 if ((db_result($result,$i,0) != '100') || (db_result($result,$i,0) == '100' && !$show_100)) {
544 <option value="'.db_result($result,$i,0).'"';
546 Determine if it's checked
548 $val=db_result($result,$i,0);
549 for ($j=0; $j<$checked_count; $j++) {
550 if ($val == $checked_array[$j]) {
551 $return .= ' selected="selected"';
554 $return .= '>'. substr(db_result($result,$i,1),0,35). '</option>';
563 * html_build_multiple_select_box_from_arrays() - Takes two arrays and builds a multi-select box
565 * @param array id of the field
566 * @param array Text to be displayed
567 * @param string id of the items selected
568 * @param string The item that should be checked
569 * @param int The size of this box
570 * @param bool Whether or not to show the '100 row'
572 function html_build_multiple_select_box_from_arrays($ids,$texts,$name,$checked_array,$size='8',$show_100=true,$text_100='none') {
573 $checked_count=count($checked_array);
575 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
577 if ($text_100=='none') {
581 Put in the default NONE box
584 <option value="100"';
585 for ($j=0; $j<$checked_count; $j++) {
586 if ($checked_array[$j] == '100') {
587 $return .= ' selected="selected"';
590 $return .= '>'.$text_100.'</option>';
594 for ($i=0; $i<$rows; $i++) {
595 if (( $ids[$i] != '100') || ($ids[$i] == '100' && !$show_100)) {
597 <option value="'.$ids[$i].'"';
599 Determine if it's checked
602 for ($j=0; $j<$checked_count; $j++) {
603 if ($val == $checked_array[$j]) {
604 $return .= ' selected="selected"';
607 $return .= '>'.$texts[$i].' </option>';
616 * html_build_checkbox() - Render checkbox control
618 * @param name - name of control
619 * @param value - value of control
620 * @param checked - true if control should be checked
621 * @return html code for checkbox control
623 function html_build_checkbox($name, $value, $checked) {
624 return '<input type="checkbox" name="'.$name.'"'
625 .' value="'.$value.'"'
626 .($checked ? 'checked="checked"' : '').'>';
631 * build_priority_select_box() - Wrapper for html_build_priority_select_box()
633 * @see html_build_priority_select_box()
635 function build_priority_select_box ($name='priority', $checked_val='3', $nochange=false) {
636 echo html_build_priority_select_box ($name, $checked_val, $nochange);
640 * html_build_priority_select_box() - Return a select box of standard priorities.
641 * The name of this select box is optional and so is the default checked value.
643 * @param string Name of the select box
644 * @param string The value to be checked
645 * @param bool Whether to make 'No Change' selected.
647 function html_build_priority_select_box ($name='priority', $checked_val='3', $nochange=false) {
649 <select id="tracker-<?php echo $name ?>" name="<?php echo $name; ?>" title="<?php echo util_html_secure(html_get_tooltip_description($name)) ?>">
650 <?php if($nochange) { ?>
651 <option value="100"<?php if ($nochange) {echo " selected=\"selected\"";} ?>><?php echo _('No Change') ?></option>
653 <option value="1"<?php if ($checked_val=="1") {echo " selected=\"selected\"";} ?>>1 - <?php echo _('Lowest') ?></option>
654 <option value="2"<?php if ($checked_val=="2") {echo " selected=\"selected\"";} ?>>2</option>
655 <option value="3"<?php if ($checked_val=="3") {echo " selected=\"selected\"";} ?>>3</option>
656 <option value="4"<?php if ($checked_val=="4") {echo " selected=\"selected\"";} ?>>4</option>
657 <option value="5"<?php if ($checked_val=="5") {echo " selected=\"selected\"";} ?>>5 - <?php echo _('Highest') ?></option>
664 * html_buildcheckboxarray() - Build an HTML checkbox array.
666 * @param array Options array
667 * @param name Checkbox name
668 * @param array Array of boxes to be pre-checked
670 function html_buildcheckboxarray($options,$name,$checked_array) {
671 $option_count=count($options);
672 $checked_count=count($checked_array);
674 for ($i=1; $i<=$option_count; $i++) {
676 <br /><input type="checkbox" name="'.$name.'" value="'.$i.'"';
677 for ($j=0; $j<$checked_count; $j++) {
678 if ($i == $checked_array[$j]) {
679 echo ' checked="checked"';
682 echo ' /> '.$options[$i];
687 * site_header() - everything required to handle security and
688 * add navigation for user pages like /my/ and /account/
690 * @param array Must contain $user_id
692 function site_header($params) {
695 Check to see if active user
696 Check to see if logged in
698 echo $HTML->header($params);
702 * site_footer() - Show the HTML site footer.
704 * @param array Footer params array
706 function site_footer($params) {
708 $HTML->footer($params);
712 * site_project_header() - everything required to handle
713 * security and state checks for a project web page
715 * @param params array() must contain $toptab and $group
717 function site_project_header($params) {
721 Check to see if active
722 Check to see if project rather than foundry
723 Check to see if private (if private check if user_ismember)
726 $group_id=$params['group'];
728 //get the project object
729 $project = group_get_object($group_id);
731 if (!$project || !is_object($project)) {
733 } else if ($project->isError()) {
734 if ($project->isPermissionDeniedError()) {
735 if (!session_get_user()) {
736 $next = '/account/login.php?error_msg='.urlencode($project->getErrorMessage());
737 if (getStringFromServer('REQUEST_METHOD') != 'POST') {
738 $next .= '&return_to='.urlencode(getStringFromServer('REQUEST_URI'));
740 session_redirect($next);
743 exit_error(sprintf(_('Project access problem: %s'),$project->getErrorMessage()),'home');
745 exit_error(sprintf(_('Project Problem: %s'),$project->getErrorMessage()),'home');
748 // Check permissions in case of restricted access
749 session_require_perm ('project_read', $group_id);
751 //for dead projects must be member of admin project
752 if (!$project->isActive()) {
753 session_require_global_perm ('forge_admin');
756 if (isset($params['title'])){
757 $h1=$params['title'];
758 $params['title']=$project->getPublicName().': '.$params['title'];
760 $h1=$project->getPublicName();
761 $params['title']=$project->getPublicName();
763 if (!isset($params['h1'])){
767 site_header($params);
771 * site_project_footer() - currently a simple shim
772 * that should be on every project page, rather than
773 * a direct call to site_footer() or theme_footer()
775 * @param params array() empty
777 function site_project_footer($params) {
778 site_footer($params);
782 * site_user_header() - everything required to handle security and
783 * add navigation for user pages like /my/ and /account/
785 * @param params array() must contain $user_id
787 function site_user_header($params) {
791 Check to see if active user
792 Check to see if logged in
794 site_header($params);
795 echo ($HTML->beginSubMenu());
799 $arr_t[] = _('My Personal Page') ;
802 $arr_t[] = _('Trackers dashboard') ;
803 $arr_l[] = '/my/dashboard.php' ;
805 if (forge_get_config('use_diary')) {
806 $arr_t[] = _('Diary & Notes') ;
807 $arr_l[] = '/my/diary.php' ;
810 $arr_t[] = _('Account Maintenance') ;
811 $arr_l[] = '/account/' ;
813 if (!forge_get_config ('project_registration_restricted')
814 || forge_check_global_perm ('approve_projects', '')) {
815 $arr_t[] = _('Register Project') ;
816 $arr_l[] = '/register/' ;
819 echo ($HTML->printSubMenu($arr_t, $arr_l)) ;
820 plugin_hook ("usermenu", false) ;
821 echo ($HTML->endSubMenu());
825 * site_user_footer() - currently a simple shim that should be on every user page,
826 * rather than a direct call to site_footer() or theme_footer()
828 * @param params array() empty
830 function site_user_footer($params) {
831 site_footer($params);
835 * html_clean_hash_string() - Remove noise characters from hex hash string
837 * Thruout SourceForge, URLs with hexadecimal hash string parameters
838 * are being sent via email to request confirmation of user actions.
839 * It was found that some mail clients distort this hash, so we take
840 * special steps to encode it in the way which help to preserve its
841 * recognition. This routine
843 * @param hashstr required hash parameter as received from browser
844 * @return pure hex string
846 function html_clean_hash_string($hashstr) {
848 if (substr($hashstr,0,1)=="_") {
849 $hashstr = substr($hashstr, 1);
852 if (substr($hashstr, strlen($hashstr)-1, 1)==">") {
853 $hashstr = substr($hashstr, 0, strlen($hashstr)-1);
859 /* TODO: think about beautifying output */
862 * html_eo() - Return proper element XHTML start tag
864 * @param string $name
866 * @param array $attrs
867 * (optional) associative array of element attributes
868 * values: arrays are space-imploded;
869 * false values and empty arrays ignored
871 * XHTML string suitable for echo'ing
873 function html_eo($name, $attrs=array()) {
875 foreach ($attrs as $key => $value) {
876 if (is_array($value)) {
877 $value = count($value) ? implode(" ", $value) : false;
879 if ($value === false) {
882 $rv .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
889 * html_e() - Return proper element XHTML start/end sequence
891 * @param string $name
893 * @param array $attrs
894 * (optional) associative array of element attributes
895 * values: arrays are space-imploded;
896 * false values and empty arrays ignored
897 * @param string $content
898 * (optional) XHTML to be placed inside
899 * @param bool $shortform
900 * (optional) allow short open-close form
903 * XHTML string suitable for echo'ing
905 function html_e($name, $attrs=array(), $content="", $shortform=true) {
907 foreach ($attrs as $key => $value) {
908 if (is_array($value)) {
909 $value = count($value) ? implode(" ", $value) : false;
911 if ($value === false) {
914 $rv .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
916 if ($content === "" && $shortform) {
919 $rv .= '>' . $content . '</' . $name . '>';
924 $html_autoclose_stack = array();
925 $html_autoclose_pos = 0;
928 * html_ap() - Return XHTML element autoclose stack position
933 global $html_autoclose_pos;
935 return $html_autoclose_pos;
939 * html_ao() - Return proper element XHTML start tag, with autoclose
941 * @param string $name
943 * @param array $attrs
944 * (optional) associative array of element attributes
945 * values: arrays are space-imploded;
946 * false values and empty arrays ignored
948 * XHTML string suitable for echo'ing
950 function html_ao($name, $attrs=array()) {
951 global $html_autoclose_pos, $html_autoclose_stack;
953 $html_autoclose_stack[$html_autoclose_pos++] = array(
957 return html_eo($name, $attrs);
961 * html_aonce() - Return once proper element XHTML start tag, with autoclose
964 initialise this to false; will be modified
965 * @param string $name
967 * @param array $attrs
968 * (optional) associative array of element attributes
969 * values: arrays are space-imploded;
970 * false values and empty arrays ignored
972 * XHTML string suitable for echo'ing
974 function html_aonce(&$sptr, $name, $attrs=array()) {
975 if ($sptr !== false) {
980 return html_ao($name, $attrs);
984 * html_ac() - Return proper element XHTML end tags, autoclosing
986 * @param integer $spos
987 * stack position to return to
988 * (nothing is done if === false)
990 * XHTML string suitable for echo'ing
992 function html_ac($spos) {
993 global $html_autoclose_pos, $html_autoclose_stack;
995 if ($spos === false) {
996 /* support for html_aonce() */
1000 if ($html_autoclose_pos < $spos) {
1001 $e = "html_autoclose stack underflow; closing down to " .
1002 $spos . " but we're down to " . $html_autoclose_pos .
1004 throw new Exception($e);
1008 while ($html_autoclose_pos > $spos) {
1009 --$html_autoclose_pos;
1010 $rv .= '</' . $html_autoclose_stack[$html_autoclose_pos]['name'] . '>';
1011 unset($html_autoclose_stack[$html_autoclose_pos]);
1017 * html_a_copy() - Return a copy of part of the autoclose stack
1019 * @param integer $spos
1020 * stack position caller will return to
1022 * argument suitable for html_a_apply()
1024 function html_a_copy($spos) {
1025 global $html_autoclose_pos, $html_autoclose_stack;
1027 if ($spos === false) {
1031 if ($spos > $html_autoclose_pos) {
1032 $e = "html_autoclose stack underflow; closing down to " .
1033 $spos . " but we're down to " . $html_autoclose_pos .
1035 throw new Exception($e);
1039 while ($spos < $html_autoclose_pos) {
1040 $rv[] = $html_autoclose_stack[$spos++];
1046 * html_a_apply() - Reopen tags based on an autoclose stack copy
1048 * @param opaque $scopy
1049 * return value from html_a_copy()
1051 * XHTML string suitable for echo'ing
1053 function html_a_apply($scopy) {
1054 /* array_reduce() would be useful here... IF IT WORKED, FFS! */
1056 foreach ($scopy as $value) {
1057 $rv .= html_ao($value['name'], $value['attr']);
1064 // c-file-style: "bsd"