Merge pull request #14465 from Piyush3079/Mod_Js_Server_Privileges

server_privileges and server_databases modularized
This commit is contained in:
Deven Bansod 2018-07-26 19:50:48 +05:30 committed by GitHub
commit dfcca3c46e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 3422 additions and 82 deletions

View File

@ -1,3 +1,4 @@
{
"presets": ["env"]
"presets": ["env"],
"plugins": ["syntax-dynamic-import"]
}

View File

@ -5,9 +5,12 @@
"node": true,
"es6": true
},
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"allowImportExportEverywhere": true,
"codeFrame": false,
"ecmaFeatures": {
"jsx": false
}

1
.gitignore vendored
View File

@ -55,3 +55,4 @@ composer.lock
/vendor/
# NPM
/node_modules/
yarn.lock

40
js/common_params.php Normal file
View File

@ -0,0 +1,40 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Exporting of common params defined in Header.php to make them available in
* the global window object and then serialize these variables in the modules.
*
* @package PhpMyAdmin
*/
if (!defined('TESTSUITE')) {
chdir('..');
// Send correct type:
header('Content-Type: text/javascript; charset=UTF-8');
// Cache output in client - the nocache query parameter makes sure that this
// file is reloaded when config changes
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT');
// Avoid loading the full common.inc.php because this would add many
// non-js-compatible stuff like DOCTYPE
define('PMA_MINIMUM_COMMON', true);
define('PMA_PATH_TO_BASEDIR', '../');
require_once './libraries/common.inc.php';
// Close session early as we won't write anything there
session_write_close();
}
// But this one is needed for Sanitize::escapeJsString()
use PhpMyAdmin\Header;
use PhpMyAdmin\Sanitize;
$header = new Header();
echo "var common_params = new Array();\n";
foreach ($header->getJsParams() as $name => $value) {
Sanitize::printJsValue("common_params['" . $name . "']", $value);
}
?>

View File

@ -5105,3 +5105,63 @@ jQuery.fn.getPostData = function () {
}
return dataPost;
};
/**
* @todo REMOVE THESE FUNCTIONS AFTER COMPLETE CODE BEING MODULAR
*
* Copy of functions copied from different files to make them globally
* available so that build does not break during modularisation
*/
/**
* server_privilages.js
*/
/**
* Validates the "add a user" form
*
* @return boolean whether the form is validated or not
*/
function checkAddUser (the_form) {
if (the_form.elements.pred_hostname.value === 'userdefined' && the_form.elements.hostname.value === '') {
alert(PMA_messages.strHostEmpty);
the_form.elements.hostname.focus();
return false;
}
if (the_form.elements.pred_username.value === 'userdefined' && the_form.elements.username.value === '') {
alert(PMA_messages.strUserEmpty);
the_form.elements.username.focus();
return false;
}
return PMA_checkPassword($(the_form));
} // end of the 'checkAddUser()' function
function checkPasswordStrength (value, meter_obj, meter_object_label, username) {
// List of words we don't want to appear in the password
var customDict = [
'phpmyadmin',
'mariadb',
'mysql',
'php',
'my',
'admin',
];
if (username !== null) {
customDict.push(username);
}
var zxcvbn_obj = zxcvbn(value, customDict);
var strength = zxcvbn_obj.score;
strength = parseInt(strength);
meter_obj.val(strength);
switch (strength) {
case 0: meter_object_label.html(PMA_messages.strExtrWeak);
break;
case 1: meter_object_label.html(PMA_messages.strVeryWeak);
break;
case 2: meter_object_label.html(PMA_messages.strWeak);
break;
case 3: meter_object_label.html(PMA_messages.strGood);
break;
case 4: meter_object_label.html(PMA_messages.strStrong);
}
}

View File

@ -755,6 +755,26 @@ foreach ($js_messages as $name => $js_message) {
Sanitize::printJsValue("PMA_messages['" . $name . "']", $js_message);
}
/* for new js code */
/* Calendar */
echo "var globalVars = new Array();\n";
echo "globalVars['themeCalendarImage'] = '" , $GLOBALS['pmaThemeImage']
, 'b_calendar.png' , "';\n";
/* Image path */
echo "globalVars['pmaThemeImage'] = '" , $GLOBALS['pmaThemeImage'] , "';\n";
echo "globalVars['mysql_doc_template'] = '" , PhpMyAdmin\Util::getMySQLDocuURL('%s')
, "';\n";
//Max input vars allowed by PHP.
$maxInputVars = ini_get('max_input_vars');
echo "globalVars['maxInputVars'] = '"
, (false === $maxInputVars || '' == $maxInputVars ? 'false' : (int)$maxInputVars)
, ';' . "'\n";
/* for new js code */
/* for old js code */
/* Calendar */
echo "var themeCalendarImage = '" , $GLOBALS['pmaThemeImage']
, 'b_calendar.png' , "';\n";
@ -770,7 +790,144 @@ $maxInputVars = ini_get('max_input_vars');
echo 'var maxInputVars = '
, (false === $maxInputVars || '' == $maxInputVars ? 'false' : (int)$maxInputVars)
, ';' . "\n";
/* for old js code */
/* for new js code */
echo "datePicker = new Array();\n";
echo "timePicker = new Array();\n";
/* l10n: Display text for calendar close link */
Sanitize::printJsValue("datePicker['closeText']", __('Done'));
/* l10n: Display text for previous month link in calendar */
Sanitize::printJsValue(
"datePicker['prevText']",
_pgettext('Previous month', 'Prev')
);
/* l10n: Display text for next month link in calendar */
Sanitize::printJsValue(
"datePicker['nextText']",
_pgettext('Next month', 'Next')
);
/* l10n: Display text for current month link in calendar */
Sanitize::printJsValue("datePicker['currentText']", __('Today'));
Sanitize::printJsValue(
"datePicker['monthNames']",
array(
__('January'),
__('February'),
__('March'),
__('April'),
__('May'),
__('June'),
__('July'),
__('August'),
__('September'),
__('October'),
__('November'),
__('December')
)
);
Sanitize::printJsValue(
"datePicker['monthNamesShort']",
array(
/* l10n: Short month name */
__('Jan'),
/* l10n: Short month name */
__('Feb'),
/* l10n: Short month name */
__('Mar'),
/* l10n: Short month name */
__('Apr'),
/* l10n: Short month name */
_pgettext('Short month name', 'May'),
/* l10n: Short month name */
__('Jun'),
/* l10n: Short month name */
__('Jul'),
/* l10n: Short month name */
__('Aug'),
/* l10n: Short month name */
__('Sep'),
/* l10n: Short month name */
__('Oct'),
/* l10n: Short month name */
__('Nov'),
/* l10n: Short month name */
__('Dec')
)
);
Sanitize::printJsValue(
"datePicker['dayNames']",
array(
__('Sunday'),
__('Monday'),
__('Tuesday'),
__('Wednesday'),
__('Thursday'),
__('Friday'),
__('Saturday')
)
);
Sanitize::printJsValue(
"datePicker['dayNamesShort']",
array(
/* l10n: Short week day name */
__('Sun'),
/* l10n: Short week day name */
__('Mon'),
/* l10n: Short week day name */
__('Tue'),
/* l10n: Short week day name */
__('Wed'),
/* l10n: Short week day name */
__('Thu'),
/* l10n: Short week day name */
__('Fri'),
/* l10n: Short week day name */
__('Sat')
)
);
Sanitize::printJsValue(
"datePicker['dayNamesMin']",
array(
/* l10n: Minimal week day name */
__('Su'),
/* l10n: Minimal week day name */
__('Mo'),
/* l10n: Minimal week day name */
__('Tu'),
/* l10n: Minimal week day name */
__('We'),
/* l10n: Minimal week day name */
__('Th'),
/* l10n: Minimal week day name */
__('Fr'),
/* l10n: Minimal week day name */
__('Sa')
)
);
/* l10n: Column header for week of the year in calendar */
Sanitize::printJsValue("datePicker['weekHeader']", __('Wk'));
Sanitize::printJsValue(
"datePicker['showMonthAfterYear']",
/* l10n: Month-year order for calendar, use either "calendar-month-year"
* or "calendar-year-month".
*/
(__('calendar-month-year') == 'calendar-year-month')
);
/* l10n: Year suffix for calendar, "none" is empty. */
$year_suffix = _pgettext('Year suffix', 'none');
Sanitize::printJsValue(
"datePicker['yearSuffix']",
($year_suffix == 'none' ? '' : $year_suffix)
);
Sanitize::printJsValue("timePicker['timeText']", __('Time'));
Sanitize::printJsValue("timePicker['hourText']", __('Hour'));
Sanitize::printJsValue("timePicker['minuteText']", __('Minute'));
Sanitize::printJsValue("timePicker['secondText']", __('Second'));
/* for new js code */
/* for old js code */
echo "if ($.datepicker) {\n";
/* l10n: Display text for calendar close link */
Sanitize::printJsValue("$.datepicker.regional['']['closeText']", __('Done'));
@ -908,11 +1065,78 @@ Sanitize::printJsValue("$.timepicker.regional['']['timeText']", __('Time'));
Sanitize::printJsValue("$.timepicker.regional['']['hourText']", __('Hour'));
Sanitize::printJsValue("$.timepicker.regional['']['minuteText']", __('Minute'));
Sanitize::printJsValue("$.timepicker.regional['']['secondText']", __('Second'));
/* for old js code */
?>
$.extend($.timepicker._defaults, $.timepicker.regional['']);
} /* if ($.timepicker) */
<?php
/* for new js code */
/* Form validation */
/* Default validation functions */
echo "validationMessage = {\n";
Sanitize::printJsValueForFormValidation('required', __('This field is required'));
Sanitize::printJsValueForFormValidation('remote', __('Please fix this field'));
Sanitize::printJsValueForFormValidation('email', __('Please enter a valid email address'));
Sanitize::printJsValueForFormValidation('url', __('Please enter a valid URL'));
Sanitize::printJsValueForFormValidation('date', __('Please enter a valid date'));
Sanitize::printJsValueForFormValidation(
'dateISO',
__('Please enter a valid date ( ISO )')
);
Sanitize::printJsValueForFormValidation('number', __('Please enter a valid number'));
Sanitize::printJsValueForFormValidation(
'creditcard',
__('Please enter a valid credit card number')
);
Sanitize::printJsValueForFormValidation('digits', __('Please enter only digits'));
Sanitize::printJsValueForFormValidation(
'equalTo',
__('Please enter the same value again')
);
echo "\n};\n";
echo "validationFormat = {\n";
Sanitize::printJsValueForFormValidation(
'maxlength',
__('Please enter no more than {0} characters')
);
Sanitize::printJsValueForFormValidation(
'minlength',
__('Please enter at least {0} characters')
);
Sanitize::printJsValueForFormValidation(
'rangelength',
__('Please enter a value between {0} and {1} characters long')
);
Sanitize::printJsValueForFormValidation(
'range',
__('Please enter a value between {0} and {1}')
);
Sanitize::printJsValueForFormValidation(
'max',
__('Please enter a value less than or equal to {0}')
);
Sanitize::printJsValueForFormValidation(
'min',
__('Please enter a value greater than or equal to {0}')
);
/* customed functions */
Sanitize::printJsValueForFormValidation(
'validationFunctionForDateTime',
__('Please enter a valid date or time')
);
Sanitize::printJsValueForFormValidation(
'validationFunctionForHex',
__('Please enter a valid HEX input')
);
Sanitize::printJsValueForFormValidation(
'validationFunctionForFuns',
__('Error')
);
echo "\n};\n";
/* for new js code */
/* for old js code */
/* Form validation */
echo "function extendingValidatorMessages() {\n";
@ -986,4 +1210,5 @@ Sanitize::printJsValueForFormValidation(
);
echo "\n});";
echo "\n} /* if ($.validator) */";
/* for old js code */
?>

View File

@ -9,57 +9,6 @@
*
*/
/**
* Validates the "add a user" form
*
* @return boolean whether the form is validated or not
*/
function checkAddUser (the_form) {
if (the_form.elements.pred_hostname.value === 'userdefined' && the_form.elements.hostname.value === '') {
alert(PMA_messages.strHostEmpty);
the_form.elements.hostname.focus();
return false;
}
if (the_form.elements.pred_username.value === 'userdefined' && the_form.elements.username.value === '') {
alert(PMA_messages.strUserEmpty);
the_form.elements.username.focus();
return false;
}
return PMA_checkPassword($(the_form));
} // end of the 'checkAddUser()' function
function checkPasswordStrength (value, meter_obj, meter_object_label, username) {
// List of words we don't want to appear in the password
customDict = [
'phpmyadmin',
'mariadb',
'mysql',
'php',
'my',
'admin',
];
if (username !== null) {
customDict.push(username);
}
var zxcvbn_obj = zxcvbn(value, customDict);
var strength = zxcvbn_obj.score;
strength = parseInt(strength);
meter_obj.val(strength);
switch (strength) {
case 0: meter_obj_label.html(PMA_messages.strExtrWeak);
break;
case 1: meter_obj_label.html(PMA_messages.strVeryWeak);
break;
case 2: meter_obj_label.html(PMA_messages.strWeak);
break;
case 3: meter_obj_label.html(PMA_messages.strGood);
break;
case 4: meter_obj_label.html(PMA_messages.strStrong);
}
}
/**
* AJAX scripts for server_privileges page.
*
@ -75,7 +24,6 @@ function checkPasswordStrength (value, meter_obj, meter_object_label, username)
* @name document.ready
*/
/**
* Unbind all event handlers before tearing down a page
*/

757
js/src/ajax.js Normal file
View File

