Merge pull request #420 from chillu/sapphire

---

See http://open.silverstripe.org/ticket/7261
This commit is contained in:
Ingo Schommer 2012-05-11 13:42:47 +02:00
commit ffbcf634bb
7 changed files with 171 additions and 1 deletions

View File

@ -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));

View File

@ -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,

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -26,6 +26,12 @@ class FieldList extends ArrayList {
*/
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) {
$items = func_get_args();
@ -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.
*/

View File

@ -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'
);
}
}