diff --git a/.gitignore b/.gitignore
index a773f8e3e7..b492910cc1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,5 @@ locale
sources
# API documentation
apidoc
+# Demo server
+revision-info.php
diff --git a/ChangeLog b/ChangeLog
index 3935ec69ca..66bc93bc81 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,9 @@
+ Patch #3256122 [search] Show/hide db search results
+ Patch #3302354 Add gettext wrappers around a message
+ Remove deprecated function PMA_DBI_get_fields
++ rfe #2098927 Remember recent tables
++ rfe #3078542 Remember the last sort order for each table
++ AJAX for Create table in navigation panel
3.4.2.0 (not yet released)
- bug #3301249 [interface] Iconic table operations does not remove inline edit label
@@ -19,6 +22,8 @@
- [auth] Fixed error handling for signon auth method.
- bug #3276001 [core] Avoid caching of index.php.
- bug #3306958 [interface] Unnecessary Details slider
+- bug #3308476 [interface] "Show all" not persistent after a sort
+- bug #3308072 [auth] Version disclosure to anonymous visitors
3.4.1.0 (2011-05-20)
- bug #3301108 [interface] Synchronize and already configured host
diff --git a/Documentation.html b/Documentation.html
index 3bbb832dd4..2ff0881ba0 100644
--- a/Documentation.html
+++ b/Documentation.html
@@ -1077,6 +1077,25 @@ ALTER TABLE `pma_column_comments`
+
+ $cfg['Servers'][$i]['table_uiprefs'] string
+
+
+ Since release 3.5.0 phpMyAdmin can be configured to remember several things
+ (table sorting
+ $cfg['RememberSorting']
+ , etc.) for browsing tables.
+ Without configuring the storage, these features still can be used,
+ but the values will disappear after you logout.
+
+ To allow the usage of these functionality persistently:
+
+
+ - set up pmadb and the phpMyAdmin configuration storage
+ - put the table name in $cfg['Servers'][$i]['table_uiprefs'] (e.g. 'pma_table_uiprefs')
+
+
+
$cfg['Servers'][$i]['tracking'] string
@@ -1934,6 +1953,9 @@ $cfg['TrustedProxies'] =
each row on a vertical lineup.
+ $cfg['RememberSorting'] boolean
+ If enabled, when browsing tables, the sorting of each table is remembered.
+
The HeaderFlipType can be set to 'auto', 'css' or 'fake'. When using
diff --git a/config.sample.inc.php b/config.sample.inc.php
index 95d3a1a911..edffd03345 100644
--- a/config.sample.inc.php
+++ b/config.sample.inc.php
@@ -53,6 +53,7 @@ $cfg['Servers'][$i]['AllowNoPassword'] = false;
// $cfg['Servers'][$i]['column_info'] = 'pma_column_info';
// $cfg['Servers'][$i]['history'] = 'pma_history';
// $cfg['Servers'][$i]['recent'] = 'pma_recent';
+// $cfg['Servers'][$i]['table_uiprefs'] = 'pma_table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma_tracking';
// $cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords';
// $cfg['Servers'][$i]['userconfig'] = 'pma_userconfig';
diff --git a/db_datadict.php b/db_datadict.php
index e9d18fdf1e..9941ef4440 100644
--- a/db_datadict.php
+++ b/db_datadict.php
@@ -135,7 +135,7 @@ while ($row = PMA_DBI_fetch_assoc($rowset)) {
$analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table));
}
- // Check if we can use Relations (Mike Beck)
+ // Check if we can use Relations
if (!empty($cfgRelation['relation'])) {
// Find which tables are related with the current one and write it in
// an array
diff --git a/db_qbe.php b/db_qbe.php
index a076798741..a5bd7a7e4e 100644
--- a/db_qbe.php
+++ b/db_qbe.php
@@ -686,7 +686,6 @@ if (!empty($qry_select)) {
// 2. FROM
// Create LEFT JOINS out of Relations
-// Code originally by Mike Beck
// If we can use Relations we could make some left joins.
// First find out if relations are available in this database.
diff --git a/js/config.js b/js/config.js
index 7f55503f5f..a753034cc0 100644
--- a/js/config.js
+++ b/js/config.js
@@ -1,3 +1,4 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Functions used in configuration forms and on user preferences pages
*/
@@ -14,9 +15,9 @@ var PMA_messages = {};
* @param {Element} field
*/
function getFieldType(field) {
- field = $(field);
- var tagName = field.attr('tagName');
- if (tagName == 'INPUT') {
+ field = $(field);
+ var tagName = field.prop('tagName');
+ if (tagName == 'INPUT') {
return field.attr('type');
} else if (tagName == 'SELECT') {
return 'select';
@@ -40,7 +41,7 @@ function getFieldType(field) {
* @param {String|Boolean} [value]
*/
function setFieldValue(field, field_type, value) {
- field = $(field);
+ field = $(field);
switch (field_type) {
case 'text':
field.attr('value', (value != undefined ? value : field.attr('defaultValue')));
@@ -50,14 +51,14 @@ function setFieldValue(field, field_type, value) {
break;
case 'select':
var options = field.attr('options');
- var i, imax = options.length;
+ var i, imax = options.length;
if (value == undefined) {
for (i = 0; i < imax; i++) {
- options[i].selected = options[i].defaultSelected;
+ options[i].selected = options[i].defaultSelected;
}
} else {
for (i = 0; i < imax; i++) {
- options[i].selected = (value.indexOf(options[i].value) != -1);
+ options[i].selected = (value.indexOf(options[i].value) != -1);
}
}
break;
@@ -78,14 +79,14 @@ function setFieldValue(field, field_type, value) {
* @type Boolean|String|String[]
*/
function getFieldValue(field, field_type) {
- field = $(field);
+ field = $(field);
switch (field_type) {
case 'text':
- return field.attr('value');
+ return field.prop('value');
case 'checkbox':
- return field.attr('checked');
+ return field.prop('checked');
case 'select':
- var options = field.attr('options');
+ var options = field.prop('options');
var i, imax = options.length, items = [];
for (i = 0; i < imax; i++) {
if (options[i].selected) {
@@ -354,7 +355,7 @@ function displayErrors(error_list) {
* @param {Object} errors
*/
function validate_fieldset(fieldset, isKeyUp, errors) {
- fieldset = $(fieldset);
+ fieldset = $(fieldset);
if (fieldset.length && typeof validators._fieldset[fieldset.attr('id')] != 'undefined') {
var fieldset_errors = validators._fieldset[fieldset.attr('id')].apply(fieldset[0], [isKeyUp]);
for (var field_id in fieldset_errors) {
@@ -377,8 +378,8 @@ function validate_fieldset(fieldset, isKeyUp, errors) {
* @param {Object} errors
*/
function validate_field(field, isKeyUp, errors) {
- field = $(field);
- var field_id = field.attr('id');
+ field = $(field);
+ var field_id = field.attr('id');
errors[field_id] = [];
var functions = getFieldValidators(field_id, isKeyUp);
for (var i = 0; i < functions.length; i++) {
@@ -389,7 +390,7 @@ function validate_field(field, isKeyUp, errors) {
var result = functions[i][0].apply(field[0], args);
if (result !== true) {
if (typeof result == 'string') {
- result = [result];
+ result = [result];
}
$.merge(errors[field_id], result);
}
@@ -403,7 +404,7 @@ function validate_field(field, isKeyUp, errors) {
* @param {boolean} isKeyUp
*/
function validate_field_and_fieldset(field, isKeyUp) {
- field = $(field);
+ field = $(field);
var errors = {};
validate_field(field, isKeyUp, errors);
validate_fieldset(field.closest('fieldset'), isKeyUp, errors);
@@ -416,7 +417,7 @@ function validate_field_and_fieldset(field, isKeyUp) {
* @param {Element} field
*/
function markField(field) {
- field = $(field);
+ field = $(field);
var type = getFieldType(field);
var isDefault = checkFieldDefault(field, type);
@@ -439,7 +440,7 @@ function setRestoreDefaultBtn(field, display) {
$(function() {
// register validators and mark custom values
- var elements = $('input[id], select[id], textarea[id]');
+ var elements = $('input[id], select[id], textarea[id]');
$('input[id], select[id], textarea[id]').each(function(){
markField(this);
var el = $(this);
@@ -450,35 +451,35 @@ $(function() {
var tagName = el.attr('tagName');
// text fields can be validated after each change
if (tagName == 'INPUT' && el.attr('type') == 'text') {
- el.keyup(function() {
+ el.keyup(function() {
validate_field_and_fieldset(el, true);
markField(el);
});
}
// disable textarea spellcheck
if (tagName == 'TEXTAREA') {
- el.attr('spellcheck', false);
+ el.attr('spellcheck', false);
}
});
- // check whether we've refreshed a page and browser remembered modified
- // form values
- var check_page_refresh = $('#check_page_refresh');
- if (check_page_refresh.length == 0 || check_page_refresh.val() == '1') {
- // run all field validators
- var errors = {};
- for (var i = 0; i < elements.length; i++) {
- validate_field(elements[i], false, errors);
- }
- // run all fieldset validators
- $('fieldset').each(function(){
- validate_fieldset(this, false, errors);
- });
+ // check whether we've refreshed a page and browser remembered modified
+ // form values
+ var check_page_refresh = $('#check_page_refresh');
+ if (check_page_refresh.length == 0 || check_page_refresh.val() == '1') {
+ // run all field validators
+ var errors = {};
+ for (var i = 0; i < elements.length; i++) {
+ validate_field(elements[i], false, errors);
+ }
+ // run all fieldset validators
+ $('fieldset').each(function(){
+ validate_fieldset(this, false, errors);
+ });
- displayErrors(errors);
- } else if (check_page_refresh) {
- check_page_refresh.val('1');
- }
+ displayErrors(errors);
+ } else if (check_page_refresh) {
+ check_page_refresh.val('1');
+ }
});
//
diff --git a/js/functions.js b/js/functions.js
index 38a5cc3f75..ae36e1b777 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -1309,6 +1309,53 @@ function PMA_showNoticeForEnum(selectElement) {
}
}
+/**
+ * Generates a dialog box to pop up the create_table form
+ */
+function PMA_createTableDialog( div, url , target){
+ /**
+ * @var button_options Object that stores the options passed to jQueryUI
+ * dialog
+ */
+ var button_options = {};
+ // in the following function we need to use $(this)
+ button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
+
+ var button_options_error = {};
+ button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
+
+ var $msgbox = PMA_ajaxShowMessage();
+
+ $.get( target , url , function(data) {
+ //in the case of an error, show the error message returned.
+ if (data.success != undefined && data.success == false) {
+ div
+ .append(data.error)
+ .dialog({
+ title: PMA_messages['strCreateTable'],
+ height: 230,
+ width: 900,
+ open: PMA_verifyTypeOfAllColumns,
+ buttons : button_options_error
+ })// end dialog options
+ //remove the redundant [Back] link in the error message.
+ .find('fieldset').remove();
+ } else {
+ div
+ .append(data)
+ .dialog({
+ title: PMA_messages['strCreateTable'],
+ height: 600,
+ width: 900,
+ open: PMA_verifyTypeOfAllColumns,
+ buttons : button_options
+ }); // end dialog options
+ }
+ PMA_ajaxRemoveMessage($msgbox);
+ }) // end $.get()
+
+}
+
/**
* jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
* return a jQuery object yet and hence cannot be chained
@@ -1403,7 +1450,7 @@ jQuery.fn.PMA_sort_table = function(text_selector) {
*/
$(document).ready(function() {
- /**
+ /**
* Attach event handler to the submit action of the create table minimal form
* and retrieve the full table form and display it in a dialog
*
@@ -1412,50 +1459,15 @@ $(document).ready(function() {
$("#create_table_form_minimal.ajax").live('submit', function(event) {
event.preventDefault();
$form = $(this);
-
- /* @todo Validate this form! */
-
- /**
- * @var button_options Object that stores the options passed to jQueryUI
- * dialog
- */
- var button_options = {};
- // in the following function we need to use $(this)
- button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
-
- var button_options_error = {};
- button_options_error[PMA_messages['strOK']] = function() {$(this).dialog('close').remove();}
-
- var $msgbox = PMA_ajaxShowMessage();
PMA_prepareForAjaxRequest($form);
- $.get($form.attr('action'), $form.serialize(), function(data) {
- //in the case of an error, show the error message returned.
- if (data.success != undefined && data.success == false) {
- $('')
- .append(data.error)
- .dialog({
- title: PMA_messages['strCreateTable'],
- height: 230,
- width: 900,
- open: PMA_verifyTypeOfAllColumns,
- buttons : button_options_error
- })// end dialog options
- //remove the redundant [Back] link in the error message.
- .find('fieldset').remove();
- } else {
- $('')
- .append(data)
- .dialog({
- title: PMA_messages['strCreateTable'],
- height: 600,
- width: 900,
- open: PMA_verifyTypeOfAllColumns,
- buttons : button_options
- }); // end dialog options
- }
- PMA_ajaxRemoveMessage($msgbox);
- }) // end $.get()
+ /*variables which stores the common attributes*/
+ var url = $form.serialize();
+ var action = $form.attr('action');
+ var div = $('');
+
+ /*Calling to the createTableDialog function*/
+ PMA_createTableDialog(div, url, action);
// empty table name and number of columns from the minimal form
$form.find('input[name=table],input[name=num_fields]').val('');
@@ -2289,9 +2301,13 @@ $(document).ready(function() {
}
});
- $('#update_recent_tables').ready(function() {
+ $('#update_recent_tables').ready(function() {
+ if (window.parent.frame_navigation != undefined
+ && window.parent.frame_navigation.PMA_reloadRecentTable != undefined)
+ {
window.parent.frame_navigation.PMA_reloadRecentTable();
- });
+ }
+ });
}) // end of $(document).ready()
diff --git a/js/navigation.js b/js/navigation.js
index 52d13cfd4d..7f9a013119 100644
--- a/js/navigation.js
+++ b/js/navigation.js
@@ -202,4 +202,22 @@ $(document).ready(function(){
window.parent.refreshMain($('#LeftDefaultTabTable')[0].value);
}
});
-});
+
+ /* Create table */
+ $('#newtable a.ajax').click(function(event){
+ event.preventDefault();
+ /*Getting the url */
+ var url = $('#newtable a').attr("href");
+ if (url.substring(0, 15) == "tbl_create.php?") {
+ url = url.substring(15);
+ }
+ url = url +"&num_fields=&ajax_request=true";
+ /*Creating a div on the frame_content frame */
+ var div = parent.frame_content.$('');
+ var target = "tbl_create.php";
+
+ /*Calling to the createTableDialog function*/
+ PMA_createTableDialog(div , url , target);
+ });//end of create new table
+});//end of document get ready
+
diff --git a/libraries/Table.class.php b/libraries/Table.class.php
index d41eadc8d9..c73eb31e5a 100644
--- a/libraries/Table.class.php
+++ b/libraries/Table.class.php
@@ -11,6 +11,10 @@
*/
class PMA_Table
{
+ /**
+ * UI preferences property: sorted column
+ */
+ const PROP_SORTED_COLUMN = 'sorted_col';
static $cache = array();
@@ -39,6 +43,11 @@ class PMA_Table
*/
var $settings = array();
+ /**
+ * @var array UI preferences
+ */
+ var $uiprefs;
+
/**
* @var array errors occured
*/
@@ -1185,5 +1194,142 @@ class PMA_Table
return $return;
}
+
+ /**
+ * Return UI preferences for this table from phpMyAdmin database.
+ *
+ * @uses PMA_query_as_controluser()
+ * @uses PMA_DBI_fetch_array()
+ * @uses json_decode()
+ *
+ * @return array
+ */
+ protected function getUiPrefsFromDb()
+ {
+ $pma_table = PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) .".".
+ PMA_backquote($GLOBALS['cfg']['Server']['table_uiprefs']);
+
+ // Read from phpMyAdmin database
+ $sql_query =
+ " SELECT `prefs` FROM " . $pma_table .
+ " WHERE `username` = '" . $GLOBALS['cfg']['Server']['user'] . "'" .
+ " AND `db_name` = '" . $this->db_name . "'" .
+ " AND `table_name` = '" . $this->name . "'";
+
+ $row = PMA_DBI_fetch_array(PMA_query_as_controluser($sql_query));
+ if (isset($row[0])) {
+ return json_decode($row[0], true);
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Save this table's UI preferences into phpMyAdmin database.
+ *
+ * @uses PMA_DBI_try_query()
+ * @uses json_decode()
+ * @uses PMA_Message
+ *
+ * @return true|PMA_Message
+ */
+ protected function saveUiPrefsToDb()
+ {
+ $pma_table = PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) .".".
+ PMA_backquote($GLOBALS['cfg']['Server']['table_uiprefs']);
+
+ $username = $GLOBALS['cfg']['Server']['user'];
+ $sql_query =
+ " REPLACE INTO " . $pma_table .
+ " VALUES ('" . $username . "', '" . $this->db_name . "', '" .
+ $this->name . "', '" . PMA_sqlAddslashes(json_encode($this->uiprefs)) . "')";
+
+ $success = PMA_DBI_try_query($sql_query, $GLOBALS['controllink']);
+
+ if (!$success) {
+ $message = PMA_Message::error(__('Could not save table UI preferences'));
+ $message->addMessage('
');
+ $message->addMessage(PMA_Message::rawError(PMA_DBI_getError($GLOBALS['controllink'])));
+ return $message;
+ }
+ return true;
+ }
+
+ /**
+ * Loads the UI preferences for this table.
+ * If pmadb and table_uiprefs is set, it will load the UI preferences from
+ * phpMyAdmin database.
+ *
+ * @uses getUiPrefsFromDb()
+ */
+ protected function loadUiPrefs()
+ {
+ // set session variable if it's still undefined
+ if (! isset($_SESSION['tmp_user_values']['table_uiprefs'][$this->db_name][$this->name])) {
+ $_SESSION['tmp_user_values']['table_uiprefs'][$this->db_name][$this->name] =
+ // check whether we can get from pmadb
+ (strlen($GLOBALS['cfg']['Server']['pmadb'])
+ && strlen($GLOBALS['cfg']['Server']['table_uiprefs'])) ?
+ $this->getUiPrefsFromDb() : array();
+ }
+ $this->uiprefs =& $_SESSION['tmp_user_values']['table_uiprefs'][$this->db_name][$this->name];
+ }
+
+ /**
+ * Get UI preferences array for this table.
+ * If pmadb and table_uiprefs is set, it will get the UI preferences from
+ * phpMyAdmin database.
+ *
+ * @return array
+ */
+ public function getUiPrefs()
+ {
+ if (! isset($this->uiprefs)) {
+ $this->loadUiPrefs();
+ }
+ return $this->uiprefs;
+ }
+
+ /**
+ * Get a property from UI preferences.
+ * Return false if the property is not found.
+ * Available property:
+ * - PROP_SORTED_COLUMN
+ *
+ * @uses loadUiPrefs()
+ *
+ * @param string $property
+ * @return mixed
+ */
+ public function getUiProp($property)
+ {
+ if (! isset($this->uiprefs)) {
+ $this->loadUiPrefs();
+ }
+ return isset($this->uiprefs[$property]) ? $this->uiprefs[$property] : false;
+ }
+
+ /**
+ * Set a property from UI preferences.
+ * If pmadb and table_uiprefs is set, it will save the UI preferences to
+ * phpMyAdmin database.
+ *
+ * @param string $property
+ * @param mixed $value
+ * @return true|PMA_Message
+ */
+ public function setUiProp($property, $value)
+ {
+ if (! isset($this->uiprefs)) {
+ $this->loadUiPrefs();
+ }
+ $this->uiprefs[$property] = $value;
+ // check if pmadb is set
+ if (strlen($GLOBALS['cfg']['Server']['pmadb'])
+ && strlen($GLOBALS['cfg']['Server']['table_uiprefs'])) {
+ return $this->saveUiprefsToDb();
+ }
+ return true;
+ }
}
?>
diff --git a/libraries/auth/cookie.auth.lib.php b/libraries/auth/cookie.auth.lib.php
index 84bfa80ad9..c04d5a2b65 100644
--- a/libraries/auth/cookie.auth.lib.php
+++ b/libraries/auth/cookie.auth.lib.php
@@ -169,6 +169,7 @@ function PMA_auth()
/* HTML header; do not show here the PMA version to improve security */
$page_title = 'phpMyAdmin ';
require './libraries/header_meta_style.inc.php';
+ // if $page_title is set, this script uses it as the title:
require './libraries/header_scripts.inc.php';
?>
+
+