5 * Copyright 1999-2001 (c) VA Linux Systems
6 * Copyright 2010 (c) FusionForge Team
7 * Copyright (C) 2010-2012 Alain Peyrat - Alcatel-Lucent
8 * Copyright 2011, Franck Villaume - Capgemini
9 * Copyright 2011-2012, Franck Villaume - TrivialDev
10 * Copyright © 2011, 2012
11 * Thorsten “mirabilos” Glaser <t.glaser@tarent.de>
13 * This file is part of FusionForge. FusionForge is free software;
14 * you can redistribute it and/or modify it under the terms of the
15 * GNU General Public License as published by the Free Software
16 * Foundation; either version 2 of the Licence, or (at your option)
19 * FusionForge is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 require_once $gfcommon.'include/minijson.php';
32 * html_generic_fileheader() - Output <html><head> and <meta/> inside.
34 * @param string $title
35 * Mandatory content of <title> attribute,
36 * will be HTML-secured
38 function html_generic_fileheader($title) {
39 global $HTML, $sysDTDs, $sysXMLNSs;
42 throw new Exception('A title is mandatory in XHTML!');
45 $HTML->headerHTMLDeclaration();
47 echo '<meta http-equiv="Content-Type" ' .
48 'content="text/html; charset=utf-8" />' . "\n";
49 echo '<script language="JavaScript" type="text/javascript">//<![CDATA[' .
50 "\n\tvar sys_url_base = " . minijson_encode(util_make_url("/"),
53 $HTML->headerForgepluckerMeta();
54 echo html_e('title', array(), util_html_secure($title)) . "\n";
58 * html_feedback_top() - Show the feedback output at the top of the page.
60 * @param string The feedback.
62 function html_feedback_top($feedback) {
64 echo $HTML->feedback($feedback);
68 * html_warning_top() - Show the warning output at the top of the page.
70 * @param string The warning message.
72 function html_warning_top($msg) {
74 echo $HTML->warning_msg($msg);
78 * html_error_top() - Show the error output at the top of the page.
80 * @param string The error message.
82 function html_error_top($msg) {
84 echo $HTML->error_msg($msg);
88 * make_user_link() - Make a username reference into a link to that users User page on SF.
90 * @param string The username of the user to link.
92 function make_user_link($username, $displayname = '') {
93 if (empty($displayname))
94 $displayname = $username;
96 if (!strcasecmp($username,'Nobody') || !strcasecmp($username,'None')) {
99 return '<a href="/users/'.$username.'">'.$displayname.'</a>';
104 * html_feedback_bottom() - Show the feedback output at the bottom of the page.
106 * @param string The feedback.
108 function html_feedback_bottom($feedback) {
110 echo $HTML->feedback($feedback);
114 * html_blankimage() - Show the blank spacer image.
116 * @param int The height of the image
117 * @param int The width of the image
119 function html_blankimage($height,$width) {
120 return '<img src="/images/blank.png" width="' . $width . '" height="' . $height . '" alt="" />';
124 * html_abs_image() - Show an image given an absolute URL.
127 * @param int width of the image
128 * @param int height of the image
129 * @param array Any <img> tag parameters (i.e. 'border', 'alt', etc...)
131 function html_abs_image($url, $width, $height, $args) {
132 $return = ('<img src="' . $url . '"');
134 while(list($k,$v) = each($args)) {
135 $return .= ' '.$k.'="'.$v.'"';
138 if (!isset($args['alt'])) {
139 $return .= ' alt=""';
142 // Add image dimensions (if given)
143 $return .= $width ?" width=\"" . $width . "\"": '';
144 $return .= $height? " height=\"" . $height . "\"": '';
151 * html_image() - Build an image tag of an image contained in $src
153 * @param string The source location of the image
154 * @param int The width of the image
155 * @param int The height of the image
156 * @param array Any IMG tag parameters associated with this image (i.e. 'border', 'alt', etc...)
157 * @param bool DEPRECATED
159 function html_image($src, $width='', $height='', $args=array(), $display=1) {
162 if (method_exists($HTML, 'html_image')) {
163 $HTML->html_image($src, $width, $height, $args);
165 $s = ((session_issecure()) ? forge_get_config('images_secure_url') : forge_get_config('images_url') );
166 return html_abs_image($s.$HTML->imgroot.$src, $width, $height, $args);
170 * html_get_language_popup() - Pop up box of supported languages.
172 * @param string The title of the popup box.
173 * @param string Which element of the box is to be selected.
174 * @return string The html select box.
176 function html_get_language_popup($title='language_id', $selected='xzxz') {
177 $res = db_query_params('SELECT * FROM supported_languages ORDER BY name ASC',
179 return html_build_select_box($res, $title, $selected, false);
183 * html_get_theme_popup() - Pop up box of supported themes.
185 * @param string The title of the popup box.
186 * @param string Which element of the box is to be selected.
187 * @return string The html select box.
189 function html_get_theme_popup($title='theme_id', $selected='xzxz') {
190 $res=db_query_params('SELECT theme_id, fullname FROM themes WHERE enabled=true',
192 $nbTheme = db_numrows($res);
194 $thetheme = db_result($res, 0, 'fullname');
195 return util_html_secure($thetheme) . html_e('input', array(
198 'value' => db_result($res, 0, 'theme_id'),
200 } elseif ($nbTheme < 1) {
203 return html_build_select_box($res,$title,$selected,false);
208 * html_get_ccode_popup() - Pop up box of supported country_codes.
210 * @param string The title of the popup box.
211 * @param string Which element of the box is to be selected.
212 * @return string The html select box.
214 function html_get_ccode_popup($title='ccode', $selected='xzxz') {
215 $res=db_query_params('SELECT ccode,country_name FROM country_code ORDER BY country_name',
217 return html_build_select_box($res, $title, $selected, false);
221 * html_get_timezone_popup() - Pop up box of supported Timezones.
222 * Assumes you have included Timezones array file.
224 * @param string The title of the popup box.
225 * @param string Which element of the box is to be selected.
226 * @return string The html select box.
228 function html_get_timezone_popup($title='timezone', $selected='xzxz') {
230 if ($selected == 'xzxzxzx') {
231 $r = file('/etc/timezone');
232 $selected = str_replace("\n", '', $r[0]);
234 return html_build_select_box_from_arrays($TZs, $TZs, $title, $selected, false);
239 * html_build_select_box_from_assoc() - Takes one assoc array and returns a pop-up box.
241 * @param array An array of items to use.
242 * @param string The name you want assigned to this form element.
243 * @param string The value of the item that should be checked.
244 * @param boolean Whether we should swap the keys / names.
245 * @param bool Whether or not to show the '100 row'.
246 * @param string What to call the '100 row' defaults to none.
248 function html_build_select_box_from_assoc ($arr,$select_name,$checked_val='xzxz',$swap=false,$show_100=false,$text_100='None') {
250 $keys=array_values($arr);
251 $vals=array_keys($arr);
253 $vals=array_values($arr);
254 $keys=array_keys($arr);
256 return html_build_select_box_from_arrays ($keys,$vals,$select_name,$checked_val,$show_100,$text_100);
260 * html_build_select_box_from_array() - Takes one array, with the first array being the "id"
261 * or value and the array being the text you want displayed.
263 * @param array An array of items to use.
264 * @param string The name you want assigned to this form element.
265 * @param string The value of the item that should be checked.
267 function html_build_select_box_from_array ($vals,$select_name,$checked_val='xzxz',$samevals = 0) {
269 <select name="'.$select_name.'">';
271 $rows = count($vals);
273 for ($i = 0; $i < $rows; $i++) {
275 $return .= "\n\t\t<option value=\"" . $vals[$i] . "\"";
276 if ($vals[$i] == $checked_val) {
277 $return .= ' selected="selected"';
280 $return .= "\n\t\t<option value=\"" . $i .'"';
281 if ($i == $checked_val) {
282 $return .= ' selected="selected"';
285 $return .= '>'.htmlspecialchars($vals[$i]).'</option>';
294 * html_build_radio_buttons_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
295 * array being the text you want displayed.
297 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
298 * There must be a related row in users, categories, et , and by default that
299 * row is 100, so almost every pop-up box has 100 as the default
300 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
302 * @param array The ID or value
303 * @param array Text to be displayed
304 * @param string Name to assign to this form element
305 * @param string The item that should be checked
306 * @param bool Whether or not to show the '100 row'
307 * @param string What to call the '100 row' defaults to none
308 * @param bool Whether or not to show the 'Any row'
309 * @param string What to call the 'Any row' defaults to any
311 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') {
312 if ($text_100=='none'){
318 if (count($texts) != $rows) {
319 $return .= 'ERROR - uneven row counts';
322 //we don't always want the default Any row shown
325 <input type="radio" name="'.$select_name.'" value=""'.(($checked_val=='') ? ' checked="checked"' : '').' /> '. $text_any .'<br />';
327 //we don't always want the default 100 row shown
330 <input type="radio" name="'.$select_name.'" value="100"'.(($checked_val==100) ? ' checked="checked"' : '').' /> '. $text_100 .'<br />';
333 $checked_found=false;
335 for ($i=0; $i<$rows; $i++) {
336 // uggh - sorry - don't show the 100 row
337 // if it was shown above, otherwise do show it
338 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
340 <input type="radio" id="'.$select_name.'_'.$vals[$i].'" name="'.$select_name.'" value="'.$vals[$i].'"';
341 if ((string)$vals[$i] == (string)$checked_val) {
343 $return .= ' checked="checked"';
345 $return .= ' /> '.htmlspecialchars($texts[$i]).'<br />';
349 // If the passed in "checked value" was never "SELECTED"
350 // we want to preserve that value UNLESS that value was 'xzxz', the default value
352 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
354 <input type="radio" value="'.$checked_val.'" checked="checked" /> '._('No Change').'<br />';
361 * html_get_tooltip_description() - Get the tooltip description of the element
363 * @param string element name
366 function html_get_tooltip_description($element_name) {
367 global $use_tooltips;
369 switch( $element_name ) {
371 return( _('This drop-down box represents the person to which a tracker item is assigned.'));
373 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\'.'));
375 return( _('Tracker category'));
377 return( _('Tracker group'));
379 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.'));
380 case 'new_artifact_type_id':
381 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.'));
383 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.'));
385 return( _('Resolution'));
387 return( _('The summary text-box represents a short tracker item summary. Useful when browsing through several tracker items.'));
388 case 'canned_response':
389 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'));
391 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.'));
393 return( htmlentities(_('Enter the complete description.').'<br/><br/>'.
394 _("<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>"),
395 ENT_COMPAT, 'UTF-8'));
397 return( _('When you wish to attach a file to a tracker item you must check this checkbox before submitting changes.'));
399 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!'),
400 ENT_COMPAT, 'UTF-8'));
409 function html_use_jquery() {
410 use_javascript('/scripts/jquery/jquery-1.8.3.js');
413 function html_use_tooltips() {
415 use_javascript('/scripts/jquery-tipsy/src/javascripts/jquery.tipsy.js');
416 use_javascript('/js/jquery-common.js');
417 use_stylesheet('/scripts/jquery-tipsy/src/stylesheets/tipsy.css');
420 function html_use_storage() {
422 use_javascript('/scripts/jquery-storage/jquery.Storage.js');
425 function html_use_simplemenu() {
427 use_javascript('/scripts/jquery-simpletreemenu/js/jquery-simpleTreeMenu-1.5.0.js');
428 use_stylesheet('/scripts/jquery-simpletreemenu/css/jquery-simpleTreeMenu-1.5.0.css');
431 function html_use_coolfieldset() {
433 use_javascript('/scripts/coolfieldset/js/jquery.coolfieldset.js');
434 use_javascript('/js/jquery-common.js');
435 use_stylesheet('/scripts/coolfieldset/css/jquery.coolfieldset.css');
438 function html_use_jqueryui() {
440 use_javascript('/scripts/jquery-ui/js/jquery-ui-1.9.2.custom.js');
441 use_stylesheet('/scripts/jquery-ui/css/overcast/jquery-ui-1.9.2.custom.css');
444 function html_use_jqueryjqplot() {
446 use_javascript('/scripts/jquery-jqplot/jquery.jqplot.js');
447 use_stylesheet('/scripts/jquery-jqplot/jquery.jqplot.css');
450 function html_use_jqueryjqplotpluginCanvas() {
451 html_use_jqueryjqplot();
452 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasTextRenderer.js');
453 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasAxisLabelRenderer.js');
454 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasAxisTickRenderer.js');
455 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.categoryAxisRenderer.js');
458 function html_use_jqueryjqplotpluginBar() {
459 html_use_jqueryjqplot();
460 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.barRenderer.js');
461 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.pointLabels.js');
462 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.categoryAxisRenderer.js');
465 function html_use_jqueryjqplotpluginPie() {
466 html_use_jqueryjqplot();
467 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.pieRenderer.js');
470 function html_use_jqueryjqplotpluginhighlighter() {
471 html_use_jqueryjqplot();
472 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.highlighter.js');
475 function html_use_jqueryjqplotplugindateAxisRenderer() {
476 html_use_jqueryjqplot();
477 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.dateAxisRenderer.js');
481 * html_build_select_box_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
482 * array being the text you want displayed.
484 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
485 * There must be a related row in users, categories, et , and by default that
486 * row is 100, so almost every pop-up box has 100 as the default
487 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
489 * @param array The ID or value
490 * @param array Text to be displayed
491 * @param string Name to assign to this form element
492 * @param string The item that should be checked
493 * @param bool Whether or not to show the '100 row'
494 * @param string What to call the '100 row' defaults to none
495 * @param bool Whether or not to show the 'Any row'
496 * @param string What to call the 'Any row' defaults to any
497 * @param array Array of all allowed values from the full list.
499 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) {
500 $have_a_subelement = false;
502 if ($text_100=='none'){
503 $text_100 = _('None');
507 $rows = count($vals);
508 if (count($texts) != $rows) {
509 $return .= _('ERROR - uneven row counts');
512 //TODO: remove this ugly ack to get something more generic...
513 $title = html_get_tooltip_description($select_name);
516 $id = ' id="tracker-'.$select_name.'"';
517 if (preg_match('/\[\]/', $id)) {
523 <select'.$id.' name="'.$select_name.'" title="'.util_html_secure($title).'">';
525 //we don't always want the default Any row shown
528 <option value=""'.(($checked_val=='') ? ' selected="selected"' : '').'>'. util_html_secure($text_any) .'</option>';
529 $have_a_subelement = true;
531 //we don't always want the default 100 row shown
534 <option value="100"'.(($checked_val==100) ? ' selected="selected"' : '').'>'. util_html_secure($text_100) .'</option>';
535 $have_a_subelement = true;
538 $checked_found=false;
540 for ($i=0; $i<$rows; $i++) {
541 // uggh - sorry - don't show the 100 row
542 // if it was shown above, otherwise do show it
543 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
545 <option value="'.util_html_secure($vals[$i]).'"';
546 if ((string)$vals[$i] == (string)$checked_val) {
548 $return .= ' selected="selected"';
550 if (is_array($allowed) && !in_array($vals[$i], $allowed)) {
551 $return .= ' disabled="disabled" class="option_disabled"';
553 $return .= '>'.util_html_secure($texts[$i]).'</option>';
554 $have_a_subelement = true;
558 // If the passed in "checked value" was never "SELECTED"
559 // we want to preserve that value UNLESS that value was 'xzxz', the default value
561 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
563 <option value="'.util_html_secure($checked_val).'" selected="selected">'._('No Change').'</option>';
564 $have_a_subelement = true;
567 if (!$have_a_subelement) {
568 /* <select></select> without <option/> in between is invalid */
569 return '<!-- select without options -->';
578 * html_build_select_box() - Takes a result set, with the first column being the "id" or value and
579 * the second column being the text you want displayed.
581 * @param int The result set
582 * @param string Text to be displayed
583 * @param string The item that should be checked
584 * @param bool Whether or not to show the '100 row'
585 * @param string What to call the '100 row'. Defaults to none.
587 function html_build_select_box ($result, $name, $checked_val="xzxz", $show_100=true, $text_100='none', $show_any=false, $text_any='Select One') {
588 if ($text_100=='none'){
591 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);
595 * html_build_select_box_sorted() - Takes a result set, with the first column being the "id" or value and
596 * the second column being the text you want displayed.
598 * @param int The result set
599 * @param string Text to be displayed
600 * @param string The item that should be checked
601 * @param bool Whether or not to show the '100 row'
602 * @param string What to call the '100 row'. Defaults to none.
604 function html_build_select_box_sorted ($result, $name, $checked_val="xzxz",$show_100=true,$text_100='none') {
605 if ($text_100=='none'){
608 $vals = util_result_column_to_array($result, 0);
609 $texts = util_result_column_to_array($result, 1);
610 array_multisort($texts, SORT_ASC, SORT_STRING,
612 return html_build_select_box_from_arrays ($vals, $texts, $name, $checked_val, $show_100, $text_100);
616 * html_build_multiple_select_box() - Takes a result set, with the first column being the "id" or value
617 * and the second column being the text you want displayed.
619 * @param int The result set
620 * @param string Text to be displayed
621 * @param string The item that should be checked
622 * @param int The size of this box
623 * @param bool Whether or not to show the '100 row'
625 function html_build_multiple_select_box ($result,$name,$checked_array,$size='8',$show_100=true) {
626 $checked_count=count($checked_array);
628 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
631 Put in the default NONE box
634 <option value="100"';
635 for ($j=0; $j<$checked_count; $j++) {
636 if ($checked_array[$j] == '100') {
637 $return .= ' selected="selected"';
640 $return .= '>'._('None').'</option>';
643 $rows=db_numrows($result);
644 for ($i=0; $i<$rows; $i++) {
645 if ((db_result($result,$i,0) != '100') || (db_result($result,$i,0) == '100' && !$show_100)) {
647 <option value="'.db_result($result,$i,0).'"';
649 Determine if it's checked
651 $val=db_result($result,$i,0);
652 for ($j=0; $j<$checked_count; $j++) {
653 if ($val == $checked_array[$j]) {
654 $return .= ' selected="selected"';
657 $return .= '>'. substr(db_result($result,$i,1),0,35). '</option>';
666 * html_build_multiple_select_box_from_arrays() - Takes two arrays and builds a multi-select box
668 * @param array id of the field
669 * @param array Text to be displayed
670 * @param string id of the items selected
671 * @param string The item that should be checked
672 * @param int The size of this box
673 * @param bool Whether or not to show the '100 row'
675 function html_build_multiple_select_box_from_arrays($ids,$texts,$name,$checked_array,$size='8',$show_100=true,$text_100='none') {
676 $checked_count=count($checked_array);
678 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
680 if ($text_100=='none') {
684 Put in the default NONE box
687 <option value="100"';
688 for ($j=0; $j<$checked_count; $j++) {
689 if ($checked_array[$j] == '100') {
690 $return .= ' selected="selected"';
693 $return .= '>'.$text_100.'</option>';
697 for ($i=0; $i<$rows; $i++) {
698 if (( $ids[$i] != '100') || ($ids[$i] == '100' && !$show_100)) {
700 <option value="'.$ids[$i].'"';
702 Determine if it's checked
705 for ($j=0; $j<$checked_count; $j++) {
706 if ($val == $checked_array[$j]) {
707 $return .= ' selected="selected"';
710 $return .= '>'.$texts[$i].' </option>';
719 * html_build_checkbox() - Render checkbox control
721 * @param name - name of control
722 * @param value - value of control
723 * @param checked - true if control should be checked
724 * @return html code for checkbox control
726 function html_build_checkbox($name, $value, $checked) {
727 return '<input type="checkbox" name="'.$name.'"'
728 .' value="'.$value.'"'
729 .($checked ? 'checked="checked"' : '').'>';
734 * build_priority_select_box() - Wrapper for html_build_priority_select_box()
736 * @see html_build_priority_select_box()
738 function build_priority_select_box ($name='priority', $checked_val='3', $nochange=false) {
739 echo html_build_priority_select_box ($name, $checked_val, $nochange);
743 * html_build_priority_select_box() - Return a select box of standard priorities.
744 * The name of this select box is optional and so is the default checked value.
746 * @param string Name of the select box
747 * @param string The value to be checked
748 * @param bool Whether to make 'No Change' selected.
750 function html_build_priority_select_box ($name='priority', $checked_val='3', $nochange=false) {
752 <select id="tracker-<?php echo $name ?>" name="<?php echo $name; ?>" title="<?php echo util_html_secure(html_get_tooltip_description($name)) ?>">
753 <?php if($nochange) { ?>
754 <option value="100"<?php if ($nochange) {echo " selected=\"selected\"";} ?>><?php echo _('No Change') ?></option>
756 <option value="1"<?php if ($checked_val=="1") {echo " selected=\"selected\"";} ?>>1 - <?php echo _('Lowest') ?></option>
757 <option value="2"<?php if ($checked_val=="2") {echo " selected=\"selected\"";} ?>>2</option>
758 <option value="3"<?php if ($checked_val=="3") {echo " selected=\"selected\"";} ?>>3</option>
759 <option value="4"<?php if ($checked_val=="4") {echo " selected=\"selected\"";} ?>>4</option>
760 <option value="5"<?php if ($checked_val=="5") {echo " selected=\"selected\"";} ?>>5 - <?php echo _('Highest') ?></option>
767 * html_buildcheckboxarray() - Build an HTML checkbox array.
769 * @param array Options array
770 * @param name Checkbox name
771 * @param array Array of boxes to be pre-checked
773 function html_buildcheckboxarray($options,$name,$checked_array) {
774 $option_count=count($options);
775 $checked_count=count($checked_array);
777 for ($i=1; $i<=$option_count; $i++) {
779 <br /><input type="checkbox" name="'.$name.'" value="'.$i.'"';
780 for ($j=0; $j<$checked_count; $j++) {
781 if ($i == $checked_array[$j]) {
782 echo ' checked="checked"';
785 echo ' /> '.$options[$i];
790 * site_header() - everything required to handle security and
791 * add navigation for user pages like /my/ and /account/
793 * @param array Must contain $user_id
795 function site_header($params) {
798 Check to see if active user
799 Check to see if logged in
801 $HTML->header($params);
805 * site_footer() - Show the HTML site footer.
807 * @param array Footer params array
809 function site_footer($params) {
811 $HTML->footer($params);
815 * site_project_header() - everything required to handle
816 * security and state checks for a project web page
818 * @param params array() must contain $toptab and $group
820 function site_project_header($params) {
824 Check to see if active
825 Check to see if project rather than foundry
826 Check to see if private (if private check if user_ismember)
829 $group_id=$params['group'];
831 //get the project object
832 $project = group_get_object($group_id);
834 if (!$project || !is_object($project)) {
836 } elseif ($project->isError()) {
837 if ($project->isPermissionDeniedError()) {
838 if (!session_get_user()) {
839 $next = '/account/login.php?error_msg='.urlencode($project->getErrorMessage());
840 if (getStringFromServer('REQUEST_METHOD') != 'POST') {
841 $next .= '&return_to='.urlencode(getStringFromServer('REQUEST_URI'));
843 session_redirect($next);
846 exit_error(sprintf(_('Project access problem: %s'),$project->getErrorMessage()),'home');
848 exit_error(sprintf(_('Project Problem: %s'),$project->getErrorMessage()),'home');
851 // Check permissions in case of restricted access
852 session_require_perm ('project_read', $group_id);
854 //for dead projects must be member of admin project
855 if (!$project->isActive()) {
856 session_require_global_perm ('forge_admin');
859 if (isset($params['title'])){
860 $h1=$params['title'];
861 $params['title']=$project->getPublicName().': '.$params['title'];
863 $h1=$project->getPublicName();
864 $params['title']=$project->getPublicName();
866 if (!isset($params['h1'])){
870 if ($project->getDescription()) {
871 $params['meta-description'] = $project->getDescription();
874 if (forge_get_config('use_project_tags')) {
875 $res = db_query_params('SELECT name FROM project_tags WHERE group_id = $1', array($group_id));
876 if ($res && db_numrows($res) > 0) {
877 while ($row = db_fetch_array($res)) {
878 $array[] = $row['name'];
880 $params['meta-keywords'] = htmlspecialchars(join(', ', $array));
884 site_header($params);
888 * site_project_footer() - currently a simple shim
889 * that should be on every project page, rather than
890 * a direct call to site_footer() or theme_footer()
892 * @param params array() empty
894 function site_project_footer($params) {
895 site_footer($params);
899 * site_user_header() - everything required to handle security and
900 * add navigation for user pages like /my/ and /account/
902 * @param params array() must contain $user_id
904 function site_user_header($params) {
908 Check to see if active user
909 Check to see if logged in
911 site_header($params);
912 echo ($HTML->beginSubMenu());
917 $arr_t[] = _('My Personal Page');
919 $arr_attr[] = array('title' => _('View your personal page, a selection of widgets to follow the informations from projects.'), 'class' => 'tabtitle-nw');
921 if (forge_get_config('use_tracker')) {
922 $arr_t[] = _('Trackers dashboard');
923 $arr_l[] = '/my/dashboard.php';
924 $arr_attr[] = array('title' => _('View your tasks and artifacts.'), 'class' => 'tabtitle');
928 if (forge_get_config('use_diary')) {
929 $arr_t[] = _('Diary & Notes');
930 $arr_l[] = '/my/diary.php';
931 $arr_attr[] = array('title' => _('Manage your diary. Add, modify or delete your notes.'), 'class' => 'tabtitle');
934 $arr_t[] = _('Account Maintenance');
935 $arr_l[] = '/account/';
936 $arr_attr[] = array('title' => _('Manage your account. Change your password, select your preferences.'), 'class' => 'tabtitle');
938 if (!forge_get_config('project_registration_restricted')
939 || forge_check_global_perm('approve_projects', '')) {
940 $arr_t[] = _('Register Project');
941 $arr_l[] = '/register/';
942 $arr_attr[] = array('title' => _('Register a new project in forge, following the workflow.'), 'class' => 'tabtitle');
945 echo ($HTML->printSubMenu($arr_t, $arr_l, $arr_attr));
946 if ( plugin_hook_listeners("usermenu") > 0 ) {
947 echo $HTML->subMenuSeparator();
949 plugin_hook("usermenu", false);
950 echo ($HTML->endSubMenu());
954 * site_user_footer() - currently a simple shim that should be on every user page,
955 * rather than a direct call to site_footer() or theme_footer()
957 * @param params array() empty
959 function site_user_footer($params) {
960 site_footer($params);
964 * html_clean_hash_string() - Remove noise characters from hex hash string
966 * Thruout SourceForge, URLs with hexadecimal hash string parameters
967 * are being sent via email to request confirmation of user actions.
968 * It was found that some mail clients distort this hash, so we take
969 * special steps to encode it in the way which help to preserve its
970 * recognition. This routine
972 * @param hashstr required hash parameter as received from browser
973 * @return pure hex string
975 function html_clean_hash_string($hashstr) {
977 if (substr($hashstr,0,1)=="_") {
978 $hashstr = substr($hashstr, 1);
981 if (substr($hashstr, strlen($hashstr)-1, 1)==">") {
982 $hashstr = substr($hashstr, 0, strlen($hashstr)-1);
988 function relative_date ($date) {
989 $delta = time() - $date;
991 return sprintf(ngettext('%d second ago', '%d seconds ago', $delta), $delta);
993 $delta = round($delta/60);
995 return sprintf(ngettext('%d minute ago', '%d minutes ago', $delta), $delta);
997 $delta = round($delta/60);
999 return sprintf(ngettext('%d hour ago', '%d hours ago', $delta), $delta);
1001 $delta = round($delta/24);
1003 return sprintf(ngettext('%d day ago', '%d days ago', $delta), $delta);
1005 $delta = round($delta/7);
1007 return sprintf(ngettext('%d week ago', '%d weeks ago', $delta), $delta);
1009 return date(_('Y-m-d H:i'), $date);
1012 /* TODO: think about beautifying output */
1015 * html_eo() - Return proper element XHTML start tag
1017 * @param string $name
1019 * @param array $attrs
1020 * (optional) associative array of element attributes
1021 * values: arrays are space-imploded;
1022 * false values and empty arrays ignored
1024 * XHTML string suitable for echo'ing
1026 function html_eo($name, $attrs=array()) {
1028 foreach ($attrs as $key => $value) {
1029 if (is_array($value)) {
1030 $value = count($value) ? implode(" ", $value) : false;
1032 if ($value === false) {
1035 $rv .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
1042 * html_e() - Return proper element XHTML start/end sequence
1044 * @param string $name
1046 * @param array $attrs
1047 * (optional) associative array of element attributes
1048 * values: arrays are space-imploded;
1049 * false values and empty arrays ignored
1050 * @param string $content
1051 * (optional) XHTML to be placed inside
1052 * @param bool $shortform
1053 * (optional) allow short open-close form
1056 * XHTML string suitable for echo'ing
1058 function html_e($name, $attrs=array(), $content="", $shortform=true) {
1060 foreach ($attrs as $key => $value) {
1061 if (is_array($value)) {
1062 $value = count($value) ? implode(" ", $value) : false;
1064 if ($value === false) {
1067 $rv .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
1069 if ($content === "" && $shortform) {
1072 $rv .= '>' . $content . '</' . $name . '>';
1077 $html_autoclose_stack = array();
1078 $html_autoclose_pos = 0;
1081 * html_ap() - Return XHTML element autoclose stack position
1085 function html_ap() {
1086 global $html_autoclose_pos;
1088 return $html_autoclose_pos;
1092 * html_ao() - Return proper element XHTML start tag, with autoclose
1094 * @param string $name
1096 * @param array $attrs
1097 * (optional) associative array of element attributes
1098 * values: arrays are space-imploded;
1099 * false values and empty arrays ignored
1101 * XHTML string suitable for echo'ing
1103 function html_ao($name, $attrs=array()) {
1104 global $html_autoclose_pos, $html_autoclose_stack;
1106 $html_autoclose_stack[$html_autoclose_pos++] = array(
1110 return html_eo($name, $attrs);
1114 * html_aonce() - Return once proper element XHTML start tag, with autoclose
1117 initialise this to false; will be modified
1118 * @param string $name
1120 * @param array $attrs
1121 * (optional) associative array of element attributes
1122 * values: arrays are space-imploded;
1123 * false values and empty arrays ignored
1125 * XHTML string suitable for echo'ing
1127 function html_aonce(&$sptr, $name, $attrs=array()) {
1128 if ($sptr !== false) {
1133 return html_ao($name, $attrs);
1137 * html_ac() - Return proper element XHTML end tags, autoclosing
1139 * @param integer $spos
1140 * stack position to return to
1141 * (nothing is done if === false)
1143 * XHTML string suitable for echo'ing
1145 function html_ac($spos) {
1146 global $html_autoclose_pos, $html_autoclose_stack;
1148 if ($spos === false) {
1149 /* support for html_aonce() */
1153 if ($html_autoclose_pos < $spos) {
1154 $e = "html_autoclose stack underflow; closing down to " .
1155 $spos . " but we're down to " . $html_autoclose_pos .
1157 throw new Exception($e);
1161 while ($html_autoclose_pos > $spos) {
1162 --$html_autoclose_pos;
1163 $rv .= '</' . $html_autoclose_stack[$html_autoclose_pos]['name'] . '>';
1164 unset($html_autoclose_stack[$html_autoclose_pos]);
1170 * html_a_copy() - Return a copy of part of the autoclose stack
1172 * @param integer $spos
1173 * stack position caller will return to
1175 * argument suitable for html_a_apply()
1177 function html_a_copy($spos) {
1178 global $html_autoclose_pos, $html_autoclose_stack;
1180 if ($spos === false) {
1184 if ($spos > $html_autoclose_pos) {
1185 $e = "html_autoclose stack underflow; closing down to " .
1186 $spos . " but we're down to " . $html_autoclose_pos .
1188 throw new Exception($e);
1192 while ($spos < $html_autoclose_pos) {
1193 $rv[] = $html_autoclose_stack[$spos++];
1199 * html_a_apply() - Reopen tags based on an autoclose stack copy
1201 * @param opaque $scopy
1202 * return value from html_a_copy()
1204 * XHTML string suitable for echo'ing
1206 function html_a_apply($scopy) {
1207 /* array_reduce() would be useful here... IF IT WORKED, FFS! */
1209 foreach ($scopy as $value) {
1210 $rv .= html_ao($value['name'], $value['attr']);
1217 // c-file-style: "bsd"