Framework  3.9
select_field_renderer.inc
Go to the documentation of this file.
1 <?php
6 /**************************************************************
7 
8  Copyright (c) 2007-2010 Sonjara, Inc
9 
10  Permission is hereby granted, free of charge, to any person
11  obtaining a copy of this software and associated documentation
12  files (the "Software"), to deal in the Software without
13  restriction, including without limitation the rights to use,
14  copy, modify, merge, publish, distribute, sublicense, and/or sell
15  copies of the Software, and to permit persons to whom the
16  Software is furnished to do so, subject to the following
17  conditions:
18 
19  The above copyright notice and this permission notice shall be
20  included in all copies or substantial portions of the Software.
21 
22  Except as contained in this notice, the name(s) of the above
23  copyright holders shall not be used in advertising or otherwise
24  to promote the sale, use or other dealings in this Software
25  without prior written authorization.
26 
27  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
29  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
31  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
32  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
34  OTHER DEALINGS IN THE SOFTWARE.
35 
36 *****************************************************************/
37 
38 require_once realpath(dirname(__FILE__))."/../field_renderers.inc";
39 
67 class SelectFieldRenderer extends FieldRenderer
68 {
69  var $options;
70  var $addEntry;
71  var $addEntryText;
72  var $onChange;
73  var $max_chars;
74  var $width;
75 
76  var $defaultBlank = false;
77  var $defaultText = "Choose One";
78  var $defaultValue = "";
79  var $allowDeselect = false;
80 
81  var $CSSclass;
82  var $stripHTML = false;
83 
84  function SelectFieldRenderer(&$form, $field, $label, $options = null, $onChange="", $grouped = false)
85  {
86  $this->options = $options;
87  $this->onChange = $onChange;
88  $this->grouped = $grouped;
89  $this->FieldRenderer($form);
90  if ($form->getData()->hasField($field))
91  {
92  // JDG 5/30/11 - don't crash on additiona/psuedo fields
93  // only query if real field
94  $form->override($field, $label, $this);
95  if ($this->options == null)
96  {
97  $opt = $form->getData()->distinctValues($field, true);
98  if (count($opt) > 0)
99  {
100  $this->options = array_combine($opt, $opt);
101  }
102  else
103  {
104  $this->options = array();
105  }
106  }
107  }
108  else
109  {
110  $form->add($this, $field);
111  // JDG 7/22/2011 - allow "additional" fields to override label
112  $form->overrides[$field]['label'] = $label;
113  }
114 
115  }
116 
121  function setMaxChars($max)
122  {
123  $this->max_chars = $max;
124  return $this;
125  }
126 
132  function allowAddEntry($text = "or add new")
133  {
134  $this->addEntry = true;
135  $this->addEntryText = $text;
136  $this->addOtherOption();
137  return $this;
138  }
139 
144  function allowBlank($text = "", $value = "")
145  {
146  if (!$this->grouped && !$text) $text = "Choose One";
147  $this->defaultBlank = true;
148  $this->defaultText = $text;
149  $this->defaultValue = $value;
150  return $this;
151  }
152 
159  function addDefaultOption($field)
160  {
161  $val = $this->parent->data->get($field);
162  if(!$this->defaultBlank || ($val && !$this->allowDeselect)) return;
163 
164  if(count($this->options) && !array_search("", $this->options))
165  {
166  // want the blank at the top - array_merge causes issues; copy array instead
167  $options[$this->defaultValue] = $val ? "" : $this->defaultText;
168  foreach($this->options as $key => $value)
169  {
170  $options[$key] = $value;
171  }
172  $this->options = $options;
173  }
174  }
175 
181  function extendOptions($options)
182  {
183  if ($this->grouped)
184  {
185  throw new FakoliException("SelectFieldRenderer::extendOptions() not supported in grouped mode");
186  }
187 
188  foreach($options as $value => $text)
189  {
190  if (!array_key_exists($value, $this->options))
191  {
192  $this->options[$value] = $text;
193  }
194  }
195  }
196 
197  function renderField($field)
198  {
199  $this->_startField($field);
200 
201  if (count($this->options) > 0 || !$this->addEntry)
202  {
203  $cssClass = $this->CSSclass ? " class='{$this->CSSclass}'" : "";
204  if($this->width)
205  $style = "style='width: {$this->width}'";
206  echo "<select {$class}{$style} name='$field' id='{$this->parent->id}_{$field}'";
207 
208  if ($this->onChange != "")
209  echo " onchange='$this->onChange(this)'";
210  elseif($this->addEntry)
211  echo " onchange='onChange_{$this->parent->id}_{$field}(this)'";
212 
213  echo ">\n";
214 
215  /* Check if we have addEntry text coming in from the db;
216  * othEntry is text that doesn't match the set of options
217  * for this field
218  * */
219  $othEntry = true;
220  $current = $this->parent->data->get($field);
221 
222  if ($this->parent->data->getType($field) == 'String')
223  {
224  $comparator = function($a, $b) { return (strcmp($a, $b) == 0); };
225  }
226  else
227  {
228  $comparator = function($a, $b) { return $a == $b; };
229  }
230 
231  if ($this->grouped)
232  {
233  if ($this->defaultBlank)
234  {
235  echo "<option value=''>{$this->defaultText}</option>\n";
236  }
237 
238  //$this->addDefaultOption($field);
239 
240  foreach($this->options as $groupName => $group)
241  {
242  if ($groupName == "")
243  {
244  //echo "<option value=''>{$this->defaultText}</option>\n";
245  continue;
246  }
247 
248  echo "<optgroup label=\"$groupName\">\n";
249 
250  foreach($group as $value => $name)
251  {
252  $name = ($this->stripHTML) ? stripHTML($name) : htmlSafe($name);
253  $trunced = $this->max_chars ? ellipsis($name, $this->max_chars, true) : $name;
254 
255  if ($comparator($current, $value))
256  {
257  $selected = " selected";
258  $othEntry = false;
259  }
260  else
261  $selected = "";
262 
263  trace("$current == $value ".($current==$value)." $selected", 3);
264 
265  $optionTitle = ($name != $trunced) ? " title='$name'" : "";
266 
267  echo "<option$optionTitle value='".htmlSafe($value)."'$selected>$trunced</option>\n";
268  }
269 
270  echo "</optgroup>\n";
271  }
272  }
273  else
274  {
275  /*
276  * If there is no match but there is a value saved,
277  * (user entered an addEntry value) then set current
278  * to blank so that the "Other" option is shown as selected.
279  */
280  if(!array_key_exists($current, $this->options))
281  {
282  $addEntryValue = $current;
283  $current = "";
284  }
285 
286  $this->addDefaultOption($field);
287 
288  foreach($this->options as $value => $name)
289  {
290  $name = ($this->stripHTML) ? stripHTML($name) : htmlSafe($name);
291  $trunced = $this->max_chars ? ellipsis($name, $this->max_chars, true) : $name;
292 
293  if($comparator($current, $value))
294  {
295  $selected = " selected";
296  }
297  else
298  $selected = "";
299 
300  $optionTitle = ($name != $trunced) ? " title='$name'" : "";
301 
302  echo "<option$optionTitle value='".htmlSafe($value)."'$selected>$trunced</option>\n";
303  }
304  }
305 
306  echo "</select>\n";
307  }
308 
309  /*
310  * We need to create this field whether displayed or not so that the
311  * custom required validator, SelectFieldRequiredValidator, works for
312  * either case.
313  */
314  $type = $this->addEntry ? 'text' : 'hidden';
315 
316  if ($this->addEntry)
317  {
318  echo "&nbsp;{$this->addEntryText}&nbsp;";
319  $onChange = " onchange='onChange_{$this->parent->id}_{$field}_addEntry(this)'";
320 
321  }
322  echo "<input type='$type' name='{$field}_addEntry' class='add_entry' id='{$field}_addEntry' value='{$addEntryValue}' size='20' $onChange/>";
323 
324  $this->_endField($field);
325  }
326 
327  function renderSearchField($field, $mode, $value = "")
328  {
329  if ($mode != "equal" && $mode != "member") $mode = "equal";
330 
331  $searchValue = (!$value) ? $this->parent->params->get($field, $mode) : $value;
332 
333  $this->_startField($field);
334 
335  if($this->width)
336  {
337  $style = "style='width: {$this->width}'";
338  }
339 
340  echo "<select $style id='$field' name='$field:$mode'";
341 
342  if ($this->onChange != "")
343  echo " onchange='$this->onChange(this)'";
344 
345  echo "><option value=''></option>\n";
346  foreach($this->options as $value => $name)
347  {
348  $selected = ($searchValue === $value) ? " selected" : "";
349  $name = ($this->stripHTML) ? stripHTML($name) : htmlSafe($name);
350 
351  echo "<option value='".htmlSafe($value)."'$selected>$name</option>";
352  }
353  echo "</select>\n";
354 
355  $this->_endField($field);
356  }
357 
358 
359  function renderReadOnly($field)
360  {
361  $this->_startField($field);
362 
363  $value = $this->parent->data->get($field);
364  if ($this->grouped)
365  {
366  $found = false;
367  foreach($this->options as $group => $options)
368  {
369  if (array_key_exists($value, $options))
370  {
371  echo $options[$value];
372  $found = true;
373  break;
374  }
375  }
376  if (!$found)
377  {
378  echo "Not specified";
379  }
380  }
381  else
382  {
383  if (array_key_exists($value, $this->options))
384  {
385  echo $this->options[$value];
386  }
387  elseif($value)
388  {
389  echo $value;
390  }
391  else
392  {
393  echo "Not specified";
394  }
395  }
396 
397  $this->_endField($field);
398  }
399 
400  function preProcess($field = "")
401  {
402  $found = false;
403 
404  $current = $this->parent->data->get($field);
405 
406  if ($this->grouped)
407  {
408  foreach($this->options as $groupName => $group)
409  {
410  foreach($group as $value => $name)
411  {
412  if($current == $value && $value != '')
413  $found = true;
414  }
415  }
416  }
417  else
418  {
419  foreach($this->options as $value => $name)
420  {
421  if($current == $value && $value != '')
422  $found = true;
423  }
424  }
425 
426  $addEntry = $_POST["{$field}_addEntry"];
427  trace("addEntry($field): $addEntry and found $found", 3);
428 
429  if ($_POST["{$field}_addEntry"] && !$found)
430  {
431  trace("setting field $field with add entry value $addEntry", 3);
432  $this->parent->data->set($field, $addEntry);
433  }
434  }
435 
446  function renderScript($field)
447  {
448  $fn = "{$this->parent->id}_$field";
449  $addEntry = $field . "_addEntry";
450 
451  if(!$this->onChange && $this->addEntry)
452  {
453 ?>
454 <script type="text/javascript">
455 function onChange_<?echo $fn?>(elt)
456 {
457  if(!elt.value == '')
458  {
459  var addEntry = document.id('<?php echo $addEntry ?>');
460  if(addEntry)
461  addEntry.value = '';
462  }
463 }
464 </script>
465 <?
466  } // end if onChange and addEntry
467 
468  if($this->addEntry)
469  {
470 ?>
471  <script type="text/javascript">
472 function onChange_<?echo "{$fn}_addEntry" ?>(elt)
473 {
474  if(elt.value)
475  {
476  var selected = document.id('<?php echo $field ?>');
477  if(selected)
478  selected.value = '';
479  }
480 }
481 </script>
482 <?php
483  } // ent if this addEntry
484  } // end function renderScript
485 
486 
492  function addOtherOption($text = "Other")
493  {
494  if(!array_key_exists("", $this->options))
495  {
496  $this->options[""] = $text;
497  }
498 
499  return $this;
500  }
501 
502 
503 } // end class SelectFieldRenderer
504 ?>
FieldRenderer is the abstract base class for all FieldRenderers.
_startField($field, $styles="")
Internal method to generate the starting HTML for the field (including the label)
preProcess($field="")
FieldRenderers can override this method to provide behavior that occurs prior to the saving of the pa...
renderField($field)
FieldRenderers must override this method to provide the HTML implementation of the control used to ed...
_endField($field)
Internal method to generate the closing HTML for the field.
renderScript($field)
FieldRenderers can override this method to provide any Javascript that their control requires for an ...
renderSearchField($field, $mode)
FieldRenderers must override this method to provide the HTML implementation of the control displayed ...
FieldRenderer($parent)
Constructor.
trace($msg, $lvl=3, $callStack=null)
Send output to the trace log.
Definition: functions.inc:1010
stripHTML($text)
Definition: functions.inc:847
ellipsis($txt, $max, $wholeWord=false)
Truncate the supplied text at the given maximum length.
Definition: functions.inc:779