- Added missing CSS Sprites, Icon sprites now also for PMA_linkOrButton()

- Rewrote PMA_linkOrButton() to rely on Javascript, making the code way less complicated
- Removed legacy support of Javascript 1.1 or lower
- Fixed a bug in cases where PMA_linkOrButton() creates a form, which when clicked required a js confirm, the confirm is being displayed a second time after the form is submitted.
This commit is contained in:
Tyron Madlener 2011-07-23 09:23:18 +03:00
parent 9ee8ff38c3
commit ace73f25bb
8 changed files with 138 additions and 172 deletions

View File

@ -210,7 +210,13 @@ function confirmLink(theLink, theSqlQuery)
var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
if (is_confirmed) {
if ( typeof(theLink.href) != 'undefined' ) {
if ( $(theLink).hasClass('formLinkSubmit') ) {
var name = 'is_js_confirmed';
if($(theLink).attr('href').indexOf('usesubform') != -1)
name = 'subform[' + $(theLink).attr('href').substr('#').match(/usesubform\[(\d+)\]/i)[1] + '][is_js_confirmed]';
$(theLink).parents('form').append('<input type="hidden" name="' + name + '" value="1" />');
} else if ( typeof(theLink.href) != 'undefined' ) {
theLink.href += '&is_js_confirmed=1';
} else if ( typeof(theLink.form) != 'undefined' ) {
theLink.form.action += '?is_js_confirmed=1';
@ -265,59 +271,51 @@ function confirmQuery(theForm1, sqlQuery1)
return true;
}
// The replace function (js1.2) isn't supported
else if (typeof(sqlQuery1.value.replace) == 'undefined') {
return true;
}
// js1.2+ -> validation with regular expressions
else {
// "DROP DATABASE" statement isn't allowed
if (PMA_messages['strNoDropDatabases'] != '') {
var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
if (drop_re.test(sqlQuery1.value)) {
alert(PMA_messages['strNoDropDatabases']);
theForm1.reset();
sqlQuery1.focus();
return false;
} // end if
// "DROP DATABASE" statement isn't allowed
if (PMA_messages['strNoDropDatabases'] != '') {
var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
if (drop_re.test(sqlQuery1.value)) {
alert(PMA_messages['strNoDropDatabases']);
theForm1.reset();
sqlQuery1.focus();
return false;
} // end if
} // end if
// Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
//
// TODO: find a way (if possible) to use the parser-analyser
// for this kind of verification
// For now, I just added a ^ to check for the statement at
// beginning of expression
// Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
//
// TODO: find a way (if possible) to use the parser-analyser
// for this kind of verification
// For now, I just added a ^ to check for the statement at
// beginning of expression
var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
if (do_confirm_re_0.test(sqlQuery1.value)
|| do_confirm_re_1.test(sqlQuery1.value)
|| do_confirm_re_2.test(sqlQuery1.value)
|| do_confirm_re_3.test(sqlQuery1.value)) {
var message = (sqlQuery1.value.length > 100)
? sqlQuery1.value.substr(0, 100) + '\n ...'
: sqlQuery1.value;
var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
// statement is confirmed -> update the
// "is_js_confirmed" form field so the confirm test won't be
// run on the server side and allows to submit the form
if (is_confirmed) {
theForm1.elements['is_js_confirmed'].value = 1;
return true;
}
// statement is rejected -> do not submit the form
else {
window.focus();
sqlQuery1.focus();
return false;
} // end if (handle confirm box result)
} // end if (display confirm box)
} // end confirmation stuff
if (do_confirm_re_0.test(sqlQuery1.value)
|| do_confirm_re_1.test(sqlQuery1.value)
|| do_confirm_re_2.test(sqlQuery1.value)
|| do_confirm_re_3.test(sqlQuery1.value)) {
var message = (sqlQuery1.value.length > 100)
? sqlQuery1.value.substr(0, 100) + '\n ...'
: sqlQuery1.value;
var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
// statement is confirmed -> update the
// "is_js_confirmed" form field so the confirm test won't be
// run on the server side and allows to submit the form
if (is_confirmed) {
theForm1.elements['is_js_confirmed'].value = 1;
return true;
}
// statement is rejected -> do not submit the form
else {
window.focus();
sqlQuery1.focus();
return false;
} // end if (handle confirm box result)
} // end if (display confirm box)
return true;
} // end of the 'confirmQuery()' function
@ -360,47 +358,31 @@ function checkSqlQuery(theForm)
var sqlQuery = theForm.elements['sql_query'];
var isEmpty = 1;
// The replace function (js1.2) isn't supported -> basic tests
if (typeof(sqlQuery.value.replace) == 'undefined') {
isEmpty = (sqlQuery.value == '') ? 1 : 0;
if (isEmpty && typeof(theForm.elements['sql_file']) != 'undefined') {
isEmpty = (theForm.elements['sql_file'].value == '') ? 1 : 0;
}
if (isEmpty && typeof(theForm.elements['sql_localfile']) != 'undefined') {
isEmpty = (theForm.elements['sql_localfile'].value == '') ? 1 : 0;
}
if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined') {
isEmpty = (theForm.elements['id_bookmark'].value == null || theForm.elements['id_bookmark'].value == '');
var space_re = new RegExp('\\s+');
if (typeof(theForm.elements['sql_file']) != 'undefined' &&
theForm.elements['sql_file'].value.replace(space_re, '') != '') {
return true;
}
if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
return true;
}
if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
(theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
theForm.elements['id_bookmark'].selectedIndex != 0
) {
return true;
}
// Checks for "DROP/DELETE/ALTER" statements
if (sqlQuery.value.replace(space_re, '') != '') {
if (confirmQuery(theForm, sqlQuery)) {
return true;
} else {
return false;
}
}
// js1.2+ -> validation with regular expressions
else {
var space_re = new RegExp('\\s+');
if (typeof(theForm.elements['sql_file']) != 'undefined' &&
theForm.elements['sql_file'].value.replace(space_re, '') != '') {
return true;
}
if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
return true;
}
if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
(theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
theForm.elements['id_bookmark'].selectedIndex != 0
) {
return true;
}
// Checks for "DROP/DELETE/ALTER" statements
if (sqlQuery.value.replace(space_re, '') != '') {
if (confirmQuery(theForm, sqlQuery)) {
return true;
} else {
return false;
}
}
theForm.reset();
isEmpty = 1;
}
theForm.reset();
isEmpty = 1;
if (isEmpty) {
sqlQuery.select();
@ -423,19 +405,9 @@ function checkSqlQuery(theForm)
*/
function emptyCheckTheField(theForm, theFieldName)
{
var isEmpty = 1;
var theField = theForm.elements[theFieldName];
// Whether the replace function (js1.2) is supported or not
var isRegExp = (typeof(theField.value.replace) != 'undefined');
if (!isRegExp) {
isEmpty = (theField.value == '') ? 1 : 0;
} else {
var space_re = new RegExp('\\s+');
isEmpty = (theField.value.replace(space_re, '') == '') ? 1 : 0;
}
return isEmpty;
var space_re = new RegExp('\\s+');
return (theField.value.replace(space_re, '') == '') ? 1 : 0;
} // end of the 'emptyCheckTheField()' function
@ -1457,6 +1429,7 @@ function PMA_createTableDialog( div, url , target) {
* - the current response value of the GET request, JSON parsed
* - the previous response value of the GET request, JSON parsed
* - the number of added points
* error: Callback function when the get request fails. TODO: Apply callback on timeouts aswell
* }
*
* @return object The created highcharts instance
@ -1489,7 +1462,13 @@ function PMA_createChart(passedSettings) {
thisChart.options.realtime.url,
thisChart.options.realtime.postData,
function(data) {
curValue = jQuery.parseJSON(data);
try {
curValue = jQuery.parseJSON(data);
} catch (err) {
if(thisChart.options.realtime.error)
thisChart.options.realtime.error(err);
return;
}
if(lastValue==null) diff = curValue.x - thisChart.xAxis[0].getExtremes().max;
else diff = parseInt(curValue.x - lastValue.x);
@ -1618,12 +1597,12 @@ function PMA_createProfilingChart(data, options) {
// Formats a profiling duration nicely. Used in PMA_createProfilingChart() and server_status.js
function PMA_prettyProfilingNum(num, acc) {
if(!acc) acc = 1;
acc = Math.pow(10,acc);
if(num*1000 < 0.1) num = Math.round(acc*(num*1000*1000))/acc + 'µ'
else if(num < 0.1) num = Math.round(acc*(num*1000))/acc + 'm'
return num + 's';
if(!acc) acc = 1;
acc = Math.pow(10,acc);
if(num*1000 < 0.1) num = Math.round(acc*(num*1000*1000))/acc + 'µ'
else if(num < 0.1) num = Math.round(acc*(num*1000))/acc + 'm'
return num + 's';
}
/**
@ -2750,22 +2729,15 @@ $(document).ready(function() {
/**
* Enables the text generated by PMA_linkOrButton() to be clickable
*/
$('.clickprevimage')
.css('color', function(index) {
return $('a').css('color');
})
.css('cursor', function(index) {
return $('a').css('cursor');
}) //todo: hover effect
.live('click',function(e) {
$this_span = $(this);
if ($this_span.closest('td').is('.inline_edit_anchor')) {
// this would bind a second click event to the inline edit
// anchor and would disturb its behavior
} else {
$this_span.parent().find('input:image').click();
}
});
$('a[class~="formLinkSubmit"]').live('click',function(e) {
if($(this).attr('href').indexOf('=') != -1) {
var data = $(this).attr('href').substr($(this).attr('href').indexOf('#')+1).split('=',2);
$(this).parents('form').append('<input type="hidden" name="' + data[0] + '" value="' + data[1] + '"/>');
}
$(this).parents('form').submit();
return false;
});
$('#update_recent_tables').ready(function() {
if (window.parent.frame_navigation != undefined

View File

@ -55,6 +55,7 @@ function getFieldName($this_field) {
function appendInlineAnchor() {
// TODO: remove two lines below if vertical display mode has been completely removed
var disp_mode = $("#top_direction_dropdown").val();
if (disp_mode != 'vertical') {
$('.edit_row_anchor').each(function() {
@ -65,8 +66,9 @@ function appendInlineAnchor() {
var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
if ($img_object.length != 0) {
var img_class = $img_object.attr('class').replace(/b_edit/,'b_inline_edit');
$img_object.attr('class', img_class);
$img_object.removeClass('ic_b_edit');
$img_object.addClass('ic_b_inline_edit');
$cloned_anchor.find('a').attr('href', '#');
var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
var $span = $cloned_anchor.find('a').find('span');
@ -85,8 +87,8 @@ function appendInlineAnchor() {
// the link was too big so <input type="image"> is there
$img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
if ($img_object.length > 0) {
var img_class = $img_object.attr('class').replace(/b_edit/,'b_inline_edit');
$img_object.attr('class', img_class);
$img_object.removeClass('ic_b_edit');
$img_object.addClass('ic_b_inline_edit');
}
$cloned_anchor
.find('.clickprevimage')
@ -444,8 +446,8 @@ $(document).ready(function() {
// If icons are displayed. See $cfg['PropertiesIconic']
if ($img_object.length > 0) {
$img_object.attr('title', PMA_messages['strSave']);
var img_class = $img_object.attr('class').replace(/b_inline_edit/,'b_save');
$img_object.attr('class', img_class);
$img_object.removeClass('ic_b_inline_edit');
$img_object.addClass('ic_b_save');
$this_children.prepend($img_object);
}
@ -464,8 +466,8 @@ $(document).ready(function() {
// If icons are displayed. See $cfg['PropertiesIconic']
if ($img_object.length > 0) {
$img_object.attr('title', PMA_messages['strHide']);
var img_class = $img_object.attr('class').replace(/b_save/,'b_close');
$img_object.attr('class', img_class);
$img_object.removeClass('ic_b_save');
$img_object.addClass('ic_b_close');
$hide_span.prepend($img_object);
}

View File

@ -66,9 +66,10 @@ function PMA_pow($base, $exp, $use_function = false)
* @param string $alternate alternate text
* @param boolean $container include in container
* @param boolean $force_text whether to force alternate text to be displayed
* @param boolean $noSprite If true, the image source will be not replaced with a CSS Sprite
* @return html img tag
*/
function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = false)
function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = false, $noSprite = false)
{
$include_icon = false;
$include_text = false;
@ -80,14 +81,12 @@ function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = f
$include_icon = true;
}
if ($force_text
|| ! (true === $GLOBALS['cfg']['PropertiesIconic'])
|| ! $include_icon) {
if ($force_text || true !== $GLOBALS['cfg']['PropertiesIconic']) {
// $cfg['PropertiesIconic'] is false or both
// OR we have no $include_icon
$include_text = true;
}
if ($include_text && $include_icon && $container) {
// we have icon, text and request for container
$include_box = true;
@ -97,9 +96,14 @@ function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = f
$button .= '<span class="nowrap">';
if ($include_icon) {
$button .= '<img src="themes/dot.gif"'
. ' title="' . $alternate . '" alt="' . $alternate . '"'
. ' class="icon ic_' . str_replace('.png','',$icon) . '" />';
if($noSprite) {
$button .= '<img src="' . $GLOBALS['pmaThemeImage'] . $icon . '"'
. ' class="icon" width="16" height="16" />';
} else {
$button .= '<img src="themes/dot.gif"'
. ' title="' . $alternate . '" alt="' . $alternate . '"'
. ' class="icon ic_' . str_replace(array('.gif','.png'),array('',''),$icon) . '" />';
}
}
if ($include_icon && $include_text) {
@ -1648,6 +1652,7 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
return '';
}
if (! is_array($tag_params)) {
$tmp = $tag_params;
$tag_params = array();
@ -1669,11 +1674,17 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
$tag_params_strings[] = $par_name . '="' . $par_value . '"';
}
$displayed_message = '';
// Add text if not already added
if (stristr($message, '<img') && (!$strip_img || $GLOBALS['cfg']['PropertiesIconic'] === true) && strip_tags($message)==$message) {
$displayed_message = '<span>' . htmlspecialchars(preg_replace('/^.*\salt="([^"]*)".*$/si', '\1', $message)) . '</span>';
}
if ($url_length <= $GLOBALS['cfg']['LinkLengthLimit']) {
// no whitespace within an <a> else Safari will make it part of the link
$ret = "\n" . '<a href="' . $url . '" '
. implode(' ', $tag_params_strings) . '>'
. $message . '</a>' . "\n";
. $message . $displayed_message . '</a>' . "\n";
} else {
// no spaces (linebreaks) at all
// or after the hidden fields
@ -1702,7 +1713,7 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
. ' method="post"' . $target . ' style="display: inline;">';
$subname_open = '';
$subname_close = '';
$submit_name = '';
$submit_link = '#';
} else {
$query_parts[] = 'redirect=' . $url_parts['path'];
if (empty($GLOBALS['subform_counter'])) {
@ -1712,7 +1723,7 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
$ret = '';
$subname_open = 'subform[' . $GLOBALS['subform_counter'] . '][';
$subname_close = ']';
$submit_name = ' name="usesubform[' . $GLOBALS['subform_counter'] . ']"';
$submit_link = '#usesubform[' . $GLOBALS['subform_counter'] . ']=1';
}
foreach ($query_parts as $query_pair) {
list($eachvar, $eachval) = explode('=', $query_pair);
@ -1721,35 +1732,10 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
. htmlspecialchars(urldecode($eachval)) . '" />';
} // end while
if (stristr($message, '<img')) {
if ($strip_img) {
$message = trim(strip_tags($message));
$ret .= '<input type="submit"' . $submit_name . ' '
. implode(' ', $tag_params_strings)
. ' value="' . htmlspecialchars($message) . '" />';
} else {
$displayed_message = htmlspecialchars(
preg_replace('/^.*\salt="([^"]*)".*$/si', '\1',
$message));
$ret .= '<input type="image"' . $submit_name . ' '
. implode(' ', $tag_params_strings)
. ' src="' . preg_replace(
'/^.*\ssrc="([^"]*)".*$/si', '\1', $message) . '"'
. ' value="' . $displayed_message . '" title="' . $displayed_message . '" />';
// Here we cannot obey PropertiesIconic completely as a
// generated link would have a length over LinkLengthLimit
// but we can at least show the message.
// If PropertiesIconic is false or 'both'
if ($GLOBALS['cfg']['PropertiesIconic'] !== true) {
$ret .= ' <span class="clickprevimage">' . $displayed_message . '</span>';
}
}
} else {
$message = trim(strip_tags($message));
$ret .= '<input type="submit"' . $submit_name . ' '
. implode(' ', $tag_params_strings)
. ' value="' . htmlspecialchars($message) . '" />';
}
$ret .= "\n" . '<a href="' . $submit_link . '" class="formLinkSubmit" '
. implode(' ', $tag_params_strings) . '>'
. $message . ' ' . $displayed_message . '</a>' . "\n";
if ($new_form) {
$ret .= '</form>';
}

View File

@ -87,6 +87,8 @@ button {
.ic_b_browse { background-position: 0 -18px; }
.ic_b_sbrowse { background-position: 0 -660px; width: 10px; height: 10px; }
.ic_b_view { background-position: 0 -1044px; }
.ic_b_minus { background-position: 0 -440px; width: 9px; height: 9px; }
.ic_b_plus { background-position: 0 -523px; width: 9px; height: 9px; }
/******************************************************************************/
/* classes */

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

View File

@ -92,6 +92,10 @@ button {
.ic_s_loggoff { background-position: -1698px 0; }
.ic_b_browse, .ic_b_sbrowse { background-position: -34px 0; }
.ic_b_view { background-position: -1077px 0; }
.ic_b_plus { background-position: -573px 0; }
.ic_b_minus { background-position: -471px 0; }
.ic_b_views, .ic_s_views { background-position: -1094px 0; }
/******************************************************************************/
/* classes */

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B