Skip to content

Commit b8a51c3

Browse files
committed
Merge branch '3.0' into 3.1
2 parents b282c9f + 00bcdf3 commit b8a51c3

10 files changed

+312
-38
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ matrix:
2222
- php: 5.4
2323
env:
2424
- PHPCS=1
25+
- env: TESTDB=SQLITE
2526

2627
before_script:
2728
- pear install pear/PHP_CodeSniffer

admin/code/LeftAndMain.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ public function SiteTreeAsUL() {
691691
* @return String Nested unordered list with links to each page
692692
*/
693693
public function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null,
694-
$filterFunction = null, $minNodeCount = 30) {
694+
$filterFunction = null, $nodeCountThreshold = 30) {
695695

696696
// Filter criteria
697697
$params = $this->request->getVar('q');
@@ -719,7 +719,7 @@ public function getSiteTreeFor($className, $rootID = null, $childrenMethod = nul
719719
// Mark the nodes of the tree to return
720720
if ($filterFunction) $obj->setMarkingFilterFunction($filterFunction);
721721

722-
$obj->markPartialTree($minNodeCount, $this, $childrenMethod, $numChildrenMethod);
722+
$obj->markPartialTree($nodeCountThreshold, $this, $childrenMethod, $numChildrenMethod);
723723

724724
// Ensure current page is exposed
725725
if($p = $this->currentPage()) $obj->markToExpose($p);
@@ -744,7 +744,7 @@ public function getSiteTreeFor($className, $rootID = null, $childrenMethod = nul
744744
true,
745745
$childrenMethod,
746746
$numChildrenMethod,
747-
$minNodeCount
747+
$nodeCountThreshold
748748
);
749749

750750
// Wrap the root if needs be.

core/Core.php

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
if($_REQUEST) stripslashes_recursively($_REQUEST);
120120
if($_GET) stripslashes_recursively($_GET);
121121
if($_POST) stripslashes_recursively($_POST);
122+
if($_COOKIE) stripslashes_recursively($_COOKIE);
122123
}
123124

124125
/**

docs/en/reference/dataextension.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ implementation. Have a look at `[api:Object->useCustomClass()]`.
99

1010
## Usage
1111

12-
Your extension will nee to be a subclass of `[api:DataExtension]` or the `[api:Extension]` class.
12+
Your extension will need to be a subclass of `[api:DataExtension]` or the `[api:Extension]` class.
1313

1414
:::php
1515
<?php
@@ -155,4 +155,4 @@ extended by.
155155

156156

157157
## API Documentation
158-
`[api:DataExtension]`
158+
`[api:DataExtension]`

docs/en/reference/form-field-types.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,23 @@ This is a highlevel overview of available `[api:FormField]` subclasses. An autom
99
* `[api:ReadonlyField]`: Read-only field to display a non-editable value with a label.
1010
* `[api:TextareaField]`: Multi-line text field.
1111
* `[api:TextField]`: Single-line text field.
12-
* `[api:PasswordField]`: Masked input field
12+
* `[api:PasswordField]`: Masked input field.
1313

14-
## Actions
14+
## Actions
1515

1616
* `[api:FormAction]`: Button element for forms, both for `<input type="submit">` and `<button>`.
1717
* `[api:ResetFormAction]`: Action that clears all fields on a form.
1818

1919
## Formatted Input
2020

21-
* `[api:AjaxUniqueTextField]`: Text field that automatically checks that the value entered is unique for the given set of fields in a given set of tables
21+
* `[api:AjaxUniqueTextField]`: Text field that automatically checks that the value entered is unique for the given set of fields in a given set of tables.
2222
* `[api:ConfirmedPasswordField]`: Two masked input fields, checks for matching passwords.
2323
* `[api:CountryDropdownField]`: A simple extension to dropdown field, pre-configured to list countries.
2424
* `[api:CreditCardField]`: Allows input of credit card numbers via four separate form fields, including generic validation of its numeric values.
2525
* `[api:CurrencyField]`: Text field, validating its input as a currency. Limited to US-centric formats, including a hardcoded currency symbol and decimal separators.
2626
See `[api:MoneyField]` for a more flexible implementation.
2727
* `[api:DateField]`: Represents a date in a single input field, or separated into day, month, and year. Can optionally use a calendar popup.
28-
* `[api:DatetimeField]`: Combined date- and time field
28+
* `[api:DatetimeField]`: Combined date- and time field.
2929
* `[api:EmailField]`: Text input field with validation for correct email format according to RFC 2822.
3030
* `[api:GroupedDropdownField]`: Grouped dropdown, using <optgroup> tags.
3131
* `[api:HTMLEditorField].
@@ -43,7 +43,7 @@ doesn't necessarily have any visible styling.
4343
* `[api:FieldGroup] attached in CMS-context.
4444
* `[api:FieldList]`: Basic container for sequential fields, or nested fields through CompositeField.
4545
* `[api:TabSet]`: Collection of fields which is rendered as separate tabs. Can be nested.
46-
* `[api:Tab]`: A single tab inside a `TabSet`
46+
* `[api:Tab]`: A single tab inside a `TabSet`.
4747
* `[api:ToggleCompositeField]`: Allows visibility of a group of fields to be toggled.
4848
* `[api:ToggleField]`: ReadonlyField with added toggle-capabilities - will preview the first sentence of the contained text-value, and show the full content by a javascript-switch.
4949

@@ -58,7 +58,7 @@ doesn't necessarily have any visible styling.
5858
* `[api:TableField]`: In-place editing of tabular data.
5959
* `[api:TreeDropdownField]`: Dropdown-like field that allows you to select an item from a hierarchical AJAX-expandable tree.
6060
* `[api:TreeMultiselectField]`: Represents many-many joins using a tree selector shown in a dropdown-like element
61-
* `[api:GridField](/reference/grid-field)`: Displays a `[api:SS_List]` in a tabular format. Versatile base class which can be configured to allow editing, sorting, etc.
61+
* `[api:GridField]`: Displays a `[api:SS_List]` in a tabular format. Versatile base class which can be configured to allow editing, sorting, etc.
6262
* `[api:ListboxField]`: Multi-line listbox field, through `<select multiple>`.
6363

6464

@@ -67,6 +67,6 @@ doesn't necessarily have any visible styling.
6767
* `[api:DatalessField]` - Base class for fields which add some HTML to the form but don't submit any data or
6868
save it to the database
6969
* `[api:HeaderField]`: Renders a simple HTML header element.
70-
* `[api:HiddenField]`
70+
* `[api:HiddenField]`.
7171
* `[api:LabelField]`: Simple label tag. This can be used to add extra text in your forms.
7272
* `[api:LiteralField]`: Renders arbitrary HTML into a form.

docs/en/topics/module-development.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,4 @@ adherence to conventions, writing documentation, and releasing updates. See [con
5454
* [Modules](modules)
5555
* [Module Release Process](module-release-process)
5656
* [Debugging methods](/topics/debugging)
57-
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of ���page options��� , ���rendering tools��� or ���special
58-
URL variables��� that you can use to debug your SilverStripe applications
57+
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of page options, rendering tools or special URL variables that you can use to debug your SilverStripe applications

docs/en/tutorials/2-extending-a-basic-site.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ First, the template for displaying a single article:
245245

246246

247247
:::ss
248-
<div class="content-container">
248+
<% include SideBar %>
249+
<div class="content-container unit size3of4 lastUnit">
249250
<article>
250251
<h1>$Title</h1>
251252
<div class="news-details">
@@ -255,7 +256,6 @@ First, the template for displaying a single article:
255256
</article>
256257
$Form
257258
</div>
258-
<% include SideBar %>
259259

260260

261261
Most of the code is just like the regular Page.ss, we include an informational div with the date and the author of the Article.
@@ -278,7 +278,8 @@ We'll now create a template for the article holder. We want our news section to
278278
**themes/simple/templates/Layout/ArticleHolder.ss**
279279

280280
:::ss
281-
<div class="content-container">
281+
<% include SideBar %>
282+
<div class="content-container unit size3of4 lastUnit">
282283
<article>
283284
<h1>$Title</h1>
284285
$Content
@@ -293,7 +294,6 @@ We'll now create a template for the article holder. We want our news section to
293294
<% end_loop %>
294295
$Form
295296
</div>
296-
<% include SideBar %>
297297

298298

299299
Here we use the page control *Children*. As the name suggests, this control allows you to iterate over the children of a page. In this case, the children are our news articles. The *$Link* variable will give the address of the article which we can use to create a link, and the *FirstParagraph* function of the `[api:HTMLText]` field gives us a nice summary of the article. The function strips all tags from the paragraph extracted.
@@ -482,7 +482,8 @@ The staff section templates aren't too difficult to create, thanks to the utilit
482482
**themes/simple/templates/Layout/StaffHolder.ss**
483483

484484
:::ss
485-
<div class="content-container">
485+
<% include SideBar %>
486+
<div class="content-container unit size3of4 lastUnit">
486487
<article>
487488
<h1>$Title</h1>
488489
$Content
@@ -498,7 +499,6 @@ The staff section templates aren't too difficult to create, thanks to the utilit
498499
<% end_loop %>
499500
$Form
500501
</div>
501-
<% include SideBar %>
502502

503503

504504
This template is very similar to the *ArticleHolder* template. The *SetWidth* method of the `[api:Image]` class
@@ -512,7 +512,8 @@ The *StaffPage* template is also very straight forward.
512512
**themes/simple/templates/Layout/StaffPage.ss**
513513

514514
:::ss
515-
<div class="content-container">
515+
<% include SideBar %>
516+
<div class="content-container unit size3of4 lastUnit">
516517
<article>
517518
<h1>$Title</h1>
518519
<div class="content">
@@ -521,7 +522,6 @@ The *StaffPage* template is also very straight forward.
521522
</article>
522523
$Form
523524
</div>
524-
<% include SideBar %>
525525

526526
Here we use the *SetWidth* method to get a different sized image from the same source image. You should now have
527527
a complete staff section.

docs/en/tutorials/5-dataobject-relationship-management.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ a named list of object.
278278
**themes/simple/templates/Layout/ProjectsHolder.ss**
279279

280280
:::ss
281-
<div class="content-container typography">
281+
<% include SideBar %>
282+
<div class="content-container unit size3of4 lastUnit">
282283
<article>
283284
<h1>$Title</h1>
284285
<div class="content">
@@ -314,7 +315,6 @@ a named list of object.
314315
</div>
315316
</article>
316317
</div>
317-
<% include SideBar %>
318318

319319
Navigate to the holder page through your website navigation,
320320
or the "Preview" feature in the CMS. You should see a list of all projects now.
@@ -336,7 +336,8 @@ we can access the "Students" and "Mentors" relationships directly in the templat
336336
**themes/simple/templates/Layout/Project.ss**
337337

338338
:::ss
339-
<div class="content-container typography">
339+
<% include SideBar %>
340+
<div class="content-container unit size3of4 lastUnit">
340341
<article>
341342
<h1>$Title</h1>
342343
<div class="content">
@@ -364,7 +365,6 @@ we can access the "Students" and "Mentors" relationships directly in the templat
364365
</div>
365366
</article>
366367
</div>
367-
<% include SideBar %>
368368

369369
Follow the link to a project detail from from your holder page,
370370
or navigate to it through the submenu provided by the theme.

model/Hierarchy.php

+52-11
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,17 @@ public function validate(ValidationResult $validationResult) {
7474
* @param string $childrenMethod The name of the method used to get children from each object
7575
* @param boolean $rootCall Set to true for this first call, and then to false for calls inside the recursion. You
7676
* should not change this.
77-
* @param int $minNodeCount
77+
* @param int $nodeCountThreshold The lower bounds for the amount of nodes to mark. If set, the logic will expand
78+
* nodes until it eaches at least this number, and then stops. Root nodes will always
79+
* show regardless of this settting. Further nodes can be lazy-loaded via ajax.
80+
* This isn't a hard limit. Example: On a value of 10, with 20 root nodes, each having
81+
* 30 children, the actual node count will be 50 (all root nodes plus first expanded child).
82+
*
7883
* @return string
7984
*/
8085
public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child->Title', $extraArg = null,
8186
$limitToMarked = false, $childrenMethod = "AllChildrenIncludingDeleted",
82-
$numChildrenMethod = "numChildren", $rootCall = true, $minNodeCount = 30) {
87+
$numChildrenMethod = "numChildren", $rootCall = true, $nodeCountThreshold = 30) {
8388

8489
if($limitToMarked && $rootCall) {
8590
$this->markingFinished($numChildrenMethod);
@@ -103,9 +108,25 @@ public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child-
103108
if(!$limitToMarked || $child->isMarked()) {
104109
$foundAChild = true;
105110
$output .= (is_callable($titleEval)) ? $titleEval($child) : eval("return $titleEval;");
106-
$output .= "\n" .
107-
$child->getChildrenAsUL("", $titleEval, $extraArg, $limitToMarked, $childrenMethod,
108-
$numChildrenMethod, false, $minNodeCount) . "</li>\n";
111+
$output .= "\n";
112+
113+
114+
$numChildren = $child->$numChildrenMethod();
115+
if(
116+
// Always traverse into opened nodes (they might be exposed as parents of search results)
117+
$child->isExpanded()
118+
// Only traverse into children if we haven't reached the maximum node count already.
119+
// Otherwise, the remaining nodes are lazy loaded via ajax.
120+
&& $child->isMarked()
121+
) {
122+
$output .= $child->getChildrenAsUL("", $titleEval, $extraArg, $limitToMarked, $childrenMethod,
123+
$numChildrenMethod, false, $nodeCountThreshold);
124+
}
125+
elseif($child->isTreeOpened()) {
126+
// Since we're not loading children, don't mark it as open either
127+
$child->markClosed();
128+
}
129+
$output .= "</li>\n";
109130
}
110131
}
111132

@@ -125,21 +146,23 @@ public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child-
125146
* This method returns the number of nodes marked. After this method is called other methods
126147
* can check isExpanded() and isMarked() on individual nodes.
127148
*
128-
* @param int $minNodeCount The minimum amount of nodes to mark.
149+
* @param int $nodeCountThreshold See {@link getChildrenAsUL()}
129150
* @return int The actual number of nodes marked.
130151
*/
131-
public function markPartialTree($minNodeCount = 30, $context = null,
152+
public function markPartialTree($nodeCountThreshold = 30, $context = null,
132153
$childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren") {
133154

134-
if(!is_numeric($minNodeCount)) $minNodeCount = 30;
155+
if(!is_numeric($nodeCountThreshold)) $nodeCountThreshold = 30;
135156

136157
$this->markedNodes = array($this->owner->ID => $this->owner);
137158
$this->owner->markUnexpanded();
138159

139160
// foreach can't handle an ever-growing $nodes list
140161
while(list($id, $node) = each($this->markedNodes)) {
141-
$this->markChildren($node, $context, $childrenMethod, $numChildrenMethod);
142-
if($minNodeCount && sizeof($this->markedNodes) >= $minNodeCount) {
162+
$children = $this->markChildren($node, $context, $childrenMethod, $numChildrenMethod);
163+
if($nodeCountThreshold && sizeof($this->markedNodes) > $nodeCountThreshold) {
164+
// Undo marking children as opened since they're lazy loaded
165+
if($children) foreach($children as $child) $child->markClosed();
143166
break;
144167
}
145168
}
@@ -200,6 +223,7 @@ public function markingFilterMatches($node) {
200223
/**
201224
* Mark all children of the given node that match the marking filter.
202225
* @param DataObject $node Parent node.
226+
* @return DataList
203227
*/
204228
public function markChildren($node, $context = null, $childrenMethod = "AllChildrenIncludingDeleted",
205229
$numChildrenMethod = "numChildren") {
@@ -213,7 +237,13 @@ public function markChildren($node, $context = null, $childrenMethod = "AllChild
213237
$node->markExpanded();
214238
if($children) {
215239
foreach($children as $child) {
216-
if(!$this->markingFilter || $this->markingFilterMatches($child)) {
240+
$markingMatches = $this->markingFilterMatches($child);
241+
// Filtered results should always show opened, since actual matches
242+
// might be hidden by non-matching parent nodes.
243+
if($this->markingFilter && $markingMatches) {
244+
$child->markOpened();
245+
}
246+
if(!$this->markingFilter || $markingMatches) {
217247
if($child->$numChildrenMethod()) {
218248
$child->markUnexpanded();
219249
} else {
@@ -223,6 +253,8 @@ public function markChildren($node, $context = null, $childrenMethod = "AllChild
223253
}
224254
}
225255
}
256+
257+
return $children;
226258
}
227259

228260
/**
@@ -350,6 +382,15 @@ public function markOpened() {
350382
self::$marked[ClassInfo::baseDataClass($this->owner->class)][$this->owner->ID] = true;
351383
self::$treeOpened[ClassInfo::baseDataClass($this->owner->class)][$this->owner->ID] = true;
352384
}
385+
386+
/**
387+
* Mark this DataObject's tree as closed.
388+
*/
389+
public function markClosed() {
390+
if(isset(self::$treeOpened[ClassInfo::baseDataClass($this->owner->class)][$this->owner->ID])) {
391+
unset(self::$treeOpened[ClassInfo::baseDataClass($this->owner->class)][$this->owner->ID]);
392+
}
393+
}
353394

354395
/**
355396
* Check if this DataObject is marked.

0 commit comments

Comments
 (0)