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) {
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 $feedback 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 $msg 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 $msg 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 $username The username of the user to link.
91 * @param string $displayname The name to display.
94 function make_user_link($username, $displayname = '') {
95 if (empty($displayname))
96 $displayname = $username;
98 if (!strcasecmp($username, 'Nobody') || !strcasecmp($username, 'None')) {
101 return '<a href="/users/'.$username.'">'.$displayname.'</a>';
106 * html_feedback_bottom() - Show the feedback output at the bottom of the page.
108 * @param string $feedback The feedback.
110 function html_feedback_bottom($feedback) {
112 echo $HTML->feedback($feedback);
116 * html_blankimage() - Show the blank spacer image.
118 * @param int $height The height of the image
119 * @param int $width The width of the image
122 function html_blankimage($height, $width) {
123 return '<img src="/images/blank.png" width="'.$width.'" height="'.$height.'" alt="" />';
127 * html_abs_image() - Show an image given an absolute URL.
129 * @param string $url URL
130 * @param int $width width of the image
131 * @param int $height height of the image
132 * @param array $args Any <img> tag parameters (i.e. 'border', 'alt', etc...)
135 function html_abs_image($url, $width, $height, $args) {
136 $return = ('<img src="'.$url.'"');
138 while (list($k, $v) = each($args)) {
139 $return .= ' '.$k.'="'.$v.'"';
142 if (!isset($args['alt'])) {
143 $return .= ' alt=""';
146 // Add image dimensions (if given)
147 $return .= $width ? " width=\"".$width."\"" : '';
148 $return .= $height ? " height=\"".$height."\"" : '';
155 * html_image() - Build an image tag of an image contained in $src
157 * @param string $src The source location of the image
158 * @param int $width The width of the image
159 * @param int $height The height of the image
160 * @param array $args Any IMG tag parameters associated with this image (i.e. 'border', 'alt', etc...)
161 * @param bool $display DEPRECATED
164 function html_image($src, $width = '', $height = '', $args = array(), $display = 1) {
167 if (method_exists($HTML, 'html_image')) {
168 $HTML->html_image($src, $width, $height, $args);
170 $s = ((session_issecure()) ? forge_get_config('images_secure_url') : forge_get_config('images_url') );
171 return html_abs_image($s.$HTML->imgroot.$src, $width, $height, $args);
175 * html_get_language_popup() - Pop up box of supported languages.
177 * @param string $title The title of the popup box.
178 * @param string $selected Which element of the box is to be selected.
179 * @return string The html select box.
181 function html_get_language_popup($title = 'language_id', $selected = 'xzxz') {
182 $res = db_query_params('SELECT * FROM supported_languages ORDER BY name ASC',
184 return html_build_select_box($res, $title, $selected, false);
188 * html_get_theme_popup() - Pop up box of supported themes.
190 * @param string $title The title of the popup box.
191 * @param string $selected Which element of the box is to be selected.
192 * @return string The html select box.
194 function html_get_theme_popup($title = 'theme_id', $selected = 'xzxz') {
195 $res = db_query_params('SELECT theme_id, fullname FROM themes WHERE enabled=true',
197 $nbTheme = db_numrows($res);
199 $thetheme = db_result($res, 0, 'fullname');
200 return util_html_secure($thetheme) . html_e('input', array(
203 'value' => db_result($res, 0, 'theme_id'),
205 } elseif ($nbTheme < 1) {
208 return html_build_select_box($res, $title, $selected, false);
213 * html_get_ccode_popup() - Pop up box of supported country_codes.
215 * @param string $title The title of the popup box.
216 * @param string $selected Which element of the box is to be selected.
217 * @return string The html select box.
219 function html_get_ccode_popup($title = 'ccode', $selected = 'xzxz') {
220 $res = db_query_params('SELECT ccode,country_name FROM country_code ORDER BY country_name',
222 return html_build_select_box($res, $title, $selected, false);
226 * html_get_timezone_popup() - Pop up box of supported Timezones.
227 * Assumes you have included Timezones array file.
229 * @param string $title The title of the popup box.
230 * @param string $selected Which element of the box is to be selected.
231 * @return string The html select box.
233 function html_get_timezone_popup($title = 'timezone', $selected = 'xzxz') {
235 if ($selected == 'xzxzxzx') {
236 $r = file('/etc/timezone');
237 $selected = str_replace("\n", '', $r[0]);
239 return html_build_select_box_from_arrays($TZs, $TZs, $title, $selected, false);
243 * html_build_select_box_from_assoc() - Takes one assoc array and returns a pop-up box.
245 * @param array $arr An array of items to use.
246 * @param string $select_name The name you want assigned to this form element.
247 * @param string $checked_val The value of the item that should be checked.
248 * @param bool $swap Whether we should swap the keys / names.
249 * @param bool $show_100 Whether or not to show the '100 row'.
250 * @param string $text_100 What to call the '100 row' defaults to none.
253 function html_build_select_box_from_assoc($arr, $select_name, $checked_val = 'xzxz', $swap = false, $show_100 = false, $text_100 = 'None') {
255 $keys = array_values($arr);
256 $vals = array_keys($arr);
258 $vals = array_values($arr);
259 $keys = array_keys($arr);
261 return html_build_select_box_from_arrays($keys, $vals, $select_name, $checked_val, $show_100, $text_100);
265 * html_build_select_box_from_array() - Takes one array, with the first array being the "id"
266 * or value and the array being the text you want displayed.
268 * @param array $vals An array of items to use.
269 * @param string $select_name The name you want assigned to this form element.
270 * @param string $checked_val The value of the item that should be checked.
271 * @param int $samevals
274 function html_build_select_box_from_array($vals, $select_name, $checked_val = 'xzxz', $samevals = 0) {
276 <select name="'.$select_name.'">';
278 $rows = count($vals);
280 for ($i = 0; $i < $rows; $i++) {
282 $return .= "\n\t\t<option value=\"".$vals[$i]."\"";
283 if ($vals[$i] == $checked_val) {
284 $return .= ' selected="selected"';
287 $return .= "\n\t\t<option value=\"".$i.'"';
288 if ($i == $checked_val) {
289 $return .= ' selected="selected"';
292 $return .= '>'.htmlspecialchars($vals[$i]).'</option>';
301 * html_build_radio_buttons_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
302 * array being the text you want displayed.
304 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
305 * There must be a related row in users, categories, et , and by default that
306 * row is 100, so almost every pop-up box has 100 as the default
307 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
309 * @param array $vals The ID or value
310 * @param array $texts Text to be displayed
311 * @param string $select_name Name to assign to this form element
312 * @param string $checked_val The item that should be checked
313 * @param bool $show_100 Whether or not to show the '100 row'
314 * @param string $text_100 What to call the '100 row' defaults to none
315 * @param bool $show_any Whether or not to show the 'Any row'
316 * @param string $text_any What to call the 'Any row' defaults to any
319 function html_build_radio_buttons_from_arrays($vals, $texts, $select_name, $checked_val = 'xzxz',
320 $show_100 = true, $text_100 = 'none', $show_any = false, $text_any = 'any') {
321 if ($text_100 == 'none') {
322 $text_100 = _('None');
326 $rows = count($vals);
327 if (count($texts) != $rows) {
328 $return .= 'Error: uneven row counts';
331 //we don't always want the default Any row shown
334 <input type="radio" name="'.$select_name.'" value=""'.(($checked_val == '')? ' checked="checked"' : '').' /> '.$text_any.'<br />';
336 //we don't always want the default 100 row shown
339 <input type="radio" name="'.$select_name.'" value="100"'.(($checked_val == 100)? ' checked="checked"' : '').' /> '.$text_100.'<br />';
342 $checked_found = false;
344 for ($i = 0; $i < $rows; $i++) {
345 // uggh - sorry - don't show the 100 row
346 // if it was shown above, otherwise do show it
347 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
349 <input type="radio" id="'.$select_name.'_'.$vals[$i].'" name="'.$select_name.'" value="'.$vals[$i].'"';
350 if ((string)$vals[$i] == (string)$checked_val) {
351 $checked_found = true;
352 $return .= ' checked="checked"';
354 $return .= ' /> '.htmlspecialchars($texts[$i]).'<br />';
358 // If the passed in "checked value" was never "SELECTED"
359 // we want to preserve that value UNLESS that value was 'xzxz', the default value
361 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
363 <input type="radio" value="'.$checked_val.'" checked="checked" /> '._('No Change').'<br />';
370 * html_get_tooltip_description() - Get the tooltip description of the element
372 * @param string element name
376 function html_get_tooltip_description($element_name) {
377 global $use_tooltips;
378 if (!$use_tooltips) {
381 switch ($element_name) {
383 return _('This drop-down box represents the person to which a tracker item is assigned.');
385 return _('This drop-down box represents the current status of a tracker item.')
387 ._('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 does not respond with an admin-defined amount of time (default is 14 days) then the item is given a status of “Deleted”.');
389 return _('Tracker category');
391 return _('Tracker group');
393 return _('The Sort By option allows you to determine how the browse results are sorted.')
395 ._('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.');
396 case 'new_artifact_type_id':
397 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.')
399 ._('This has the added benefit of enabling an admin to turn a support request into a bug.');
401 return _('The priority option allows a user to define a tracker item priority (ranging from 1-Lowest to 5-Highest).')
403 ._('This is especially helpful for bugs and support requests where a user might find a critical problem with a project.');
405 return _('Resolution');
407 return _('The summary text-box represents a short tracker item summary. Useful when browsing through several tracker items.');
408 case 'canned_response':
409 return _('The canned response drop-down represents a list of project admin-defined canned responses to common support or bug submission.')
411 ._('If you are a project admin you can click the “Manage Canned Responses” link to define your own canned responses');
413 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.');
415 return _('Enter the complete description.')
417 .'<div align="left">'
418 ._("<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.")
421 return _('When you wish to attach a file to a tracker item you must check this checkbox before submitting changes.');
423 return _('You can monitor or un-monitor this item by clicking the “Monitor” button.')
425 ._('<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!');
431 function html_use_jquery() {
432 use_javascript('/scripts/jquery/jquery-1.8.3.js');
435 function html_use_tooltips() {
437 use_javascript('/scripts/jquery-tipsy/src/javascripts/jquery.tipsy.js');
438 use_javascript('/js/jquery-common.js');
439 use_stylesheet('/scripts/jquery-tipsy/src/stylesheets/tipsy.css');
442 function html_use_storage() {
444 use_javascript('/scripts/jquery-storage/jquery.Storage.js');
447 function html_use_simplemenu() {
449 use_javascript('/scripts/jquery-simpletreemenu/js/jquery-simpleTreeMenu-1.5.0.js');
450 use_stylesheet('/scripts/jquery-simpletreemenu/css/jquery-simpleTreeMenu-1.5.0.css');
453 function html_use_coolfieldset() {
455 use_javascript('/scripts/coolfieldset/js/jquery.coolfieldset.js');
456 use_javascript('/js/jquery-common.js');
457 use_stylesheet('/scripts/coolfieldset/css/jquery.coolfieldset.css');
460 function html_use_jqueryui() {
462 use_javascript('/scripts/jquery-ui/js/jquery-ui-1.9.2.custom.js');
463 use_stylesheet('/scripts/jquery-ui/css/overcast/jquery-ui-1.9.2.custom.css');
466 function html_use_jqueryjqplot() {
468 use_javascript('/scripts/jquery-jqplot/jquery.jqplot.js');
469 use_stylesheet('/scripts/jquery-jqplot/jquery.jqplot.css');
472 function html_use_jqueryjqplotpluginCanvas() {
473 html_use_jqueryjqplot();
474 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasTextRenderer.js');
475 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasAxisLabelRenderer.js');
476 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.canvasAxisTickRenderer.js');
477 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.categoryAxisRenderer.js');
480 function html_use_jqueryjqplotpluginBar() {
481 html_use_jqueryjqplot();
482 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.barRenderer.js');
483 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.pointLabels.js');
484 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.categoryAxisRenderer.js');
487 function html_use_jqueryjqplotpluginPie() {
488 html_use_jqueryjqplot();
489 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.pieRenderer.js');
492 function html_use_jqueryjqplotpluginhighlighter() {
493 html_use_jqueryjqplot();
494 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.highlighter.js');
497 function html_use_jqueryjqplotplugindateAxisRenderer() {
498 html_use_jqueryjqplot();
499 use_javascript('/scripts/jquery-jqplot/plugins/jqplot.dateAxisRenderer.js');
502 function html_use_jqueryteamworkgantt() {
504 use_javascript('/scripts/jquery-teamwork-gantt/libs/jquery.livequery.min.js');
505 use_javascript('/scripts/jquery-teamwork-gantt/libs/jquery.timers.js');
506 use_javascript('/scripts/jquery-teamwork-gantt/libs/platform.js');
507 use_javascript('/scripts/jquery-teamwork-gantt/libs/date.js');
508 use_javascript('/scripts/jquery-teamwork-gantt/libs/date.js');
509 use_javascript('/scripts/jquery-teamwork-gantt/libs/i18nJs.js');
510 use_javascript('/scripts/jquery-teamwork-gantt/libs/dateField/jquery.dateField.js');
511 use_javascript('/scripts/jquery-teamwork-gantt/libs/JST/jquery.JST.js');
512 use_javascript('/scripts/jquery-teamwork-gantt/ganttUtilities.js');
513 use_javascript('/scripts/jquery-teamwork-gantt/ganttTask.js');
514 use_javascript('/scripts/jquery-teamwork-gantt/ganttDrawer.js');
515 use_javascript('/scripts/jquery-teamwork-gantt/ganttGridEditor.js');
516 use_javascript('/scripts/jquery-teamwork-gantt/ganttMaster.js');
517 use_stylesheet('/scripts/jquery-teamwork-gantt/platform.css');
518 use_stylesheet('/scripts/jquery-teamwork-gantt/libs/dateField/jquery.dateField.css');
519 use_stylesheet('/scripts/jquery-teamwork-gantt/gantt.css');
522 function html_use_jquerysplitter() {
524 use_javascript('/scripts/jquery-splitter/js/jquery.splitter-0.8.0.js');
525 use_stylesheet('/scripts/jquery-splitter/css/jquery.splitter.css');
529 * html_build_select_box_from_arrays() - Takes two arrays, with the first array being the "id" or value and the other
530 * array being the text you want displayed.
532 * The infamous '100 row' has to do with the SQL Table joins done throughout all this code.
533 * There must be a related row in users, categories, et , and by default that
534 * row is 100, so almost every pop-up box has 100 as the default
535 * Most tables in the database should therefore have a row with an id of 100 in it so that joins are successful
537 * @param array $vals The ID or value
538 * @param array $texts Text to be displayed
539 * @param string $select_name Name to assign to this form element
540 * @param string $checked_val The item that should be checked
541 * @param bool $show_100 Whether or not to show the '100 row'
542 * @param string $text_100 What to call the '100 row' defaults to none
543 * @param bool $show_any Whether or not to show the 'Any row'
544 * @param string $text_any What to call the 'Any row' defaults to any
545 * @param array $allowed Array of all allowed values from the full list.
548 function html_build_select_box_from_arrays($vals, $texts, $select_name, $checked_val = 'xzxz',
549 $show_100 = true, $text_100 = 'none',
550 $show_any = false, $text_any = 'any', $allowed = false) {
551 $have_a_subelement = false;
553 if ($text_100 == 'none') {
554 $text_100 = _('None');
558 $rows = count($vals);
559 if (count($texts) != $rows) {
560 $return .= _('Error: uneven row counts');
563 //TODO: remove this ugly ack to get something more generic...
564 $title = html_get_tooltip_description($select_name);
567 $id = ' id="tracker-'.$select_name.'"';
568 if (preg_match('/\[\]/', $id)) {
574 <select'.$id.' name="'.$select_name.'" title="'.util_html_secure($title).'">';
576 //we don't always want the default Any row shown
579 <option value=""'.(($checked_val == '') ? ' selected="selected"' : '').'>'. util_html_secure($text_any) .'</option>';
580 $have_a_subelement = true;
582 //we don't always want the default 100 row shown
585 <option value="100"'.(($checked_val == 100) ? ' selected="selected"' : '').'>'. util_html_secure($text_100) .'</option>';
586 $have_a_subelement = true;
589 $checked_found = false;
591 for ($i = 0; $i < $rows; $i++) {
592 // uggh - sorry - don't show the 100 row
593 // if it was shown above, otherwise do show it
594 if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) {
596 <option value="'.util_html_secure($vals[$i]).'"';
597 if ((string)$vals[$i] == (string)$checked_val) {
598 $checked_found = true;
599 $return .= ' selected="selected"';
601 if (is_array($allowed) && !in_array($vals[$i], $allowed)) {
602 $return .= ' disabled="disabled" class="option_disabled"';
604 $return .= '>'.util_html_secure($texts[$i]).'</option>';
605 $have_a_subelement = true;
609 // If the passed in "checked value" was never "SELECTED"
610 // we want to preserve that value UNLESS that value was 'xzxz', the default value
612 if (!$checked_found && $checked_val != 'xzxz' && $checked_val && $checked_val != 100) {
614 <option value="'.util_html_secure($checked_val).'" selected="selected">'._('No Change').'</option>';
615 $have_a_subelement = true;
618 if (!$have_a_subelement) {
619 /* <select></select> without <option/> in between is invalid */
620 return '<!-- select without options -->';
629 * html_build_select_box() - Takes a result set, with the first column being the "id" or value and
630 * the second column being the text you want displayed.
632 * @param resource $result The result set
633 * @param string $name Text to be displayed
634 * @param string $checked_val The item that should be checked
635 * @param bool $show_100 Whether or not to show the '100 row'
636 * @param string $text_100 What to call the '100 row'. Defaults to none.
638 function html_build_select_box($result, $name, $checked_val = "xzxz", $show_100 = true, $text_100 = 'none',
639 $show_any = false, $text_any = 'Select One', $allowed = false) {
640 if ($text_100 == 'none') {
641 $text_100 = _('None');
643 if ($text_any == 'Select One') {
644 $text_any = _('Select One');
646 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);
650 * html_build_select_box_sorted() - Takes a result set, with the first column being the "id" or value and
651 * the second column being the text you want displayed.
653 * @param int $result The result set
654 * @param string $name Text to be displayed
655 * @param string $checked_val The item that should be checked
656 * @param bool $show_100 Whether or not to show the '100 row'
657 * @param string $text_100 What to call the '100 row'. Defaults to none.
660 function html_build_select_box_sorted($result, $name, $checked_val = "xzxz", $show_100 = true, $text_100 = 'none') {
661 if ($text_100 == 'none') {
662 $text_100 = _('None');
664 $vals = util_result_column_to_array($result, 0);
665 $texts = util_result_column_to_array($result, 1);
666 array_multisort($texts, SORT_ASC, SORT_STRING, $vals);
667 return html_build_select_box_from_arrays ($vals, $texts, $name, $checked_val, $show_100, $text_100);
671 * html_build_multiple_select_box() - Takes a result set, with the first column being the "id" or value
672 * and the second column being the text you want displayed.
674 * @param int The result set
675 * @param string Text to be displayed
676 * @param string The item that should be checked
677 * @param int The size of this box
678 * @param bool Whether or not to show the '100 row'
681 function html_build_multiple_select_box($result, $name, $checked_array, $size = '8', $show_100 = true) {
682 $checked_count = count($checked_array);
684 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
687 Put in the default NONE box
690 <option value="100"';
691 for ($j = 0; $j < $checked_count; $j++) {
692 if ($checked_array[$j] == '100') {
693 $return .= ' selected="selected"';
696 $return .= '>'._('None').'</option>';
699 $rows = db_numrows($result);
700 for ($i = 0; $i < $rows; $i++) {
701 if ((db_result($result, $i, 0) != '100') || (db_result($result, $i, 0) == '100' && !$show_100)) {
703 <option value="'.db_result($result, $i, 0).'"';
705 Determine if it's checked
707 $val = db_result($result, $i, 0);
708 for ($j = 0; $j < $checked_count; $j++) {
709 if ($val == $checked_array[$j]) {
710 $return .= ' selected="selected"';
713 $return .= '>'.substr(db_result($result, $i, 1), 0, 35).'</option>';
722 * html_build_multiple_select_box_from_arrays() - Takes two arrays and builds a multi-select box
724 * @param array id of the field
725 * @param array Text to be displayed
726 * @param string id of the items selected
727 * @param string The item that should be checked
728 * @param int The size of this box
729 * @param bool Whether or not to show the '100 row'
732 function html_build_multiple_select_box_from_arrays($ids, $texts, $name, $checked_array, $size = '8', $show_100 = true, $text_100 = 'none') {
733 $checked_count = count($checked_array);
735 <select name="'.$name.'" multiple="multiple" size="'.$size.'">';
737 if ($text_100 == 'none') {
738 $text_100 = _('None');
741 Put in the default NONE box
744 <option value="100"';
745 for ($j = 0; $j < $checked_count; $j++) {
746 if ($checked_array[$j] == '100') {
747 $return .= ' selected="selected"';
750 $return .= '>'.$text_100.'</option>';
754 for ($i = 0; $i < $rows; $i++) {
755 if (($ids[$i] != '100') || ($ids[$i] == '100' && !$show_100)) {
757 <option value="'.$ids[$i].'"';
759 Determine if it's checked
762 for ($j = 0; $j < $checked_count; $j++) {
763 if ($val == $checked_array[$j]) {
764 $return .= ' selected="selected"';
767 $return .= '>'.$texts[$i].' </option>';
776 * html_build_checkbox() - Render checkbox control
778 * @param name - name of control
779 * @param value - value of control
780 * @param checked - true if control should be checked
781 * @return html code for checkbox control
783 function html_build_checkbox($name, $value, $checked) {
784 return '<input type="checkbox" id="'.$name.'" name="'.$name.'"'
785 .' value="'.$value.'"'
786 .($checked ? 'checked="checked"' : '').'>';
790 * build_priority_select_box() - Wrapper for html_build_priority_select_box()
792 * @see html_build_priority_select_box()
794 function build_priority_select_box($name = 'priority', $checked_val = '3', $nochange = false) {
795 html_build_priority_select_box($name, $checked_val, $nochange);
799 * html_build_priority_select_box() - Return a select box of standard priorities.
800 * The name of this select box is optional and so is the default checked value.
802 * @param string $name Name of the select box
803 * @param string $checked_val The value to be checked
804 * @param bool $nochange Whether to make 'No Change' selected.
806 function html_build_priority_select_box($name = 'priority', $checked_val = '3', $nochange = false) {
808 <select id="tracker-<?php echo $name ?>" name="<?php echo $name; ?>"
809 title="<?php echo util_html_secure(html_get_tooltip_description($name)) ?>">
810 <?php if ($nochange) { ?>
811 <option value="100"<?php if ($nochange) {echo " selected=\"selected\"";} ?>><?php echo _('No Change') ?></option>
813 <option value="1"<?php if ($checked_val == "1") {echo " selected=\"selected\"";} ?>>1 - <?php echo _('Lowest') ?></option>
814 <option value="2"<?php if ($checked_val == "2") {echo " selected=\"selected\"";} ?>>2</option>
815 <option value="3"<?php if ($checked_val == "3") {echo " selected=\"selected\"";} ?>>3</option>
816 <option value="4"<?php if ($checked_val == "4") {echo " selected=\"selected\"";} ?>>4</option>
817 <option value="5"<?php if ($checked_val == "5") {echo " selected=\"selected\"";} ?>>5 - <?php echo _('Highest') ?></option>
824 * html_buildcheckboxarray() - Build an HTML checkbox array.
826 * @param array Options array
827 * @param name Checkbox name
828 * @param array Array of boxes to be pre-checked
830 function html_buildcheckboxarray($options, $name, $checked_array) {
831 $option_count = count($options);
832 $checked_count = count($checked_array);
834 for ($i = 1; $i <= $option_count; $i++) {
836 <br /><input type="checkbox" name="'.$name.'" value="'.$i.'"';
837 for ($j = 0; $j < $checked_count; $j++) {
838 if ($i == $checked_array[$j]) {
839 echo ' checked="checked"';
842 echo ' /> '.$options[$i];
847 * site_header() - everything required to handle security and
848 * add navigation for user pages like /my/ and /account/
850 * @param array Must contain $user_id
852 function site_header($params) {
855 Check to see if active user
856 Check to see if logged in
858 $HTML->header($params);
862 * site_footer() - Show the HTML site footer.
864 * @param array Footer params array
866 function site_footer($params) {
868 $HTML->footer($params);
872 * site_project_header() - everything required to handle
873 * security and state checks for a project web page
875 * @param params array() must contain $toptab and $group
877 function site_project_header($params) {
880 Check to see if active
881 Check to see if project rather than foundry
882 Check to see if private (if private check if user_ismember)
885 $group_id = $params['group'];
887 //get the project object
888 $project = group_get_object($group_id);
890 if (!$project || !is_object($project)) {
892 } elseif ($project->isError()) {
893 if ($project->isPermissionDeniedError()) {
894 if (!session_get_user()) {
895 $next = '/account/login.php?error_msg='.urlencode($project->getErrorMessage());
896 if (getStringFromServer('REQUEST_METHOD') != 'POST') {
897 $next .= '&return_to='.urlencode(getStringFromServer('REQUEST_URI'));
899 session_redirect($next);
901 exit_error(sprintf(_('Project access problem: %s'), $project->getErrorMessage()), 'home');
903 exit_error(sprintf(_('Project Problem: %s'), $project->getErrorMessage()), 'home');
906 // Check permissions in case of restricted access
907 session_require_perm('project_read', $group_id);
909 //for dead projects must be member of admin project
910 if (!$project->isActive()) {
911 session_require_global_perm('forge_admin');
914 if (isset($params['title'])) {
915 $h1 = $params['title'];
916 $params['title'] = $project->getPublicName().': '.$params['title'];
918 $h1 = $project->getPublicName();
919 $params['title'] = $project->getPublicName();
921 if (!isset($params['h1'])) {
925 if ($project->getDescription()) {
926 $params['meta-description'] = $project->getDescription();
929 if (forge_get_config('use_project_tags')) {
930 $res = db_query_params('SELECT name FROM project_tags WHERE group_id = $1', array($group_id));
931 if ($res && db_numrows($res) > 0) {
932 while ($row = db_fetch_array($res)) {
933 $array[] = $row['name'];
935 $params['meta-keywords'] = htmlspecialchars(join(', ', $array));
939 site_header($params);
943 * site_project_footer() - currently a simple shim
944 * that should be on every project page, rather than
945 * a direct call to site_footer() or theme_footer()
947 * @param params array() empty
949 function site_project_footer($params) {
950 site_footer($params);
954 * site_user_header() - everything required to handle security and
955 * add navigation for user pages like /my/ and /account/
957 * @param params array() must contain $user_id
959 function site_user_header($params) {
963 Check to see if active user
964 Check to see if logged in
966 site_header($params);
967 echo $HTML->beginSubMenu();
972 $arr_t[] = _('My Personal Page');
974 $arr_attr[] = array('title' => _('View your personal page, a selection of widgets to follow the informations from projects.'), 'class' => 'tabtitle-nw');
976 if (forge_get_config('use_tracker')) {
977 $arr_t[] = _('My Trackers Dashboard');
978 $arr_l[] = '/my/dashboard.php';
979 $arr_attr[] = array('title' => _('View your tasks and artifacts.'), 'class' => 'tabtitle');
982 if (forge_get_config('use_diary')) {
983 $arr_t[] = _('My Diary and Notes');
984 $arr_l[] = '/my/diary.php';
985 $arr_attr[] = array('title' => _('Manage your diary. Add, modify or delete your notes.'), 'class' => 'tabtitle');
988 $arr_t[] = _('My Account');
989 $arr_l[] = '/account/';
990 $arr_attr[] = array('title' => _('Manage your account. Change your password, select your preferences.'), 'class' => 'tabtitle');
992 if (!forge_get_config('project_registration_restricted')
993 || forge_check_global_perm('approve_projects', '')) {
994 $arr_t[] = _('Register Project');
995 $arr_l[] = '/register/';
996 $arr_attr[] = array('title' => _('Register a new project in forge, following the workflow.'), 'class' => 'tabtitle');
999 echo ($HTML->printSubMenu($arr_t, $arr_l, $arr_attr));
1000 if (plugin_hook_listeners("usermenu") > 0) {
1001 echo $HTML->subMenuSeparator();
1003 plugin_hook("usermenu", false);
1004 echo $HTML->endSubMenu();
1008 * site_user_footer() - currently a simple shim that should be on every user page,
1009 * rather than a direct call to site_footer() or theme_footer()
1011 * @param params array() empty
1013 function site_user_footer($params) {
1014 site_footer($params);
1018 * html_clean_hash_string() - Remove noise characters from hex hash string
1020 * Thruout SourceForge, URLs with hexadecimal hash string parameters
1021 * are being sent via email to request confirmation of user actions.
1022 * It was found that some mail clients distort this hash, so we take
1023 * special steps to encode it in the way which help to preserve its
1024 * recognition. This routine
1026 * @param hashstr required hash parameter as received from browser
1027 * @return pure hex string
1029 function html_clean_hash_string($hashstr) {
1031 if (substr($hashstr, 0, 1) == "_") {
1032 $hashstr = substr($hashstr, 1);
1035 if (substr($hashstr, strlen($hashstr) - 1, 1) == ">") {
1036 $hashstr = substr($hashstr, 0, strlen($hashstr) - 1);
1042 function relative_date($date) {
1043 $delta = max(time() - $date, 0);
1045 return sprintf(ngettext('%d second ago', '%d seconds ago', $delta), $delta);
1047 $delta = round($delta / 60);
1049 return sprintf(ngettext('%d minute ago', '%d minutes ago', $delta), $delta);
1051 $delta = round($delta / 60);
1053 return sprintf(ngettext('%d hour ago', '%d hours ago', $delta), $delta);
1055 $delta = round($delta / 24);
1057 return sprintf(ngettext('%d day ago', '%d days ago', $delta), $delta);
1059 $delta = round($delta / 7);
1061 return sprintf(ngettext('%d week ago', '%d weeks ago', $delta), $delta);
1063 return date(_('Y-m-d H:i'), $date);
1066 /* TODO: think about beautifying output */
1069 * html_eo() - Return proper element XHTML start tag
1071 * @param string $name
1073 * @param array $attrs
1074 * (optional) associative array of element attributes
1075 * values: arrays are space-imploded;
1076 * false values and empty arrays ignored
1078 * XHTML string suitable for echo'ing
1080 function html_eo($name, $attrs = array()) {
1082 foreach ($attrs as $key => $value) {
1083 if (is_array($value)) {
1084 $value = count($value) ? implode(" ", $value) : false;
1086 if ($value === false) {
1089 $rv .= ' '.$key.'="'.htmlspecialchars($value).'"';
1096 * html_e() - Return proper element XHTML start/end sequence
1098 * @param string $name
1100 * @param array $attrs
1101 * (optional) associative array of element attributes
1102 * values: arrays are space-imploded;
1103 * false values and empty arrays ignored
1104 * @param string $content
1105 * (optional) XHTML to be placed inside
1106 * @param bool $shortform
1107 * (optional) allow short open-close form
1110 * XHTML string suitable for echo'ing
1112 function html_e($name, $attrs = array(), $content = "", $shortform = true) {
1114 foreach ($attrs as $key => $value) {
1115 if (is_array($value)) {
1116 $value = count($value) ? implode(" ", $value) : false;
1118 if ($value === false) {
1121 $rv .= ' '.$key.'="'.htmlspecialchars($value).'"';
1123 if ($content === "" && $shortform) {
1126 $rv .= '>'.$content.'</'.$name.'>';
1131 $html_autoclose_stack = array();
1132 $html_autoclose_pos = 0;
1135 * html_ap() - Return XHTML element autoclose stack position
1139 function html_ap() {
1140 global $html_autoclose_pos;
1142 return $html_autoclose_pos;
1146 * html_ao() - Return proper element XHTML start tag, with autoclose
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_ao($name, $attrs = array()) {
1158 global $html_autoclose_pos, $html_autoclose_stack;
1160 $html_autoclose_stack[$html_autoclose_pos++] = array(
1164 return html_eo($name, $attrs);
1168 * html_aonce() - Return once proper element XHTML start tag, with autoclose
1171 initialise this to false; will be modified
1172 * @param string $name
1174 * @param array $attrs
1175 * (optional) associative array of element attributes
1176 * values: arrays are space-imploded;
1177 * false values and empty arrays ignored
1179 * XHTML string suitable for echo'ing
1181 function html_aonce(&$sptr, $name, $attrs = array()) {
1182 if ($sptr !== false) {
1187 return html_ao($name, $attrs);
1191 * html_ac() - Return proper element XHTML end tags, autoclosing
1193 * @param $spos integer
1194 * stack position to return to (nothing is done if === false)
1196 * @return string XHTML string suitable for echo'ing
1198 function html_ac($spos) {
1199 global $html_autoclose_pos, $html_autoclose_stack;
1201 if ($spos === false) {
1202 /* support for html_aonce() */
1206 if ($html_autoclose_pos < $spos) {
1207 $e = "html_autoclose stack underflow; closing down to ".
1208 $spos." but we're down to ".$html_autoclose_pos.
1210 throw new Exception($e);
1214 while ($html_autoclose_pos > $spos) {
1215 --$html_autoclose_pos;
1216 $rv .= '</'.$html_autoclose_stack[$html_autoclose_pos]['name'].'>';
1217 unset($html_autoclose_stack[$html_autoclose_pos]);
1223 * html_a_copy() - Return a copy of part of the autoclose stack
1225 * @param $spos integer
1226 * stack position caller will return to
1229 * argument suitable for html_a_apply()
1231 function html_a_copy($spos) {
1232 global $html_autoclose_pos, $html_autoclose_stack;
1234 if ($spos === false) {
1238 if ($spos > $html_autoclose_pos) {
1239 $e = "html_autoclose stack underflow; closing down to ".
1240 $spos." but we're down to ".$html_autoclose_pos.
1242 throw new Exception($e);
1246 while ($spos < $html_autoclose_pos) {
1247 $rv[] = $html_autoclose_stack[$spos++];
1253 * html_a_apply() - Reopen tags based on an autoclose stack copy
1255 * @param opaque $scopy
1256 * return value from html_a_copy()
1258 * XHTML string suitable for echo'ing
1260 function html_a_apply($scopy) {
1261 /* array_reduce() would be useful here... IF IT WORKED, FFS! */
1263 foreach ($scopy as $value) {
1264 $rv .= html_ao($value['name'], $value['attr']);
1270 * html_trove_limit_navigation_box() - displays the navigation links for paging browsing
1272 * @param string URL of the very same script
1273 * @param int total number of results
1274 * @param int the maximum number displayed on a single page
1275 * @param int current page number (starting at 1)
1277 function html_trove_limit_navigation_box($php_self, $querytotalcount, $trove_browselimit, $page) {
1279 $html_limit = sprintf(_(' Displaying %1$s per page. Projects sorted by alphabetical order.'), $trove_browselimit).'<br/>';
1281 // display all the numbers
1282 for ($i=1;$i<=ceil($querytotalcount/$trove_browselimit);$i++) {
1285 $html_limit .= '<a href="'.$php_self;
1286 $html_limit .= '?page='.$i;
1287 $html_limit .= '">';
1288 } else $html_limit .= '<strong>';
1289 $html_limit .= '<'.$i.'>';
1291 $html_limit .= '</a>';
1292 } else $html_limit .= '</strong>';
1300 // c-file-style: "bsd"