Initial implementation of microhistory

This commit is contained in:
Rouslan Placella 2012-08-09 12:58:03 +02:00
parent 3d8cf0f716
commit 753e1f3648
7 changed files with 599 additions and 84 deletions

View File

@ -1,60 +1,6 @@
var menus = {
size: function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
size++;
}
}
return size;
},
data: {},
add: function (hash, content) {
console.log(this.size(this.data))
if (this.size(this.data) > 6) {
var oldest, key, init = 0;
for (var i in this.data) {
if (this.data[i]) {
console.log(this.data[i].timestamp, oldest)
if (! init || this.data[i].timestamp.getTime() < oldest.getTime()) {
oldest = this.data[i].timestamp;
key = i;
init = 1;
}
}
}
delete this.data[key];
}
this.data[hash] = {
content: content,
timestamp: new Date()
};
},
get: function (hash) {
if (this.data[hash]) {
return this.data[hash].content;
} else {
return '';
}
},
getRequestParam: function () {
var param = '';
var menuHashes = [];
for (var i in this.data) {
menuHashes.push(i);
}
var menuHashesParam = menuHashes.join('-');
if (menuHashesParam) {
param = '&menuHashes=' + menuHashesParam;
}
return param;
}
};
/**
* This object handles ajax requests for pages. It also
* handles the reloading of the main menu and scripts (TODO: navigation).
* handles the reloading of the main menu and scripts.
*/
var AJAX = {
/**
@ -188,7 +134,7 @@ var AJAX = {
params += '&' + $(this).serialize();
}
params += menus.getRequestParam();
params += AJAX.cache.menus.getRequestParam();
if (isLink) {
$.get(url, params, AJAX.responseHandler);
@ -235,30 +181,32 @@ var AJAX = {
}
if (data._menu) {
$('#floating_menubar').html(data._menu)
.children().first().remove(); // Remove duplicate wrapper (TODO: don't send it in the response)
menuPrepare();
menuResize();
menus.add(data._menuHash, data._menu);
AJAX.cache.menus.replace(data._menu);
AJAX.cache.menus.add(data._menuHash, data._menu);
} else if (data._menuHash) {
$('#floating_menubar').html(menus.get(data._menuHash))
.children().first().remove(); // Remove duplicate wrapper (TODO: don't send it in the response)
menuPrepare();
menuResize();
AJAX.cache.menus.replace(AJAX.cache.menus.get(data._menuHash));
}
$('body').children().not('#pma_navigation').not('#floating_menubar').not('#page_content').not('#selflink').remove();
$('body').children()
.not('#pma_navigation')
.not('#floating_menubar')
.not('#page_content')
.not('#selflink')
.remove();
$('#page_content').replaceWith("<div id='page_content'>" + data.message + "</div>");
if (data._selflink) {
$('#selflink > a').attr('href', data._selflink);
setURLHash(data._selflink);
}
if (data._scripts) {
AJAX.scriptHandler.load(data._scripts, 1);
}
if (data._selflink && data._scripts && data._menuHash) {
AJAX.cache.add(data._selflink, data._scripts, data._menuHash);
}
if (data._params) {
PMA_commonParams.setAll(data._params);
}
@ -384,6 +332,163 @@ var AJAX = {
}
}
};
AJAX.cache = {
/**
* An array used to prime the cache with data about the initially
* loaded page. This is set in the footer, and then loaded
* by a double-queued event further down this file.
*/
primer: [],
pages: [],
current: 0,
add: function (hash, scripts, menu) {
//console.log(this.current)
while (this.current < this.pages.length) {
// trim the cache if we went back in the history
this.pages.pop();
}
if (typeof this.pages[this.current - 1] !== 'undefined'
&& this.pages[this.current - 1].hash == hash
) {
// we're on the same page
return;
}
this.pages.push({
hash: hash,
content: $('#page_content').html(),
scripts: scripts,
selflink: $('#selflink').html(),
menu: menu,
navigation: $('#pma_navigation').html()
});
setURLHash(this.current, hash);
this.current++;
//console.log(this.pages)
},
goto: function (index) {
if (index > this.pages.length) {
alert('The requested page was not found in the history');
} else {
this.update();
AJAX.active = true;
var record = this.pages[index];
AJAX.scriptHandler.reset();
$('#page_content').html(record.content);
$('#selflink').html(record.selflink);
$('#pma_navigation').html(record.navigation);
this.menus.replace(this.menus.get(record.menu));
AJAX.scriptHandler.load(record.scripts);
this.current = ++index;
}
},
update: function () {
var page = this.pages[this.current - 1];
if (page) {
page.content = $('#page_content').html();
page.navigation = $('#pma_navigation').html();
}
},
menus: {
size: function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
size++;
}
}
return size;
},
data: {},
add: function (hash, content) {
//console.log(this.size(this.data))
if (this.size(this.data) > 6) {
// when the cache grows, we remove the oldest entry
var oldest, key, init = 0;
for (var i in this.data) {
if (this.data[i]) {
// console.log(this.data[i].timestamp, oldest)
if (! init || this.data[i].timestamp.getTime() < oldest.getTime()) {
oldest = this.data[i].timestamp;
key = i;
init = 1;
}
}
}
delete this.data[key];
}
this.data[hash] = {
content: content,
timestamp: new Date()
};
},
get: function (hash) {
if (this.data[hash]) {
return this.data[hash].content;
} else {
return '';
}
},
getRequestParam: function () {
var param = '';
var menuHashes = [];
for (var i in this.data) {
menuHashes.push(i);
}
var menuHashesParam = menuHashes.join('-');
if (menuHashesParam) {
param = '&menuHashes=' + menuHashesParam;
}
return param;
},
replace: function (content) {
$('#floating_menubar').html(content)
// Remove duplicate wrapper
// TODO: don't send it in the response
.children().first().remove();
menuPrepare();
menuResize();
}
}
};
var settingHash = false;
$(function () {
// Add the menu from the initial page into the cache
AJAX.cache.menus.add(
AJAX.cache.primer.menuHash,
$('<div></div>')
.append('<div></div>')
.append($('#serverinfo').clone())
.append($('#topmenucontainer').clone())
.html()
);
$(function () {
// Queue up this event twice to make sure that we get a copy
// of the page after all other onload events have been fired
AJAX.cache.add(
AJAX.cache.primer.url,
AJAX.cache.primer.scripts,
AJAX.cache.primer.menuHash
);
});
$(window).hashchange(function () {
// The settingHash flag is used to distinguish whether
// we have deliberately changed the hash of if the user
// clicked the back/forward button in the browser
if (settingHash) {
settingHash = false;
return;
}
if (/^#PMAURL-\d+:/.test(window.location.hash)) {
var index = window.location.hash.substring(
8, window.location.hash.indexOf(':')
);
AJAX.cache.goto(index);
}
});
});
/**
* Attach a generic event handler to clicks
* on pages and submissions of forms

View File

@ -0,0 +1,390 @@
/*!
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
// Script: jQuery hashchange event
//
// *Version: 1.3, Last updated: 7/21/2010*
//
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub - http://github.com/cowboy/jquery-hashchange/
// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
//
// About: License
//
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
//
// About: Known issues
//
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
//
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
//
// Also note that should a browser natively support the window.onhashchange
// event, but not report that it does, the fallback polling loop will be used.
//
// About: Release History
//
// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
// "removable" for mobile-only development. Added IE6/7 document.title
// support. Attempted to make Iframe as hidden as possible by using
// techniques from http://www.paciellogroup.com/blog/?p=604. Added
// support for the "shortcut" format $(window).hashchange( fn ) and
// $(window).hashchange() like jQuery provides for built-in events.
// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
// and <jQuery.fn.hashchange.src> properties plus document-domain.html
// file to address access denied issues when setting document.domain in
// IE6/7.
// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
// from a page on another domain would cause an error in Safari 4. Also,
// IE6/7 Iframe is now inserted after the body (this actually works),
// which prevents the page from scrolling when the event is first bound.
// Event can also now be bound before DOM ready, but it won't be usable
// before then in IE6/7.
// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
// where browser version is incorrectly reported as 8.0, despite
// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
// window.onhashchange functionality into a separate plugin for users
// who want just the basic event & back button support, without all the
// extra awesomeness that BBQ provides. This plugin will be included as
// part of jQuery BBQ, but also be available separately.
(function($,window,undefined){
'$:nomunge'; // Used by YUI compressor.
// Reused string.
var str_hashchange = 'hashchange',
// Method / object references.
doc = document,
fake_onhashchange,
special = $.event.special,
// Does the browser support window.onhashchange? Note that IE8 running in
// IE7 compatibility mode reports true for 'onhashchange' in window, even
// though the event isn't supported, so also test document.documentMode.
doc_mode = doc.documentMode,
supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
// Get location.hash (or what you'd expect location.hash to be) sans any
// leading #. Thanks for making this necessary, Firefox!
function get_fragment( url ) {
url = url || location.href;
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
};
// Method: jQuery.fn.hashchange
//
// Bind a handler to the window.onhashchange event or trigger all bound
// window.onhashchange event handlers. This behavior is consistent with
// jQuery's built-in event handlers.
//
// Usage:
//
// > jQuery(window).hashchange( [ handler ] );
//
// Arguments:
//
// handler - (Function) Optional handler to be bound to the hashchange
// event. This is a "shortcut" for the more verbose form:
// jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
// all bound window.onhashchange event handlers will be triggered. This
// is a shortcut for the more verbose
// jQuery(window).trigger( 'hashchange' ). These forms are described in
// the <hashchange event> section.
//
// Returns:
//
// (jQuery) The initial jQuery collection of elements.
// Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
// $(elem).hashchange() for triggering, like jQuery does for built-in events.
$.fn[ str_hashchange ] = function( fn ) {
return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
};
// Property: jQuery.fn.hashchange.delay
//
// The numeric interval (in milliseconds) at which the <hashchange event>
// polling loop executes. Defaults to 50.
// Property: jQuery.fn.hashchange.domain
//
// If you're setting document.domain in your JavaScript, and you want hash
// history to work in IE6/7, not only must this property be set, but you must
// also set document.domain BEFORE jQuery is loaded into the page. This
// property is only applicable if you are supporting IE6/7 (or IE8 operating
// in "IE7 compatibility" mode).
//
// In addition, the <jQuery.fn.hashchange.src> property must be set to the
// path of the included "document-domain.html" file, which can be renamed or
// modified if necessary (note that the document.domain specified must be the
// same in both your main JavaScript as well as in this file).
//
// Usage:
//
// jQuery.fn.hashchange.domain = document.domain;
// Property: jQuery.fn.hashchange.src
//
// If, for some reason, you need to specify an Iframe src file (for example,
// when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
// do so using this property. Note that when using this property, history
// won't be recorded in IE6/7 until the Iframe src file loads. This property
// is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
// compatibility" mode).
//
// Usage:
//
// jQuery.fn.hashchange.src = 'path/to/file.html';
$.fn[ str_hashchange ].delay = 50;
/*
$.fn[ str_hashchange ].domain = null;
$.fn[ str_hashchange ].src = null;
*/
// Event: hashchange event
//
// Fired when location.hash changes. In browsers that support it, the native
// HTML5 window.onhashchange event is used, otherwise a polling loop is
// initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
// see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
// compatibility" mode), a hidden Iframe is created to allow the back button
// and hash-based history to work.
//
// Usage as described in <jQuery.fn.hashchange>:
//
// > // Bind an event handler.
// > jQuery(window).hashchange( function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).hashchange();
//
// A more verbose usage that allows for event namespacing:
//
// > // Bind an event handler.
// > jQuery(window).bind( 'hashchange', function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).trigger( 'hashchange' );
//
// Additional Notes:
//
// * The polling loop and Iframe are not created until at least one handler
// is actually bound to the 'hashchange' event.
// * If you need the bound handler(s) to execute immediately, in cases where
// a location.hash exists on page load, via bookmark or page refresh for
// example, use jQuery(window).hashchange() or the more verbose
// jQuery(window).trigger( 'hashchange' ).
// * The event can be bound before DOM ready, but since it won't be usable
// before then in IE6/7 (due to the necessary Iframe), recommended usage is
// to bind it inside a DOM ready handler.
// Override existing $.event.special.hashchange methods (allowing this plugin
// to be defined after jQuery BBQ in BBQ's source code).
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
// Called only when the first 'hashchange' event is bound to window.
setup: function() {
// If window.onhashchange is supported natively, there's nothing to do..
if ( supports_onhashchange ) { return false; }
// Otherwise, we need to create our own. And we don't want to call this
// until the user binds to the event, just in case they never do, since it
// will create a polling loop and possibly even a hidden Iframe.
$( fake_onhashchange.start );
},
// Called only when the last 'hashchange' event is unbound from window.
teardown: function() {
// If window.onhashchange is supported natively, there's nothing to do..
if ( supports_onhashchange ) { return false; }
// Otherwise, we need to stop ours (if possible).
$( fake_onhashchange.stop );
}
});
// fake_onhashchange does all the work of triggering the window.onhashchange
// event for browsers that don't natively support it, including creating a
// polling loop to watch for hash changes and in IE 6/7 creating a hidden
// Iframe to enable back and forward.
fake_onhashchange = (function(){
var self = {},
timeout_id,
// Remember the initial hash so it doesn't get triggered immediately.
last_hash = get_fragment(),
fn_retval = function(val){ return val; },
history_set = fn_retval,
history_get = fn_retval;
// Start the polling loop.
self.start = function() {
timeout_id || poll();
};
// Stop the polling loop.
self.stop = function() {
timeout_id && clearTimeout( timeout_id );
timeout_id = undefined;
};
// This polling loop checks every $.fn.hashchange.delay milliseconds to see
// if location.hash has changed, and triggers the 'hashchange' event on
// window when necessary.
function poll() {
var hash = get_fragment(),
history_hash = history_get( last_hash );
if ( hash !== last_hash ) {
history_set( last_hash = hash, history_hash );
$(window).trigger( str_hashchange );
} else if ( history_hash !== last_hash ) {
location.href = location.href.replace( /#.*/, '' ) + history_hash;
}
timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
};
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
$.browser.msie && !supports_onhashchange && (function(){
// Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
// when running in "IE7 compatibility" mode.
var iframe,
iframe_src;
// When the event is bound and polling starts in IE 6/7, create a hidden
// Iframe for history handling.
self.start = function(){
if ( !iframe ) {
iframe_src = $.fn[ str_hashchange ].src;
iframe_src = iframe_src && iframe_src + get_fragment();
// Create hidden Iframe. Attempt to make Iframe as hidden as possible
// by using techniques from http://www.paciellogroup.com/blog/?p=604.
iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
// When Iframe has completely loaded, initialize the history and
// start polling.
.one( 'load', function(){
iframe_src || history_set( get_fragment() );
poll();
})
// Load Iframe src if specified, otherwise nothing.
.attr( 'src', iframe_src || 'javascript:0' )
// Append Iframe after the end of the body to prevent unnecessary
// initial page scrolling (yes, this works).
.insertAfter( 'body' )[0].contentWindow;
// Whenever `document.title` changes, update the Iframe's title to
// prettify the back/next history menu entries. Since IE sometimes
// errors with "Unspecified error" the very first time this is set
// (yes, very useful) wrap this with a try/catch block.
doc.onpropertychange = function(){
try {
if ( event.propertyName === 'title' ) {
iframe.document.title = doc.title;
}
} catch(e) {}
};
}
};
// Override the "stop" method since an IE6/7 Iframe was created. Even
// if there are no longer any bound event handlers, the polling loop
// is still necessary for back/next to work at all!
self.stop = fn_retval;
// Get history by looking at the hidden Iframe's location.hash.
history_get = function() {
return get_fragment( iframe.location.href );
};
// Set a new history item by opening and then closing the Iframe
// document, *then* setting its location.hash. If document.domain has
// been set, update that as well.
history_set = function( hash, history_hash ) {
var iframe_doc = iframe.document,
domain = $.fn[ str_hashchange ].domain;
if ( hash !== history_hash ) {
// Update Iframe with any initial `document.title` that might be set.
iframe_doc.title = doc.title;
// Opening the Iframe's document after it has been closed is what
// actually adds a history entry.
iframe_doc.open();
// Set document.domain for the Iframe document as well, if necessary.
domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
iframe_doc.close();
// Update the Iframe's hash, for great justice.
iframe.location.hash = hash;
}
};
})();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return self;
})();
})(jQuery,this);

