Implemented page, menu and scripts loading via ajax
This commit is contained in:
parent
100ca317f8
commit
5486bdb312
210
js/ajax.js
Normal file
210
js/ajax.js
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* This object handles ajax requests for pages. It also
|
||||
* handles the reloading of the main menu and scripts (TODO: navigation).
|
||||
*/
|
||||
var AJAX = {
|
||||
/**
|
||||
* @var bool active Whether we are busy
|
||||
*/
|
||||
active: false,
|
||||
/**
|
||||
* @var bool _debug Makes noise in your Firebug console
|
||||
*/
|
||||
_debug: false,
|
||||
/**
|
||||
* Given the filename of a script, returns a string to be
|
||||
* used to refer to all the events registered for the file
|
||||
*
|
||||
* @param string key The filename for which to get the event name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
getEventName: function (key){
|
||||
/* http://burtleburtle.net/bob/hash/doobs.html#one */
|
||||
key += "";
|
||||
var len = key.length, hash=0, i=0;
|
||||
for (; i<len; ++i) {
|
||||
hash += key.charCodeAt(i);
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return "onload_" + Math.abs(hash);
|
||||
},
|
||||
/**
|
||||
* Registers an onload event for a file
|
||||
*
|
||||
* @param string file The filename for which to register the event
|
||||
* @param function func The function to execute when the page is ready
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
registerOnload: function (file, func) {
|
||||
eventName = AJAX.getEventName(file);
|
||||
$(document).bind(eventName, func);
|
||||
this._debug && console.log("Registered event " + eventName + " for file " + file); // no need to translate
|
||||
},
|
||||
/**
|
||||
* Called when a page has finished loading, once for every
|
||||
* file that registered to the onload event of that file.
|
||||
*
|
||||
* @param string file The filename for which to fire the event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
fireOnload: function (file) {
|
||||
eventName = AJAX.getEventName(file);
|
||||
$(document).trigger(eventName);
|
||||
this._debug && console.log("Fired event " + eventName + " for file " + file); // no need to translate
|
||||
},
|
||||
/**
|
||||
* Event handler for clicks on links and form submissions
|
||||
*
|
||||
* @param eventData e
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
requestHandler: function (e) {
|
||||
if ($(this).attr('target')) {
|
||||
return true;
|
||||
} else if ($(this).hasClass('ajax') || $(this).hasClass('disableAjax')) {
|
||||
return true;
|
||||
} else if ($(this).attr('href') && $(this).attr('href').match(/^#/)) {
|
||||
return true;
|
||||
} else if ($(this).attr('href') && $(this).attr('href').match(/^mailto/)) {
|
||||
return true;
|
||||
} else {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
if (AJAX.active == true) {
|
||||
return false;
|
||||
} else {
|
||||
AJAX.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
var url = $(this).attr('href') || $(this).attr('action') + '?' + $(this).serialize();
|
||||
this._debug && console.log("Loading: " + url); // no need to translate
|
||||
var $msgbox = PMA_ajaxShowMessage();
|
||||
$('html, body').animate({scrollTop: 0}, 'fast');
|
||||
$.get(url, {'ajax_request': true, 'ajax_page_request': true}, function (data) {
|
||||
if (data.success) {
|
||||
PMA_ajaxRemoveMessage($msgbox);
|
||||
|
||||
if (data._menu) {
|
||||
$('#floating_menubar').html(data._menu)
|
||||
.children().first().remove(); // Remove duplicate wrapper (TODO: don't send it in the response)
|
||||
menuPrepare();
|
||||
menuResize();
|
||||
}
|
||||
|
||||
$('*').unbind().die();
|
||||
|
||||
$('body').children().not('#floating_menubar').not('#page_content').not('#selflink').remove();
|
||||
|
||||
$('#page_content').replaceWith("<div id='page_content'>" + data.message + "</div>");
|
||||
|
||||
if (data._scripts) {
|
||||
AJAX.scriptHandler.load(data._scripts);
|
||||
}
|
||||
} else {
|
||||
PMA_ajaxShowMessage(data.error, false);
|
||||
AJAX.active = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* This object is in charge of downloading scripts,
|
||||
* keeping track of what's downloaded and firing
|
||||
* the onload event for them when the page is ready.
|
||||
*/
|
||||
scriptHandler: {
|
||||
/**
|
||||
* @var array _scripts The list of files already downloaded
|
||||
*/
|
||||
_scripts: [],
|
||||
/**
|
||||
* @var array _scriptsToBeLoaded The list of files that
|
||||
* need to be downloaded
|
||||
*/
|
||||
_scriptsToBeLoaded: [],
|
||||
/**
|
||||
* @var array _scriptsToBeFired The list of files for which
|
||||
* to fire the onload event
|
||||
*/
|
||||
_scriptsToBeFired: [],
|
||||
/**
|
||||
* Records that a file has been downloaded
|
||||
*
|
||||
* @param string file The filename
|
||||
*
|
||||
* @return self For chaining
|
||||
*/
|
||||
add: function (file) {
|
||||
this._scripts.push(file);
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Queues up an array of files to be downloaded
|
||||
*
|
||||
* @param array files An array of filenames and flags
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
load: function (files) {
|
||||
this._scriptsToBeLoaded = [];
|
||||
this._scriptsToBeFired = [];
|
||||
for (var i in files) {
|
||||
this._scriptsToBeLoaded.push(files[i].name);
|
||||
if (files[i].fire) {
|
||||
this._scriptsToBeFired.push(files[i].name);
|
||||
}
|
||||
}
|
||||
this.callback();
|
||||
},
|
||||
/**
|
||||
* Called whenever a file is loaded.
|
||||
* Will queue up another file, or call done();
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
callback: function () {
|
||||
var scripts = this._scriptsToBeLoaded;
|
||||
if (scripts.length > 0) {
|
||||
var script = scripts.shift();
|
||||
if (this._scripts.indexOf(script) === -1) {
|
||||
this.add(script);
|
||||
var self = this;
|
||||
$.getScript('js/' + script, function () {
|
||||
self.callback();
|
||||
});
|
||||
} else {
|
||||
this.callback();
|
||||
}
|
||||
} else {
|
||||
this.done();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Called whenever all files are loaded
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
done: function () {
|
||||
for (var i in this._scriptsToBeFired) {
|
||||
AJAX.fireOnload(this._scriptsToBeFired[i]);
|
||||
}
|
||||
AJAX.active = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach a generic event handler to clicks
|
||||
* on pages and submissions of forms
|
||||
*/
|
||||
$('a').live('click', AJAX.requestHandler);
|
||||
$('form').live('submit', AJAX.requestHandler);
|
||||
|
||||
@ -2824,7 +2824,8 @@ function menuResize()
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
function menuPrepare()
|
||||
{
|
||||
var topmenu = $('#topmenu');
|
||||
if (topmenu.length == 0) {
|
||||
return;
|
||||
@ -2853,7 +2854,10 @@ $(function() {
|
||||
}
|
||||
});
|
||||
topmenu.append(submenu);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
menuPrepare();
|
||||
// populate submenu and register resize event
|
||||
menuResize();
|
||||
$(window).resize(menuResize);
|
||||
|
||||
@ -142,6 +142,7 @@ class PMA_Header
|
||||
private function _addDefaultScripts()
|
||||
{
|
||||
$this->_scripts->addFile('jquery/jquery-1.6.2.js');
|
||||
$this->_scripts->addFile('ajax.js');
|
||||
$this->_scripts->addFile('jquery/jquery-ui-1.8.16.custom.js');
|
||||
$this->_scripts->addFile('jquery/jquery.sprintf.js');
|
||||
$this->_scripts->addFile('update-location.js');
|
||||
@ -206,6 +207,16 @@ class PMA_Header
|
||||
return $this->_scripts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PMA_Menu object
|
||||
*
|
||||
* @return PMA_Menu object
|
||||
*/
|
||||
public function getMenu()
|
||||
{
|
||||
return $this->_menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the ID attribute in the BODY tag
|
||||
*
|
||||
|
||||
@ -66,6 +66,14 @@ class PMA_Response
|
||||
* @var bool
|
||||
*/
|
||||
private $_isAjax;
|
||||
/**
|
||||
* Whether we are servicing an ajax request for a page
|
||||
* that was fired using the generic page handler in JS.
|
||||
*
|
||||
* @access private
|
||||
* @var bool
|
||||
*/
|
||||
private $_isAjaxPage;
|
||||
/**
|
||||
* Whether there were any errors druing the processing of the request
|
||||
* Only used for ajax responses
|
||||
@ -96,11 +104,15 @@ class PMA_Response
|
||||
$this->_JSON = array();
|
||||
$this->_footer = new PMA_Footer();
|
||||
|
||||
$this->_isSuccess = true;
|
||||
$this->_isAjax = false;
|
||||
$this->_isSuccess = true;
|
||||
$this->_isAjax = false;
|
||||
$this->_isAjaxPage = false;
|
||||
if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
|
||||
$this->_isAjax = true;
|
||||
}
|
||||
if (isset($_REQUEST['ajax_page_request']) && $_REQUEST['ajax_page_request'] == true) {
|
||||
$this->_isAjaxPage = true;
|
||||
}
|
||||
$this->_header->setAjax($this->_isAjax);
|
||||
$this->_footer->setAjax($this->_isAjax);
|
||||
$this->_CWD = getcwd();
|
||||
@ -278,6 +290,11 @@ class PMA_Response
|
||||
unset($this->_JSON['message']);
|
||||
}
|
||||
|
||||
if ($this->_isAjaxPage) {
|
||||
$this->addJSON('_menu', $this->getHeader()->getMenu()->getDisplay());
|
||||
$this->addJSON('_scripts', $this->getHeader()->getScripts()->getFiles());
|
||||
}
|
||||
|
||||
// Set the Content-Type header to JSON so that jQuery parses the
|
||||
// response correctly.
|
||||
if (! defined('TESTSUITE')) {
|
||||
|
||||
@ -96,14 +96,15 @@ class PMA_Scripts
|
||||
*/
|
||||
public function addFile($filename, $conditional_ie = false)
|
||||
{
|
||||
$filename = 'js/' . $filename;
|
||||
$hash = md5($filename);
|
||||
if (empty($this->_files[$hash])) {
|
||||
$has_onload = $this->eventBlacklist($filename);
|
||||
$timestamp = null;
|
||||
if (strpos($filename, '?') === false) {
|
||||
$timestamp = filemtime($filename);
|
||||
$timestamp = filemtime('js/' . $filename);
|
||||
}
|
||||
$this->_files[$hash] = array(
|
||||
'has_onload' => $has_onload,
|
||||
'filename' => $filename,
|
||||
'timestamp' => $timestamp,
|
||||
'conditional_ie' => $conditional_ie
|
||||
@ -111,6 +112,29 @@ class PMA_Scripts
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to fire up an onload event for a file
|
||||
*
|
||||
* @param string $filename
|
||||
*
|
||||
* @return int 1 to fire up the event, 0 not to
|
||||
*/
|
||||
private function eventBlacklist($filename)
|
||||
{
|
||||
if ( strpos($filename, 'jquery') !== false
|
||||
|| strpos($filename, 'codemirror') !== false
|
||||
|| strpos($filename, 'messages.php') !== false
|
||||
|| strpos($filename, 'ajax.js') !== false
|
||||
|| strpos($filename, 'update-location.js') !== false
|
||||
|| strpos($filename, 'get_image.js.php') !== false
|
||||
|| strpos($filename, 'cross_framing_protection.js') !== false
|
||||
) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new code snippet to the code to be executed
|
||||
*
|
||||
@ -141,6 +165,26 @@ class PMA_Scripts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list with filenames and a flag to indicate
|
||||
* whether to register onload events for this file
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles()
|
||||
{
|
||||
$retval = array();
|
||||
foreach ($this->_files as $file) {
|
||||
if (! $file['conditional_ie'] || PMA_USR_BROWSER_AGENT == 'IE') {
|
||||
$retval[] = array(
|
||||
'name' => $file['filename'],
|
||||
'fire' => $file['has_onload']
|
||||
);
|
||||
}
|
||||
}
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders all the JavaScript file inclusions, code and events
|
||||
*
|
||||
@ -152,11 +196,27 @@ class PMA_Scripts
|
||||
|
||||
foreach ($this->_files as $file) {
|
||||
$retval .= $this->_includeFile(
|
||||
$file['filename'],
|
||||
'js/' . $file['filename'],
|
||||
$file['timestamp'],
|
||||
$file['conditional_ie']
|
||||
);
|
||||
}
|
||||
$code = 'AJAX.scriptHandler';
|
||||
foreach ($this->_files as $file) {
|
||||
$code .= '.add("' . PMA_escapeJsString($file['filename']) . '")';
|
||||
}
|
||||
$code .= ';';
|
||||
$this->addCode($code);
|
||||
|
||||
$code = '$(function() {';
|
||||
foreach ($this->_files as $file) {
|
||||
if ($file['has_onload']) {
|
||||
$code .= 'AJAX.fireOnload("' . PMA_escapeJsString($file['filename']) . '");';
|
||||
}
|
||||
}
|
||||
$code .= '});';
|
||||
$this->addCode($code);
|
||||
|
||||
$retval .= '<script type="text/javascript">';
|
||||
$retval .= "// <![CDATA[\n";
|
||||
$retval .= $this->_code;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user