mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '3'
This commit is contained in:
commit
f548ddf8a8
@ -329,7 +329,8 @@ class Hierarchy extends DataExtension {
|
|||||||
foreach($children as $child) {
|
foreach($children as $child) {
|
||||||
$markingMatches = $this->markingFilterMatches($child);
|
$markingMatches = $this->markingFilterMatches($child);
|
||||||
if($markingMatches) {
|
if($markingMatches) {
|
||||||
if($child->$numChildrenMethod()) {
|
// Mark a child node as unexpanded if it has children and has not already been expanded
|
||||||
|
if($child->$numChildrenMethod() && !$child->isExpanded()) {
|
||||||
$child->markUnexpanded();
|
$child->markUnexpanded();
|
||||||
} else {
|
} else {
|
||||||
$child->markExpanded();
|
$child->markExpanded();
|
||||||
|
@ -172,7 +172,8 @@ We call `setDisplayFields()` directly on the component responsible for their ren
|
|||||||
Adding a `GridField` to a page type is a popular way to manage data,
|
Adding a `GridField` to a page type is a popular way to manage data,
|
||||||
but not the only one. If your data requires a dedicated interface
|
but not the only one. If your data requires a dedicated interface
|
||||||
with more sophisticated search and management logic, consider
|
with more sophisticated search and management logic, consider
|
||||||
using the `[ModelAdmin](reference/modeladmin)` interface instead.
|
using the [ModelAdmin](/developer_guides/customising_the_admin_interface/modeladmin)
|
||||||
|
interface instead.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
![tutorial:tutorial5_project_creation.jpg](../_images/tutorial5_project_creation.jpg)
|
![tutorial:tutorial5_project_creation.jpg](../_images/tutorial5_project_creation.jpg)
|
||||||
|
@ -494,13 +494,9 @@ class Form extends RequestHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always allow actions which map to buttons. See httpSubmission() for further access checks.
|
$actions = $this->getAllActions();
|
||||||
$fields = $this->fields->dataFields() ?: array();
|
foreach ($actions as $formAction) {
|
||||||
$actions = $this->actions->dataFields() ?: array();
|
if ($formAction->actionName() === $action) {
|
||||||
|
|
||||||
$fieldsAndActions = array_merge($fields, $actions);
|
|
||||||
foreach ($fieldsAndActions as $fieldOrAction) {
|
|
||||||
if ($fieldOrAction instanceof FormAction && $fieldOrAction->actionName() === $action) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1734,21 +1730,31 @@ class Form extends RequestHandler {
|
|||||||
* @return FormAction
|
* @return FormAction
|
||||||
*/
|
*/
|
||||||
public function buttonClicked() {
|
public function buttonClicked() {
|
||||||
|
$actions = $this->getAllActions();
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
if ($this->buttonClickedFunc === $action->actionName()) {
|
||||||
|
return $action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all actions, including those in the main "fields" FieldList
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getAllActions() {
|
||||||
$fields = $this->fields->dataFields() ?: array();
|
$fields = $this->fields->dataFields() ?: array();
|
||||||
$actions = $this->actions->dataFields() ?: array();
|
$actions = $this->actions->dataFields() ?: array();
|
||||||
|
|
||||||
if(!$actions && !$fields) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fieldsAndActions = array_merge($fields, $actions);
|
$fieldsAndActions = array_merge($fields, $actions);
|
||||||
foreach ($fieldsAndActions as $fieldOrAction) {
|
$actions = array_filter($fieldsAndActions, function($fieldOrAction) {
|
||||||
if ($fieldOrAction instanceof FormAction && $this->buttonClickedFunc === $fieldOrAction->actionName()) {
|
return $fieldOrAction instanceof FormAction;
|
||||||
return $fieldOrAction;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return $actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,6 +97,25 @@ class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the columns to export
|
||||||
|
*
|
||||||
|
* @param GridField $gridField
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getExportColumnsForGridField(GridField $gridField) {
|
||||||
|
if($this->exportColumns) {
|
||||||
|
$exportColumns = $this->exportColumns;
|
||||||
|
} else if($dataCols = $gridField->getConfig()->getComponentByType('GridFieldDataColumns')) {
|
||||||
|
$exportColumns = $dataCols->getDisplayFields($gridField);
|
||||||
|
} else {
|
||||||
|
$exportColumns = singleton($gridField->getModelClass())->summaryFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exportColumns;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate export fields for CSV.
|
* Generate export fields for CSV.
|
||||||
*
|
*
|
||||||
@ -104,9 +123,7 @@ class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function generateExportFileData($gridField) {
|
public function generateExportFileData($gridField) {
|
||||||
$csvColumns = ($this->exportColumns)
|
$csvColumns = $this->getExportColumnsForGridField($gridField);
|
||||||
? $this->exportColumns
|
|
||||||
: singleton($gridField->getModelClass())->summaryFields();
|
|
||||||
$fileData = array();
|
$fileData = array();
|
||||||
|
|
||||||
if($this->csvHasHeader) {
|
if($this->csvHasHeader) {
|
||||||
|
@ -65,12 +65,12 @@ class HierarchyTest extends SapphireTest {
|
|||||||
// Obj 3 has been deleted; let's bring it back from the grave
|
// Obj 3 has been deleted; let's bring it back from the grave
|
||||||
$obj3 = Versioned::get_including_deleted("HierarchyTest_Object", "\"Title\" = 'Obj 3'")->First();
|
$obj3 = Versioned::get_including_deleted("HierarchyTest_Object", "\"Title\" = 'Obj 3'")->First();
|
||||||
|
|
||||||
// Check that both obj 3 children are returned
|
// Check that all obj 3 children are returned
|
||||||
$this->assertEquals(array("Obj 3a", "Obj 3b", "Obj 3c"),
|
$this->assertEquals(array("Obj 3a", "Obj 3b", "Obj 3c", "Obj 3d"),
|
||||||
$obj3->AllHistoricalChildren()->column('Title'));
|
$obj3->AllHistoricalChildren()->column('Title'));
|
||||||
|
|
||||||
// Check numHistoricalChildren
|
// Check numHistoricalChildren
|
||||||
$this->assertEquals(3, $obj3->numHistoricalChildren());
|
$this->assertEquals(4, $obj3->numHistoricalChildren());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,11 +100,11 @@ class HierarchyTest extends SapphireTest {
|
|||||||
public function testNumChildren() {
|
public function testNumChildren() {
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj1')->numChildren(), 0);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj1')->numChildren(), 0);
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2')->numChildren(), 2);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2')->numChildren(), 2);
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3')->numChildren(), 3);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3')->numChildren(), 4);
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2a')->numChildren(), 2);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2a')->numChildren(), 2);
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2b')->numChildren(), 0);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2b')->numChildren(), 0);
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3a')->numChildren(), 2);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3a')->numChildren(), 2);
|
||||||
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3b')->numChildren(), 0);
|
$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3d')->numChildren(), 0);
|
||||||
|
|
||||||
$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
|
$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
|
||||||
$this->assertEquals($obj1->numChildren(), 0);
|
$this->assertEquals($obj1->numChildren(), 0);
|
||||||
@ -186,6 +186,53 @@ class HierarchyTest extends SapphireTest {
|
|||||||
$this->assertEquals('Obj 2 » Obj 2a » Obj 2aa', $obj2aa->getBreadcrumbs());
|
$this->assertEquals('Obj 2 » Obj 2a » Obj 2aa', $obj2aa->getBreadcrumbs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Hierarchy::markChildren()
|
||||||
|
*/
|
||||||
|
public function testMarkChildrenDoesntUnmarkPreviouslyMarked() {
|
||||||
|
$obj3 = $this->objFromFixture('HierarchyTest_Object', 'obj3');
|
||||||
|
$obj3aa = $this->objFromFixture('HierarchyTest_Object', 'obj3aa');
|
||||||
|
$obj3ba = $this->objFromFixture('HierarchyTest_Object', 'obj3ba');
|
||||||
|
$obj3ca = $this->objFromFixture('HierarchyTest_Object', 'obj3ca');
|
||||||
|
|
||||||
|
$obj3->markPartialTree();
|
||||||
|
$obj3->markToExpose($obj3aa);
|
||||||
|
$obj3->markToExpose($obj3ba);
|
||||||
|
$obj3->markToExpose($obj3ca);
|
||||||
|
|
||||||
|
$expected = <<<EOT
|
||||||
|
<ul>
|
||||||
|
<li>Obj 3a
|
||||||
|
<ul>
|
||||||
|
<li>Obj 3aa
|
||||||
|
</li>
|
||||||
|
<li>Obj 3ab
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Obj 3b
|
||||||
|
<ul>
|
||||||
|
<li>Obj 3ba
|
||||||
|
</li>
|
||||||
|
<li>Obj 3bb
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Obj 3c
|
||||||
|
<ul>
|
||||||
|
<li>Obj 3c
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Obj 3d
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
$this->assertSame($expected, $obj3->getChildrenAsUL());
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetChildrenAsUL() {
|
public function testGetChildrenAsUL() {
|
||||||
$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
|
$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
|
||||||
$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
|
$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
|
||||||
@ -574,6 +621,8 @@ class HierarchyTest_Object extends DataObject implements TestOnly {
|
|||||||
'SilverStripe\\ORM\\Versioning\\Versioned',
|
'SilverStripe\\ORM\\Versioning\\Versioned',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static $default_sort = 'Title ASC';
|
||||||
|
|
||||||
public function cmstreeclasses() {
|
public function cmstreeclasses() {
|
||||||
return $this->markingClasses();
|
return $this->markingClasses();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ HierarchyTest_Object:
|
|||||||
obj3c:
|
obj3c:
|
||||||
Parent: =>HierarchyTest_Object.obj3
|
Parent: =>HierarchyTest_Object.obj3
|
||||||
Title: Obj 3c
|
Title: Obj 3c
|
||||||
|
obj3d:
|
||||||
|
Parent: =>HierarchyTest_Object.obj3
|
||||||
|
Title: Obj 3d
|
||||||
obj2aa:
|
obj2aa:
|
||||||
Parent: =>HierarchyTest_Object.obj2a
|
Parent: =>HierarchyTest_Object.obj2a
|
||||||
Title: Obj 2aa
|
Title: Obj 2aa
|
||||||
@ -32,15 +35,21 @@ HierarchyTest_Object:
|
|||||||
obj3ab:
|
obj3ab:
|
||||||
Parent: =>HierarchyTest_Object.obj3a
|
Parent: =>HierarchyTest_Object.obj3a
|
||||||
Title: Obj 3ab
|
Title: Obj 3ab
|
||||||
|
obj3ba:
|
||||||
|
Parent: =>HierarchyTest_Object.obj3b
|
||||||
|
Title: Obj 3ba
|
||||||
|
obj3bb:
|
||||||
|
Parent: =>HierarchyTest_Object.obj3b
|
||||||
|
Title: Obj 3bb
|
||||||
|
obj3ca:
|
||||||
|
Parent: =>HierarchyTest_Object.obj3c
|
||||||
|
Title: Obj 3c
|
||||||
HierarchyHideTest_Object:
|
HierarchyHideTest_Object:
|
||||||
obj4:
|
obj4:
|
||||||
Title: Obj 4
|
Title: Obj 4
|
||||||
obj4a:
|
obj4a:
|
||||||
Parent: =>HierarchyHideTest_Object.obj4
|
Parent: =>HierarchyHideTest_Object.obj4
|
||||||
Title: Obj 4a
|
Title: Obj 4a
|
||||||
|
|
||||||
HierarchyHideTest_SubObject:
|
HierarchyHideTest_SubObject:
|
||||||
obj4b:
|
obj4b:
|
||||||
Parent: =>HierarchyHideTest_Object.obj4
|
Parent: =>HierarchyHideTest_Object.obj4
|
||||||
Title: Obj 4b
|
|
||||||
|
@ -199,6 +199,23 @@ class Requirements implements Flushable {
|
|||||||
self::backend()->themedCSS($name, $module, $media);
|
self::backend()->themedCSS($name, $module, $media);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given themeable javascript as required.
|
||||||
|
*
|
||||||
|
* A javascript file in the current theme path name 'themename/javascript/$name.js' is first searched for,
|
||||||
|
* and it that doesn't exist and the module parameter is set then a javascript file with that name in
|
||||||
|
* the module is used.
|
||||||
|
*
|
||||||
|
* @param string $name The name of the file - eg '/javascript/File.js' would have the name 'File'
|
||||||
|
* @param string $module The module to fall back to if the javascript file does not exist in the
|
||||||
|
* current theme.
|
||||||
|
* @param string $type Comma-separated list of types to use in the script tag
|
||||||
|
* (e.g. 'text/javascript,text/ecmascript')
|
||||||
|
*/
|
||||||
|
public static function themedJavascript($name, $module = null, $type = null) {
|
||||||
|
return self::backend()->themedJavascript($name, $module, $type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear either a single or all requirements
|
* Clear either a single or all requirements
|
||||||
*
|
*
|
||||||
@ -1817,10 +1834,52 @@ class Requirements_Backend
|
|||||||
return $this->css($path . $css, $media);
|
return $this->css($path . $css, $media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
if($module) {
|
"The css file doesn't exists. Please check if the file $name.css exists in any context or search for "
|
||||||
return $this->css($module . $css, $media);
|
. "themedCSS references calling this file in your templates."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given themeable javascript as required.
|
||||||
|
*
|
||||||
|
* A javascript file in the current theme path name 'themename/javascript/$name.js' is first searched for,
|
||||||
|
* and it that doesn't exist and the module parameter is set then a javascript file with that name in
|
||||||
|
* the module is used.
|
||||||
|
*
|
||||||
|
* @param string $name The name of the file - eg '/js/File.js' would have the name 'File'
|
||||||
|
* @param string $module The module to fall back to if the javascript file does not exist in the
|
||||||
|
* current theme.
|
||||||
|
* @param string $type Comma-separated list of types to use in the script tag
|
||||||
|
* (e.g. 'text/javascript,text/ecmascript')
|
||||||
|
*/
|
||||||
|
public function themedJavascript($name, $module = null, $type = null) {
|
||||||
|
$js = "/javascript/$name.js";
|
||||||
|
|
||||||
|
$opts = array(
|
||||||
|
'type' => $type,
|
||||||
|
);
|
||||||
|
|
||||||
|
$project = project();
|
||||||
|
$absbase = BASE_PATH . DIRECTORY_SEPARATOR;
|
||||||
|
$absproject = $absbase . $project;
|
||||||
|
|
||||||
|
if(file_exists($absproject . $js)) {
|
||||||
|
return $this->javascript($project . $js, $opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(SSViewer::get_themes() as $theme) {
|
||||||
|
$path = TemplateLoader::instance()->getPath($theme);
|
||||||
|
$abspath = BASE_PATH . '/' . $path;
|
||||||
|
|
||||||
|
if(file_exists($abspath . $js)) {
|
||||||
|
return $this->javascript($path . $js, $opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
"The javascript file doesn't exists. Please check if the file $name.js exists in any context or search for "
|
||||||
|
. "themedJavascript references calling this file in your templates."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user