Skip to content
This repository
Browse code

FEATURE: Disable specific tree nodes in TreeDropdownField

DO NOT MERGE: to be reviewed.

This feature request was born out of wanting the ability to disable (for example) a top level page from being selected, while still being able to select a child page. Using setFilterFunction() simply removes the node and its children.

Extra styling for disabled nodes

Disable ability to select a disabled node for TreeDropdownField

Disable hover CSS changes

Fixing merge conflict during rebase

Return a boolean for nodeIsDisabled()
  • Loading branch information...
commit 6b3b61873a3d514f073b970cedea014de454abd2 1 parent 92e98f0
Loz Calver authored May 30, 2013
2  admin/css/screen.css
@@ -747,6 +747,7 @@ form.import-form label.left { width: 250px; }
747 747
 .cms .jstree li.jstree-open > ul, .TreeDropdownField .treedropdownfield-panel .jstree li.jstree-open > ul { display: block; }
748 748
 .cms .jstree li.jstree-closed > ul, .TreeDropdownField .treedropdownfield-panel .jstree li.jstree-closed > ul { display: none; }
749 749
 .cms .jstree li.disabled > a, .TreeDropdownField .treedropdownfield-panel .jstree li.disabled > a { color: #aaaaaa; }
  750
+.cms .jstree li.disabled > a:hover, .TreeDropdownField .treedropdownfield-panel .jstree li.disabled > a:hover { background: transparent; cursor: default; }
750 751
 .cms .jstree li.edit-disabled > a, .TreeDropdownField .treedropdownfield-panel .jstree li.edit-disabled > a { color: #aaaaaa; }
751 752
 .cms .jstree li > .jstree-icon, .TreeDropdownField .treedropdownfield-panel .jstree li > .jstree-icon { cursor: pointer; }
752 753
 .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; }
817 818
 .tree-holder.jstree-apple li.Root > a .jstree-icon, .cms-tree.jstree-apple li.Root > a .jstree-icon { background-position: -56px -36px; }
818 819
 .tree-holder.jstree-apple li.status-deletedonlive .text, .cms-tree.jstree-apple li.status-deletedonlive .text { text-decoration: line-through; }
819 820
 .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; }
  821
+.tree-holder.jstree-apple li.disabled > a > .jstree-checkbox, .cms-tree.jstree-apple li.disabled > a > .jstree-checkbox { background-position: -57px -54px; }
820 822
 .tree-holder.jstree-apple li.readonly, .cms-tree.jstree-apple li.readonly { color: #aaaaaa; padding-left: 18px; }
821 823
 .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; }
822 824
 .tree-holder.jstree-apple li.readonly .jstree-icon, .cms-tree.jstree-apple li.readonly .jstree-icon { display: none; }
BIN  admin/images/sitetree_ss_default_icons.png
11  admin/scss/_tree.scss
@@ -32,6 +32,10 @@
32 32
 			}
33 33
 			&.disabled > a {
34 34
 				color: #aaaaaa;
  35
+				&:hover {
  36
+					background: transparent;
  37
+					cursor: default;
  38
+				}
35 39
 			}
36 40
 			&.edit-disabled > a {
37 41
 				color: #aaaaaa;
@@ -438,7 +442,12 @@
438 442
 				> a, > a:link{
439 443
 					background-color: $color-cms-batchactions-menu-selected-background;
440 444
 				}
441  
-			} 
  445
+			}
  446