@ -0,0 +1,757 @@
import { PMA_ajaxShowMessage } from './utils/show_ajax_messages';
import { PMA_Messages as PMA_messages } from './variables/export_variables';
import { PMA_commonParams } from './variables/common_params';
import { jQuery as $ } from './utils/JqueryExtended';
import { PMA_getImage } from './functions/get_image';
/**
* This object handles ajax requests for pages. It also
* handles the reloading of the main menu and scripts.
*/
/**
* @todo this function is to be removed when complete code is modularised
*/
function checkNewCode (script) {
var check = script.split('.js');
// console.log(check);
if (check.length === 2) {
return false;
} else {
return true;
}
}
export let AJAX = {
/**
* @var bool test variable for checking this object
*/
test: false,
/**
* @var bool active Whether we are busy
*/
active: false,
/**
* @var object source The object whose event initialized the request
*/
source: null,
/**
* @var object xhr A reference to the ajax request that is currently running
*/
xhr: null,
/**
* @var object lockedTargets, list of locked targets
*/
lockedTargets: {},
/**
* @var function Callback to execute after a successful request
* Used by PMA_commonFunctions from common.js
*/
_callback: function () {},
/**
* @var bool _debug Makes noise in your Firebug console
*/
_debug: false,
/**
* @var object $msgbox A reference to a jQuery object that links to a message
* box that is generated by PMA_ajaxShowMessage()
*/
$msgbox: null,
/**
* Given the filename of a script, returns a hash to be
* used to refer to all the events registered for the file
*
* @param key string key The filename for which to get the event name
*
* @return int
*/
hash: function (key) {
/* http://burtleburtle.net/bob/hash/doobs.html#one */
key += '';
var len = key.length;
var hash = 0;
var 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 Math.abs(hash);
},
/**
* Registers an onload event for a file
*
* @param file string file The filename for which to register the event
* @param func function func The function to execute when the page is ready
*
* @return self For chaining
*/
registerOnload: function (file, func) {
var eventName = 'onload_' + this.hash(file);
$(document).on(eventName, func);
if (this._debug) {
console.log(
// no need to translate
'Registered event ' + eventName + ' for file ' + file
);
}
return this;
},
/**
* Registers a teardown event for a file. This is useful to execute functions
* that unbind events for page elements that are about to be removed.
*
* @param string file The filename for which to register the event
* @param function func The function to execute when
* the page is about to be torn down
*
* @return self For chaining
*/
registerTeardown: function (file, func) {
var eventName = 'teardown_' + this.hash(file);
$(document).on(eventName, func);
if (this._debug) {
console.log(
// no need to translate
'Registered event ' + eventName + ' for file ' + file
);
}
return this;
},
/**
* 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) {
var eventName = 'onload_' + this.hash(file);
$(document).trigger(eventName);
if (this._debug) {
console.log(
// no need to translate
'Fired event ' + eventName + ' for file ' + file
);
}
},
/**
* Called just before a page is torn down, once for every
* file that registered to the teardown event of that file.
*
* @param string file The filename for which to fire the event
*
* @return void
*/
fireTeardown: function (file) {
var eventName = 'teardown_' + this.hash(file);
$(document).triggerHandler(eventName);
if (this._debug) {
console.log(
// no need to translate
'Fired event ' + eventName + ' for file ' + file
);
}
},
/**
* function to handle lock page mechanism
*
* @param event the event object
*
* @return void
*/
lockPageHandler: function (event) {
var newHash = null;
var oldHash = null;
var lockId;
// CodeMirror lock
if (event.data.value === 3) {
newHash = event.data.content;
oldHash = true;
lockId = 'cm';
} else {
// Don't lock on enter.
if (0 === event.charCode) {
return;
}
lockId = $(this).data('lock-id');
if (typeof lockId === 'undefined') {
return;
}
/*
* @todo Fix Code mirror does not give correct full value (query)
* in textarea, it returns only the change in content.
*/
if (event.data.value === 1) {
newHash = AJAX.hash($(this).val());
} else {
newHash = AJAX.hash($(this).is(':checked'));
}
oldHash = $(this).data('val-hash');
}
// Set lock if old value !== new value
// otherwise release lock
if (oldHash !== newHash) {
AJAX.lockedTargets[lockId] = true;
} else {
delete AJAX.lockedTargets[lockId];
}
// Show lock icon if locked targets is not empty.
// otherwise remove lock icon
if (!$.isEmptyObject(AJAX.lockedTargets)) {
$('#lock_page_icon').html(PMA_getImage('s_lock', PMA_messages.strLockToolTip).toString());
} else {
$('#lock_page_icon').html('');
}
},
/**
* resets the lock
*
* @return void
*/
resetLock: function () {
AJAX.lockedTargets = {};
$('#lock_page_icon').html('');
},
handleMenu: {
replace: function (content) {
$('#floating_menubar').html(content)
// Remove duplicate wrapper
// TODO: don't send it in the response
.children().first().remove();
$('#topmenu').menuResizer(PMA_mainMenuResizerCallback);
}
},
/**
* Event handler for clicks on links and form submissions
*
* @param object e Event data
*
* @return void
*/
requestHandler: function (event) {
// In some cases we don't want to handle the request here and either
// leave the browser deal with it natively (e.g: file download)
// or leave an existing ajax event handler present elsewhere deal with it
var href = $(this).attr('href');
if (typeof event !== 'undefined' && (event.shiftKey || event.ctrlKey)) {
return true;
} else if ($(this).attr('target')) {
return true;
} else if ($(this).hasClass('ajax') || $(this).hasClass('disableAjax')) {
// reset the lockedTargets object, as specified AJAX operation has finished
AJAX.resetLock();
return true;
} else if (href && href.match(/^#/)) {
return true;
} else if (href && href.match(/^mailto/)) {
return true;
} else if ($(this).hasClass('ui-datepicker-next') ||
$(this).hasClass('ui-datepicker-prev')
) {
return true;
}
if (typeof event !== 'undefined') {
event.preventDefault();
event.stopImmediatePropagation();
}
// triggers a confirm dialog if:
// the user has performed some operations on loaded page
// the user clicks on some link, (won't trigger for buttons)
// the click event is not triggered by script
if (typeof event !== 'undefined' && event.type === 'click' &&
event.isTrigger !== true &&
!$.isEmptyObject(AJAX.lockedTargets)
) {
if (confirm(PMA_messages.strConfirmNavigation) === false) {
return false;
} else {
if (isStorageSupported('localStorage')) {
window.localStorage.removeItem('auto_saved_sql');
} else {
Cookies.set('auto_saved_sql', '');
}
}
}
AJAX.resetLock();
var isLink = !! href || false;
var previousLinkAborted = false;
if (AJAX.active === true) {
// Cancel the old request if abortable, when the user requests
// something else. Otherwise silently bail out, as there is already
// a request well in progress.
if (AJAX.xhr) {
// In case of a link request, attempt aborting
AJAX.xhr.abort();
if (AJAX.xhr.status === 0 && AJAX.xhr.statusText === 'abort') {
// If aborted
AJAX.$msgbox = PMA_ajaxShowMessage(PMA_messages.strAbortedRequest);
AJAX.active = false;
AJAX.xhr = null;
previousLinkAborted = true;
} else {
// If can't abort
return false;
}
} else {
// In case submitting a form, don't attempt aborting
return false;
}
}
AJAX.source = $(this);
$('html, body').animate({ scrollTop: 0 }, 'fast');
var url = isLink ? href : $(this).attr('action');
var argsep = PMA_commonParams.get('arg_separator');
var params = 'ajax_request=true' + argsep + 'ajax_page_request=true';
var dataPost = AJAX.source.getPostData();
if (! isLink) {
params += argsep + $(this).serialize();
} else if (dataPost) {
params += argsep + dataPost;
isLink = false;
}
if (! (history && history.pushState)) {
// Add a list of menu hashes that we have in the cache to the request
params += PMA_MicroHistory.menus.getRequestParam();
}
if (AJAX._debug) {
console.log('Loading: ' + url); // no need to translate
}
if (isLink) {
AJAX.active = true;
AJAX.$msgbox = PMA_ajaxShowMessage();
// Save reference for the new link request
AJAX.xhr = $.get(url, params, AJAX.responseHandler);
if (history && history.pushState) {
var state = {
url : href
};
if (previousLinkAborted) {
// hack: there is already an aborted entry on stack
// so just modify the aborted one
history.replaceState(state, null, href);
} else {
history.pushState(state, null, href);
}
}
} else {
/**
* Manually fire the onsubmit event for the form, if any.
* The event was saved in the jQuery data object by an onload
* handler defined below. Workaround for bug #3583316
*/
var onsubmit = $(this).data('onsubmit');
// Submit the request if there is no onsubmit handler
// or if it returns a value that evaluates to true
if (typeof onsubmit !== 'function' || onsubmit.apply(this, [event])) {
AJAX.active = true;
AJAX.$msgbox = PMA_ajaxShowMessage();
$.post(url, params, AJAX.responseHandler);
}
}
},
/**
* Called after the request that was initiated by this.requestHandler()
* has completed successfully or with a caught error. For completely
* failed requests or requests with uncaught errors, see the .ajaxError
* handler at the bottom of this file.
*
* To refer to self use 'AJAX', instead of 'this' as this function
* is called in the jQuery context.
*
* @param object e Event data
*
* @return void
*/
responseHandler: function (data) {
if (typeof data === 'undefined' || data === null) {
return;
}
if (typeof data.success !== 'undefined' && data.success) {
$('html, body').animate({ scrollTop: 0 }, 'fast');
PMA_ajaxRemoveMessage(AJAX.$msgbox);
if (data._redirect) {
PMA_ajaxShowMessage(data._redirect, false);
AJAX.active = false;
AJAX.xhr = null;
return;
}
AJAX.scriptHandler.reset(function () {
if (data._reloadNavigation) {
PMA_reloadNavigation();
}
if (data._title) {
$('title').replaceWith(data._title);
}
if (data._menu) {
if (history && history.pushState) {
var state = {
url : data._selflink,
menu : data._menu
};
history.replaceState(state, null);
AJAX.handleMenu.replace(data._menu);
} else {
PMA_MicroHistory.menus.replace(data._menu);
PMA_MicroHistory.menus.add(data._menuHash, data._menu);
}
} else if (data._menuHash) {
if (! (history && history.pushState)) {
PMA_MicroHistory.menus.replace(PMA_MicroHistory.menus.get(data._menuHash));
}
}
if (data._disableNaviSettings) {
PMA_disableNaviSettings();
} else {
PMA_ensureNaviSettings(data._selflink);
}
// Remove all containers that may have
// been added outside of #page_content
$('body').children()
.not('#pma_navigation')
.not('#floating_menubar')
.not('#page_nav_icons')
.not('#page_content')
.not('#selflink')
.not('#pma_header')
.not('#pma_footer')
.not('#pma_demo')
.not('#pma_console_container')
.not('#prefs_autoload')
.remove();
// Replace #page_content with new content
if (data.message && data.message.length > 0) {
$('#page_content').replaceWith(
'<div id=\'page_content\'>' + data.message + '</div>'
);
PMA_highlightSQL($('#page_content'));
checkNumberOfFields();
}
if (data._selflink) {
var source = data._selflink.split('?')[0];
// Check for faulty links
var $selflink_replace = {
'import.php': 'tbl_sql.php',
'tbl_chart.php': 'sql.php',
'tbl_gis_visualization.php': 'sql.php'
};
if ($selflink_replace[source]) {
var replacement = $selflink_replace[source];
data._selflink = data._selflink.replace(source, replacement);
}
$('#selflink').find('> a').attr('href', data._selflink);
}
if (data._params) {
PMA_commonParams.setAll(data._params);
}
if (data._scripts) {
AJAX.scriptHandler.load(data._scripts);
}
if (data._selflink && data._scripts && data._menuHash && data._params) {
if (! (history && history.pushState)) {
PMA_MicroHistory.add(
data._selflink,
data._scripts,
data._menuHash,
data._params,
AJAX.source.attr('rel')
);
}
}
if (data._displayMessage) {
$('#page_content').prepend(data._displayMessage);
PMA_highlightSQL($('#page_content'));
}
$('#pma_errors').remove();
var msg = '';
if (data._errSubmitMsg) {
msg = data._errSubmitMsg;
}
if (data._errors) {
$('<div/>', { id : 'pma_errors', class : 'clearfloat' })
.insertAfter('#selflink')
.append(data._errors);
// bind for php error reporting forms (bottom)
$('#pma_ignore_errors_bottom').on('click', function (e) {
e.preventDefault();
PMA_ignorePhpErrors();
});
$('#pma_ignore_all_errors_bottom').on('click', function (e) {
e.preventDefault();
PMA_ignorePhpErrors(false);
});
// In case of 'sendErrorReport'='always'
// submit the hidden error reporting form.
if (data._sendErrorAlways === '1' &&
data._stopErrorReportLoop !== '1'
) {
$('#pma_report_errors_form').submit();
PMA_ajaxShowMessage(PMA_messages.phpErrorsBeingSubmitted, false);
$('html, body').animate({ scrollTop:$(document).height() }, 'slow');
} else if (data._promptPhpErrors) {
// otherwise just prompt user if it is set so.
msg = msg + PMA_messages.phpErrorsFound;
// scroll to bottom where all the errors are displayed.
$('html, body').animate({ scrollTop:$(document).height() }, 'slow');
}
}
PMA_ajaxShowMessage(msg, false);
// bind for php error reporting forms (popup)
$('#pma_ignore_errors_popup').on('click', function () {
PMA_ignorePhpErrors();
});
$('#pma_ignore_all_errors_popup').on('click', function () {
PMA_ignorePhpErrors(false);
});
if (typeof AJAX._callback === 'function') {
AJAX._callback.call();
}
AJAX._callback = function () {};
});
} else {
PMA_ajaxShowMessage(data.error, false);
AJAX.active = false;
AJAX.xhr = null;
PMA_handleRedirectAndReload(data);
if (data.fieldWithError) {
$(':input.error').removeClass('error');
$('#' + data.fieldWithError).addClass('error');
}
}
},
/**
* 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 string _scriptsVersion version of phpMyAdmin from which the
* scripts have been loaded
*/
_scriptsVersion: null,
/**
* @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 and unload events
*/
_scriptsToBeFired: [],
_scriptsCompleted: false,
/**
* Records that a file has been downloaded
*
* @param string file The filename
* @param string fire Whether this file will be registering
* onload/teardown events
*
* @return self For chaining
*/
add: function (file, fire, callback) {
var self = this;
this._scripts.push(file);
if (fire) {
// Record whether to fire any events for the file
// This is necessary to correctly tear down the initial page
this._scriptsToBeFired.push(file);
}
/**
* @todo This condition is to be removed once all the files are modularised
*/
if (checkNewCode(file)) {
var fileImports = ['server_privileges', 'server_databases'];
if ($.inArray(file, fileImports) !== -1) {
// Dynamic import to load the files dynamically
// This is used for the purpose of code splitting
import(`./${file}`)
.then((module) => {
/**
* setTimeout is used so that scripts run only when content is
* available.
*/
setTimeout(function () {
/**
* @var i The name of the module exported in corresponding file
*/
for (var i in module) {
// If the export has onload in its name, register onload for that export
if (i.indexOf('onload') !== -1) {
AJAX.registerOnload(`${file}`, module[i]);
} else if (i.indexOf('teardown') !== -1) {
// If the export has teardown in its name, register teardown for that export
AJAX.registerTeardown(file, module[i]);
}
}
// Firinf onload for the files being dynamically imported.
AJAX.fireOnload(file);
}, 250);
// AJAX.fireTeardown('server_databases_new.js');
})
// Error of Dynamica Imoprts need to be handled with Tracekit gracefully
.catch(e => console.log(e));
}
}
return this;
},
/**
* Download a list of js files in one request
*
* @param array files An array of filenames and flags
*
* @return void
*/
load: function (files, callback) {
var self = this;
var i;
// Clear loaded scripts if they are from another version of phpMyAdmin.
// Depends on common params being set before loading scripts in responseHandler
if (self._scriptsVersion === null) {
self._scriptsVersion = PMA_commonParams.get('PMA_VERSION');
} else if (self._scriptsVersion !== PMA_commonParams.get('PMA_VERSION')) {
self._scripts = [];
self._scriptsVersion = PMA_commonParams.get('PMA_VERSION');
}
self._scriptsCompleted = false;
self._scriptsToBeFired = [];
// We need to first complete list of files to load
// as next loop will directly fire requests to load them
// and that triggers removal of them from
// self._scriptsToBeLoaded
for (i in files) {
self._scriptsToBeLoaded.push(files[i].name);
if (files[i].fire) {
self._scriptsToBeFired.push(files[i].name);
}
}
for (i in files) {
var script = files[i].name;
// Only for scripts that we don't already have
if ($.inArray(script, self._scripts) === -1) {
this.add(script, 0, callback);
/**
* @todo To be removed once complete code is modularised
* Only for appending js files in the header if not already present
*/
if (!checkNewCode(script)) {
this.appendScript(script, callback);
}
}
self.done(script, callback);
}
// Trigger callback if there is nothing else to load
self.done(null, callback);
},
/**
* Called whenever all files are loaded
*
* @return void
*/
done: function (script, callback) {
if (typeof ErrorReport !== 'undefined') {
ErrorReport.wrap_global_functions();
}
if ($.inArray(script, this._scriptsToBeFired)) {
AJAX.fireOnload(script);
}
if ($.inArray(script, this._scriptsToBeLoaded)) {
this._scriptsToBeLoaded.splice($.inArray(script, this._scriptsToBeLoaded), 1);
}
if (script === null) {
this._scriptsCompleted = true;
}
/* We need to wait for last signal (with null) or last script load */
AJAX.active = (this._scriptsToBeLoaded.length > 0) || ! this._scriptsCompleted;
/* Run callback on last script */
if (! AJAX.active && $.isFunction(callback)) {
callback();
}
},
/**
* Appends a script element to the head to load the scripts
*
* @return void
* this is to be removed in modularised code
* no appending of scripts is needed
*
* @todo This method will be of no use in modular code
*/
appendScript: function (name, callback) {
var head = document.head || document.getElementsByTagName('head')[0];
var script = document.createElement('script');
var self = this;
script.type = 'text/javascript';
script.src = 'js/' + name + '?' + 'v=' + encodeURIComponent(PMA_commonParams.get('PMA_VERSION'));
script.async = false;
script.onload = function () {
self.done(name, callback);
};
head.appendChild(script);
},
/**
* Fires all the teardown event handlers for the current page
* and rebinds all forms and links to the request handler
*
* @param function callback The callback to call after resetting
*
* @return void
*/
reset: function (callback) {
for (var i in this._scriptsToBeFired) {
AJAX.fireTeardown(this._scriptsToBeFired[i]);
}
this._scriptsToBeFired = [];
/**
* Re-attach a generic event handler to clicks
* on pages and submissions of forms
*/
$(document).off('click', 'a').on('click', 'a', AJAX.requestHandler);
$(document).off('submit', 'form').on('submit', 'form', AJAX.requestHandler);
if (! (history && history.pushState)) {
PMA_MicroHistory.update();
}
callback();
}
}
};
/**
* Attach a generic event handler to clicks
* on pages and submissions of forms
*/
$(document).on('click', 'a', AJAX.requestHandler);
$(document).on('submit', 'form', AJAX.requestHandler);
/**
* @todo this is to be removed when complete code is modularised
* Exporsing module to window for use with non modular code
*/
window.AJAX = AJAX;

