mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
Merge pull request #420 from chillu/sapphire
--- See http://open.silverstripe.org/ticket/7261
This commit is contained in:
commit
ffbcf634bb
@ -193,6 +193,17 @@
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Hide tabs when only one is available
|
||||
*/
|
||||
$('.cms-edit-form .ss-tabset').entwine({
|
||||
onmatch: function() {
|
||||
var tabs = this.find("ul:first").children('li');
|
||||
if(tabs.length == 1) this.find('ul:first').hide();
|
||||
this._super();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}(jQuery));
|
@ -326,7 +326,7 @@ The page tree moved from a bespoke tree library to [JSTree](http://jstree.com),
|
||||
which required changes to markup of the tree and its JavaScript architecture.
|
||||
This includes changes to `TreeDropdownField` and `TreeMultiSelectField`.
|
||||
|
||||
### Settings-related fields move from `SiteTree->getCMSFields()` to new `SiteTree->getSettingsFields()` [getcmsfields]###
|
||||
### Settings-related fields move from SiteTree->getCMSFields() to new SiteTree->getSettingsFields() [getcmsfields]###
|
||||
|
||||
The fields and tabs are now split into two separate forms, which required a structural
|
||||
change to the underlying class logic. In case you have added or removed fields
|
||||
@ -338,6 +338,41 @@ We've also removed the `$params` attribute on `DataObject->getCMSFields()`
|
||||
which could be used as a shortcut for customizations to `FormScaffolder`,
|
||||
in order to achieve E_STRICT compliance. Please use `FormScaffolder` directly.
|
||||
|
||||
### Changed tab paths in SiteTree->getCMSFields() {#tab-paths}
|
||||
|
||||
In order to simplify the interface, the `SiteTree->getCMSFields`
|
||||
method now only has one rather than two levels of tabs.
|
||||
This changes the tab paths, affecting any fields you might have added.
|
||||
We have also moved all fields from the "Metadata" tab into the "Main Content" tab.
|
||||
|
||||
:::php
|
||||
// 2.4
|
||||
$fields->addFieldToTab('Root.Content.Main', $myField);
|
||||
$fields->addFieldToTab('Root.Content.Metadata', $myOtherField);
|
||||
// 3.0
|
||||
$fields->addFieldToTab('Root.Main', $myField);
|
||||
$fields->addFieldToTab('Root.Main', $myOtherField);
|
||||
|
||||
![Tab paths in 2.4](_images/tab-paths-before.png)
|
||||
![Tab paths in 3.0](_images/tab-paths-after.png)
|
||||
|
||||
The old paths are rewritten automatically, but will be deprecated in the next point release.
|
||||
If you are working with tab objects directly in your `FieldSet`, you'll need to update
|
||||
the tab names manually:
|
||||
|
||||
:::php
|
||||
// 2.4
|
||||
$fields->fieldByName('Root')->fieldByName('Content')->fieldByName('Main')->push($myField);
|
||||
// 3.0
|
||||
$fields->fieldByName('Root')->fieldByName('Main')->push($myField);
|
||||
|
||||
If only a single tab is found in any CMS tabset, it is hidden by default
|
||||
to reduce UI clutter. You still need to address it through the usual tabset methods,
|
||||
as the underlying object structure doesn't change. Once you add more tabs,
|
||||
e.g. to the "Root.Main" tab in `SiteTree`, the tab bar automatically shows.
|
||||
|
||||
![Tab paths in 3.0 with a custom tab](_images/tab-paths-customtab.png)
|
||||
|
||||
### New `SiteTree::$description` field to describe purpose of a page type [sitetree-description]###
|
||||
|
||||
Please use this static property to describe the purpose of your page types,
|
||||
|
BIN
docs/en/changelogs/_images/tab-paths-after.png
Normal file
BIN
docs/en/changelogs/_images/tab-paths-after.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
docs/en/changelogs/_images/tab-paths-before.png
Normal file
BIN
docs/en/changelogs/_images/tab-paths-before.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
docs/en/changelogs/_images/tab-paths-customtab.png
Normal file
BIN
docs/en/changelogs/_images/tab-paths-customtab.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -25,6 +25,12 @@ class FieldList extends ArrayList {
|
||||
* @todo Documentation
|
||||
*/
|
||||
protected $containerField;
|
||||
|
||||
/**
|
||||
* @var array Ordered list of regular expressions,
|
||||
* see {@link setTabPathRewrites()}.
|
||||
*/
|
||||
protected $tabPathRewrites = array();
|
||||
|
||||
public function __construct($items = array()) {
|
||||
if (!is_array($items) || func_num_args() > 1) {
|
||||
@ -255,6 +261,9 @@ class FieldList extends ArrayList {
|
||||
* @return Tab The found or newly created Tab instance
|
||||
*/
|
||||
public function findOrMakeTab($tabName, $title = null) {
|
||||
// Backwards compatibility measure: Allow rewriting of outdated tab paths
|
||||
$tabName = $this->rewriteTabPath($tabName);
|
||||
|
||||
$parts = explode('.',$tabName);
|
||||
$last_idx = count($parts) - 1;
|
||||
// We could have made this recursive, but I've chosen to keep all the logic code within FieldList rather than add it to TabSet and Tab too.
|
||||
@ -291,6 +300,7 @@ class FieldList extends ArrayList {
|
||||
* @todo Implement similiarly to dataFieldByName() to support nested sets - or merge with dataFields()
|
||||
*/
|
||||
public function fieldByName($name) {
|
||||
$name = $this->rewriteTabPath($name);
|
||||
if(strpos($name,'.') !== false) list($name, $remainder) = explode('.',$name,2);
|
||||
else $remainder = null;
|
||||
|
||||
@ -555,6 +565,59 @@ class FieldList extends ArrayList {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ordered list of regular expressions
|
||||
* matching a tab path, to their rewrite rule (through preg_replace()).
|
||||
* Mainly used for backwards compatibility.
|
||||
* Ensure that more specific rules are placed earlier in the list,
|
||||
* and that tabs with children are accounted for in the rule sets.
|
||||
*
|
||||
* Example:
|
||||
* $fields->setTabPathRewriting(array(
|
||||
* // Rewrite specific innermost tab
|
||||
* '/^Root\.Content\.Main$/' => 'Root.Content',
|
||||
* // Rewrite all innermost tabs
|
||||
* '/^Root\.Content\.([^.]+)$/' => 'Root.\\1',
|
||||
* ));
|
||||
*
|
||||
* @param array $rewrites
|
||||
*/
|
||||
public function setTabPathRewrites($rewrites) {
|
||||
$this->tabPathRewrites = $rewrites;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTabPathRewrites() {
|
||||
return $this->tabPathRewrites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support function for backwards compatibility purposes.
|
||||
* Caution: Volatile API, might be removed in 3.1 or later.
|
||||
*
|
||||
* @param String $tabname Path to a tab, e.g. "Root.Content.Main"
|
||||
* @return String Rewritten path, based on {@link tabPathRewrites}
|
||||
*/
|
||||
protected function rewriteTabPath($name) {
|
||||
$isRunningTest = (class_exists('SapphireTest', false) && SapphireTest::is_running_test());
|
||||
foreach($this->getTabPathRewrites() as $regex => $replace) {
|
||||
if(preg_match($regex, $name)) {
|
||||
$newName = preg_replace($regex, $replace, $name);
|
||||
Deprecation::notice('3.0.0', sprintf(
|
||||
'Using outdated tab path "%s", please use the new location "%s" instead',
|
||||
$name,
|
||||
$newName
|
||||
));
|
||||
return $newName;
|
||||
}
|
||||
}
|
||||
|
||||
// No match found, return original path
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default template rendering of a FieldList will concatenate all FieldHolder values.
|
||||
*/
|
||||
|
@ -789,5 +789,66 @@ class FieldListTest extends SapphireTest {
|
||||
$this->assertNotNull($visible->dataFieldByName('D2'));
|
||||
}
|
||||
|
||||
function testRewriteTabPath() {
|
||||
$fields = new FieldList(
|
||||
new Tabset("Root",
|
||||
$tab1Level1 = new Tab("Tab1Level1",
|
||||
$tab1Level2 = new Tab("Tab1Level2"),
|
||||
$tab2Level2 = new Tab("Tab2Level2")
|
||||
),
|
||||
$tab2Level1 = new Tab("Tab2Level1")
|
||||
)
|
||||
);
|
||||
$fields->setTabPathRewrites(array(
|
||||
'/Root\.Tab1Level1\.([^.]+)$/' => 'Root.Tab1Level1Renamed.\\1',
|
||||
'/Root\.Tab1Level1$/' => 'Root.Tab1Level1Renamed',
|
||||
));
|
||||
$method = new ReflectionMethod($fields, 'rewriteTabPath');
|
||||
$method->setAccessible(true);
|
||||
$this->assertEquals(
|
||||
'Root.Tab1Level1Renamed',
|
||||
$method->invoke($fields, 'Root.Tab1Level1Renamed'),
|
||||
"Doesn't rewrite new name"
|
||||
);
|
||||
$this->assertEquals(
|
||||
'Root.Tab1Level1Renamed',
|
||||
$method->invoke($fields, 'Root.Tab1Level1'),
|
||||
'Direct aliasing on toplevel'
|
||||
);
|
||||
$this->assertEquals(
|
||||
'Root.Tab1Level1Renamed.Tab1Level2',
|
||||
$method->invoke($fields, 'Root.Tab1Level1.Tab1Level2'),
|
||||
'Indirect aliasing on toplevel'
|
||||
);
|
||||
}
|
||||
|
||||
function testRewriteTabPathFindOrMakeTab() {
|
||||
$fields = new FieldList(
|
||||
new Tabset("Root",
|
||||
$tab1Level1 = new Tab("Tab1Level1Renamed",
|
||||
$tab1Level2 = new Tab("Tab1Level2"),
|
||||
$tab2Level2 = new Tab("Tab2Level2")
|
||||
),
|
||||
$tab2Level1 = new Tab("Tab2Level1")
|
||||
)
|
||||
);
|
||||
$fields->setTabPathRewrites(array(
|
||||
'/Root\.Tab1Level1\.([^.]+)$/' => 'Root.Tab1Level1Renamed.\\1',
|
||||
'/Root\.Tab1Level1$/' => 'Root.Tab1Level1Renamed',
|
||||
));
|
||||
|
||||
$this->assertEquals($tab1Level1, $fields->findOrMakeTab('Root.Tab1Level1'),
|
||||
'findOrMakeTab() with toplevel tab under old name'
|
||||
);
|
||||
$this->assertEquals($tab1Level1, $fields->findOrMakeTab('Root.Tab1Level1Renamed'),
|
||||
'findOrMakeTab() with toplevel tab under new name'
|
||||
);
|
||||
$this->assertEquals($tab1Level2, $fields->findOrMakeTab('Root.Tab1Level1.Tab1Level2'),
|
||||
'findOrMakeTab() with nested tab under old parent tab name'
|
||||
);
|
||||
$this->assertEquals($tab1Level2, $fields->findOrMakeTab('Root.Tab1Level1Renamed.Tab1Level2'),
|
||||
'findOrMakeTab() with nested tab under new parent tab name'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user