3 * FusionForge Survey HTML Facility
5 * Portions Copyright 1999-2001 (c) VA Linux Systems
6 * The rest Copyright 2002-2004 (c) GForge Team - Sung Kim
7 * Copyright 2008-2010 (c) FusionForge Team
8 * Copyright (C) 2011 Alain Peyrat - Alcatel-Lucent
9 * http://fusionforge.org/
11 * This file is part of FusionForge.
13 * FusionForge is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * FusionForge is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with FusionForge; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 require_once $gfcommon.'include/pre.php';
29 require_once $gfwww.'include/note.php';
32 * Survey HTML related functions
34 class SurveyHTML extends Error {
39 function SurveyHTML() {
46 function header($params) {
47 global $group_id,$is_admin_page,$HTML;
49 if (!forge_get_config('use_survey')) {
53 $params['toptab']='surveys';
54 $params['group']=$group_id;
56 if ($project = group_get_object($group_id)){
57 if (!$project->usesSurvey()) {
61 if ($is_admin_page && $group_id) {
62 $params['submenu'] = $HTML->subMenu(
70 '/survey/admin/survey.php?group_id='.$group_id,
71 '/survey/admin/question.php?group_id='.$group_id,
72 '/survey/admin/show_results.php?group_id='.$group_id,
73 '/survey/admin/?group_id='.$group_id
77 $labels[] = _('Views Surveys');
78 $links[] = '/survey/?group_id='.$group_id;
79 if (forge_check_perm ('project_admin', $group_id)) {
80 $labels[] = _('Administration');
81 $links[] = '/survey/admin/?group_id='.$group_id;
83 $params['submenu'] = $HTML->subMenu($labels,$links);
85 site_project_header($params);
86 }// end if (valid group id)
92 function footer($params) {
93 site_project_footer($params);
97 * Show Add/Modify Question Forums
98 * @param Survey Question Question Object
101 function showAddQuestionForm( &$q ) {
105 $question_button = _('Add this Question');
107 /* If we have a question object, it is a Modify */
108 if ($q && is_object($q) && !$q->isError() && $q->getID()) {
109 $warning_msg = '<p class="warning_msg">'.
110 _('WARNING! It is a bad idea to change a question after responses to it have been submitted').
112 $question_id = $q->getID();
113 $question = $q->getQuestion();
114 $question_type = $q->getQuestionType();
115 $question_button = _('Submit Changes');
124 $ret.='<form action="'.getStringFromServer('PHP_SELF').'" method="post">';
125 $ret.='<p><input type="hidden" name="post" value="Y" />';
126 $ret.='<input type="hidden" name="group_id" value="'.$group_id.'" />';
127 $ret.='<input type="hidden" name="question_id" value="'.$question_id.'" />';
128 $ret.='<input type="hidden" name="form_key" value="' . form_generate_key() . '" />';
129 $ret.=_('Question').':<br />';
130 $ret.='<input type="text" name="question" value="'.$question.'" size="60" maxlength="150" /></p>';
131 $ret.='<p>'. _('Question Type').':<br />';
133 $result = db_query_params ('SELECT * FROM survey_question_types',
135 $ret.= html_build_select_box($result,'question_type',$question_type,false);
137 $ret.='</p><p><input type="submit" name="submit" value="'.$question_button.'" /></p>';
144 * Show Add/Modify Question Forums
145 * @param Survey Question Question Object
148 function showAddSurveyForm( &$s) {
152 /* If no question is available */
153 if (! $survey_id && ! count($s->getAddableQuestionInstances())) {
154 $ret = '<p>' . sprintf(_('Please %1$s create a question %2$s before creating a survey'),
155 '<a href="'.util_make_url('/survey/admin/question.php?group_id='.$group_id).'">',
162 $survey_button = _('Add this Survey');
163 $active = ' checked="checked" ';
166 /* If we have a survey object, it is a Modify */
167 if ($s && is_object($s) && !$s->isError() && $s->getID()) {
168 $warning_msg = '<p class="warning_msg">'.
169 _('WARNING! It is a bad idea to edit a survey after responses have been posted').'</p>';
170 $survey_id = $s->getID();
171 $survey_title = $s->getTitle();
172 $survey_questions = $s->getQuestionString();
173 $survey_button = _('Submit Changes');
174 if (!$s->isActive()) {
175 $inactive = 'checked ="checked" ';
180 $survey_questions = '';
185 $ret.='<form action="'.getStringFromServer('PHP_SELF').'" method="post">';
186 $ret.='<input type="hidden" name="post" value="Y" />';
187 $ret.='<input type="hidden" name="group_id" value="'.$group_id.'" />';
188 $ret.='<input type="hidden" name="survey_id" value="'.$survey_id.'" />';
189 $ret.='<input type="hidden" name="survey_questions" value="'.$survey_questions.'" />';
190 $ret.='<input type="hidden" name="form_key" value="' . form_generate_key() . '">';
191 $ret.='<strong>'. _('Name Of Survey:').'</strong>' .utils_requiredField();
192 $ret.= '<input type="text" name="survey_title" value="'.$survey_title.'" length="60" maxlength="150" /><p>';
194 $ret.='<p><strong>'. _('Is Active?').'</strong>';
195 $ret.='<br /><input type="radio" name="is_active" value="1"' .$active. '/>'._('Yes');
196 $ret.='<br /><input type="radio" name="is_active" value="0"' .$inactive. '/>'._('No');
198 $arr_to_add = & $s->getAddableQuestionInstances();
199 $arr_to_del = & $s->getQuestionInstances();
201 if (count($arr_to_add)>0) {
202 $ret.='<h2>'. _('Addable Questions').'</h2>';
203 $title_arr[] = " ";
204 $title_arr[] = _('Questions');
205 $title_arr[] = " ";
206 $ret.=$GLOBALS['HTML']->listTableTop ($title_arr);
209 for($i = 0; $i < count($arr_to_add); $i++) {
211 if ($arr_to_add[$i]->isError()) {
212 echo $arr_to_add[$i]->getErrorMessage();
217 $ret.= "<tr ". $GLOBALS['HTML']->boxGetAltRowStyle($i) .">\n";
220 $ret.= '<td><input type="checkbox" name="to_add[]" value="'.$arr_to_add[$i]->getID().'" />'.
221 $arr_to_add[$i]->getQuestion().' ('.
222 $arr_to_add[$i]->getQuestionStringType().')</td>';
229 if (count($arr_to_add)>0) {
230 /* Fill the remain cells */
232 $ret.='<td> </td><td> </td></tr>';
233 } else if ($i%3==2) {
234 $ret.='<td> </td></tr>';
237 $ret.= $GLOBALS['HTML']->listTableBottom();
240 /* Deletable questions */
241 if (count($arr_to_del) > 0) {
242 $ret.='<p><strong>'. _('Questions in this Survey').'</strong></p>';
243 $title_arr = array('Question ID', 'Question', 'Type', 'Order', 'Delete from this Survey');
244 $ret.=$GLOBALS['HTML']->listTableTop ($title_arr);
247 for($i = 0; $i < count($arr_to_del); $i++) {
248 if ($arr_to_del[$i]->isError()) {
249 echo $arr_to_del[$i]->getErrorMessage();
253 $ret.= "<tr ". $GLOBALS['HTML']->boxGetAltRowStyle($i) .">\n";
255 $ret.= '<td>'.$arr_to_del[$i]->getID().'</td>';
256 $ret.= '<td>'.$arr_to_del[$i]->getQuestion().'</td>';
257 $ret.= '<td>'.$arr_to_del[$i]->getQuestionStringType().'</td>';
258 $ret.= '<td><center>['.util_make_link ('/survey/admin/survey.php?group_id='.$group_id.'&survey_id='. $survey_id.'&is_up=1&updown=Y'.'&question_id='.$arr_to_del[$i]->getID(),_('Up')).'] ';
259 $ret.= '['.util_make_link ('/survey/admin/survey.php?group_id='.$group_id.'&survey_id='. $survey_id.'&is_up=0&updown=Y'.'&question_id='.$arr_to_del[$i]->getID(),_('Down')).']</center></td>';
261 $ret.= '<td><center><input type="checkbox" name="to_del[]" value="'.$arr_to_del[$i]->getID().'" /></center></td>';
266 if (count($arr_to_del)) {
267 $ret.= $GLOBALS['HTML']->listTableBottom();
270 /* Privous style question input text box. deprecated.
271 $ret.= _('List question numbers, in desired order, separated by commas. <strong>Refer to your list of questions</strong> so you can view the question id\'s. Do <strong>not</strong> include spaces or end your list with a comma. <br />Ex: 1,2,3,4,5,6,7');
272 $ret.='<br /><input type="text" name="survey_questions" value="" length="90" maxlength="1500" /></p>';
275 $ret.='<p><input type="submit" name="submit" value="'.$survey_button.'" /></p>';
282 * Show list of questions
284 function ShowQuestions(&$questions) {
287 $n = count($questions);
288 $ret = "<h2>" . sprintf(ngettext("%d question found", "%d questions found", $n), $n)."</h2>";
290 /* Head information */
291 $title_arr = array ('Question ID', 'Question', 'Type', 'Edit/Delete');
292 $ret.=$GLOBALS['HTML']->listTableTop ($title_arr);
294 for($i = 0; $i < count($questions); $i++) {
295 if ($questions[$i]->isError()) {
296 echo $questions[$i]->getErrorMessage();
300 $ret.= "<tr ". $GLOBALS['HTML']->boxGetAltRowStyle($i) .">\n";
301 $ret.= "<td><a href=\"question.php?group_id=$group_id&question_id=".
302 $questions[$i]->getID()."\">".$questions[$i]->getID()."</a></td>\n";
304 $ret.= '<td>'.$questions[$i]->getQuestion().'</td>';
305 $ret.= '<td>'.$questions[$i]->getQuestionStringType().'</td>';
307 /* Edit/Delete Link */
308 $ret.= "<td>[<a href=\"question.php?group_id=$group_id&question_id=".$questions[$i]->getID().'">';
309 $ret.= _('Edit').'</a>] ';
310 $ret.= "[<a href=\"question.php?delete=Y&group_id=$group_id&question_id=".$questions[$i]->getID().'">';
311 $ret.= _('Delete').'</a>]</td>';
315 $ret.= $GLOBALS['HTML']->listTableBottom();
320 * Show list of surveys
322 * Show surveys with many options
323 * have to set $user_id to get the right show_vote option
327 function ShowSurveys(&$surveys, $show_id=0, $show_questions=0,
328 $show_number_questions=0, $show_number_votes=0,
329 $show_vote=0, $show_edit=0, $show_result=0,
330 $show_result_graph=0, $show_result_comment=0,
335 $ret = '<h2>'. ngettext('Existing Survey', 'Existing Surveys', count($surveys)). '</h2>';
337 /* Head information */
339 $title_arr[] = _('Survey ID');
342 $title_arr[] = _('Survey Title');
344 if ($show_questions) {
345 $title_arr[] = _('Questions');
347 if ($show_number_questions) {
348 $title_arr[] = _('Number of Questions');
350 if ($show_number_votes) {
351 $title_arr[] = _('Number of Votes');
353 if ($show_vote && $user_id) {
354 $title_arr[] = _('Did I Vote?');
357 $title_arr[] = _('Edit');
360 $title_arr[] = _('Result');
362 if ($show_result_graph) {
363 $title_arr[] = _('Result with Graph');
365 if ($show_result_comment) {
366 $title_arr[] = _('Result with Graph and Comments');
369 $ret.=$GLOBALS['HTML']->listTableTop ($title_arr);
371 /* Color index for table */
373 for($i = 0; $i < count($surveys); $i++) {
374 if ($surveys[$i]->isError()) {
375 echo $surveys[$i]->getErrorMessage();
379 if (!$surveys[$i]->isActive()) {
380 if ($show_inactive) {
381 $strike_open="<strike>";
382 $strike_close="</strike>";
392 $ret.= "<tr ". $GLOBALS['HTML']->boxGetAltRowStyle($color_index++) .">\n";
394 $ret.= '<td>'.$surveys[$i]->getID().'</td>';
397 $ret.= '<td>'.$strike_open.util_make_link ('/survey/survey.php?group_id='.$group_id.'&survey_id='. $surveys[$i]->getID(), $surveys[$i]->getTitle()). $strike_close.'</td>';
399 if ($show_questions) {
400 // add a space after comma
401 $ret.= '<td>'.str_replace(",", ", ", $surveys[$i]->getQuestionString()).'</td>';
403 if ($show_number_questions) {
404 $ret.= '<td>'.$surveys[$i]->getNumberOfQuestions().'</td>';
406 if ($show_number_votes) {
407 $ret.= '<td>'.$surveys[$i]->getNumberOfVotes().'</td>';
409 if ($show_vote && $user_id) {
410 if ($surveys[$i]->isUserVote($user_id)) {
411 $ret.='<td>'. _('Yes') . '</td>';
413 $ret.='<td>'. _('No') . '</td>';
417 /* Edit/Delete Link */
418 $ret.= '<td>['.util_make_link ('/survey/admin/survey.php?group_id='.$group_id.'&survey_id='. $surveys[$i]->getID(),_('Edit')).'] ';
420 /* We don;t support delete yet. Need to delete all results as well */
422 $ret.= '['.util_make_link ('/survey/admin/survey.php?delete=Y&group_id='.$group_id.'&survey_id='. $surveys[$i]->getID(),_('Delete')).']';
427 /* Edit/Delete Link */
428 $ret.= '<td>['.util_make_link ('/survey/admin/show_results.php?group_id='.$group_id.'&survey_id='. $surveys[$i]->getID(),_('Result')).']</td>';
430 if ($show_result_graph) {
431 /* Edit/Delete Link */
432 $ret.= '<td>['.util_make_link ('/survey/admin/show_results.php?graph=yes&group_id='.$group_id.'&survey_id='. $surveys[$i]->getID(),_('Result with Graph')).']</td>';
434 if ($show_result_comment) {
435 /* Edit/Delete Link */
436 $ret.= '<td>['.util_make_link ('/survey/admin/show_results.php?graph=yes&show_comment=yes&group_id='.$group_id.'&survey_id='.$surveys[$i]->getID(),_('Result with Graph and Comments')).']</td>';
441 $ret.= $GLOBALS['HTML']->listTableBottom();
446 * Show survey form - Show all forums of Survey
448 function ShowSurveyForm( &$s ) {
452 if (!$s->isActive()) {
453 return '<div class="error">'. _('Error - you can\'t vote for inactive survey').'</div>';
455 /* Get questions of this survey */
456 $questions = & $s->getQuestionInstances();
459 if ($s->isUserVote(user_getid())) {
460 $ret.= '<p class="warning_msg">'. _('Warning - you are about to vote a second time on this survey.').'</p>';
462 $ret.= '<form action="/survey/survey_resp.php" method="post">'.
463 '<input type="hidden" name="group_id" value="'.$group_id.'" />'.
464 '<input type="hidden" name="survey_id" value="'.$survey_id. '" />';
466 $ret.= '<table border="0">';
468 /* Keep question numbers */
470 $last_question_type = "";
471 for($i = 0; $i < count($questions); $i++) {
472 if ($questions[$i]->isError()) {
473 echo $questions[$i]->getErrorMessage();
476 $question_type = $questions[$i]->getQuestionType();
477 $question_id = $questions[$i]->getID();
478 $question_title = stripslashes($questions[$i]->getQuestion());
480 if ($question_type == '4') {
481 /* Don't show question number if it's just a comment */
482 $ret.='<tr><td valign="top"> </td><td>';
484 $ret.= '<tr><td valign="top"><strong>';
485 /* If it's a 1-5 question box and first in series, move Quest number down a bit */
486 if (($question_type != $last_question_type) && (($question_type == '1') || ($question_type == '3'))) {
487 $ret.= ' <br />';
490 $ret.= $index++.' <br /></td><td>';
493 switch($question_type) {
494 case 1: /* This is a radio-button question. Values 1-5.
495 Show the 1-5 markers only if this is the first in a series */
496 if ($question_type != $last_question_type) {
497 $ret.=' <strong>1</strong>'._('Low').
498 ' <strong>5</strong>' .
502 for ($j=1; $j<=5; $j++) {
503 $ret.= '<input type="radio" name="_'.$question_id.'" value="'.$j.'" />';
506 $ret.= ' '.$question_title;
509 case 2: /* This is a text-area question. */
510 $ret.= $question_title.'<br />';
511 $ret.='<textarea name="_'.$question_id.'" rows="5" cols="60"></textarea>';
513 case 3: /* This is a Yes/No question.
514 Show the Yes/No only if this is the first in a series */
515 if ($question_type != $last_question_type) {
516 $ret.= '<strong>Yes / No</strong><br />';
519 $ret.='<input type="radio" name="_'.$question_id.'" value="1" />';
520 $ret.='<input type="radio" name="_'.$question_id.'" value="5" />';
521 $ret.=' '.$question_title;
523 case 4: /* This is a comment only. */
524 $ret.= ' <br /><strong>'.util_make_links($question_title).'</strong>';
525 $ret.= '<input type="hidden" name="_'.$question_id.'" value="-666" />';
527 case 5: /* This is a text-field question. */
528 $ret.= $question_title. '<br />';
529 $ret.= '<input type="text" name="_'.$question_id.'" size="20" maxlength="70" />';
532 $ret.= $question_title. '<br />';
536 $last_question_type=$question_type;
539 $ret.='<tr><td style="text-align:center" colspan="2">'.
540 '<input type="submit" name="submit" value="'._('Submit').'" />'.
541 '<br />'.util_make_link ('/survey/privacy.php',_('Survey Privacy')).
542 '</td></tr></form></table>';
551 * @param Object a Survey Response Factory
553 function ShowResult( &$sr, $show_comment=0, $q_num="", $show_graph=0) {
556 $Survey = $sr->getSurvey();
557 $Question = $sr->getQuestion();
561 $ret.= $q_num . '. ';
564 $ret.=$Question->getQuestion().'</strong><br />';
565 $results = $sr->getResults();
567 echo ($sr->getErrorMessage());
570 $totalCount = $sr->getNumberOfSurveyResponses();
571 $votes = $Survey->getNumberOfVotes();
573 /* No votes, no result to show */
575 $ret.= '<ul><li>'._('No Votes').'</li></ul>';
579 switch($Question->getQuestionType()) {
580 case 1: /* This is a radio-button question. Values 1-5.
581 Show the 1-5 markers only if this is the first in a series */
582 $arr_name=array('No Answer', 'Low 1', '2', '3', '4', 'High 5', 'No Answer');
583 $arr_color=array('black', 'red', 'blue', 'yellow', 'green', 'brown', 'black');
584 $results[0] = $votes - $results[1] - $results[2] - $results[3] - $results[4] - $results[5];
587 $url ='graphs.php?type=vbar';
588 for ($j=5; $j>=0; $j--) {
589 $percent = sprintf("%02.1f%%", (float)$results[$j]*100/$votes);
591 $url.='&legend[]='.urlencode($arr_name[$j].' ('. $percent.')');
592 $url.='&value[]='.urlencode($results[$j]);
594 $ret.= '<img border="0" src="'.$url.'" alt="Graph of '.$Question->getQuestion().'"></img>';
596 $ret.= '<dd><table border="0" cellspacing="0" cellpadding="0" width=100%>';
598 for ($j=5; $j>=0; $j--) {
599 $percent = (float)$results[$j]*100/$votes;
600 $ret.= $this->_makeBar($arr_name[$j].' ('.$results[$j].')', $percent, $arr_color[$j]);
602 $ret.= '</table></dd>';
607 case 3: /* This is a Yes/No question. */
609 $arr_name=array('', 'YES', 'NO', 'No Answer');
610 $arr_color=array('', 'red', 'blue', 'black');
612 $res[1] = $results[1]; /* Yes */
613 $res[2] = $results[5]; /* No */
614 $res[3] = $votes - $res[1] -$res[2];
617 $url ='graphs.php?type=pie';
618 for ($j=1; $j<=3; $j++) {
619 $url.='&legend[]='.urlencode($arr_name[$j].'('.$res[$j].')');
620 $url.='&value[]='.urlencode($res[$j]);
622 $ret.= '<img border="0" src="'.$url.'" alt="Graph of '.$Question->getQuestion().'"></img>';
624 $ret.= '<dd><table border="0" cellspacing="0" cellpadding="0" width=100%>';
625 for ($j=1; $j<=3; $j++) {
626 $result_per[$j] = (float)$res[$j]*100/$votes;
627 $ret.= $this->_makeBar($arr_name[$j].' ('.$res[$j].')', $result_per[$j], $arr_color[$j]);
629 $ret.= '</table></dd>';
634 case 4: /* This is a comment only. */
637 case 2: /* This is a text-area question. */
638 case 5: /* This is a text-field question. */
640 for($j=0; $j<$totalCount; $j++) {
641 $ret.='<hr /><strong>'._('Comments').
642 ' # '.($j+1).'/'.$totalCount. '</strong><p/>';
644 $words = explode(" ",$results[$j]);
647 //print 100 chars in words per line
648 foreach ($words as $word) {
649 // if we have a stupidly strange word with lots of letters, we'll make a new line for it and split it
650 if ( (strlen($word)>100) && ((strlen($word)+$linelength)>100)) {
651 $chunks = $this->split_str($word,50);
652 foreach ($chunks as $chunk) {
658 $linelength += strlen($word);
659 if ($linelength>100) {
670 $ret.='<ul><li><a href="show_results.php?survey_id='.$Survey->getID().
671 '&question_id='.$Question->getID().
672 '&group_id='.$group_id.'">'.
673 sprintf(ngettext('View All %1$s Comment', 'View All %1$s Comments', $totalCount), $totalCount).
686 * split_str - works as str_split of PHP5 - Converts a string to an array.
689 * @param int length of chunk
690 * @return array array of chunks of the string
692 function split_str($str,$split_lengt=1) {
694 for ($i=0;$i<$cnt;$i+=$split_lengt) {
695 $rslt[]= substr($str,$i,$split_lengt);
701 * _makeBar - make Precentage bar as a cell in a table. Starts with <tr> and ends with </tr>
703 * @param String name Name
704 * @param int percentage of the name
707 function _makeBar($name, $percent, $color) {
708 $ret = '<tr><td width="30%">'.$name.'</td><td>';
709 $ret.= '<table width="'.$percent.'%" border="0" cellspacing="0" cellpadding="0"><tr>';
711 $ret.='<td width="90%" bgcolor="'.$color.'"> </td>';
714 $ret.= '<td>'.sprintf("%.2f", $percent).'%</td></tr></table></td></tr>'."\n";
722 // c-file-style: "bsd"