diff --git a/admin/css/screen.css b/admin/css/screen.css index ff33a4c9d..ddd577c97 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -747,6 +747,7 @@ form.import-form label.left { width: 250px; } .cms .jstree li.jstree-open > ul, .TreeDropdownField .treedropdownfield-panel .jstree li.jstree-open > ul { display: block; } .cms .jstree li.jstree-closed > ul, .TreeDropdownField .treedropdownfield-panel .jstree li.jstree-closed > ul { display: none; } .cms .jstree li.disabled > a, .TreeDropdownField .treedropdownfield-panel .jstree li.disabled > a { color: #aaaaaa; } +.cms .jstree li.disabled > a:hover, .TreeDropdownField .treedropdownfield-panel .jstree li.disabled > a:hover { background: transparent; cursor: default; } .cms .jstree li.edit-disabled > a, .TreeDropdownField .treedropdownfield-panel .jstree li.edit-disabled > a { color: #aaaaaa; } .cms .jstree li > .jstree-icon, .TreeDropdownField .treedropdownfield-panel .jstree li > .jstree-icon { cursor: pointer; } .cms .jstree ins, .TreeDropdownField .treedropdownfield-panel .jstree ins { display: inline-block; text-decoration: none; width: 18px; height: 18px; margin: 0 0 0 0; padding: 0; float: left; } @@ -817,6 +818,7 @@ form.import-form label.left { width: 250px; } .tree-holder.jstree-apple li.Root > a .jstree-icon, .cms-tree.jstree-apple li.Root > a .jstree-icon { background-position: -56px -36px; } .tree-holder.jstree-apple li.status-deletedonlive .text, .cms-tree.jstree-apple li.status-deletedonlive .text { text-decoration: line-through; } .tree-holder.jstree-apple li.jstree-checked > a, .tree-holder.jstree-apple li.jstree-checked > a:link, .cms-tree.jstree-apple li.jstree-checked > a, .cms-tree.jstree-apple li.jstree-checked > a:link { background-color: #efe999; } +.tree-holder.jstree-apple li.disabled > a > .jstree-checkbox, .cms-tree.jstree-apple li.disabled > a > .jstree-checkbox { background-position: -57px -54px; } .tree-holder.jstree-apple li.readonly, .cms-tree.jstree-apple li.readonly { color: #aaaaaa; padding-left: 18px; } .tree-holder.jstree-apple li.readonly a, .tree-holder.jstree-apple li.readonly a:link, .cms-tree.jstree-apple li.readonly a, .cms-tree.jstree-apple li.readonly a:link { margin: 0; padding: 0; } .tree-holder.jstree-apple li.readonly .jstree-icon, .cms-tree.jstree-apple li.readonly .jstree-icon { display: none; } diff --git a/admin/images/sitetree_ss_default_icons.png b/admin/images/sitetree_ss_default_icons.png index 101351db9..783fd2268 100644 Binary files a/admin/images/sitetree_ss_default_icons.png and b/admin/images/sitetree_ss_default_icons.png differ diff --git a/admin/scss/_tree.scss b/admin/scss/_tree.scss index df8098c14..1be4b67f7 100644 --- a/admin/scss/_tree.scss +++ b/admin/scss/_tree.scss @@ -32,6 +32,10 @@ } &.disabled > a { color: #aaaaaa; + &:hover { + background: transparent; + cursor: default; + } } &.edit-disabled > a { color: #aaaaaa; @@ -438,7 +442,12 @@ > a, > a:link{ background-color: $color-cms-batchactions-menu-selected-background; } - } + } + &.disabled { + > a > .jstree-checkbox { + background-position: -57px -54px; + } + } &.readonly { color: $color-text-disabled; padding-left: 18px; diff --git a/forms/TreeDropdownField.php b/forms/TreeDropdownField.php index d9a57c954..c56f575b7 100644 --- a/forms/TreeDropdownField.php +++ b/forms/TreeDropdownField.php @@ -53,7 +53,8 @@ class TreeDropdownField extends FormField { /** * @ignore */ - protected $sourceObject, $keyField, $labelField, $filterCallback, $searchCallback, $baseID = 0; + protected $sourceObject, $keyField, $labelField, $filterCallback, + $disableCallback, $searchCallback, $baseID = 0; /** * @var string default child method in Hierarcy->getChildrenAsUL */ @@ -122,6 +123,20 @@ class TreeDropdownField extends FormField { $this->filterCallback = $callback; return $this; } + + /** + * Set a callback used to disable checkboxes for some items in the tree + * + * @param callback $callback + */ + public function setDisableFunction($callback) { + if(!is_callable($callback, true)) { + throw new InvalidArgumentException('TreeDropdownField->setDisableFunction(): not passed a valid callback'); + } + + $this->disableCallback = $callback; + return $this; + } /** * Set a callback used to search the hierarchy globally, even before @@ -181,11 +196,11 @@ class TreeDropdownField extends FormField { if($record) { $title = $record->{$this->labelField}; } else { - if($this->showSearch){ + if($this->showSearch) { $title = _t('DropdownField.CHOOSESEARCH', '(Choose or Search)', 'start value of a dropdown'); - }else{ - $title = _t('DropdownField.CHOOSE', '(Choose)', 'start value of a dropdown'); - } + } else { + $title = _t('DropdownField.CHOOSE', '(Choose)', 'start value of a dropdown'); + } } // TODO Implement for TreeMultiSelectField @@ -276,12 +291,13 @@ class TreeDropdownField extends FormField { $keyField = $self->keyField; $labelField = $self->labelField; return sprintf( - '
  • %s', + '
  • %s', Convert::raw2xml($self->getName()), Convert::raw2xml($child->$keyField), Convert::raw2xml($child->$keyField), Convert::raw2xml($child->class), Convert::raw2xml($child->markingClasses()), + ($self->nodeIsDisabled($child)) ? 'disabled' : '', (int)$child->ID, $escapeLabelField ? Convert::raw2xml($child->$labelField) : $child->$labelField ); @@ -351,6 +367,15 @@ class TreeDropdownField extends FormField { return true; } + /** + * Marking a specific node in the tree as disabled + * @param $node + * @return boolean + */ + public function nodeIsDisabled($node) { + return ($this->disableCallback && call_user_func($this->disableCallback, $node)); + } + /** * @param String $field */ diff --git a/javascript/TreeDropdownField.js b/javascript/TreeDropdownField.js index 4f687b719..7c05f33e4 100644 --- a/javascript/TreeDropdownField.js +++ b/javascript/TreeDropdownField.js @@ -228,7 +228,25 @@ 'themes': { 'theme': 'apple' }, - 'plugins': ['html_data', 'ui', 'themes'] + 'types' : { + 'types' : { + 'default': { + 'check_node': function(node) { + return ( ! node.hasClass('disabled')); + }, + 'uncheck_node': function(node) { + return ( ! node.hasClass('disabled')); + }, + 'select_node': function(node) { + return ( ! node.hasClass('disabled')); + }, + 'deselect_node': function(node) { + return ( ! node.hasClass('disabled')); + } + } + } + }, + 'plugins': ['html_data', 'ui', 'themes', 'types'] }; }, /**