diff --git a/config.sample.inc.php b/config.sample.inc.php index 2b3024d12d..0e57bc50d2 100644 --- a/config.sample.inc.php +++ b/config.sample.inc.php @@ -57,6 +57,7 @@ $cfg['Servers'][$i]['AllowNoPassword'] = false; // $cfg['Servers'][$i]['designer_coords'] = 'pma__designer_coords'; // $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig'; // $cfg['Servers'][$i]['recent'] = 'pma__recent'; +// $cfg['Servers'][$i]['favorite'] = 'pma__favorite'; // $cfg['Servers'][$i]['users'] = 'pma__users'; // $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups'; // $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding'; diff --git a/db_structure.php b/db_structure.php index e848ad641e..63e36fc9c0 100644 --- a/db_structure.php +++ b/db_structure.php @@ -41,6 +41,7 @@ if ((!empty($_POST['submit_mult']) && isset($_POST['selected_tbl'])) $_POST['message'] = PMA_Message::success(); } } + require 'libraries/db_common.inc.php'; $url_query .= '&goto=db_structure.php'; @@ -132,12 +133,14 @@ $overhead_size = (double) 0; $hidden_fields = array(); $odd_row = true; $sum_row_count_pre = ''; - +// Instance of PMA_FavoriteTable class. +$fav_instance = PMA_FavoriteTable::getInstance(); foreach ($tables as $keyname => $current_table) { // Get valid statistics whatever is the table type $drop_query = ''; $drop_message = ''; + $already_favorite = false; $overhead = ''; $table_is_view = false; @@ -251,6 +254,24 @@ foreach ($tables as $keyname => $current_table) { list($do, $ignored) = PMA_getServerSlaveStatus( $server_slave_status, $truename ); + // Handle favorite table list. ----START---- + $already_favorite = PMA_checkFavoriteTable($db, $current_table['TABLE_NAME']); + + if (isset($_REQUEST['remove_favorite'])) { + if ($already_favorite) { + // If already in favorite list, remove it. + $favorite_table = $_REQUEST['favorite_table']; + $fav_instance->remove($db, $favorite_table); + } + } + + if (isset($_REQUEST['add_favorite'])) { + if (!$already_favorite) { + // Otherwise add to favorite list. + $favorite_table = $_REQUEST['favorite_table']; + $fav_instance->add($db, $favorite_table); + } + } // Handle favorite table list. ----ENDS---- list($html_output, $odd_row) = PMA_getHtmlForStructureTableRow( $i, $odd_row, $table_is_view, $current_table, diff --git a/examples/create_tables.sql b/examples/create_tables.sql index 8ffbf5ef84..953a4b6bbc 100644 --- a/examples/create_tables.sql +++ b/examples/create_tables.sql @@ -119,6 +119,20 @@ CREATE TABLE IF NOT EXISTS `pma__recent` ( -- -------------------------------------------------------- +-- +-- Table structure for table `pma__favorite` +-- + +CREATE TABLE IF NOT EXISTS `pma__favorite` ( + `username` varchar(64) NOT NULL, + `tables` text NOT NULL, + PRIMARY KEY (`username`) +) + COMMENT='Favorite tables' + DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; + +-- -------------------------------------------------------- + -- -- Table structure for table `pma__table_uiprefs` -- diff --git a/js/db_structure.js b/js/db_structure.js index 63d6f43ee6..25161811fb 100644 --- a/js/db_structure.js +++ b/js/db_structure.js @@ -382,4 +382,18 @@ AJAX.registerOnload('db_structure.js', function () { return false; }); //end Calculate Real End for InnoDB + PMA_tooltip( + $("select[name*='funcs']"), + 'select', + PMA_messages.strFunctionHint + ); + // Add tooltip to favorite icons. + $(".favorite_table_anchor").each(function () { + PMA_tooltip( + $(this), + 'a', + $(this).attr("title") + ); + }); + }); // end $() diff --git a/js/navigation.js b/js/navigation.js index 07f2874add..5d7d99fd01 100644 --- a/js/navigation.js +++ b/js/navigation.js @@ -107,6 +107,20 @@ $(function () { } }); + /** + * Jump to favorite table + */ + $('#favoriteTable').live('change', function () { + if (this.value !== '') { + var arr = jQuery.parseJSON(this.value); + var $form = $(this).closest('form'); + $form.find('input[name=db]').val(arr.db); + $form.find('input[name=table]').val(arr.table); + $form.submit(); + $(this).prop('selectedIndex', 0); + } + }); + /** Create a Routine, Trigger or Event */ $('li.new_procedure a.ajax, li.new_function a.ajax').live('click', function (event) { event.preventDefault(); diff --git a/libraries/FavoriteTable.class.php b/libraries/FavoriteTable.class.php new file mode 100644 index 0000000000..4e445e8240 --- /dev/null +++ b/libraries/FavoriteTable.class.php @@ -0,0 +1,271 @@ +_pmaTable + = PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . "." + . PMA_Util::backquote($GLOBALS['cfg']['Server']['favorite']); + } + $server_id = $GLOBALS['server']; + if (! isset($_SESSION['tmpval']['favorite_tables'][$server_id])) { + $_SESSION['tmpval']['favorite_tables'][$server_id] + = isset($this->_pmaTable) ? $this->getFromDb() : array(); + } + $this->tables =& $_SESSION['tmpval']['favorite_tables'][$server_id]; + } + + /** + * Returns class instance. + * + * @return PMA_FavoriteTable + */ + public static function getInstance() + { + if (is_null(self::$_instance)) { + self::$_instance = new PMA_FavoriteTable(); + } + return self::$_instance; + } + + /** + * Returns favorite tables from phpMyAdmin database. + * + * @return array + */ + public function getFromDb() + { + // Read from phpMyAdmin database, if favorite tables are not in session + $sql_query + = " SELECT `tables` FROM " . $this->_pmaTable . + " WHERE `username` = '" . $GLOBALS['cfg']['Server']['user'] . "'"; + + $return = array(); + $result = PMA_queryAsControlUser($sql_query, false); + if ($result) { + $row = $GLOBALS['dbi']->fetchArray($result); + if (isset($row[0])) { + $return = json_decode($row[0], true); + } + } + return $return; + } + + /** + * Save favorite tables into phpMyAdmin database. + * + * @return true|PMA_Message + */ + public function saveToDb() + { + $username = $GLOBALS['cfg']['Server']['user']; + $sql_query + = " REPLACE INTO " . $this->_pmaTable . " (`username`, `tables`)" . + " VALUES ('" . $username . "', '" + . PMA_Util::sqlAddSlashes( + json_encode($this->tables) + ) . "')"; + + $success = $GLOBALS['dbi']->tryQuery($sql_query, $GLOBALS['controllink']); + + if (! $success) { + $message = PMA_Message::error(__('Could not save favorite table!')); + $message->addMessage('

