diff --git a/forms/TreeDropdownField.php b/forms/TreeDropdownField.php index 3dcff4899..7baa0bd9e 100755 --- a/forms/TreeDropdownField.php +++ b/forms/TreeDropdownField.php @@ -1,148 +1,181 @@ '$Action' + ); + + public static $allowed_actions = array ( + 'tree' + ); /** - * Create a new tree dropdown field. - * @param name The name of the field. - * @param title The label of the field. - * @param sourceObject The object-type to list in the tree. Must be a 'hierachy' object. - * @param keyField The column of that object-type to return as the field value. Defaults to ID - * @param labelField The column to show as the human-readable value in the tree. Defaults to Title + * @ignore */ - function __construct($name, $title, $sourceObject = "Group", $keyField = "ID", $labelField = "Title") { + protected $sourceObject, $keyField, $labelField, $filterCallback, $baseID = 0; + + /** + * @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). + */ + public function __construct($name, $title = null, $sourceObject = 'Group', $keyField = 'ID', $labelField = 'Title') { $this->sourceObject = $sourceObject; - $this->keyField = $keyField; - $this->labelField = $labelField; + $this->keyField = $keyField; + $this->labelField = $labelField; + + if(!Object::has_extension($this->sourceObject, 'Hierarchy')) { + throw new Exception ( + "TreeDropdownField: the source class '$this->sourceObject' must have the Hierarchy extension applied" + ); + } + + Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); + + Requirements::javascript(THIRDPARTY_DIR . '/behaviour.js'); + Requirements::javascript(THIRDPARTY_DIR . '/tree/tree.js'); + Requirements::javascript(SAPPHIRE_DIR . '/javascript/TreeSelectorField.js'); + + Requirements::css(THIRDPARTY_DIR . '/tree/tree.css'); + Requirements::css(SAPPHIRE_DIR . '/css/TreeDropdownField.css'); + parent::__construct($name, $title); } - function setFilterFunction($filterFunc) { - $this->filterFunc = $filterFunc; - } /** - * Set the root node of the tree. Defaults to 0, ie, the whole tree + * Set the ID of the root node of the tree. This defaults to 0 - i.e. displays the whole tree. + * + * @param int $ID */ - function setTreeBaseID($treeBaseID) { - $this->treeBaseID = $treeBaseID; + public function setTreeBaseID($ID) { + $this->baseID = (int) $ID; } - function Field() { - Requirements::css(SAPPHIRE_DIR . '/css/TreeDropdownField.css'); - Requirements::javascript(THIRDPARTY_DIR . "/tree/tree.js"); - Requirements::css(THIRDPARTY_DIR . "/tree/tree.css"); - Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); - Requirements::javascript(SAPPHIRE_DIR . "/javascript/TreeSelectorField.js"); + /** + * 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'); + } - if($this->value) { - $record = $this->getByKey($this->value); - $title = ($record) ? $record->Title : _t('DropdownField.CHOOSE', "(Choose)", PR_MEDIUM, 'Start-value of a dropdown'); + $this->filterCallback = $callback; + } + + /** + * @return string + */ + public function Field() { + 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'); + $title = _t('DropdownField.CHOOSE', '(Choose)', PR_MEDIUM, 'start value of a dropdown'); } - $id = $this->id(); - - $classes = "TreeDropdownField single"; - if($this->extraClass()) $classes .= ' ' . $this->extraClass(); - - return <<$title -HTML; + 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->createTag ( + 'span', + array ( + 'class' => 'items' + ), + $title + ) . $this->createTag ( + 'a', + array ( + 'href' => '#', + 'title' => 'open', + 'class' => 'editLink' + ), + ' ' + ) + ); } - - /** - * Return the site tree + * Get the whole tree of a part of the tree via an AJAX request. + * + * @param HTTPRequest $request + * @return string */ - function gettree() { - if($this->treeBaseID) $obj = DataObject::get_by_id($this->sourceObject, $this->treeBaseID); - else $obj = singleton($this->sourceObject); + public function tree(HTTPRequest $request) { + $isSubTree = false; - if($this->filterFunc) $obj->setMarkingFilterFunction($this->filterFunc); - else if($this->sourceObject == 'Folder') $obj->setMarkingFilter('ClassName', 'Folder'); - $obj->markPartialTree(); - - // If we've already got values selected, make sure that we've got them in our tree - if($_REQUEST['forceValues']) { - $forceValues = preg_split("/ *, */", trim($_REQUEST['forceValues'])); - foreach($forceValues as $value) { - $obj->markToExpose($this->getByKey($value)); - } + if($ID = (int) $request->param('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); + } + + if($this->filterCallback) { + $obj->setMarkingFilterFunction($this->filterCallback); + } elseif($this->sourceObject == 'Folder') { + $obj->setMarkingFilter('ClassName', 'Folder'); } - $eval = '"