+			&.disabled {
  447
+				> a > .jstree-checkbox {
  448
+					background-position: -57px -54px;
  449
+				}
  450
+			}
442 451
 			&.readonly {
443 452
 				color: $color-text-disabled;
444 453
 				padding-left: 18px;
37  forms/TreeDropdownField.php
@@ -53,7 +53,8 @@ class TreeDropdownField extends FormField {
53 53
 	/**
54 54
 	 * @ignore
55 55
 	 */
56  
-	protected $sourceObject, $keyField, $labelField, $filterCallback, $searchCallback, $baseID = 0;
  56
+	protected $sourceObject, $keyField, $labelField, $filterCallback,
  57
+		$disableCallback, $searchCallback, $baseID = 0;
57 58
 	/**
58 59
 	 * @var string default child method in Hierarcy->getChildrenAsUL
59 60
 	 */
@@ -122,6 +123,20 @@ public function setFilterFunction($callback) {
122 123
 		$this->filterCallback = $callback;
123 124
 		return $this;
124 125
 	}
  126
+
  127
+	/**
  128
+	 * Set a callback used to disable checkboxes for some items in the tree 
  129
+	 *
  130
+	 * @param callback $callback
  131
+	 */
  132
+	public function setDisableFunction($callback) {
  133
+		if(!is_callable($callback, true)) {
  134
+			throw new InvalidArgumentException('TreeDropdownField->setDisableFunction(): not passed a valid callback');
  135
+		}
  136
+		
  137
+		$this->disableCallback = $callback;
  138
+		return $this;
  139
+	}
125 140
 	
126 141
 	/**
127 142
 	 * Set a callback used to search the hierarchy globally, even before 
@@ -181,11 +196,11 @@ public function Field($properties = array()) {
181 196
 		if($record) {
182 197
 			$title = $record->{$this->labelField};
183 198
 		} else {
184  
-			if($this->showSearch){
  199
+			if($this->showSearch) {
185 200
 				$title = _t('DropdownField.CHOOSESEARCH', '(Choose or Search)', 'start value of a dropdown');
186  
-			}else{
187  
-			$title = _t('DropdownField.CHOOSE', '(Choose)', 'start value of a dropdown');
188  
-		}
  201
+			} else {
  202
+				$title = _t('DropdownField.CHOOSE', '(Choose)', 'start value of a dropdown');
  203
+			}
189 204
 		}
190 205
 
191 206
 		// TODO Implement for TreeMultiSelectField
@@ -276,12 +291,13 @@ public function tree(SS_HTTPRequest $request) {
276 291
 			$keyField = $self->keyField;
277 292
 			$labelField = $self->labelField;
278 293
 			return sprintf(
279  
-				'<li id="selector-%s-%s" data-id="%s" class="class-%s %s"><a rel="%d">%s</a>',
  294
+				'<li id="selector-%s-%s" data-id="%s" class="class-%s %s %s"><a rel="%d">%s</a>',
280 295
 				Convert::raw2xml($self->getName()),
281 296
 				Convert::raw2xml($child->$keyField),
282 297
 				Convert::raw2xml($child->$keyField),
283 298
 				Convert::raw2xml($child->class),
284 299
 				Convert::raw2xml($child->markingClasses()),
  300
+				($self->nodeIsDisabled($child)) ? 'disabled' : '',
285 301
 				(int)$child->ID,
286 302
 				$escapeLabelField ? Convert::raw2xml($child->$labelField) : $child->$labelField
287 303
 			);
@@ -352,6 +368,15 @@ public function filterMarking($node) {
352 368
 	}
353 369
 
354 370
 	/**
  371
+	 * Marking a specific node in the tree as disabled
  372
+	 * @param $node
  373
+	 * @return boolean
  374
+	 */
  375
+	public function nodeIsDisabled($node) {
  376
+		return ($this->disableCallback && call_user_func($this->disableCallback, $node));
  377
+	}
  378
+
  379
+	/**
355 380
 	 * @param String $field
356 381
 	 */
357 382
 	public function setLabelField($field) {
20  javascript/TreeDropdownField.js
@@ -228,7 +228,25 @@
228 228
 					'themes': {
229 229
 						'theme': 'apple'
230 230
 					},
231  
-					'plugins': ['html_data', 'ui', 'themes']
  231
+					'types' : {
  232
+						'types' : {
  233
+							'default': {
  234
+								'check_node': function(node) {
  235
+									return ( ! node.hasClass('disabled'));
  236
+								},
  237
+								'uncheck_node': function(node) {
  238
+									return ( ! node.hasClass('disabled'));
  239
+								},
  240
+								'select_node': function(node) {
  241
+									return ( ! node.hasClass('disabled'));
  242
+								},
  243
+								'deselect_node': function(node) {
  244
+									return ( ! node.hasClass('disabled'));
  245
+								}
  246
+							}
  247
+						}
  248
+					},
  249
+					'plugins': ['html_data', 'ui', 'themes', 'types']
232 250
 				};
233 251
 			},
234 252
 			/**

0 notes on commit 6b3b618

Please sign in to comment.
Something went wrong with that request. Please try again.