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-2013, 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 $title string
35 * Mandatory content of <title> attribute, 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 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.
93 function make_user_link($username, $displayname = '') {
94 if (empty($displayname))
95 $displayname = $username;
97 if (!strcasecmp($username, 'Nobody') || !strcasecmp($username, 'None')) {
100 return '<a href="/users/'.$username.'">'.$displayname.'</a>';
105 * html_feedback_bottom() - Show the feedback output at the bottom of the page.
107 * @param string The feedback.
109 function html_feedback_bottom($feedback) {
111 echo $HTML->feedback($feedback);
115 * html_blankimage() - Show the blank spacer image.
117 * @param int The height of the image
118 * @param int The width of the image
121 function html_blankimage($height, $width) {
122 return '<img src="/images/blank.png" width="'.$width.'" height="'.$height.'" alt="" />';
126 * html_abs_image() - Show an image given an absolute URL.
129 * @param int width of the image
130 * @param int height of the image
131 * @param array Any <img> tag parameters (i.e. 'border', 'alt', etc...)
134 function html_abs_image($url, $width, $height, $args) {
135 $return = ('<img src="'.$url.'"');
137 while (list($k, $v) = each($args)) {
138 $return .= ' '.$k.'="'.$v.'"';
141 if (!isset($args['alt'])) {
142 $return .= ' alt=""';
145 // Add image dimensions (if given)
146 $return .= $width ? " width=\"".$width."\"" : '';
147 $return .= $height ? " height=\"".$height."\"" : '';
154 * html_image() - Build an image tag of an image contained in $src
156 * @param string The source location of the image
157 * @param int The width of the image
158 * @param int The height of the image
159 * @param array Any IMG tag parameters associated with this image (i.e. 'border', 'alt', etc...)
160 * @param bool DEPRECATED
162 function html_image($src, $width = '', $height = '', $args = array(), $display = 1) {
165 if (method_exists($HTML, 'html_image')) {
166 $HTML->html_image($src, $width, $height, $args);
168 $s = ((session_issecure()) ? forge_get_config('images_secure_url') : forge_get_config('images_url') );
169 return html_abs_image($s.$HTML->imgroot.$src, $width, $height, $args);
173 * html_get_language_popup() - Pop up box of supported languages.
175 * @param string The title of the popup box.
176 * @param string Which element of the box is to be selected.
177 * @return string The html select box.
179 function html_get_language_popup($title = 'language_id', $selected = 'xzxz') {
180 $res = db_query_params('SELECT * FROM supported_languages ORDER BY name ASC',
182 return html_build_select_box($res, $title, $selected, false);
186 * html_get_theme_popup() - Pop up box of supported themes.
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_theme_popup($title = 'theme_id', $selected = 'xzxz') {
193 $res = db_query_params('SELECT theme_id, fullname FROM themes WHERE enabled=true',
195 $nbTheme = db_numrows($res);
197 $thetheme = db_result($res, 0, 'fullname');
198 return util_html_secure($thetheme) . html_e('input', array(
201 'value' => db_result($res, 0, 'theme_id'),
203 } elseif ($nbTheme < 1) {
206 return html_build_select_box($res, $title, $selected, false);
211 * html_get_ccode_popup() - Pop up box of supported country_codes.
213 * @param string The title of the popup box.
214 * @param string Which element of the box is to be selected.
215 * @return string The html select box.
217 function html_get_ccode_popup($title = 'ccode', $selected = 'xzxz') {
218 $res = db_query_params('SELECT ccode,country_name FROM country_code ORDER BY country_name',
220 return html_build_select_box($res, $title, $selected, false);
224 * html_get_timezone_popup() - Pop up box of supported Timezones.
225 * Assumes you have included Timezones array file.
227 * @param string The title of the popup box.
228 * @param string Which element of the box is to be selected.
229 * @return string The html select box.
231 function html_get_timezone_popup($title = 'timezone', $selected = 'xzxz') {
233 if ($selected == 'xzxzxzx') {
234 $r = file('/etc/timezone');
235 $selected = str_replace("\n", '', $r[0]);
237 return html_build_select_box_from_arrays($TZs, $TZs, $title, $selected, false);
242 * html_build_select_box_from_assoc() - Takes one assoc array and returns a pop-up box.
244 * @param array An array of items to use.
245 * @param string The name you want assigned to this form element.
246 * @param string The value of the item that should be checked.
247 * @param boolean Whether we should swap the keys / names.
248 * @param bool Whether or not to show the '100 row'.
249 * @param string What to call the '100 row' defaults to none.
252 function html_build_select_box_from_assoc($arr, $select_name, $checked_val = 'xzxz', $swap = false, $show_100 = false, $text_100 = 'None') {
254 $keys = array_values($arr);
255 $vals = array_keys($arr);
257 $vals = array_values($arr);
258 $keys = array_keys($arr);
260 return html_build_select_box_from_arrays($keys, $vals, $select_name, $checked_val, $show_100, $text_100);
264 * html_build_select_box_from_array() - Takes one array, with the first array being the "id"
265 * or value and the array being the text you want displayed.
267 * @param array An array of items to use.
268 * @param string The name you want assigned to this form element.
269 * @param string The value of the item that should be checked.
272 function html_build_select_box_from_array($vals, $select_name, $checked_val = 'xzxz', $samevals = 0) {
274 <select name="'.$select_name.'">';
276 $rows = count($vals);
278 for ($i = 0; $i < $rows; $i++) {
280 $return .= "\n\t\t<option value=\"".$vals[$i]."\"";
281 if ($vals[$i] == $checked_val) {
282 $return .= ' selected="selected"';
285 $return .= "\n\t\t<option value=\"".$i.'"';
286 if ($i == $checked_val) {
287 $return .= ' selected="selected"';
290 $return .= '>'.htmlspecialchars($vals[$i]).'</option>';
299 * html_build_radio_buttons_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
300 * array being the text you want displayed.
302 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
303 * There must be a related row in users, categories, et , and by default that
304 * row is 100, so almost every pop-up box has 100 as the default
305 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
307 * @param array The ID or value
308 * @param array Text to be displayed
309 * @param string Name to assign to this form element
310 * @param string The item that should be checked
311 * @param bool Whether or not to show the '100 row'
312 * @param string What to call the '100 row' defaults to none
313 * @param bool Whether or not to show the 'Any row'
314 * @param string What to call the 'Any row' defaults to any
317 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') {
318 if ($text_100 == 'none') {
319 $text_100 = _('None');
323 $rows = count($vals);
324 if (count($texts) != $rows) {
325 $return .= 'Error: uneven row counts';
328 //we don't always want the default Any row shown
331 <input type="radio" name="'.$select_name.'" value=""'.(($checked_val == '')? ' checked="checked"' : '').' /> '.$text_any.'<br />';
333 //we don't always want the default 100 row shown
336 <input type="radio" name="'.$select_name.'" value="100"'.(($checked_val == 100)? ' checked="checked"' : '').' /> '.$text_100.'<br />';
339 $checked_found = false;
341 for ($i = 0; $i < $rows; $i++) {
342 // uggh - sorry - don't show the 100 row
343 // if it was shown above, otherwise do show it
344 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
346 <input type="radio" id="'.$select_name.'_'.$vals[$i].'" name="'.$select_name.'" value="'.$vals[$i].'"';
347 if ((string)$vals[$i] == (string)$checked_val) {
348 $checked_found = true;
349 $return .= ' checked="checked"';
351 $return .= ' /> '.htmlspecialchars($texts[$i]).'<br />';
355 // If the passed in "checked value" was never "SELECTED"
356 // we want to preserve that value UNLESS that value was 'xzxz', the default value
358 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
360 <input type="radio" value="'.$checked_val.'" checked="checked" /> '._('No Change').'<br />';
367 * html_get_tooltip_description() - Get the tooltip description of the element
369 * @param string element name
372 function html_get_tooltip_description($element_name) {
373 global $use_tooltips;
375 switch( $element_name ) {
377 return( _('This drop-down box represents the person to which a tracker item is assigned.'));
379 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\'.'));
381 return( _('Tracker category'));
383 return( _('Tracker group'));
385 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.'));
386 case 'new_artifact_type_id':
387 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.'));
389 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.'));
391 return( _('Resolution'));
393 return( _('The summary text-box represents a short tracker item summary. Useful when browsing through several tracker items.'));
394 case 'canned_response':
395 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'));
397 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.'));
399 return( htmlentities(_('Enter the complete description.').'<br/><br/>'.
400 _("<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>"),
401 ENT_COMPAT, 'UTF-8'));
403 return( _('When you wish to attach a file to a tracker item you must check this checkbox before submitting changes.'));
405 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!'),
406 ENT_COMPAT, 'UTF-8'));
415 function html_use_jquery() {
416 use_javascript('/scripts/jquery/jquery-1.8.3.js');
419 function html_use_tooltips() {
421 use_javascript('/scripts/jquery-tipsy/src/javascripts/jquery.tipsy.js');
422 use_javascript('/js/jquery-common.js');
423 use_stylesheet('/scripts/jquery-tipsy/src/stylesheets/tipsy.css');
426 function html_use_storage() {
428 use_javascript('/scripts/jquery-storage/jquery.Storage.js');
431 function html_use_simplemenu() {
433 use_javascript('/scripts/jquery-simpletreemenu/js/jquery-simpleTreeMenu-1.5.0.js');
434 use_stylesheet('/scripts/jquery-simpletreemenu/css/jquery-simpleTreeMenu-1.5.0.css');
437 function html_use_coolfieldset() {
439 use_javascript('/scripts/coolfieldset/js/jquery.coolfieldset.js');
440 use_javascript('/js/jquery-common.js');
441 use_stylesheet('/scripts/coolfieldset/css/jquery.coolfieldset.css');
444 function html_use_jqueryui() {
446 use_javascript('/scripts/jquery-ui/js/jquery-ui-1.9.2.custom.js');
447 use_stylesheet('/scripts/jquery-ui/css/overcast/jquery-ui-1.9.2.custom.css');
450 function html_use_jqueryjqplot() {
452 use_javascript('/scripts/jquery-jqplot/jquery.jqplot.js');
453 use_stylesheet('/scripts/jquery-jqplot/jquery.jqplot.css');
456 function html_use_jqueryjqplotpluginCanvas() {
457 html_use_jqueryjqplot();
458 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasTextRenderer.js');
459 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasAxisLabelRenderer.js');
460 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasAxisTickRenderer.js');
461 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.categoryAxisRenderer.js');
464 function html_use_jqueryjqplotpluginBar() {
465 html_use_jqueryjqplot();
466 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.barRenderer.js');
467 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.pointLabels.js');
468 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.categoryAxisRenderer.js');
471 function html_use_jqueryjqplotpluginPie() {
472 html_use_jqueryjqplot();
473 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.pieRenderer.js');
476 function html_use_jqueryjqplotpluginhighlighter() {
477 html_use_jqueryjqplot();
478 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.highlighter.js');
481 function html_use_jqueryjqplotplugindateAxisRenderer() {
482 html_use_jqueryjqplot();
483 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.dateAxisRenderer.js');
486 function html_use_jqueryteamworkgantt() {
488 use_javascript('/scripts/jquery-teamwork-gantt/libs/jquery.livequery.min.js');
489 use_javascript('/scripts/jquery-teamwork-gantt/libs/jquery.timers.js');
490 use_javascript('/scripts/jquery-teamwork-gantt/libs/platform.js');
491 use_javascript('/scripts/jquery-teamwork-gantt/libs/date.js');
492 use_javascript('/scripts/jquery-teamwork-gantt/libs/date.js');
493 use_javascript('/scripts/jquery-teamwork-gantt/libs/i18nJs.js');
494 use_javascript('/scripts/jquery-teamwork-gantt/libs/dateField/jquery.dateField.js');
495 use_javascript('/scripts/jquery-teamwork-gantt/libs/JST/jquery.JST.js');
496 use_javascript('/scripts/jquery-teamwork-gantt/ganttUtilities.js');
497 use_javascript('/scripts/jquery-teamwork-gantt/ganttTask.js');
498 use_javascript('/scripts/jquery-teamwork-gantt/ganttDrawer.js');
499 use_javascript('/scripts/jquery-teamwork-gantt/ganttGridEditor.js');
500 use_javascript('/scripts/jquery-teamwork-gantt/ganttMaster.js');
501 use_stylesheet('/scripts/jquery-teamwork-gantt/platform.css');
502 use_stylesheet('/scripts/jquery-teamwork-gantt/libs/dateField/jquery.dateField.css');
503 use_stylesheet('/scripts/jquery-teamwork-gantt/gantt.css');
507 * html_build_select_box_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
508 * array being the text you want displayed.
510 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
511 * There must be a related row in users, categories, et , and by default that
512 * row is 100, so almost every pop-up box has 100 as the default
513 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
515 * @param array The ID or value
516 * @param array Text to be displayed
517 * @param string Name to assign to this form element
518 * @param string The item that should be checked
519 * @param bool Whether or not to show the '100 row'
520 * @param string What to call the '100 row' defaults to none
521 * @param bool Whether or not to show the 'Any row'
522 * @param string What to call the 'Any row' defaults to any
523 * @param array Array of all allowed values from the full list.
526 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) {
527 $have_a_subelement = false;
529 if ($text_100 == 'none') {
530 $text_100 = _('None');
534 $rows = count($vals);
535 if (count($texts) != $rows) {
536 $return .= _('Error: uneven row counts');
539 //TODO: remove this ugly ack to get something more generic...
540 $title = html_get_tooltip_description($select_name);
543 $id = ' id="tracker-'.$select_name.'"';
544 if (preg_match('/\[\]/', $id)) {
550 <select'.$id.' name="'.$select_name.'" title="'.util_html_secure($title).'">';
552 //we don't always want the default Any row shown
555 <option value=""'.(($checked_val=='') ? ' selected="selected"' : '').'>'. util_html_secure($text_any) .'</option>';
556 $have_a_subelement = true;
558 //we don't always want the default 100 row shown
561 <option value="100"'.(($checked_val==100) ? ' selected="selected"' : '').'>'. util_html_secure($text_100) .'</option>';
562 $have_a_subelement = true;
565 $checked_found = false;
567 for ($i = 0; $i < $rows; $i++) {
568 // uggh - sorry - don't show the 100 row
569 // if it was shown above, otherwise do show it
570 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
572 <option value="'.util_html_secure($vals[$i]).'"';
573 if ((string)$vals[$i] == (string)$checked_val) {
574 $checked_found = true;
575 $return .= ' selected="selected"';
577 if (is_array($allowed) && !in_array($vals[$i], $allowed)) {
578 $return .= ' disabled="disabled" class="option_disabled"';
580 $return .= '>'.util_html_secure($texts[$i]).'</option>';
581 $have_a_subelement = true;
585 // If the passed in "checked value" was never "SELECTED"
586 // we want to preserve that value UNLESS that value was 'xzxz', the default value
588 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
590 <option value="'.util_html_secure($checked_val).'" selected="selected">'._('No Change').'</option>';
591 $have_a_subelement = true;
594 if (!$have_a_subelement) {
595 /* <select></select> without <option/> in between is invalid */
596 return '<!-- select without options -->';
605 * html_build_select_box() - Takes a result set, with the first column being the "id" or value and
606 * the second column being the text you want displayed.
608 * @param int The result set
609 * @param string Text to be displayed
610 * @param string The item that should be checked
611 * @param bool Whether or not to show the '100 row'
612 * @param string What to call the '100 row'. Defaults to none.
614 function html_build_select_box($result, $name, $checked_val = "xzxz", $show_100 = true, $text_100 = 'none', $show_any = false, $text_any = 'Select One', $allowed = false) {
615 if ($text_100 == 'none') {
616 $text_100 = _('None');
618 if ($text_any == 'Select One') {
619 $text_any = _('Select One');
621 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);
625 * html_build_select_box_sorted() - Takes a result set, with the first column being the "id" or value and
626 * the second column being the text you want displayed.
628 * @param int The result set
629 * @param string Text to be displayed
630 * @param string The item that should be checked
631 * @param bool Whether or not to show the '100 row'
632 * @param string What to call the '100 row'. Defaults to none.
634 function html_build_select_box_sorted($result, $name, $checked_val = "xzxz", $show_100 = true, $text_100 = 'none') {
635 if ($text_100 == 'none') {
636 $text_100 = _('None');
638 $vals = util_result_column_to_array($result, 0);
639 $texts = util_result_column_to_array($result, 1);
640 array_multisort($texts, SORT_ASC, SORT_STRING,
642 return html_build_select_box_from_arrays ($vals, $texts, $name, $checked_val, $show_100, $text_100);
646 * html_build_multiple_select_box() - Takes a result set, with the first column being the "id" or value
647 * and the second column being the text you want displayed.
649 * @param int The result set
650 * @param string Text to be displayed
651 * @param string The item that should be checked
652 * @param int The size of this box
653 * @param bool Whether or not to show the '100 row'
656 function html_build_multiple_select_box($result, $name, $checked_array, $size = '8', $show_100 = true) {
657 $checked_count = count($checked_array);
659 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
662 Put in the default NONE box
665 <option value="100"';
666 for ($j = 0; $j < $checked_count; $j++) {
667 if ($checked_array[$j] == '100') {
668 $return .= ' selected="selected"';
671 $return .= '>'._('None').'</option>';
674 $rows = db_numrows($result);
675 for ($i = 0; $i < $rows; $i++) {
676 if ((db_result($result, $i, 0) != '100') || (db_result($result, $i, 0) == '100' && !$show_100)) {
678 <option value="'.db_result($result, $i, 0).'"';
680 Determine if it's checked
682 $val = db_result($result, $i, 0);
683 for ($j = 0; $j < $checked_count; $j++) {
684 if ($val == $checked_array[$j]) {
685 $return .= ' selected="selected"';
688 $return .= '>'.substr(db_result($result, $i, 1), 0, 35).'</option>';
697 * html_build_multiple_select_box_from_arrays() - Takes two arrays and builds a multi-select box
699 * @param array id of the field
700 * @param array Text to be displayed
701 * @param string id of the items selected
702 * @param string The item that should be checked
703 * @param int The size of this box
704 * @param bool Whether or not to show the '100 row'
707 function html_build_multiple_select_box_from_arrays($ids, $texts, $name, $checked_array, $size = '8', $show_100 = true, $text_100 = 'none') {
708 $checked_count = count($checked_array);
710 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
712 if ($text_100 == 'none') {
713 $text_100 = _('None');
716 Put in the default NONE box
719 <option value="100"';
720 for ($j = 0; $j < $checked_count; $j++) {
721 if ($checked_array[$j] == '100') {
722 $return .= ' selected="selected"';
725 $return .= '>'.$text_100.'</option>';
729 for ($i = 0; $i < $rows; $i++) {
730 if (($ids[$i] != '100') || ($ids[$i] == '100' && !$show_100)) {
732 <option value="'.$ids[$i].'"';
734 Determine if it's checked
737 for ($j = 0; $j < $checked_count; $j++) {
738 if ($val == $checked_array[$j]) {
739 $return .= ' selected="selected"';
742 $return .= '>'.$texts[$i].' </option>';
751 * html_build_checkbox() - Render checkbox control
753 * @param name - name of control
754 * @param value - value of control
755 * @param checked - true if control should be checked
756 * @return html code for checkbox control
758 function html_build_checkbox($name, $value, $checked) {
759 return '<input type="checkbox" name="'.$name.'"'
760 .' value="'.$value.'"'
761 .($checked ? 'checked="checked"' : '').'>';
765 * build_priority_select_box() - Wrapper for html_build_priority_select_box()
767 * @see html_build_priority_select_box()
769 function build_priority_select_box($name = 'priority', $checked_val = '3', $nochange = false) {
770 echo html_build_priority_select_box($name, $checked_val, $nochange);
774 * html_build_priority_select_box() - Return a select box of standard priorities.
775 * The name of this select box is optional and so is the default checked value.
777 * @param string $name Name of the select box
778 * @param string $checked_val The value to be checked
779 * @param bool $nochange Whether to make 'No Change' selected.
781 function html_build_priority_select_box($name = 'priority', $checked_val = '3', $nochange = false) {
783 <select id="tracker-<?php echo $name ?>" name="<?php echo $name; ?>" title="<?php echo util_html_secure(html_get_tooltip_description($name)) ?>">
784 <?php if ($nochange) { ?>
785 <option value="100"<?php if ($nochange) {echo " selected=\"selected\"";} ?>><?php echo _('No Change') ?></option>
787 <option value="1"<?php if ($checked_val=="1") {echo " selected=\"selected\"";} ?>>1 - <?php echo _('Lowest') ?></option>
788 <option value="2"<?php if ($checked_val=="2") {echo " selected=\"selected\"";} ?>>2</option>
789 <option value="3"<?php if ($checked_val=="3") {echo " selected=\"selected\"";} ?>>3</option>
790 <option value="4"<?php if ($checked_val=="4") {echo " selected=\"selected\"";} ?>>4</option>
791 <option value="5"<?php if ($checked_val=="5") {echo " selected=\"selected\"";} ?>>5 - <?php echo _('Highest') ?></option>
798 * html_buildcheckboxarray() - Build an HTML checkbox array.
800 * @param array Options array
801 * @param name Checkbox name
802 * @param array Array of boxes to be pre-checked
804 function html_buildcheckboxarray($options, $name, $checked_array) {
805 $option_count = count($options);
806 $checked_count = count($checked_array);
808 for ($i = 1; $i <= $option_count; $i++) {
810 <br /><input type="checkbox" name="'.$name.'" value="'.$i.'"';
811 for ($j = 0; $j < $checked_count; $j++) {
812 if ($i == $checked_array[$j]) {
813 echo ' checked="checked"';
816 echo ' /> '.$options[$i];
821 * site_header() - everything required to handle security and
822 * add navigation for user pages like /my/ and /account/
824 * @param array Must contain $user_id
826 function site_header($params) {
829 Check to see if active user
830 Check to see if logged in
832 $HTML->header($params);
836 * site_footer() - Show the HTML site footer.
838 * @param array Footer params array
840 function site_footer($params) {
842 $HTML->footer($params);
846 * site_project_header() - everything required to handle
847 * security and state checks for a project web page
849 * @param params array() must contain $toptab and $group
851 function site_project_header($params) {
854 Check to see if active
855 Check to see if project rather than foundry
856 Check to see if private (if private check if user_ismember)
859 $group_id = $params['group'];
861 //get the project object
862 $project = group_get_object($group_id);
864 if (!$project || !is_object($project)) {
866 } elseif ($project->isError()) {
867 if ($project->isPermissionDeniedError()) {
868 if (!session_get_user()) {
869 $next = '/account/login.php?error_msg='.urlencode($project->getErrorMessage());
870 if (getStringFromServer('REQUEST_METHOD') != 'POST') {
871 $next .= '&return_to='.urlencode(getStringFromServer('REQUEST_URI'));
873 session_redirect($next);
876 exit_error(sprintf(_('Project access problem: %s'),$project->getErrorMessage()),'home');
878 exit_error(sprintf(_('Project Problem: %s'),$project->getErrorMessage()),'home');
881 // Check permissions in case of restricted access
882 session_require_perm('project_read', $group_id);
884 //for dead projects must be member of admin project
885 if (!$project->isActive()) {
886 session_require_global_perm('forge_admin');
889 if (isset($params['title'])) {
890 $h1 = $params['title'];
891 $params['title'] = $project->getPublicName().': '.$params['title'];
893 $h1 = $project->getPublicName();
894 $params['title'] = $project->getPublicName();
896 if (!isset($params['h1'])) {
900 if ($project->getDescription()) {
901 $params['meta-description'] = $project->getDescription();
904 if (forge_get_config('use_project_tags')) {
905 $res = db_query_params('SELECT name FROM project_tags WHERE group_id = $1', array($group_id));
906 if ($res && db_numrows($res) > 0) {
907 while ($row = db_fetch_array($res)) {
908 $array[] = $row['name'];
910 $params['meta-keywords'] = htmlspecialchars(join(', ', $array));
914 site_header($params);
918 * site_project_footer() - currently a simple shim
919 * that should be on every project page, rather than
920 * a direct call to site_footer() or theme_footer()
922 * @param params array() empty
924 function site_project_footer($params) {
925 site_footer($params);
929 * site_user_header() - everything required to handle security and
930 * add navigation for user pages like /my/ and /account/
932 * @param params array() must contain $user_id
934 function site_user_header($params) {
938 Check to see if active user
939 Check to see if logged in
941 site_header($params);
942 echo $HTML->beginSubMenu();
947 $arr_t[] = _('My Personal Page');
949 $arr_attr[] = array('title' => _('View your personal page, a selection of widgets to follow the informations from projects.'), 'class' => 'tabtitle-nw');
951 if (forge_get_config('use_tracker')) {
952 $arr_t[] = _('Trackers dashboard');
953 $arr_l[] = '/my/dashboard.php';
954 $arr_attr[] = array('title' => _('View your tasks and artifacts.'), 'class' => 'tabtitle');
958 if (forge_get_config('use_diary')) {
959 $arr_t[] = _('Diary & Notes');
960 $arr_l[] = '/my/diary.php';
961 $arr_attr[] = array('title' => _('Manage your diary. Add, modify or delete your notes.'), 'class' => 'tabtitle');
964 $arr_t[] = _('Account Maintenance');
965 $arr_l[] = '/account/';
966 $arr_attr[] = array('title' => _('Manage your account. Change your password, select your preferences.'), 'class' => 'tabtitle');
968 if (!forge_get_config('project_registration_restricted')
969 || forge_check_global_perm('approve_projects', '')) {
970 $arr_t[] = _('Register Project');
971 $arr_l[] = '/register/';
972 $arr_attr[] = array('title' => _('Register a new project in forge, following the workflow.'), 'class' => 'tabtitle');
975 echo ($HTML->printSubMenu($arr_t, $arr_l, $arr_attr));
976 if (plugin_hook_listeners("usermenu") > 0) {
977 echo $HTML->subMenuSeparator();
979 plugin_hook("usermenu", false);
980 echo $HTML->endSubMenu();
984 * site_user_footer() - currently a simple shim that should be on every user page,
985 * rather than a direct call to site_footer() or theme_footer()
987 * @param params array() empty
989 function site_user_footer($params) {
990 site_footer($params);
994 * html_clean_hash_string() - Remove noise characters from hex hash string
996 * Thruout SourceForge, URLs with hexadecimal hash string parameters
997 * are being sent via email to request confirmation of user actions.
998 * It was found that some mail clients distort this hash, so we take
999 * special steps to encode it in the way which help to preserve its
1000 * recognition. This routine
1002 * @param hashstr required hash parameter as received from browser
1003 * @return pure hex string
1005 function html_clean_hash_string($hashstr) {
1007 if (substr($hashstr, 0, 1) == "_") {
1008 $hashstr = substr($hashstr, 1);
1011 if (substr($hashstr, strlen($hashstr) - 1, 1) == ">") {
1012 $hashstr = substr($hashstr, 0, strlen($hashstr) - 1);
1018 function relative_date ($date) {
1019 $delta = time() - $date;
1021 return sprintf(ngettext('%d second ago', '%d seconds ago', $delta), $delta);
1023 $delta = round($delta/60);
1025 return sprintf(ngettext('%d minute ago', '%d minutes ago', $delta), $delta);
1027 $delta = round($delta/60);
1029 return sprintf(ngettext('%d hour ago', '%d hours ago', $delta), $delta);
1031 $delta = round($delta/24);
1033 return sprintf(ngettext('%d day ago', '%d days ago', $delta), $delta);
1035 $delta = round($delta/7);
1037 return sprintf(ngettext('%d week ago', '%d weeks ago', $delta), $delta);
1039 return date(_('Y-m-d H:i'), $date);
1042 /* TODO: think about beautifying output */
1045 * html_eo() - Return proper element XHTML start tag
1047 * @param string $name
1049 * @param array $attrs
1050 * (optional) associative array of element attributes
1051 * values: arrays are space-imploded;
1052 * false values and empty arrays ignored
1054 * XHTML string suitable for echo'ing
1056 function html_eo($name, $attrs = array()) {
1058 foreach ($attrs as $key => $value) {
1059 if (is_array($value)) {
1060 $value = count($value) ? implode(" ", $value) : false;
1062 if ($value === false) {
1065 $rv .= ' '.$key.'="'.htmlspecialchars($value).'"';
1072 * html_e() - Return proper element XHTML start/end sequence
1074 * @param string $name
1076 * @param array $attrs
1077 * (optional) associative array of element attributes
1078 * values: arrays are space-imploded;
1079 * false values and empty arrays ignored
1080 * @param string $content
1081 * (optional) XHTML to be placed inside
1082 * @param bool $shortform
1083 * (optional) allow short open-close form
1086 * XHTML string suitable for echo'ing
1088 function html_e($name, $attrs = array(), $content = "", $shortform = true) {
1090 foreach ($attrs as $key => $value) {
1091 if (is_array($value)) {
1092 $value = count($value) ? implode(" ", $value) : false;
1094 if ($value === false) {
1097 $rv .= ' '.$key.'="'.htmlspecialchars($value).'"';
1099 if ($content === "" && $shortform) {
1102 $rv .= '>'.$content.'</'.$name.'>';
1107 $html_autoclose_stack = array();
1108 $html_autoclose_pos = 0;
1111 * html_ap() - Return XHTML element autoclose stack position
1115 function html_ap() {
1116 global $html_autoclose_pos;
1118 return $html_autoclose_pos;
1122 * html_ao() - Return proper element XHTML start tag, with autoclose
1124 * @param string $name
1126 * @param array $attrs
1127 * (optional) associative array of element attributes
1128 * values: arrays are space-imploded;
1129 * false values and empty arrays ignored
1131 * XHTML string suitable for echo'ing
1133 function html_ao($name, $attrs = array()) {
1134 global $html_autoclose_pos, $html_autoclose_stack;
1136 $html_autoclose_stack[$html_autoclose_pos++] = array(
1140 return html_eo($name, $attrs);
1144 * html_aonce() - Return once proper element XHTML start tag, with autoclose
1147 initialise this to false; will be modified
1148 * @param string $name
1150 * @param array $attrs
1151 * (optional) associative array of element attributes
1152 * values: arrays are space-imploded;
1153 * false values and empty arrays ignored
1155 * XHTML string suitable for echo'ing
1157 function html_aonce(&$sptr, $name, $attrs = array()) {
1158 if ($sptr !== false) {
1163 return html_ao($name, $attrs);
1167 * html_ac() - Return proper element XHTML end tags, autoclosing
1169 * @param integer $spos
1170 * stack position to return to
1171 * (nothing is done if === false)
1173 * XHTML string suitable for echo'ing
1175 function html_ac($spos) {
1176 global $html_autoclose_pos, $html_autoclose_stack;
1178 if ($spos === false) {
1179 /* support for html_aonce() */
1183 if ($html_autoclose_pos < $spos) {
1184 $e = "html_autoclose stack underflow; closing down to ".
1185 $spos." but we're down to ".$html_autoclose_pos.
1187 throw new Exception($e);
1191 while ($html_autoclose_pos > $spos) {
1192 --$html_autoclose_pos;
1193 $rv .= '</'.$html_autoclose_stack[$html_autoclose_pos]['name'].'>';
1194 unset($html_autoclose_stack[$html_autoclose_pos]);
1200 * html_a_copy() - Return a copy of part of the autoclose stack
1202 * @param $spos integer
1203 * stack position caller will return to
1206 * argument suitable for html_a_apply()
1208 function html_a_copy($spos) {
1209 global $html_autoclose_pos, $html_autoclose_stack;
1211 if ($spos === false) {
1215 if ($spos > $html_autoclose_pos) {
1216 $e = "html_autoclose stack underflow; closing down to ".
1217 $spos." but we're down to ".$html_autoclose_pos.
1219 throw new Exception($e);
1223 while ($spos < $html_autoclose_pos) {
1224 $rv[] = $html_autoclose_stack[$spos++];
1230 * html_a_apply() - Reopen tags based on an autoclose stack copy
1232 * @param opaque $scopy
1233 * return value from html_a_copy()
1235 * XHTML string suitable for echo'ing
1237 function html_a_apply($scopy) {
1238 /* array_reduce() would be useful here... IF IT WORKED, FFS! */
1240 foreach ($scopy as $value) {
1241 $rv .= html_ao($value['name'], $value['attr']);
1248 // c-file-style: "bsd"