Skip to content

Commit

Permalink
ENHANCEMENT HTML5 History.pushState support in CMS
Browse files Browse the repository at this point in the history
  • Loading branch information
chillu committed Jul 8, 2011
1 parent ff54044 commit 2f2096c
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 26 deletions.
17 changes: 17 additions & 0 deletions admin/code/LeftAndMain.php
Expand Up @@ -69,6 +69,7 @@ class LeftAndMain extends Controller {
*/ */
static $allowed_actions = array( static $allowed_actions = array(
'index', 'index',
'save',
'savetreenode', 'savetreenode',
'getitem', 'getitem',
'getsubtree', 'getsubtree',
Expand Down Expand Up @@ -241,6 +242,9 @@ function init() {
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js'); Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js');


Requirements::javascript(THIRDPARTY_DIR . '/behaviour/behaviour.js'); Requirements::javascript(THIRDPARTY_DIR . '/behaviour/behaviour.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js');
Expand Down Expand Up @@ -300,6 +304,9 @@ function init() {
SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js', SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js', SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js', SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js',
SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js',
THIRDPARTY_DIR . '/jstree/jquery.jstree.js', THIRDPARTY_DIR . '/jstree/jquery.jstree.js',
SAPPHIRE_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js', SAPPHIRE_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js',
SAPPHIRE_DIR . '/javascript/TreeDropdownField.js', SAPPHIRE_DIR . '/javascript/TreeDropdownField.js',
Expand Down Expand Up @@ -333,6 +340,16 @@ function init() {
// TableListField.ss or Form.ss. // TableListField.ss or Form.ss.
SSViewer::set_theme(null); SSViewer::set_theme(null);
} }

function handleRequest($request) {
$response = parent::handleRequest($request);
$response->addHeader('X-Controller', $this->class);
return $response;
}

function index($request) {
return ($this->isAjax()) ? $this->show($request) : $this->getViewer('index')->process($this);
}




/** /**
Expand Down
15 changes: 10 additions & 5 deletions admin/javascript/LeftAndMain.Content.js
Expand Up @@ -20,11 +20,7 @@


var url = $(node).find('a:first').attr('href'); var url = $(node).find('a:first').attr('href');
if(url && url != '#') { if(url && url != '#') {
var xmlhttp = self.loadForm( window.History.pushState({}, '', url);
url,
null,
function(response) {}
);
} else { } else {
self.removeForm(); self.removeForm();
} }
Expand All @@ -33,11 +29,20 @@
this._super(); this._super();
}, },


onunmatch: function() {
this._super();
},

beforeLoad: function(url) { beforeLoad: function(url) {
this.addClass('loading'); this.addClass('loading');
this.cleanup(); this.cleanup();
}, },


afterLoad: function(data, status, xhr) {
this.removeClass('loading');
this.replaceWith(data);
},

cleanup: function() { cleanup: function() {
this.empty(); this.empty();
}, },
Expand Down
21 changes: 7 additions & 14 deletions admin/javascript/LeftAndMain.EditForm.js
Expand Up @@ -79,6 +79,13 @@
$(this).remove(); $(this).remove();
}); });


// Remove all TinyMCE instances
if((typeof tinymce != 'undefined') && tinymce.editors) {
$(tinymce.editors).each(function() {
if(typeof(this.remove) == 'function') this.remove();
});
}

this._super(); this._super();
}, },


Expand Down Expand Up @@ -150,20 +157,6 @@
this.trigger('validate', {isValid: isValid}); this.trigger('validate', {isValid: isValid});


return isValid; return isValid;
},

/**
* Function: cleanup
*
* Remove all the currently active TinyMCE editors.
* Note: Everything that calls this externally has an inappropriate coupling to TinyMCE.
*/
cleanup: function() {
if((typeof tinymce != 'undefined') && tinymce.editors) {
$(tinymce.editors).each(function() {
if(typeof(this.remove) == 'function') this.remove();
});
}
} }
}); });