365
js/src/consts/doclinks.js Normal file
View File

@ -0,0 +1,365 @@
/**
* Definition of links to MySQL documentation.
*/
export const mysql_doc_keyword = {
/* Multi word */
'CHARACTER SET': Array('charset'),
'SHOW AUTHORS': Array('show-authors'),
'SHOW BINARY LOGS': Array('show-binary-logs'),
'SHOW BINLOG EVENTS': Array('show-binlog-events'),
'SHOW CHARACTER SET': Array('show-character-set'),
'SHOW COLLATION': Array('show-collation'),
'SHOW COLUMNS': Array('show-columns'),
'SHOW CONTRIBUTORS': Array('show-contributors'),
'SHOW CREATE DATABASE': Array('show-create-database'),
'SHOW CREATE EVENT': Array('show-create-event'),
'SHOW CREATE FUNCTION': Array('show-create-function'),
'SHOW CREATE PROCEDURE': Array('show-create-procedure'),
'SHOW CREATE TABLE': Array('show-create-table'),
'SHOW CREATE TRIGGER': Array('show-create-trigger'),
'SHOW CREATE VIEW': Array('show-create-view'),
'SHOW DATABASES': Array('show-databases'),
'SHOW ENGINE': Array('show-engine'),
'SHOW ENGINES': Array('show-engines'),
'SHOW ERRORS': Array('show-errors'),
'SHOW EVENTS': Array('show-events'),
'SHOW FUNCTION CODE': Array('show-function-code'),
'SHOW FUNCTION STATUS': Array('show-function-status'),
'SHOW GRANTS': Array('show-grants'),
'SHOW INDEX': Array('show-index'),
'SHOW MASTER STATUS': Array('show-master-status'),
'SHOW OPEN TABLES': Array('show-open-tables'),
'SHOW PLUGINS': Array('show-plugins'),
'SHOW PRIVILEGES': Array('show-privileges'),
'SHOW PROCEDURE CODE': Array('show-procedure-code'),
'SHOW PROCEDURE STATUS': Array('show-procedure-status'),
'SHOW PROCESSLIST': Array('show-processlist'),
'SHOW PROFILE': Array('show-profile'),
'SHOW PROFILES': Array('show-profiles'),
'SHOW RELAYLOG EVENTS': Array('show-relaylog-events'),
'SHOW SLAVE HOSTS': Array('show-slave-hosts'),
'SHOW SLAVE STATUS': Array('show-slave-status'),
'SHOW STATUS': Array('show-status'),
'SHOW TABLE STATUS': Array('show-table-status'),
'SHOW TABLES': Array('show-tables'),
'SHOW TRIGGERS': Array('show-triggers'),
'SHOW VARIABLES': Array('show-variables'),
'SHOW WARNINGS': Array('show-warnings'),
'LOAD DATA INFILE': Array('load-data'),
'LOAD XML': Array('load-xml'),
'LOCK TABLES': Array('lock-tables'),
'UNLOCK TABLES': Array('lock-tables'),
'ALTER DATABASE': Array('alter-database'),
'ALTER EVENT': Array('alter-event'),
'ALTER LOGFILE GROUP': Array('alter-logfile-group'),
'ALTER FUNCTION': Array('alter-function'),
'ALTER PROCEDURE': Array('alter-procedure'),
'ALTER SERVER': Array('alter-server'),
'ALTER TABLE': Array('alter-table'),
'ALTER TABLESPACE': Array('alter-tablespace'),
'ALTER VIEW': Array('alter-view'),
'CREATE DATABASE': Array('create-database'),
'CREATE EVENT': Array('create-event'),
'CREATE FUNCTION': Array('create-function'),
'CREATE INDEX': Array('create-index'),
'CREATE LOGFILE GROUP': Array('create-logfile-group'),
'CREATE PROCEDURE': Array('create-procedure'),
'CREATE SERVER': Array('create-server'),
'CREATE TABLE': Array('create-table'),
'CREATE TABLESPACE': Array('create-tablespace'),
'CREATE TRIGGER': Array('create-trigger'),
'CREATE VIEW': Array('create-view'),
'DROP DATABASE': Array('drop-database'),
'DROP EVENT': Array('drop-event'),
'DROP FUNCTION': Array('drop-function'),
'DROP INDEX': Array('drop-index'),
'DROP LOGFILE GROUP': Array('drop-logfile-group'),
'DROP PROCEDURE': Array('drop-procedure'),
'DROP SERVER': Array('drop-server'),
'DROP TABLE': Array('drop-table'),
'DROP TABLESPACE': Array('drop-tablespace'),
'DROP TRIGGER': Array('drop-trigger'),
'DROP VIEW': Array('drop-view'),
'RENAME TABLE': Array('rename-table'),
'TRUNCATE TABLE': Array('truncate-table'),
/* Statements */
'SELECT': Array('select'),
'SET': Array('set'),
'EXPLAIN': Array('explain'),
'DESCRIBE': Array('describe'),
'DELETE': Array('delete'),
'SHOW': Array('show'),
'UPDATE': Array('update'),
'INSERT': Array('insert'),
'REPLACE': Array('replace'),
'CALL': Array('call'),
'DO': Array('do'),
'HANDLER': Array('handler'),
'COLLATE': Array('charset-collations'),
/* Functions */
'ABS': Array('mathematical-functions', 'function_abs'),
'ACOS': Array('mathematical-functions', 'function_acos'),
'ADDDATE': Array('date-and-time-functions', 'function_adddate'),
'ADDTIME': Array('date-and-time-functions', 'function_addtime'),
'AES_DECRYPT': Array('encryption-functions', 'function_aes_decrypt'),
'AES_ENCRYPT': Array('encryption-functions', 'function_aes_encrypt'),
'AND': Array('logical-operators', 'operator_and'),
'ASCII': Array('string-functions', 'function_ascii'),
'ASIN': Array('mathematical-functions', 'function_asin'),
'ATAN2': Array('mathematical-functions', 'function_atan2'),
'ATAN': Array('mathematical-functions', 'function_atan'),
'AVG': Array('group-by-functions', 'function_avg'),
'BENCHMARK': Array('information-functions', 'function_benchmark'),
'BIN': Array('string-functions', 'function_bin'),
'BINARY': Array('cast-functions', 'operator_binary'),
'BIT_AND': Array('group-by-functions', 'function_bit_and'),
'BIT_COUNT': Array('bit-functions', 'function_bit_count'),
'BIT_LENGTH': Array('string-functions', 'function_bit_length'),
'BIT_OR': Array('group-by-functions', 'function_bit_or'),
'BIT_XOR': Array('group-by-functions', 'function_bit_xor'),
'CASE': Array('control-flow-functions', 'operator_case'),
'CAST': Array('cast-functions', 'function_cast'),
'CEIL': Array('mathematical-functions', 'function_ceil'),
'CEILING': Array('mathematical-functions', 'function_ceiling'),
'CHAR_LENGTH': Array('string-functions', 'function_char_length'),
'CHAR': Array('string-functions', 'function_char'),
'CHARACTER_LENGTH': Array('string-functions', 'function_character_length'),
'CHARSET': Array('information-functions', 'function_charset'),
'COALESCE': Array('comparison-operators', 'function_coalesce'),
'COERCIBILITY': Array('information-functions', 'function_coercibility'),
'COLLATION': Array('information-functions', 'function_collation'),
'COMPRESS': Array('encryption-functions', 'function_compress'),
'CONCAT_WS': Array('string-functions', 'function_concat_ws'),
'CONCAT': Array('string-functions', 'function_concat'),
'CONNECTION_ID': Array('information-functions', 'function_connection_id'),
'CONV': Array('mathematical-functions', 'function_conv'),
'CONVERT_TZ': Array('date-and-time-functions', 'function_convert_tz'),
'Convert': Array('cast-functions', 'function_convert'),
'COS': Array('mathematical-functions', 'function_cos'),
'COT': Array('mathematical-functions', 'function_cot'),
'COUNT': Array('group-by-functions', 'function_count'),
'CRC32': Array('mathematical-functions', 'function_crc32'),
'CURDATE': Array('date-and-time-functions', 'function_curdate'),
'CURRENT_DATE': Array('date-and-time-functions', 'function_current_date'),
'CURRENT_TIME': Array('date-and-time-functions', 'function_current_time'),
'CURRENT_TIMESTAMP': Array('date-and-time-functions', 'function_current_timestamp'),
'CURRENT_USER': Array('information-functions', 'function_current_user'),
'CURTIME': Array('date-and-time-functions', 'function_curtime'),
'DATABASE': Array('information-functions', 'function_database'),
'DATE_ADD': Array('date-and-time-functions', 'function_date_add'),
'DATE_FORMAT': Array('date-and-time-functions', 'function_date_format'),
'DATE_SUB': Array('date-and-time-functions', 'function_date_sub'),
'DATE': Array('date-and-time-functions', 'function_date'),
'DATEDIFF': Array('date-and-time-functions', 'function_datediff'),
'DAY': Array('date-and-time-functions', 'function_day'),
'DAYNAME': Array('date-and-time-functions', 'function_dayname'),
'DAYOFMONTH': Array('date-and-time-functions', 'function_dayofmonth'),
'DAYOFWEEK': Array('date-and-time-functions', 'function_dayofweek'),
'DAYOFYEAR': Array('date-and-time-functions', 'function_dayofyear'),
'DECLARE': Array('declare', 'declare'),
'DECODE': Array('encryption-functions', 'function_decode'),
'DEFAULT': Array('miscellaneous-functions', 'function_default'),
'DEGREES': Array('mathematical-functions', 'function_degrees'),
'DES_DECRYPT': Array('encryption-functions', 'function_des_decrypt'),
'DES_ENCRYPT': Array('encryption-functions', 'function_des_encrypt'),
'DIV': Array('arithmetic-functions', 'operator_div'),
'ELT': Array('string-functions', 'function_elt'),
'ENCODE': Array('encryption-functions', 'function_encode'),
'ENCRYPT': Array('encryption-functions', 'function_encrypt'),
'EXP': Array('mathematical-functions', 'function_exp'),
'EXPORT_SET': Array('string-functions', 'function_export_set'),
'EXTRACT': Array('date-and-time-functions', 'function_extract'),
'ExtractValue': Array('xml-functions', 'function_extractvalue'),
'FIELD': Array('string-functions', 'function_field'),
'FIND_IN_SET': Array('string-functions', 'function_find_in_set'),
'FLOOR': Array('mathematical-functions', 'function_floor'),
'FORMAT': Array('string-functions', 'function_format'),
'FOUND_ROWS': Array('information-functions', 'function_found_rows'),
'FROM_DAYS': Array('date-and-time-functions', 'function_from_days'),
'FROM_UNIXTIME': Array('date-and-time-functions', 'function_from_unixtime'),
'GET_FORMAT': Array('date-and-time-functions', 'function_get_format'),
'GET_LOCK': Array('miscellaneous-functions', 'function_get_lock'),
'GREATEST': Array('comparison-operators', 'function_greatest'),
'GROUP_CONCAT': Array('group-by-functions', 'function_group_concat'),
'HEX': Array('string-functions', 'function_hex'),
'HOUR': Array('date-and-time-functions', 'function_hour'),
'IF': Array('control-flow-functions', 'function_if'),
'IFNULL': Array('control-flow-functions', 'function_ifnull'),
'IN': Array('comparison-operators', 'function_in'),
'INET_ATON': Array('miscellaneous-functions', 'function_inet_aton'),
'INET_NTOA': Array('miscellaneous-functions', 'function_inet_ntoa'),
'INSTR': Array('string-functions', 'function_instr'),
'INTERVAL': Array('comparison-operators', 'function_interval'),
'IS_FREE_LOCK': Array('miscellaneous-functions', 'function_is_free_lock'),
'IS_USED_LOCK': Array('miscellaneous-functions', 'function_is_used_lock'),
'IS': Array('comparison-operators', 'operator_is'),
'ISNULL': Array('comparison-operators', 'function_isnull'),
'LAST_DAY': Array('date-and-time-functions', 'function_last_day'),
'LAST_INSERT_ID': Array('information-functions', 'function_last_insert_id'),
'LCASE': Array('string-functions', 'function_lcase'),
'LEAST': Array('comparison-operators', 'function_least'),
'LEFT': Array('string-functions', 'function_left'),
'LENGTH': Array('string-functions', 'function_length'),
'LIKE': Array('string-comparison-functions', 'operator_like'),
'LN': Array('mathematical-functions', 'function_ln'),
'LOAD_FILE': Array('string-functions', 'function_load_file'),
'LOCALTIME': Array('date-and-time-functions', 'function_localtime'),
'LOCALTIMESTAMP': Array('date-and-time-functions', 'function_localtimestamp'),
'LOCATE': Array('string-functions', 'function_locate'),
'LOG10': Array('mathematical-functions', 'function_log10'),
'LOG2': Array('mathematical-functions', 'function_log2'),
'LOG': Array('mathematical-functions', 'function_log'),
'LOWER': Array('string-functions', 'function_lower'),
'LPAD': Array('string-functions', 'function_lpad'),
'LTRIM': Array('string-functions', 'function_ltrim'),
'MAKE_SET': Array('string-functions', 'function_make_set'),
'MAKEDATE': Array('date-and-time-functions', 'function_makedate'),
'MAKETIME': Array('date-and-time-functions', 'function_maketime'),
'MASTER_POS_WAIT': Array('miscellaneous-functions', 'function_master_pos_wait'),
'MATCH': Array('fulltext-search', 'function_match'),
'MAX': Array('group-by-functions', 'function_max'),
'MD5': Array('encryption-functions', 'function_md5'),
'MICROSECOND': Array('date-and-time-functions', 'function_microsecond'),
'MID': Array('string-functions', 'function_mid'),
'MIN': Array('group-by-functions', 'function_min'),
'MINUTE': Array('date-and-time-functions', 'function_minute'),
'MOD': Array('mathematical-functions', 'function_mod'),
'MONTH': Array('date-and-time-functions', 'function_month'),
'MONTHNAME': Array('date-and-time-functions', 'function_monthname'),
'NAME_CONST': Array('miscellaneous-functions', 'function_name_const'),
'NOT': Array('logical-operators', 'operator_not'),
'NOW': Array('date-and-time-functions', 'function_now'),
'NULLIF': Array('control-flow-functions', 'function_nullif'),
'OCT': Array('mathematical-functions', 'function_oct'),
'OCTET_LENGTH': Array('string-functions', 'function_octet_length'),
'OLD_PASSWORD': Array('encryption-functions', 'function_old_password'),
'OR': Array('logical-operators', 'operator_or'),
'ORD': Array('string-functions', 'function_ord'),
'PASSWORD': Array('encryption-functions', 'function_password'),
'PERIOD_ADD': Array('date-and-time-functions', 'function_period_add'),
'PERIOD_DIFF': Array('date-and-time-functions', 'function_period_diff'),
'PI': Array('mathematical-functions', 'function_pi'),
'POSITION': Array('string-functions', 'function_position'),
'POW': Array('mathematical-functions', 'function_pow'),
'POWER': Array('mathematical-functions', 'function_power'),
'QUARTER': Array('date-and-time-functions', 'function_quarter'),
'QUOTE': Array('string-functions', 'function_quote'),
'RADIANS': Array('mathematical-functions', 'function_radians'),
'RAND': Array('mathematical-functions', 'function_rand'),
'REGEXP': Array('regexp', 'operator_regexp'),
'RELEASE_LOCK': Array('miscellaneous-functions', 'function_release_lock'),
'REPEAT': Array('string-functions', 'function_repeat'),
'REVERSE': Array('string-functions', 'function_reverse'),
'RIGHT': Array('string-functions', 'function_right'),
'RLIKE': Array('regexp', 'operator_rlike'),
'ROUND': Array('mathematical-functions', 'function_round'),
'ROW_COUNT': Array('information-functions', 'function_row_count'),
'RPAD': Array('string-functions', 'function_rpad'),
'RTRIM': Array('string-functions', 'function_rtrim'),
'SCHEMA': Array('information-functions', 'function_schema'),
'SEC_TO_TIME': Array('date-and-time-functions', 'function_sec_to_time'),
'SECOND': Array('date-and-time-functions', 'function_second'),
'SESSION_USER': Array('information-functions', 'function_session_user'),
'SHA': Array('encryption-functions', 'function_sha1'),
'SHA1': Array('encryption-functions', 'function_sha1'),
'SIGN': Array('mathematical-functions', 'function_sign'),
'SIN': Array('mathematical-functions', 'function_sin'),
'SLEEP': Array('miscellaneous-functions', 'function_sleep'),
'SOUNDEX': Array('string-functions', 'function_soundex'),
'SPACE': Array('string-functions', 'function_space'),
'SQRT': Array('mathematical-functions', 'function_sqrt'),
'STD': Array('group-by-functions', 'function_std'),
'STDDEV_POP': Array('group-by-functions', 'function_stddev_pop'),
'STDDEV_SAMP': Array('group-by-functions', 'function_stddev_samp'),
'STDDEV': Array('group-by-functions', 'function_stddev'),
'STR_TO_DATE': Array('date-and-time-functions', 'function_str_to_date'),
'STRCMP': Array('string-comparison-functions', 'function_strcmp'),
'SUBDATE': Array('date-and-time-functions', 'function_subdate'),
'SUBSTR': Array('string-functions', 'function_substr'),
'SUBSTRING_INDEX': Array('string-functions', 'function_substring_index'),
'SUBSTRING': Array('string-functions', 'function_substring'),
'SUBTIME': Array('date-and-time-functions', 'function_subtime'),
'SUM': Array('group-by-functions', 'function_sum'),
'SYSDATE': Array('date-and-time-functions', 'function_sysdate'),
'SYSTEM_USER': Array('information-functions', 'function_system_user'),
'TAN': Array('mathematical-functions', 'function_tan'),
'TIME_FORMAT': Array('date-and-time-functions', 'function_time_format'),
'TIME_TO_SEC': Array('date-and-time-functions', 'function_time_to_sec'),
'TIME': Array('date-and-time-functions', 'function_time'),
'TIMEDIFF': Array('date-and-time-functions', 'function_timediff'),
'TIMESTAMP': Array('date-and-time-functions', 'function_timestamp'),
'TIMESTAMPADD': Array('date-and-time-functions', 'function_timestampadd'),
'TIMESTAMPDIFF': Array('date-and-time-functions', 'function_timestampdiff'),
'TO_DAYS': Array('date-and-time-functions', 'function_to_days'),
'TRIM': Array('string-functions', 'function_trim'),
'TRUNCATE': Array('mathematical-functions', 'function_truncate'),
'UCASE': Array('string-functions', 'function_ucase'),
'UNCOMPRESS': Array('encryption-functions', 'function_uncompress'),
'UNCOMPRESSED_LENGTH': Array('encryption-functions', 'function_uncompressed_length'),
'UNHEX': Array('string-functions', 'function_unhex'),
'UNIX_TIMESTAMP': Array('date-and-time-functions', 'function_unix_timestamp'),
'UpdateXML': Array('xml-functions', 'function_updatexml'),
'UPPER': Array('string-functions', 'function_upper'),
'USER': Array('information-functions', 'function_user'),
'UTC_DATE': Array('date-and-time-functions', 'function_utc_date'),
'UTC_TIME': Array('date-and-time-functions', 'function_utc_time'),
'UTC_TIMESTAMP': Array('date-and-time-functions', 'function_utc_timestamp'),
'UUID_SHORT': Array('miscellaneous-functions', 'function_uuid_short'),
'UUID': Array('miscellaneous-functions', 'function_uuid'),
'VALUES': Array('miscellaneous-functions', 'function_values'),
'VAR_POP': Array('group-by-functions', 'function_var_pop'),
'VAR_SAMP': Array('group-by-functions', 'function_var_samp'),
'VARIANCE': Array('group-by-functions', 'function_variance'),
'VERSION': Array('information-functions', 'function_version'),
'WEEK': Array('date-and-time-functions', 'function_week'),
'WEEKDAY': Array('date-and-time-functions', 'function_weekday'),
'WEEKOFYEAR': Array('date-and-time-functions', 'function_weekofyear'),
'XOR': Array('logical-operators', 'operator_xor'),
'YEAR': Array('date-and-time-functions', 'function_year'),
'YEARWEEK': Array('date-and-time-functions', 'function_yearweek'),
'SOUNDS_LIKE': Array('string-functions', 'operator_sounds-like'),
'IS_NOT_NULL': Array('comparison-operators', 'operator_is-not-null'),
'IS_NOT': Array('comparison-operators', 'operator_is-not'),
'IS_NULL': Array('comparison-operators', 'operator_is-null'),
'NOT_LIKE': Array('string-comparison-functions', 'operator_not-like'),
'NOT_REGEXP': Array('regexp', 'operator_not-regexp'),
'COUNT_DISTINCT': Array('group-by-functions', 'function_count-distinct'),
'NOT_IN': Array('comparison-operators', 'function_not-in')
};
export const mysql_doc_builtin = {
'TINYINT': Array('numeric-types'),
'SMALLINT': Array('numeric-types'),
'MEDIUMINT': Array('numeric-types'),
'INT': Array('numeric-types'),
'BIGINT': Array('numeric-types'),
'DECIMAL': Array('numeric-types'),
'FLOAT': Array('numeric-types'),
'DOUBLE': Array('numeric-types'),
'REAL': Array('numeric-types'),
'BIT': Array('numeric-types'),
'BOOLEAN': Array('numeric-types'),
'SERIAL': Array('numeric-types'),
'DATE': Array('date-and-time-types'),
'DATETIME': Array('date-and-time-types'),
'TIMESTAMP': Array('date-and-time-types'),
'TIME': Array('date-and-time-types'),
'YEAR': Array('date-and-time-types'),
'CHAR': Array('string-types'),
'VARCHAR': Array('string-types'),
'TINYTEXT': Array('string-types'),
'TEXT': Array('string-types'),
'MEDIUMTEXT': Array('string-types'),
'LONGTEXT': Array('string-types'),
'BINARY': Array('string-types'),
'VARBINARY': Array('string-types'),
'TINYBLOB': Array('string-types'),
'MEDIUMBLOB': Array('string-types'),
'BLOB': Array('string-types'),
'LONGBLOB': Array('string-types'),
'ENUM': Array('string-types'),
'SET': Array('string-types')
};

