From d90ea0d236169fcccf7bc348db35e2e50302dd65 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Fri, 19 Aug 2011 12:32:31 +1200 Subject: [PATCH 1/7] ENHANCEMENT: implemented CMSPageHistoryController with comparsion view, single version view into new CMSMain API. --- code/controller/CMSPageHistoryController.php | 12 - .../AssetAdmin.php | 0 code/{controller => controllers}/CMSMain.php | 298 +--------------- .../CMSPageEditController.php | 0 code/controllers/CMSPageHistoryController.php | 322 ++++++++++++++++++ .../CMSPageReportsController.php | 0 .../CMSPageSettingsController.php | 8 +- .../CMSPagesController.php | 12 +- .../CMSSettingsController.php | 0 .../CMSSiteTreeFilter.php | 0 .../ContentController.php | 0 .../ModelAsController.php | 0 .../NestedController.php | 0 .../ReportAdmin.php | 0 .../RootURLController.php | 0 .../StaticExporter.php | 0 css/CMSMain.css | 5 + javascript/CMSMain.EditForm.js | 26 -- javascript/CMSMain.js | 128 ------- javascript/CMSPageHistoryController.js | 163 +++++++++ scss/CMSMain.scss | 31 ++ templates/CMSMain_versions.ss | 40 --- .../CMSPageHistoryController_versions.ss | 23 ++ .../CMSPageHistoryController_Content.ss | 16 +- .../CMSPageReportsController_Content.ss | 3 - .../Includes/CMSPagesController_Content.ss | 4 +- 26 files changed, 592 insertions(+), 499 deletions(-) delete mode 100644 code/controller/CMSPageHistoryController.php rename code/{controller => controllers}/AssetAdmin.php (100%) rename code/{controller => controllers}/CMSMain.php (81%) rename code/{controller => controllers}/CMSPageEditController.php (100%) create mode 100644 code/controllers/CMSPageHistoryController.php rename code/{controller => controllers}/CMSPageReportsController.php (100%) rename code/{controller => controllers}/CMSPageSettingsController.php (92%) rename code/{controller => controllers}/CMSPagesController.php (88%) rename code/{controller => controllers}/CMSSettingsController.php (100%) rename code/{controller => controllers}/CMSSiteTreeFilter.php (100%) rename code/{controller => controllers}/ContentController.php (100%) rename code/{controller => controllers}/ModelAsController.php (100%) rename code/{controller => controllers}/NestedController.php (100%) rename code/{controller => controllers}/ReportAdmin.php (100%) rename code/{controller => controllers}/RootURLController.php (100%) rename code/{controller => controllers}/StaticExporter.php (100%) create mode 100644 javascript/CMSPageHistoryController.js delete mode 100644 templates/CMSMain_versions.ss create mode 100755 templates/CMSPageHistoryController_versions.ss delete mode 100644 templates/Includes/CMSPageReportsController_Content.ss diff --git a/code/controller/CMSPageHistoryController.php b/code/controller/CMSPageHistoryController.php deleted file mode 100644 index 2a1c38d2..00000000 --- a/code/controller/CMSPageHistoryController.php +++ /dev/null @@ -1,12 +0,0 @@ -forTemplate(); } + /** - * Get a database record to be managed by the CMS + * Get a database record to be managed by the CMS. + * + * @param int $id Record ID + * @param int $versionID optional Version id of the given record */ - public function getRecord($id) { + public function getRecord($id, $versionID = null) { $treeClass = $this->stat('tree_class'); if($id instanceof $treeClass) { return $id; } else if($id && is_numeric($id)) { - $version = isset($_REQUEST['Version']) ? $_REQUEST['Version'] : null; - if(is_numeric($version)) { + $versionID = null; + + if(isset($_REQUEST['Version'])) $versionID = (int) $_REQUEST['Version']; + + if($versionID && is_int($version)) { $record = Versioned::get_version($treeClass, $id, $version); } else { $record = DataObject::get_one($treeClass, "\"$treeClass\".\"ID\" = $id"); @@ -470,7 +475,7 @@ JS; $readonlyFields = $form->Fields()->makeReadonly(); $form->setFields($readonlyFields); } - + $this->extend('updateEditForm', $form); return $form; @@ -909,100 +914,6 @@ JS; } } - /** - * @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 - */ - function versions() { - $form = $this->VersionsForm(); - return (Director::is_ajax()) ? $form->forTemplate() : $form; - } - - /** - * Roll a page back to a previous version - */ - function rollback($data, $form) { - $this->extend('onBeforeRollback', $data['ID']); - - if(isset($data['Version']) && (bool)$data['Version']) { - $record = $this->performRollback($data['ID'], $data['Version']); - $message = sprintf( - _t('CMSMain.ROLLEDBACKVERSION',"Rolled back to version #%d. New version number is #%d"), - $data['Version'], - $record->Version - ); - } else { - $record = $this->performRollback($data['ID'], "Live"); - $message = sprintf( - _t('CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #%d"), - $record->Version - ); - } - - $this->response->addHeader('X-Status', $message); - - $form = $this->getEditForm($record->ID); - - return $form->forTemplate(); - } - function publish($data, $form) { $data['publish'] = '1'; @@ -1036,179 +947,6 @@ JS; return $record; } - /** - * Supports both direct URL links (format: admin/getversion//), - * and through GET parameters: admin/getversion/?ID=&Versions[]= - */ - function getversion() { - $id = ($this->request->param('ID')) ? - $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); - - if($record) { - if($record && !$record->canView()) return Security::permissionFailure($this); - $fields = $record->getCMSFields($this); - $fields->removeByName("Status"); - - $fields->push(new HiddenField("ID")); - $fields->push(new HiddenField("Version")); - - $versionAuthor = DataObject::get_by_id('Member', $record->AuthorID); - if(!$versionAuthor) $versionAuthor = new ArrayData(array('Title' => 'Unknown author')); - $fields->insertBefore( - new LiteralField( - 'YouAreViewingHeader', - '

' . - sprintf( - _t( - 'CMSMain.VIEWING', - "You are viewing version #%s, created %s by %s", - PR_MEDIUM, - 'Version number is a linked string, created is a relative time (e.g. 2 days ago), by a specific author' - ), - "ID/$version\" title=\"" . ($versionAuthor ? $versionAuthor->Title : '') . "\">$version", - $record->obj('LastEdited')->Ago(), - ($versionAuthor ? $versionAuthor->Title : '') - ) . - '

' - ), - 'Root' - ); - - $actions = $record->getCMSActions(); - - // encode the message to appear in the body of the email - $archiveURL = Director::absoluteBaseURL() . $record->URLSegment . '?archiveDate=' . $record->obj('LastEdited')->URLDatetime(); - - // Ensure that source file comments are disabled - SSViewer::set_source_file_comments(false); - - $archiveEmailMessage = urlencode( $this->customise( array( 'ArchiveDate' => $record->obj('LastEdited'), 'ArchiveURL' => $archiveURL ) )->renderWith( 'ViewArchivedEmail' ) ); - $archiveEmailMessage = preg_replace( '/\+/', '%20', $archiveEmailMessage ); - - $fields->push( new HiddenField( 'ArchiveEmailMessage', '', $archiveEmailMessage ) ); - $fields->push( new HiddenField( 'ArchiveEmailSubject', '', preg_replace( '/\+/', '%20', urlencode( 'Archived version of ' . $record->Title ) ) ) ); - $fields->push( new HiddenField( 'ArchiveURL', '', $archiveURL ) ); - - $form = new Form($this, "EditForm", $fields, $actions); - $form->loadDataFrom($record); - $form->loadDataFrom(array( - "ID" => $id, - "Version" => $version, - )); - - // historical version shouldn't be editable - $readonlyFields = $form->Fields()->makeReadonly(); - $form->setFields($readonlyFields); - - $templateData = $this->customise(array( - "EditForm" => $form - )); - - SSViewer::setOption('rewriteHashlinks', false); - - if(Director::is_ajax()) { - $result = $templateData->renderWith(array($this->class . '_right', 'LeftAndMain_right')); - $parts = split(']*>', $result); - $content = $parts[sizeof($parts)-2]; - if($this->ShowSwitchView()) { - $content .= '
' . $this->SwitchView($record) . '
'; - } - return $content; - } else { - return $templateData->renderWith('LeftAndMain'); - } - } - } - - function compareversions() { - $id = ($this->request->param('ID')) ? - $this->request->param('ID') : $this->request->requestVar('ID'); - - $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 ) { - $toVersion = $version1; - $fromVersion = $version2; - } else { - $toVersion = $version2; - $fromVersion = $version1; - } - - if(!$toVersion || !$toVersion) return false; - - $page = DataObject::get_by_id("SiteTree", $id); - if($page && !$page->canView()) return Security::permissionFailure($this); - - $record = $page->compareVersions($fromVersion, $toVersion); - - $fromVersionRecord = Versioned::get_version('SiteTree', $id, $fromVersion); - $toVersionRecord = Versioned::get_version('SiteTree', $id, $toVersion); - if(!$fromVersionRecord) user_error("Can't find version $fromVersion of page $id", E_USER_ERROR); - if(!$toVersionRecord) user_error("Can't find version $toVersion of page $id", E_USER_ERROR); - - if($record) { - $fromDateNice = $fromVersionRecord->obj('LastEdited')->Ago(); - $toDateNice = $toVersionRecord->obj('LastEdited')->Ago(); - $fromAuthor = DataObject::get_by_id('Member', $fromVersionRecord->AuthorID); - if(!$fromAuthor) $fromAuthor = new ArrayData(array('Title' => 'Unknown author')); - $toAuthor = DataObject::get_by_id('Member', $toVersionRecord->AuthorID); - if(!$toAuthor) $toAuthor = new ArrayData(array('Title' => 'Unknown author')); - - $fields = $record->getCMSFields($this); - $fields->push(new HiddenField("ID")); - $fields->push(new HiddenField("Version")); - $fields->insertBefore( - new LiteralField( - 'YouAreComparingHeader', - '

' . - sprintf( - _t('CMSMain.COMPARINGV',"Comparing versions %s and %s"), - "Version\" title=\"$fromAuthor->Title\">$fromVersionRecord->Version ($fromDateNice)", - "Version\" title=\"$toAuthor->Title\">$toVersionRecord->Version ($toDateNice)" - ) . - '

' - ), - "Root" - ); - - $actions = new FieldSet(); - - $form = new Form($this, "EditForm", $fields, $actions); - $form->loadDataFrom($record); - $form->loadDataFrom(array( - "ID" => $id, - "Version" => $fromVersion, - )); - $form->addExtraClass('compare'); - - // comparison views shouldn't be editable - $readonlyFields = $form->Fields()->makeReadonly(); - $form->setFields($readonlyFields); - - foreach($form->Fields()->dataFields() as $field) { - $field->dontEscape = true; - } - - if($this->isAjax()) { - return $form->forTemplate(); - } else { - $templateData = $this->customise(array( - "EditForm" => $form - )); - return $templateData->renderWith('LeftAndMain'); - } - } - } - function sendFormToBrowser($templateData) { if(Director::is_ajax()) { SSViewer::setOption('rewriteHashlinks', false); diff --git a/code/controller/CMSPageEditController.php b/code/controllers/CMSPageEditController.php similarity index 100% rename from code/controller/CMSPageEditController.php rename to code/controllers/CMSPageEditController.php diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php new file mode 100644 index 00000000..00b28764 --- /dev/null +++ b/code/controllers/CMSPageHistoryController.php @@ -0,0 +1,322 @@ + 'handleAction' + ); + + /** + * @var array + */ + function version() { + return array( + 'EditForm' => $this->ShowVersionForm( + $this->request->param('ID') + ) + ); + } + + /** + * @var array + */ + function compare() { + return array( + 'EditForm' => $this->CompareVersionsForm( + $this->request->param('VersionID'), + $this->request->param('OtherVersionID') + ) + ); + } + + /** + * Returns the read only version of the edit form. Detaches {@link FormAction} + * instances attached since only action relates to revert. + * + * Permission checking is done at the {@link CMSMain::getEditForm()} level. + * + * @param int $id ID of the record to show + * @param array $fields optional + * @param int $versionID + */ + function getEditForm($id = null, $fields = null, $versionID = null) { + $record = $this->getRecord($id, $versionID); + + $form = parent::getEditForm($record, ($record) ? $record->getCMSFields() : null); + + $fields = $form->Fields(); + $fields->removeByName("Status"); + $fields->push(new HiddenField("ID")); + $fields->push(new HiddenField("Version")); + + $fields = $fields->makeReadonly(); + + foreach($fields->dataFields() as $field) { + $field->dontEscape = true; + } + + $form->setFields($fields->makeReadonly()); + + // attach additional information + $form->loadDataFrom(array( + "ID" => $id, + "Version" => $versionID, + )); + + $form->setActions(new FieldSet( + $revert = new FormAction('doRevert', _t('CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')) + )); + + $form->removeExtraClass('cms-content'); + + return $form; + } + + /** + * Compare version selection form. Displays a list of previous versions + * and options for selecting filters on the version + * + * @return Form + */ + function VersionsForm() { + $id = $this->currentPageID(); + $page = $this->getRecord($id); + $versionsHtml = ''; + + if($page) { + $versions = $page->allVersions(); + + if($versions) { + foreach($versions as $k => $version) { + $version->CMSLink = sprintf('%s/%s/%s', + $this->Link('version'), + $version->ID, + $version->Version + ); + } + } + + $vd = new ViewableData(); + + $versionsHtml = $vd->customise(array( + 'Versions' => $versions + ))->renderWith('CMSPageHistoryController_versions'); + } + + $form = new Form( + $this, + 'VersionsForm', + new FieldSet( + new CheckboxField( + 'ShowUnpublished', + _t('CMSPageHistoryController.SHOWUNPUBLISHED','Show unpublished versions') + ), + new CheckboxField( + 'CompareMode', + _t('CMSPageHistoryController.COMPAREMODE', 'Compare mode') + ), + new LiteralField('VersionsHtml', $versionsHtml), + new HiddenField('ID', false, $id) + ), + new FieldSet( + new FormAction( + 'doCompare', _t('CMSPageHistoryController.COMPAREVERSIONS','Compare Versions') + ), + new FormAction( + 'doShowVersion', _t('CMSPageHistoryController.SHOWVERSION','Show Version') + ) + ) + ); + + $form->loadDataFrom($this->request->requestVars()); + $form->unsetValidator(); + + return $form; + } + + /** + * Process the {@link VersionsForm} compare function between two pages. + * + * @param array + * @param Form + * + * @return html + */ + function doCompare($data, $form) { + $versions = $data['Versions']; + if(count($versions) < 2) return null; + + $id = $this->currentPageID(); + $version1 = array_shift($versions); + $version2 = array_shift($versions); + + $form = $this->CompareVersionsForm($version1, $version2); + + // javascript solution, render into template + if($this->isAjax()) { + return $this->customise(array( + "EditForm" => $form + ))->renderWith(array( + $this->class . '_EditForm', + 'LeftAndMain_Content' + )); + } + + // non javascript, redirect the user to the page + $this->redirect(Controller::join_links( + $this->Link('compare'), + $version1, + $version2 + )); + } + + /** + * Process the {@link VersionsForm} show version function. Only requires + * one page to be selected. + * + * @param array + * @param Form + * + * @return html + */ + function doShowVersion($data, $form) { + $versionID = null; + + if(isset($data['Versions']) && is_array($data['Versions'])) { + $versionID = array_shift($data['Versions']); + } + + if(!$versionID) return; + + if($this->isAjax()) { + return $this->customise(array( + "EditForm" => $this->ShowVersionForm($versionID) + ))->renderWith(array( + $this->class . '_EditForm', + 'LeftAndMain_Content' + )); + } + + // non javascript, redirect the user to the page + $this->redirect(Controller::join_links( + $this->Link('version'), + $versionID + )); + } + + /** + * Rolls a site back to a given version ID + * + * @param array + * @param Form + * + * @return html + */ + function doRollback($data, $form) { + // + } + + /** + * @return Form + */ + function ShowVersionForm($versionID = null) { + if(!$versionID) return null; + + $id = $this->currentPageID(); + $form = $this->getEditForm($id, null, $versionID); + + return $form; + } + + /** + * @return Form + */ + function CompareVersionsForm($versionID, $otherVersionID) { + if($versionID > $otherVersionID) { + $toVersion = $versionID; + $fromVersion = $otherVersionID; + } else { + $toVersion = $otherVersionID; + $fromVersion = $versionID; + } + + if(!$toVersion || !$toVersion) return false; + + $id = $this->currentPageID(); + $page = DataObject::get_by_id("SiteTree", $id); + + if($page && !$page->canView()) { + return Security::permissionFailure($this); + } + + $record = $page->compareVersions($fromVersion, $toVersion); + + $fromVersionRecord = Versioned::get_version('SiteTree', $id, $fromVersion); + $toVersionRecord = Versioned::get_version('SiteTree', $id, $toVersion); + + if(!$fromVersionRecord) { + user_error("Can't find version $fromVersion of page $id", E_USER_ERROR); + } + + if(!$toVersionRecord) { + user_error("Can't find version $toVersion of page $id", E_USER_ERROR); + } + + if($record) { + $form = $this->getEditForm($id, null, null); + $form->setActions(new FieldSet()); + $form->loadDataFrom($record); + + $form->loadDataFrom(array( + "ID" => $id, + "Version" => $fromVersion, + )); + + $form->addExtraClass('compare'); + + return $form; + } + } + + /** + * Roll a page back to a previous version + */ + function rollback($data, $form) { + $this->extend('onBeforeRollback', $data['ID']); + + if(isset($data['Version']) && (bool)$data['Version']) { + $record = $this->performRollback($data['ID'], $data['Version']); + $message = sprintf( + _t('CMSMain.ROLLEDBACKVERSION',"Rolled back to version #%d. New version number is #%d"), + $data['Version'], + $record->Version + ); + } else { + $record = $this->performRollback($data['ID'], "Live"); + $message = sprintf( + _t('CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #%d"), + $record->Version + ); + } + + $this->response->addHeader('X-Status', $message); + $form = $this->getEditForm($record->ID); + + return $form->forTemplate(); + } +} \ No newline at end of file diff --git a/code/controller/CMSPageReportsController.php b/code/controllers/CMSPageReportsController.php similarity index 100% rename from code/controller/CMSPageReportsController.php rename to code/controllers/CMSPageReportsController.php diff --git a/code/controller/CMSPageSettingsController.php b/code/controllers/CMSPageSettingsController.php similarity index 92% rename from code/controller/CMSPageSettingsController.php rename to code/controllers/CMSPageSettingsController.php index dc19a2cd..cf359880 100644 --- a/code/controller/CMSPageSettingsController.php +++ b/code/controllers/CMSPageSettingsController.php @@ -1,13 +1,19 @@ getRecord($id ? $id : $this->currentPageID()); + return parent::getEditForm($record, ($record) ? $record->getSettingsFields() : null); } - } \ No newline at end of file diff --git a/code/controller/CMSPagesController.php b/code/controllers/CMSPagesController.php similarity index 88% rename from code/controller/CMSPagesController.php rename to code/controllers/CMSPagesController.php index db7e66b0..8370d3a9 100644 --- a/code/controller/CMSPagesController.php +++ b/code/controllers/CMSPagesController.php @@ -1,4 +1,8 @@ param('ID')) { $c = new CMSPageEditController(); return $this->redirect(Controller::join_links($c->Link('show'), $request->param('ID'))); - } else { - return parent::show($request); } + + return parent::show($request); } function Link($action = null) { // Special case: All show links should redirect to the page edit interface instead (mostly from tree nodes) if(preg_match('/^show/', $action)) { return singleton('CMSPageEditController')->Link($action); - } else { - return parent::Link($action); } + + return parent::Link($action); } } \ No newline at end of file diff --git a/code/controller/CMSSettingsController.php b/code/controllers/CMSSettingsController.php similarity index 100% rename from code/controller/CMSSettingsController.php rename to code/controllers/CMSSettingsController.php diff --git a/code/controller/CMSSiteTreeFilter.php b/code/controllers/CMSSiteTreeFilter.php similarity index 100% rename from code/controller/CMSSiteTreeFilter.php rename to code/controllers/CMSSiteTreeFilter.php diff --git a/code/controller/ContentController.php b/code/controllers/ContentController.php similarity index 100% rename from code/controller/ContentController.php rename to code/controllers/ContentController.php diff --git a/code/controller/ModelAsController.php b/code/controllers/ModelAsController.php similarity index 100% rename from code/controller/ModelAsController.php rename to code/controllers/ModelAsController.php diff --git a/code/controller/NestedController.php b/code/controllers/NestedController.php similarity index 100% rename from code/controller/NestedController.php rename to code/controllers/NestedController.php diff --git a/code/controller/ReportAdmin.php b/code/controllers/ReportAdmin.php similarity index 100% rename from code/controller/ReportAdmin.php rename to code/controllers/ReportAdmin.php diff --git a/code/controller/RootURLController.php b/code/controllers/RootURLController.php similarity index 100% rename from code/controller/RootURLController.php rename to code/controllers/RootURLController.php diff --git a/code/controller/StaticExporter.php b/code/controllers/StaticExporter.php similarity index 100% rename from code/controller/StaticExporter.php rename to code/controllers/StaticExporter.php diff --git a/css/CMSMain.css b/css/CMSMain.css index e69de29b..cf6b0185 100644 --- a/css/CMSMain.css +++ b/css/CMSMain.css @@ -0,0 +1,5 @@ +/** Style custom to the CMSMain admin interface. CMSMain extends the built in sapphire admin section styles. As much as possible we want to use those built in styles. If anything in this file can be implemented in a generic way then it should be include in the admin scss files. @package cms */ +/** ------------------------------------------------------------------ Page History Section. ----------------------------------------------------------------- */ +#cms-page-history-versions tr.loading { color: #999; } +#cms-page-history-versions tr.loading td:hover { cursor: none; } +#cms-page-history-versions td:hover { cursor: pointer; } diff --git a/javascript/CMSMain.EditForm.js b/javascript/CMSMain.EditForm.js index 89762551..85b9305a 100644 --- a/javascript/CMSMain.EditForm.js +++ b/javascript/CMSMain.EditForm.js @@ -194,32 +194,6 @@ } }); - /** - * Class: .cms-edit-form .Actions #Form_EditForm_action_email - * - * Email containing the link to the archived version of the page. - * Visible on readonly older versions of a specific page at the moment. - */ - $('.cms-edit-form .Actions #Form_EditForm_action_email').entwine({ - /** - * Function: onclick - * - * Parameters: - * (Event) e - */ - onclick: function(e) { - window.open( - 'mailto:?subject=' - + $('input[name=ArchiveEmailSubject]', this[0].form).val() - + '&body=' - + $(':input[name=ArchiveEmailMessage]', this[0].form).val(), - 'archiveemail' - ); - - return false; - } - }); - /** * Class: .cms-edit-form .Actions #Form_EditForm_action_print * diff --git a/javascript/CMSMain.js b/javascript/CMSMain.js index 5e048d6a..8fc1e8b2 100644 --- a/javascript/CMSMain.js +++ b/javascript/CMSMain.js @@ -213,133 +213,5 @@ return false; } }); - - /** - * Class: #Form_VersionsForm - * - * Simple form showing versions of a specific page. - */ - $('#Form_VersionsForm').entwine({ - onmatch: function() { - var self = this; - - // set button to be available in form submit event later on - this.find(':submit').bind('click', function(e) { - self.data('_clickedButton', this); - }); - - this.bind('submit', function(e) { - return self._submit(); - }); - - // integrate with sitetree selection changes - jQuery('.cms-tree').bind('select_node.jstree', function(e, data) { - var node = data.rslt.obj; - self.find(':input[name=ID]').val(node ? $(node).data('id') : null); - if(self.is(':visible')) 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('.cms-content').entwine('ss').loadForm( - link, - null, - 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(true); - - return false; - }); - - this._super(); - }, - - /** - * Function: _submit - * - * Parameters: - * (bool) loadEditForm - Determines if responses should show in current panel, - * or in the edit form (in the case of 'compare versions'). - */ - _submit: function(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('.cms-content').entwine('ss').loadForm( - this.attr('action'), - null, - 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; - } - }); }); })(jQuery); \ No newline at end of file diff --git a/javascript/CMSPageHistoryController.js b/javascript/CMSPageHistoryController.js new file mode 100644 index 00000000..b739fa83 --- /dev/null +++ b/javascript/CMSPageHistoryController.js @@ -0,0 +1,163 @@ +(function($) { + /** + * File: CMSPageHistoryController.js + * + * Handles related interactions between the version selection form on the + * left hand side of the panel and the version displaying on the right + * hand side. + */ + + $.entwine('ss', function($){ + /** + * Class: #Form_VersionsForm + * + * The left hand side version selection form is the main interface for + * users to select a version to view, or to compare two versions + */ + $('#Form_VersionsForm').entwine({ + /** + * Constructor + */ + onmatch: function() { + var self = this; + + /** + * Event: :input[name=ShowUnpublished] change + * + * Changing the show unpublished checkbox toggles whether to show + * or hide the unpublished versions. Because those rows may be being + * compared this also ensures those rows are unselected. + */ + this.find(':input[name=ShowUnpublished]').bind('change', function(e) { + if($(this).attr("checked")) { + self.find("tr[data-published=false]").show(); + } + else { + self.find("tr[data-published=false]").hide()._unselect(); + } + }); + + this._super(); + }, + /** + * Function: submit. + * + * Submits either the compare versions form or the view single form + * display based on whether we have two or 1 option selected + */ + onsubmit: function(e, d) { + var id, self = this; + id = this.find(':input[name=ID]').val(); + + if(!id) return false; + + var button, url, selected, to, from, compare; + + compare = (this.find(":input[name=CompareMode]").is(":checked")); + selected = this.find("table input[type=checkbox]").filter(":checked"); + + if(compare) { + if(selected.length != 2) return false; + + to = selected.eq(0).val(); + from = selected.eq(1).val(); + button = this.find(':submit[name=action_doCompare]'); + url = 'admin/page/history/compare/'+ [id,from,to].join('/') +"/"; + } + else { + to = selected.eq(0).val(); + button = this.find(':submit[name=action_doShowVersion]'); + url = 'admin/page/history/version/'+ [id,to].join('/') + "/"; + } + + // we can access this comparsion directly in the url. + window.History.pushState({selector: '.cms-content-fields form:first'}, '', url); + + var data = this.serializeArray(); + + data.push({ + name: button.attr('name'), value: button.val() + }); + + $('.cms-content').loadForm(this.attr('action'), null, function() {}, { + data: data, type: this.attr('method') + }); + + return false; + } + }); + + /** + * Class: #Form_VersionsForm tr + * + * An individual row in the versions form. Selecting the row updates + * the edit form depending on whether we're showing individual version + * information or displaying comparsion. + */ + $("#Form_VersionsForm tbody tr").entwine({ + + /** + * Function: onclick + * + * Selects or deselects the row (if in compare mode). Will trigger + * an update of the edit form if either selected (in single mode) + * or if this is the second row selected (in compare mode) + */ + onclick: function(e) { + var compare, selected; + + // compare mode + compare = this.parents("form").find(':input[name=CompareMode]').attr("checked"), + selected = this.siblings(".active"); + + if(compare && this.hasClass('active')) { + this._unselect(); + + return; + } + else if(compare) { + // check if we have already selected more than two. + if(selected.length > 1) { + return alert(ss.i18n._t('ONLYSELECTTWO', 'Can only compare two versions at at time.')); + } + + this._select(); + + // if this is the second selected then we can compare. + if(selected.length == 1) { + this.parents('form').submit(); + } + + return; + } + else { + this._select(); + selected._unselect(); + + this.parents("form").submit(); + } + }, + + /** + * Function: _unselect() + * + * Unselects the row from the form selection. + */ + _unselect: function() { + this.removeClass('active'); + this.find(":input[type=checkbox]").attr("checked", false); + }, + + /** + * Function: _select() + * + * Selects the currently matched row in the form selection + */ + _select: function() { + this.addClass('active'); + this.find(":input[type=checkbox]").attr("checked", true); + } + + }) + }); +})(jQuery); \ No newline at end of file diff --git a/scss/CMSMain.scss b/scss/CMSMain.scss index e69de29b..3402d063 100644 --- a/scss/CMSMain.scss +++ b/scss/CMSMain.scss @@ -0,0 +1,31 @@ +/** + * Style custom to the CMSMain admin interface. CMSMain extends the built in + * sapphire admin section styles. As much as possible we want to use those + * built in styles. If anything in this file can be implemented in a generic + * way then it should be include in the admin scss files. + * + * @package cms + */ + +/** ------------------------------------------------------------------ + * Page History Section. + * ----------------------------------------------------------------- */ +#cms-page-history-versions { + tr { + &.loading { + color: #999; + + td { + + &:hover { + cursor: none; + } + } + } + } + td { + &:hover { + cursor: pointer; + } + } +} \ No newline at end of file diff --git a/templates/CMSMain_versions.ss b/templates/CMSMain_versions.ss deleted file mode 100644 index cbddc48d..00000000 --- a/templates/CMSMain_versions.ss +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - <% control Versions %> - - - - - - - - <% end_control %> - -
#<% _t('WHEN','When') %><% _t('AUTHOR','User') %><% _t('PUBR','Publisher') %>
- - - $LastEdited.Ago - - $Author.FirstName $Author.Surname.Initial - - <% if Published %> - <% if Publisher %> - $Publisher.FirstName $Publisher.Surname.Initial - <% else %> - <% _t('UNKNOWN','Unknown') %> - <% end_if %> - <% else %> - <% _t('NOTPUB','Not published') %> - <% end_if %> -
\ No newline at end of file diff --git a/templates/CMSPageHistoryController_versions.ss b/templates/CMSPageHistoryController_versions.ss new file mode 100755 index 00000000..1337b255 --- /dev/null +++ b/templates/CMSPageHistoryController_versions.ss @@ -0,0 +1,23 @@ + + + + + + + + + + + + <% control Versions %> + + + <% control LastEdited %> + + <% end_control %> + + + + <% end_control %> + +
<% _t('WHEN','When') %><% _t('AUTHOR','Author') %><% _t('PUBLISHER','Publisher') %>
$Nice<% if Author %>$Author.FirstName $Author.Surname.Initial<% else %><% _t('UNKNOWN','Unknown') %><% end_if %><% if Published %><% if Publisher %>$Publisher.FirstName $Publisher.Surname.Initial<% else %><% _t('UNKNOWN','Unknown') %><% end_if %><% else %><% _t('NOTPUBLISHED','Not published') %><% end_if %>
\ No newline at end of file diff --git a/templates/Includes/CMSPageHistoryController_Content.ss b/templates/Includes/CMSPageHistoryController_Content.ss index 7e0037f2..40a64133 100644 --- a/templates/Includes/CMSPageHistoryController_Content.ss +++ b/templates/Includes/CMSPageHistoryController_Content.ss @@ -1,3 +1,15 @@ -
- Not implemented yet +
+
+
+
+

<% _t('CMSPageHistoryController.History','History') %>

+
+
+ +
+ $VersionsForm +
+
+ + $EditForm
\ No newline at end of file diff --git a/templates/Includes/CMSPageReportsController_Content.ss b/templates/Includes/CMSPageReportsController_Content.ss deleted file mode 100644 index 7e0037f2..00000000 --- a/templates/Includes/CMSPageReportsController_Content.ss +++ /dev/null @@ -1,3 +0,0 @@ -
- Not implemented yet -
\ No newline at end of file diff --git a/templates/Includes/CMSPagesController_Content.ss b/templates/Includes/CMSPagesController_Content.ss index 25cb2790..5c2c6a39 100644 --- a/templates/Includes/CMSPagesController_Content.ss +++ b/templates/Includes/CMSPagesController_Content.ss @@ -22,13 +22,11 @@
-

Filter

+

<% _t('FILTER', 'Filter') %>

$SearchForm
- -
From f81531115fa9852e7c37425a8f52460cc4b25ac5 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Fri, 26 Aug 2011 14:03:21 +1200 Subject: [PATCH 2/7] ENHANCEMENT: added notice template for outputting notices to cmsmain interfaces. --- code/controllers/CMSMain.php | 6 +- code/controllers/CMSPageHistoryController.php | 109 ++++++++++++++---- javascript/CMSPageHistoryController.js | 2 +- templates/CMSMain_notice.ss | 3 + .../CMSPageHistoryController_versions.ss | 4 +- 5 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 templates/CMSMain_notice.ss diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 0a5aa706..027928b1 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -358,12 +358,10 @@ JS; if($id instanceof $treeClass) { return $id; } else if($id && is_numeric($id)) { - $versionID = null; - if(isset($_REQUEST['Version'])) $versionID = (int) $_REQUEST['Version']; - if($versionID && is_int($version)) { - $record = Versioned::get_version($treeClass, $id, $version); + if($versionID) { + $record = Versioned::get_version($treeClass, $id, $versionID); } else { $record = DataObject::get_one($treeClass, "\"$treeClass\".\"ID\" = $id"); } diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index 00b28764..08ff1100 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -22,18 +22,18 @@ class CMSPageHistoryController extends CMSMain { ); /** - * @var array + * @return array */ function version() { return array( 'EditForm' => $this->ShowVersionForm( - $this->request->param('ID') + $this->request->param('VersionID') ) ); } /** - * @var array + * @return array */ function compare() { return array( @@ -43,9 +43,9 @@ class CMSPageHistoryController extends CMSMain { ) ); } - + /** - * Returns the read only version of the edit form. Detaches {@link FormAction} + * Returns the read only version of the edit form. Detaches all {@link FormAction} * instances attached since only action relates to revert. * * Permission checking is done at the {@link CMSMain::getEditForm()} level. @@ -53,44 +53,93 @@ class CMSPageHistoryController extends CMSMain { * @param int $id ID of the record to show * @param array $fields optional * @param int $versionID + * @param int $compare Compare mode + * + * @return Form */ - function getEditForm($id = null, $fields = null, $versionID = null) { + function getEditForm($id = null, $fields = null, $versionID = null, $compareID = null) { + if(!$id) $id = $this->currentPageID(); + $record = $this->getRecord($id, $versionID); + $versionID = ($record) ? $record->Version : $versionID; $form = parent::getEditForm($record, ($record) ? $record->getCMSFields() : null); + $form->setActions(new FieldSet( + $revert = new FormAction('doRevert', _t('CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')) + )); + $fields = $form->Fields(); $fields->removeByName("Status"); $fields->push(new HiddenField("ID")); $fields->push(new HiddenField("Version")); $fields = $fields->makeReadonly(); - + foreach($fields->dataFields() as $field) { $field->dontEscape = true; + $field->reserveNL = true; } - $form->setFields($fields->makeReadonly()); + $link = Controller::join_links( + $this->Link('version'), + $id + ); - // attach additional information + $view = _t('CMSPageHistoryController.VIEW',"view"); + + if($compareID) { + $message = sprintf( + _t('CMSPageHistoryController.COMPARINGVERSION',"Comparing versions %s and %s."), + sprintf('%s (%s)', $versionID, Controller::join_links($link, $versionID), $view), + sprintf('%s (%s)', $compareID, Controller::join_links($link, $compareID), $view) + ); + + $revert->setReadonly(true); + } + else { + $message = sprintf( + _t('CMSPageHistoryController.VIEWINGVERSION',"Currently viewing version %s."), + sprintf('%s (%s)', + $versionID, + Controller::join_links($link, $versionID), + $view + ) + ); + } + + $fields->addFieldToTab('Root.Main', + new LiteralField('CurrentlyViewingMessage', $this->customise(array( + 'Content' => $message, + 'Classes' => 'notice' + ))->renderWith(array('CMSMain_notice'))), + "Title" + ); + + + $form->setFields($fields->makeReadonly()); $form->loadDataFrom(array( "ID" => $id, "Version" => $versionID, )); - $form->setActions(new FieldSet( - $revert = new FormAction('doRevert', _t('CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')) - )); + if(($record && $record->isLatestVersion())) { + $revert->setReadonly(true); + } $form->removeExtraClass('cms-content'); return $form; } + /** - * Compare version selection form. Displays a list of previous versions - * and options for selecting filters on the version - * + * Version select form. Main interface between selecting versions to view + * and comparing multiple versions. + * + * Because we can reload the page directly to a compare view (history/compare/1/2/3) + * this form has to adapt to those parameters as well. + * * @return Form */ function VersionsForm() { @@ -98,16 +147,34 @@ class CMSPageHistoryController extends CMSMain { $page = $this->getRecord($id); $versionsHtml = ''; + $action = $this->request->param('Action'); + $versionID = $this->request->param('VersionID'); + $otherVersionID = $this->request->param('OtherVersionID'); + + $showUnpublishedChecked = 0; + $compareModeChecked = ($action == "compare"); + if($page) { $versions = $page->allVersions(); if($versions) { foreach($versions as $k => $version) { + $active = false; + + if($version->Version == $versionID || $version->Version == $otherVersionID) { + $active = true; + + if(!$version->WasPublished) { + $showUnpublishedChecked = 1; + } + } $version->CMSLink = sprintf('%s/%s/%s', $this->Link('version'), $version->ID, $version->Version ); + + $version->Active = ($active); } } @@ -117,18 +184,20 @@ class CMSPageHistoryController extends CMSMain { 'Versions' => $versions ))->renderWith('CMSPageHistoryController_versions'); } - + $form = new Form( $this, 'VersionsForm', new FieldSet( new CheckboxField( 'ShowUnpublished', - _t('CMSPageHistoryController.SHOWUNPUBLISHED','Show unpublished versions') + _t('CMSPageHistoryController.SHOWUNPUBLISHED','Show unpublished versions'), + $showUnpublishedChecked ), new CheckboxField( 'CompareMode', - _t('CMSPageHistoryController.COMPAREMODE', 'Compare mode') + _t('CMSPageHistoryController.COMPAREMODE', 'Compare mode'), + $compareModeChecked ), new LiteralField('VersionsHtml', $versionsHtml), new HiddenField('ID', false, $id) @@ -236,7 +305,7 @@ class CMSPageHistoryController extends CMSMain { */ function ShowVersionForm($versionID = null) { if(!$versionID) return null; - + $id = $this->currentPageID(); $form = $this->getEditForm($id, null, $versionID); @@ -278,7 +347,7 @@ class CMSPageHistoryController extends CMSMain { } if($record) { - $form = $this->getEditForm($id, null, null); + $form = $this->getEditForm($id, null, null, true); $form->setActions(new FieldSet()); $form->loadDataFrom($record); diff --git a/javascript/CMSPageHistoryController.js b/javascript/CMSPageHistoryController.js index b739fa83..27c599c4 100644 --- a/javascript/CMSPageHistoryController.js +++ b/javascript/CMSPageHistoryController.js @@ -70,7 +70,7 @@ url = 'admin/page/history/version/'+ [id,to].join('/') + "/"; } - // we can access this comparsion directly in the url. + // we can access this comparsion directly in the url window.History.pushState({selector: '.cms-content-fields form:first'}, '', url); var data = this.serializeArray(); diff --git a/templates/CMSMain_notice.ss b/templates/CMSMain_notice.ss new file mode 100644 index 00000000..41bd345e --- /dev/null +++ b/templates/CMSMain_notice.ss @@ -0,0 +1,3 @@ +
+

$Content

+
\ No newline at end of file diff --git a/templates/CMSPageHistoryController_versions.ss b/templates/CMSPageHistoryController_versions.ss index 1337b255..98c281bf 100755 --- a/templates/CMSPageHistoryController_versions.ss +++ b/templates/CMSPageHistoryController_versions.ss @@ -10,8 +10,8 @@ <% control Versions %> - - + + checked="checked"<% end_if %> /> <% control LastEdited %> $Nice <% end_control %> From 18471e8878e5771df975029361569df145fd48fe Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Tue, 30 Aug 2011 10:26:40 +1200 Subject: [PATCH 3/7] ENHANCEMENT: added tests for CMSPageHistoryController::VersionsForm(). BUGFIX: fixed VersionsForm hidden ID storing a reference to itself. ENHANCEMENT: changed url structure from /version/ to /show/ for consistency between CMSPageHistoryController and CMSMain. APICHANGE: moved performRollback() from CMSMain to CMSPageHistoryController --- code/controllers/CMSMain.php | 8 -- code/controllers/CMSPageHistoryController.php | 115 +++++++++++------- javascript/CMSPageHistoryController.js | 11 +- .../CMSPageHistoryControllerTest.php | 102 ++++++++++++++++ .../CMSPageHistoryControllerTest.yml | 10 ++ 5 files changed, 188 insertions(+), 58 deletions(-) create mode 100644 tests/controller/CMSPageHistoryControllerTest.php create mode 100644 tests/controller/CMSPageHistoryControllerTest.yml diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 027928b1..6837b1f9 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -937,14 +937,6 @@ JS; return $form->forTemplate(); } - function performRollback($id, $version) { - $record = DataObject::get_by_id($this->stat('tree_class'), $id); - if($record && !$record->canEdit()) return Security::permissionFailure($this); - - $record->doRollbackTo($version); - return $record; - } - function sendFormToBrowser($templateData) { if(Director::is_ajax()) { SSViewer::setOption('rewriteHashlinks', false); diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index 08ff1100..98420774 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -13,7 +13,6 @@ class CMSPageHistoryController extends CMSMain { static $allowed_actions = array( 'VersionsForm', - 'version', 'compare' ); @@ -24,7 +23,7 @@ class CMSPageHistoryController extends CMSMain { /** * @return array */ - function version() { + function show() { return array( 'EditForm' => $this->ShowVersionForm( $this->request->param('VersionID') @@ -43,6 +42,16 @@ class CMSPageHistoryController extends CMSMain { ) ); } + + /** + * @return array + */ + function rollback() { + return $this->doRollback(array( + 'ID' => $this->currentPageID(), + 'Version' => $this->request->param('VersionID') + ), null); + } /** * Returns the read only version of the edit form. Detaches all {@link FormAction} @@ -81,14 +90,14 @@ class CMSPageHistoryController extends CMSMain { $field->reserveNL = true; } - $link = Controller::join_links( - $this->Link('version'), - $id - ); - - $view = _t('CMSPageHistoryController.VIEW',"view"); - if($compareID) { + $link = Controller::join_links( + $this->Link('version'), + $id + ); + + $view = _t('CMSPageHistoryController.VIEW',"view"); + $message = sprintf( _t('CMSPageHistoryController.COMPARINGVERSION',"Comparing versions %s and %s."), sprintf('%s (%s)', $versionID, Controller::join_links($link, $versionID), $view), @@ -99,12 +108,7 @@ class CMSPageHistoryController extends CMSMain { } else { $message = sprintf( - _t('CMSPageHistoryController.VIEWINGVERSION',"Currently viewing version %s."), - sprintf('%s (%s)', - $versionID, - Controller::join_links($link, $versionID), - $view - ) + _t('CMSPageHistoryController.VIEWINGVERSION',"Currently viewing version %s."), $versionID ); } @@ -169,7 +173,7 @@ class CMSPageHistoryController extends CMSMain { } } $version->CMSLink = sprintf('%s/%s/%s', - $this->Link('version'), + $this->Link('show'), $version->ID, $version->Version ); @@ -200,7 +204,7 @@ class CMSPageHistoryController extends CMSMain { $compareModeChecked ), new LiteralField('VersionsHtml', $versionsHtml), - new HiddenField('ID', false, $id) + $hiddenID = new HiddenField('ID', false, "") ), new FieldSet( new FormAction( @@ -213,6 +217,7 @@ class CMSPageHistoryController extends CMSMain { ); $form->loadDataFrom($this->request->requestVars()); + $hiddenID->setValue($id); $form->unsetValidator(); return $form; @@ -297,7 +302,54 @@ class CMSPageHistoryController extends CMSMain { * @return html */ function doRollback($data, $form) { - // + $this->extend('onBeforeRollback', $data['ID']); + $id = (isset($data['ID'])) ? (int) $data['ID'] : null; + $version = (isset($data['Version'])) ? (int) $data['Version'] : null; + + if(isset($data['Version']) && (bool)$data['Version']) { + $record = $this->performRollback($data['ID'], $data['Version']); + $message = sprintf( + _t('CMSMain.ROLLEDBACKVERSION',"Rolled back to version #%d. New version number is #%d"), + $data['Version'], + $record->Version + ); + } else { + $record = $this->performRollback($data['ID'], "Live"); + $message = sprintf( + _t('CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #%d"), + $record->Version + ); + } + + if($this->isAjax()) { + $this->response->addHeader('X-Status', $message); + $form = $this->getEditForm($record->ID); + + return $form->forTemplate(); + } + + return array( + 'EditForm' => $this->customise(array( + 'Message' => $message, + 'Status' => 'success' + ))->renderWith('CMSMain_notice') + ); + } + + /** + * Performs a rollback of the a given + * + * @param int $id record ID + * @param int $version version ID to rollback to + */ + function performRollback($id, $version) { + $record = DataObject::get_by_id($this->stat('tree_class'), $id); + + if($record && !$record->canEdit()) return Security::permissionFailure($this); + + $record->doRollbackTo($version); + + return $record; } /** @@ -361,31 +413,4 @@ class CMSPageHistoryController extends CMSMain { return $form; } } - - /** - * Roll a page back to a previous version - */ - function rollback($data, $form) { - $this->extend('onBeforeRollback', $data['ID']); - - if(isset($data['Version']) && (bool)$data['Version']) { - $record = $this->performRollback($data['ID'], $data['Version']); - $message = sprintf( - _t('CMSMain.ROLLEDBACKVERSION',"Rolled back to version #%d. New version number is #%d"), - $data['Version'], - $record->Version - ); - } else { - $record = $this->performRollback($data['ID'], "Live"); - $message = sprintf( - _t('CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #%d"), - $record->Version - ); - } - - $this->response->addHeader('X-Status', $message); - $form = $this->getEditForm($record->ID); - - return $form->forTemplate(); - } } \ No newline at end of file diff --git a/javascript/CMSPageHistoryController.js b/javascript/CMSPageHistoryController.js index 27c599c4..e7519a5f 100644 --- a/javascript/CMSPageHistoryController.js +++ b/javascript/CMSPageHistoryController.js @@ -44,6 +44,9 @@ * * Submits either the compare versions form or the view single form * display based on whether we have two or 1 option selected + * + * Todo: + * Handle coupling to admin url */ onsubmit: function(e, d) { var id, self = this; @@ -51,7 +54,7 @@ if(!id) return false; - var button, url, selected, to, from, compare; + var button, url, selected, to, from, compare, data; compare = (this.find(":input[name=CompareMode]").is(":checked")); selected = this.find("table input[type=checkbox]").filter(":checked"); @@ -67,14 +70,12 @@ else { to = selected.eq(0).val(); button = this.find(':submit[name=action_doShowVersion]'); - url = 'admin/page/history/version/'+ [id,to].join('/') + "/"; + url = 'admin/page/history/show/'+ [id,to].join('/') + "/"; } - // we can access this comparsion directly in the url window.History.pushState({selector: '.cms-content-fields form:first'}, '', url); - var data = this.serializeArray(); - + data = this.serializeArray(); data.push({ name: button.attr('name'), value: button.val() }); diff --git a/tests/controller/CMSPageHistoryControllerTest.php b/tests/controller/CMSPageHistoryControllerTest.php new file mode 100644 index 00000000..ef27243e --- /dev/null +++ b/tests/controller/CMSPageHistoryControllerTest.php @@ -0,0 +1,102 @@ +loginWithPermission('ADMIN'); + + // creates a series of published, unpublished versions of a page + $this->page = new Page(); + $this->page->URLSegment = "test"; + $this->page->Content = "new content"; + $this->page->write(); + $this->versionUnpublishedCheck = $this->page->Version; + + $this->page->Content = "some further content"; + $this->page->write(); + $this->page->publish('Stage', 'Live'); + $this->versionPublishCheck = $this->page->Version; + + $this->page->Content = "No, more changes please"; + $this->page->Title = "Changing titles too"; + $this->page->write(); + $this->versionUnpublishedCheck2 = $this->page->Version; + + $this->page->Title = "Final Change"; + $this->page->write(); + $this->page->publish('Stage', 'Live'); + $this->versionPublishCheck2 = $this->page->Version; + } + + function testGetEditForm() { + + } + + /** + * @todo should be less tied to cms theme + */ + function testVersionsForm() { + $history = $this->get('admin/page/history/show/'. $this->page->ID); + + $form = $this->cssParser()->getBySelector("#Form_VersionsForm"); + $this->assertEquals(1, count($form)); + + // check the page ID is present + $hidden = $form[0]->xpath("fieldset/input[@type='hidden']"); + $this->assertFalse($hidden == null, 'Hidden ID field exists'); + $this->assertEquals(4, (int) $hidden[0]->attributes()->value); + + // ensure that all the versions are present in the table and displayed + $rows = $form[0]->xpath("fieldset/table/tbody/tr"); + + $this->assertFalse($hidden == null, "Versions exist in table"); + $this->assertEquals(4, count($rows)); + + $expected = array( + array('version' => $this->versionPublishCheck2, 'status' => 'published'), + array('version' => $this->versionUnpublishedCheck2, 'status' => 'internal'), + array('version' => $this->versionPublishCheck, 'status' => 'published'), + array('version' => $this->versionUnpublishedCheck, 'status' => 'internal') + ); + + // goes the reverse order that we created in setUp(); + $i = 0; + foreach($rows as $tr) { + $this->assertEquals( + sprintf('admin/page/history/show/%d/%d', $this->page->ID, $expected[$i]['version']), + (string) $tr->attributes()->{'data-link'} + ); + + $this->assertContains($expected[$i]['status'], (string) $tr->attributes()->class); + $i++; + } + } + + function testDoForm() { + + } + + function testCompareForm() { + + } + + function testRevertForm() { + + } + + function testIsCompareMode() { + + } +} \ No newline at end of file diff --git a/tests/controller/CMSPageHistoryControllerTest.yml b/tests/controller/CMSPageHistoryControllerTest.yml new file mode 100644 index 00000000..4d6632fa --- /dev/null +++ b/tests/controller/CMSPageHistoryControllerTest.yml @@ -0,0 +1,10 @@ +Page: + page1: + Title: Page 1 + Sort: 1 + page2: + Title: Page 2 + Sort: 2 + page3: + Title: Page 3 + Sort: 3 \ No newline at end of file From 11821f3e431deb797f7404185cc3870dde7087a5 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Tue, 30 Aug 2011 12:36:02 +1200 Subject: [PATCH 4/7] ENHANCEMENT: implemented further tests for CMSPageHistoryController::getEditForm() --- code/controllers/CMSPageHistoryController.php | 7 ++- .../CMSPageHistoryControllerTest.php | 57 +++++++++++++------ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index 98420774..b73c2627 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -75,7 +75,7 @@ class CMSPageHistoryController extends CMSMain { $form = parent::getEditForm($record, ($record) ? $record->getCMSFields() : null); $form->setActions(new FieldSet( - $revert = new FormAction('doRevert', _t('CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')) + $revert = new FormAction('doRollback', _t('CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')) )); $fields = $form->Fields(); @@ -120,7 +120,6 @@ class CMSPageHistoryController extends CMSMain { "Title" ); - $form->setFields($fields->makeReadonly()); $form->loadDataFrom(array( "ID" => $id, @@ -160,7 +159,8 @@ class CMSPageHistoryController extends CMSMain { if($page) { $versions = $page->allVersions(); - + $versionID = (!$versionID) ? $page->Version : $versionID; + if($versions) { foreach($versions as $k => $version) { $active = false; @@ -303,6 +303,7 @@ class CMSPageHistoryController extends CMSMain { */ function doRollback($data, $form) { $this->extend('onBeforeRollback', $data['ID']); + $id = (isset($data['ID'])) ? (int) $data['ID'] : null; $version = (isset($data['Version'])) ? (int) $data['Version'] : null; diff --git a/tests/controller/CMSPageHistoryControllerTest.php b/tests/controller/CMSPageHistoryControllerTest.php index ef27243e..b3ff6ae6 100644 --- a/tests/controller/CMSPageHistoryControllerTest.php +++ b/tests/controller/CMSPageHistoryControllerTest.php @@ -41,11 +41,48 @@ class CMSPageHistoryControllerTest extends FunctionalTest { } function testGetEditForm() { + $controller = new CMSPageHistoryController(); + + // should get the latest version which we cannot rollback to + $form = $controller->getEditForm($this->page->ID); + + $this->assertTrue($form->Actions()->dataFieldByName('action_doRollback')->isReadonly()); + $this->assertEquals($this->page->ID, $form->dataFieldByName('ID')->Value()); + $this->assertEquals($this->versionPublishCheck2, $form->dataFieldByName('Version')->Value()); + + $this->assertContains( + sprintf("Currently viewing version %s.", $this->versionPublishCheck2), + $form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent() + ); + + // edit form with a given version + $form = $controller->getEditForm($this->page->ID, null, $this->versionPublishCheck); + $this->assertFalse($form->Actions()->dataFieldByName('action_doRollback')->isReadonly()); + + $this->assertEquals($this->page->ID, $form->dataFieldByName('ID')->Value()); + $this->assertEquals($this->versionPublishCheck, $form->dataFieldByName('Version')->Value()); + $this->assertContains( + sprintf("Currently viewing version %s.", $this->versionPublishCheck), + $form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent() + ); + + // check that compare mode updates the message + $form = $controller->getEditForm($this->page->ID, null, $this->versionPublishCheck, $this->versionPublishCheck2); + $this->assertContains( + sprintf("Comparing versions %s", $this->versionPublishCheck), + $form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent() + ); + + $this->assertContains( + sprintf("and %s", $this->versionPublishCheck2), + $form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent() + ); } /** - * @todo should be less tied to cms theme + * @todo should be less tied to cms theme. + * @todo check highlighting for comparing pages. */ function testVersionsForm() { $history = $this->get('admin/page/history/show/'. $this->page->ID); @@ -82,21 +119,9 @@ class CMSPageHistoryControllerTest extends FunctionalTest { $this->assertContains($expected[$i]['status'], (string) $tr->attributes()->class); $i++; } - } - - function testDoForm() { - - } - - function testCompareForm() { - - } - - function testRevertForm() { - - } - - function testIsCompareMode() { + // test highlighting + $this->assertContains('active', (string) $rows[0]->attributes()->class); + $this->assertThat((string) $rows[1]->attributes()->class, $this->logicalNot($this->stringContains('active'))); } } \ No newline at end of file From ecae94e8c27b924fe3955e4a38056f79c5f1c624 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Tue, 30 Aug 2011 14:33:03 +1200 Subject: [PATCH 5/7] MINOR: added unit test for checking whether viewing an unpublished version directly selects the checkbox option --- code/controllers/CMSPageHistoryController.php | 11 +----- .../CMSPageHistoryController_versions.ss | 4 +- .../CMSPageHistoryControllerTest.php | 38 ++++++++++++++----- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index b73c2627..1d83e705 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -160,7 +160,7 @@ class CMSPageHistoryController extends CMSMain { if($page) { $versions = $page->allVersions(); $versionID = (!$versionID) ? $page->Version : $versionID; - + if($versions) { foreach($versions as $k => $version) { $active = false; @@ -168,15 +168,8 @@ class CMSPageHistoryController extends CMSMain { if($version->Version == $versionID || $version->Version == $otherVersionID) { $active = true; - if(!$version->WasPublished) { - $showUnpublishedChecked = 1; - } + if(!$version->WasPublished) $showUnpublishedChecked = 1; } - $version->CMSLink = sprintf('%s/%s/%s', - $this->Link('show'), - $version->ID, - $version->Version - ); $version->Active = ($active); } diff --git a/templates/CMSPageHistoryController_versions.ss b/templates/CMSPageHistoryController_versions.ss index 98c281bf..c6d9117c 100755 --- a/templates/CMSPageHistoryController_versions.ss +++ b/templates/CMSPageHistoryController_versions.ss @@ -10,8 +10,8 @@ <% control Versions %> - - checked="checked"<% end_if %> /> + + checked="checked"<% end_if %> /> <% control LastEdited %> $Nice <% end_control %> diff --git a/tests/controller/CMSPageHistoryControllerTest.php b/tests/controller/CMSPageHistoryControllerTest.php index b3ff6ae6..09d3fca5 100644 --- a/tests/controller/CMSPageHistoryControllerTest.php +++ b/tests/controller/CMSPageHistoryControllerTest.php @@ -86,20 +86,25 @@ class CMSPageHistoryControllerTest extends FunctionalTest { */ function testVersionsForm() { $history = $this->get('admin/page/history/show/'. $this->page->ID); - $form = $this->cssParser()->getBySelector("#Form_VersionsForm"); + $this->assertEquals(1, count($form)); // check the page ID is present $hidden = $form[0]->xpath("fieldset/input[@type='hidden']"); - $this->assertFalse($hidden == null, 'Hidden ID field exists'); + + $this->assertThat($hidden, $this->logicalNot($this->isNull()), 'Hidden ID field exists'); $this->assertEquals(4, (int) $hidden[0]->attributes()->value); // ensure that all the versions are present in the table and displayed $rows = $form[0]->xpath("fieldset/table/tbody/tr"); - - $this->assertFalse($hidden == null, "Versions exist in table"); $this->assertEquals(4, count($rows)); + } + + function testVersionsFormTableContainsInformation() { + $history = $this->get('admin/page/history/show/'. $this->page->ID); + $form = $this->cssParser()->getBySelector("#Form_VersionsForm"); + $rows = $form[0]->xpath("fieldset/table/tbody/tr"); $expected = array( array('version' => $this->versionPublishCheck2, 'status' => 'published'), @@ -108,14 +113,10 @@ class CMSPageHistoryControllerTest extends FunctionalTest { array('version' => $this->versionUnpublishedCheck, 'status' => 'internal') ); - // goes the reverse order that we created in setUp(); + // goes the reverse order that we created in setUp() $i = 0; foreach($rows as $tr) { - $this->assertEquals( - sprintf('admin/page/history/show/%d/%d', $this->page->ID, $expected[$i]['version']), - (string) $tr->attributes()->{'data-link'} - ); - + // data-link must be present for the javascript to load new $this->assertContains($expected[$i]['status'], (string) $tr->attributes()->class); $i++; } @@ -124,4 +125,21 @@ class CMSPageHistoryControllerTest extends FunctionalTest { $this->assertContains('active', (string) $rows[0]->attributes()->class); $this->assertThat((string) $rows[1]->attributes()->class, $this->logicalNot($this->stringContains('active'))); } + + function testVersionsFormSelectsUnpublishedCheckbox() { + $history = $this->get('admin/page/history/show/'. $this->page->ID); + $checkbox = $this->cssParser()->getBySelector("#Form_VersionsForm #ShowUnpublished input"); + + $this->assertThat($checkbox[0], $this->logicalNot($this->isNull())); + $checked = $checkbox[0]->attributes()->checked; + + $this->assertThat($checked, $this->logicalNot($this->stringContains('checked'))); + + // viewing an unpublished + $history = $this->get('admin/page/history/show/'.$this->page->ID .'/'.$this->versionUnpublishedCheck); + $checkbox = $this->cssParser()->getBySelector("#Form_VersionsForm #ShowUnpublished input"); + + $this->assertThat($checkbox[0], $this->logicalNot($this->isNull())); + $this->assertEquals('checked', (string) $checkbox[0]->attributes()->checked); + } } \ No newline at end of file From 872239830cd32f5ca5bb768aa1bf963b602adb55 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 19 Sep 2011 21:00:17 +0200 Subject: [PATCH 6/7] BUGFIX Fixed history.pushState() ajax load duplication in CMSPageHistoryController.js --- javascript/CMSPageHistoryController.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/javascript/CMSPageHistoryController.js b/javascript/CMSPageHistoryController.js index e7519a5f..e75e425c 100644 --- a/javascript/CMSPageHistoryController.js +++ b/javascript/CMSPageHistoryController.js @@ -73,16 +73,7 @@ url = 'admin/page/history/show/'+ [id,to].join('/') + "/"; } - window.History.pushState({selector: '.cms-content-fields form:first'}, '', url); - - data = this.serializeArray(); - data.push({ - name: button.attr('name'), value: button.val() - }); - - $('.cms-content').loadForm(this.attr('action'), null, function() {}, { - data: data, type: this.attr('method') - }); + window.History.pushState({selector: '.cms-edit-form'}, '', url); return false; } From 10e76830c4bcf351eba76bbfe241fe9ed1d63611 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 19 Sep 2011 21:06:39 +0200 Subject: [PATCH 7/7] MINOR Fixed history panel non-ajax loading and version links in "comparing X and Y" titles --- code/controllers/CMSPageHistoryController.php | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index 1d83e705..6f5b9b7a 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -23,24 +23,32 @@ class CMSPageHistoryController extends CMSMain { /** * @return array */ - function show() { - return array( - 'EditForm' => $this->ShowVersionForm( - $this->request->param('VersionID') - ) + function show($request) { + $form = $this->ShowVersionForm( + $request->param('VersionID') ); + if($this->isAjax()) { + $content = $form->forTemplate(); + } else { + $content = $this->customise(array('EditForm' => $form))->renderWith($this->getViewer('show')); + } + return $content; } /** * @return array */ - function compare() { - return array( - 'EditForm' => $this->CompareVersionsForm( - $this->request->param('VersionID'), - $this->request->param('OtherVersionID') - ) + function compare($request) { + $form = $this->CompareVersionsForm( + $request->param('VersionID'), + $request->param('OtherVersionID') ); + if($this->isAjax()) { + $content = $form->forTemplate(); + } else { + $content = $this->customise(array('EditForm' => $form))->renderWith($this->getViewer('show')); + } + return $content; } /** @@ -92,7 +100,7 @@ class CMSPageHistoryController extends CMSMain { if($compareID) { $link = Controller::join_links( - $this->Link('version'), + $this->Link('show'), $id );