Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
metadata_field_hierarchy_edit_fns.inc
1 <?php
18 require_once dirname(__FILE__).'/../../metadata_field/metadata_field_edit_fns.inc';
19 
32 {
33 
34 
39  function __construct()
40  {
41  parent::__construct();
42 
43  }//end constructor
44 
45 
62  public function paintValueInterface(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $value_str, $write_access, $enable_default=TRUE, $print_cascade_values_option=TRUE)
63  {
64  $prefix = $asset->getPrefix();
65  require_once SQ_LIB_PATH.'/html_form/html_form.inc';
66 
67  $value = '';
68  $value_components = $asset->attr('value_components');
69 
70  $is_default = FALSE;
71  if (is_null($value_str)) {
72  $value_str = $asset->getDefaultValue();
73  $is_default = TRUE;
74  }
75 
76  Metadata_Field::decodeValueString($value_str, $value, $value_components);
77 
78  if ($asset->attr('multiple')) {
79  // if there is no value we need a blank array...not an array with one element (a blank string)
80  if ($value == '') {
81  $value = Array();
82  } else {
83  $value = explode('; ', $value);
84  }
85  }
86 
87  if ($enable_default) {
88  echo '<span id="'.$prefix.'_field">';
89  }
90 
91  $display_type = $asset->attr('display_type');
92  $hierarchy = $asset->getHierarchyAttribute();
93  $hierarchy_options = $hierarchy->_params['options'];
94  if ($write_access) {
95  if (!$display_type) {
96  // flat view
97  $hierarchy->value = $value;
98  $hierarchy_sort = $hierarchy->_params['sort'];
99  $hierarchy_structure = $hierarchy->_params['structure'];
100 
101  $hier_sort = (isset($hierarchy_sort) && $hierarchy_sort>=0) ? $hierarchy_sort : '0';
102  $hier_structure = (isset($hierarchy_structure) && $hierarchy_structure) ? $hierarchy_structure : FALSE;
103 
104  if ($enable_default) {
105  $hierarchy->_edit_params['extras'] = 'onclick="document.getElementById(\''.$prefix.'_default\').checked = false;"';
106  if ($is_default) {
107  $hierarchy->_edit_params['extras'] .= ' disabled="disabled"';
108  }
109  echo '<span id="'.$prefix.'_field">';
110  }
111 
112  // Sort the hierarchy if selected
113  if ($hier_sort) {
114  $options = $hierarchy->_params['options'];
115  $options = $this->_sortHierarchyOptions($options, $hier_sort, $hier_structure);
116 
117  $hierarchy->_params['options'] = $options;
118  }
119  $hierarchy->paint($prefix, FALSE);
120  } else {
121  // drill-down view
122  $level_titles = $asset->attr('level_titles');
123  $hierarchy_options = $this->_sortHierarchyOptions($hierarchy_options, 1, FALSE);
124  if (!is_array($value)) {
125  $value = explode('; ', $value);
126  }
127 
128  // work out whether our fields are disabled or not based on whether we are currently showing the 'use default' checkbox
129  if (!$enable_default) {
130  $show_default_box = FALSE;
131  } else {
132  if ($is_default) {
133  $show_default_box = TRUE;
134  } else {
135  $show_default_box = FALSE;
136  }
137  }
138  $this->paintDrillDownView($hierarchy_options, $value, $level_titles, $show_default_box, explode('; ', $asset->attr('default')), $prefix);
139  }
140  } else {
141  if (!((is_array($value) && empty($value)) || (is_string($value) && $value == ''))) {
142  if (!is_array($value)) $value = Array($value);
143  $value_output = '';
144  foreach ($value as $option) {
145  if (isset($hierarchy_options[$option])) {
146  $value_output .= $hierarchy_options[$option].'; ';
147  }
148  }
149  echo trim($value_output, '; ');
150  }
151  }
152 
153  if ($enable_default) {
154 
155  echo '</span>';
156 
157  if ($write_access) {
158  echo ' &nbsp; &nbsp; &nbsp; ';
159 
160  // Work out which options we have to set if we have to
161  $i = 0;
162  $default_keys = explode('; ', $asset->attr('default'));
163  $default_selected = Array();
164 
165  $default_key_values = Array();
166  $default_values = Array();
167  $non_default_keys = Array();
168  foreach ($hierarchy_options as $key => $hierarchy_option) {
169  if (in_array($key, $default_keys)) {
170  $default_key_values[] = "'".addslashes($key)."'";
171  $default_values[] = "'".addslashes($hierarchy_option)."'";
172  } else {
173  $non_default_keys[] = "'".addslashes($key)."'";
174  }
175  }
176  $default_keys_expr = '['.implode(', ', $default_key_values).']';
177  $default_values_expr = '['.implode(', ', $default_values).']';
178  $non_default_keys_expr = '['.implode(', ', $non_default_keys).']';
179  check_box($prefix.'_default', '1', $is_default, "handleDefaultClickHierarchy(this, '$prefix', $default_keys_expr, $default_values_expr, $non_default_keys_expr, $display_type); ");
180  label(translate('use_default'), $prefix.'_default');
181  $o->addJsInclude(sq_web_path('data').'/asset_types/metadata_field_hierarchy/js/metadata_field_hierarchy.js');
182  } else {
183  if ($is_default) {
184  echo ' <em style="color: #666">('.strtolower(translate('default')).')</em>';
185  }
186  }
187  }
188 
189  if ($write_access && $print_cascade_values_option) {
190  echo '&nbsp;&nbsp;&nbsp;&nbsp;';
191  check_box($prefix.'_cascade_value', '1', FALSE);
192  label(translate('cascade_value'), $prefix.'_cascade_value');
193  }
194 
195  return $write_access;
196 
197  }//end paintValueInterface()
198 
199 
211  public function processInlineValueInterface(Metadata_Field_Hierarchy $asset, &$new_value_str, &$field_cascade_value)
212  {
213  if (!$asset->attr('editable')) return FALSE; // nothing for us to do
214 
215  $processed = FALSE;
216 
217  $prefix = $asset->getPrefix();
218  if (!empty($_POST[$prefix.'_default'])) {
219  // use default
220  $new_value_str = NULL;
221  $processed = TRUE;
222  } else {
223  // Default is not checked, so process our hierarchy attribute
224  $hierarchy = $asset->getHierarchyAttribute();
225 
226  $value = (isset($_REQUEST[$prefix])) ? $_REQUEST[$prefix] : '';
227  if (is_array($value)) $value = implode('; ', $value);
228  $value = Metadata_Field::encodeValueString(trim($value), Array());
229  $hoptions = $hierarchy->_params['options'];
230 
231  $hierarchy->value = $value;
232 
233  $new_value_str = $value;
234  $processed = TRUE;
235 
236  }//end if
237 
238  if (isset($_POST[$prefix.'_cascade_value'])) {
239  $field_cascade_value = TRUE;
240  $processed = TRUE;
241  }
242 
243  return $processed;
244 
245  }//end processInlineValueInterface()
246 
247 
258  public function paintHierarchy(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
259  {
260  $write_access = $asset->writeAccess('attributes');
261  $hierarchy_options = $asset->getContextedHierarchyOptions();
262  $hierarchy_sort = $asset->attr('hier_sort');
263 
264  $is_contextable = (boolean)$asset->attr('is_contextable');
265 
266  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
267  $is_default_context = ($contextid === 0) ? TRUE : FALSE;
268 
269  if ($is_contextable === TRUE) {
270  $hierarchy_options = $asset->getContextedHierarchyOptions();
271  } else {
272  $hierarchy_options = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('hierarchy_options', 'metadata_field_hierarchy', Array($asset->id), 0);
273  $hierarchy_options = unserialize($hierarchy_options[$asset->id]);
274  }
275 
276  if (!empty($hierarchy_options)) {
277  ?>
278  <table class="sq-backend-table">
279  <tr>
280  <td class="sq-backend-table-header"><?php echo translate('option_key'); ?></td>
281  <td class="sq-backend-table-header"><?php echo translate('option_value'); ?></td>
282  <?php
283  if (($write_access === TRUE) && ($is_default_context === TRUE)) {
284  ?><td class="sq-backend-table-header"><?php echo translate('delete_question'); ?></td><?php
285  }
286  ?>
287  </tr>
288  <?php
289  $i = 0;
290  foreach ($hierarchy_options as $option_key => $option_value) {
291  ?>
292  <tr>
293  <td class="sq-backend-table-cell">
294  <?php
295  if ($write_access === TRUE) {
296  if (($is_default_context === TRUE) || ($is_contextable === FALSE)) {
297  text_box($prefix.'_options[key]['.$i.']', $option_key, 20);
298  } else {
299  echo $option_key;
300  hidden_field($prefix.'_options[key]['.$i.']', $option_key);
301  }
302  } else {
303  echo $option_key;
304  }
305  ?>
306  </td>
307  <td class="sq-backend-table-cell" align="left">
308  <?php
309  if ($write_access) {
310  text_box($prefix.'_options[val]['.$i.']', $option_value, 20);
311  } else {
312  echo $option_value;
313  }
314  ?>
315  </td>
316  <?php
317  if (($write_access === TRUE) && (($is_default_context === TRUE) || ($is_contextable === FALSE))) {
318  ?>
319  <td class="sq-backend-table-cell">
320  <?php check_box($prefix.'_options[del]['.$i.']', $option_key); ?>
321  </td>
322  <?php
323  }
324  ?>
325  </tr>
326  <?php
327  $i++;
328  }//end foreach
329  ?>
330  </table>
331  <?php
332 
333  } else {
334  echo translate('no_hierarchy_box_options');
335  }//end if empty
336 
337  // now adding two fields for new entry (key => value)
338  if (($write_access === TRUE) && (($is_default_context === TRUE) || ($is_contextable === FALSE))) {
339  $o->openField(translate('new_option'));
340  echo '<b>'.translate('key').'</b> ';
341  text_box($prefix.'_new_key','');
342  echo ' <b>'.translate('value').'</b> ';
343  text_box($prefix.'_new_val','');
344  $o->closeField();
345  }
346 
347  // Some values we need
348  $sort = $asset->attr('hier_sort');
349  $format = $asset->attr('hier_structure');
350 
351  if (!empty($hierarchy_options)) {
352  // displaying default value if any values were actually saved in the array
353  $o->openField(translate('default_value'));
354  $default_hier = $asset->getHierarchyAttribute();
355  $default_hier->paint($prefix.'_default', !$write_access);
356  $o->closeField();
357  }
358 
359  // Being user friendly show a quick preview of what it looks like
360  $o->openField(translate('preview'));
361  if (!empty($hierarchy_options)) {
362 
363  $display_type = $asset->attr('display_type');
364  if (!$display_type) {
365 
366  // perform any sorting and indentation
367  if ($sort > 0) {
368  $preview_options = $this->_sortHierarchyOptions($hierarchy_options, $sort, $format);
369  if (isset($preview_options) && !is_null($preview_options)) {
370  foreach ($preview_options as $key => $value) {
371  $preview_options[$key] = substr($value, 0, 100);
372  }
373  }
374  } else {
375  $preview_options = $hierarchy_options;
376  }
377 
378  // Only preview don't show full length
379  if (isset($preview_options) && !is_null($preview_options)) {
380  foreach ($preview_options as $key => $value) {
381  $preview_options[$key] = substr($value, 0, 100);
382  }
383  }
384 
385  // flat view
386  $preview_hierarchy = $asset->getHierarchyAttribute();
387  $preview_hierarchy->_params['options'] = $preview_options;
388  $preview_hierarchy->value = '';
389  $preview_hierarchy->paint('some_name_not_used', FALSE);
390  } else {
391  $preview_options = $this->_sortHierarchyOptions($hierarchy_options, 1, FALSE);
392  $level_titles = $asset->attr('level_titles');
393  $this->paintDrillDownView($preview_options, Array(), $level_titles, FALSE, Array(), $prefix);
394  }
395  } else {
396  echo translate('no_hierarchy_box_options');
397  }//end if
398  $o->closeField();
399 
400  return TRUE;
401 
402  }//end paintHierarchy()
403 
404 
418  public function paintDrillDownView($options, $receptacle_keys, $level_titles, $is_default, $default_keys, $prefix)
419  {
420  echo '<table width="100px">';
421 
422  $levels = Array();
423  $receptacle_options = Array();
424  foreach ($options as $key => $value) {
425  // hierarchy may not be linear so calculate how many select boxes we will need this way
426  if (!in_array(strlen($key), $levels)) {
427  $levels[] = strlen($key);
428  }
429 
430  // get formatted receptacle contents
431  if ($is_default) {
432  // default values
433  if (in_array($key, $default_keys)) {
434  $receptacle_options[$key] = $key.'. '.$value;
435  }
436  } else {
437  foreach ($receptacle_keys as $receptacle_key) {
438  if ($receptacle_key === $key) {
439  $receptacle_options[$key] = $key.'. '.$value;
440  }
441  }
442  }
443  }
444 
445  $the_options = Array();
446  $count_levels = count($levels);
447  $field_name = '';
448  $receptacle_field_name = $prefix;
449  for ($i=0; $i<$count_levels; $i++) {
450  $title = isset($level_titles[$levels[$i]]) ? $level_titles[$levels[$i]] : '';
451  echo '<tr><td>';
452  echo empty($title) ? '' : $title;
453  echo '</td><td>';
454 
455  foreach ($options as $key => $value) {
456  $field_name = $prefix.'_stationary_drill_'.$i;
457 
458  // print each level's combo boxes and filter at the same time
459  if (strlen($key) === $levels[$i]) {
460  // first level is easy
461  if ($i === 0) {
462  $the_options[$key] = $value;
463  } else {
464  // fetch the children for the previous list
465  // the currently selected value is the first in the array
466  $keys = array_keys($the_options);
467 
468  // used for the initial painting of the drill-down
469  if (isset($keys[0])) {
470  $the_options = $this->_getImmediateChildren($options, $keys[0]);
471  } else {
472  // hierarchy may not be linear so deal with it
473  // look for the next level if this is the case
474  foreach ($options as $search_key => $search_value) {
475  // the options must be sorted for this to work
476  if (strlen($search_key) === $levels[$i-1]) {
477  $found_key = $search_key;
478  break;
479  }
480  }
481 
482  $the_options = $this->_getImmediateChildren($options, $found_key);
483  }
484 
485  break;
486  }
487 
488  }
489  }
490 
491  // deepest level box allows multiple selections
492  // also give the deepest level box a maximum height
493  $extras = $is_default ? 'disabled="disabled"; onChange="swapOptions_for_'.$prefix.'(this)";' : 'onChange="swapOptions_for_'.$prefix.'(this)";';
494  echo combo_box($field_name, $the_options, ($i === $count_levels-1) ? TRUE : FALSE, '', ($i === $count_levels-1) ? 5 : '', $extras);
495 
496  // print the 'add' button
497  // $field_name contains the name of the last box
498  $add_on_click = 'addToReceptacle_for_'.$prefix.'(\''.$field_name.'\')';
499  // new column for 'add' buttons
500  echo '</td><td valign="top">';
501  echo normal_button($prefix.'_drill_down_button', translate('add'), $add_on_click);
502 
503  echo '</td></tr>';
504  }
505 
506  // print the receptacle box
507  echo '<tr><td></td><td>';
508  $extras = $is_default ? 'disabled="disabled"; style="width:300px";' : 'style="width:300px";';
509  echo combo_box($receptacle_field_name, $receptacle_options, TRUE, '', 5, $extras);
510 
511  // print the remove buttons
512  echo '<br />';
513  $remove_on_click = 'removeFromReceptacle_for_'.$prefix.'()';
514  echo normal_button($prefix.'_drill_down_button', translate('remove'), $remove_on_click);
515  $remove_all_on_click = 'removeAllFromReceptacle_for_'.$prefix.'()';
516  echo normal_button($prefix.'_drill_down_button', translate('remove_all'), $remove_all_on_click);
517 
518  // close the receptacle row
519  echo '</td></tr>';
520  echo '</table>';
521 
522  echo $this->_printJSObjects($options, $prefix);
523 
524  ?>
525  <script type="text/javascript">
526  var prefix_for_<?php echo $prefix ?> = '<?php echo $prefix; ?>';
527  // select all options in the receptacle box otherwise on commit we will lose our values
528  var receptacleName_for_<?php echo $prefix ?> = '<?php echo $receptacle_field_name; ?>';
529  var receptacle_for_<?php echo $prefix ?> = document.getElementById(receptacleName_for_<?php echo $prefix ?>);
530  selectAllReceptacleItems_for_<?php echo $prefix ?>(receptacle_for_<?php echo $prefix ?>);
531 
532  function swapOptions_for_<?php echo $prefix ?>(select)
533  {
534  // the values to replace with
535  var replaceWith = data_for_<?php echo $prefix ?>[select.value];
536 
537  // get the next box which is the box we will populate
538  var stationaryDrillNum = select.name.match(/.+_stationary_drill_(.+)/);
539  stationaryDrillNum = parseInt(stationaryDrillNum[1]) + 1;
540  var nextBoxName = prefix_for_<?php echo $prefix ?> + '_stationary_drill_' + stationaryDrillNum;
541  var nextBox = document.getElementById(nextBoxName);
542 
543  // does it exist or are we at the end of the line?
544  if (!isset(nextBox)) {
545  return;
546  }
547 
548  // truncate entries from the next box
549  nextBox.options.length = 0;
550 
551  // populate the next box with the correct entries
552  var i = 0;
553  for (key in replaceWith) {
554  nextBox.options[i] = new Option(replaceWith[key], key);
555  i++;
556  }
557 
558  // recurse until there are no more boxes to populate
559  if (nextBox) {
560  swapOptions_for_<?php echo $prefix ?>(nextBox);
561  }
562 
563  }
564 
565  function addToReceptacle_for_<?php echo $prefix ?>(selectName_for_<?php echo $prefix ?>)
566  {
567  // get the box which holds the values we want to add
568  var select = document.getElementById(selectName_for_<?php echo $prefix ?>);
569 
570  var options = select.options;
571  for (var i=0; i<options.length; i++) {
572  if (options[i].selected) {
573 
574  // we have the selected options, now add them to the receptacle if not currently present
575  var found = false;
576  for (var j=0; j<receptacle_for_<?php echo $prefix ?>.options.length; j++) {
577  if (receptacle_for_<?php echo $prefix ?>.options[j].value == options[i].value) {
578  found = true;
579  }
580  }
581 
582  if (!found) {
583  // didn't find it, so append it to the receptacle
584  receptacle_for_<?php echo $prefix ?>.options[receptacle_for_<?php echo $prefix ?>.options.length] = new Option(options[i].value + '. ' + options[i].text, options[i].value);
585  }
586  }
587  }
588 
589  selectAllReceptacleItems_for_<?php echo $prefix ?>(receptacle_for_<?php echo $prefix ?>);
590  }
591 
592  function removeFromReceptacle_for_<?php echo $prefix ?>()
593  {
594  // remove all selected items from the receptacle
595  var receptacle_for_<?php echo $prefix ?> = document.getElementById(receptacleName_for_<?php echo $prefix ?>);
596  var options = receptacle_for_<?php echo $prefix ?>.options;
597  for (var i=0; i<options.length; i++) {
598  if (options[i].selected) {
599  receptacle_for_<?php echo $prefix ?>.remove(i);
600  }
601  }
602 
603  selectAllReceptacleItems_for_<?php echo $prefix ?>(receptacle_for_<?php echo $prefix ?>);
604  }
605 
606  function removeAllFromReceptacle_for_<?php echo $prefix ?>()
607  {
608  // remove all items from the receptacle
609  var receptacle_for_<?php echo $prefix ?> = document.getElementById(receptacleName_for_<?php echo $prefix ?>);
610  receptacle_for_<?php echo $prefix ?>.options.length = 0;
611  }
612 
613  function isset(v)
614  {
615  if (typeof v !== 'undefined' && v !== null) {
616  return true;
617  }
618 
619  return false;
620  }
621 
622  function selectAllReceptacleItems_for_<?php echo $prefix ?>(receptacle_for_<?php echo $prefix ?>)
623  {
624  var options = receptacle_for_<?php echo $prefix ?>.options;
625  for (var i=0; i<options.length; i++) {
626  if (!options[i].selected) {
627  options[i].selected = true;
628  }
629  }
630  }
631 
632  </script>
633 
634  <?php
635 
636  }//end paintDrillDownView()
637 
638 
648  function _printJSObjects($options, $prefix)
649  {
650  echo '<script type="text/javascript">';
651  echo 'var data_for_'.$prefix.' = {};';
652  foreach ($options as $key => $value) {
653  $children = $this->_getImmediateChildren($options, $key);
654 
655  if (!empty($children)) {
656  echo 'var options_for_'.$prefix.' = {};';
657  // create a JS object holding the values of the children
658  foreach ($children as $child_key => $child_value) {
659  echo 'options_for_'.$prefix.'[\''.$child_key.'\'] = \''.$child_value.'\';';
660  }
661  ?>
662  data_for_<?php echo $prefix ?>.<?php echo $key; ?> = options_for_<?php echo $prefix ?>;
663  <?php
664  }
665  }
666  echo '</script>';
667 
668  }//end _printJSObjects()
669 
670 
681  function _getImmediateChildren($options, $parent_string, $target_length=NULL)
682  {
683  if (is_null($target_length)) {
684  // a child is by definition, 1 char longer
685  $target_length = strlen($parent_string) + 1;
686  }
687 
688  $children = Array();
689  foreach ($options as $key => $value) {
690  // ensure we are getting children of this value
691  if ((strlen($key) === $target_length) && (strpos($key, $parent_string) === 0)) {
692  $children[$key] = $value;
693  }
694  }
695 
696  if (empty($children)) {
697  // look for a deeper level because the hierarchy may not be linear
698  $levels = Array();
699  foreach ($options as $key => $value) {
700  if (strlen($key) > $target_length) {
701  if (!in_array(strlen($key), $levels)) {
702  $levels[] = strlen($key);
703  }
704  }
705  }
706 
707  // sort so we are sure the first index is the next level
708  sort($levels);
709  if (isset($levels[0])) {
710  $target_length = $levels[0];
711  // do our search again
712  foreach ($options as $key => $value) {
713  // ensure we are getting children of this value
714  if ((strlen($key) === $target_length) && (strpos($key, $parent_string) === 0)) {
715  $children[$key] = $value;
716  }
717  }
718  }
719  }
720 
721  return $children;
722 
723  }//end _getImmediateChildren()
724 
725 
736  public function processHierarchy(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
737  {
738  // need to have write access to make any changes
739  if (!$asset->writeAccess('attributes')) return FALSE;
740  $is_contextable = (boolean)$asset->attr('is_contextable');
741 
742  if ($is_contextable === FALSE) {
743  // If we are not contextable, we might as well be in the default
744  // context... so change to it, and reload our asset
745  $GLOBALS['SQ_SYSTEM']->changeContext(0);
746  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($asset->id);
747  }
748 
749  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
750 
751  $hierarchy_options = Array();
752  if (isset($_POST[$prefix.'_options'])) {
753  $option_changes = $_POST[$prefix.'_options'];
754  foreach ($option_changes['key'] as $i => $key) {
755  if (isset($option_changes['del'][$i])) continue;
756  $hierarchy_options[trim($key)] = trim($option_changes['val'][$i]);
757  }
758  }
759 
760  // now get the new submitted values (if any) and add them to array
761  if (array_key_exists($prefix.'_new_key', $_POST) === TRUE) {
762  if (strlen(trim($_POST[$prefix.'_new_key']))>0 && strlen(trim($_POST[$prefix.'_new_val']))>0) {
763  $new_hierarchy_key = trim($_POST[$prefix.'_new_key']);
764  $new_hierarchy_val = trim($_POST[$prefix.'_new_val']);
765  $hierarchy_options[$new_hierarchy_key] = $new_hierarchy_val;
766  }
767  }
768 
769  // updating asset attribute value
770  $asset->setAttrValue('hierarchy_options', $hierarchy_options);
771 
772  // saving default value
773  $new_default = '';
774  if (!empty($hierarchy_options) && isset($_POST[$prefix.'_default'])) {
775  $new_default = $_POST[$prefix.'_default'];
776  if (is_array($new_default)) {
777  $new_default = implode('; ', $new_default);
778  }
779  }
780  $asset->setAttrValue('default', $new_default);
781  if ($asset->saveAttributes() === TRUE) {
782  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
783  } else {
784  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
785  }
786 
787  if ($is_contextable === FALSE) {
788  // If we are not contextable, we might as well be in the default
789  // context... so change to it, and reload our asset
790  $GLOBALS['SQ_SYSTEM']->restoreContext();
791  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($asset->id);
792  }
793 
794  // Don't require our own saving of attributes
795  return FALSE;
796 
797  }//end processHierarchy()
798 
799 
810  public function paintEditParams(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
811  {
812  $hierarchy = $asset->getHierarchyAttribute();
813  $hierarchy->paintEditParams($prefix.'_style', $asset->writeAccess('attributes'));
814 
815  }//end paintEditParams()
816 
817 
828  public function processEditParams(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
829  {
830  if (!$asset->writeAccess('attributes')) return FALSE;
831 
832  $hierarchy = $asset->getHierarchyAttribute();
833  $edit_params = $hierarchy->processEditParams($prefix.'_style');
834  return $asset->setAttrValue('edit_params', $edit_params);
835 
836  }//end processEditParams()
837 
838 
851  public function generateMetadata(Metadata_Field_Hierarchy $asset, $value_str, &$tag_value, Array &$keywords)
852  {
853  if (is_null($value_str)) {
854  $value_str = Metadata_Field::encodeValueString($asset->attr('default'), Array());
855  }
856 
857  // If we are showing the value, then go fetch it
858  if ($asset->attr('visible_part') === 'value') {
859  $value_str = $asset->getValueFromKey($value_str);
860  }
861 
862  return parent::generateMetadata($asset, $value_str, $tag_value, $keywords);
863 
864  }//end generateMetadata()
865 
866 
878  public function _sortHierarchyOptions($hierarchy, $sort_by=0, $show_parents=FALSE, $pad='-')
879  {
880  if (!is_array($hierarchy)) return NULL;
881  if (empty($hierarchy)) return $hierarchy;
882 
883  switch ($sort_by) {
884  case 1:
885  // Using usort to get a more structured list
886  $sort_by_key = array_keys($hierarchy);
887  $aok = usort($sort_by_key, 'strcmp');
888  $sort_hier = Array();
889  foreach ($sort_by_key as $key) {
890  $sort_hier[$key] = $hierarchy[$key];
891  }
892 
893  // Reset hierarchy and reset it to $sort_hier
894  $hierarchy = Array();
895  $hierarchy = $sort_hier;
896  break;
897  case 2:
898  // Sort by value
899  $aok = asort($hierarchy);
900  break;
901  }
902 
903  if ($show_parents) {
904  foreach ($hierarchy as $key => $value) {
905  $show_lvl = str_pad('', (strlen($key)-1), $pad);
906  $hierarchy[$key] = $show_lvl.$value;
907  }
908  }//end if
909 
910  return $hierarchy;
911 
912  }//end _sortHierarchyOptions()
913 
914 
925  public function getHierarchyTree($start_value, $options, $pad='; ')
926  {
927  $return_value = $start_value;
928  $start_value = strtolower($start_value);
929  $get_values = explode($pad, $start_value);
930  if (is_array($get_values)) {
931  $new_values = Array();
932  foreach ($get_values as $value) {
933  // Get the parents and add them
934  $get_parents = $this->getParentHierarchy($value, $options);
935  if (is_array($get_parents) && !is_null($get_parents)) {
936  foreach ($get_parents as $parent) {
937  if (!in_array($parent, $get_values)) {
938  $new_values[] = $parent;
939  }
940  }
941  }
942  // Get the children and add them
943  $get_childs = $this->getChildrenHierarchy($value, $options);
944  if (is_array($get_childs) && !is_null($get_childs)) {
945  foreach ($get_childs as $child) {
946  if (!in_array($child, $get_values)) {
947  $new_values[] = $child;
948  }
949  }
950  }
951  }
952  // Add the old values to the end
953  foreach ($get_values as $value) {
954  $new_values[] = $value;
955  }
956 
957  // Sort them out
958  natsort($new_values);
959 
960  // Remove duplicate entries
961  $new_values = array_unique($new_values);
962 
963  // Prep the value to return
964  $return_value = implode($pad, $new_values);
965  }//end if
966 
967  return $return_value;
968 
969  }//end getHierarchyTree()
970 
971 
981  public function getParentHierarchy($value, $options=NULL)
982  {
983  $return_val = NULL;
984 
985  if (!empty($value)) {
986  if (is_null($options) || !is_array($options)) {
987  return $return_val;
988  }
989 
990  // This is the parent or no depth was specified
991  if (strlen($value) == 1) return $return_val;
992 
993  for ($i=0; $i<strlen($value); $i++) {
994  $parent = '';
995  $parent = substr($value, 0, $i);
996  if (array_key_exists(strtolower($parent), array_change_key_case($options, CASE_LOWER))) {
997  $return_val[] = $parent;
998  }
999  }
1000 
1001  }
1002 
1003  return $return_val;
1004 
1005  }//end getParentHierarchy()
1006 
1007 
1017  public function getChildrenHierarchy($value, $options=NULL)
1018  {
1019  $return_val = NULL;
1020 
1021  if (!empty($value)) {
1022  if (is_null($options) || !is_array($options)) {
1023  return $return_val;
1024  }
1025 
1026  foreach ($options as $opt_key => $opt_value) {
1027  if (preg_match('/^'.strtolower($value).'/i', strtolower($opt_key))) {
1028  $return_val[] = strtolower($opt_key);
1029  }
1030  }
1031  }
1032 
1033  return $return_val;
1034 
1035  }//end getChildrenHierarchy()
1036 
1037 
1046  function isFlatView(&$asset)
1047  {
1048  $attr = $asset->attr('display_type');
1049  return empty($attr) ? TRUE : FALSE;
1050 
1051  }//end isFlatView()
1052 
1053 
1062  function isDrillDownView(&$asset)
1063  {
1064  $attr = $asset->attr('display_type');
1065  return empty($attr) ? FALSE : TRUE;
1066 
1067  }//end isDrillDownView()
1068 
1069 
1080  public function paintLevelTitles(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
1081  {
1082  $wa = $asset->writeAccess('attributes');
1083  $hierarchy = $asset->getHierarchyAttribute();
1084  $hierarchy_options = $hierarchy->_params['options'];
1085  unset($hierarchy);
1086  $level_titles = $asset->attr('level_titles');
1087 
1088  $levels = Array();
1089  foreach ($hierarchy_options as $key => $value) {
1090  // hierarchy may not be linear so calculate how many select boxes we will need this way
1091  if (!in_array(strlen($key), $levels)) {
1092  $levels[] = strlen($key);
1093  }
1094  }
1095 
1096  echo '<table>';
1097  $i = 1;
1098  foreach ($levels as $id) {
1099  echo '<tr>';
1100  echo '<td>'.translate('level').' '.$i.':</td><td>';
1101  if ($wa) {
1102  echo text_box($prefix.'_level_titles['.$id.']', isset($level_titles[$id]) ? htmlspecialchars_decode($level_titles[$id]) : '').'</td>';
1103  } else {
1104  echo isset($level_titles[$id]) ? $level_titles[$id] : '';
1105  }
1106  echo '</tr>';
1107  $i++;
1108  }
1109  echo '</table>';
1110 
1111  return $wa;
1112 
1113  }//end paintLevelTitles()
1114 
1115 
1126  public function processLevelTitles(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
1127  {
1128  $wa = $asset->writeAccess('attributes');
1129  if ($wa) {
1130  if (isset($_POST[$prefix.'_level_titles'])) {
1131  foreach ($_POST[$prefix.'_level_titles'] as $key => $value) {
1132  $_POST[$prefix.'_level_titles'][$key] = htmlspecialchars($value);
1133  }
1134  $asset->setAttrValue('level_titles', $_POST[$prefix.'_level_titles']);
1135  }
1136  }
1137 
1138  return $wa;
1139 
1140  }//end processLevelTitles()
1141 
1142 
1153  public function paintDisplayType(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
1154  {
1155  $wa = $asset->writeAccess('attributes');
1156  $display_type = $asset->attr('display_type');
1157  $options = Array(
1158  '0' => 'Flat View',
1159  '1' => 'Drill-Down View',
1160  );
1161  if ($wa) {
1162  echo combo_box($prefix.'_display_type', $options, FALSE, $display_type);
1163  } else {
1164  echo $options[$display_type];
1165  }
1166 
1167  return $wa;
1168 
1169  }//end paintDisplayType()
1170 
1171 
1182  public function processDisplayType(Metadata_Field_Hierarchy $asset, Backend_Outputter $o, $prefix)
1183  {
1184  $wa = $asset->writeAccess('attributes');
1185  if ($wa) {
1186  if (isset($_POST[$prefix.'_display_type'])) {
1187  $asset->setAttrValue('display_type', $_POST[$prefix.'_display_type']);
1188  if ($_POST[$prefix.'_display_type'] == '1') $asset->setAttrValue('multiple', TRUE);
1189  $asset->saveAttributes();
1190  }
1191  }
1192 
1193  return $wa;
1194 
1195  }//end processDisplayType()
1196 
1197 
1198 }//end class
1199 
1200 ?>