14
js/src/consts/files.js Normal file
View File

@ -0,0 +1,14 @@
/**
* List of JS files need to be loaded at the time of initial page load.
* Eg. For server_privileges.php, server_privileges.js is required
*/
/**
* @type {Object} files
*/
const files = {
server_privileges: ['server_privileges'],
server_databases: ['server_databases']
};
export default files;

View File

@ -0,0 +1,78 @@
import { escapeHtml } from '../utils/Sanitise';
/**
* Returns an HTML IMG tag for a particular image from a theme,
* which may be an actual file or an icon from a sprite
*
* @param string image The name of the file to get
* @param string alternate Used to set 'alt' and 'title' attributes of the image
* @param object attributes An associative array of other attributes
*
* @return Object The requested image, this object has two methods:
* .toString() - Returns the IMG tag for the requested image
* .attr(name) - Returns a particular attribute of the IMG
* tag given it's name
* .attr(name, value) - Sets a particular attribute of the IMG
* tag to the given value
*/
export function PMA_getImage (image, alternate, attributes) {
// custom image object, it will eventually be returned by this functions
var retval = {
data: {
// this is private
alt: '',
title: '',
src: 'themes/dot.gif',
},
attr: function (name, value) {
if (value === undefined) {
if (this.data[name] === undefined) {
return '';
} else {
return this.data[name];
}
} else {
this.data[name] = value;
}
},
toString: function () {
var retval = '<' + 'img';
for (var i in this.data) {
retval += ' ' + i + '="' + this.data[i] + '"';
}
retval += ' /' + '>';
return retval;
}
};
// initialise missing parameters
if (attributes === undefined) {
attributes = {};
}
if (alternate === undefined) {
alternate = '';
}
// set alt
if (attributes.alt !== undefined) {
retval.attr('alt', escapeHtml(attributes.alt));
} else {
retval.attr('alt', escapeHtml(alternate));
}
// set title
if (attributes.title !== undefined) {
retval.attr('title', escapeHtml(attributes.title));
} else {
retval.attr('title', escapeHtml(alternate));
}
// set css classes
retval.attr('class', 'icon ic_' + image);
// set all other attrubutes
for (var i in attributes) {
if (i === 'src') {
// do not allow to override the 'src' attribute
continue;
}
retval.attr(i, attributes[i]);
}
return retval;
}

View File