'); + $message->addMessage( + PMA_Message::rawError( + $GLOBALS['dbi']->getError($GLOBALS['controllink']) + ) + ); + return $message; + } + return true; + } + + /** + * Remove favorite tables from phpMyAdmin database. + * + * @return true|PMA_Message + */ + public function removeFromDb() + { + $username = $GLOBALS['cfg']['Server']['user']; + $sql_query + = " REPLACE INTO " . $this->_pmaTable . " (`username`, `tables`)" . + " VALUES ('" . $username . "', '" + . PMA_Util::sqlAddSlashes( + json_encode($this->tables) + ) . "')"; + + $success = $GLOBALS['dbi']->tryQuery($sql_query, $GLOBALS['controllink']); + + if (! $success) { + $message = PMA_Message::error(__('Could not remove favorite table!')); + $message->addMessage('

'); + $message->addMessage( + PMA_Message::rawError( + $GLOBALS['dbi']->getError($GLOBALS['controllink']) + ) + ); + return $message; + } + return true; + } + + /** + * Trim favorite table according to the NumFavoriteTables configuration. + * + * @return boolean True if trimming occurred + */ + public function trim() + { + $max = max($GLOBALS['cfg']['NumFavoriteTables'], 0); + $trimming_occurred = count($this->tables) > $max; + while (count($this->tables) > $max) { + array_pop($this->tables); + } + return $trimming_occurred; + } + + /** + * Return options for HTML select. + * + * @return string + */ + public function getHtmlSelectOption() + { + // trim and save, in case where the configuration is changed + if ($this->trim() && isset($this->_pmaTable)) { + $this->saveToDb(); + } + + $html = ''; + if (count($this->tables)) { + foreach ($this->tables as $table) { + $html .= ''; + } + } else { + $html .= ''; + } + return $html; + } + + /** + * Return HTML select. + * + * @return string + */ + public function getHtmlSelect() + { + $html = ''; + + return $html; + } + + /** + * Add favorite tables. + * + * @param string $db database name where the table is located + * @param string $table table name + * + * @return true|PMA_Message True if success, PMA_Message if not + */ + public function add($db, $table) + { + $table_arr = array(); + $table_arr['db'] = $db; + $table_arr['table'] = $table; + + // add only if this is new table + if (! isset($this->tables[0]) || $this->tables[0] != $table_arr) { + array_unshift($this->tables, $table_arr); + $this->tables = array_merge(array_unique($this->tables, SORT_REGULAR)); + $this->trim(); + if (isset($this->_pmaTable)) { + return $this->saveToDb(); + } + } + return true; + } + + /** + * Remove favorite tables. + * + * @param string $db database name where the table is located + * @param string $table table name + * + * @return true|PMA_Message True if success, PMA_Message if not + */ + public function remove($db, $table) + { + $table_arr = array(); + $table_arr['db'] = $db; + $table_arr['table'] = $table; + foreach ($this->tables as $key => $value) { + if ($value['db'] == $db && $value['table'] == $table) { + unset($this->tables[$key]); + } + } + if (isset($this->_pmaTable)) { + return $this->removeFromDb(); + } + return true; + } +} +?> diff --git a/libraries/Header.class.php b/libraries/Header.class.php index 798cfadbd5..14ae45dc24 100644 --- a/libraries/Header.class.php +++ b/libraries/Header.class.php @@ -11,6 +11,7 @@ if (! defined('PHPMYADMIN')) { require_once 'libraries/Scripts.class.php'; require_once 'libraries/RecentTable.class.php'; +require_once 'libraries/FavoriteTable.class.php'; require_once 'libraries/Menu.class.php'; require_once 'libraries/navigation/Navigation.class.php'; require_once 'libraries/url_generating.lib.php'; diff --git a/libraries/Util.class.php b/libraries/Util.class.php index 59f2d20530..e98930825b 100644 --- a/libraries/Util.class.php +++ b/libraries/Util.class.php @@ -3418,6 +3418,8 @@ class PMA_Util $titles['NoExport'] = self::getIcon('bd_export.png', __('Export')); $titles['Execute'] = self::getIcon('b_nextpage.png', __('Execute')); $titles['NoExecute'] = self::getIcon('bd_nextpage.png', __('Execute')); + $titles['Favorite'] = self::getIcon('b_favorite.png', __('')); + $titles['NoFavorite']= self::getIcon('b_no_favorite.png', __('')); return $titles; } diff --git a/libraries/config.default.php b/libraries/config.default.php index 68ee0fd0e8..b5d1a815f0 100644 --- a/libraries/config.default.php +++ b/libraries/config.default.php @@ -413,6 +413,13 @@ $cfg['Servers'][$i]['designer_coords'] = ''; */ $cfg['Servers'][$i]['recent'] = ''; +/** + * table to store favorite tables + * - leave blank for no favorite tables + * SUGGESTED: 'pma__favorite' + */ +$cfg['Servers'][$i]['favorite'] = ''; + /** * table to store UI preferences for tables * - leave blank for no "persistent" UI preferences @@ -906,6 +913,13 @@ $cfg['NavigationLogoLinkWindow'] = 'main'; */ $cfg['NumRecentTables'] = 10; +/** + * number of favorite tables displayed in the navigation panel + * + * @global integer $cfg['NumFavoriteTables'] + */ +$cfg['NumFavoriteTables'] = 10; + /** * display a JavaScript table filter in the navigation panel * when more then x tables are present diff --git a/libraries/config.values.php b/libraries/config.values.php index 33285614b9..d5b63ad45e 100644 --- a/libraries/config.values.php +++ b/libraries/config.values.php @@ -221,6 +221,7 @@ $cfg_db['_validators'] = array( 'Import/skip_queries' => 'validateNonNegativeNumber', 'InsertRows' => 'validatePositiveNumber', 'NumRecentTables' => 'validateNonNegativeNumber', + 'NumFavoriteTables' => 'validateNonNegativeNumber', 'LimitChars' => 'validatePositiveNumber', 'LoginCookieValidity' => 'validatePositiveNumber', 'LoginCookieStore' => 'validateNonNegativeNumber', diff --git a/libraries/config/messages.inc.php b/libraries/config/messages.inc.php index bcfafdf4f5..f0032047c3 100644 --- a/libraries/config/messages.inc.php +++ b/libraries/config/messages.inc.php @@ -471,6 +471,8 @@ $strConfigNavigationTreeDisableDatabaseExpansion_name = __('Disable database expansion'); $strConfigNumRecentTables_desc = __('Maximum number of recently used tables; set 0 to disable.'); +$strConfigNumFavoriteTables_desc + = __('Maximum number of favorite tables; set 0 to disable.'); $strConfigNumRecentTables_name = __('Recently used tables'); $strConfigRowActionLinks_desc = __('These are Edit, Copy and Delete links.'); $strConfigRowActionLinks_name = __('Where to show the table row links'); diff --git a/libraries/config/setup.forms.php b/libraries/config/setup.forms.php index 9ba96c752b..d87b63a7d2 100644 --- a/libraries/config/setup.forms.php +++ b/libraries/config/setup.forms.php @@ -131,6 +131,7 @@ $forms['Features']['Other_core_settings'] = array( 'MaxDbList', 'MaxTableList', 'NumRecentTables', + 'NumFavoriteTables', 'ShowHint', 'OBGzip', 'PersistentConnections', diff --git a/libraries/config/user_preferences.forms.php b/libraries/config/user_preferences.forms.php index 6c0e77ece8..98313de90a 100644 --- a/libraries/config/user_preferences.forms.php +++ b/libraries/config/user_preferences.forms.php @@ -33,6 +33,7 @@ $forms['Features']['General'] = array( 'MaxDbList', 'MaxTableList', 'NumRecentTables', + 'NumFavoriteTables', 'ShowHint', 'SendErrorReports'); $forms['Features']['Text_fields'] = array( diff --git a/libraries/navigation/NavigationHeader.class.php b/libraries/navigation/NavigationHeader.class.php index 41d34ed2ca..7577209b60 100644 --- a/libraries/navigation/NavigationHeader.class.php +++ b/libraries/navigation/NavigationHeader.class.php @@ -303,11 +303,27 @@ class PMA_NavigationHeader ) ); $retval .= PMA_RecentTable::getInstance()->getHtmlSelect(); + $retval .= $this->_favorite(); $retval .= ''; $retval .= ''; $retval .= ''; } return $retval; } + + /** + * Displays a drop-down choice of favorite tables + * + * @return string HTML code for the Favorite tables + */ + private function _favorite() + { + $retval = ''; + // display favorite tables + if ($GLOBALS['cfg']['NumFavoriteTables'] > 0) { + $retval .= PMA_FavoriteTable::getInstance()->getHtmlSelect(); + } + return $retval; + } } ?> diff --git a/libraries/structure.lib.php b/libraries/structure.lib.php index 981e480d3e..69909f56d5 100644 --- a/libraries/structure.lib.php +++ b/libraries/structure.lib.php @@ -181,7 +181,7 @@ function PMA_getHtmlBodyForTableSummary($num_tables, $server_slave_status, if ($server_slave_status) { $html_output .= '' . __('Replication') . '' . "\n"; } - $html_output .= '' + $html_output .= '' . __('Sum') . ''; $html_output .= '' @@ -451,6 +451,7 @@ function PMA_getHtmlForStructureTableRow( $collation, $formatted_size, $unit, $overhead, $create_time, $update_time, $check_time,$is_show_stats, $ignored, $do, $colspan_for_structure ) { + global $db; $html_output = ''; + $html_output .= '' + . (!$already_favorite ? $titles['NoFavorite'] : $titles['Favorite']) . ''; $html_output .= '' . $browse_table . ''; $html_output .= '' @@ -747,7 +765,7 @@ function PMA_tableHeader($db_is_system_schema = false, $replication = false) if ($db_is_system_schema) { $action_colspan = 3; } else { - $action_colspan = 6; + $action_colspan = 7; } $html_output = '' . "\n" @@ -2675,4 +2693,22 @@ function PMA_displayTableBrowseForSelectedColumns($db, $table, $goto, null, $sql_query, null, null ); } + +/** + * Function to check if a table is already in favorite list. + * + * @param string $db current database + * @param string $table current table + * + * @return true|false + */ +function PMA_checkFavoriteTable($db, $current_table) +{ + foreach ($_SESSION['tmpval']['favorite_tables'][$GLOBALS['server']] as $key => $value) { + if ($value['db'] == $db && $value['table'] == $current_table) { + return true; + } + } + return false; +} ?> diff --git a/test/libraries/common/PMA_buildActionTitles_test.php b/test/libraries/common/PMA_buildActionTitles_test.php index 7c2c82291d..caacb4a37d 100644 --- a/test/libraries/common/PMA_buildActionTitles_test.php +++ b/test/libraries/common/PMA_buildActionTitles_test.php @@ -59,6 +59,8 @@ class PMA_BuildActionTitles_Test extends PHPUnit_Framework_TestCase $titles['NoExport'] = PMA_Util::getIcon('bd_export.png', __('Export')); $titles['Execute'] = PMA_Util::getIcon('b_nextpage.png', __('Execute')); $titles['NoExecute'] = PMA_Util::getIcon('bd_nextpage.png', __('Execute')); + $titles['Favorite'] = PMA_Util::getIcon('b_favorite.png', __('')); + $titles['NoFavorite'] = PMA_Util::getIcon('b_no_favorite.png', __('')); $this->assertEquals($titles, PMA_Util::buildActionTitles()); diff --git a/themes/original/css/navigation.css.php b/themes/original/css/navigation.css.php index f9fbc3e0f5..4a69562b15 100644 --- a/themes/original/css/navigation.css.php +++ b/themes/original/css/navigation.css.php @@ -70,15 +70,22 @@ if (! defined('PMA_MINIMUM_COMMON') && ! defined('TESTSUITE')) { padding: .3em; } -#pma_navigation div#recentTableList { +#pma_navigation div#recentTableList, +#pma_navigation div#FavoriteTableList { text-align: center; margin-bottom: 0.5em; } +#pma_navigation #recentTable, +#pma_navigation #FavoriteTable { + width: 200px; +} + #pma_navigation #pmalogo, #pma_navigation #serverChoice, #pma_navigation #navipanellinks, #pma_navigation #recentTableList, +#pma_navigation #FavoriteTableList, #pma_navigation #databaseList, #pma_navigation div.pageselector.dbselector { text-align: center; @@ -88,12 +95,14 @@ if (! defined('PMA_MINIMUM_COMMON') && ! defined('TESTSUITE')) { } #pma_navigation #recentTableList select, +#pma_navigation #FavoriteTableList select, #pma_navigation #serverChoice select { width: 80%; } -#pma_navigation #recentTableList { +#pma_navigation #recentTableList, +#pma_navigation #FavoriteTableList { margin-bottom: 0; padding-bottom: 0; } diff --git a/themes/pmahomme/css/navigation.css.php b/themes/pmahomme/css/navigation.css.php index 4326f81a7e..8895cdc162 100644 --- a/themes/pmahomme/css/navigation.css.php +++ b/themes/pmahomme/css/navigation.css.php @@ -70,6 +70,7 @@ if (! defined('PMA_MINIMUM_COMMON') && ! defined('TESTSUITE')) { #pma_navigation #serverChoice, #pma_navigation #navipanellinks, #pma_navigation #recentTableList, +#pma_navigation #favoriteTableList, #pma_navigation #databaseList, #pma_navigation div.pageselector.dbselector { text-align: center; @@ -77,7 +78,12 @@ if (! defined('PMA_MINIMUM_COMMON') && ! defined('TESTSUITE')) { border: 0; } -#pma_navigation #recentTableList select, +#pma_navigation #recentTable, +#pma_navigation #favoriteTable { + width: 200px; +} + +#pma_navigation #favoriteTableList select, #pma_navigation #serverChoice select { width: 80%; diff --git a/themes/pmahomme/img/b_favorite.png b/themes/pmahomme/img/b_favorite.png new file mode 100644 index 0000000000..90a4013c32 Binary files /dev/null and b/themes/pmahomme/img/b_favorite.png differ diff --git a/themes/pmahomme/img/b_no_favorite.png b/themes/pmahomme/img/b_no_favorite.png new file mode 100644 index 0000000000..92ab1647ec Binary files /dev/null and b/themes/pmahomme/img/b_no_favorite.png differ