ENHANCEMENT Refactored versions panel in CMS: Removed "compare mode" checkbox in UI, and replaced with explicit checkboxes and a "compare versions" button. Added manual "refresh" button. Replaced custom markup with a form generated through CMSMain->VersionsForm(), and adjusted markup in CMSMain_versions.ss accordingly

API CHANGE Removed CMSMain->sendFormToBrowser(), replaced with custom code

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92731 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2009-11-21 03:16:09 +00:00
parent 66e1d7141a
commit cb1895866a
7 changed files with 238 additions and 277 deletions

View File

@ -57,7 +57,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
'getfilteredsubtree', 'getfilteredsubtree',
'batchactions', 'batchactions',
'SearchTreeForm', 'SearchTreeForm',
'ReportForm' 'ReportForm',
'LangForm',
'VersionsForm'
); );
public function init() { public function init() {
@ -644,6 +646,7 @@ JS;
) )
); );
$form->unsetValidator(); $form->unsetValidator();
$form->setFormMethod('GET');
return $form; return $form;
} }
@ -680,20 +683,71 @@ JS;
$form = $this->ReportForm(); $form = $this->ReportForm();
return (Director::is_ajax()) ? $form->forTemplate() : $form; return (Director::is_ajax()) ? $form->forTemplate() : $form;
} }
/**
* @return Form
*/
function VersionsForm() {
$pageID = ($this->request->requestVar('ID')) ? $this->request->requestVar('ID') : $this->currentPageID();
$page = $this->getRecord($pageID);
if($page) {
$versions = $page->allVersions(
($this->request->requestVar('ShowUnpublished')) ?
"" : "\"SiteTree\".\"WasPublished\" = 1"
);
// inject link to cms
if($versions) foreach($versions as $k => $version) {
$version->CMSLink = sprintf('%s/%s/%s',
$this->Link('getversion'),
$version->ID,
$version->Version
);
}
$vd = new ViewableData();
$versionsHtml = $vd->customise(
array('Versions'=>$versions)
)->renderWith('CMSMain_versions');
} else {
$versionsHtml = '';
}
$form = new Form(
$this,
'VersionsForm',
new FieldSet(
new CheckboxField(
'ShowUnpublished',
_t('CMSMain_left.ss.SHOWUNPUB','Show unpublished versions')
),
new LiteralField('VersionsHtml', $versionsHtml),
new HiddenField('ID', false, $pageID),
new HiddenField('Locale', false, $this->Locale)
),
new FieldSet(
new FormAction(
'versions',
_t('CMSMain.BTNREFRESH','Refresh')
),
new FormAction(
'compareversions',
_t('CMSMain.BTNCOMPAREVERSIONS','Compare Versions')
)
)
);
$form->loadDataFrom($this->request->requestVars());
$form->setFormMethod('GET');
$form->unsetValidator();
return $form;
}
/** /**
* Get the versions of the current page * Get the versions of the current page
*/ */
function versions() { function versions() {
$pageID = $this->urlParams['ID']; $form = $this->VersionsForm();
$page = $this->getRecord($pageID); return (Director::is_ajax()) ? $form->forTemplate() : $form;
if($page) {
$versions = $page->allVersions($_REQUEST['unpublished'] ? "" : "\"SiteTree\".\"WasPublished\" = 1");
return array(
'Versions' => $versions,
);
} else {
return sprintf(_t('CMSMain.VERSIONSNOPAGE',"Can't find page #%d",PR_LOW),$pageID);
}
} }
/** /**
@ -752,9 +806,17 @@ JS;
return $record; return $record;
} }
/**
* Supports both direct URL links (format: admin/getversion/<page-id>/<version>),
* and through GET parameters: admin/getversion/?ID=<page-id>&Versions[]=<version>
*/
function getversion() { function getversion() {
$id = $this->urlParams['ID']; $id = ($this->request->param('ID')) ?
$version = str_replace('&ajax=1','',$this->urlParams['OtherID']); $this->request->param('ID') : $this->request->requestVar('ID');
$version = ($this->request->param('OtherID')) ?
$this->request->param('OtherID') : $this->request->requestVar('Versions');
$record = Versioned::get_version("SiteTree", $id, $version); $record = Versioned::get_version("SiteTree", $id, $version);
if($record) { if($record) {
@ -817,28 +879,28 @@ JS;
$readonlyFields = $form->Fields()->makeReadonly(); $readonlyFields = $form->Fields()->makeReadonly();
$form->setFields($readonlyFields); $form->setFields($readonlyFields);
$templateData = $this->customise(array(
"EditForm" => $form
));
SSViewer::setOption('rewriteHashlinks', false); SSViewer::setOption('rewriteHashlinks', false);
if(Director::is_ajax()) { if(Director::is_ajax()) {
$result = $templateData->renderWith($this->class . '_right'); return $form->formHtmlContent();
$parts = split('</?form[^>]*>', $result);
return $parts[sizeof($parts)-2];
} else { } else {
$templateData = $this->customise(array(
"EditForm" => $form
));
return $templateData->renderWith('LeftAndMain'); return $templateData->renderWith('LeftAndMain');
} }
} }
} }
function compareversions() { function compareversions() {
$id = (int)$this->urlParams['ID']; $id = ($this->request->param('ID')) ?
$version1 = (int)$_REQUEST['From']; $this->request->param('ID') : $this->request->requestVar('ID');
$version2 = (int)$_REQUEST['To'];
$versions = $this->request->requestVar('Versions');
$version1 = ($versions && isset($versions[0])) ?
$versions[0] : $this->request->getVar('From');
$version2 = ($versions && isset($versions[1])) ?
$versions[1] : $this->request->getVar('To');
if( $version1 > $version2 ) { if( $version1 > $version2 ) {
$toVersion = $version1; $toVersion = $version1;
@ -848,6 +910,8 @@ JS;
$fromVersion = $version1; $fromVersion = $version1;
} }
if(!$toVersion || !$toVersion) return false;
$page = DataObject::get_by_id("SiteTree", $id); $page = DataObject::get_by_id("SiteTree", $id);
if($page && !$page->canView()) return Security::permissionFailure($this); if($page && !$page->canView()) return Security::permissionFailure($this);
@ -899,23 +963,15 @@ JS;
$field->dontEscape = true; $field->dontEscape = true;
} }
return $this->sendFormToBrowser(array( if(Director::is_ajax()) {
return $form->formHtmlContent();
} else {
$templateData = $this->customise(array(
"EditForm" => $form "EditForm" => $form
)); ));
return $templateData->renderWith('LeftAndMain');
} }
} }
function sendFormToBrowser($templateData) {
if(Director::is_ajax()) {
SSViewer::setOption('rewriteHashlinks', false);
$result = $this->customise($templateData)->renderWith($this->class . '_right');
$parts = split('</?form[^>]*>', $result);
return $parts[sizeof($parts)-2];
} else {
return array(
"Right" => $this->customise($templateData)->renderWith($this->class . '_right'),
);
}
} }
/** /**

View File

@ -231,8 +231,6 @@ class LeftAndMain extends Controller {
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.Tree.js'); Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.Tree.js');
Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.EditForm.js'); Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.EditForm.js');
Requirements::javascript(CMS_DIR . '/javascript/SideTabs.js');
Requirements::themedCSS('typography'); Requirements::themedCSS('typography');
foreach (self::$extra_requirements['javascript'] as $file) { foreach (self::$extra_requirements['javascript'] as $file) {
@ -289,7 +287,6 @@ class LeftAndMain extends Controller {
array( array(
'cms/javascript/CMSMain_left.js', 'cms/javascript/CMSMain_left.js',
'cms/javascript/CMSMain_right.js', 'cms/javascript/CMSMain_right.js',
'cms/javascript/SideTabs.js',
) )
); );

View File

@ -473,6 +473,9 @@ ul.tree span.untranslated a:visited {
margin: 0 !important; margin: 0 !important;
padding: 4px 7px; padding: 4px 7px;
} }
#Form_VersionsForm td.checkbox {
}
form#SideReportForm label.left { form#SideReportForm label.left {
margin-left: 0em; margin-left: 0em;

View File

@ -261,9 +261,7 @@
/** /**
* @class Simple form with a page type dropdown * @class Simple form with a page type dropdown
* which creates a new page through #Form_EditForm and adds a new tree node. * which creates a new page through #Form_EditForm and adds a new tree node.
* @name ss.Form_AddPageOptionsForm * @name ss.reports_holder
* @requires ss.i18n
* @requires ss.reports_holder
*/ */
$('#Form_ReportForm').concrete(function($) { $('#Form_ReportForm').concrete(function($) {
return/** @lends ss.reports_holder */{ return/** @lends ss.reports_holder */{
@ -320,6 +318,129 @@
} }
}); });
return false;
}
};
});
/**
* @class Simple form showing versions of a specific page.
* @name ss.Form_VersionsForm
* @requires ss.i18n
*/
$('#Form_VersionsForm').concrete(function($) {
return/** @lends ss.Form_VersionsForm */{
onmatch: function() {
var self = this;
this.bind('submit', function(e) {
return self._submit(e);
});
// set button to be available in form submit event later on
this.find(':submit').bind('click', function(e) {
self.data('_clickedButton', this);
});
// integrate with sitetree selection changes
jQuery('#sitetree').bind('selectionchanged', function(e, data) {
self.find(':input[name=ID]').val(data.node.getIdx());
self.trigger('submit');
});
// refresh when field is selected
// TODO coupling
$('#treepanes').bind('accordionchange', function(e, ui) {
if($(ui.newContent).attr('id') == 'Form_VersionsForm') self.trigger('submit');
});
// submit when 'show unpublished versions' checkbox is changed
this.find(':input[name=ShowUnpublished]').bind('change', function(e) {
// force the refresh button, not 'compare versions'
self.data('_clickedButton', self.find(':submit[name=action_versions]'));
self.trigger('submit');
});
// move submit button to the top
this.find('#ReportClass').after(this.find('.Actions'));
// links in results
this.find('td').bind('click', function(e) {
var td = $(this);
// exclude checkboxes
if($(e.target).is(':input')) return true;
var link = $(this).siblings('.versionlink').find('a').attr('href');
td.addClass('loading');
jQuery('#Form_EditForm').concrete('ss').loadForm(
link,
function(e) {
td.removeClass('loading');
}
);
return false;
});
// compare versions action
this.find(':submit[name=action_compareversions]').bind('click', function(e) {
// validation: only allow selection of exactly two versions
var versions = self.find(':input[name=Versions[]]:checked');
if(versions.length != 2) {
alert(ss.i18n._t(
'CMSMain.VALIDATIONTWOVERSION',
'Please select two versions'
));
return false;
}
// overloaded submission: refresh the right form instead
self.data('_clickedButton', this);
self._submit(e, true);
return false;
})
},
/**
* @param {boolean} loadEditForm Determines if responses should show in current panel,
* or in the edit form (in the case of 'compare versions').
*/
_submit: function(e, loadEditForm) {
var self = this;
// Don't submit with empty ID
if(!this.find(':input[name=ID]').val()) return false;
var $button = (self.data('_clickedButton')) ? $(self.data('_clickedButton')) : this.find(':submit:first');
$button.addClass('loading');
var data = this.serializeArray();
data.push({name:$button.attr('name'), value: $button.val()});
if(loadEditForm) {
jQuery('#Form_EditForm').concrete('ss').loadForm(
this.attr('action'),
function(e) {
$button.removeClass('loading');
},
{data: data, type: 'POST'}
);
} else {
jQuery.ajax({
url: this.attr('action'),
data: data,
dataType: 'html',
success: function(data, status) {
self.replaceWith(data);
},
complete: function(xmlhttp, status) {
$button.removeClass('loading');
}
});
}
return false; return false;
} }
}; };