@ -0,0 +1,159 @@
/**
* Expand the navigation and highlight the current database or table/view
*
* @returns void
*/
import { PMA_commonParams } from '../variables/common_params';
export function PMA_showCurrentNavigation () {
var db = PMA_commonParams.get('db');
var table = PMA_commonParams.get('table');
$('#pma_navigation_tree').find('li.selected').removeClass('selected');
if (db) {
var $dbItem = findLoadedItem($('#pma_navigation_tree').find('> div'), db, 'database', !table);
if ($('#navi_db_select').length && $('option:selected', $('#navi_db_select')).length) {
if (!PMA_selectCurrentDb()) {
return;
}
// If loaded database in navigation is not same as current one
if ($('#pma_navigation_tree_content').find('span.loaded_db:first').text() !== $('#navi_db_select').val()) {
loadChildNodes(false, $('option:selected', $('#navi_db_select')), function (data) {
handleTableOrDb(table, $('#pma_navigation_tree_content'));
var $children = $('#pma_navigation_tree_content').children('div.list_container');
$children.promise().done(navTreeStateUpdate);
});
} else {
handleTableOrDb(table, $('#pma_navigation_tree_content'));
}
} else if ($dbItem) {
var $expander = $dbItem.children('div:first').children('a.expander');
// if not loaded or loaded but collapsed
if (!$expander.hasClass('loaded') || $expander.find('img').is('.ic_b_plus')) {
expandTreeNode($expander, function () {
handleTableOrDb(table, $dbItem);
});
} else {
handleTableOrDb(table, $dbItem);
}
}
} else if ($('#navi_db_select').length && $('#navi_db_select').val()) {
$('#navi_db_select').val('').hide().trigger('change');
}
PMA_showFullName($('#pma_navigation_tree'));
function handleTableOrDb (table, $dbItem) {
if (table) {
loadAndHighlightTableOrView($dbItem, table);
} else {
var $container = $dbItem.children('div.list_container');
var $tableContainer = $container.children('ul').children('li.tableContainer');
if ($tableContainer.length > 0) {
var $expander = $tableContainer.children('div:first').children('a.expander');
$tableContainer.addClass('selected');
expandTreeNode($expander, function () {
scrollToView($dbItem, true);
});
} else {
scrollToView($dbItem, true);
}
}
}
function findLoadedItem ($container, name, clazz, doSelect) {
var ret = false;
$container.children('ul').children('li').each(function () {
var $li = $(this);
// this is a navigation group, recurse
if ($li.is('.navGroup')) {
var $container = $li.children('div.list_container');
var $childRet = findLoadedItem($container, name, clazz, doSelect);
if ($childRet) {
ret = $childRet;
return false;
}
} else {
// this is a real navigation item
// name and class matches
if ((clazz && $li.is('.' + clazz) || !clazz) && $li.children('a').text() === name) {
if (doSelect) {
$li.addClass('selected');
}
// taverse up and expand and parent navigation groups
$li.parents('.navGroup').each(function () {
var $cont = $(this).children('div.list_container');
if (!$cont.is(':visible')) {
$(this).children('div:first').children('a.expander').click();
}
});
ret = $li;
return false;
}
}
});
return ret;
}
function loadAndHighlightTableOrView ($dbItem, itemName) {
var $container = $dbItem.children('div.list_container');
var $expander;
var $whichItem = isItemInContainer($container, itemName, 'li.table, li.view');
// If item already there in some container
if ($whichItem) {
// get the relevant container while may also be a subcontainer
var $relatedContainer = $whichItem.closest('li.subContainer').length ? $whichItem.closest('li.subContainer') : $dbItem;
$whichItem = findLoadedItem($relatedContainer.children('div.list_container'), itemName, null, true);
// Show directly
showTableOrView($whichItem, $relatedContainer.children('div:first').children('a.expander'));
// else if item not there, try loading once
} else {
var $sub_containers = $dbItem.find('.subContainer');
// If there are subContainers i.e. tableContainer or viewContainer
if ($sub_containers.length > 0) {
var $containers = [];
$sub_containers.each(function (index) {
$containers[index] = $(this);
$expander = $containers[index].children('div:first').children('a.expander');
if (!$expander.hasClass('loaded')) {
loadAndShowTableOrView($expander, $containers[index], itemName);
}
});
// else if no subContainers
} else {
$expander = $dbItem.children('div:first').children('a.expander');
if (!$expander.hasClass('loaded')) {
loadAndShowTableOrView($expander, $dbItem, itemName);
}
}
}
}
function loadAndShowTableOrView ($expander, $relatedContainer, itemName) {
loadChildNodes(true, $expander, function (data) {
var $whichItem = findLoadedItem($relatedContainer.children('div.list_container'), itemName, null, true);
if ($whichItem) {
showTableOrView($whichItem, $expander);
}
});
}
function showTableOrView ($whichItem, $expander) {
expandTreeNode($expander, function (data) {
if ($whichItem) {
scrollToView($whichItem, false);
}
});
}
function isItemInContainer ($container, name, clazz) {
var $whichItem = null;
$items = $container.find(clazz);
var found = false;
$items.each(function () {
if ($(this).children('a').text() === name) {
$whichItem = $(this);
return false;
}
});
return $whichItem;
}
}

86
js/src/index.js Normal file
View File

@ -0,0 +1,86 @@
import { AJAX } from './ajax';
import './variables/import_variables';
import { jQuery as $ } from './utils/JqueryExtended';
import files from './consts/files';
/**
* Page load event handler
*/
$(function () {
var menuContent = $('<div></div>')
.append($('#serverinfo').clone())
.append($('#topmenucontainer').clone())
.html();
if (history && history.pushState) {
// set initial state reload
var initState = ('state' in window.history && window.history.state !== null);
var initURL = $('#selflink').find('> a').attr('href') || location.href;
var state = {
url : initURL,
menu : menuContent
};
history.replaceState(state, null);
$(window).on('popstate', function (event) {
var initPop = (! initState && location.href === initURL);
initState = true;
// check if popstate fired on first page itself
if (initPop) {
return;
}
var state = event.originalEvent.state;
if (state && state.menu) {
AJAX.$msgbox = PMA_ajaxShowMessage();
var params = 'ajax_request=true' + PMA_commonParams.get('arg_separator') + 'ajax_page_request=true';
var url = state.url || location.href;
$.get(url, params, AJAX.responseHandler);
// TODO: Check if sometimes menu is not retrieved from server,
// Not sure but it seems menu was missing only for printview which
// been removed lately, so if it's right some dead menu checks/fallbacks
// may need to be removed from this file and Header.php
// AJAX.handleMenu.replace(event.originalEvent.state.menu);
}
});
} else {
// Fallback to microhistory mechanism
AJAX.scriptHandler
.load([{ 'name' : 'microhistory.js', 'fire' : 1 }], function () {
// The cache primer is set by the footer class
if (PMA_MicroHistory.primer.url) {
PMA_MicroHistory.menus.add(
PMA_MicroHistory.primer.menuHash,
menuContent
);
}
$(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
if (PMA_MicroHistory.primer.url) {
PMA_MicroHistory.add(
PMA_MicroHistory.primer.url,
PMA_MicroHistory.primer.scripts,
PMA_MicroHistory.primer.menuHash
);
}
});
});
}
});
/**
* This block of code is for importing javascript files needed
* for the first time loading of the page.
*/
let firstPage = window.location.pathname.replace('/', '').replace('.php', '');
let indexStart = window.location.search.indexOf('target') + 7;
let indexEnd = window.location.search.indexOf('.php');
let indexPage = window.location.search.slice(indexStart, indexEnd);
if (typeof files[firstPage] !== 'undefined' && firstPage.toLocaleLowerCase() !== 'index') {
for (let i in files[firstPage]) {
AJAX.scriptHandler.add(files[firstPage][i], 1);
}
} else if (typeof files[indexPage] !== 'undefined' && firstPage.toLocaleLowerCase() === 'index') {
for (let i in files[indexPage]) {
AJAX.scriptHandler.add(files[indexPage][i], 1);
}
}

151
js/src/server_databases.js Normal file
View File

@ -0,0 +1,151 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* @fileoverview functions used on the server databases list page
* @name Server Databases
*
* @requires jQuery
* @requires jQueryUI
* @required js/functions.js
*/
import { PMA_sprintf } from './utils/sprintf';
import './variables/import_variables';
import { PMA_ajaxShowMessage } from './utils/show_ajax_messages';
import { escapeHtml } from './utils/Sanitise';
import { PMA_Messages as PMA_messages } from './variables/export_variables';
import { jQuery as $ } from './utils/JqueryExtended';
import { AJAX } from './ajax';
import { PMA_commonParams } from './variables/common_params';
/**
* Unbind all event handlers before tearing down a page
*/
export function teardown1 () {
$(document).off('submit', '#dbStatsForm');
$(document).off('submit', '#create_database_form.ajax');
}
export function onload1 () {
/**
* Attach Event Handler for 'Drop Databases'
*/
$(document).on('submit', '#dbStatsForm', function (event) {
// debugger;
event.preventDefault();
var $form = $(this);
/**
* @var selected_dbs Array containing the names of the checked databases
*/
var selected_dbs = [];
// loop over all checked checkboxes, except the .checkall_box checkbox
$form.find('input:checkbox:checked:not(.checkall_box)').each(function () {
$(this).closest('tr').addClass('removeMe');
selected_dbs[selected_dbs.length] = 'DROP DATABASE `' + escapeHtml($(this).val()) + '`;';
});
if (! selected_dbs.length) {
PMA_ajaxShowMessage(
$('<div class="notice" />').text(
PMA_messages.strNoDatabasesSelected
),
2000
);
return;
}
/**
* @var question String containing the question to be asked for confirmation
*/
var question = PMA_messages.strDropDatabaseStrongWarning + ' ' +
PMA_sprintf(PMA_messages.strDoYouReally, selected_dbs.join('<br />'));
var argsep = PMA_commonParams.get('arg_separator');
$(this).PMA_confirm(
question,
$form.prop('action') + '?' + $(this).serialize() +
argsep + 'drop_selected_dbs=1' + argsep + 'is_js_confirmed=1' + argsep + 'ajax_request=true',
function (url) {
PMA_ajaxShowMessage(PMA_messages.strProcessingRequest, false);
var params = getJSConfirmCommonParam(this);
$.post(url, params, function (data) {
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxShowMessage(data.message);
var $rowsToRemove = $form.find('tr.removeMe');
var $databasesCount = $('#filter-rows-count');
var newCount = parseInt($databasesCount.text(), 10) - $rowsToRemove.length;
$databasesCount.text(newCount);
$rowsToRemove.remove();
$form.find('tbody').PMA_sort_table('.name');
if ($form.find('tbody').find('tr').length === 0) {
// user just dropped the last db on this page
PMA_commonActions.refreshMain();
}
PMA_reloadNavigation();
} else {
$form.find('tr.removeMe').removeClass('removeMe');
PMA_ajaxShowMessage(data.error, false);
}
}); // end $.post()
}
); // end $.PMA_confirm()
}); // end of Drop Database action
/**
* Attach Ajax event handlers for 'Create Database'.
*/
$(document).on('submit', '#create_database_form.ajax', function (event) {
event.preventDefault();
var $form = $(this);
// TODO Remove this section when all browsers support HTML5 "required" property
var newDbNameInput = $form.find('input[name=new_db]');
if (newDbNameInput.val() === '') {
newDbNameInput.focus();
alert(PMA_messages.strFormEmpty);
return;
}
// end remove
PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
PMA_prepareForAjaxRequest($form);
$.post($form.attr('action'), $form.serialize(), function (data) {
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxShowMessage(data.message);
var $databases_count_object = $('#filter-rows-count');
var databases_count = parseInt($databases_count_object.text(), 10) + 1;
$databases_count_object.text(databases_count);
PMA_reloadNavigation();
// make ajax request to load db structure page - taken from ajax.js
var dbStruct_url = data.url_query;
dbStruct_url = dbStruct_url.replace(/amp;/ig, '');
var params = 'ajax_request=true' + PMA_commonParams.get('arg_separator') + 'ajax_page_request=true';
if (! (history && history.pushState)) {
params += PMA_MicroHistory.menus.getRequestParam();
}
$.get(dbStruct_url, params, AJAX.responseHandler);
} else {
PMA_ajaxShowMessage(data.error, false);
}
}); // end $.post()
}); // end $(document).on()
/* Don't show filter if number of databases are very few */
var databasesCount = $('#filter-rows-count').html();
if (databasesCount <= 10) {
$('#tableFilter').hide();
}
var tableRows = $('.server_databases');
$.each(tableRows, function (index, item) {
$(this).click(function () {
PMA_commonActions.setDb($(this).attr('data'));
});
});
}

436
js/src/server_privileges.js Normal file
View File

