Skip to content
This repository
Browse code

ENHANCEMENT: populate FormField:: on the fly based on class name of f…

…ield rather than requiring explict definition.
  • Loading branch information...
commit 07d2d5273ac890e9a5ea81a4bf83b5ef001e3bb6 1 parent 907568b
Will Rossiter authored April 14, 2012

Showing 35 changed files with 270 additions and 219 deletions. Show diff stats Hide diff stats

  1. 4  css/GridField.css
  2. 17  forms/CheckboxField.php
  3. 7  forms/CheckboxSetField.php
  4. 38  forms/CompositeField.php
  5. 4  forms/DropdownField.php
  6. 23  forms/FieldGroup.php
  7. 9  forms/FileField.php
  8. 2  forms/FileIFrameField.php
  9. 7  forms/FormAction.php
  10. 203  forms/FormField.php
  11. 5  forms/HeaderField.php
  12. 3  forms/HiddenField.php
  13. 2  forms/LabelField.php
  14. 9  forms/ListboxField.php
  15. 12  forms/OptionsetField.php
  16. 13  forms/SelectionGroup.php
  17. 6  forms/TabSet.php
  18. 13  forms/TextField.php
  19. 16  forms/TextareaField.php
  20. 8  forms/ToggleCompositeField.php
  21. 9  forms/UploadField.php
  22. 2  forms/gridfield/GridFieldDetailForm.php
  23. 8  scss/GridField.scss
  24. 0  templates/forms/{CheckboxFieldHolder.ss → CheckboxField_holder.ss}
  25. 5  templates/forms/CheckboxField_holder_small.ss
  26. 11  templates/forms/CheckboxSetField_Select.ss
  27. 8  templates/forms/CompositeField.ss
  28. 15  templates/forms/CompositeField_holder.ss
  29. 15  templates/forms/CompositeField_holder_small.ss
  30. 2  templates/forms/{FieldGroupField.ss → FieldGroup.ss}
  31. 0  templates/forms/{FieldGroupHolder.ss → FieldGroup_holder.ss}
  32. 0  templates/forms/{FieldHolder.ss → FormField_holder.ss}
  33. 11  templates/forms/FormField_holder_small.ss
  34. 0  templates/{ → forms}/ToggleCompositeField.ss
  35. 2  tests/forms/CompositeFieldTest.php
4  css/GridField.css
@@ -65,10 +65,10 @@
65 65
 .cms table.ss-gridfield-table tr th button.ss-gridfield-sort:hover { background-position: right -34px; }
66 66
 .cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-desc { background-position: right -72px; }
67 67
 .cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-asc { background-position: right -116px; }
