'$Action' ); public static $allowed_actions = array ( 'tree' ); /** * @ignore */ protected $sourceObject, $keyField, $labelField, $filterCallback, $searchCallback, $baseID = 0; /** * Used by field search to leave only the relevant entries */ protected $searchIds = null, $searchExpanded = array(); /** * CAVEAT: for search to work properly $labelField must be a database field, or you need to setSearchFunction. * * @param string $name the field name * @param string $title the field label * @param string $souceClass the class to display in the tree, must have the "Hierachy" extension. * @param string $keyField to field on the source class to save as the field value (default ID). * @param string $labelField the field name to show as the human-readable value on the tree (default Title). * @param string $showSearch enable the ability to search the tree by entering the text in the input field. */ public function __construct($name, $title = null, $sourceObject = 'Group', $keyField = 'ID', $labelField = 'Title', $showSearch = false) { $this->sourceObject = $sourceObject; $this->keyField = $keyField; $this->labelField = $labelField; $this->showSearch = $showSearch; if(!Object::has_extension($this->sourceObject, 'Hierarchy')) { throw new Exception ( "TreeDropdownField: the source class '$this->sourceObject' must have the Hierarchy extension applied" ); } parent::__construct($name, $title); } /** * Set the ID of the root node of the tree. This defaults to 0 - i.e. displays the whole tree. * * @param int $ID */ public function setTreeBaseID($ID) { $this->baseID = (int) $ID; } /** * Set a callback used to filter the values of the tree before displaying to the user. * * @param callback $callback */ public function setFilterFunction($callback) { if(!is_callable($callback, true)) { throw new InvalidArgumentException('TreeDropdownField->setFilterCallback(): not passed a valid callback'); } $this->filterCallback = $callback; } /** * Set a callback used to search the hierarchy globally, even before applying the filter. * * @param callback $callback */ public function setSearchFunction($callback) { if(!is_callable($callback, true)) { throw new InvalidArgumentException('TreeDropdownField->setSearchFunction(): not passed a valid callback'); } $this->searchCallback = $callback; } /** * @return string */ public function Field() { Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js'); Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js'); Requirements::javascript(SAPPHIRE_DIR . '/javascript/tree/tree.js'); Requirements::javascript(SAPPHIRE_DIR . '/javascript/TreeSelectorField.js'); Requirements::css(SAPPHIRE_DIR . '/javascript/tree/tree.css'); Requirements::css(SAPPHIRE_DIR . '/css/TreeDropdownField.css'); if($this->Value() && $record = $this->objectForKey($this->Value())) { $title = $record->{$this->labelField}; } else { $title = _t('DropdownField.CHOOSE', '(Choose)', PR_MEDIUM, 'start value of a dropdown'); } return $this->createTag ( 'div', array ( 'id' => "TreeDropdownField_{$this->id()}", 'class' => 'TreeDropdownField single' . ($this->extraClass() ? " {$this->extraClass()}" : '') ), $this->createTag ( 'input', array ( 'id' => $this->id(), 'type' => 'hidden', 'name' => $this->name, 'value' => $this->value ) ) . ($this->showSearch ? $this->createTag( 'input', array( 'class' => 'items', 'value' => '(Choose or type search)' ) ) : $this->createTag ( 'span', array ( 'class' => 'items' ), $title ) ) . $this->createTag ( 'a', array ( 'href' => '#', 'title' => 'open', 'class' => 'editLink' ), ' ' ) ); } /** * Get the whole tree of a part of the tree via an AJAX request. * * @param SS_HTTPRequest $request * @return string */ public function tree(SS_HTTPRequest $request) { $isSubTree = false; $this->search = Convert::Raw2SQL($request->getVar('search')); if($ID = (int) $request->latestparam('ID')) { $obj = DataObject::get_by_id($this->sourceObject, $ID); $isSubTree = true; if(!$obj) { throw new Exception ( "TreeDropdownField->tree(): the object #$ID of type $this->sourceObject could not be found" ); } } else { if($this->baseID) { $obj = DataObject::get_by_id($this->sourceObject, $this->baseID); } if(!$this->baseID || !$obj) $obj = singleton($this->sourceObject); } // pre-process the tree - search needs to operate globally, not locally as marking filter does if ( $this->search != "" ) $this->populateIDs(); if ($this->filterCallback || $this->sourceObject == 'Folder' || $this->search != "" ) $obj->setMarkingFilterFunction(array($this, "filterMarking")); $obj->markPartialTree(); if($forceValues = $this->value) { if(($values = preg_split('/,\s*/', $forceValues)) && count($values)) foreach($values as $value) { $obj->markToExpose($this->objectForKey($value)); } } $eval = '"