@ -0,0 +1,436 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* @fileoverview functions used in server privilege pages
* @name Server Privileges
*
* @requires jQuery
* @requires jQueryUI
* @requires js/functions.js
*
*/
import { PMA_sprintf } from './utils/sprintf';
import { checkPasswordStrength, displayPasswordGenerateButton } from './utils/password';
// import { AJAX } from './ajax';
import { PMA_Messages as PMA_messages } from './variables/export_variables';
import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
import { PMA_commonParams } from './variables/common_params';
import { jQuery as $ } from './utils/JqueryExtended';
/**
* AJAX scripts for server_privileges page.
*
* Actions ajaxified here:
* Add user
* Revoke a user
* Edit privileges
* Export privileges
* Paginate table of users
* Flush privileges
*
* @memberOf jQuery
* @name document.ready
*/
/**
* Unbind all event handlers before tearing down a page
*/
export function teardown1 () {
$('#fieldset_add_user_login').off('change', 'input[name=\'username\']');
$(document).off('click', '#fieldset_delete_user_footer #buttonGo.ajax');
$(document).off('click', 'a.edit_user_group_anchor.ajax');
$(document).off('click', 'button.mult_submit[value=export]');
$(document).off('click', 'a.export_user_anchor.ajax');
$(document).off('click', '#initials_table a.ajax');
$('#checkbox_drop_users_db').off('click');
$(document).off('click', '.checkall_box');
$(document).off('change', '#checkbox_SSL_priv');
$(document).off('change', 'input[name="ssl_type"]');
$(document).off('change', '#select_authentication_plugin');
}
export function onload1 () {
/**
* Display a warning if there is already a user by the name entered as the username.
*/
$('#fieldset_add_user_login').on('change', 'input[name=\'username\']', function () {
var username = $(this).val();
var $warning = $('#user_exists_warning');
if ($('#select_pred_username').val() === 'userdefined' && username !== '') {
var href = $('form[name=\'usersForm\']').attr('action');
var params = {
'ajax_request' : true,
'server' : PMA_commonParams.get('server'),
'validate_username' : true,
'username' : username
};
$.get(href, params, function (data) {
if (data.user_exists) {
$warning.show();
} else {
$warning.hide();
}
});
} else {
$warning.hide();
}
});
/**
* Indicating password strength
*/
var meter_obj;
var meter_obj_label;
var username;
$(document).on('keyup', '#text_pma_pw', function () {
meter_obj = $('#password_strength_meter');
meter_obj_label = $('#password_strength');
username = $('input[name="username"]');
username = username.val();
checkPasswordStrength($(this).val(), meter_obj, meter_obj_label, username);
});
$(document).on('keyup', '#text_pma_change_pw', function () {
meter_obj = $('#change_password_strength_meter');
meter_obj_label = $('#change_password_strength');
checkPasswordStrength($(this).val(), meter_obj, meter_obj_label, PMA_commonParams.get('user'));
});
/**
* Display a notice if sha256_password is selected
*/
$(document).on('change', '#select_authentication_plugin', function () {
var selected_plugin = $(this).val();
if (selected_plugin === 'sha256_password') {
$('#ssl_reqd_warning').show();
} else {
$('#ssl_reqd_warning').hide();
}
});
/**
* AJAX handler for 'Revoke User'
*
* @see PMA_ajaxShowMessage()
* @memberOf jQuery
* @name revoke_user_click
*/
$(document).on('click', '#fieldset_delete_user_footer #buttonGo.ajax', function (event) {
event.preventDefault();
var $thisButton = $(this);
var $form = $('#usersForm');
$thisButton.PMA_confirm(PMA_messages.strDropUserWarning, $form.attr('action'), function (url) {
var $drop_users_db_checkbox = $('#checkbox_drop_users_db');
if ($drop_users_db_checkbox.is(':checked')) {
var is_confirmed = confirm(PMA_messages.strDropDatabaseStrongWarning + '\n' + PMA_sprintf(PMA_messages.strDoYouReally, 'DROP DATABASE'));
if (! is_confirmed) {
// Uncheck the drop users database checkbox
$drop_users_db_checkbox.prop('checked', false);
}
}
PMA_ajaxShowMessage(PMA_messages.strRemovingSelectedUsers);
var argsep = PMA_commonParams.get('arg_separator');
$.post(url, $form.serialize() + argsep + 'delete=' + $thisButton.val() + argsep + 'ajax_request=true', function (data) {
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxShowMessage(data.message);
// Refresh navigation, if we droppped some databases with the name
// that is the same as the username of the deleted user
if ($('#checkbox_drop_users_db:checked').length) {
PMA_reloadNavigation();
}
// Remove the revoked user from the users list
$form.find('input:checkbox:checked').parents('tr').slideUp('medium', function () {
var this_user_initial = $(this).find('input:checkbox').val().charAt(0).toUpperCase();
$(this).remove();
// If this is the last user with this_user_initial, remove the link from #initials_table
if ($('#tableuserrights').find('input:checkbox[value^="' + this_user_initial + '"], input:checkbox[value^="' + this_user_initial.toLowerCase() + '"]').length === 0) {
$('#initials_table').find('td > a:contains(' + this_user_initial + ')').parent('td').html(this_user_initial);
}
// Re-check the classes of each row
$form
.find('tbody').find('tr:odd')
.removeClass('even').addClass('odd')
.end()
.find('tr:even')
.removeClass('odd').addClass('even');
// update the checkall checkbox
$(checkboxes_sel).trigger('change');
});
} else {
PMA_ajaxShowMessage(data.error, false);
}
}); // end $.post()
});
}); // end Revoke User
$(document).on('click', 'a.edit_user_group_anchor.ajax', function (event) {
event.preventDefault();
$(this).parents('tr').addClass('current_row');
var $msg = PMA_ajaxShowMessage();
$.get(
$(this).attr('href'),
{
'ajax_request': true,
'edit_user_group_dialog': true
},
function (data) {
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxRemoveMessage($msg);
var buttonOptions = {};
buttonOptions[PMA_messages.strGo] = function () {
var usrGroup = $('#changeUserGroupDialog')
.find('select[name="userGroup"]')
.val();
var $message = PMA_ajaxShowMessage();
var argsep = PMA_commonParams.get('arg_separator');
$.post(
'server_privileges.php',
$('#changeUserGroupDialog').find('form').serialize() + argsep + 'ajax_request=1',
function (data) {
PMA_ajaxRemoveMessage($message);
if (typeof data !== 'undefined' && data.success === true) {
$('#usersForm')
.find('.current_row')
.removeClass('current_row')
.find('.usrGroup')
.text(usrGroup);
} else {
PMA_ajaxShowMessage(data.error, false);
$('#usersForm')
.find('.current_row')
.removeClass('current_row');
}
}
);
$(this).dialog('close');
};
buttonOptions[PMA_messages.strClose] = function () {
$(this).dialog('close');
};
var $dialog = $('<div/>')
.attr('id', 'changeUserGroupDialog')
.append(data.message)
.dialog({
width: 500,
minWidth: 300,
modal: true,
buttons: buttonOptions,
title: $('legend', $(data.message)).text(),
close: function () {
$(this).remove();
}
});
$dialog.find('legend').remove();
} else {
PMA_ajaxShowMessage(data.error, false);
$('#usersForm')
.find('.current_row')
.removeClass('current_row');
}
}
);
});
/**
* AJAX handler for 'Export Privileges'
*
* @see PMA_ajaxShowMessage()
* @memberOf jQuery
* @name export_user_click
*/
$(document).on('click', 'button.mult_submit[value=export]', function (event) {
event.preventDefault();
// can't export if no users checked
if ($(this.form).find('input:checked').length === 0) {
PMA_ajaxShowMessage(PMA_messages.strNoAccountSelected, 2000, 'success');
return;
}
var $msgbox = PMA_ajaxShowMessage();
var button_options = {};
button_options[PMA_messages.strClose] = function () {
$(this).dialog('close');
};
var argsep = PMA_commonParams.get('arg_separator');
$.post(
$(this.form).prop('action'),
$(this.form).serialize() + argsep + 'submit_mult=export' + argsep + 'ajax_request=true',
function (data) {
if (typeof data !== 'undefined' && data.success === true) {
var $ajaxDialog = $('<div />')
.append(data.message)
.dialog({
title: data.title,
width: 500,
buttons: button_options,
close: function () {
$(this).remove();
}
});
PMA_ajaxRemoveMessage($msgbox);
// Attach syntax highlighted editor to export dialog
PMA_getSQLEditor($ajaxDialog.find('textarea'));
} else {
PMA_ajaxShowMessage(data.error, false);
}
}
); // end $.post
});
// if exporting non-ajax, highlight anyways
PMA_getSQLEditor($('textarea.export'));
$(document).on('click', 'a.export_user_anchor.ajax', function (event) {
event.preventDefault();
var $msgbox = PMA_ajaxShowMessage();
/**
* @var button_options Object containing options for jQueryUI dialog buttons
*/
var button_options = {};
button_options[PMA_messages.strClose] = function () {
$(this).dialog('close');
};
$.get($(this).attr('href'), { 'ajax_request': true }, function (data) {
if (typeof data !== 'undefined' && data.success === true) {
var $ajaxDialog = $('<div />')
.append(data.message)
.dialog({
title: data.title,
width: 500,
buttons: button_options,
close: function () {
$(this).remove();
}
});
PMA_ajaxRemoveMessage($msgbox);
// Attach syntax highlighted editor to export dialog
PMA_getSQLEditor($ajaxDialog.find('textarea'));
} else {
PMA_ajaxShowMessage(data.error, false);
}
}); // end $.get
}); // end export privileges
/**
* AJAX handler to Paginate the Users Table
*
* @see PMA_ajaxShowMessage()
* @name paginate_users_table_click
* @memberOf jQuery
*/
$(document).on('click', '#initials_table a.ajax', function (event) {
event.preventDefault();
var $msgbox = PMA_ajaxShowMessage();
$.get($(this).attr('href'), { 'ajax_request' : true }, function (data) {
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxRemoveMessage($msgbox);
// This form is not on screen when first entering Privileges
// if there are more than 50 users
$('div.notice').remove();
$('#usersForm').hide('medium').remove();
$('#fieldset_add_user').hide('medium').remove();
$('#initials_table')
.prop('id', 'initials_table_old')
.after(data.message).show('medium')
.siblings('h2').not(':first').remove();
// prevent double initials table
$('#initials_table_old').remove();
} else {
PMA_ajaxShowMessage(data.error, false);
}
}); // end $.get
}); // end of the paginate users table
$(document).on('change', 'input[name="ssl_type"]', function (e) {
var $div = $('#specified_div');
if ($('#ssl_type_SPECIFIED').is(':checked')) {
$div.find('input').prop('disabled', false);
} else {
$div.find('input').prop('disabled', true);
}
});
$(document).on('change', '#checkbox_SSL_priv', function (e) {
var $div = $('#require_ssl_div');
if ($(this).is(':checked')) {
$div.find('input').prop('disabled', false);
$('#ssl_type_SPECIFIED').trigger('change');
} else {
$div.find('input').prop('disabled', true);
}
});
$('#checkbox_SSL_priv').trigger('change');
/*
* Create submenu for simpler interface
*/
var addOrUpdateSubmenu = function () {
var $topmenu2 = $('#topmenu2');
var $edit_user_dialog = $('#edit_user_dialog');
var submenu_label;
var submenu_link;
var link_number;
// if submenu exists yet, remove it first
if ($topmenu2.length > 0) {
$topmenu2.remove();
}
// construct a submenu from the existing fieldsets
$topmenu2 = $('<ul/>').prop('id', 'topmenu2');
$('#edit_user_dialog .submenu-item').each(function () {
submenu_label = $(this).find('legend[data-submenu-label]').data('submenu-label');
submenu_link = $('<a/>')
.prop('href', '#')
.html(submenu_label);
$('<li/>')
.append(submenu_link)
.appendTo($topmenu2);
});
// click handlers for submenu
$topmenu2.find('a').click(function (e) {
e.preventDefault();
// if already active, ignore click
if ($(this).hasClass('tabactive')) {
return;
}
$topmenu2.find('a').removeClass('tabactive');
$(this).addClass('tabactive');
// which section to show now?
link_number = $topmenu2.find('a').index($(this));
// hide all sections but the one to show
$('#edit_user_dialog .submenu-item').hide().eq(link_number).show();
});
// make first menu item active
// TODO: support URL hash history
$topmenu2.find('> :first-child a').addClass('tabactive');
$edit_user_dialog.prepend($topmenu2);
// hide all sections but the first
$('#edit_user_dialog .submenu-item').hide().eq(0).show();
// scroll to the top
$('html, body').animate({ scrollTop: 0 }, 'fast');
};
$('input.autofocus').focus();
$(checkboxes_sel).trigger('change');
displayPasswordGenerateButton();
if ($('#edit_user_dialog').length > 0) {
addOrUpdateSubmenu();
}
var windowwidth = $(window).width();
$('.jsresponsive').css('max-width', (windowwidth - 35) + 'px');
}

View File

@ -0,0 +1,253 @@
import $ from 'jquery';
import 'jquery-migrate';
import 'jquery-ui-bundle';
import 'jquery-ui-timepicker-addon';
import 'jquery-mousewheel';
import 'jquery.event.drag';
import 'jquery-validation';
import { methods } from './menu_resizer';
// TODO: To use this import for replacing variables used in this file for
// extending various strings for localization.
// import { GlobalVariables, timePicker, validations } from '../variables/export_variables';
import { PMA_Messages as PMA_messages } from '../variables/export_variables';
/**
* Make sure that ajax requests will not be cached
* by appending a random variable to their parameters
*/
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
var nocache = new Date().getTime() + '' + Math.floor(Math.random() * 1000000);
if (typeof options.data === 'string') {
options.data += '&_nocache=' + nocache + '&token=' + encodeURIComponent(PMA_commonParams.get('token'));
} else if (typeof options.data === 'object') {
options.data = $.extend(originalOptions.data, { '_nocache' : nocache, 'token': PMA_commonParams.get('token') });
}
});
/**
* Comes from menu_resizer.js
*/
$.fn.menuResizer = function (method) {
if (methods[method]) {
return methods[method].call(this);
} else if (typeof method === 'function') {
return methods.init.apply(this, [method]);
} else {
$.error('Method ' + method + ' does not exist on jQuery.menuResizer');
}
};
/**
* comes from makegrid.js
*/
$.fn.noSelect = function (p) { // no select plugin by Paulo P.Marinas
var prevent = (p === null) ? true : p;
var is_msie = navigator.userAgent.indexOf('MSIE') > -1 || !!window.navigator.userAgent.match(/Trident.*rv\:11\./);
var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
var is_safari = navigator.userAgent.indexOf('Safari') > -1;
var is_opera = navigator.userAgent.indexOf('Presto') > -1;
if (prevent) {
return this.each(function () {
if (is_msie || is_safari) {
$(this).on('selectstart', false);
} else if (is_firefox) {
$(this).css('MozUserSelect', 'none');
$('body').trigger('focus');
} else if (is_opera) {
$(this).on('mousedown', false);
} else {
$(this).attr('unselectable', 'on');
}
});
} else {
return this.each(function () {
if (is_msie || is_safari) {
$(this).off('selectstart');
} else if (is_firefox) {
$(this).css('MozUserSelect', 'inherit');
} else if (is_opera) {
$(this).off('mousedown');
} else {
$(this).removeAttr('unselectable');
}
});
}
};
/**
* comes from functions.js
*/
/**
* jQuery plugin to correctly filter input fields by value, needed
* because some nasty values may break selector syntax
*/
$.fn.filterByValue = function (value) {
return this.filter(function () {
return $(this).val() === value;
});
};
/**
* jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
* return a jQuery object yet and hence cannot be chained
*
* @param string question
* @param string url URL to be passed to the callbackFn to make
* an Ajax call to
* @param function callbackFn callback to execute after user clicks on OK
* @param function openCallback optional callback to run when dialog is shown
*/
$.fn.PMA_confirm = function (question, url, callbackFn, openCallback) {
var confirmState = PMA_commonParams.get('confirm');
if (! confirmState) {
// user does not want to confirm
if ($.isFunction(callbackFn)) {
callbackFn.call(this, url);
return true;
}
}
if (PMA_messages.strDoYouReally === '') {
return true;
}
/**
* @var button_options Object that stores the options passed to jQueryUI
* dialog
*/
var button_options = [
{
text: PMA_messages.strOK,
'class': 'submitOK',
click: function () {
$(this).dialog('close');
if ($.isFunction(callbackFn)) {
callbackFn.call(this, url);
}
}
},
{
text: PMA_messages.strCancel,
'class': 'submitCancel',
click: function () {
$(this).dialog('close');
}
}
];
$('<div/>', { 'id': 'confirm_dialog', 'title': PMA_messages.strConfirm })
.prepend(question)
.dialog({
buttons: button_options,
close: function () {
$(this).remove();
},
open: openCallback,
modal: true
});
};
/**
* jQuery function to sort a table's body after a new row has been appended to it.
*
* @param string text_selector string to select the sortKey's text
*
* @return jQuery Object for chaining purposes
*/
$.fn.PMA_sort_table = function (text_selector) {
return this.each(function () {
/**
* @var table_body Object referring to the table's <tbody> element
*/
var table_body = $(this);
/**
* @var rows Object referring to the collection of rows in {@link table_body}
*/
var rows = $(this).find('tr').get();
// get the text of the field that we will sort by
$.each(rows, function (index, row) {
row.sortKey = $.trim($(row).find(text_selector).text().toLowerCase());
});
// get the sorted order
rows.sort(function (a, b) {
if (a.sortKey < b.sortKey) {
return -1;
}
if (a.sortKey > b.sortKey) {
return 1;
}
return 0;
});
// pull out each row from the table and then append it according to it's order
$.each(rows, function (index, row) {
$(table_body).append(row);
row.sortKey = null;
});
});
};
/**
* Return POST data as stored by Util::linkOrButton
*/
$.fn.getPostData = function () {
var dataPost = this.attr('data-post');
// Strip possible leading ?
if (dataPost !== undefined && dataPost.substring(0,1) === '?') {
dataPost = dataPost.substr(1);
}
return dataPost;
};
/**
* Replacing default datepicker strings for localization
*/
if ($.datepicker) {
// Creating copy of datepicker strings object
var datePicker = Object.assign(window.datePicker);
// Deleting datepicker variable from window as it is of no use now
delete window.datePicker;
for (let key in datePicker) {
$.datepicker.regional[''][key] = datePicker[key];
}
}
/**
* Replacing default timepicker strings for localozation
*/
if ($.timePicker) {
// Creating copy of timepicker strings object
var timePicker = Object.assign(window.timePicker);
// Deleting timepicker variable from window as it is of no use now
delete window.timePicker;
for (let key in timePicker) {
$.timepicker.regional[''][key] = timePicker[key];
}
}
export function extendingValidatorMessages () {
// Creating copy of validationMessage strings object
var validateMessage = Object.assign(window.validationMessage);
// Deleting validationMessage variable from window as it is of no use now
delete window.validationMessage;
// Replacing default validation messages forr localization
$.extend($.validator.messages, validateMessage);
// Creating copy of validationFormat strings object
var validateFormat = Object.assign(window.validationFormat);
// Deleting validationFormat variable from window as it is of no use now
delete window.validationFormat;
for (let i in validateFormat) {
validateFormat[i] = $.validator.format(validateFormat[i]);
}
// Replacing default validation messages forr localization
$.extend($.validator.messages, validateFormat);
}
window.jQ = $;
export const jQuery = $;

