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: + + +
+
$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.
+
$cfg['HeaderFlipType'] string
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'; ?> + +