Permalink
Browse files

ENHANCEMENT New CMSPreviewable interface class to standardize metadat…

…a making a record previewable by the CMS.

ENHANCEMENT New "preview" and "edit" buttons to toggle between preview and cms views. Reinstated utility links to switch between draft and live preview (based on SilverStripeNavigator) (formerly called "AjaxSwitchView")
  • Loading branch information...
1 parent c06d52d commit 4461cae31bceef27d1e87b860067864cbf6e2777 @chillu chillu committed Jul 21, 2011
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Interface to provide enough information about a record to make it previewable
+ * through the CMS. It uses the record database ID, its "frontend" and "backend" links
+ * to link up the edit form with its preview.
+ *
+ * Also used by {@link SilverStripeNavigator} to generate links -
+ * both within the CMS preview, and as a frontend utility
+ * for logged-in CMS authors in custom themes (with the $SilverStripeNavigator template marker).
+ */
+interface CMSPreviewable {
+
+ /**
+ * @return String Absolute URL to the end-user view for this record.
+ * Example: http://mysite.com/my-record
+ */
+ function Link();
+
+ /**
+ * @return String Absolute URL to the CMS-author view. Should point to a controller subclassing {@link LeftAndMain}.
+ * Example: http://mysite.com/admin/edit/6
+ */
+ function CMSEditLink();
+
+}
View
@@ -421,11 +421,7 @@ public function show($request) {
} else {
$content = $this->renderWith($this->getViewer('show'));
}
-
- if($this->ShowSwitchView()) {
- $content .= '<div id="AjaxSwitchView">' . $this->SwitchView() . '</div>';
- }
-
+
return $content;
}
@@ -844,6 +840,13 @@ public function getEditForm($id = null, $fields = null) {
) {
$fields->push(new HiddenField('ParentID'));
}
+
+ // Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load
+ if(in_array('CMSPreviewable', class_implements($record))) {
+ $navField = new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator());
+ $navField->setAllowHTML(true);
+ $fields->push($navField);
+ }
if($record->hasMethod('getAllCMSActions')) {
$actions = $record->getAllCMSActions();
@@ -1059,6 +1062,21 @@ public function printable() {
}
/**
+ * Used for preview controls, mainly links which switch between different states of the page.
+ *
+ * @return ArrayData
+ */
+ function getSilverStripeNavigator() {
+ $page = $this->currentPage();
+ if($page) {
+ $navigator = new SilverStripeNavigator($page);
+ return $navigator->renderWith($this->getTemplatesWithSuffix('_SilverStripeNavigator'));
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Identifier for the currently shown record,
* in most cases a database ID. Inspects the following
* sources (in this order):
@@ -942,6 +942,10 @@ public function EditForm() {
$fields = $this->currentRecord->getCMSFields();
$fields->push(new HiddenField("ID"));
+ if($this->currentRecord->hasMethod('Link')) {
+ $fields->push(new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator()));
+ }
+
$validator = ($this->currentRecord->hasMethod('getCMSValidator')) ? $this->currentRecord->getCMSValidator() : new RequiredFields();
$validator->setJavascriptValidationHandler('none');
View

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -68,6 +68,14 @@
// TODO validation shouldnt need a special case
statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
}
+
+ // Move navigator to preview if one is available.
+ // If not, just leave the links in the form.
+ var previewEl = $('.cms-preview');
+ if(previewEl.length) {
+ // TODO Relies on DOM element order (the second .cms-navigator is the "old" one)
+ previewEl.find('.cms-preview-controls').html(this.find('.cms-navigator').detach());
+ }
this._super();
},
@@ -11,9 +11,8 @@
* Relies on the server responses to indicate if a preview URL is available for the currently loaded
* admin interface. If no preview is available, the panel is "blocked" automatically.
*
- * When a CMS user is logged in, all page views are redirected to the same view in the CMS,
- * with the preview window expanded. All internal links in the preview iframe are
- * automatically rewritten to point to the version without the CMS via ?cms-preview-expanded=1.
+ * Internal links within the preview iframe trigger a refresh of the admin panel as well,
+ * while all external links are disabled (via JavaScript).
*/
$('.cms-preview').entwine({
@@ -33,7 +32,6 @@
this.setSharedWidth(500);
// Create layout and controls
- this.prepend('<div class="cms-preview-toggle west"><a href="#">&laquo;</a></div>');
this.find('iframe').addClass('center');
this.layout({type: 'border'});
@@ -82,8 +80,12 @@
loadUrl: function(url) {
this.find('iframe').attr('src', url);
},
-
- loadCurrentPage: function() {
+
+ /**
+ * Loads the matching edit form for a page viewed in the preview iframe,
+ * based on metadata sent along with this document.
+ */
+ loadCurrentPage: function() {
var doc = this.find('iframe')[0].contentDocument,
containerEl = this.getLayoutContainer(),
contentEl = containerEl.find('.cms-content');
@@ -92,10 +94,12 @@
if(!contentEl.hasClass('CMSMain') || contentEl.hasClass('CMSPagesController') || contentEl.hasClass('CMSSettingsController')) return;
// Load this page in the admin interface if appropriate
- var id = $(doc).find('meta[name=x-page-id]').attr('content'), contentPanel = $('.cms-content');
+ var id = $(doc).find('meta[name=x-page-id]').attr('content'),
+ editLink = $(doc).find('meta[name=x-cms-edit-link]').attr('content'),
+ contentPanel = $('.cms-content');
// TODO Remove hardcoding
if(id && contentPanel.find(':input[name=ID]').val() != id) {
- window.History.pushState({}, '', 'admin/page/edit/show/' + id);
+ window.History.pushState({}, '', editLink);
}
},
@@ -119,9 +123,12 @@
// this.css('overflow', 'auto');
contentEl.removeClass('center').hide();
this.find('iframe').show();
- containerEl.find('.cms-menu').collapsePanel();
this.find('.cms-preview-toggle a').html('&raquo;');
- containerEl.redraw();
+ this.find('.cms-preview-controls').show();
+ containerEl.find('.cms-menu').collapsePanel();
+
+ // Already triggered through panel toggle above
+ // containerEl.redraw();
},
collapse: function() {
@@ -130,9 +137,12 @@
// this.css('overflow', 'hidden');
contentEl.addClass('center').show();
this.find('iframe').hide();
- containerEl.find('.cms-menu').expandPanel();
this.find('.cms-preview-toggle a').html('&laquo;');
- containerEl.redraw();
+ this.find('.cms-preview-controls').hide();
+ containerEl.find('.cms-menu').expandPanel();
+
+ // Already triggered through panel toggle above
+ // containerEl.redraw();
},
block: function() {
@@ -149,6 +159,9 @@
toggle: function(bool) {
this[this.hasClass('is-collapsed') ? 'expand' : 'collapse']();
+ },
+ redraw: function() {
+ this.layout();
}
});
@@ -199,5 +212,29 @@
}
}
});
+
+ $('.cms-preview .cms-preview-states').entwine({
+ onmatch: function() {
+ this.find('a').addClass('ss-ui-button');
+ this.find('.active a').addClass('ui-state-highlight');
+ }
+ });
+ $('.cms-preview .cms-preview-states a').entwine({
+ onclick: function(e) {
+ e.preventDefault();
+ this.parents('.cms-preview').loadUrl(this.attr('href'));
+ this.addClass('ui-state-highlight');
+ this.parents('.cms-preview-states').find('a').not(this).removeClass('ui-state-highlight');
+
+ }
+ });
+
+ $('.cms-preview-toggle-link').entwine({
+ onclick: function(e) {
+ e.preventDefault();
+ $('.cms-preview').toggle();
+
+ }
+ });
});
}(jQuery));
@@ -60,14 +60,17 @@
// Initialize layouts
this.redraw();
+
+ // Monitor window resizes, panel changes and edit form loads for layout changes.
+ // Also triggers redraw through handleStateChange()
$(window).resize(function() {self.redraw()});
+ $('.cms-panel').live('toggle', function() {self.redraw();});
+ $('.cms-edit-form').live('loadnewpage', function() {self.redraw()});
// Remove loading screen
$('.ss-loading-screen').hide();
$('body').removeClass('loading');
$(window).unbind('resize', positionLoadingSpinner);
-
- $('.cms-edit-form').live('loadnewpage', function() {self.redraw()});
History.Adapter.bind(window,'statechange',function(){
self.handleStateChange();
@@ -145,15 +148,6 @@
this.setCurrentXHR(xhr);
}
});
-
- /**
- * Monitor all panels for layout changes
- */
- $('.cms-panel').entwine({
- ontoggle: function(e) {
- this.parents('.cms-container').redraw();
- }
- });
/**
* Make all buttons "hoverable" with jQuery theming.
@@ -272,47 +266,6 @@
});
/**
- * Class: #switchView a
- *
- * Updates the different stage links which are generated through
- * the SilverStripeNavigator class on the serverside each time a form record
- * is reloaded.
- */
- $('#switchView').entwine({
- onmatch: function() {
- this._super();
-
- $('.cms-edit-form').bind('loadnewpage delete', function(e) {
- var updatedSwitchView = $('#AjaxSwitchView');
- if(updatedSwitchView.length) {
- $('#SwitchView').html(updatedSwitchView.html());
- updatedSwitchView.remove();
- }
- });
- }
- });
-
- /**
- * Class: #switchView a
- *
- * Links for viewing the currently loaded page
- * in different modes: 'live', 'stage' or 'archived'.
- *
- * Requires:
- * jquery.metadata
- */
- $('#switchView a').entwine({
- /**
- * Function: onclick
- */
- onclick: function(e) {
- // Open in popup
- window.open($(e.target).attr('href'));
- return false;
- }
- });
-
- /**
* Duplicates functionality in DateField.js, but due to using entwine we can match
* the DOM element on creation, rather than onclick - which allows us to decorate
* the field with a calendar icon
View
@@ -168,6 +168,21 @@ form.nostyle {
* Buttons
* ---------------------------------------------------- */
+.Actions {
+ margin-right: 80px; // Accommodate preview button
+ min-height: 30px;
+
+ & > div {
+ overflow: auto;
+ }
+}
+
+.cms-preview-toggle-link {
+ display: block;
+ float: right;
+ font-size: 11px;
+}
+
.cms {
.ui-widget {
/* loading */
@@ -194,14 +209,14 @@ form.nostyle {
background-color: $color-button-generic;
border: 1px solid $color-button-generic-border;
@include text-shadow(lighten($color-button-generic, 20%) 0 1px 1px);
-
@include box-shadow(lighten($color-base, 10%) 0 1px 2px);
@include background(image-url("../images/btn_icons_sprite.png") no-repeat 999px 999px,
linear-gradient(color-stops(
lighten($color-button-generic, 10%),
darken($color-button-generic, 5%)
))
);
+
&.ui-state-hover {
border: 1px solid darken($color-button-generic-border, 5%);
@@ -213,6 +228,7 @@ form.nostyle {
))
);
}
+
&:focus,
&:active {
border: 1px solid darken($color-button-generic-border, 5%);
@@ -225,6 +241,16 @@ form.nostyle {
))
);
}
+
+ &.ss-ui-button-small {
+ padding: ($grid-vertical/2) ($grid-horizontal/2);
+ }
+
+ &.ui-state-highlight {
+ background-color: $color-button-highlight;
+ border: 1px solid $color-button-highlight-border;
+ }
+
/* constructive */
&.ss-ui-action-constructive {
padding-left: 24px;
@@ -355,7 +381,9 @@ form.nostyle {
cursor: pointer;
padding: 0 0 0 $grid-vertical * 2;
}
+
}
+
}
/** ----------------------------------------------------
Oops, something went wrong.

0 comments on commit 4461cae

Please sign in to comment.