CMS  Version 3.9
question_renderer.inc
Go to the documentation of this file.
1 <?php
7 /**************************************************************
8 
9 Copyright (c) 2007,2008 Sonjara, Inc
10 
11 Permission is hereby granted, free of charge, to any person
12 obtaining a copy of this software and associated documentation
13 files (the "Software"), to deal in the Software without
14 restriction, including without limitation the rights to use,
15 copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the
17 Software is furnished to do so, subject to the following
18 conditions:
19 
20 The above copyright notice and this permission notice shall be
21 included in all copies or substantial portions of the Software.
22 
23 Except as contained in this notice, the name(s) of the above
24 copyright holders shall not be used in advertising or otherwise
25 to promote the sale, use or other dealings in this Software
26 without prior written authorization.
27 
28 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
30 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
32 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
33 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35 OTHER DEALINGS IN THE SOFTWARE.
36 
37 *****************************************************************/
38 /*
39  * Title: question_renderer.inc
40  *
41  * Description: Classes for rendering different types of questions:
42  * multiple choice
43  * rating
44  * short text
45  * free text
46  * checklist
47  *
48  * author: Janice Gallant for Sonjara, Inc.
49  *
50  * date: 11/4/09
51  */
52 
53 Fakoli::using("questionnaire");
54 Fakoli::usingFile("framework/validation.inc");
55 
56 /*
57  * QuestionField
58  *
59  * Displays each type of question
60  */
62 {
63  var $parent;
64  var $question;
65  var $readonly;
66  var $answer;
67  var $answerSeparator = "<br>";
68 
70  {
71  $this->parent = $parent;
72  $this->question = $question;
73  $qPk = $question->getPrimaryKey();
74  $this->answer = $this->parent->answers[$this->question->$qPk];
75  }
76 
77  function getID()
78  {
79  return $this->question->get($this->question->getPrimaryKey());
80  }
81 
82  function writeScript()
83  {
84  return "";
85  }
86 
87  function writeHTML()
88  {
89  return "";
90  }
91 
92  function drawGraph()
93  {
94 
95  }
96 
97  /*
98  * Draws the answer to a question as text, not
99  * as formatted hmtl.
100  */
101  function drawSummaryView()
102  {
103  echo "<p>" . $this->getAnswer() . "</p>";
104  }
105 
106  /*
107  * Gets the answer, unmassaged, from the value
108  * field of the table. Used for freetext and
109  * shorttext.
110  */
111  function getAnswer()
112  {
113  return $this->parent->getAnswer($this->question);
114  }
115 
117  {
118  return $this->getAnswer();
119  }
120 
121  // Get single answer from a set of options
122  // (SelectField and Multichoice)
123  function getOptionAnswer()
124  {
125  $pk = $this->question->getPrimaryKey();
126  $options = explode("\n", $this->question->options);
127 
128  $valueAnswer = $this->parent->getAnswer($this->question);
129 
130  $count = count($options);
131  if($count > 0)
132  {
133  $idx = 1;
134  foreach($options as $value => $text)
135  {
136  if($valueAnswer == $idx)
137  {
138  $answer = $text;
139  break;
140  }
141  $idx++;
142  }
143  }
144 
145  return $answer;
146  }
147 
148  function writeLimitScript()
149  {
150  if ($this->question->char_limit)
151  {
152 
153  $pk = $this->question->getPrimaryKey();
154  $field = "question_{$this->question->$pk}";
155 
156  $script = <<<ENDSCRIPT
157 
158 /* <![CDATA[ */
159  function {$field}_keyup(event)
160  {
161  var form = document.getElementById('Questionnaire_form');
162  var ctrl = form['{$field}'];
163  var len = ctrl.value.length;
164  if (len >= {$this->question->char_limit})
165  {
166  ctrl.value = ctrl.value.substring(0, {$this->question->char_limit});
167  len = {$this->question->char_limit};
168  }
169 
170  var count = document.getElementById('{$field}_length');
171  count.innerHTML = len;
172  }
173 
174 ENDSCRIPT;
175 
176  return $script;
177 
178  }
179  }
180 
181 
182  function renderLimitEnd($limit, $field, $value)
183  {
184  if ($limit)
185  {
186  echo strlen(trim($value));
187  echo "</span> of {$limit} characters";
188  }
189  }
190 
191  // Indicate required with asterisk
192  function getRequired()
193  {
194  return ($this->question->required) ? "*" : "";
195  }
196 
198  {
199  // empty answer signals to validate from form and $_POST
200  $pk = $this->question->getPrimaryKey();
201 
202  $answer = ($this->parent->readOnlyForm) ? $this->answer : "";
203  $question_number = ($this->question->question_number) ? $this->question->question_number : $this->parent->mgr->getQuestionNumber($this->question);
204  return new RequiredQuestionValidator("question_{$this->question->$pk}", "Question {$question_number}", "", $answer);
205  }
206 
207 
208  static function create($parent, $question)
209  {
210  $questionType = new QuestionType($question->question_type_id);
211 
212  if($questionType AND $questionType->class_name)
213  return new $questionType->class_name($parent, $question);
214  else
215  {
216  trace("QuestionField::create(): Unknown question type", 2);
217  die("Unknown question type {$question->question_type_id}");
218  }
219  }
220 }
221 
222 
224 {
225  var $skipNumbering = true;
226 
228  {
230  }
231 
232 
233  function drawView()
234  {
235  $this->writeHTML();
236  }
237 
238  /*
239  * Draws the answer to a question as text, not
240  * as formatted hmtl.
241  */
242  function drawSummaryView()
243  {
244  }
245 }
246 
247 
248 /*
249  * readonly attribute doesn't work for radio buttons;
250  * use "disabled" instead.
251  *
252  * Radio buttons are in a table layout so that they align properly in IE7
253  */
255 {
257  {
259  }
260 
261 
262  function writeHTML()
263  {
264  $pk = $this->question->getPrimaryKey();
265  $options = explode("\n", $this->question->options);
266  $tips = explode("\n", $this->question->context_help);
267 
268  $valueAnswer = $this->parent->getAnswer($this->question);
269 
270  $readonly = $this->parent->readOnlyForm ? " DISABLED" : "";
271 
272  echo "<table class=\"layout\">";
273 
274  $count = count($options);
275 
276  if($count > 0)
277  {
278  $idx = 1;
279  foreach($options as $value => $text)
280  {
281  $tip = $tips[$idx - 1];
282  if ($tip)
283  {
284  $tip = " onmouseover=\"showTextToolTip('question_{$this->question->$pk}', event, 'question_help', '".jsSafe($tip)."'); return false;\" onmouseout=\"hideToolTip('question_help');return false\" ";
285  }
286 
287  $selected = ($valueAnswer == $idx) ? " checked" : "";
288 
289  echo "<tr><td style=\"padding:1px\"$tip><input type='radio'
290  style='border: none' name='question_{$this->question->$pk}' id='question_{$this->question->$pk}_$idx'
291  value='$idx'$selected $readonly>&nbsp;$text</td></tr>";
292  $idx++;
293  }
294  }
295 
296  // Save this count to loop through checkboxes on required validation
297  echo "<input type=\"hidden\" name=\"count_question_{$this->question->$pk}\" value=\"$count\">";
298 
299  echo "</table>";
300 
301  }
302 
303  function drawView()
304  {
305  $this->writeHTML();
306  }
307 
308  /*
309  * Get the single text answer for this mult choice question
310  */
311  function getAnswer()
312  {
313  return $this->getOptionAnswer();
314  }
315 
317  {
318  $pk = $this->question->getPrimaryKey();
319  // Empty question object signals to validator to validate from form and $_POST.
320  // Not empty means this is a view so we have the answer object that was saved.
321  $answer = ($this->parent->readOnlyForm) ? $this->answer : "";
322  $question_number = $this->question->question_number ? $this->question->question_number : $this->parent->mgr->getQuestionNumber($this->question);
323  return new RequiredRadioButtonQuestionValidator("question_{$this->question->$pk}", "Question {$question_number}", $answer);
324  }
325 
334  {
336  }
337 
338 }
339 
340 
341 
342 
343 /*
344  * Creates a drop down view of options list
345  *
346  */
348 {
350  {
352  }
353 
354 
355  function writeHTML()
356  {
357  $options = explode("\n", $this->question->options);
358 
359  $num = 1;
360  $value = $this->parent->getAnswer($this->question);
361 
362  $readonly = $this->parent->readOnlyForm ? " DISABLED" : "";
363 
364  if(count($options) > 0)
365  {
366  echo "<table class=\"layout\">";
367  $pk = $this->question->getPrimaryKey();
368  echo "<select name='question_{$this->question->$pk}'>\n";
369  if(!$readonly)
370  {
371  echo "<option value=''></option>"; // blank
372  }
373 
374  foreach($options as $option)
375  {
376  $selected = ($value == $num) ? " selected" : "";
377  echo "<option value='$num'$readonly$selected>$option</option>";
378  $num++;
379  }
380 
381  echo "</select>";
382  }
383 
384  echo "</table>";
385  }
386 
387  function drawView()
388  {
389  $this->writeHTML();
390  }
391 
392 
393  function getAnswer()
394  {
395  return $this->getOptionAnswer();
396  }
397 
406  {
408  }
409 }
410 
412 {
414  {
416  }
417 
418  function writeHTML()
419  {
420  list($from, $to, $steps) = explode("\n", $this->question->options);
421  if (!$from) $from = "Lowest";
422  if (!$to) $to = "Highest";
423  if (!$steps) $steps = 5;
424 
425 
426  $readonly = $this->parent->readOnlyForm ? " disabled='disabled'" : "";
427  $valueAnswer = $this->parent->getAnswer($this->question);
428 
429  $qPk = $this->question->getPrimaryKey();
430 
431  $tip = $this->question->context_help;
432  if ($tip)
433  {
434  $tip = " onmouseover=\"showTextToolTip('question_{$this->question->$qPk}', event, 'question_help', '".jsSafe($tip)."'); return false;\" onmouseout=\"hideToolTip('question_help');return false\" ";
435  }
436  echo "<div$tip>$from&nbsp;";
437 
438  for($i = 1; $i <= $steps; ++$i)
439  {
440  $selected = ($valueAnswer == $i) ? " checked" : "";
441 
442  echo "<input type='radio' style='border: none' name='question_{$this->question->$qPk}'
443  id='question_{$this->question->$qPk}_$i'
444  value='$i'$selected $readonly />&nbsp;";
445  }
446 
447  // Save this count to loop through checkboxes on required validation
448  echo "<input type=\"hidden\" name=\"count_question_{$this->question->$qPk}\" value=\"$steps\">";
449 
450  echo $to."</div>";
451  }
452 
453  function getAnswer()
454  {
455  $this->getOptions($this->question->options, $from, $to, $steps);
456 
457  $valueAnswer = $this->parent->getAnswer($this->question);
458  if($valueAnswer)
459  $answer = "{$valueAnswer} rating on scale of $steps $from &ndash; $to";
460 
461  return $answer;
462  }
463 
465  {
466  $this->getOptions($this->question->options, $from, $to, $steps);
467  $valueAnswer = $this->parent->getAnswer($this->question);
468 
469  return $valueAnswer;
470  }
471 
472  static function getOptions($options, &$from, &$to, &$steps)
473  {
474  list($from, $to, $steps) = explode("\n", $options);
475  if (!$from) $from = "Lowest";
476  if (!$to) $to = "Highest";
477  if (!$steps) $steps = 5;
478  }
479 
480  function drawView()
481  {
482  $this->writeHTML();
483  }
484 
486  {
487  // Empty question object signals to validator to validate from form and $_POST.
488  // Not empty means this is a view so we have the answer object that was saved.
489  $pk = $this->question->getPrimaryKey();
490  $answer = ($this->parent->readOnlyForm) ? $this->answer : "";
491  $question_number = $this->question->question_number ? $this->question->question_number : $this->parent->mgr->getQuestionNumber($this->question);
492  return new RequiredRadioButtonQuestionValidator("question_{$this->question->$pk}", "Question {$question_number}", $answer);
493  }
494 
503  {
505  }
506 }
507 
508 // JDG 8/4/2011 - change to String rendering
510 {
512  {
514  }
515 
516  function writeHTML()
517  {
518  $value = $this->parent->getAnswer($this->question);
519  $readonly = $this->parent->readOnlyForm ? " readonly='readonly'": "";
520  $autocomplete = "autocomplete='off'";
521 
522  $pk = $this->question->getPrimaryKey();
523 
524  $field = "question_" . $this->question->$pk;
525 
526  if ($this->question->char_limit)
527  {
528  $onkeypress = " onkeyup='{$field}_keyup(event);'";
529  }
530 
531  $tip = $this->question->context_help;
532  if ($tip)
533  {
534  $tip = " onmouseover=\"showTextToolTip('question_{$this->question->$pk}', event, 'question_help', '".jsSafe($tip)."'); return false;\" onmouseout=\"hideToolTip('question_help');return false\" ";
535  }
536 
537  echo "<input id='$field' type='text' name='$field' $readonly $autocomplete value='".htmlspecialchars($value, ENT_QUOTES, 'UTF-8')."' size='50' $disable $onkeypress $tip/>";
538  echo "<br/><div style='clear: left; float: right'><span id='{$field}_length'>";
539 
540  parent::renderLimitEnd($this->question->char_limit, $field, $value);
541  echo "</div>";
542 
543  }
544 
545  function drawView()
546  {
547  $value = $this->parent->getAnswer($this->question);
548  echo "<em>".htmlsafe($value)."</em>";
549  }
550 
551  function writeScript()
552  {
553  return parent::writeLimitScript();
554  }
555 
565  {
566  $pk = $this->question->getPrimaryKey();
567  echo "<ul>\n";
568 
569  foreach($answers as $answer)
570  {
571  if ($answer->value)
572  {
573  echo "<li>" . formatAsHTML(stripHTML($answer->value)) . "</li>\n";
574  }
575  }
576  echo "</ul>\n";
577  }
578 }
579 
581 {
582 
584  {
586  }
587 
588  function writeScript()
589  {
590  return parent::writeLimitScript();
591  }
592 
593 
594  function writeHTML()
595  {
596  $pk = $this->question->getPrimaryKey();
597  $field = "question_{$this->question->$pk}";
598 
599  $rows = ($this->question->num_rows) ? $this->question->num_rows : 6;
600 
601  echo "<div>";
602  if ($this->question->char_limit)
603  {
604  $onkeypress = " onkeyup='{$field}_keyup(event);'";
605  }
606 
607  $value = $this->parent->getAnswer($this->question);
608 
609  $readonly = $this->parent->readOnlyForm ? " readonly='readonly'": "";
610  $autocomplete = "autocomplete='off'";
611 
612  $tip = $this->question->context_help;
613  if ($tip)
614  {
615  $tip = " onmouseover=\"showTextToolTip('question_{$this->question->$pk}', event, 'question_help', '".jsSafe($tip)."'); return false;\" onmouseout=\"hideToolTip('question_help');return false\" ";
616  }
617 
618  echo "<textarea name='{$field}' cols='75' rows='$rows' $onkeypress $readonly $autocomplete $tip>".htmlsafe($value)."</textarea>";
619 
620  echo "<br/><div style='clear: left; float: right'><span id='{$field}_length'>";
621 
622  parent::renderLimitEnd($this->question->char_limit, $field, $value);
623 
624  echo "</div></div>";
625 
626  }
627 
628  function drawView()
629  {
630  $value = $this->parent->getAnswer($this->question);
631 
632  /* JDG 2/9/10, htmlsafe makes some text with bad characters
633  * disappear
634  */
635 
636  $answerVal = htmlsafe($value);
637  if(!$answerVal)
638  $answerVal = formatAsHTML($value);
639 
640  echo "<em>".$answerVal."</em>";
641  }
642 
643 
653  {
654  $pk = $this->question->getPrimaryKey();
655  echo "<ul>\n";
656 
657  foreach($answers as $answer)
658  {
659  if ($answer->value)
660  {
661  echo "<li>" . formatAsHTML(stripHTML($answer->value)) . "</li>\n";
662  }
663  }
664  echo "</ul>\n";
665  }
666 }
667 
668 
670 {
672  {
674  }
675 
676  function getValues()
677  {
678  $values = $this->parent->getAnswer($this->question);
679 
680  // include 0 value, first checkbox
681  if(strlen($values)==1 AND is_numeric($values))
682  $values = array($values);
683  elseif(strlen($values)==0)
684  $values = "";
685  else
686  $values = explode(",", $values);
687 
688  return $values;
689  }
690 
691  function writeHTML()
692  {
693  $optionArr = explode("\n", $this->question->options);
694  $options = $this->parent->incrementArray($optionArr);
695  $tips = explode("\n", $this->question->context_help);
696 
697  $values = $this->getValues();
698 
699  $readonly = $this->parent->readOnlyForm ? " DISABLED" : "";
700 
701  // to do - put the font style into css
702  echo "<table class=\"layout\">";
703  $idx = 1;
704 
705  $count = count($options);
706  $pk = $this->question->getPrimaryKey();
707 
708  if($count > 0)
709  {
710  foreach($options as $value => $text)
711  {
712  if(is_array($values))
713  {
714  $checked = (array_search($value, $values) !== FALSE) ? " checked" : "";
715  }
716 
717  $tip = $tips[$idx - 1];
718  if ($tip)
719  {
720  $tip = " onmouseover=\"showTextToolTip('question_{$this->question->$pk}', event, 'question_help', '".jsSafe($tip)."'); return false;\" onmouseout=\"hideToolTip('question_help');return false\" ";
721  }
722 
723  echo "<tr><td style=\"padding:1px\"$tip><input type='checkbox'
724  class='checkbox' name='question_{$this->question->$pk}[$idx]'
725  value='$value'$readonly$checked/>&nbsp;$text</td></tr>";
726  $idx++;
727  }
728 
729  // Save this count to loop through checkboxes on required validation
730  echo "<input type=\"hidden\" name=\"count_question_{$this->question->$pk}\" value=\"$count\">";
731  }
732 
733  echo "</table>";
734 
735  }
736 
737  /*
738  * Indicate count of required checkboxes
739  *
740  * If the count of options is 1 and the
741  * question is required, then just
742  * show "*" to denote required.
743  */
744  function getRequired()
745  {
746  if($this->question->required > 0)
747  {
748  $optionArr = explode("\n", $this->question->options);
749  if(count($optionArr) > 1)
750  {
751  $label = ($this->question->required > 1) ? "checkboxes" : "checkbox";
752  $required = "* at least " . $this->question->required . " $label must be checked";
753  }
754  else
755  $required = "*";
756  }
757  return $required;
758  }
759 
761  {
762  // Empty question object signals to validator to validate from form and $_POST.
763  // Not empty means this is a view so we have the answer object that was saved.
764  $pk = $this->question->getPrimaryKey();
765  $answer = ($this->parent->readOnlyForm) ? $this->answer : "";
766  $question_number = $this->question->question_number ? $this->question->question_number : $this->parent->mgr->getQuestionNumber($this->question);
767  return new RequiredCheckListQuestionValidator("question_{$this->question->$pk}", "Question {$question_number}", $this->question->required, $answer);
768  }
769 
770  function drawView()
771  {
772  $this->writeHTML();
773  }
774 
775 
776  function getAnswer()
777  {
778  $optionArr = explode("\n", $this->question->options);
779  $options = $this->parent->incrementArray($optionArr);
780 
781  $answers = array();
782  $values = $this->getValues();
783 
784  $count = count($options);
785  if($count > 0)
786  {
787  $idx = 1;
788  foreach($options as $value => $text)
789  {
790  if(is_array($values))
791  {
792  if(array_search($value, $values) !== FALSE)
793  {
794  $answers[] = $text;
795  }
796  }
797  $idx++;
798  }
799  }
800  return implode($this->answerSeparator, $answers);
801  }
802 
811  {
813  }
814 }
815 ?>
CheckListView($parent, $question)
drawGraph($mgr, $answers)
Draws an interactive graphical view of answers to one question.
static using()
Import the datamodels, views and manifest for the specified component(s).
Definition: core.inc:116
static usingFile()
Uses the specified framework file(s) from the framework directory.
Definition: core.inc:369
FreeTextView($parent, $question)
drawGraph($mgr, $answers)
There is no graphical display for free text questions so just display the answers as a list.
MultipleChoiceView($parent, $question)
drawGraph($mgr, $answers)
Draws an interactive graphical view of answers to one question.
MultipleChoiceView($parent, $question)
QuestionField($parent, $question)
static create($parent, $question)
$answer
The answer to the question obj.
$readonly
Whether the questions should be drawn readonly.
$question
The question renderer obj.
$answerSeparator
for list of answers in checklist renderer
renderLimitEnd($limit, $field, $value)
$parent
The parent QuestionForm obj.
static drawChecklistGraph($question, $resultsManager, $answers)
Draws an interactive graphical view of answers to one question.
static drawSelectGraph($question, $resultsManager, $answers)
Draws an interactive graphical view of answers to one question.
static drawRatingsGraph($question, $resultsManager, $answers)
Draws an interactive graphical view of answers to one question.
RatingView($parent, $question)
drawGraph($mgr, $answers)
Draws an interactive graphical view of answers to one question.
static getOptions($options, &$from, &$to, &$steps)
RequiredCheckListQuestion Validator.
Definition: validation.inc:117
RequiredQuestion Validator.
Definition: validation.inc:58
RequiredRadioButtonQuestion Validator.
Definition: validation.inc:199
SelectFieldView($parent, $question)
drawGraph($mgr, $answers)
Draws an interactive graphical view of answers to one question.
drawGraph($mgr, $answers)
There is no graphical display for free text questions so just display the answers as a list.
ShortTextView($parent, $question)
if( $method=="POST")
$answers