35
js/src/utils/Sanitise.js Normal file
View File

@ -0,0 +1,35 @@
/**
* HTML escaping
*/
export function escapeHtml (unsafe) {
if (typeof(unsafe) !== 'undefined') {
return unsafe
.toString()
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
} else {
return false;
}
}
export function escapeJsString (unsafe) {
if (typeof(unsafe) !== 'undefined') {
return unsafe
.toString()
.replace('\x00', '')
.replace('\\', '\\\\')
.replace('\'', '\\\'')
.replace('&#039;', '\\\&#039;')
.replace('"', '\"')
.replace('&quot;', '\&quot;')
.replace('\n', '\n')
.replace('\r', '\r')
.replace(/<\/script/gi, '</\' + \'script');
} else {
return false;
}
}

View File

@ -0,0 +1,209 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Handles the resizing of a menu according to the available screen width
*
* Uses themes/original/css/resizable-menu.css.php
*
* To initialise:
* $('#myMenu').menuResizer(function () {
* // This function will be called to find out how much
* // available horizontal space there is for the menu
* return $('body').width() - 5; // Some extra margin for good measure
* });
*
* To trigger a resize operation:
* $('#myMenu').menuResizer('resize'); // Bind this to $(window).resize()
*
* To restore the menu to a state like before it was initialized:
* $('#myMenu').menuResizer('destroy');
*
* @package PhpMyAdmin
*/
function MenuResizer ($container, widthCalculator) {
var self = this;
self.$container = $container;
self.widthCalculator = widthCalculator;
var windowWidth = $(window).width();
if (windowWidth < 768) {
$('#pma_navigation_resizer').css({ 'width': '0px' });
}
// Sets the image for the left and right scroll indicator
$('.scrollindicator--left').html($(PMA_getImage('b_left').toString()));
$('.scrollindicator--right').html($(PMA_getImage('b_right').toString()));
// Set the width of the navigation bar without scroll indicator
$('.navigationbar').css({ 'width': widthCalculator.call($container) - 60 });
// Scroll the navigation bar on click
$('.scrollindicator--right').on('click', function () {
$('.navigationbar').scrollLeft($('.navigationbar').scrollLeft() + 70);
});
$('.scrollindicator--left').on('click', function () {
$('.navigationbar').scrollLeft($('.navigationbar').scrollLeft() - 70);
});
// create submenu container
var link = $('<a />', { href: '#', 'class': 'tab nowrap' })
.text(PMA_messages.strMore)
.on('click', false); // same as event.preventDefault()
var img = $container.find('li img');
if (img.length) {
$(PMA_getImage('b_more').toString()).prependTo(link);
}
var $submenu = $('<li />', { 'class': 'submenu' })
.append(link)
.append($('<ul />'))
.on('mouseenter', function () {
if ($(this).find('ul .tabactive').length === 0) {
$(this)
.addClass('submenuhover')
.find('> a')
.addClass('tabactive');
}
})
.on('mouseleave', function () {
if ($(this).find('ul .tabactive').length === 0) {
$(this)
.removeClass('submenuhover')
.find('> a')
.removeClass('tabactive');
}
});
$container.children('.clearfloat').remove();
$container.append($submenu).append('<div class=\'clearfloat\'></div>');
setTimeout(function () {
self.resize();
}, 4);
}
MenuResizer.prototype.resize = function () {
var wmax = this.widthCalculator.call(this.$container);
var windowWidth = $(window).width();
var $submenu = this.$container.find('.submenu:last');
var submenu_w = $submenu.outerWidth(true);
var $submenu_ul = $submenu.find('ul');
var $li = this.$container.find('> li');
var $li2 = $submenu_ul.find('li');
var more_shown = $li2.length > 0;
// Calculate the total width used by all the shown tabs
var total_len = more_shown ? submenu_w : 0;
var l = $li.length - 1;
var i;
for (i = 0; i < l; i++) {
total_len += $($li[i]).outerWidth(true);
}
var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
if (hasVScroll) {
windowWidth += 15;
}
var navigationwidth = wmax;
if (windowWidth < 768) {
wmax = 2000;
}
// Now hide menu elements that don't fit into the menubar
var hidden = false; // Whether we have hidden any tabs
while (total_len >= wmax && --l >= 0) { // Process the tabs backwards
hidden = true;
var el = $($li[l]);
var el_width = el.outerWidth(true);
el.data('width', el_width);
if (! more_shown) {
total_len -= el_width;
el.prependTo($submenu_ul);
total_len += submenu_w;
more_shown = true;
} else {
total_len -= el_width;
el.prependTo($submenu_ul);
}
}
// If we didn't hide any tabs, then there might be some space to show some
if (! hidden) {
// Show menu elements that do fit into the menubar
for (i = 0, l = $li2.length; i < l; i++) {
total_len += $($li2[i]).data('width');
// item fits or (it is the last item
// and it would fit if More got removed)
if (total_len < wmax ||
(i === $li2.length - 1 && total_len - submenu_w < wmax)
) {
$($li2[i]).insertBefore($submenu);
} else {
break;
}
}
}
// Show/hide the "More" tab as needed
if (windowWidth < 768) {
$('.navigationbar').css({ 'width': windowWidth - 80 - $('#pma_navigation').width() });
$submenu.removeClass('shown');
$('.navigationbar').css({ 'overflow': 'hidden' });
} else {
$('.navigationbar').css({ 'width': 'auto' });
$('.navigationbar').css({ 'overflow': 'visible' });
if ($submenu_ul.find('li').length > 0) {
$submenu.addClass('shown');
} else {
$submenu.removeClass('shown');
}
}
if (this.$container.find('> li').length === 1) {
// If there is only the "More" tab left, then we need
// to align the submenu to the left edge of the tab
$submenu_ul.removeClass().addClass('only');
} else {
// Otherwise we align the submenu to the right edge of the tab
$submenu_ul.removeClass().addClass('notonly');
}
if ($submenu.find('.tabactive').length) {
$submenu
.addClass('active')
.find('> a')
.removeClass('tab')
.addClass('tabactive');
} else {
$submenu
.removeClass('active')
.find('> a')
.addClass('tab')
.removeClass('tabactive');
}
};
MenuResizer.prototype.destroy = function () {
var $submenu = this.$container.find('li.submenu').removeData();
$submenu.find('li').appendTo(this.$container);
$submenu.remove();
};
/** Public API */
export var methods = {
init: function (widthCalculator) {
return this.each(function () {
var $this = $(this);
if (! $this.data('menuResizer')) {
$this.data(
'menuResizer',
new MenuResizer($this, widthCalculator)
);
}
});
},
resize: function () {
return this.each(function () {
var self = $(this).data('menuResizer');
if (self) {
self.resize();
}
});
},
destroy: function () {
return this.each(function () {
var self = $(this).data('menuResizer');
if (self) {
self.destroy();
}
});
}
};

179
js/src/utils/password.js Normal file
View File

@ -0,0 +1,179 @@
import { PMA_Messages as PMA_messages } from '../variables/export_variables';
import zxcvbn from 'zxcvbn';
/**
* Generate a new password and copy it to the password input areas
*
* @param passwd_form object the form that holds the password fields
*
* @return boolean always true
*/
export function suggestPassword (passwd_form) {
// restrict the password to just letters and numbers to avoid problems:
// "editors and viewers regard the password as multiple words and
// things like double click no longer work"
var pwchars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWYXZ';
var passwordlength = 16; // do we want that to be dynamic? no, keep it simple :)
var passwd = passwd_form.generated_pw;
var randomWords = new Int32Array(passwordlength);
passwd.value = '';
// First we're going to try to use a built-in CSPRNG
if (window.crypto && window.crypto.getRandomValues) {
window.crypto.getRandomValues(randomWords);
} else if (window.msCrypto && window.msCrypto.getRandomValues) {
// Because of course IE calls it msCrypto instead of being standard
window.msCrypto.getRandomValues(randomWords);
} else {
// Fallback to Math.random
for (let i = 0; i < passwordlength; i++) {
randomWords[i] = Math.floor(Math.random() * pwchars.length);
}
}
for (let i = 0; i < passwordlength; i++) {
passwd.value += pwchars.charAt(Math.abs(randomWords[i]) % pwchars.length);
}
var $jquery_passwd_form = $(passwd_form);
passwd_form.elements.pma_pw.value = passwd.value;
passwd_form.elements.pma_pw2.value = passwd.value;
var meter_obj = $jquery_passwd_form.find('meter[name="pw_meter"]').first();
var meter_obj_label = $jquery_passwd_form.find('span[name="pw_strength"]').first();
checkPasswordStrength(passwd.value, meter_obj, meter_obj_label);
return true;
}
/**
* for PhpMyAdmin\Display\ChangePassword
* libraries/user_password.php
*
*/
export function displayPasswordGenerateButton () {
var generatePwdRow = $('<tr />').addClass('vmiddle');
$('<td />').html(PMA_messages.strGeneratePassword).appendTo(generatePwdRow);
var pwdCell = $('<td />').appendTo(generatePwdRow);
var pwdButton = $('<input />')
.attr({ type: 'button', id: 'button_generate_password', value: PMA_messages.strGenerate })
.addClass('button')
.on('click', function () {
suggestPassword(this.form);
});
var pwdTextbox = $('<input />')
.attr({ type: 'text', name: 'generated_pw', id: 'generated_pw' });
pwdCell.append(pwdButton).append(pwdTextbox);
$('#tr_element_before_generate_password').parent().append(generatePwdRow);
var generatePwdDiv = $('<div />').addClass('item');
$('<label />').attr({ for: 'button_generate_password' })
.html(PMA_messages.strGeneratePassword + ':')
.appendTo(generatePwdDiv);
var optionsSpan = $('<span/>').addClass('options')
.appendTo(generatePwdDiv);
pwdButton.clone(true).appendTo(optionsSpan);
pwdTextbox.clone(true).appendTo(generatePwdDiv);
$('#div_element_before_generate_password').parent().append(generatePwdDiv);
}
/**
* Validates the "add a user" form
*
* @return {boolean} whether the form is validated or not
*/
export function checkAddUser (the_form) {
if (the_form.elements.pred_hostname.value === 'userdefined' && the_form.elements.hostname.value === '') {
alert(PMA_messages.strHostEmpty);
the_form.elements.hostname.focus();
return false;
}
if (the_form.elements.pred_username.value === 'userdefined' && the_form.elements.username.value === '') {
alert(PMA_messages.strUserEmpty);
the_form.elements.username.focus();
return false;
}
return PMA_checkPassword($(the_form));
} // end of the 'checkAddUser()' function
/**
* Function to check the password strength
*
* @param {string} value Passworrd string
* @param {object} meter_obj jQuery object to show strength in meter
* @param {object} meter_object_label jQuery object to show text of password strnegth
* @param {string} username Username string
*
* @returns {void}
*/
export function checkPasswordStrength (value, meter_obj, meter_object_label, username) {
// List of words we don't want to appear in the password
var customDict = [
'phpmyadmin',
'mariadb',
'mysql',
'php',
'my',
'admin',
];
if (username !== null) {
customDict.push(username);
}
var zxcvbn_obj = zxcvbn(value, customDict);
var strength = zxcvbn_obj.score;
strength = parseInt(strength);
meter_obj.val(strength);
switch (strength) {
case 0: meter_object_label.html(PMA_messages.strExtrWeak);
break;
case 1: meter_object_label.html(PMA_messages.strVeryWeak);
break;
case 2: meter_object_label.html(PMA_messages.strWeak);
break;
case 3: meter_object_label.html(PMA_messages.strGood);
break;
case 4: meter_object_label.html(PMA_messages.strStrong);
}
}
/**
* Validates the password field in a form
*
* @see PMA_messages.strPasswordEmpty
* @see PMA_messages.strPasswordNotSame
* @param object $the_form The form to be validated
* @return bool
*/
function PMA_checkPassword ($the_form) {
// Did the user select 'no password'?
if ($the_form.find('#nopass_1').is(':checked')) {
return true;
} else {
var $pred = $the_form.find('#select_pred_password');
if ($pred.length && ($pred.val() === 'none' || $pred.val() === 'keep')) {
return true;
}
}
var $password = $the_form.find('input[name=pma_pw]');
var $password_repeat = $the_form.find('input[name=pma_pw2]');
var alert_msg = false;
if ($password.val() === '') {
alert_msg = PMA_messages.strPasswordEmpty;
} else if ($password.val() !== $password_repeat.val()) {
alert_msg = PMA_messages.strPasswordNotSame;
}
if (alert_msg) {
alert(alert_msg);
$password.val('');
$password_repeat.val('');
$password.focus();
return false;
}
return true;
}

View File