View File

@ -1,214 +0,0 @@
/**
* Generic base class for all side panels
*/
SidePanel = Class.create();
SidePanel.prototype = {
initialize : function() {
this.body = this.getElementsByTagName('div')[0];
},
destroy: function() {
this.body = null;
},
onshow : function() {
this.onresize();
this.body.innerHTML = '<p>loading...</p>';
this.ajaxGetPanel(this.afterPanelLoaded);
},
ajaxGetPanel : function(onComplete) {
new Ajax.Updater(this.body, this.ajaxURL(), {
onComplete : onComplete ? onComplete.bind(this) : null,
onFailure : this.ajaxPanelError
});
},
ajaxPanelError : function (response) {
errorMessage("error getting side panel", response);
},
ajaxURL : function() {
var srcName = this.id.replace('_holder','');
var id = $('Form_EditForm').elements.ID;
if(id) id = id.value; else id = "";
// This assumes that admin/cms/ refers to CMSMain
var url = 'admin/cms/' + srcName + '/' + id + '?ajax=1';
if($('Form_EditForm_Locale')) url += "&locale=" + $('Form_EditForm_Locale').value;
return url;
},
afterPanelLoaded : function() {
},
onpagechanged : function() {
}
}
SidePanelRecord = Class.create();
SidePanelRecord.prototype = {
onclick : function(event) {
Event.stop(event);
$('Form_EditForm').getPageFromServer(this.getID());
},
destroy: function() {
this.onclick = null;
},
getID : function() {
if(this.href.match(/\/([^\/]+)$/)) return parseInt(RegExp.$1);
}
}
/**
* Version list
*/
VersionList = Class.extend('SidePanel');
VersionList.prototype = {
initialize : function() {
this.mode = 'view';
this.SidePanel.initialize();
},
destroy: function() {
this.SidePanel = null;
this.onclose = null;
},
ajaxURL : function() {
return this.SidePanel.ajaxURL() + '&unpublished=' + ($('versions_showall').checked ? 1 : 0);
},
afterPanelLoaded : function() {
this.idLoaded = $('Form_EditForm').elements.ID.value;
VersionItem.applyTo('#' + this.id + ' tbody tr');
},
select : function(pageID, versionID, sourceEl) {
if(this.mode == 'view') {
sourceEl.select();
var url = 'admin/getversion/' + pageID + '/' + versionID;
if($('Form_EditForm_Locale')) url += "?locale=" + $('Form_EditForm_Locale').value;
$('Form_EditForm').loadURLFromServer(url);
$('viewArchivedSite').style.display = '';
$('viewArchivedSite').getVars = '?archiveDate=' + sourceEl.getElementsByTagName('td')[1].className;
} else {
$('viewArchivedSite').style.display = 'none';
if(this.otherVersionID) {
sourceEl.select();
this.otherSourceEl.select(true);
statusMessage('Loading comparison...');
var url = 'admin/compareversions/' + pageID + '/?From=' + this.otherVersionID + '&To=' + versionID;
if($('Form_EditForm_Locale')) url += "&locale=" + $('Form_EditForm_Locale').value;
$('Form_EditForm').loadURLFromServer(url);
} else {
sourceEl.select();
}
}
this.otherVersionID = versionID;
this.otherSourceEl = sourceEl;
},
onpagechanged : function() {
if(this.idLoaded != $('Form_EditForm').elements.ID.value) {
this.body.innerHTML = '<p>loading...</p>';
this.ajaxGetPanel(this.afterPanelLoaded);
}
},
refresh : function() {
this.ajaxGetPanel(this.afterPanelLoaded);
},
onclose : function() {
if(this.idLoaded) {
$('Form_EditForm').getPageFromServer(this.idLoaded);
}
$('viewArchivedSite').style.display = 'none';
}
}
VersionItem = Class.create();
VersionItem.prototype = {
initialize : function() {
this.holder = $('versions_holder');
},
destroy: function() {
this.holder = null;
this.onclick = null;
},
onclick : function() {
this.holder.select(this.pageID(), this.versionID(), this);
},
idPair : function() {
if(this.id.match(/page-([^-]+)-version-([^-]+)$/)) {
return RegExp.$1 + '/' + RegExp.$2;
}
},
pageID : function() {
if(this.id.match(/page-([^-]+)-version-([^-]+)$/)) {
return RegExp.$1;
}
},
versionID : function() {
if(this.id.match(/page-([^-]+)-version-([^-]+)$/)) {
return RegExp.$2;
}
}
}
VersionAction = Class.create();
VersionAction.prototype = {
initialize: function() {
this.holder = $('versions_holder');
this.showallCheckbox = $('versions_showall');
this.showallCheckbox.holder = this;
this.showallCheckbox.onclick = this.showall_change;
this.comparemodeCheckbox = $('versions_comparemode');
this.comparemodeCheckbox.holder = this;
this.comparemodeCheckbox.onclick = function() { this.holder.comparemode_change(this.checked); }
},
showall_change: function() {
this.holder.holder.refresh();
},
destroy: function() {
if(this.comparemodeCheckbox) {
this.comparemodeCheckbox.holder = null;
this.comparemodeCheckbox.onclick = null;
}
if(this.showallCheckbox) {
this.showallCheckbox.holder = null;
this.showallCheckbox.onchange = null;
}
this.holder = null;
this.comparemodeCheckbox = null;
},
/**
* Handler function when comparemode checkbox is clicked
*/
comparemode_change: function(isChecked) {
if (true == isChecked) {
return this.compare();
} else {
return this.view();
}
},
view: function() {
this.holder.mode = 'view';
},
compare: function() {
this.holder.mode = 'compare';
}
}
VersionItem.applyTo('#versions_holder tbody tr');
VersionAction.applyTo('#versions_holder p.pane_actions');
VersionList.applyTo('#versions_holder');

