Permalink
Browse files

Merge pull request #935 from chillu/pulls/tabs-docs

Tabs docs for CMS
  • Loading branch information...
2 parents f4a4465 + ada4210 commit 8e6ad8c856493e8da307151c1f04ab6961b7b6a9 @sminnee sminnee committed Nov 6, 2012
Showing with 137 additions and 1 deletion.
  1. +137 −1 docs/en/reference/cms-architecture.md
@@ -110,7 +110,46 @@ before the form itself is layouted with its sibling panels to avoid incorrect di
SilverStripe constructs forms and its fields within PHP,
mainly through the `[getCMSFields()](api:DataObject->getCMSFields())` method.
This in turn means that the CMS loads these forms as HTML via Ajax calls,
-e.g. after saving a record (which requires a form refresh), or switching the section in the CMS>
+e.g. after saving a record (which requires a form refresh), or switching the section in the CMS.
+
+Depending on where in the DOM hierarchy you want to use a form,
+custom templates and additional CSS classes might be required for correct operation.
+For example, the "EditForm" has specific view and logic JavaScript behaviour
+which can be enabled via adding the "cms-edit-form" class.
+In order to set the correct layout classes, we also need a custom template.
+To obey the inheritance chain, we use `$this->getTemplatesWithSuffix('_EditForm')` for
+selecting the most specific template (so `MyAdmin_EditForm.ss`, if it exists).
+
+Basic example form in a CMS controller subclass:
+
+ :::php
+ class MyAdmin extends LeftAndMain {
+ function getEditForm() {
+ $form = new Form(
+ $this,
+ 'EditForm',
+ new FieldSet(
+ TabSet::create(
+ 'Root',
+ Tab::create('Main',
+ TextField::create('MyText')
+ )
+ )->setTemplate('CMSTabset')
+ ),
+ new FieldSet(
+ FormAction::create('doSubmit')
+ )
+ );
+ // Required for correct CMS layout
+ $form->addExtraClass('cms-edit-form');
+ $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
+ return $form;
+ }
+ }
+
+Note: Usually you don't need to worry about these settings,
+and will simply call `parent::getEditForm()` to modify an existing,
+correctly configured form.
## JavaScript through jQuery.entwine
@@ -351,6 +390,103 @@ Note that a similar tree logic is also used for the
form fields to select one or more entries from those hierarchies
(`[api:TreeDropdownField]` and `[api:TreeMultiselectField]`).
+## Tabs
+
+We're using [jQuery UI tabs](http://jqueryui.com/), but in a customized fashion.
+HTML with tabs can be created either directly through HTML templates in the CMS,
+or indirectly through a `[api:TabSet]` form field. Since tabsets are useable
+outside of the CMS as well, the baseline application of tabs happens via
+a small wrapper around `jQuery.tabs()` stored in `TabSet.js`.
+
+In the CMS however, tabs need to do more: They memorize their active tab
+in the user's browser, and lazy load content via ajax once they're activated.
+
+They also need to work across different "layout containers" (see above),
+meaning a tab navigation might be in a layout header, while the tab
+content is occupied by the main content area. jQuery assumes a common
+parent in the DOM for both the tab navigation and its target DOM elements.
+In order to achieve this level of flexibility, most tabsets in the CMS
+use a custom template which leaves rendering the tab navigation to
+a separate template: `CMSMain.ss`. See the "Forms" section above
+for an example form.
+
+Here's how you would apply this template to your own tabsets used in the CMS.
+Note that you usually only need to apply it to the outermost tabset,
+since all others should render with their tab navigation inline.
+
+Form template with custom tab navigation (trimmed down):
+
+ :::ss
+ <form $FormAttributes data-layout-type="border">
+
+ <div class="cms-content-header north">
+ <% if Fields.hasTabset %>
+ <% with Fields.fieldByName('Root') %>
+ <div class="cms-content-header-tabs">
+ <ul>
+ <% loop Tabs %>
+ <li><a href="#$id">$Title</a></li>
+ <% end_loop %>
+ </ul>
+ </div>
+ <% end_with %>
+ <% end_if %>
+ </div>
+
+ <div class="cms-content-fields center">
+ <fieldset>
+ <% loop Fields %>$FieldHolder<% end_loop %>
+ </fieldset>
+ </div>
+
+ </form>
+
+Tabset template without tab navigation (e.g. `CMSTabset.ss`)
+
+ :::ss
+ <div $AttributesHTML>
+ <% loop Tabs %>
+ <% if Tabs %>
+ $FieldHolder
+ <% else %>
+ <div $AttributesHTML>
+ <% loop Fields %>
+ $FieldHolder
+ <% end_loop %>
+ </div>
+ <% end_if %>
+ <% end_loop %>
+ </div>
+
+Lazy loading works based on the `href` attribute of the tab navigation.
+The base behaviour is applied through adding a class `.cms-tabset` to a container.
+Assuming that each tab has its own URL which is tracked in the HTML5 history,
+the current tab display also has to work when loaded directly without Ajax.
+This is achieved by template conditionals (see "MyActiveCondition").
+The `.cms-panel-link` class will automatically trigger the ajax loading,
+and load the HTML content into the main view. Example:
+
+ :::ss
+ <div id="my-tab-id" class="cms-tabset" data-ignore-tab-state="true">
+ <ul>
+ <li class="<% if MyActiveCondition %> ui-tabs-active<% end_if %>">
+ <a href="admin/mytabs/tab1" class="cms-panel-link">
+ Tab1
+ </a>
+ </li>
+ <li class="<% if MyActiveCondition %> ui-tabs-active<% end_if %>">
+ <a href="admin/mytabs/tab2" class="cms-panel-link">
+ Tab2
+ </a>
+ </li>
+ </ul>
+ </div>
+
+The URL endpoints `admin/mytabs/tab1` and `admin/mytabs/tab2`
+should return HTML fragments suitable for inserting into the content area,
+through the `PjaxResponseNegotiator` class (see above).
+
+
## Related
* [Howto: Extend the CMS Interface](../howto/extend-cms-interface)

0 comments on commit 8e6ad8c

Please sign in to comment.