@ -0,0 +1,190 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Functions for adding and removing ajax messages
*/
/**
* Module imports
*/
import { PMA_Messages as PMA_messages } from '../variables/export_variables';
/**
* @var int ajax_message_count Number of AJAX messages shown since page load
*/
let ajax_message_count = 0;
/**
* Create a jQuery UI tooltip
*
* @param $elements jQuery object representing the elements
* @param item the item
* (see https://api.jqueryui.com/tooltip/#option-items)
* @param myContent content of the tooltip
* @param additionalOptions to override the default options
*
*/
export function PMA_tooltip ($elements, item, myContent, additionalOptions) {
if ($('#no_hint').length > 0) {
return;
}
var defaultOptions = {
content: myContent,
items: item,
tooltipClass: 'tooltip',
track: true,
show: false,
hide: false
};
$elements.tooltip($.extend(true, defaultOptions, additionalOptions));
}
/**
* Show a message on the top of the page for an Ajax request
*
* Sample usage:
*
* 1) var $msg = PMA_ajaxShowMessage();
* This will show a message that reads "Loading...". Such a message will not
* disappear automatically and cannot be dismissed by the user. To remove this
* message either the PMA_ajaxRemoveMessage($msg) function must be called or
* another message must be show with PMA_ajaxShowMessage() function.
*
* 2) var $msg = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
* This is a special case. The behaviour is same as above,
* just with a different message
*
* 3) var $msg = PMA_ajaxShowMessage('The operation was successful');
* This will show a message that will disappear automatically and it can also
* be dismissed by the user.
*
* 4) var $msg = PMA_ajaxShowMessage('Some error', false);
* This will show a message that will not disappear automatically, but it
* can be dismissed by the user after he has finished reading it.
*
* @param string message string containing the message to be shown.
* optional, defaults to 'Loading...'
* @param mixed timeout number of milliseconds for the message to be visible
* optional, defaults to 5000. If set to 'false', the
* notification will never disappear
* @param string type string to dictate the type of message shown.
* optional, defaults to normal notification.
* If set to 'error', the notification will show message
* with red background.
* If set to 'success', the notification will show with
* a green background.
* @return jQuery object jQuery Element that holds the message div
* this object can be passed to PMA_ajaxRemoveMessage()
* to remove the notification
*/
export const PMA_ajaxShowMessage = (message, timeout, type) => {
/**
* @var self_closing Whether the notification will automatically disappear
*/
var self_closing = true;
/**
* @var dismissable Whether the user will be able to remove
* the notification by clicking on it
*/
var dismissable = true;
// Handle the case when a empty data.message is passed.
// We don't want the empty message
if (message === '') {
return true;
} else if (! message) {
// If the message is undefined, show the default
message = PMA_messages.strLoading;
dismissable = false;
self_closing = false;
} else if (message === PMA_messages.strProcessingRequest) {
// This is another case where the message should not disappear
dismissable = false;
self_closing = false;
}
// Figure out whether (or after how long) to remove the notification
if (timeout === undefined) {
timeout = 5000;
} else if (timeout === false) {
self_closing = false;
}
// Determine type of message, add styling as required
if (type === 'error') {
message = '<div class="error">' + message + '</div>';
} else if (type === 'success') {
message = '<div class="success">' + message + '</div>';
}
// Create a parent element for the AJAX messages, if necessary
if ($('#loading_parent').length === 0) {
$('<div id="loading_parent"></div>')
.prependTo('#page_content');
}
// Update message count to create distinct message elements every time
ajax_message_count++;
// Remove all old messages, if any
$('span.ajax_notification[id^=ajax_message_num]').remove();
/**
* @var $retval a jQuery object containing the reference
* to the created AJAX message
*/
var $retval = $(
'<span class="ajax_notification" id="ajax_message_num_' +
ajax_message_count +
'"></span>'
)
.hide()
.appendTo('#loading_parent')
.html(message)
.show();
// If the notification is self-closing we should create a callback to remove it
if (self_closing) {
$retval
.delay(timeout)
.fadeOut('medium', function () {
if ($(this).is(':data(tooltip)')) {
$(this).tooltip('destroy');
}
// Remove the notification
$(this).remove();
});
}
// If the notification is dismissable we need to add the relevant class to it
// and add a tooltip so that the users know that it can be removed
if (dismissable) {
$retval.addClass('dismissable').css('cursor', 'pointer');
/**
* Add a tooltip to the notification to let the user know that (s)he
* can dismiss the ajax notification by clicking on it.
*/
PMA_tooltip(
$retval,
'span',
PMA_messages.strDismiss
);
}
PMA_highlightSQL($retval);
return $retval;
};
/**
* Removes the message shown for an Ajax operation when it's completed
*
* @param jQuery object jQuery Element that holds the notification
*
* @return nothing
*/
export function PMA_ajaxRemoveMessage ($this_msgbox) {
if ($this_msgbox !== undefined && $this_msgbox instanceof jQuery) {
$this_msgbox
.stop(true, true)
.fadeOut('medium');
if ($this_msgbox.is(':data(tooltip)')) {
$this_msgbox.tooltip('destroy');
} else {
$this_msgbox.remove();
}
}
}

18
js/src/utils/sprintf.js Normal file
View File

@ -0,0 +1,18 @@
import sprintf from 'sprintf-js';
/**
* @param string string message to display
*
* @return string A concated string of aguments passed
*/
export function PMA_sprintf () {
/**
* This package can be implemented in two ways
*
* 1) sprintf.sprintf("A %s is %s", "string", "string");
*
* 2) sprintf.vsprintf("A %s is %s", ["string", "string"]);
*/
return sprintf.sprintf(...arguments);
}

View File

@ -0,0 +1,99 @@
import { PMA_sprintf } from '../utils/sprintf';
import { PMA_showCurrentNavigation } from '../functions/navigation';
/**
* Holds common parameters such as server, db, table, etc
*
* The content for this is normally loaded from Header.php or
* Response.php and executed by ajax.js
*/
export const PMA_commonParams = (function () {
/**
* @var hash params An associative array of key value pairs
* @access private
*/
var params = {};
// The returned object is the public part of the module
return {
/**
* Saves all the key value pair that
* are provided in the input array
*
* @param obj hash The input array
*
* @return void
*/
setAll: function (obj) {
// var reload = false;
var updateNavigation = false;
for (var i in obj) {
if (params[i] !== undefined && params[i] !== obj[i]) {
if (i === 'db' || i === 'table') {
updateNavigation = true;
}
// reload = true;
}
params[i] = obj[i];
}
if (updateNavigation &&
$('#pma_navigation_tree').hasClass('synced')
) {
PMA_showCurrentNavigation();
}
},
/**
* Retrieves a value given its key
* Returns empty string for undefined values
*
* @param name string The key
*
* @return string
*/
get: function (name) {
return params[name];
},
/**
* Saves a single key value pair
*
* @param name string The key
* @param value string The value
*
* @return self For chainability
*/
set: function (name, value) {
var updateNavigation = false;
if (name === 'db' || name === 'table' &&
params[name] !== value
) {
updateNavigation = true;
}
params[name] = value;
if (updateNavigation &&
$('#pma_navigation_tree').hasClass('synced')
) {
PMA_showCurrentNavigation();
}
return this;
},
/**
* Returns the url query string using the saved parameters
*
* @return string
*/
getUrlQuery: function () {
var common = this.get('common_query');
var separator = '?';
var argsep = PMA_commonParams.get('arg_separator');
if (common.length > 0) {
separator = argsep;
}
return PMA_sprintf(
'%s%sserver=%s' + argsep + 'db=%s' + argsep + 'table=%s',
this.get('common_query'),
separator,
encodeURIComponent(this.get('server')),
encodeURIComponent(this.get('db')),
encodeURIComponent(this.get('table'))
);
}
};
}());

View File

@ -0,0 +1,10 @@
import { Variables } from './global_variables';
export const PMA_Messages = Variables.getMessages();
export const timePicker = Variables.getTimePickerVars();
export const GlobalVariables = Variables.getGlobalVars();
export const validations = Variables.getValidatorMessages();

View File

@ -2,23 +2,23 @@
/**
* Takes parameters defined in messages.php file like messages, validations,
* jquery-ui-timepicker edits using global functions
* jquery-ui-timepicker edits
*/
export const PMA_messages = (function () {
export const Variables = (function () {
/**
* @var obj params An associate array having key value pairs
* of messages to show in js files.
*
* @access private
*/
let messages = new Array();
let pmaMessages = new Array();
/**
* @var obj params Associative array having global configurations
*
* @access private
*/
let globalVars = new Array();
let globalVariables = new Array();
/**
* @var obj params Associative array having timepicker edits
*
@ -37,7 +37,7 @@ export const PMA_messages = (function () {
* @return array
*/
getMessages: () => {
return messages;
return pmaMessages;
},
/**
* Retrieves the globalVars array
@ -45,7 +45,7 @@ export const PMA_messages = (function () {
* @return array
*/
getGlobalVars: () => {
return globalVars;
return globalVariables;
},
/**
* Retrieves the timePickerVars array
@ -72,7 +72,7 @@ export const PMA_messages = (function () {
*/
setAllMessages: (obj) => {
for (var i in obj) {
messages[i] = obj[i];
pmaMessages[i] = obj[i];
}
},
/**
@ -84,7 +84,7 @@ export const PMA_messages = (function () {
*/
setGlobalVars: (obj) => {
for (var i in obj) {
globalVars[i] = obj[i];
globalVariables[i] = obj[i];
}
},
/**

View File

@ -0,0 +1,20 @@
import { Variables } from './global_variables';
import { PMA_commonParams } from './common_params';
var jqueryValidations = {
validationFormat: window.validateFormat,
validationMessage: window.validationMessage
};
Variables.setAllMessages(window.PMA_messages);
Variables.setTimePickerVars({
datePicker: window.datePicker,
timePicker: window.timePicker
});
Variables.setValidatorMessages(jqueryValidations);
Variables.setGlobalVars(window.globalVars);
/**
* This statement to be placed in the file going to be
* executed firstly like functions.js
*/
PMA_commonParams.setAll(window.common_params);

View File

@ -84,7 +84,7 @@ class ServerDatabasesController extends Controller
$header = $this->response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('server_databases.js');
$scripts->addFile('server_databases');
$this->_setSortDetails();
$this->_dbstats = empty($_REQUEST['dbstats']) ? false : true;

View File

@ -164,13 +164,10 @@ class Header
private function _addDefaultScripts(): void
{
// Localised strings
$this->_scripts->addFile('vendor/jquery/jquery.min.js');
$this->_scripts->addFile('vendor/jquery/jquery-migrate.js');
$this->_scripts->addFile('whitelist.php');
$this->_scripts->addFile('vendor/sprintf.js');
$this->_scripts->addFile('ajax.js');
$this->_scripts->addFile('keyhandler.js');
$this->_scripts->addFile('vendor/jquery/jquery-ui.min.js');
$this->_scripts->addFile('vendor/js.cookie.js');
$this->_scripts->addFile('vendor/jquery/jquery.mousewheel.js');
@ -185,7 +182,9 @@ class Header
// the user preferences have not been merged at this point
$this->_scripts->addFile('messages.php', array('l' => $GLOBALS['lang']));
$this->_scripts->addFile('common_params.php', array('l' => $GLOBALS['lang']));
$this->_scripts->addFile('index_new.js');
$this->_scripts->addFile('keyhandler.js');
// Cross-framing protection
if ($GLOBALS['cfg']['AllowThirdPartyFraming'] === false) {
$this->_scripts->addFile('cross_framing_protection.js');

View File

@ -65,7 +65,7 @@ class Scripts
}
$result .= '<script data-cfasync="false" type="text/javascript" src="' . $src . 'js/dist/'
. $value['filename'] . '?' . Header::getVersionParameter() . '"></script>' . "\n";
} else {
} else if (strpos($value['filename'], ".js") !== false) {
$result .= '<script data-cfasync="false" type="text/javascript" src="js/'
. $value['filename'] . '?' . Header::getVersionParameter() . '"></script>' . "\n";
}
@ -137,6 +137,7 @@ class Scripts
|| strpos($filename, 'messages.php') !== false
|| strpos($filename, 'ajax.js') !== false
|| strpos($filename, 'cross_framing_protection.js') !== false
|| strpos($filename, 'index_new.js') !== false
) {
return 0;
}
@ -186,7 +187,6 @@ class Scripts
public function getDisplay()
{
$retval = '';
if (count($this->_files) > 0) {
$retval .= $this->_includeFiles(
$this->_files
@ -195,18 +195,20 @@ class Scripts
$code = 'AJAX.scriptHandler';
foreach ($this->_files as $file) {
$code .= sprintf(
'.add("%s",%d)',
Sanitize::escapeJsString($file['filename']),
$file['has_onload'] ? 1 : 0
);
if (strpos($file['filename'], ".js") !== false) {
$code .= sprintf(
'.add("%s",%d)',
Sanitize::escapeJsString($file['filename']),
$file['has_onload'] ? 1 : 0
);
}
}
$code .= ';';
$this->addCode($code);
$code = '$(function() {';
foreach ($this->_files as $file) {
if ($file['has_onload']) {
if ($file['has_onload'] && strpos($file['filename'], ".js") !== false) {
$code .= 'AJAX.fireOnload("';
$code .= Sanitize::escapeJsString($file['filename']);
$code .= '");';

View File

@ -14,20 +14,24 @@
"dependencies": {
"codemirror": "5.37.0",
"jquery": "3.3.1",
"jquery-migrate": "3.0.1",
"jquery-migrate": "3.0.0",
"jquery-mousewheel": "3.1.13",
"jquery-ui": "1.12.1",
"jquery-ui": "^1.12.1",
"jquery-ui-bundle": "^1.12.1-migrate",
"jquery-ui-timepicker-addon": "1.6.3",
"jquery-validation": "1.17.0",
"jquery.event.drag": "2.2.2",
"js-cookie": "2.2.0",
"sprintf-js": "^1.1.1",
"tracekit": "0.4.5",
"updated-jqplot": "1.0.9",
"zxcvbn": "4.4.2"
},
"devDependencies": {
"babel-cli": "6.26.0",
"babel-eslint": "8.2.6",
"babel-loader": "^7.1.4",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-env": "^1.7.0",
"cross-env": "^5.1.5",
"del-cli": "^1.1.0",

View File

@ -35,8 +35,7 @@ $cfgRelation = $relation->getRelationsParam();
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('server_privileges.js');
$scripts->addFile('vendor/zxcvbn.js');
$scripts->addFile('server_privileges');
$template = new Template();
$serverPrivileges = new Privileges($template);

View File

@ -25,9 +25,8 @@ require_once 'libraries/replication.inc.php';
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('server_privileges.js');
$scripts->addFile('server_privileges');
$scripts->addFile('replication.js');
$scripts->addFile('vendor/zxcvbn.js');
$template = new Template();

View File

@ -40,10 +40,10 @@ var plugins = [
export default [{
mode: MODE,
entry: {
db_search_new: './js/src/db_search.js'
index_new: './js/src/index.js'
},
output: {
filename: 'db_search_new.js',
filename: '[name].js',
path: path.resolve(__dirname, 'js/dist'),
publicPath: PUBLIC_PATH
},