View File

@ -1,6 +1,7 @@
<table id="Versions"> <table id="Versions">
<thead> <thead>
<tr> <tr>
<td class="checkbox"></td>
<td>#</td> <td>#</td>
<td><% _t('WHEN','When') %></td> <td><% _t('WHEN','When') %></td>
<td><% _t('AUTHOR','Author') %></td> <td><% _t('AUTHOR','Author') %></td>
@ -10,9 +11,18 @@
<tbody> <tbody>
<% control Versions %> <% control Versions %>
<tr id="page-$RecordID-version-$Version" class="$EvenOdd $PublishedClass"> <tr id="page-$RecordID-version-$Version" class="$EvenOdd $PublishedClass">
<td>$Version</td> <td class="checkbox">
<td class="$LastEdited" title="$LastEdited.Ago - $LastEdited.Nice">$LastEdited.Ago</td> <input type="checkbox" name="Versions[]" id="Versions_$Version" value="$Version" />
<td>$Author.FirstName $Author.Surname.Initial</td> </td>
<td class="versionlink">
<a href="$CMSLink">$Version</a>
</td>
<td class="$LastEdited" title="$LastEdited.Ago - $LastEdited.Nice">
$LastEdited.Ago
</td>
<td>
$Author.FirstName $Author.Surname.Initial
</td>
<td> <td>
<% if Published %> <% if Published %>
<% if Publisher %> <% if Publisher %>

View File

@ -25,19 +25,7 @@
<a href="#"><% _t('PAGEVERSIONH','Page Version History') %></a> <a href="#"><% _t('PAGEVERSIONH','Page Version History') %></a>
</h3> </h3>
<div id="versions_holder"> <div id="versions_holder">
<p class="pane_actions" id="versions_actions"> $VersionsForm
<span class="versionChoice">
<input type="checkbox" id="versions_comparemode" /> <label for="versions_comparemode"><% _t('COMPAREMODE','Compare mode (click 2 below)') %></label>
</span>
<span class="versionChoice">
<input type="checkbox" id="versions_showall" /> <label for="versions_showall"><% _t('SHOWUNPUB','Show unpublished versions') %></label>
</span>
</p>
<div class="unitBody">
</div>
</div> </div>
<h3> <h3>