View File

@ -95,7 +95,7 @@ $(function() {
* Register event handler for click on the reload
* navigation icon at the top of the panel
*/
$('#pma_navigation_reload').click(function () {
$('#pma_navigation_reload').live('click', function () {
PMA_reloadNavigation();
});
@ -138,7 +138,7 @@ $(function() {
/**
* Jump to recent table
*/
$('#recentTable').change(function() {
$('#recentTable').live('change', function() {
if (this.value != '') {
var arr = jQuery.parseJSON(this.value);
var $form = $(this).closest('form');
@ -398,7 +398,7 @@ var ScrollHandler = {
};
this.displayScrollbar();
$(window).bind('resize', this.displayScrollbar);
this.elms.$handle.bind('drag', function (event, drag) {
this.elms.$handle.live('drag', function (event, drag) {
var elms = ScrollHandler.elms;
var scrollbarOffset = elms.$scrollbar.offset().top;
var pos = drag.offsetY - scrollbarOffset;
@ -407,7 +407,7 @@ var ScrollHandler = {
ScrollHandler.setScrollbar(value);
ScrollHandler.setContent(value);
});
this.elms.$scrollbar.bind('click', function (event) {
this.elms.$scrollbar.live('click', function (event) {
if($(event.target).attr('id') === $(this).attr('id')) {
var $scrollbar = ScrollHandler.elms.$scrollbar;
var $handle = ScrollHandler.elms.$handle;
@ -418,7 +418,7 @@ var ScrollHandler = {
ScrollHandler.setContent(target);
}
});
$('#pma_navigation').bind(
$('#pma_navigation').live(
'mousewheel',
function(event, delta, deltaX, deltaY) {
event.preventDefault();
@ -606,12 +606,12 @@ var ResizeHandler = function () {
}
// Register the events for the resizer and the collapser
$('#pma_navigation_resizer')
.bind('mousedown', {'this':this}, this.mousedown);
.live('mousedown', {'this':this}, this.mousedown);
$(document)
.bind('mouseup', {'this':this}, this.mouseup)
.bind('mousemove', {'this':this}, this.mousemove);
var $collapser = $('#pma_navigation_collapser');
$collapser.bind('click', {'this':this}, this.collapse);
$collapser.live('click', {'this':this}, this.collapse);
// Add the correct arrow symbol to the collapser
$collapser.html(this.getSymbol($('#pma_navigation').width()));
}; // End of ResizeHandler

View File

@ -1,4 +1,8 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
// TODO: merge this file into ajax.js
/**
* Scripts to update location to allow bookmarking of frameset
* and restoring the bookmark once the page is loaded.
@ -13,8 +17,9 @@ var hash_init_done = 0;
* work itself. The hash is not set directly if we did not yet process old
* one.
*/
function setURLHash(hash)
function setURLHash(index, hash)
{
settingHash = true;
if (jQuery.browser.webkit) {
/*
* Setting hash leads to reload in webkit:
@ -23,9 +28,9 @@ function setURLHash(hash)
return;
}
if (hash_init_done) {
window.location.hash = "PMAURL:" + hash;
window.location.hash = "PMAURL-" + index + ":" + hash;
} else {
hash_to_set = "PMAURL:" + hash;
hash_to_set = "PMAURL-" + index + ":" + hash;
}
}
@ -35,8 +40,11 @@ function setURLHash(hash)
*/
$(function(){
/* Check if hash contains parameters */
if (window.location.hash.substring(0, 8) == '#PMAURL:') {
window.location = window.location.hash.substring(8);
if (window.location.hash.substring(0, 8) == '#PMAURL-') {
// FIXME: don't if the page is the same
window.location = window.location.hash.substring(
window.location.hash.indexOf(':') + 1
);
return;
}
/* Check if we should set URL */

View File

@ -237,11 +237,21 @@ class PMA_Footer
&& ! $this->_isAjax
) {
$url = $this->getSelfUrl('unencoded');
$this->_scripts->addCode("
// Store current location in hash part
// of URL to allow direct bookmarking
setURLHash('$url');
");
$header = PMA_Response::getInstance()->getHeader();
$scripts = $header->getScripts()->getFiles();
$menuHash = $header->getMenu()->getHash();
$this->_scripts->addCode( // prime the client-side cache
sprintf(
'AJAX.cache.primer = {'
. ' url: "%s",'
. ' scripts: %s,'
. ' menuHash: "%s"'
. '};',
PMA_escapeJsString($url),
json_encode($scripts),
PMA_escapeJsString($menuHash)
)
);
$url = $this->getSelfUrl();
$retval .= $this->_getSelfLink($url);
}

View File

@ -156,6 +156,7 @@ class PMA_Header
$this->_scripts->addFile('jquery/jquery.event.drag-2.0.js');
$this->_scripts->addFile('jquery/timepicker.js');
$this->_scripts->addFile('update-location.js');
$this->_scripts->addFile('jquery/jquery.ba-hashchange-1.3.js');
$this->_scripts->addFile('jquery/jquery.qtip-1.0.0-rc3.js');
if ($GLOBALS['cfg']['CodemirrorEnable']) {

View File

@ -127,6 +127,7 @@ class PMA_Scripts
|| strpos($filename, 'ajax.js') !== false
|| strpos($filename, 'navigation.js') !== false
|| strpos($filename, 'get_image.js.php') !== false
|| strpos($filename, 'update-location.js') !== false
) {
return 0;
} else {