Expand Down
9 changes: 9 additions & 0 deletions admin/javascript/LeftAndMain.Menu.js
Expand Up @@ -25,11 +25,18 @@
*/ */
$('.cms-menu-list').entwine({ $('.cms-menu-list').entwine({
onmatch: function() { onmatch: function() {
var self = this;

// TODO Fix icon etc. // TODO Fix icon etc.
// this.children('li').each(function() { // this.children('li').each(function() {
// $(this).find('a:first').append('<span class="toggle">o</span>'); // $(this).find('a:first').append('<span class="toggle">o</span>');
// }); // });


$('.LeftAndMain').bind('afterstatechange', function(e, data) {
var controller = data.xhr.getResponseHeader('X-Controller');
if(controller) self.find('li#Menu-' + controller).select();
});

// Sync collapsed state with parent panel // Sync collapsed state with parent panel
this.parents('.cms-panel:first').bind('toggle', function(e) { this.parents('.cms-panel:first').bind('toggle', function(e) {
self.toggleClass('collapsed', $(this).hasClass('collapsed')); self.toggleClass('collapsed', $(this).hasClass('collapsed'));
Expand Down Expand Up @@ -92,6 +99,8 @@
if(children.length) { if(children.length) {
children.first().find('a').click(); children.first().find('a').click();
} else { } else {
// Active menu item is set based on X-Controller ajax header,
// which matches one class on the menu
window.History.pushState({}, '', this.attr('href')); window.History.pushState({}, '', this.attr('href'));
} }
} }
Expand Down
14 changes: 11 additions & 3 deletions admin/javascript/LeftAndMain.Preview.js
Expand Up @@ -36,6 +36,12 @@
var url = $(this).find(':input[name=StageURLSegment]').val(); var url = $(this).find(':input[name=StageURLSegment]').val();
if(url) self.loadUrl(url + '&cms-preview-disabled=1'); if(url) self.loadUrl(url + '&cms-preview-disabled=1');
}); });

$('.cms-container').bind('afterstatechange', function(e) {
// var url = ui.xmlhttp.getResponseHeader('x-frontend-url');
var url = $('.cms-edit-form').find(':input[name=StageURLSegment]').val();
if(url) self.loadUrl(url + '&cms-preview-disabled=1');
});


if(this.hasClass('is-expanded')) this.expand(); if(this.hasClass('is-expanded')) this.expand();
else this.collapse(); else this.collapse();
Expand All @@ -51,12 +57,14 @@
var doc = this.find('iframe')[0].contentDocument, container = this.getLayoutContainer(); var doc = this.find('iframe')[0].contentDocument, container = this.getLayoutContainer();


// Only load if we're in the "edit page" view // Only load if we're in the "edit page" view
if(!container.hasClass('CMSMain')) return; if(!container.hasClass('CMSMain') || container.hasClass('CMSPagesController')) return;


// Load this page in the admin interface if appropriate // 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'), contentPanel = $('.cms-content');
// TODO Remove hardcoding // TODO Remove hardcoding
if(id && contentPanel.find(':input[name=ID]').val() != id) contentPanel.loadPanel('admin/page/edit/show/' + id); if(id && contentPanel.find(':input[name=ID]').val() != id) {
window.History.pushState({}, '', 'admin/page/edit/show/' + id);
}
}, },


_fixIframeLinks: function() { _fixIframeLinks: function() {
Expand All @@ -69,7 +77,7 @@
if (href && href.match(/^http:\/\//)) { if (href && href.match(/^http:\/\//)) {
links[i].setAttribute('href', 'javascript:false'); links[i].setAttribute('href', 'javascript:false');
} else { } else {
links[i].setAttribute('href', href + '?cms-preview=1'); links[i].setAttribute('href', href + '?cms-preview-disabled=1');
} }
} }
}, },
Expand Down
57 changes: 55 additions & 2 deletions admin/javascript/LeftAndMain.js
Expand Up @@ -41,13 +41,15 @@
* loadnewpage - ... * loadnewpage - ...
*/ */
$('.LeftAndMain').entwine({ $('.LeftAndMain').entwine({


CurrentXHR: null,

/** /**
* Constructor: onmatch * Constructor: onmatch
*/ */
onmatch: function() { onmatch: function() {
var self = this; var self = this;

// Browser detection // Browser detection
if($.browser.msie && parseInt($.browser.version, 10) < 7) { if($.browser.msie && parseInt($.browser.version, 10) < 7) {
$('.ss-loading-screen').append( $('.ss-loading-screen').append(
Expand All @@ -68,6 +70,10 @@
$(window).unbind('resize', positionLoadingSpinner); $(window).unbind('resize', positionLoadingSpinner);


$('.cms-edit-form').live('loadnewpage', function() {self.redraw()}); $('.cms-edit-form').live('loadnewpage', function() {self.redraw()});

History.Adapter.bind(window,'statechange',function(){
self.handleStateChange();
});


this._super(); this._super();
}, },
Expand All @@ -77,6 +83,53 @@
var editForm = this.find('.cms-edit-form[data-layout]').layout(); var editForm = this.find('.cms-edit-form[data-layout]').layout();
this.find('.cms-content').layout(); this.find('.cms-content').layout();
this.find('.cms-container').layout({resize: false}) this.find('.cms-container').layout({resize: false})
},

/**
* Handles ajax loading of new panels through the window.History object.
* To trigger loading, pass a new URL to window.History.pushState().
*
* Due to the nature of history management, no callbacks are allowed.
* Use the 'beforestatechange' and 'afterstatechange' events instead,
* or overwrite the beforeLoad() and afterLoad() methods on the
* DOM element you're loading the new content into.
* Although you can pass data into pushState(), it shouldn't contain
* DOM elements or callback closures.
*
* The passed URL should allow reconstructing important interface state
* without additional parameters, in the following use cases:
* - Explicit loading through History.pushState()
* - Implicit loading through browser navigation event triggered by the user (forward or back)
* - Full window refresh without ajax
* For example, a ModelAdmin search event should contain the search terms
* as URL parameters, and the result display should automatically appear
* if the URL is loaded without ajax.
*
* Alternatively, you can load new content via $('.cms-content').loadForm(<url>).
* In this case, the action won't be recorded in the browser history.
*/
handleStateChange: function() {
var self = this, h = window.History, state = h.getState();

// Don't allow parallel loading to avoid edge cases
if(this.getCurrentXHR()) this.getCurrentXHR().abort();

// TODO Support loading into multiple panels
var contentEl = $(state.data.selector || '.LeftAndMain .cms-content');
this.trigger('beforestatechange', {state: state});
contentEl.beforeLoad(state.url);

var xhr = $.ajax({
url: state.url,
success: function(data, status, xhr) {
// Update panels
contentEl.afterLoad(data, status, xhr);
self.redraw();

self.trigger('afterstatechange', {data: data, status: status, xhr: xhr});
}
});
this.setCurrentXHR(xhr);
} }
}); });


Expand Down
6 changes: 4 additions & 2 deletions admin/javascript/ModelAdmin.History.js
Expand Up @@ -66,6 +66,8 @@
redraw: function() { redraw: function() {
this.find('.historyNav .forward').toggle(Boolean(this.getFuture().length > 0)); this.find('.historyNav .forward').toggle(Boolean(this.getFuture().length > 0));
this.find('.historyNav .back').toggle(Boolean(this.getHistory().length > 1)); this.find('.historyNav .back').toggle(Boolean(this.getHistory().length > 1));

this._super();
}, },


/** /**
Expand Down Expand Up @@ -116,7 +118,7 @@
this.trigger('historyGoBack', {url:previousPage}); this.trigger('historyGoBack', {url:previousPage});


// load new location // load new location
$('.cms-edit-form').loadForm(previousPage); $('.cms-content').loadForm(previousPage);


this.redraw(); this.redraw();
} }
Expand All @@ -136,7 +138,7 @@
this.trigger('historyGoForward', {url:nextPage}); this.trigger('historyGoForward', {url:nextPage});


// load new location // load new location
$('.cms-edit-form').loadForm(nextPage); $('.cms-content').loadForm(nextPage);


this.redraw(); this.redraw();
} }
Expand Down

0 comments on commit 2f2096c

Please sign in to comment.