68  
-.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button { position: absolute; right: 5px; top: -28px; display: block; text-indent: -9999em; width: 30px; height: 28px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, linear-gradient(#ffffff, #d9d9d9); }
  68
+.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button { position: absolute; top: 0; right: 0; display: block; text-indent: -9999em; width: 30px; height: 28px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, linear-gradient(#ffffff, #d9d9d9); }
69 69
 .cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike:active { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); }
70 70
 .cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); }
71  
-.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button { position: absolute; right: 34px; top: -28px; display: block; text-indent: -9999em; width: 30px; height: 28px; float: right; border-radius: 0px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, linear-gradient(#ffffff, #d9d9d9); }
  71
+.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button { position: absolute; right: 29px; top: 0; display: block; text-indent: -9999em; width: 30px; height: 28px; float: right; border-radius: 0px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, linear-gradient(#ffffff, #d9d9d9); }
72 72
 .cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:hover { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); }
73 73
 .cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:active { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); }
74 74
 .cms table.ss-gridfield-table tr th input.ss-gridfield-sort { padding: 2px; }
17  forms/CheckboxField.php
... ...
@@ -1,15 +1,12 @@
1 1
 <?php
2 2
 /**
3 3
  * Single checkbox field.
  4
+ *
4 5
  * @package forms
5 6
  * @subpackage fields-basic
6 7
  */
7 8
 class CheckboxField extends FormField {
8 9
 
9  
-	protected $template = 'CheckboxField';
10  
-
11  
-	protected $fieldHolderTemplate = 'CheckboxFieldHolder';
12  
-
13 10
 	function setValue($value) {
14 11
 		$this->value = ($value) ? 1 : 0;
15 12
 		return $this;
@@ -23,17 +20,6 @@ function Value() {
23 20
 		return ($this->value) ? 1 : 0;
24 21
 	}
25 22
 
26  
-	/**
27  
-	 * Returns a restricted field holder used within things like FieldGroups
28  
-	 */
29  
-	function SmallFieldHolder() {
30  
-		$result = $this->Field();
31  
-		if($t = $this->Title()) {
32  
-			$result .= "<label for=\"" . $this->id() ."\">$t</label> ";
33  
-		}
34  
-		return $result;
35  
-	}
36  
-
37 23
 	function getAttributes() {
38 24
 		$attrs = parent::getAttributes();
39 25
 		$attrs['value'] = 1;
@@ -65,6 +51,7 @@ function performDisabledTransformation() {
65 51
 
66 52
 /**
67 53
  * Readonly version of a checkbox field - "Yes" or "No".
  54
+ *
68 55
  * @package forms
69 56
  * @subpackage fields-basic
70 57
  */
7  forms/CheckboxSetField.php
@@ -33,11 +33,9 @@
33 33
  * @subpackage fields-basic
34 34
  */
35 35
 class CheckboxSetField extends OptionsetField {
36  
-
37  
-	protected $template = 'CheckboxSetField';
38 36
 	
39 37
 	/**
40  
-	 * @var Array
  38
+	 * @var array
41 39
 	 */
42 40
 	protected $defaultItems = array();
43 41
 	
@@ -130,7 +128,7 @@ function Field($properties = array()) {
130 128
 
131 129
 		$properties = array_merge($properties, array('Options' => new ArrayList($options)));
132 130
 
133  
-		return $this->customise($properties)->renderWith($this->getTemplate());
  131
+		return $this->customise($properties)->renderWith($this->getTemplates());
134 132
 	}
135 133
 	
136 134
 	/**
@@ -288,5 +286,4 @@ function Type() {
288 286
 	function ExtraOptions() {
289 287
 		return FormField::ExtraOptions();
290 288
 	}
291  
-	
292 289
 }
38  forms/CompositeField.php
... ...
@@ -1,8 +1,11 @@
1 1
 <?php
2 2
 /**
3 3
  * Base class for all fields that contain other fields.
4  
- * Implements sequentialisation - so that when we're saving / loading data, we can populate
5  
- * a tabbed form properly.  All of the children are stored in $this->children
  4
+ *
  5
+ * Implements sequentialisation - so that when we're saving / loading data, we 
  6
+ * can populate a tabbed form properly. All of the children are stored in 
  7
+ * $this->children
  8
+ *
6 9
  * @package forms
7 10
  * @subpackage fields-structural
8 11
  */
@@ -34,11 +37,6 @@ class CompositeField extends FormField {
34 37
 	protected $tag = 'div';
35 38
 	
36 39
 	/**
37  
-	 * @var string
38  
-	 */
39  
-	protected $template = "CompositeField";
40  
-	
41  
-	/**
42 40
 	 * @var String Optional description for this set of fields.
43 41
 	 * If the {@link $tag} property is set to use a 'fieldset', this will be
44 42
 	 * rendered as a <legend> tag, otherwise its a 'title' attribute.
@@ -152,32 +150,6 @@ function getAttributes() {
152 150
 		);
153 151
 	}
154 152
 
155  
-	public function Field($properties = array()) {
156  
-		$props = $this->customise($properties);
157  
-		
158  
-		return $props->renderWith($this->getTemplate());
159  
-	}
160  
-
161  
-	/**
162  
-	 * @param array
163  
-	 */
164  
-	function FieldHolder($properties = array()) {
165  
-		$props = $this->customise($properties);
166  
-
167  
-		return $props->renderWith($this->getTemplate());
168  
-	}
169  
-		
170  
-	/**
171  
-	 * Returns the fields in the restricted field holder.
172  
-	 *
173  
-	 * @param array
174  
-	 */
175  
-	function SmallFieldHolder($properties = array()) {
176  
-		$obj = ($properties) ? $this->customise($properties) : $this;
177  
-
178  
-		return $obj->renderWith($this->getTemplate());
179  
-	}	
180  
-	
181 153
 	/**
182 154
 	 * Add all of the non-composite fields contained within this field to the 
183 155
 	 * list.
4  forms/DropdownField.php
@@ -75,8 +75,6 @@
75 75
  * @subpackage fields-basic
76 76
  */
77 77
 class DropdownField extends FormField {
78  
-	
79  
-	protected $template = 'DropdownField';
80 78
 
81 79
 	/**
82 80
 	 * @var boolean $source Associative or numeric array of all dropdown items,
@@ -158,7 +156,7 @@ function Field($properties = array()) {
158 156
 
159 157
 		$properties = array_merge($properties, array('Options' => new ArrayList($options)));
160 158
 
161  
-		return $this->customise($properties)->renderWith($this->getTemplate());
  159
+		return parent::Field($properties);
162 160
 	}
163 161
 
164 162
 	function getAttributes() {
23  forms/FieldGroup.php
@@ -85,29 +85,6 @@ function Name(){
85 85
 		return preg_replace("/[^a-zA-Z0-9]+/", "", $this->title);
86 86
 	}
87 87
 
88  
-
89  
-	/**
90  
-	 * Generates the field HTML with the HTML for child {@link FormField}
91  
-	 *
92  
-	 * @param array $properties custom properties for the template
93  
-	 */
94  
-	function Field($properties = array()) {
95  
-		$props = $this->customise(new ArrayData($properties));
96  
-		
97  
-		return $props->renderWith('FieldGroupField');
98  
-	}
99  
-	
100  
-	/**
101  
-	 * Generates the field HTML with the HTML for child {@link FormField}
102  
-	 *
103  
-	 * @param array $properties custom properties for the template
104  
-	 */
105  
-	function FieldHolder($properties = array()) {
106  
-		$props = $this->customise(new ArrayData($properties));
107  
-	
108  
-		return $props->renderWith('FieldGroupHolder');
109  
-	}
110  
-  
111 88
 	/**
112 89
 	 * Set an odd/even class
113 90
 	 *
9  forms/FileField.php
@@ -42,8 +42,6 @@
42 42
  * @subpackage fields-files
43 43
  */
44 44
 class FileField extends FormField {
45  
-
46  
-	protected $template = 'FileField';
47 45
 	
48 46
 	/**
49 47
 	 * Restrict filesize for either all filetypes
@@ -112,8 +110,11 @@ function __construct($name, $title = null, $value = null) {
112 110
 	}
113 111
 
114 112
 	public function Field($properties = array()) {
115  
-		$properties = array_merge($properties, array('MaxFileSize' => $this->getValidator()->getAllowedMaxFileSize()));
116  
-		return $this->customise($properties)->renderWith($this->getTemplate());
  113
+		$properties = array_merge($properties, array(
  114
+			'MaxFileSize' => $this->getValidator()->getAllowedMaxFileSize()
  115
+		));
  116
+		
  117
+		return parent::Field($properties);
117 118
 	}
118 119
 
119 120
 	function getAttributes() {
2  forms/FileIFrameField.php
@@ -12,8 +12,6 @@
12 12
  */
13 13
 class FileIFrameField extends FileField {
14 14
 	
15  
-	protected $template = 'FileIFrameField';
16  
-	
17 15
 	public static $allowed_actions = array (
18 16
 		'iframe',
19 17
 		'EditFileForm',
7  forms/FormAction.php
@@ -20,8 +20,6 @@
20 20
  */
21 21
 class FormAction extends FormField {
22 22
 
23  
-	protected $template = 'FormAction';
24  
-
25 23
 	protected $action;
26 24
 	
27 25
 	/**
@@ -36,12 +34,14 @@ class FormAction extends FormField {
36 34
 	
37 35
 	/**
38 36
 	 * Create a new action button.
  37
+	 *
39 38
 	 * @param action The method to call when the button is clicked
40 39
 	 * @param title The label on the button
41 40
 	 * @param form The parent form, auto-set when the field is placed inside a form 
42 41
 	 */
43 42
 	function __construct($action, $title = "", $form = null) {
44 43
 		$this->action = "action_$action";
  44
+		
45 45
 		parent::__construct($this->action, $title, null, $form);
46 46
 	}
47 47
 
@@ -67,7 +67,8 @@ function Field($properties = array()) {
67 67
 				'UseButtonTag' => $this->useButtonTag
68 68
 			)
69 69
 		);
70  
-		return $this->customise($properties)->renderWith($this->getTemplate());
  70
+		
  71
+		return parent::Field($properties);
71 72
 	}
72 73
 	
73 74
 	function FieldHolder($properties = array()) {
203  forms/FormField.php
@@ -57,31 +57,35 @@ class FormField extends RequestHandler {
57 57
 	protected $containerFieldSet;
58 58
 	
59 59
 	/**
60  
-	 * @var $readonly boolean
  60
+	 * @var boolean
61 61
 	 */
62 62
 	protected $readonly = false;
63 63
 
64 64
 	/**
65  
-	 * @var $disabled boolean
  65
+	 * @var boolean
66 66
 	 */
67 67
 	protected $disabled = false;
68 68
 	
69 69
 	/**
70  
-	 * @var String
71  
-	 */
72  
-	protected $template = 'FormField';
73  
-	
74  
-	/**
75  
-	 * @var Custom Validation Message for the Field
  70
+	 * @var string custom validation message for the Field
76 71
 	 */
77 72
 	protected $customValidationMessage = "";
78  
-
  73
+	
79 74
 	/**
80  
-	 * Template name to render this FormField field holder into.
  75
+	 * Name of the template used to render this form field. If not set, then
  76
+	 * will look up the class ancestry for the first matching template where 
  77
+	 * the template name equals the class name.
  78
+	 *
  79
+	 * To explicitly use a custom template or one named other than the form 
  80
+	 * field see {@link setTemplate()}, {@link setFieldHolderTemplate()}
  81
+	 *
81 82
 	 * @var string
82 83
 	 */
83  
-	protected $fieldHolderTemplate = 'FieldHolder';
84  
-
  84
+	protected 
  85
+		$template,
  86
+		$fieldHolderTemplate,
  87
+ 		$smallFieldHolderTemplate;
  88
+		
85 89
 	/**
86 90
 	 * @var array All attributes on the form field (not the field holder).
87 91
 	 * Partially determined based on other instance properties, please use {@link getAttributes()}.
@@ -268,7 +272,7 @@ public function getTabIndex() {
268 272
 	 * Uses {@link Message()} and {@link MessageType()} to add validatoin
269 273
 	 * error classes which can be used to style the contained tags.
270 274
 	 * 
271  
-	 * @return String CSS-classnames
  275
+	 * @return string CSS-classnames
272 276
 	 */
273 277
 	function extraClass() {
274 278
 		$classes = array();
@@ -323,8 +327,8 @@ function removeExtraClass($class) {
323 327
 	 * CreditCardField, CurrencyField, DateField, DatetimeField, FieldGroup, GridField, HtmlEditorField,
324 328
 	 * ImageField, ImageFormAction, InlineFormAction, ListBoxField, etc.
325 329
 	 * 
326  
-	 * @param String
327  
-	 * @param String
  330
+	 * @param string
  331
+	 * @param string
328 332
 	 */
329 333
 	function setAttribute($name, $value) {
330 334
 		$this->attributes[$name] = $value;
@@ -335,7 +339,7 @@ function setAttribute($name, $value) {
335 339
 	 * Get an HTML attribute defined by the field, or added through {@link setAttribute()}.
336 340
 	 * Caution: Doesn't work on all fields, see {@link setAttribute()}.
337 341
 	 * 
338  
-	 * @return String
  342
+	 * @return string
339 343
 	 */
340 344
 	function getAttribute($name) {
341 345
 		$attrs = $this->getAttributes();
@@ -355,13 +359,14 @@ function getAttributes() {
355 359
 			'disabled' => $this->isDisabled(),
356 360
 			'title' => $this->getDescription(),
357 361
 		);
  362
+		
358 363
 		return array_merge($attrs, $this->attributes);
359 364
 	}
360 365
 
361 366
 	/**
362 367
 	 * @param Array Custom attributes to process. Falls back to {@link getAttributes()}.
363 368
 	 * If at least one argument is passed as a string, all arguments act as excludes by name.
364  
-	 * @return String HTML attributes, ready for insertion into an HTML tag
  369
+	 * @return string HTML attributes, ready for insertion into an HTML tag
365 370
 	 */
366 371
 	function getAttributesHTML($attrs = null) {
367 372
 		$exclude = (is_string($attrs)) ? func_get_args() : null;
@@ -431,28 +436,7 @@ function setForm($form) {
431 436
 	function getForm() {
432 437
 		return $this->form; 
433 438
 	}
434  
-
435  
-	/**
436  
-	 * @return String
437  
-	 */
438  
-	public function getFieldHolderTemplate() {
439  
-		return $this->fieldHolderTemplate;
440  
-	}
441  
-
442  
-	/**
443  
-	 * Set name of template (without path or extension) for the holder,
444  
-	 * which in turn is responsible for rendering {@link Field()}.
445  
-	 * 
446  
-	 * Caution: Not consistently implemented in all subclasses,
447  
-	 * please check the {@link Field()} method on the subclass for support.
448  
-	 * 
449  
-	 * @param String
450  
-	 */
451  
-	public function setFieldHolderTemplate($template) {
452  
-		$this->fieldHolderTemplate = $template;
453  
-		return $this;
454  
-	}
455  
-
  439
+	
456 440
 	/**
457 441
 	 * Return TRUE if security token protection is enabled on the parent {@link Form}.
458 442
 	 *
@@ -461,6 +445,7 @@ public function setFieldHolderTemplate($template) {
461 445
 	public function securityTokenEnabled() {
462 446
 		$form = $this->getForm();
463 447
 		if(!$form) return false;
  448
+		
464 449
 		return $form->getSecurityToken()->isEnabled();
465 450
 	}
466 451
 	
@@ -471,6 +456,7 @@ public function securityTokenEnabled() {
471 456
 	function setError($message, $messageType) {
472 457
 		$this->message = $message; 
473 458
 		$this->messageType = $messageType; 
  459
+		
474 460
 		return $this;
475 461
 	}
476 462
 	
@@ -479,10 +465,11 @@ function setError($message, $messageType) {
479 465
 	 * format of Please Fill In XXX. Different from setError() as
480 466
 	 * that appends it to the standard error messaging
481 467
 	 * 
482  
-	 * @param String Message for the error
  468
+	 * @param string Message for the error
483 469
 	 */
484 470
 	public function setCustomValidationMessage($msg) {
485 471
 		$this->customValidationMessage = $msg;
  472
+		
486 473
 		return $this;
487 474
 	}
488 475
 	
@@ -492,7 +479,7 @@ public function setCustomValidationMessage($msg) {
492 479
 	 * error is defined on {@link Validator}.
493 480
 	 *
494 481
 	 * @todo Should the default error message be stored here instead
495  
-	 * @return String
  482
+	 * @return string
496 483
 	 */
497 484
 	public function getCustomValidationMessage() {
498 485
 		return $this->customValidationMessage;
@@ -503,21 +490,66 @@ public function getCustomValidationMessage() {
503 490
 	 * Caution: Not consistently implemented in all subclasses,
504 491
 	 * please check the {@link Field()} method on the subclass for support.
505 492
 	 * 
506  
-	 * @param String
  493
+	 * @param string
507 494
 	 */
508 495
 	function setTemplate($template) {
509 496
 		$this->template = $template;
  497
+		
510 498
 		return $this;
511 499
 	}
512 500
 	
513 501
 	/**
514  
-	 * @return String
  502
+	 * @return string
515 503
 	 */
516 504
 	function getTemplate() {
517 505
 		return $this->template;
518 506
 	}
519 507
 	
520 508
 	/**
  509
+	 * @return string
  510
+	 */
  511
+	public function getFieldHolderTemplate() {
  512
+		return $this->fieldHolderTemplate;
  513
+	}
  514
+	
  515
+	/**
  516
+	 * Set name of template (without path or extension) for the holder,
  517
+	 * which in turn is responsible for rendering {@link Field()}.
  518
+	 * 
  519
+	 * Caution: Not consistently implemented in all subclasses,
  520
+	 * please check the {@link Field()} method on the subclass for support.
  521
+	 * 
  522
+	 * @param string
  523
+	 */
  524
+	public function setFieldHolderTemplate($template) {
  525
+		$this->fieldHolderTemplate = $template;
  526
+		
  527
+		return $this;
  528
+	}
  529
+	
  530
+	/**
  531
+	 * @return string
  532
+	 */
  533
+	public function getSmallFieldHolderTemplate() {
  534
+		return $this->smallFieldHolderTemplate;
  535
+	}
  536
+	
  537
+	/**
  538
+	 * Set name of template (without path or extension) for the small holder,
  539
+	 * which in turn is responsible for rendering {@link Field()}.
  540
+	 * 
  541
+	 * Caution: Not consistently implemented in all subclasses,
  542
+	 * please check the {@link Field()} method on the subclass for support.
  543
+	 * 
  544
+	 * @param string
  545
+	 */
  546
+	public function setSmallFieldHolderTemplate($template) {
  547
+		$this->smallFieldHolderTemplate = $template;
  548
+		
  549
+		return $this;
  550
+	}
  551
+	
  552
+	/**
521 553
 	 * Returns the form field - used by templates.
522 554
 	 * Although FieldHolder is generally what is inserted into templates, all of the field holder
523 555
 	 * templates make use of $Field.  It's expected that FieldHolder will give you the "complete"
@@ -529,7 +561,8 @@ function getTemplate() {
529 561
 	 */
530 562
 	function Field($properties = array()) {
531 563
 		$obj = ($properties) ? $this->customise($properties) : $this;
532  
-		return $obj->renderWith($this->getTemplate());
  564
+
  565
+		return $obj->renderWith($this->getTemplates());
533 566
 	}
534 567
 
535 568
 	/**
@@ -544,29 +577,81 @@ function Field($properties = array()) {
544 577
 	 */
545 578
 	function FieldHolder($properties = array()) {
546 579
 		$obj = ($properties) ? $this->customise($properties) : $this;
547  
-		return $obj->renderWith($this->getFieldHolderTemplate());
  580
+
  581
+		return $obj->renderWith($this->getFieldHolderTemplates());
548 582
 	}
549 583
 
550 584
    /**
551 585
     * Returns a restricted field holder used within things like FieldGroups.
  586
+	*
  587
+	* @param array $properties
  588
+	*
  589
+	* @return string
552 590
     */
553  
-   function SmallFieldHolder() {
554  
-		$result = '';
555  
-		// set label
556  
-		if($title = $this->RightTitle()){
557  
-			$result .= "<label class=\"right\" for=\"" . $this->id() . "\">{$title}</label>\n";
558  
-		} elseif($title = $this->LeftTitle()) {
559  
-			$result .= "<label class=\"left\" for=\"" . $this->id() . "\">{$title}</label>\n";
560  
-		} elseif($title = $this->Title()) {
561  
-			$result .= "<label for=\"" . $this->id() . "\">{$title}</label>\n";
562  
-		}
  591
+   function SmallFieldHolder($properties = array()) {
  592
+		$obj = ($properties) ? $this->customise($properties) : $this;
563 593
 
564  
-		$result .= $this->Field();
  594
+		return $obj->renderWith($this->getSmallFieldHolderTemplates());
  595
+	}
  596
+	
  597
+	/**
  598
+	* Returns an array of templates to use for rendering {@link FieldH}
  599
+	 *
  600
+	 * @return array
  601
+	 */
  602
+	public function getTemplates() {
  603
+		return $this->_templates($this->getTemplate());
  604
+	}
  605
+	
  606
+	/**
  607
+	 * Returns an array of templates to use for rendering {@link FieldHolder}
  608
+	 *
  609
+	 * @return array
  610
+	 */
  611
+	public function getFieldHolderTemplates() {
  612
+		return $this->_templates(
  613
+			$this->getFieldHolderTemplate(), 
  614
+			'_holder'
  615
+		);
  616
+	}
  617
+
  618
+	/**
  619
+	 * Returns an array of templates to use for rendering {@link SmallFieldHolder}
  620
+	 *
  621
+	 * @return array
  622
+	 */	
  623
+	public function getSmallFieldHolderTemplates() {
  624
+		return $this->_templates(
  625
+			$this->getSmallFieldHolderTemplate(), 
  626
+			'_holder_small'
  627
+		);
  628
+	}
565 629
 
566  
-		return $result;
567  
-   }
568 630
 
569 631
 	/**
  632
+	 * Generate an array of classname strings to use for rendering this form 
  633
+	 * field into HTML
  634
+	 *
  635
+	 * @param string $custom custom template (if set)
  636
+	 * @param string $suffix template suffix
  637
+	 *
  638
+	 * @return array $stack a stack of 
  639
+	 */
  640
+	private function _templates($custom = null, $suffix = null) {
  641
+		$matches = array();
  642
+		
  643
+		foreach(array_reverse(ClassInfo::ancestry($this)) as $className) {
  644
+			$matches[] = $className . $suffix;
  645
+			
  646
+			if($className == "FormField") break;
  647
+		}
  648
+		
  649
+		if($custom) array_unshift($matches, $custom);
  650
+		
  651
+		return $matches;
  652
+	}
  653
+	
  654
+	/**
570 655
 	 * Returns true if this field is a composite field.
571 656
 	 * To create composite field types, you should subclass {@link CompositeField}.
572 657
 	 */
@@ -722,7 +807,7 @@ function setDescription($description) {
722 807
 	}
723 808
 
724 809
 	/**
725  
-	 * @return String
  810
+	 * @return string
726 811
 	 */
727 812
 	function getDescription() {
728 813
 		return $this->description;
5  forms/HeaderField.php
... ...
@@ -1,13 +1,13 @@
1 1
 <?php
2 2
 /**
3 3
  * Field that generates a heading tag.
  4
+ *
4 5
  * This can be used to add extra text in your forms.
  6
+ *
5 7
  * @package forms
6 8
  * @subpackage fields-dataless
7 9
  */
8 10
 class HeaderField extends DatalessField {
9  
-
10  
-	protected $template = 'HeaderField';
11 11
 	
12 12
 	/**
13 13
 	 * @var int $headingLevel The level of the <h1> to <h6> HTML tag. Default: 2
@@ -53,5 +53,4 @@ function getAttributes() {
53 53
 	function Type() {
54 54
 		return null;
55 55
 	}
56  
-
57 56
 }
3  forms/HiddenField.php
... ...
@@ -1,13 +1,12 @@
1 1
 <?php
2 2
 /**
3 3
  * Hidden field.
  4
+ *
4 5
  * @package forms
5 6
  * @subpackage fields-dataless
6 7
  */
7 8
 class HiddenField extends FormField {
8 9
 
9  
-	protected $template = 'HiddenField';
10  
-
11 10
 	function FieldHolder($properties = array()) {
12 11
 		return $this->Field($properties);
13 12
 	}
2  forms/LabelField.php
@@ -8,8 +8,6 @@
8 8
  * @subpackage fields-dataless
9 9
  */
10 10
 class LabelField extends DatalessField {
11  
-
12  
-	protected $template = 'LabelField';
13 11
 	
14 12
 	/**
15 13
 	 * @param string $name
9  forms/ListboxField.php
@@ -64,6 +64,7 @@ class ListboxField extends DropdownField {
64 64
 	function __construct($name, $title = '', $source = array(), $value = '', $size = null, $multiple = false) {
65 65
 		if($size) $this->size = $size;
66 66
 		if($multiple) $this->multiple = $multiple;
  67
+		
67 68
 		parent::__construct($name, $title, $source, $value);
68 69
 	}
69 70
 	
@@ -96,8 +97,12 @@ function Field($properties = array()) {
96 97
 				));
97 98
 			}
98 99
 		}
99  
-		$properties = array_merge($properties, array('Options' => new ArrayList($options)));
100  
-		return $this->customise($properties)->renderWith($this->getTemplate());
  100
+		
  101
+		$properties = array_merge($properties, array(
  102
+			'Options' => new ArrayList($options)
  103
+		));
  104
+		
  105
+		return $this->customise($properties)->renderWith($this->getTemplates());
101 106
 	}
102 107
 
103 108
 	function getAttributes() {
12  forms/OptionsetField.php
@@ -55,8 +55,6 @@
55 55
  * @subpackage fields-basic
56 56
  */
57 57
 class OptionsetField extends DropdownField {
58  
-
59  
-	protected $template = 'OptionsetField';
60 58
 	
61 59
 	/**
62 60
 	 * @var Array
@@ -67,6 +65,7 @@ function Field($properties = array()) {
67 65
 		$source = $this->getSource();
68 66
 		$odd = 0;
69 67
 		$options = array();
  68
+		
70 69
 		if($source) {
71 70
 			foreach($source as $value => $title) {
72 71
 				$itemID = $this->ID() . '_' . preg_replace('/[^a-zA-Z0-9]/', '', $value);
@@ -86,9 +85,13 @@ function Field($properties = array()) {
86 85
 			}
87 86
 		}
88 87
 
89  
-		$properties = array_merge($properties, array('Options' => new ArrayList($options)));
  88
+		$properties = array_merge($properties, array(
  89
+			'Options' => new ArrayList($options)
  90
+		));
90 91
 
91  
-		return $this->customise($properties)->renderWith($this->getTemplate());
  92
+		return $this->customise($properties)->renderWith(
  93
+			$this->getTemplates()
  94
+		);
92 95
 	}
93 96
 
94 97
 	function performReadonlyTransformation() {
@@ -97,6 +100,7 @@ function performReadonlyTransformation() {
97 100
 		$field = new LookupField($this->name, $this->title ? $this->title : '', $items, $this->value);
98 101
 		$field->setForm($this->form);
99 102
 		$field->setReadonly(true);
  103
+		
100 104
 		return $field;
101 105
 	}
102 106
 	
13  forms/SelectionGroup.php
... ...
@@ -1,15 +1,15 @@
1 1
 <?php
2 2
 /**
3  
- * SelectionGroup represents a number of fields that are selectable by a radio button that appears at
4  
- * the beginning of each item.  Using CSS, you can configure the field to only display its contents if
5  
- * the corresponding radio button is selected.
  3
+ * SelectionGroup represents a number of fields that are selectable by a radio 
  4
+ * button that appears at the beginning of each item.  Using CSS, you can 
  5
+ * configure the field to only display its contents if the corresponding radio 
  6
+ * button is selected.
  7
+ *
6 8
  * @package forms
7 9
  * @subpackage fields-structural
8 10
  */
9 11
 class SelectionGroup extends CompositeField {
10 12
 	
11  
-	protected $template = "SelectionGroup";
12  
-	
13 13
 	/**
14 14
 	 * Create a new selection group.
15 15
 	 * @param name The field name of the selection group.
@@ -59,6 +59,7 @@ function FieldList() {
59 59
 
60 60
 			$firstSelected = $checked ="";
61 61
 		}
  62
+		
62 63
 		return new ArrayList($newItems);
63 64
 	}
64 65
 	
@@ -73,7 +74,7 @@ function FieldHolder($properties = array()) {
73 74
 
74 75
 		$obj = $properties ? $this->customise($properties) : $this;
75 76
 		
76  
-		return $obj->renderWith($this->template);
  77
+		return $obj->renderWith($this->getFieldHolderTemplates());
77 78
 	}
78 79
 }
79 80
 
6  forms/TabSet.php
@@ -27,8 +27,6 @@
27 27
  */
28 28
 class TabSet extends CompositeField {
29 29
 	
30  
-	protected $template = "TabSetFieldHolder";
31  
-	
32 30
 	/**
33 31
 	 * @param string $name Identifier
34 32
 	 * @param string $title (Optional) Natural language title of the tabset
@@ -81,7 +79,8 @@ public function FieldHolder($properties = array()) {
81 79
 		Requirements::javascript(SAPPHIRE_DIR . '/javascript/TabSet.js');
82 80
 		
83 81
 		$obj = $properties ? $this->customise($properties) : $this;
84  
-		return $obj->renderWith($this->template);
  82
+		
  83
+		return $obj->renderWith($this->getFieldHolderTemplates());
85 84
 	}
86 85
 	
87 86
 	/**
@@ -90,6 +89,7 @@ public function FieldHolder($properties = array()) {
90 89
 	public function Tabs() {
91 90
 		return $this->children;
92 91
 	}
  92
+	
93 93
 	public function setTabs($children){
94 94
 		$this->children = $children;
95 95
 	}
13  forms/TextField.php
... ...
@@ -1,15 +1,14 @@
1 1
 <?php
2 2
 /**
3 3
  * Text input field.
  4
+ *
4 5
  * @package forms
5 6
  * @subpackage fields-basic
6 7
  */
7 8
 class TextField extends FormField {
8 9
 
9  
-	protected $template = 'TextField';
10  
-
11 10
 	/**
12  
-	 * @var Int
  11
+	 * @var int
13 12
 	 */
14 13
 	protected $maxLength;
15 14
 	
@@ -23,15 +22,16 @@ function __construct($name, $title = null, $value = '', $maxLength = null, $form
23 22
 	}
24 23
 	
25 24
 	/**
26  
-	 * @param Int $length
  25
+	 * @param int $length
27 26
 	 */
28 27
 	function setMaxLength($length) {
29 28
 		$this->maxLength = $length;
  29
+		
30 30
 		return $this;
31 31
 	}
32 32
 	
33 33
 	/**
34  
-	 * @return Int
  34
+	 * @return int
35 35
 	 */
36 36
 	function getMaxLength() {
37 37
 		return $this->maxLength;
@@ -50,6 +50,5 @@ function getAttributes() {
50 50
 	function InternallyLabelledField() {
51 51
 		if(!$this->value) $this->value = $this->Title();
52 52
 		return $this->Field();
53  
-	}
54  
-	
  53
+	}	
55 54
 }
16  forms/TextareaField.php
@@ -21,16 +21,14 @@
21 21
  * @subpackage fields-basic
22 22
  */
23 23
 class TextareaField extends FormField {
24  
-
25  
-	protected $template = 'TextareaField';
26  
-
  24
+	
27 25
 	/**
28  
-	 * @var Int Visible number of text lines.
  26
+	 * @var int Visible number of text lines.
29 27
 	 */
30 28
 	protected $rows = 5;
31 29
 
32 30
 	/**
33  
-	 * @var Int Width of the text area (in average character widths)
  31
+	 * @var int Width of the text area (in average character widths)
34 32
 	 */
35 33
 	protected $cols = 20;
36 34
 
@@ -60,13 +58,14 @@ function getAttributes() {
60 58
 	}
61 59
 
62 60
 	function getTemplate() {
63  
-		return ($this->isReadonly()) ? "{$this->template}_Readonly" : $this->template;
  61
+		return ($this->isReadonly()) ? "{$this->template}_readonly" : $this->template;
64 62
 	}
65 63
 
66 64
 	/**
67  
-	 * Performs a readonly transformation on this field. You should still be able
68  
-	 * to copy from this field, and it should still send when you submit
  65
+	 * Performs a readonly transformation on this field. You should still be 
  66
+	 * able to copy from this field, and it should still send when you submit
69 67
 	 * the form it's attached to.
  68
+	 *
70 69
 	 * The element shouldn't be both disabled and readonly at the same time.
71 70
 	 */
72 71
 	function performReadonlyTransformation() {
@@ -80,6 +79,7 @@ function performReadonlyTransformation() {
80 79
 	 * Performs a disabled transformation on this field. You shouldn't be able to
81 80
 	 * copy from this field, and it should not send any data when you submit the
82 81
 	 * form it's attached to.
  82
+	 *
83 83
 	 * The element shouldn't be both disabled and readonly at the same time.
84 84
 	 */
85 85
 	function performDisabledTransformation() {
8  forms/ToggleCompositeField.php
... ...
@@ -1,13 +1,12 @@
1 1
 <?php
2 2
 /**
3 3
  * Allows visibility of a group of fields to be toggled using '+' and '-' icons
  4
+ *
4 5
  * @package forms
5 6
  * @subpackage fields-structural
6 7
  */
7 8
 class ToggleCompositeField extends CompositeField {
8 9
 	
9  
-	protected $template = "ToggleCompositeField";
10  
-	
11 10
 	/**
12 11
 	 * @var $headingLevel int
13 12
 	 */
@@ -28,7 +27,8 @@ public function FieldHolder($properties = array()) {
28 27
 		Requirements::javascript(SAPPHIRE_DIR . "/javascript/ToggleCompositeField.js");
29 28
 		
30 29
 		$obj = $properties ? $this->customise($properties) : $this;
31  
-		return $obj->renderWith($this->template);
  30
+		
  31
+		return $obj->renderWith($this->getTemplates());
32 32
 	}	
33 33
 	
34 34
 	/**
@@ -41,7 +41,7 @@ public function startClosed($bool) {
41 41
 	}
42 42
 	
43 43
 	/**
44  
-	 * @return String
  44
+	 * @return string
45 45
 	 */
46 46
 	public function HeadingLevel() {
47 47
 		return $this->headingLevel;
9  forms/UploadField.php
@@ -47,11 +47,6 @@ class UploadField extends FileField {
47 47
 	/**
48 48
 	 * @var String
49 49
 	 */
50  
-	protected $template = 'UploadField';
51  
-
52  
-	/**
53  
-	 * @var String
54  
-	 */
55 50
 	protected $templateFileButtons = 'UploadField_FileButtons';
56 51
 
57 52
 	/**
@@ -375,13 +370,15 @@ public function Field($properties = array()) {
375 370
 		if (is_numeric($config['maxNumberOfFiles']) && $this->getItems()->count()) {
376 371
 			$configOverwrite['maxNumberOfFiles'] = $config['maxNumberOfFiles'] - $this->getItems()->count();
377 372
 		}
  373
+		
378 374
 		$config = array_merge($config, $this->ufConfig, $configOverwrite);
  375
+		
379 376
 		return $this->customise(array(
380 377
 			'configString' => str_replace('"', "'", Convert::raw2json($config)),
381 378
 			'config' => new ArrayData($config),
382 379
 			'multiple' => $config['maxNumberOfFiles'] !== 1,
383 380
 			'displayInput' => (!isset($configOverwrite['maxNumberOfFiles']) || $configOverwrite['maxNumberOfFiles'])
384  
-		))->renderWith($this->getTemplate());
  381
+		))->renderWith($this->getTemplates());
385 382
 	}
386 383
 
387 384
 	/**
2  forms/gridfield/GridFieldDetailForm.php
@@ -12,8 +12,6 @@
12 12
  */
13 13
 class GridFieldDetailForm implements GridField_URLHandler {
14 14
 
15  
-
16  
-
17 15
 	/**
18 16
 	 * @var String
19 17
 	 */
8  scss/GridField.scss
@@ -375,8 +375,8 @@ $gf_grid_x:	16px;
375 375
 					}
376 376
 					&.ss-gridfield-button-filter.ss-ui-button{
377 377
 						position:absolute;
378  
-						right:5px; //positions filter button in correct position on top of input field
379  
-						top:-28px;
  378
+						top: 0;
  379
+						right: 0;
380 380
 						display:block;
381 381
 						text-indent:-9999em;
382 382
 						width:30px; 
@@ -412,8 +412,8 @@ $gf_grid_x:	16px;
412 412
 					}
413 413
 					&.ss-gridfield-button-reset.ss-ui-button{
414 414
 						position:absolute;
415  
-						right:34px; //positions reset button in correct position on top of input field and to the left of the filter button
416  
-						top:-28px;
  415
+						right: 29px;
  416
+						top: 0;
417 417
 						display:block;
418 418
 						text-indent:-9999em;
419 419
 						width:30px;
0  templates/forms/CheckboxFieldHolder.ss → templates/forms/CheckboxField_holder.ss
File renamed without changes
5  templates/forms/CheckboxField_holder_small.ss
... ...
@@ -0,0 +1,5 @@
  1
+<% if $Title %>
  2
+	<label class="checkboxfield-small" <% if ID %>for="$ID"<% end_if %>>$Title</label>
  3
+<% end_if %>
  4
+
  5
+$Field
11  templates/forms/CheckboxSetField_Select.ss
... ...
@@ -1,11 +0,0 @@
1  
-<%-- Renders a CheckboxField with $multiple=true as a select element which can save into relations.--%>
2  
-<%-- TODO Make relation saving available on ListboxField --%>
3  
-<select id="$ID" class="$extraClass" name="$Name[]" multiple="true">
4  
-	<% if Options.Count %>
5  
-		<% control Options %>
6  
-			<option class="$Class" value="$Value"<% if isChecked %> selected="selected"<% end_if %>>
7  
-				$Title
8  
-			</option> 
9  
-		<% end_control %>
10  
-	<% end_if %>
11  
-</select>
8  templates/forms/CompositeField.ss
... ...
@@ -1,4 +1,4 @@
1  
-<$Tag class="CompositeField $extraClass <% if ColumnCount %>multi-column<% end_if %>">
  1
+<$Tag class="CompositeField $extraClass <% if ColumnCount %>multicolumn<% end_if %>">
2 2
 	<% if $Tag == 'fieldset' && $Legend %>
3 3
 		<legend>$Legend</legend>
4 4
 	<% end_if %>
@@ -6,10 +6,10 @@
6 6
 	<% loop FieldList %>
7 7
 		<% if ColumnCount %>
8 8
 			<div class="column-{$ColumnCount} $FirstLast">
9  
-				$FieldHolder
  9
+				$Field
10 10
 			</div>
11 11
 		<% else %>
12  
-			$FieldHolder
  12
+			$Field
13 13
 		<% end_if %>
14 14
 	<% end_loop %>
15  
-</$Tag>
  15
+</$Tag>
15  templates/forms/CompositeField_holder.ss
... ...
@@ -0,0 +1,15 @@
  1
+<$Tag class="CompositeField $extraClass <% if ColumnCount %>multicolumn<% end_if %>">
  2
+	<% if $Tag == 'fieldset' && $Legend %>
  3
+		<legend>$Legend</legend>
  4
+	<% end_if %>
  5
+	
  6
+	<% loop FieldList %>
  7
+		<% if ColumnCount %>
  8
+			<div class="column-{$ColumnCount} $FirstLast">
  9
+				$FieldHolder
  10
+			</div>
  11
+		<% else %>
  12
+			$FieldHolder
  13
+		<% end_if %>
  14
+	<% end_loop %>
  15
+</$Tag>
15  templates/forms/CompositeField_holder_small.ss
... ...
@@ -0,0 +1,15 @@
  1
+<$Tag class="field CompositeField $extraClass <% if ColumnCount %>multicolumn<% end_if %>">
  2
+	<% if $Tag == 'fieldset' && $Legend %>
  3
+		<legend>$Legend</legend>
  4
+	<% end_if %>
  5
+	
  6
+	<% loop FieldList %>
  7
+		<% if ColumnCount %>
  8
+			<div class="column-{$ColumnCount} $FirstLast">
  9
+				$SmallFieldHolder
  10
+			</div>
  11
+		<% else %>
  12
+			$SmallFieldHolder
  13
+		<% end_if %>
  14
+	<% end_loop %>
  15
+</$Tag>
2  templates/forms/FieldGroupField.ss → templates/forms/FieldGroup.ss
... ...
@@ -1,7 +1,7 @@
1 1
 <div class="fieldgroup <% if Zebra %>fieldgroup-zebra<% end_if %>" <% if ID %>id="$ID"<% end_if %>>
2 2
 	<% loop FieldList %>
3 3
 		<div class="fieldgroup-field $FirstLast $EvenOdd">
4  
-			SmallFieldHolder
  4
+			$SmallFieldHolder
5 5
 		</div>
6 6
 	<% end_loop %>
7 7
 </div>
0  templates/forms/FieldGroupHolder.ss → templates/forms/FieldGroup_holder.ss
File renamed without changes
0  templates/forms/FieldHolder.ss → templates/forms/FormField_holder.ss
File renamed without changes
11  templates/forms/FormField_holder_small.ss
... ...
@@ -0,0 +1,11 @@
  1
+<div class="fieldholder-small">
  2
+	<% if $RightTitle %>
  3
+		<label class="right fieldholder-small-label" <% if ID %>for="$ID"<% end_if %>>$RightTitle</label>
  4
+	<% else_if $LeftTitle %>
  5
+		<label class="left fieldholder-small-label" <% if ID %>for="$ID"<% end_if %>>$LeftTitle</label>
  6
+	<% else_if $Title %>
  7
+		<label class="fieldholder-small-label" <% if ID %>for="$ID"<% end_if %>>$Title</label>
  8
+	<% end_if %>
  9
+	
  10
+	$Field
  11
+</div>
0  templates/ToggleCompositeField.ss → templates/forms/ToggleCompositeField.ss
File renamed without changes
2  tests/forms/CompositeFieldTest.php
@@ -15,7 +15,7 @@ function testFieldPosition() {
15 15
 			),
16 16
 			new TextField('D')
17 17
 		);
18  
-		
  18
+