1/* vim: set expandtab sw=4 ts=4 sts=4: */ 2/** 3 * This object handles ajax requests for pages. It also 4 * handles the reloading of the main menu and scripts. 5 */ 6var AJAX = { 7 /** 8 * @var bool active Whether we are busy 9 */ 10 active: false, 11 /** 12 * @var object source The object whose event initialized the request 13 */ 14 source: null, 15 /** 16 * @var object xhr A reference to the ajax request that is currently running 17 */ 18 xhr: null, 19 /** 20 * @var object lockedTargets, list of locked targets 21 */ 22 lockedTargets: {}, 23 /** 24 * @var function Callback to execute after a successful request 25 * Used by PMA_commonFunctions from common.js 26 */ 27 _callback: function () {}, 28 /** 29 * @var bool _debug Makes noise in your Firebug console 30 */ 31 _debug: false, 32 /** 33 * @var object $msgbox A reference to a jQuery object that links to a message 34 * box that is generated by PMA_ajaxShowMessage() 35 */ 36 $msgbox: null, 37 /** 38 * Given the filename of a script, returns a hash to be 39 * used to refer to all the events registered for the file 40 * 41 * @param key string key The filename for which to get the event name 42 * 43 * @return int 44 */ 45 hash: function (key) { 46 /* http://burtleburtle.net/bob/hash/doobs.html#one */ 47 key += ''; 48 var len = key.length; 49 var hash = 0; 50 var i = 0; 51 for (; i < len; ++i) { 52 hash += key.charCodeAt(i); 53 hash += (hash << 10); 54 hash ^= (hash >> 6); 55 } 56 hash += (hash << 3); 57 hash ^= (hash >> 11); 58 hash += (hash << 15); 59 return Math.abs(hash); 60 }, 61 /** 62 * Registers an onload event for a file 63 * 64 * @param file string file The filename for which to register the event 65 * @param func function func The function to execute when the page is ready 66 * 67 * @return self For chaining 68 */ 69 registerOnload: function (file, func) { 70 var eventName = 'onload_' + AJAX.hash(file); 71 $(document).on(eventName, func); 72 if (this._debug) { 73 console.log( 74 // no need to translate 75 'Registered event ' + eventName + ' for file ' + file 76 ); 77 } 78 return this; 79 }, 80 /** 81 * Registers a teardown event for a file. This is useful to execute functions 82 * that unbind events for page elements that are about to be removed. 83 * 84 * @param string file The filename for which to register the event 85 * @param function func The function to execute when 86 * the page is about to be torn down 87 * 88 * @return self For chaining 89 */ 90 registerTeardown: function (file, func) { 91 var eventName = 'teardown_' + AJAX.hash(file); 92 $(document).on(eventName, func); 93 if (this._debug) { 94 console.log( 95 // no need to translate 96 'Registered event ' + eventName + ' for file ' + file 97 ); 98 } 99 return this; 100 }, 101 /** 102 * Called when a page has finished loading, once for every 103 * file that registered to the onload event of that file. 104 * 105 * @param string file The filename for which to fire the event 106 * 107 * @return void 108 */ 109 fireOnload: function (file) { 110 var eventName = 'onload_' + AJAX.hash(file); 111 $(document).trigger(eventName); 112 if (this._debug) { 113 console.log( 114 // no need to translate 115 'Fired event ' + eventName + ' for file ' + file 116 ); 117 } 118 }, 119 /** 120 * Called just before a page is torn down, once for every 121 * file that registered to the teardown event of that file. 122 * 123 * @param string file The filename for which to fire the event 124 * 125 * @return void 126 */ 127 fireTeardown: function (file) { 128 var eventName = 'teardown_' + AJAX.hash(file); 129 $(document).triggerHandler(eventName); 130 if (this._debug) { 131 console.log( 132 // no need to translate 133 'Fired event ' + eventName + ' for file ' + file 134 ); 135 } 136 }, 137 /** 138 * function to handle lock page mechanism 139 * 140 * @param event the event object 141 * 142 * @return void 143 */ 144 lockPageHandler: function (event) { 145 var newHash = null; 146 var oldHash = null; 147 var lockId; 148 // CodeMirror lock 149 if (event.data.value === 3) { 150 newHash = event.data.content; 151 oldHash = true; 152 lockId = 'cm'; 153 } else { 154 // Don't lock on enter. 155 if (0 === event.charCode) { 156 return; 157 } 158 159 lockId = $(this).data('lock-id'); 160 if (typeof lockId === 'undefined') { 161 return; 162 } 163 /* 164 * @todo Fix Code mirror does not give correct full value (query) 165 * in textarea, it returns only the change in content. 166 */ 167 if (event.data.value === 1) { 168 newHash = AJAX.hash($(this).val()); 169 } else { 170 newHash = AJAX.hash($(this).is(':checked')); 171 } 172 oldHash = $(this).data('val-hash'); 173 } 174 // Set lock if old value !== new value 175 // otherwise release lock 176 if (oldHash !== newHash) { 177 AJAX.lockedTargets[lockId] = true; 178 } else { 179 delete AJAX.lockedTargets[lockId]; 180 }
181 // Show lock icon if locked targets is not empty. 182 // otherwise remove lock icon 183 if (!jQuery.isEmptyObject(AJAX.lockedTargets)) { 184 $('#lock_page_icon').html(PMA_getImage('s_lock', PMA_messages.strLockToolTip).toString()); 185 } else { 186 $('#lock_page_icon').html(''); 187 } 188 }, 189 /** 190 * resets the lock 191 * 192 * @return void 193 */ 194 resetLock: function () { 195 AJAX.lockedTargets = {}; 196 $('#lock_page_icon').html(''); 197 }, 198 handleMenu: { 199 replace: function (content) { 200 $('#floating_menubar').html(content) 201 // Remove duplicate wrapper 202 // TODO: don't send it in the response 203 .children().first().remove(); 204 $('#topmenu').menuResizer(PMA_mainMenuResizerCallback); 205 } 206 }, 207 /** 208 * Event handler for clicks on links and form submissions 209 * 210 * @param object e Event data 211 * 212 * @return void 213 */ 214 requestHandler: function (event) { 215 // In some cases we don't want to handle the request here and either 216 // leave the browser deal with it natively (e.g: file download) 217 // or leave an existing ajax event handler present elsewhere deal with it 218 var href = $(this).attr('href'); 219 if (typeof event !== 'undefined' && (event.shiftKey || event.ctrlKey)) { 220 return true; 221 } else if ($(this).attr('target')) { 222 return true; 223 } else if ($(this).hasClass('ajax') || $(this).hasClass('disableAjax')) { 224 // reset the lockedTargets object, as specified AJAX operation has finished 225 AJAX.resetLock(); 226 return true; 227 } else if (href && href.match(/^#/)) { 228 return true; 229 } else if (href && href.match(/^mailto/)) { 230 return true; 231 } else if ($(this).hasClass('ui-datepicker-next') || 232 $(this).hasClass('ui-datepicker-prev') 233 ) { 234 return true; 235 } 236 237 if (typeof event !== 'undefined') { 238 event.preventDefault(); 239 event.stopImmediatePropagation(); 240 } 241 242 // triggers a confirm dialog if: 243 // the user has performed some operations on loaded page 244 // the user clicks on some link, (won't trigger for buttons) 245 // the click event is not triggered by script 246 if (typeof event !== 'undefined' && event.type === 'click' && 247 event.isTrigger !== true && 248 !jQuery.isEmptyObject(AJAX.lockedTargets) && 249 confirm(PMA_messages.strConfirmNavigation) === false 250 ) { 251 return false; 252 } 253 AJAX.resetLock(); 254 var isLink = !! href || false; 255 var previousLinkAborted = false; 256 257 if (AJAX.active === true) { 258 // Cancel the old request if abortable, when the user requests 259 // something else. Otherwise silently bail out, as there is already 260 // a request well in progress. 261 if (AJAX.xhr) { 262 // In case of a link request, attempt aborting 263 AJAX.xhr.abort(); 264 if (AJAX.xhr.status === 0 && AJAX.xhr.statusText === 'abort') { 265 // If aborted 266 AJAX.$msgbox = PMA_ajaxShowMessage(PMA_messages.strAbortedRequest); 267 AJAX.active = false; 268 AJAX.xhr = null; 269 previousLinkAborted = true; 270 } else { 271 // If can't abort 272 return false; 273 } 274 } else { 275 // In case submitting a form, don't attempt aborting 276 return false; 277 } 278 } 279 280 AJAX.source = $(this); 281 282 $('html, body').animate({ scrollTop: 0 }, 'fast'); 283 284 var url = isLink ? href : $(this).attr('action'); 285 var argsep = PMA_commonParams.get('arg_separator'); 286 var params = 'ajax_request=true' + argsep + 'ajax_page_request=true'; 287 var dataPost = AJAX.source.getPostData(); 288 if (! isLink) { 289 params += argsep + $(this).serialize(); 290 } else if (dataPost) { 291 params += argsep + dataPost; 292 isLink = false;
293 } 294 if (! (history && history.pushState)) { 295 // Add a list of menu hashes that we have in the cache to the request 296 params += PMA_MicroHistory.menus.getRequestParam(); 297 } 298 299 if (AJAX._debug) { 300 console.log('Loading: ' + url); // no need to translate 301 } 302 303 if (isLink) { 304 AJAX.active = true; 305 AJAX.$msgbox = PMA_ajaxShowMessage(); 306 // Save reference for the new link request 307 AJAX.xhr = $.get(url, params, AJAX.responseHandler); 308 if (history && history.pushState) { 309 var state = { 310 url : href 311 }; 312 if (previousLinkAborted) { 313 // hack: there is already an aborted entry on stack 314 // so just modify the aborted one 315 history.replaceState(state, null, href); 316 } else { 317 history.pushState(state, null, href); 318 } 319 } 320 } else { 321 /** 322 * Manually fire the onsubmit event for the form, if any. 323 * The event was saved in the jQuery data object by an onload 324 * handler defined below. Workaround for bug #3583316 325 */ 326 var onsubmit = $(this).data('onsubmit'); 327 // Submit the request if there is no onsubmit handler 328 // or if it returns a value that evaluates to true 329 if (typeof onsubmit !== 'function' || onsubmit.apply(this, [event])) { 330 AJAX.active = true; 331 AJAX.$msgbox = PMA_ajaxShowMessage(); 332 $.post(url, params, AJAX.responseHandler); 333 } 334 } 335 }, 336 /** 337 * Called after the request that was initiated by this.requestHandler() 338 * has completed successfully or with a caught error. For completely 339 * failed requests or requests with uncaught errors, see the .ajaxError 340 * handler at the bottom of this file. 341 * 342 * To refer to self use 'AJAX', instead of 'this' as this function 343 * is called in the jQuery context. 344 * 345 * @param object e Event data 346 * 347 * @return void 348 */ 349 responseHandler: function (data) { 350 if (typeof data === 'undefined' || data === null) { 351 return; 352 } 353 if (typeof data.success !== 'undefined' && data.success) { 354 $('html, body').animate({ scrollTop: 0 }, 'fast'); 355 PMA_ajaxRemoveMessage(AJAX.$msgbox); 356 357 if (data._redirect) { 358 PMA_ajaxShowMessage(data._redirect, false); 359 AJAX.active = false; 360 AJAX.xhr = null; 361 return; 362 } 363 364 AJAX.scriptHandler.reset(function () { 365 if (data._reloadNavigation) { 366 PMA_reloadNavigation(); 367 } 368 if (data._title) { 369 $('title').replaceWith(data._title); 370 } 371 if (data._menu) { 372 if (history && history.pushState) { 373 var state = { 374 url : data._selflink, 375 menu : data._menu 376 }; 377 history.replaceState(state, null); 378 AJAX.handleMenu.replace(data._menu); 379 } else { 380 PMA_MicroHistory.menus.replace(data._menu); 381 PMA_MicroHistory.menus.add(data._menuHash, data._menu); 382 } 383 } else if (data._menuHash) { 384 if (! (history && history.pushState)) { 385 PMA_MicroHistory.menus.replace(PMA_MicroHistory.menus.get(data._menuHash)); 386 } 387 } 388 if (data._disableNaviSettings) { 389 PMA_disableNaviSettings(); 390 } else { 391 PMA_ensureNaviSettings(data._selflink); 392 } 393 394 // Remove all containers that may have 395 // been added outside of #page_content 396 $('body').children() 397 .not('#pma_navigation') 398 .not('#floating_menubar') 399 .not('#page_nav_icons') 400 .not('#page_content') 401 .not('#selflink') 402 .not('#pma_header') 403 .not('#pma_footer') 404 .not('#pma_demo') 405 .not('#pma_console_container') 406 .not('#prefs_autoload') 407 .remove(); 408 // Replace #page_content with new content 409 if (data.message && data.message.length > 0) { 410 $('#page_content').replaceWith( 411 '<div id=\'page_content\'>' + data.message + '</div>' 412 ); 413 PMA_highlightSQL($('#page_content')); 414 checkNumberOfFields(); 415 } 416 417 if (data._selflink) { 418 var source = data._selflink.split('?')[0]; 419 // Check for faulty links 420 $selflink_replace = { 421 'import.php': 'tbl_sql.php', 422 'tbl_chart.php': 'sql.php', 423 'tbl_gis_visualization.php': 'sql.php' 424 }; 425 if ($selflink_replace[source]) { 426 var replacement = $selflink_replace[source]; 427 data._selflink = data._selflink.replace(source, replacement); 428 } 429 $('#selflink').find('> a').attr('href', data._selflink); 430 } 431 if (data._params) { 432 PMA_commonParams.setAll(data._params); 433 } 434 if (data._scripts) { 435 AJAX.scriptHandler.load(data._scripts); 436 } 437 if (data._selflink && data._scripts && data._menuHash && data._params) { 438 if (! (history && history.pushState)) { 439 PMA_MicroHistory.add( 440 data._selflink, 441 data._scripts, 442 data._menuHash, 443 data._params, 444 AJAX.source.attr('rel') 445 ); 446 } 447 } 448 if (data._displayMessage) { 449 $('#page_content').prepend(data._displayMessage); 450 PMA_highlightSQL($('#page_content')); 451 } 452 453 $('#pma_errors').remove(); 454 455 var msg = ''; 456 if (data._errSubmitMsg) { 457 msg = data._errSubmitMsg; 458 } 459 if (data._errors) { 460 $('<div/>', { id : 'pma_errors', class : 'clearfloat' }) 461 .insertAfter('#selflink') 462 .append(data._errors); 463 // bind for php error reporting forms (bottom) 464 $('#pma_ignore_errors_bottom').on('click', function (e) { 465 e.preventDefault(); 466 PMA_ignorePhpErrors(); 467 }); 468 $('#pma_ignore_all_errors_bottom').on('click', function (e) { 469 e.preventDefault(); 470 PMA_ignorePhpErrors(false); 471 }); 472 // In case of 'sendErrorReport'='always' 473 // submit the hidden error reporting form. 474 if (data._sendErrorAlways === '1' && 475 data._stopErrorReportLoop !== '1' 476 ) { 477 $('#pma_report_errors_form').submit(); 478 PMA_ajaxShowMessage(PMA_messages.phpErrorsBeingSubmitted, false); 479 $('html, body').animate({ scrollTop:$(document).height() }, 'slow'); 480 } else if (data._promptPhpErrors) { 481 // otherwise just prompt user if it is set so. 482 msg = msg + PMA_messages.phpErrorsFound; 483 // scroll to bottom where all the errors are displayed. 484 $('html, body').animate({ scrollTop:$(document).height() }, 'slow'); 485 } 486 } 487 PMA_ajaxShowMessage(msg, false); 488 // bind for php error reporting forms (popup) 489 $('#pma_ignore_errors_popup').on('click', function () { 490 PMA_ignorePhpErrors(); 491 }); 492 $('#pma_ignore_all_errors_popup').on('click', function () { 493 PMA_ignorePhpErrors(false); 494 }); 495 496 if (typeof AJAX._callback === 'function') { 497 AJAX._callback.call(); 498 } 499 AJAX._callback = function () {}; 500 }); 501 } else { 502 PMA_ajaxShowMessage(data.error, false); 503 AJAX.active = false;
504 AJAX.xhr = null; 505 PMA_handleRedirectAndReload(data); 506 if (data.fieldWithError) { 507 $(':input.error').removeClass('error'); 508 $('#' + data.fieldWithError).addClass('error'); 509 } 510 } 511 }, 512 /** 513 * This object is in charge of downloading scripts, 514 * keeping track of what's downloaded and firing 515 * the onload event for them when the page is ready. 516 */ 517 scriptHandler: { 518 /** 519 * @var array _scripts The list of files already downloaded 520 */ 521 _scripts: [], 522 /** 523 * @var string _scriptsVersion version of phpMyAdmin from which the 524 * scripts have been loaded 525 */ 526 _scriptsVersion: null, 527 /** 528 * @var array _scriptsToBeLoaded The list of files that 529 * need to be downloaded 530 */ 531 _scriptsToBeLoaded: [], 532 /** 533 * @var array _scriptsToBeFired The list of files for which 534 * to fire the onload and unload events 535 */ 536 _scriptsToBeFired: [], 537 _scriptsCompleted: false, 538 /** 539 * Records that a file has been downloaded 540 * 541 * @param string file The filename 542 * @param string fire Whether this file will be registering 543 * onload/teardown events 544 * 545 * @return self For chaining 546 */ 547 add: function (file, fire) { 548 this._scripts.push(file); 549 if (fire) { 550 // Record whether to fire any events for the file 551 // This is necessary to correctly tear down the initial page 552 this._scriptsToBeFired.push(file); 553 } 554 return this; 555 }, 556 /** 557 * Download a list of js files in one request 558 * 559 * @param array files An array of filenames and flags 560 * 561 * @return void 562 */ 563 load: function (files, callback) { 564 var self = this; 565 var i; 566 // Clear loaded scripts if they are from another version of phpMyAdmin. 567 // Depends on common params being set before loading scripts in responseHandler 568 if (self._scriptsVersion === null) { 569 self._scriptsVersion = PMA_commonParams.get('PMA_VERSION'); 570 } else if (self._scriptsVersion !== PMA_commonParams.get('PMA_VERSION')) { 571 self._scripts = []; 572 self._scriptsVersion = PMA_commonParams.get('PMA_VERSION'); 573 } 574 self._scriptsCompleted = false; 575 self._scriptsToBeFired = []; 576 // We need to first complete list of files to load 577 // as next loop will directly fire requests to load them 578 // and that triggers removal of them from 579 // self._scriptsToBeLoaded 580 for (i in files) { 581 self._scriptsToBeLoaded.push(files[i].name); 582 if (files[i].fire) { 583 self._scriptsToBeFired.push(files[i].name); 584 } 585 } 586 for (i in files) { 587 var script = files[i].name; 588 // Only for scripts that we don't already have 589 if ($.inArray(script, self._scripts) === -1) { 590 this.add(script); 591 this.appendScript(script, callback); 592 } else { 593 self.done(script, callback); 594 } 595 } 596 // Trigger callback if there is nothing else to load 597 self.done(null, callback); 598 }, 599 /** 600 * Called whenever all files are loaded 601 * 602 * @return void 603 */ 604 done: function (script, callback) { 605 if (typeof ErrorReport !== 'undefined') { 606 ErrorReport.wrap_global_functions(); 607 } 608 if ($.inArray(script, this._scriptsToBeFired)) { 609 AJAX.fireOnload(script); 610 } 611 if ($.inArray(script, this._scriptsToBeLoaded)) { 612 this._scriptsToBeLoaded.splice($.inArray(script, this._scriptsToBeLoaded), 1
612); 613 } 614 if (script === null) { 615 this._scriptsCompleted = true; 616 } 617 /* We need to wait for last signal (with null) or last script load */ 618 AJAX.active = (this._scriptsToBeLoaded.length > 0) || ! this._scriptsCompleted; 619 /* Run callback on last script */ 620 if (! AJAX.active && $.isFunction(callback)) { 621 callback(); 622 } 623 }, 624 /** 625 * Appends a script element to the head to load the scripts 626 * 627 * @return void 628 */ 629 appendScript: function (name, callback) { 630 var head = document.head || document.getElementsByTagName('head')[0]; 631 var script = document.createElement('script'); 632 var self = this; 633 634 script.type = 'text/javascript'; 635 script.src = 'js/' + name + '?' + 'v=' + encodeURIComponent(PMA_commonParams.get('PMA_VERSION')); 636 script.async = false; 637 script.onload = function () { 638 self.done(name, callback); 639 }; 640 head.appendChild(script); 641 }, 642 /** 643 * Fires all the teardown event handlers for the current page 644 * and rebinds all forms and links to the request handler 645 * 646 * @param function callback The callback to call after resetting 647 * 648 * @return void 649 */ 650 reset: function (callback) { 651 for (var i in this._scriptsToBeFired) { 652 AJAX.fireTeardown(this._scriptsToBeFired[i]); 653 } 654 this._scriptsToBeFired = []; 655 /** 656 * Re-attach a generic event handler to clicks 657 * on pages and submissions of forms 658 */ 659 $(document).off('click', 'a').on('click', 'a', AJAX.requestHandler); 660 $(document).off('submit', 'form').on('submit', 'form', AJAX.requestHandler); 661 if (! (history && history.pushState)) { 662 PMA_MicroHistory.update(); 663 } 664 callback(); 665 } 666 } 667}; 668 669/** 670 * Here we register a function that will remove the onsubmit event from all 671 * forms that will be handled by the generic page loader. We then save this 672 * event handler in the "jQuery data", so that we can fire it up later in 673 * AJAX.requestHandler(). 674 * 675 * See bug #3583316 676 */ 677AJAX.registerOnload('functions.js', function () { 678 // Registering the onload event for functions.js 679 // ensures that it will be fired for all pages 680 $('form').not('.ajax').not('.disableAjax').each(function () { 681 if ($(this).attr('onsubmit')) { 682 $(this).data('onsubmit', this.onsubmit).attr('onsubmit', ''); 683 } 684 }); 685 686 var $page_content = $('#page_content'); 687 /** 688 * Workaround for passing submit button name,value on ajax form submit 689 * by appending hidden element with submit button name and value. 690 */ 691 $page_content.on('click', 'form input[type=submit]', function () { 692 var buttonName = $(this).attr('name'); 693 if (typeof buttonName === 'undefined') { 694 return; 695 } 696 $(this).closest('form').append($('<input/>', { 697 'type' : 'hidden', 698 'name' : buttonName, 699 'value': $(this).val() 700 })); 701 }); 702 703 /** 704 * Attach event listener to events when user modify visible 705 * Input,Textarea and select fields to make changes in forms 706 */ 707 $page_content.on( 708 'keyup change', 709 'form.lock-page textarea, ' + 710 'form.lock-page input[type="text"], ' + 711 'form.lock-page input[type="number"], ' + 712 'form.lock-page select', 713 { value:1 }, 714 AJAX.lockPageHandler 715 ); 716 $page_content.on( 717 'change', 718 'form.lock-page input[type="checkbox"], ' + 719 'form.lock-page input[type="radio"]', 720 { value:2 }, 721 AJAX.lockPageHandler 722 ); 723 /** 724 * Reset lock when lock-page form reset event is fired 725 * Note: reset does not bubble in all browser so attach to 726 * form directly. 727 */ 728 $('form.lock-page').on('reset', function (event) { 729 AJAX.resetLock(); 730 }); 731}); 732 733/** 734 * Page load event handler 735 */ 736$(function () { 737 var menuContent = $('<div></div>') 738 .append($('#serverinfo').clone()) 739 .append($('#topmenucontainer').clone()) 740 .html(); 741 if (history && history.pushState) { 742 // set initial state reload 743 var initState = ('state' in window.history && window.history.state !== null); 744 var initURL = $('#selflink').find('> a').attr('href') || location.href; 745 var state = { 746 url : initURL, 747 menu : menuContent 748 }; 749 history.replaceState(state, null); 750 751 $(window).on('popstate', function (event) { 752 var initPop = (! initState && location.href === initURL); 753 initState = true; 754 // check if popstate fired on first page itself 755 if (initPop) { 756 return; 757 } 758 var state = event.originalEvent.state; 759 if (state && state.menu) {
760 AJAX.$msgbox = PMA_ajaxShowMessage(); 761 var params = 'ajax_request=true' + PMA_commonParams.get('arg_separator') + 'ajax_page_request=true'; 762 var url = state.url || location.href; 763 $.get(url, params, AJAX.responseHandler); 764 // TODO: Check if sometimes menu is not retrieved from server, 765 // Not sure but it seems menu was missing only for printview which 766 // been removed lately, so if it's right some dead menu checks/fallbacks 767 // may need to be removed from this file and Header.php 768 // AJAX.handleMenu.replace(event.originalEvent.state.menu); 769 } 770 }); 771 } else { 772 // Fallback to microhistory mechanism 773 AJAX.scriptHandler 774 .load([{ 'name' : 'microhistory.js', 'fire' : 1 }], function () { 775 // The cache primer is set by the footer class 776 if (PMA_MicroHistory.primer.url) { 777 PMA_MicroHistory.menus.add( 778 PMA_MicroHistory.primer.menuHash, 779 menuContent 780 ); 781 } 782 $(function () { 783 // Queue up this event twice to make sure that we get a copy 784 // of the page after all other onload events have been fired 785 if (PMA_MicroHistory.primer.url) { 786 PMA_MicroHistory.add( 787 PMA_MicroHistory.primer.url, 788 PMA_MicroHistory.primer.scripts, 789 PMA_MicroHistory.primer.menuHash 790 ); 791 } 792 }); 793 }); 794 } 795}); 796 797/** 798 * Attach a generic event handler to clicks 799 * on pages and submissions of forms 800 */ 801$(document).on('click', 'a', AJAX.requestHandler); 802$(document).on('submit', 'form', AJAX.requestHandler); 803 804/** 805 * Gracefully handle fatal server errors 806 * (e.g: 500 - Internal server error) 807 */ 808$(document).ajaxError(function (event, request, settings) { 809 if (AJAX._debug) { 810 console.log('AJAX error: status=' + request.status + ', text=' + request.statusText); 811 } 812 // Don't handle aborted requests 813 if (request.status !== 0 || request.statusText !== 'abort') { 814 var details = ''; 815 var state = request.state(); 816 817 if (request.status !== 0) { 818 details += '<div>' + escapeHtml(PMA_sprintf(PMA_messages.strErrorCode, request.status)) + '</div>'; 819 } 820 details += '<div>' + escapeHtml(PMA_sprintf(PMA_messages.strErrorText, request.statusText + ' (' + state + ')')) + '</div>'; 821 if (state === 'rejected' || state === 'timeout') { 822 details += '<div>' + escapeHtml(PMA_messages.strErrorConnection) + '</div>'; 823 } 824 PMA_ajaxShowMessage( 825 '<div class="error">' + 826 PMA_messages.strErrorProcessingRequest + 827 details + 828 '</div>', 829 false 830 ); 831 AJAX.active = false; 832 AJAX.xhr = null; 833 } 834});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.