diff options
author | chriskl | 2005-05-02 15:47:23 +0000 |
---|---|---|
committer | chriskl | 2005-05-02 15:47:23 +0000 |
commit | 23b05fc8823bbab2f79480968c2783266df3d971 (patch) | |
tree | d5aeb31dff8a4622a01e0f6855984ebb8addf28b | |
parent | 08a01fa1ac80ed21f0cdae5db2d562e414db4509 (diff) |
Merge DEV_TREE into HEAD. May as well get this ball rolling.
67 files changed, 4385 insertions, 1032 deletions
@@ -57,4 +57,4 @@ Contributors Third Party Libraries - Highlight.php (Jacob D. Cohen of rafb.net) - +- XLoadTree2 (Erik Arvidsson & Emil A Eklund of webfx.eae.net) @@ -15,6 +15,11 @@ Features * primary key and unique key at table creation (Andreas Huber) * Add row|statement level options to create trigger for >= 7.4 (Robert Treat) * Allow altering name (for >= 7.4) and owner (for >= 8.0) of a database (Bryan Encina) +* Allow login to several servers simultaneously +* Rearrange frame layout to suit multi-server support +* New browser tree with dynamically loading branches + (Using XLoadTree from http://webfx.eae.net/) +* Allow language change on the fly Bugs * Tree Icons are displayed middle instead of top diff --git a/TRANSLATORS b/TRANSLATORS index ba0aad6f..f4bffe6b 100644 --- a/TRANSLATORS +++ b/TRANSLATORS @@ -54,11 +54,11 @@ find the rest of these steps too difficult. language's characters as well as the characters of the language in your database. -8. To add your language to phpPgAdmin's login screen, edit the - libraries/lib.inc.php file and add your language to the $appLangFiles array. +8. To add your language to phpPgAdmin, edit the lang/translations.php file + and add your language to the $appLangFiles array. You must include the HTML encoded version of your language's name. You can - get this from the recoded version of your translated strings file. Also, - edit the login.php and add your language to the list of languages for + get this from the recoded version of your translated strings file. + Also, add your language to the $availableLanguages array for browser auto detection. 9. Send your contribution to us. We need the lib.inc.php entry as well as the diff --git a/aggregates.php b/aggregates.php index e7ab25a1..81a6d21e 100644 --- a/aggregates.php +++ b/aggregates.php @@ -3,7 +3,7 @@ /** * Manage aggregates in a database * - * $Id: aggregates.php,v 1.10 2004/09/20 14:41:38 jollytoad Exp $ + * $Id: aggregates.php,v 1.11 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -46,6 +46,28 @@ $misc->printTable($aggregates, $columns, $actions, $lang['strnoaggregates']); } + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $aggregates = &$data->getAggregates(); + + $proto = concat(field('proname'), ' (', field('proargtypes'), ')'); + + $attrs = array( + 'text' => $proto, + 'icon' => 'functions', + 'toolTip'=> field('aggcomment'), + ); + + $misc->printTreeXML($aggregates, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['straggregates']); $misc->printBody(); @@ -3,7 +3,7 @@ /** * Manage databases within a server * - * $Id: all_db.php,v 1.37 2005/04/30 18:01:58 soranzo Exp $ + * $Id: all_db.php,v 1.38 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -82,8 +82,8 @@ echo "<p>", sprintf($lang['strconfdropdatabase'], $misc->printVal($_REQUEST['dropdatabase'])), "</p>\n"; echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; - echo "<input type=\"hidden\" name=\"dropdatabase\" value=\"", - htmlspecialchars($_REQUEST['dropdatabase']), "\" />\n"; + echo "<input type=\"hidden\" name=\"server\" value=\"", htmlspecialchars($_REQUEST['server']), "\" />\n"; + echo "<input type=\"hidden\" name=\"dropdatabase\" value=\"", htmlspecialchars($_REQUEST['dropdatabase']), "\" />\n"; echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n"; echo "</form>\n"; @@ -159,6 +159,7 @@ echo "</table>\n"; echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create\" />\n"; + echo $misc->form; echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n"; echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; echo "</form>\n"; @@ -229,7 +230,7 @@ echo "<br/><input type=\"radio\" name=\"output\" value=\"download\" />{$lang['strdownload']}</p>\n"; echo "<p><input type=\"hidden\" name=\"action\" value=\"export\" />\n"; - echo "<p><input type=\"hidden\" name=\"mode\" value=\"cluster\" />\n"; + echo "<p><input type=\"hidden\" name=\"subject\" value=\"server\" />\n"; echo $misc->form; echo "<input type=\"submit\" value=\"{$lang['strexport']}\" /></p>\n"; echo "</form>\n"; @@ -277,17 +278,17 @@ $actions = array( 'properties' => array( 'title' => $lang['strproperties'], - 'url' => 'redirect.php?section=database&', + 'url' => "redirect.php?subject=database&{$misc->href}&", 'vars' => array('database' => 'datname'), ), 'drop' => array( 'title' => $lang['strdrop'], - 'url' => "{$PHP_SELF}?action=confirm_drop&subject=database&", + 'url' => "{$PHP_SELF}?action=confirm_drop&subject=database&{$misc->href}&", 'vars' => array('dropdatabase' => 'datname'), ), 'privileges' => array( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?subject=database&", + 'url' => "privileges.php?subject=database&{$misc->href}&", 'vars' => array('database' => 'datname'), ) ); @@ -304,10 +305,40 @@ $misc->printTable($databases, $columns, $actions, $lang['strnodatabases']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create\">{$lang['strcreatedatabase']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}\">{$lang['strcreatedatabase']}</a></p>\n"; } + + function doTree() { + global $misc, $data, $lang; + + $databases = &$data->getDatabases(); + + $reqvars = $misc->getRequestVars('database'); + + $attrs = array( + 'text' => field('datname'), + 'icon' => 'database', + 'toolTip'=> field('datcomment'), + 'action' => url('redirect.php', + $reqvars, + array('database' => field('datname')) + ), + 'branch' => url('database.php', + $reqvars, + array( + 'action' => 'tree', + 'database' => field('datname') + ) + ), + ); + + $misc->printTreeXML($databases, $attrs); + exit; + } + if ($action == 'tree') doTree(); + $misc->printHeader($lang['strdatabases']); $misc->printBody(); diff --git a/bottombar.php b/bottombar.php deleted file mode 100644 index 10191c7f..00000000 --- a/bottombar.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - - /** - * Bottom bar - * - * $Id: bottombar.php,v 1.3 2003/12/17 09:11:32 chriskl Exp $ - */ - - // Include application functions (no db conn) - $_no_db_connection = true; - include_once('./libraries/lib.inc.php'); - - $misc->printHeader(); - $misc->printBody('bottombar'); - $misc->printFooter(); -?> diff --git a/browser.php b/browser.php index 6b7d1d8d..df42006f 100644 --- a/browser.php +++ b/browser.php @@ -5,316 +5,71 @@ * if you click on a database it shows a list of database objects in that * database. * - * $Id: browser.php,v 1.45 2005/03/11 04:32:10 chriskl Exp $ + * $Id: browser.php,v 1.46 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions + $_no_db_connection = true; include_once('./libraries/lib.inc.php'); - // Include tree classe - include_once('./classes/HTML_TreeMenu/TreeMenu.php'); - // Output header - $misc->printHeader('', "<script src=\"classes/HTML_TreeMenu/TreeMenu.js\" type=\"text/javascript\"></script>\n<script src=\"links.js\" type=\"text/javascript\"></script>"); + $misc->printHeader('', "<script src=\"xloadtree/xmlextras.js\" type=\"text/javascript\"></script>\n<script src=\"xloadtree/xtree2.js\" type=\"text/javascript\"></script>\n<script src=\"xloadtree/xloadtree2.js\" type=\"text/javascript\"></script>"); $misc->printBody('browser'); echo "<div dir=\"ltr\">\n"; - - // Construct expanding tree - $menu = new HTML_TreeMenu(null, array('usePersistence' => false)); - $root = new HTML_TreeNode(array( - 'text' => $misc->printVal(($conf['servers'][$_SESSION['webdbServerID']]['desc'])), - 'link' => addslashes('redirect.php?section=server&' . SID), - 'icon' => 'folder.gif', - 'expandedIcon' => 'folder-expanded.gif', - 'expanded' => true, - 'linkTarget' => 'detail')); - - // Add root node to menu - $menu->addItem($root); - - /** - * Helper function for adding nodes - * @param $schemanode Node onto which to add - */ - function addNodes(&$schemanode, $querystr) { - global $data, $misc, $lang, $conf; - - // Tables - $table_node = &new HTML_TreeNode(array( - 'text' => $lang['strtables'], - 'link' => addslashes(htmlspecialchars("tables.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/tables.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/tables.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add table folder to schema - $schemanode->addItem($table_node); - - $tables = &$data->getTables(); - while (!$tables->EOF) { - $return_url = urlencode("tblproperties.php?table=" . urlencode($tables->f['relname']) . "&{$querystr}"); - $item_node = &new HTML_TreeNode(array( - 'text' => $misc->printVal($tables->f['relname']), - 'link' => addslashes(htmlspecialchars("redirect.php?section=table&{$querystr}&table=" . urlencode($tables->f['relname']))), - 'icon' => "../../../images/themes/{$conf['theme']}/tables.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/tables.png", - 'expanded' => false, - 'linkTarget' => 'detail', - 'iconLink' => addslashes(htmlspecialchars('display.php?table=' . urlencode($tables->f['relname']) . '&subject=table&' . $querystr . "&return_url={$return_url}&return_desc=" . urlencode($lang['strback']))) - )); - // Add table folder to schema - $table_node->addItem($item_node); - - $tables->moveNext(); - } - - // Views - $view_node = &new HTML_TreeNode(array( - 'text' => $lang['strviews'], - 'link' => addslashes(htmlspecialchars("views.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/views.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/views.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add view folder to schema - $schemanode->addItem($view_node); - - $views = &$data->getViews(); - while (!$views->EOF) { - $return_url = urlencode("viewproperties.php?view=" . urlencode($views->f['relname']) . "&{$querystr}"); - $item_node = &new HTML_TreeNode(array( - 'text' => $misc->printVal($views->f['relname']), - 'link' => addslashes(htmlspecialchars("redirect.php?section=view&{$querystr}&view=" . - urlencode($views->f['relname']))), - 'icon' => "../../../images/themes/{$conf['theme']}/views.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/views.png", - 'expanded' => false, - 'linkTarget' => 'detail', - // XXX: FIX BROWSE - 'iconLink' => addslashes(htmlspecialchars('display.php?view='.urlencode($views->f['relname']).'&subject=view&'.$querystr. - "&return_url={$return_url}&return_desc=" . urlencode($lang['strback']))) - )); - // Add view folder to schema - $view_node->addItem($item_node); - - $views->moveNext(); - } - - // Sequences - $seq_node = &new HTML_TreeNode(array( - 'text' => $lang['strsequences'], - 'link' => addslashes(htmlspecialchars("sequences.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/sequences.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/sequences.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to schema - $schemanode->addItem($seq_node); - - // Functions - $func_node = &new HTML_TreeNode(array( - 'text' => $lang['strfunctions'], - 'link' => addslashes(htmlspecialchars("functions.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/functions.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/functions.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to schema - $schemanode->addItem($func_node); - - // Domains - if ($data->hasDomains()) { - $dom_node = &new HTML_TreeNode(array( - 'text' => $lang['strdomains'], - 'link' => addslashes(htmlspecialchars("domains.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/domains.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/domains.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - - // Add folder to schema - $schemanode->addItem($dom_node); - } - - // Advanced - if ($conf['show_advanced']) { - $adv_node = &new HTML_TreeNode(array( - 'text' => $lang['stradvanced'], -# 'link' => ($data->hasSchemas()) ? addslashes(htmlspecialchars("schema.php?{$querystr}&" . SID)) : null, - 'icon' => 'folder.gif', - 'expandedIcon' => 'folder-expanded.gif', - 'linkTarget' => 'detail')); - // Add folder to schema - $schemanode->addItem($adv_node); - - // Aggregates - $agg_node = &new HTML_TreeNode(array( - 'text' => $lang['straggregates'], - 'link' => addslashes(htmlspecialchars("aggregates.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to schema - $adv_node->addItem($agg_node); - - // Types - $type_node = &new HTML_TreeNode(array( - 'text' => $lang['strtypes'], - 'link' => addslashes(htmlspecialchars("types.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to schema - $adv_node->addItem($type_node); - - // Operators - $opr_node = &new HTML_TreeNode(array( - 'text' => $lang['stroperators'], - 'link' => addslashes(htmlspecialchars("operators.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/operators.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/operators.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to schema - $adv_node->addItem($opr_node); - - // Operator Classes - $opc_node = &new HTML_TreeNode(array( - 'text' => $lang['stropclasses'], - 'link' => addslashes(htmlspecialchars("opclasses.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/operators.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/operators.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to schema - $adv_node->addItem($opc_node); - - // Conversions - if ($data->hasConversions()) { - $con_node = &new HTML_TreeNode(array( - 'text' => $lang['strconversions'], - 'link' => addslashes(htmlspecialchars("conversions.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - - // Add folder to schema - $adv_node->addItem($con_node); - } - } - } - - $databases = &$data->getDatabases(isset($_REQUEST['database']) ? $_REQUEST['database'] : NULL); - while (!$databases->EOF) { - // If database is selected, show folder, otherwise show document - if (isset($_REQUEST['database']) && $_REQUEST['database'] == $databases->f['datname']) { - // Very ugly hack to work around the fact that the PEAR HTML_Tree can't have links with embedded - // apostrophes create the get string we need to append - $querystr = 'database=' . urlencode($databases->f['datname']) . '&' . SID; - $db_node = &new HTML_TreeNode(array( - 'text' => $misc->printVal($databases->f['datname']), - 'link' => addslashes(htmlspecialchars("redirect.php?section=database&{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/database.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/database.png", - 'expanded' => true, - 'linkTarget' => 'detail')); - - // If database supports schemas, add the extra level of hierarchy - if ($data->hasSchemas()) { - $schemas = &$data->getSchemas(); - while (!$schemas->EOF) { - $data->setSchema($schemas->f['nspname']); - // Construct database & schema query string - $querystr = 'database=' . urlencode($databases->f['datname']). '&schema=' . - urlencode($schemas->f['nspname']) . '&' . SID; - $schemanode = &new HTML_TreeNode(array( - 'text' => $misc->printVal($schemas->f['nspname']), - 'link' => addslashes(htmlspecialchars("redirect.php?section=schema&{$querystr}")), - 'icon' => 'folder.gif', - 'expandedIcon' => 'folder-expanded.gif', - // Auto-expand your personal schema, if it exists. Also expand schema if there is - // only one schema in the database. - 'expanded' => ($schemas->f['nspname'] == $_SESSION['webdbUsername'] - || $schemas->recordCount() == 1), - 'linkTarget' => 'detail')); - - addNodes($schemanode, $querystr); - - // Add schema to database - $db_node->addItem($schemanode); - - $schemas->moveNext(); - } - } - // Database doesn't support schemas - else { - // Construct database query string - $querystr = 'database=' . urlencode($databases->f['datname']) . '&' . SID; - - addNodes($db_node, $querystr); - } - - // Reset database query string - $querystr = 'database=' . urlencode($databases->f['datname']) . '&' . SID; - - // Languages - if ($conf['show_advanced']) { - $lang_node = &new HTML_TreeNode(array( - 'text' => $lang['strlanguages'], - 'link' => addslashes(htmlspecialchars("languages.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - // Add folder to database - $db_node->addItem($lang_node); - - // Casts - if ($data->hasCasts()) { - $cast_node = &new HTML_TreeNode(array( - 'text' => $lang['strcasts'], - 'link' => addslashes(htmlspecialchars("casts.php?{$querystr}")), - 'icon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/types.png", - 'expanded' => false, - 'linkTarget' => 'detail')); - - // Add folder to database - $db_node->addItem($cast_node); - } - } - - // Add node to menu - $root->addItem($db_node); +?> - } else { - // Very ugly hack to work around the fact that the PEAR HTML_Tree can't have links with embedded - // apostrophes create the get string we need to append - $jsLink = '?database=' . addslashes(htmlspecialchars(urlencode($databases->f['datname']) . '&' . SID)); - $jsLink = "javascript:updateLinks(' + \"'{$jsLink}'\" + ')"; - $db_node = &new HTML_TreeNode(array( - 'text' => $misc->printVal($databases->f['datname']), - 'link' => $jsLink, - 'icon' => "../../../images/themes/{$conf['theme']}/database.png", - 'expandedIcon' => "../../../images/themes/{$conf['theme']}/database.png", - 'expanded' => false, - 'linkTarget' => '_self')); - - // Add node to menu - $root->addItem($db_node); - } - - $databases->moveNext(); - } - // Create the presentation class - $treeMenu = &new HTML_TreeMenu_DHTML($menu, array('images' => 'classes/HTML_TreeMenu/images', 'defaultClass' => 'treeMenuDefault')); - - // Actually display the menu - $treeMenu->printMenu(); + <div class="logo"><a href="intro.php" target="detail"><img src="<?php echo $misc->icon('title') ?>" width="200" height="50" alt="<?php echo htmlspecialchars($appName) ?>" title="<?php echo htmlspecialchars($appName) ?>" /></a></div> + +<style type="text/css"> +.webfx-tree-children { + background-image: url("<?php echo $misc->icon('I') ?>"); +} +</style> +<script type="text/javascript"> + +webFXTreeConfig.rootIcon = "<?php echo $misc->icon('root') ?>"; +webFXTreeConfig.openRootIcon = "<?php echo $misc->icon('root') ?>"; +webFXTreeConfig.folderIcon = "<?php echo $misc->icon('folder') ?>"; +webFXTreeConfig.openFolderIcon = "<?php echo $misc->icon('folderOpen') ?>"; +webFXTreeConfig.fileIcon = "<?php echo $misc->icon('file') ?>"; +webFXTreeConfig.iIcon = "<?php echo $misc->icon('I') ?>"; +webFXTreeConfig.lIcon = "<?php echo $misc->icon('L') ?>"; +webFXTreeConfig.lMinusIcon = "<?php echo $misc->icon('Lminus') ?>"; +webFXTreeConfig.lPlusIcon = "<?php echo $misc->icon('Lplus') ?>"; +webFXTreeConfig.tIcon = "<?php echo $misc->icon('T') ?>"; +webFXTreeConfig.tMinusIcon = "<?php echo $misc->icon('Tminus') ?>"; +webFXTreeConfig.tPlusIcon = "<?php echo $misc->icon('Tplus') ?>"; +webFXTreeConfig.blankIcon = "<?php echo $misc->icon('blank') ?>"; +webFXTreeConfig.loadingIcon = "<?php echo $misc->icon('loading') ?>"; +webFXTreeConfig.loadingText = "<?php echo $lang['strloading'] ?>"; +webFXTreeConfig.errorIcon = "<?php echo $misc->icon('error') ?>"; +webFXTreeConfig.errorLoadingText = "<?php echo $lang['strerrorloading'] ?>"; +webFXTreeConfig.reloadText = "<?php echo $lang['strclicktoreload'] ?>"; + +// Set default target frame: +WebFXTreeAbstractNode.prototype.target = 'detail'; + +// Disable double click: +WebFXTreeAbstractNode.prototype._onDblClick = function(){} + +// Show tree XML on double click - for debugging purposes only +// TODO: REMOVE THIS BEFORE RELEASE +WebFXTreeAbstractNode.prototype._onDblClick = function(e){ + var el = e.target || e.srcElement; + + if (this.src != null) + window.open(this.src, this.target || "_self"); + return false; +}; + +var tree = new WebFXLoadTree("<?php echo $lang['strservers']; ?>", "servers.php?action=tree", "servers.php"); + +tree.write(); +tree.setExpanded(true); + +</script> +<?php // Output footer echo "</div>\n"; $misc->printFooter(); diff --git a/classes/ArrayRecordSet.php b/classes/ArrayRecordSet.php new file mode 100644 index 00000000..f05e0dbd --- /dev/null +++ b/classes/ArrayRecordSet.php @@ -0,0 +1,32 @@ +<?php + +/** + * Really simple RecordSet to allow printTable of arrays. + * + * $Id: ArrayRecordSet.php,v 1.2 2005/05/02 15:47:25 chriskl Exp $ + */ +class ArrayRecordSet { + + var $_array; + var $_count; + var $EOF = false; + var $f; + + function ArrayRecordSet($data) { + $this->_array = $data; + $this->_count = count($this->_array); + $this->f = reset($this->_array); + if ($this->f === false) $this->EOF = true; + } + + function recordCount() { + return $this->_count; + } + + function moveNext() { + $this->f = next($this->_array); + if ($this->f === false) $this->EOF = true; + } +} + +?> diff --git a/classes/Misc.php b/classes/Misc.php index 5c604992..1cd892f7 100644 --- a/classes/Misc.php +++ b/classes/Misc.php @@ -2,7 +2,7 @@ /** * Class to hold various commonly used functions * - * $Id: Misc.php,v 1.99 2005/04/11 15:15:44 chriskl Exp $ + * $Id: Misc.php,v 1.100 2005/05/02 15:47:25 chriskl Exp $ */ class Misc { @@ -21,45 +21,32 @@ * @return True, dumps are set up, false otherwise */ function isDumpEnabled($all = false) { - global $conf; - - if ($all) - return ($conf['servers'][$_SESSION['webdbServerID']]['pg_dumpall_path'] !== null - && $conf['servers'][$_SESSION['webdbServerID']]['pg_dumpall_path'] != ''); - else - return ($conf['servers'][$_SESSION['webdbServerID']]['pg_dump_path'] !== null - && $conf['servers'][$_SESSION['webdbServerID']]['pg_dump_path'] != ''); + $info = $this->getServerInfo(); + return !empty($info[$all ? 'pg_dumpall_path' : 'pg_dump_path']); } /** - * Checks whether a login is allowed - * @return True if login is allowed to be used + * Sets the href tracking variable */ - function checkExtraSecurity() { - global $conf; - - // Disallowed logins if extra_login_security is enabled. These must be lowercase. - $bad_usernames = array('pgsql', 'postgres', 'root', 'administrator'); - - // If extra security is off, return true - if (!$conf['extra_login_security']) return true; - elseif ($_SESSION['webdbPassword'] == '') return false; - else { - $username = strtolower($_SESSION['webdbUsername']); - return !in_array($username, $bad_usernames); - } + function setHREF() { + $this->href = $this->getHREF(); } - + /** - * Sets the href tracking variable + * Get a href query string, excluding objects below the given object type (inclusive) */ - function setHREF() { - $this->href = ''; - if (isset($_REQUEST['database'])) { - $this->href .= 'database=' . urlencode($_REQUEST['database']); - if (isset($_REQUEST['schema'])) - $this->href .= '&schema=' . urlencode($_REQUEST['schema']); + function getHREF($exclude_from = null) { + $href = ''; + if (isset($_REQUEST['server']) && $exclude_from != 'server') { + $href .= 'server=' . urlencode($_REQUEST['server']); + if (isset($_REQUEST['database']) && $exclude_from != 'database') { + $href .= '&database=' . urlencode($_REQUEST['database']); + if (isset($_REQUEST['schema']) && $exclude_from != 'schema') { + $href .= '&schema=' . urlencode($_REQUEST['schema']); + } + } } + return $href; } /** @@ -67,10 +54,14 @@ */ function setForm() { $this->form = ''; - if (isset($_REQUEST['database'])) { - $this->form .= "<input type=\"hidden\" name=\"database\" value=\"" . htmlspecialchars($_REQUEST['database']) . "\" />\n"; - if (isset($_REQUEST['schema'])) - $this->form .= "<input type=\"hidden\" name=\"schema\" value=\"" . htmlspecialchars($_REQUEST['schema']) . "\" />\n"; + if (isset($_REQUEST['server'])) { + $this->form .= "<input type=\"hidden\" name=\"server\" value=\"" . htmlspecialchars($_REQUEST['server']) . "\" />\n"; + if (isset($_REQUEST['database'])) { + $this->form .= "<input type=\"hidden\" name=\"database\" value=\"" . htmlspecialchars($_REQUEST['database']) . "\" />\n"; + if (isset($_REQUEST['schema'])) { + $this->form .= "<input type=\"hidden\" name=\"schema\" value=\"" . htmlspecialchars($_REQUEST['schema']) . "\" />\n"; + } + } } } @@ -264,27 +255,50 @@ /** * Creates a database accessor */ - function &getDatabaseAccessor($database) { - global $conf; + function &getDatabaseAccessor($database, $server_id = null) { + global $lang, $conf, $misc; + + $server_info = $this->getServerInfo($server_id); + // Perform extra security checks if this config option is set + if ($conf['extra_login_security']) { + // Disallowed logins if extra_login_security is enabled. + // These must be lowercase. + $bad_usernames = array('pgsql', 'postgres', 'root', 'administrator'); + + $username = strtolower($server_info['username']); + + if ($server_info['password'] == '' || in_array($username, $bad_usernames)) { + unset($_SESSION['webdbLogin'][$_REQUEST['server']]); + $msg = $lang['strlogindisallowed']; + include('./login.php'); + exit; + } + } + // Create the connection object and make the connection $_connection = new Connection( - $conf['servers'][$_SESSION['webdbServerID']]['host'], - $conf['servers'][$_SESSION['webdbServerID']]['port'], - $_SESSION['webdbUsername'], - $_SESSION['webdbPassword'], + $server_info['host'], + $server_info['port'], + $server_info['username'], + $server_info['password'], $database ); - // Get the name of the database driver we need to use. The description - // of the server is returned and placed into the conf array. - $_type = $_connection->getDriver($desc); - // XXX: NEED TO CHECK RETURN STATUS HERE - + // Get the name of the database driver we need to use. + // The description of the server is returned in $platform. + $_type = $_connection->getDriver($platform); + if ($_type === null) { + printf($lang['strpostgresqlversionnotsupported'], $postgresqlMinVer); + exit; + } + $this->setServerInfo('platform', $platform, $server_id); + // Create a database wrapper class for easy manipulation of the // connection. include_once('./classes/database/' . $_type . '.php'); - $data = &new $_type($_connection->conn); + $data =& new $_type($_connection->conn); + $data->platform = $_connection->platform; return $data; } @@ -405,7 +419,7 @@ $active = ($tab_id == $activetab) ? ' active' : ''; if (!isset($tab['hide']) || $tab['hide'] !== true) { - $tablink = "<a href=\"" . $this->printVal($tab['url'], 'nbsp') . "\">{$tab['title']}</a>"; + $tablink = "<a" . $this->printActionUrl($tab, $_REQUEST, 'href') . ">{$tab['title']}</a>"; echo "<td width=\"{$width}\" class=\"tab{$active}\">"; @@ -428,271 +442,362 @@ function getNavTabs($section) { global $data, $lang, $conf; - $databasevar = isset($_REQUEST['database']) ? 'database=' . urlencode($_REQUEST['database']) : ''; - $schemavar = isset($_REQUEST['schema']) ? '&schema=' . urlencode($_REQUEST['schema']) : ''; +# $servervar = isset($_REQUEST['server']) ? 'server=' . urlencode($_REQUEST['server']) : ''; +# $databasevar = isset($_REQUEST['database']) ? '&database=' . urlencode($_REQUEST['database']) : ''; +# $schemavar = isset($_REQUEST['schema']) ? '&schema=' . urlencode($_REQUEST['schema']) : ''; $hide_advanced = ($conf['show_advanced'] === false); switch ($section) { + case 'root': + return array ( + 'intro' => array ( + 'title' => $lang['strintroduction'], + 'url' => "intro.php", + ), + 'servers' => array ( + 'title' => $lang['strservers'], + 'url' => "servers.php", + ), + ); + case 'server': - $hide_users = !$data->isSuperUser($_SESSION['webdbUsername']); +# $vars = $servervar . $databasevar . '&subject=server'; + $server_info = $this->getServerInfo(); + $hide_users = !$data->isSuperUser($server_info['username']); + #$hide_users = false; return array ( 'databases' => array ( 'title' => $lang['strdatabases'], - 'url' => "all_db.php", + 'url' => 'all_db.php', + 'urlvars' => array('subject' => 'server'), 'help' => 'pg.database', ), 'users' => array ( 'title' => $lang['strusers'], - 'url' => "users.php", + 'url' => 'users.php', + 'urlvars' => array('subject' => 'server'), 'hide' => $hide_users, 'help' => 'pg.user', ), 'groups' => array ( 'title' => $lang['strgroups'], - 'url' => "groups.php", + 'url' => 'groups.php', + 'urlvars' => array('subject' => 'server'), 'hide' => $hide_users, 'help' => 'pg.group', ), + 'account' => array ( + 'title' => $lang['straccount'], + 'url' => 'users.php', + 'urlvars' => array('subject' => 'server', 'action' => 'action'), + 'hide' => !$hide_users, + 'help' => 'pg.user', + ), 'tablespaces' => array ( 'title' => $lang['strtablespaces'], - 'url' => "tablespaces.php", + 'url' => 'tablespaces.php', + 'urlvars' => array('subject' => 'server'), 'hide' => (!$data->hasTablespaces()), 'help' => 'pg.tablespace', ), 'export' => array ( 'title' => $lang['strexport'], - 'url' => "all_db.php?action=export", + 'url' => 'all_db.php', + 'urlvars' => array('subject' => 'server', 'action' => 'export'), 'hide' => (!$this->isDumpEnabled()), ), + 'reports' => array ( + 'title' => $lang['strreports'], + 'url' => 'reports.php', + 'urlvars' => array('subject' => 'server'), + ), ); case 'database': - $vars = $databasevar . '&subject=database'; +# $vars = $servervar . $databasevar . '&subject=database'; return array ( 'schemas' => array ( 'title' => $lang['strschemas'], - 'url' => "database.php?{$vars}", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database'), 'hide' => (!$data->hasSchemas()), 'help' => 'pg.schema', ), 'sql' => array ( 'title' => $lang['strsql'], - 'url' => "database.php?{$vars}&action=sql", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database', 'action' => 'sql'), 'help' => 'pg.sql', ), 'find' => array ( 'title' => $lang['strfind'], - 'url' => "database.php?{$vars}&action=find", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database', 'action' => 'find'), ), 'variables' => array ( 'title' => $lang['strvariables'], - 'url' => "database.php?{$vars}&action=variables", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database', 'action' => 'variables'), 'hide' => (!$data->hasVariables()), 'help' => 'pg.variable', ), 'processes' => array ( 'title' => $lang['strprocesses'], - 'url' => "database.php?{$vars}&action=processes", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database', 'action' => 'processes'), 'hide' => (!$data->hasProcesses()), 'help' => 'pg.process', ), 'admin' => array ( 'title' => $lang['stradmin'], - 'url' => "database.php?{$vars}&action=admin", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database', 'action' => 'admin'), ), 'privileges' => array ( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?{$vars}", + 'url' => 'privileges.php', + 'urlvars' => array('subject' => 'database'), 'hide' => (!isset($data->privlist['database'])), 'help' => 'pg.privilege', ), 'languages' => array ( 'title' => $lang['strlanguages'], - 'url' => "languages.php?{$vars}", + 'url' => 'languages.php', + 'urlvars' => array('subject' => 'database'), 'hide' => $hide_advanced, 'help' => 'pg.language', ), 'casts' => array ( 'title' => $lang['strcasts'], - 'url' => "casts.php?{$vars}", + 'url' => 'casts.php', + 'urlvars' => array('subject' => 'database'), 'hide' => ($hide_advanced || !$data->hasCasts()), 'help' => 'pg.cast', ), 'export' => array ( 'title' => $lang['strexport'], - 'url' => "database.php?{$vars}&action=export", + 'url' => 'database.php', + 'urlvars' => array('subject' => 'database', 'action' => 'export'), 'hide' => (!$this->isDumpEnabled()), ), ); case 'schema': - $vars = $databasevar . $schemavar . '&subject=schema'; +# $vars = $servervar . $databasevar . $schemavar . '&subject=schema'; return array ( 'tables' => array ( 'title' => $lang['strtables'], - 'url' => "tables.php?{$vars}", + 'url' => 'tables.php', + 'urlvars' => array('subject' => 'schema'), 'help' => 'pg.table', + 'icon' => 'tables', ), 'views' => array ( 'title' => $lang['strviews'], - 'url' => "views.php?{$vars}", + 'url' => 'views.php', + 'urlvars' => array('subject' => 'schema'), 'help' => 'pg.view', + 'icon' => 'views', ), 'sequences' => array ( 'title' => $lang['strsequences'], - 'url' => "sequences.php?{$vars}", + 'url' => 'sequences.php', + 'urlvars' => array('subject' => 'schema'), 'help' => 'pg.sequence', + 'icon' => 'sequences', ), 'functions' => array ( 'title' => $lang['strfunctions'], - 'url' => "functions.php?{$vars}", + 'url' => 'functions.php', + 'urlvars' => array('subject' => 'schema'), 'help' => 'pg.function', + 'icon' => 'functions', ), 'domains' => array ( 'title' => $lang['strdomains'], - 'url' => "domains.php?{$vars}", + 'url' => 'domains.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => (!$data->hasDomains()), 'help' => 'pg.domain', + 'icon' => 'domains', ), 'aggregates' => array ( 'title' => $lang['straggregates'], - 'url' => "aggregates.php?{$vars}", + 'url' => 'aggregates.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => $hide_advanced, 'help' => 'pg.aggregate', + 'icon' => 'functions', ), 'types' => array ( 'title' => $lang['strtypes'], - 'url' => "types.php?{$vars}", + 'url' => 'types.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => $hide_advanced, 'help' => 'pg.type', + 'icon' => 'types', ), 'operators' => array ( 'title' => $lang['stroperators'], - 'url' => "operators.php?{$vars}", + 'url' => 'operators.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => $hide_advanced, 'help' => 'pg.operator', + 'icon' => 'operators', ), 'opclasses' => array ( 'title' => $lang['stropclasses'], - 'url' => "opclasses.php?{$vars}", + 'url' => 'opclasses.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => $hide_advanced, 'help' => 'pg.opclass', + 'icon' => 'operators', ), 'conversions' => array ( 'title' => $lang['strconversions'], - 'url' => "conversions.php?{$vars}", + 'url' => 'conversions.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => ($hide_advanced || !$data->hasConversions()), 'help' => 'pg.conversion', + 'icon' => 'types', ), 'privileges' => array ( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?{$vars}", + 'url' => 'privileges.php', + 'urlvars' => array('subject' => 'schema'), 'hide' => (!$data->hasSchemas()), 'help' => 'pg.privilege', ), ); case 'table': - $table = urlencode($_REQUEST['table']); - $vars = $databasevar . $schemavar . "&table={$table}&subject=table"; +# $table = urlencode($_REQUEST['table']); +# $vars = $servervar . $databasevar . $schemavar . "&table={$table}&subject=table"; return array ( 'columns' => array ( 'title' => $lang['strcolumns'], - 'url' => "tblproperties.php?{$vars}", + 'url' => 'tblproperties.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), ), 'indexes' => array ( 'title' => $lang['strindexes'], - 'url' => "indexes.php?{$vars}", + 'url' => 'indexes.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), 'help' => 'pg.index', ), 'constraints' => array ( 'title' => $lang['strconstraints'], - 'url' => "constraints.php?{$vars}", + 'url' => 'constraints.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), 'help' => 'pg.constraint', ), 'triggers' => array ( 'title' => $lang['strtriggers'], - 'url' => "triggers.php?{$vars}", + 'url' => 'triggers.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), 'help' => 'pg.trigger', ), 'rules' => array ( 'title' => $lang['strrules'], - 'url' => "rules.php?{$vars}", + 'url' => 'rules.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), 'help' => 'pg.rule', ), 'info' => array ( 'title' => $lang['strinfo'], - 'url' => "info.php?{$vars}", + 'url' => 'info.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), ), 'privileges' => array ( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?{$vars}", + 'url' => 'privileges.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table')), 'help' => 'pg.privilege', ), 'import' => array ( 'title' => $lang['strimport'], - 'url' => "tblproperties.php?{$vars}&action=import", + 'url' => 'tblproperties.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table'), 'action' => 'import'), ), 'export' => array ( 'title' => $lang['strexport'], - 'url' => "tblproperties.php?{$vars}&action=export", + 'url' => 'tblproperties.php', + 'urlvars' => array('subject' => 'table', 'table' => field('table'), 'action' => 'export'), ), ); case 'view': - $view = urlencode($_REQUEST['view']); - $vars = $databasevar . $schemavar . "&view={$view}&subject=view"; +# $view = urlencode($_REQUEST['view']); +# $vars = $servervar . $databasevar . $schemavar . "&view={$view}&subject=view"; return array ( 'columns' => array ( 'title' => $lang['strcolumns'], - 'url' => "viewproperties.php?{$vars}", + 'url' => 'viewproperties.php', + 'urlvars' => array('subject' => 'view', 'view' => field('view')), ), 'definition' => array ( 'title' => $lang['strdefinition'], - 'url' => "viewproperties.php?{$vars}&action=definition", + 'url' => 'viewproperties.php', + 'urlvars' => array('subject' => 'view', 'view' => field('view'), 'action' => 'definition'), ), 'rules' => array ( 'title' => $lang['strrules'], - 'url' => "rules.php?{$vars}", + 'url' => 'rules.php', + 'urlvars' => array('subject' => 'view', 'view' => field('view')), 'help' => 'pg.rule', ), 'privileges' => array ( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?{$vars}", + 'url' => 'privileges.php', + 'urlvars' => array('subject' => 'view', 'view' => field('view')), 'help' => 'pg.privilege', ), 'export' => array ( 'title' => $lang['strexport'], - 'url' => "viewproperties.php?{$vars}&action=export", + 'url' => 'viewproperties.php', + 'urlvars' => array('subject' => 'view', 'view' => field('view'), 'action' => 'export'), ), ); case 'function': - $funcnam = urlencode($_REQUEST['function']); - $funcoid = urlencode($_REQUEST['function_oid']); - $vars = $databasevar . $schemavar . "&function={$funcnam}&function_oid={$funcoid}&subject=function"; +# $funcnam = urlencode($_REQUEST['function']); +# $funcoid = urlencode($_REQUEST['function_oid']); +# $vars = $servervar . $databasevar . $schemavar . "&function={$funcnam}&function_oid={$funcoid}&subject=function"; return array ( 'definition' => array ( 'title' => $lang['strdefinition'], - 'url' => "functions.php?{$vars}&action=properties", + 'url' => 'functions.php', + 'urlvars' => array( + 'subject' => 'function', + 'function' => field('function'), + 'function_oid' => field('function_oid'), + 'action' => 'properties', + ), ), 'privileges' => array ( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?{$vars}", + 'url' => 'privileges.php', + 'urlvars' => array( + 'subject' => 'function', + 'function' => field('function'), + 'function_oid' => field('function_oid'), + ), ), ); case 'popup': - $vars = $databasevar; +# $vars = $servervar . $databasevar; return array ( 'sql' => array ( 'title' => $lang['strsql'], - 'url' => "sqledit.php?{$vars}&action=sql", + 'url' => 'sqledit.php', + 'urlvars' => array('subject' => 'schema', 'action' => 'sql'), 'help' => 'pg.sql', ), 'find' => array ( 'title' => $lang['strfind'], - 'url' => "sqledit.php?{$vars}&action=find", + 'url' => 'sqledit.php', + 'urlvars' => array('subject' => 'schema', 'action' => 'find'), ), ); @@ -727,12 +832,70 @@ return isset($tab['url']) ? $tab['url'] : null; } + function printTopbar() { + global $lang, $conf, $appName, $appVersion, $appLangFiles; + + $server_info = $this->getServerInfo(); + + echo "<div class=\"topbar\"><table width=\"100%\"><tr><td>"; + + if ($server_info && isset($server_info['platform']) && isset($server_info['username'])) { + echo sprintf($lang['strtopbar'], + '<span class="platform">'.htmlspecialchars($server_info['platform']).'</span>', + '<span class="host">'.htmlspecialchars($server_info['host']).'</span>', + '<span class="port">'.htmlspecialchars($server_info['port']).'</span>', + '<span class="username">'.htmlspecialchars($server_info['username']).'</span>', + '<span class="date">'.date($lang['strtimefmt']).'</span>'); + } else { + echo "<span class=\"appname\">$appName</span> <span class=\"version\">$appVersion</span>"; + } + + echo "</td>"; + + if (isset($_REQUEST['server'])) { + $url = "sqledit.php?{$this->href}&action="; + + $window_id = htmlspecialchars('sqledit:'.$_REQUEST['server']); + + echo "<td align=\"right\">"; + + echo "<a class=\"toplink\" href=\"{$url}sql\" target=\"sqledit\" onclick=\"window.open('{$url}sql','{$window_id}','toolbar=no,width=600,height=400,resizable=yes,scrollbars=no').focus(); return false;\">{$lang['strsql']}</a> | "; + + echo "<a class=\"toplink\" href=\"{$url}find\" target=\"sqledit\" onclick=\"window.open('{$url}find','{$window_id}','toolbar=no,width=600,height=400,resizable=yes,scrollbars=no').focus(); return false;\">{$lang['strfind']}</a>"; + + echo "</td>"; + } +/* + echo "<td align=\"right\" width=\"1%\">"; + + echo "<form method=\"get\"><select name=\"language\" onchange=\"this.form.submit()\">\n"; + $language = isset($_SESSION['webdbLanguage']) ? $_SESSION['webdbLanguage'] : 'english'; + foreach ($appLangFiles as $k => $v) { + echo "<option value=\"{$k}\"", + ($k == $language) ? ' selected="selected"' : '', + ">{$v}</option>\n"; + } + echo "</select>\n"; + echo "<noscript><input type=\"submit\" value=\"Set Language\"></noscript>\n"; + foreach ($_GET as $key => $val) { + if ($key == 'language') continue; + echo "<input type=\"hidden\" name=\"$key\" value=\"", htmlspecialchars($val), "\" />\n"; + } + echo "</form>\n"; + + echo "</td>"; +*/ + echo "</tr></table></div>\n"; + } + /** * Display a bread crumb trail. */ function printTrail($trail = array()) { global $lang; + $this->printTopbar(); + if (is_string($trail)) { $trail = $this->getTrail($trail); } @@ -768,26 +931,37 @@ * @param $object The type of object at the end of the trail. */ function getTrail($subject = null) { - global $lang, $conf; + global $lang, $conf, $data, $appName; $trail = array(); $vars = ''; $done = false; - $trail['server'] = array( - 'title' => $lang['strserver'], - 'text' => $conf['servers'][$_SESSION['webdbServerID']]['desc'], - 'url' => 'redirect.php?section=server', - 'help' => 'pg.server' + $trail['root'] = array( + 'text' => $appName, + 'url' => 'redirect.php?subject=root', ); + + if ($subject == 'root') $done = true; + + if (!$done) { + $vars = 'server='.urlencode($_REQUEST['server']).'&'; + $server_info = $this->getServerInfo(); + $trail['server'] = array( + 'title' => $lang['strserver'], + 'text' => $server_info['desc'], + 'url' => "redirect.php?subject=server&{$vars}", + 'help' => 'pg.server' + ); + } if ($subject == 'server') $done = true; if (isset($_REQUEST['database']) && !$done) { - $vars = 'database='.urlencode($_REQUEST['database']).'&'; + $vars .= 'database='.urlencode($_REQUEST['database']).'&'; $trail['database'] = array( 'title' => $lang['strdatabase'], 'text' => $_REQUEST['database'], - 'url' => "redirect.php?section=database&{$vars}", + 'url' => "redirect.php?subject=database&{$vars}", 'help' => 'pg.database' ); } @@ -798,14 +972,14 @@ $trail['schema'] = array( 'title' => $lang['strschema'], 'text' => $_REQUEST['schema'], - 'url' => "redirect.php?section=schema&{$vars}", + 'url' => "redirect.php?subject=schema&{$vars}", 'help' => 'pg.schema' ); } if ($subject == 'schema') $done = true; if (isset($_REQUEST['table']) && !$done) { - $vars .= "section=table&table=".urlencode($_REQUEST['table']); + $vars .= "subject=table&table=".urlencode($_REQUEST['table']); $trail['table'] = array( 'title' => $lang['strtable'], 'text' => $_REQUEST['table'], @@ -813,7 +987,7 @@ 'help' => 'pg.table' ); } elseif (isset($_REQUEST['view']) && !$done) { - $vars .= "section=view&view=".urlencode($_REQUEST['view']); + $vars .= "subject=view&view=".urlencode($_REQUEST['view']); $trail['view'] = array( 'title' => $lang['strview'], 'text' => $_REQUEST['view'], @@ -827,7 +1001,7 @@ switch ($subject) { case 'function': $vars .= "{$subject}_oid=".urlencode($_REQUEST[$subject.'_oid']).'&'; - $vars .= "section={$subject}&{$subject}=".urlencode($_REQUEST[$subject]); + $vars .= "subject={$subject}&{$subject}=".urlencode($_REQUEST[$subject]); $trail[$subject] = array( 'title' => $lang['str'.$subject], 'text' => $_REQUEST[$subject], @@ -918,7 +1092,7 @@ echo $str; if ($help) { echo "<a class=\"help\" href=\""; - echo htmlspecialchars("help.php?help=".urlencode($help)); + echo htmlspecialchars("help.php?help=".urlencode($help)."&server=".urlencode($_REQUEST['server'])); echo "\" title=\"{$lang['strhelp']}\" target=\"phppgadminhelp\">{$lang['strhelpicon']}</a>"; } } @@ -934,6 +1108,18 @@ echo "-->\n"; echo "</script>\n"; } + + /** + * Outputs JavaScript to set the name of the browser window. + * @param $name the window name + * @param $addServer if true (default) then the server id is + * attached to the name. + */ + function setWindowName($name, $addServer = true) { + echo "<script type=\"text/javascript\">\n<!--\n"; + echo " window.name = '{$name}", ($addServer ? ':'.htmlspecialchars($_REQUEST['server']) : ''), "';\n"; + echo "-->\n</script>\n"; + } /** * Converts a PHP.INI size variable to bytes. Taken from publically available @@ -941,7 +1127,7 @@ * @param $strIniSize The PHP.INI variable * @return size in bytes, false on failure */ - function inisizeToBytes($strIniSize) { + function inisizeToBytes($strIniSize) { // This function will take the string value of an ini 'size' parameter, // and return a double (64-bit float) representing the number of bytes // that the parameter represents. Or false if $strIniSize is unparseable. @@ -965,8 +1151,73 @@ default: return $nSize; } - } + } + + /** + * Display a URL given an action associative array. + * @param $action An associative array of the follow properties: + * 'url' => The first part of the URL (before the ?) + * 'urlvars' => Associative array of (URL variable => field name) + * these are appended to the URL + * 'urlfn' => Function to apply to URL before display + * @param $fields Field data from which 'urlfield' and 'vars' are obtained. + * @param $attr If supplied then the URL will be quoted and prefixed with + * '$attr='. + */ + function printActionUrl(&$action, &$fields, $attr = null) { + $url = value($action['url'], $fields); + + if ($url === false) return ''; + + if (!empty($action['urlvars'])) { + $urlvars = value($action['urlvars'], $fields); + } else { + $urlvars = array(); + } + + if (isset($urlvars['subject'])) { + $subject = value($urlvars['subject'], $fields); + if (isset($_REQUEST['server']) && $subject != 'root') { + $urlvars['server'] = $_REQUEST['server']; + if (isset($_REQUEST['database']) && $subject != 'server') { + $urlvars['database'] = $_REQUEST['database']; + if (isset($_REQUEST['schema']) && $subject != 'database') { + $urlvars['schema'] = $_REQUEST['schema']; + } + } + } + } + + $sep = '?'; + foreach ($urlvars as $var => $varfield) { + $url .= $sep . value_url($var, $fields) . '=' . value_url($varfield, $fields); + $sep = '&'; + } + + $url = htmlentities($url); + + if ($attr !== null && $url != '') + return ' '.$attr.'="'.$url.'"'; + else + return $url; + } + function getRequestVars($subject = '') { + $v = array(); + if (!empty($subject)) + $v['subject'] = $subject; + if (isset($_REQUEST['server']) && $subject != 'root') { + $v['server'] = $_REQUEST['server']; + if (isset($_REQUEST['database']) && $subject != 'server') { + $v['database'] = $_REQUEST['database']; + if (isset($_REQUEST['schema']) && $subject != 'database') { + $v['schema'] = $_REQUEST['schema']; + } + } + } + return $v; + } + function printUrlVars(&$vars, &$fields) { foreach ($vars as $var => $varfield) { echo "{$var}=", urlencode($fields[$varfield]), "&"; @@ -1067,7 +1318,7 @@ switch ($column_id) { case 'actions': foreach ($alt_actions as $action) { - if (isset($action['disable'])) { + if (isset($action['disable']) && $action['disable'] === true) { echo "<td class=\"data{$id}\"></td>"; } else { echo "<td class=\"opbutton{$id}\">"; @@ -1079,15 +1330,17 @@ break; default; echo "<td class=\"data{$id}\">"; - if (isset($column['url'])) { - echo "<a href=\"{$column['url']}"; - $misc->printUrlVars($column['vars'], $tabledata->f); - echo "\">"; - } + if (isset($tabledata->f[$column['field']])) { + if (isset($column['url'])) { + echo "<a href=\"{$column['url']}"; + $misc->printUrlVars($column['vars'], $tabledata->f); + echo "\">"; + } - $type = isset($column['type']) ? $column['type'] : null; - $params = isset($column['params']) ? $column['params'] : array(); - echo $misc->printVal($tabledata->f[$column['field']], $type, $params); + $type = isset($column['type']) ? $column['type'] : null; + $params = isset($column['params']) ? $column['params'] : array(); + echo $misc->printVal($tabledata->f[$column['field']], $type, $params); + } if (isset($column['url'])) echo "</a>"; @@ -1112,6 +1365,69 @@ } } + /** Produce XML data for the browser tree + * @param $treedata A set of records to populate the tree. + * @param $attrs Attributes for tree items + * 'text' - the text for the tree node + * 'icon' - an icon for node + * 'openIcon' - an alternative icon when the node is expanded + * 'toolTip' - tool tip text for the node + * 'action' - URL to visit when single clicking the node + * 'branch' - URL for child nodes (tree XML) + * 'expand' - the action to return XML for the subtree + * 'nodata' - message to display when node has no children + */ + function printTreeXML(&$treedata, &$attrs) { + global $conf, $lang; + header("Content-Type: text/xml"); + header("Cache-Control: no-cache"); + + echo "<?xml version=\"1.0\"?>\n"; + + echo "<tree>\n"; + + if ($treedata->recordCount() > 0) { + while (!$treedata->EOF) { + $rec =& $treedata->f; + + echo "<tree"; + echo value_xml_attr('text', $attrs['text'], $rec); + echo value_xml_attr('action', $attrs['action'], $rec); + echo value_xml_attr('src', $attrs['branch'], $rec); + + $icon = $this->icon(value($attrs['icon'], $rec)); + echo value_xml_attr('icon', $icon, $rec); + + if (!empty($attrs['openIcon'])) { + $icon = $this->icon(value($attrs['openIcon'], $rec)); + } + echo value_xml_attr('openIcon', $icon, $rec); + + echo value_xml_attr('toolTip', $attrs['toolTip'], $rec); + + echo "/>\n"; + + $treedata->moveNext(); + } + } else { + $msg = isset($attrs['nodata']) ? $attrs['nodata'] : $lang['strnoobjects']; + echo "<tree text=\"{$msg}\" onaction=\"this.parentNode.reload()\" icon=\"", $this->icon('error'), "\"/>\n"; + } + + echo "</tree>\n"; + } + + function icon($icon) { + global $conf; + $path = "images/themes/{$conf['theme']}/{$icon}"; + if (file_exists($path.'.png')) return $path.'.png'; + if (file_exists($path.'.gif')) return $path.'.gif'; + $path = "images/themes/default/{$icon}"; + if (file_exists($path.'.png')) return $path.'.png'; + if (file_exists($path.'.gif')) return $path.'.gif'; + return ''; + } + /** * Function to escape command line parameters * @param $str The string to escape @@ -1150,5 +1466,88 @@ else return escapeshellcmd($str); } + + /** + * Get list of servers + * @param $recordset return as RecordSet suitable for printTable if true, + * otherwise just return an array. + */ + function &getServers($recordset = false) { + global $conf; + + $srvs = isset($_SESSION['webdbLogin']) && is_array($_SESSION['webdbLogin']) ? $_SESSION['webdbLogin'] : array(); + + foreach($conf['servers'] as $idx => $info) { + $server_id = $info['host'].':'.$info['port']; + + if (!isset($srvs[$server_id])) { + $srvs[$server_id] = $info; + } + $srvs[$server_id]['id'] = $server_id; + } + + function _cmp_desc($a, $b) { + return strcmp($a['desc'], $b['desc']); + } + uasort($srvs, '_cmp_desc'); + + if ($recordset) { + include_once('classes/ArrayRecordSet.php'); + return new ArrayRecordSet($srvs); + } + return $srvs; + } + + /** + * Get information on a server. + * If the parameter isn't supplied then the currently + * connected server is returned. + * @param $server_id A server identifier (host:port) + * @return An associative array of server properties + */ + function getServerInfo($server_id = null) { + global $conf; + + if ($server_id === null && isset($_REQUEST['server'])) + $server_id = $_REQUEST['server']; + + // Check for the server in the logged-in list + if (isset($_SESSION['webdbLogin'][$server_id])) + return $_SESSION['webdbLogin'][$server_id]; + + // Otherwise, look for it in the conf file + foreach($conf['servers'] as $idx => $info) { + if ($server_id == $info['host'].':'.$info['port']) + return $info; + } + + return null; + } + + /** + * Set server information. + * @param $key parameter name to set, or null to replace all + * params with the assoc-array in $value. + * @param $value the new value, or null to unset the parameter + * @param $server_id the server identifier, or null for current + * server. + */ + function setServerInfo($key, $value, $server_id = null) + { + if ($server_id === null && isset($_REQUEST['server'])) + $server_id = $_REQUEST['server']; + + if ($key === null) { + if ($value === null) + unset($_SESSION['webdbLogin'][$server_id]); + else + $_SESSION['webdbLogin'][$server_id] = $value; + } else { + if ($value === null) + unset($_SESSION['webdbLogin'][$server_id][$key]); + else + $_SESSION['webdbLogin'][$server_id][$key] = $value; + } + } } ?> diff --git a/classes/Reports.php b/classes/Reports.php index 8cabfcea..65fe2e19 100644 --- a/classes/Reports.php +++ b/classes/Reports.php @@ -4,7 +4,7 @@ * the functions provided by the database driver exclusively, and hence * will work with any database without modification. * - * $Id: Reports.php,v 1.11 2004/07/01 07:15:11 chriskl Exp $ + * $Id: Reports.php,v 1.12 2005/05/02 15:47:26 chriskl Exp $ */ class Reports { @@ -34,10 +34,11 @@ * @return A recordset */ function &getReports() { - global $conf; + global $conf, $misc; // Filter for owned reports if necessary if ($conf['owned_reports_only']) { - $filter['created_by'] = $_SESSION['webdbUsername']; + $server_info = $misc->getServerInfo(); + $filter['created_by'] = $server_info['username']; $ops = array('created_by' => '='); } else $filter = $ops = array(); @@ -71,10 +72,12 @@ * @return 0 success */ function createReport($report_name, $db_name, $descr, $report_sql) { + global $misc; + $server_info = $misc->getServerInfo(); $temp = array( 'report_name' => $report_name, 'db_name' => $db_name, - 'created_by' => $_SESSION['webdbUsername'], + 'created_by' => $server_info['username'], 'report_sql' => $report_sql ); if ($descr != '') $temp['descr'] = $descr; @@ -92,10 +95,12 @@ * @return 0 success */ function alterReport($report_id, $report_name, $db_name, $descr, $report_sql) { + global $misc; + $server_info = $misc->getServerInfo(); $temp = array( 'report_name' => $report_name, 'db_name' => $db_name, - 'created_by' => $_SESSION['webdbUsername'], + 'created_by' => $server_info['username'], 'report_sql' => $report_sql ); if ($descr != '') $temp['descr'] = $descr; diff --git a/classes/database/Postgres.php b/classes/database/Postgres.php index 30cf2da1..cf8c28d3 100755 --- a/classes/database/Postgres.php +++ b/classes/database/Postgres.php @@ -4,7 +4,7 @@ * A class that implements the DB interface for Postgres * Note: This class uses ADODB and returns RecordSets. * - * $Id: Postgres.php,v 1.260 2005/04/30 18:01:59 soranzo Exp $ + * $Id: Postgres.php,v 1.261 2005/05/02 15:47:26 chriskl Exp $ */ // @@@ THOUGHT: What about inherits? ie. use of ONLY??? @@ -407,10 +407,12 @@ class Postgres extends ADODB_base { * @return A list of databases, sorted alphabetically */ function &getDatabases($currentdatabase = NULL) { - global $conf; + global $conf, $misc; - if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($_SESSION['webdbUsername'])) { - $username = $_SESSION['webdbUsername']; + $server_info = $misc->getServerInfo(); + + if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($server_info['username'])) { + $username = $server_info['username']; $this->clean($username); $clause = " AND pu.usename='{$username}'"; } @@ -3353,7 +3355,9 @@ class Postgres extends ADODB_base { pt.typname AS proresult, pl.lanname AS prolanguage, oidvectortypes(pc.proargtypes) AS proarguments, - (SELECT description FROM pg_description pd WHERE pc.oid=pd.objoid) AS procomment + (SELECT description FROM pg_description pd WHERE pc.oid=pd.objoid) AS procomment, + proname || ' (' || proarguments || ')' AS proproto, + CASE WHEN proretset THEN 'setof ' ELSE '' END || pt.typname AS proreturns FROM pg_proc pc, pg_user pu, pg_type pt, pg_language pl WHERE @@ -3368,7 +3372,9 @@ class Postgres extends ADODB_base { proretset, 'OPAQUE' AS proresult, oidvectortypes(pc.proargtypes) AS proarguments, - (SELECT description FROM pg_description pd WHERE pc.oid=pd.objoid) AS procomment + (SELECT description FROM pg_description pd WHERE pc.oid=pd.objoid) AS procomment, + proname || ' (' || proarguments || ')' AS proproto, + CASE WHEN proretset THEN 'setof ' ELSE '' END || 'OPAQUE' AS proreturns FROM pg_proc pc, pg_user pu, pg_type pt WHERE diff --git a/classes/database/Postgres71.php b/classes/database/Postgres71.php index bf828ac5..bf35f02f 100644 --- a/classes/database/Postgres71.php +++ b/classes/database/Postgres71.php @@ -4,7 +4,7 @@ * A class that implements the DB interface for Postgres * Note: This class uses ADODB and returns RecordSets. * - * $Id: Postgres71.php,v 1.70 2005/02/06 20:03:20 soranzo Exp $ + * $Id: Postgres71.php,v 1.71 2005/05/02 15:47:26 chriskl Exp $ */ // @@@ THOUGHT: What about inherits? ie. use of ONLY??? @@ -86,10 +86,12 @@ class Postgres71 extends Postgres { * @return A list of databases, sorted alphabetically */ function &getDatabases($currentdatabase = NULL) { - global $conf; - - if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($_SESSION['webdbUsername'])) { - $username = $_SESSION['webdbUsername']; + global $conf, $misc; + + $server_info = $misc->getServerInfo(); + + if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($server_info['username'])) { + $username = $server_info['username']; $this->clean($username); $clause = " AND pu.usename='{$username}'"; } diff --git a/classes/database/Postgres72.php b/classes/database/Postgres72.php index 8f6da669..54d850a8 100644 --- a/classes/database/Postgres72.php +++ b/classes/database/Postgres72.php @@ -4,7 +4,7 @@ * A class that implements the DB interface for Postgres * Note: This class uses ADODB and returns RecordSets. * - * $Id: Postgres72.php,v 1.78 2004/11/10 01:46:36 chriskl Exp $ + * $Id: Postgres72.php,v 1.79 2005/05/02 15:47:26 chriskl Exp $ */ @@ -324,7 +324,9 @@ class Postgres72 extends Postgres71 { false AS proretset, format_type(p.prorettype, NULL) AS proresult, oidvectortypes(p.proargtypes) AS proarguments, - (SELECT description FROM pg_description pd WHERE p.oid=pd.objoid) AS procomment + (SELECT description FROM pg_description pd WHERE p.oid=pd.objoid) AS procomment, + p.proname || ' (' || oidvectortypes(p.proargtypes) || ')' AS proproto, + format_type(p.prorettype, NULL) AS proreturns FROM pg_proc p WHERE diff --git a/classes/database/Postgres73.php b/classes/database/Postgres73.php index 14f3b9bd..0ea905c1 100644 --- a/classes/database/Postgres73.php +++ b/classes/database/Postgres73.php @@ -4,7 +4,7 @@ * A class that implements the DB interface for Postgres * Note: This class uses ADODB and returns RecordSets. * - * $Id: Postgres73.php,v 1.142 2004/12/06 02:48:34 chriskl Exp $ + * $Id: Postgres73.php,v 1.143 2005/05/02 15:47:26 chriskl Exp $ */ // @@@ THOUGHT: What about inherits? ie. use of ONLY??? @@ -720,7 +720,9 @@ class Postgres73 extends Postgres72 { pg_catalog.format_type(p.prorettype, NULL) AS proresult, pg_catalog.oidvectortypes(p.proargtypes) AS proarguments, pl.lanname AS prolanguage, - pg_catalog.obj_description(p.oid, 'pg_proc') AS procomment + pg_catalog.obj_description(p.oid, 'pg_proc') AS procomment, + p.proname || ' (' || pg_catalog.oidvectortypes(p.proargtypes) || ')' AS proproto, + CASE WHEN p.proretset THEN 'setof ' ELSE '' END || pg_catalog.format_type(p.prorettype, NULL) AS proreturns FROM pg_catalog.pg_proc p INNER JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace INNER JOIN pg_catalog.pg_language pl ON pl.oid = p.prolang diff --git a/classes/database/Postgres80.php b/classes/database/Postgres80.php index 9d9855fc..abba2611 100644 --- a/classes/database/Postgres80.php +++ b/classes/database/Postgres80.php @@ -3,7 +3,7 @@ /** * PostgreSQL 8.0 support * - * $Id: Postgres80.php,v 1.12 2005/04/30 18:02:01 soranzo Exp $ + * $Id: Postgres80.php,v 1.13 2005/05/02 15:47:26 chriskl Exp $ */ include_once('./classes/database/Postgres74.php'); @@ -48,10 +48,12 @@ class Postgres80 extends Postgres74 { * @return A list of databases, sorted alphabetically */ function &getDatabases($currentdatabase = NULL) { - global $conf; - - if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($_SESSION['webdbUsername'])) { - $username = $_SESSION['webdbUsername']; + global $conf, $misc; + + $server_info = $misc->getServerInfo(); + + if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($server_info['username'])) { + $username = $server_info['username']; $this->clean($username); $clause = " AND pu.usename='{$username}'"; } diff --git a/constraints.php b/constraints.php index 85776870..0dcdd954 100644 --- a/constraints.php +++ b/constraints.php @@ -3,7 +3,7 @@ /** * List constraints on a table * - * $Id: constraints.php,v 1.40 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: constraints.php,v 1.41 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -478,13 +478,13 @@ $misc->printTable($constraints, $columns, $actions, $lang['strnoconstraints'], 'cnPre'); - echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=add_check&{$misc->href}&table=", urlencode($_REQUEST['table']), + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=add_check&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['straddcheck']}</a> |\n"; - echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=add_unique_key&{$misc->href}&table=", urlencode($_REQUEST['table']), + echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=add_unique_key&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['stradduniq']}</a> |\n"; - echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=add_primary_key&{$misc->href}&table=", urlencode($_REQUEST['table']), + echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=add_primary_key&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['straddpk']}</a> |\n"; - echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=add_foreign_key&{$misc->href}&table=", urlencode($_REQUEST['table']), + echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=add_foreign_key&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['straddfk']}</a></p>\n"; } diff --git a/conversions.php b/conversions.php index 7437e0dc..316bcb1a 100644 --- a/conversions.php +++ b/conversions.php @@ -3,7 +3,7 @@ /** * Manage conversions in a database * - * $Id: conversions.php,v 1.9 2004/09/01 16:35:58 jollytoad Exp $ + * $Id: conversions.php,v 1.10 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -54,7 +54,27 @@ $misc->printTable($conversions, $columns, $actions, $lang['strnoconversions']); } - + + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $conversions = &$data->getconversions(); + + $attrs = array( + 'text' => field('conname'), + 'icon' => 'conversions', + 'toolTip'=> field('concomment') + ); + + $misc->printTreeXML($conversions, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['strconversions']); $misc->printBody(); diff --git a/database.php b/database.php index a3726770..a3aee0ca 100755 --- a/database.php +++ b/database.php @@ -3,7 +3,7 @@ /** * Manage schemas within a database * - * $Id: database.php,v 1.65 2004/11/29 01:48:38 chriskl Exp $ + * $Id: database.php,v 1.66 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -318,7 +318,7 @@ } echo "</p>\n"; echo "<p><input type=\"hidden\" name=\"action\" value=\"export\" />\n"; - echo "<p><input type=\"hidden\" name=\"mode\" value=\"database\" />\n"; + echo "<input type=\"hidden\" name=\"subject\" value=\"database\" />\n"; echo $misc->form; echo "<input type=\"submit\" value=\"{$lang['strexport']}\" /></p>\n"; echo "</form>\n"; @@ -389,11 +389,13 @@ if ($data->hasSignals()) { $columns['actions'] = array('title' => $lang['stractions']); - + + $href = $misc->getHREF('schema'); + $actions = array( 'cancel' => array( 'title' => $lang['strcancel'], - 'url' => "{$PHP_SELF}?action=signal&signal=CANCEL&database=" . urlencode($_REQUEST['database']) . "&", + 'url' => "{$PHP_SELF}?action=signal&signal=CANCEL&{$href}&", 'vars' => array('procpid' => 'procpid') ) ); @@ -427,7 +429,7 @@ $status = $data->recluster(); if ($status == 0) doAdmin('', $lang['strclusteredgood']); else doAdmin('', $lang['strclusteredbad']); - break; + break; case 'reindex'; $status = $data->reindex('DATABASE', $_REQUEST['database'], isset($_REQUEST['reindex_force'])); if ($status == 0) doAdmin('', $lang['strreindexgood']); @@ -549,6 +551,7 @@ echo "<p>", sprintf($lang['strconfdropschema'], $misc->printVal($_REQUEST['schema'])), "</p>\n"; echo "<form action=\"{$PHP_SELF}\" method=\"post\">\n"; + echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; echo "<input type=\"hidden\" name=\"database\" value=\"", htmlspecialchars($_REQUEST['database']), "\" />\n"; echo "<input type=\"hidden\" name=\"schema\" value=\"", htmlspecialchars($_REQUEST['schema']), "\" />\n"; @@ -579,8 +582,10 @@ global $data, $misc; global $PHP_SELF, $lang; + $server_info = $misc->getServerInfo(); + if (!isset($_POST['formName'])) $_POST['formName'] = ''; - if (!isset($_POST['formAuth'])) $_POST['formAuth'] = $_SESSION['webdbUsername']; + if (!isset($_POST['formAuth'])) $_POST['formAuth'] = $server_info['username']; if (!isset($_POST['formSpc'])) $_POST['formSpc'] = ''; if (!isset($_POST['formComment'])) $_POST['formComment'] = ''; @@ -592,6 +597,7 @@ $misc->printMsg($msg); echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table width=\"100%\">\n"; echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n"; echo "\t\t<td class=\"data1\"><input name=\"formName\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", @@ -673,39 +679,107 @@ ), ); + $href = $misc->getHREF('schema'); + $actions = array( 'properties' => array( 'title' => $lang['strproperties'], - 'url' => "redirect.php?section=schema&database=".urlencode($_REQUEST['database'])."&", + 'url' => "redirect.php?subject=schema&{$href}&", 'vars' => array('schema' => 'nspname'), ), 'drop' => array( 'title' => $lang['strdrop'], - 'url' => "{$PHP_SELF}?action=confirm_drop&database=".urlencode($_REQUEST['database'])."&", + 'url' => "{$PHP_SELF}?action=confirm_drop&{$href}&", 'vars' => array('schema' => 'nspname'), ), 'privileges' => array( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?subject=schema&database=".urlencode($_REQUEST['database'])."&", + 'url' => "privileges.php?subject=schema&{$href}&", 'vars' => array('schema' => 'nspname'), ), 'alter' => array( 'title' => $lang['stralter'], - 'url' => "{$PHP_SELF}?action=alter_schema&database=".urlencode($_REQUEST['database'])."&", + 'url' => "{$PHP_SELF}?action=alter_schema&{$href}&", 'vars' => array('schema' => 'nspname'), ), ); $misc->printTable($schemas, $columns, $actions, $lang['strnoschemas']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?database=", urlencode($_REQUEST['database']), - "&action=create\">{$lang['strcreateschema']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$href}\">{$lang['strcreateschema']}</a></p>\n"; } else { // If the database does not support schemas... echo "<p>{$lang['strnoschemas']}</p>\n"; } } + function doTree() { + global $misc, $data, $lang, $PHP_SELF; + + $schemas = &$data->getSchemas(); + + $reqvars = $misc->getRequestVars('schema'); + + $attrs = array( + 'text' => field('nspname'), + 'icon' => 'folder', + 'toolTip'=> field('nspcomment'), + 'action' => url('redirect.php', + $reqvars, + array( + 'subject' => 'schema', + 'schema' => field('nspname') + ) + ), + 'branch' => url('database.php', + $reqvars, + array( + 'action' => 'subtree', + 'schema' => field('nspname') + ) + ) + ); + + $misc->printTreeXML($schemas, $attrs); + exit; + } + + function doSubTree() { + global $misc, $data, $lang; + + include_once('classes/ArrayRecordSet.php'); + $tabs = $misc->getNavTabs('schema'); + + // Remove Privileges link + unset($tabs['privileges']); + + // Remove hidden links + foreach ($tabs as $i => $tab) { + if (isset($tab['hide']) && $tab['hide'] === true) + unset($tabs[$i]); + } + $items =& new ArrayRecordSet($tabs); + + $reqvars = $misc->getRequestVars('schema'); + + $attrs = array( + 'text' => noEscape(field('title')), + 'icon' => field('icon', 'folder'), + 'action' => url(field('url'), + $reqvars, + field('urlvars', array()) + ), + 'branch' => url(field('url'), + $reqvars, + field('urlvars'), + array('action' => 'tree') + ) + ); + + $misc->printTreeXML($items, $attrs); + exit; + } + /** * Display a form to permit editing schema properies. * TODO: permit changing name, owner @@ -753,6 +827,9 @@ doAlterSchema($lang['strschemaalteredbad']); } + if ($action == 'tree') doTree(); + if ($action == 'subtree') doSubTree(); + $misc->printHeader($lang['strschemas']); $misc->printBody(); diff --git a/dataexport.php b/dataexport.php index 983cba88..fc9212f3 100644 --- a/dataexport.php +++ b/dataexport.php @@ -4,7 +4,7 @@ * Does an export to the screen or as a download. This checks to * see if they have pg_dump set up, and will use it if possible. * - * $Id: dataexport.php,v 1.19 2005/03/04 02:27:29 chriskl Exp $ + * $Id: dataexport.php,v 1.20 2005/05/02 15:47:23 chriskl Exp $ */ $extensions = array( @@ -23,28 +23,19 @@ // What must we do in this case? Maybe redirect to the homepage? // If format is set, then perform the export - if (isset($_REQUEST['what'])) { - + if (isset($_REQUEST['what'])) { + // Include application functions $_no_output = true; include_once('./libraries/lib.inc.php'); - + switch ($_REQUEST['what']) { case 'dataonly': // Check to see if they have pg_dump set up and if they do, use that // instead of custom dump code if ($misc->isDumpEnabled() && ($_REQUEST['d_format'] == 'copy' || $_REQUEST['d_format'] == 'sql')) { - $url = 'dbexport.php?mode=database&database=' . urlencode($_REQUEST['database']); - $url .= '&what=' . urlencode($_REQUEST['what']); - $url .= '&table=' . urlencode($_REQUEST['table']); - if ($data->hasSchemas()) $url .= '&schema=' . urlencode($_REQUEST['schema']); - $url .= '&d_format=' . urlencode($_REQUEST['d_format']); - $url .= '&output=' . urlencode($_REQUEST['output']); - if (isset($_REQUEST['d_oids'])) $url .= '&d_oids=' . urlencode($_REQUEST['d_oids']); - $url .= "&" . SID; - - header("Location: {$url}"); + include('./dbexport.php'); exit; } else { @@ -56,15 +47,7 @@ // Check to see if they have pg_dump set up and if they do, use that // instead of custom dump code if ($misc->isDumpEnabled()) { - $url = 'dbexport.php?mode=database&database=' . urlencode($_REQUEST['database']); - $url .= '&what=' . urlencode($_REQUEST['what']); - $url .= '&table=' . urlencode($_REQUEST['table']); - if ($data->hasSchemas()) $url .= '&schema=' . urlencode($_REQUEST['schema']); - $url .= '&output=' . urlencode($_REQUEST['output']); - if (isset($_REQUEST['s_clean'])) $url .= '&s_clean=' . urlencode($_REQUEST['s_clean']); - $url .= "&" . SID; - - header("Location: {$url}"); + include('./dbexport.php'); exit; } else $clean = isset($_REQUEST['s_clean']); @@ -73,17 +56,7 @@ // Check to see if they have pg_dump set up and if they do, use that // instead of custom dump code if ($misc->isDumpEnabled()) { - $url = 'dbexport.php?mode=database&database=' . urlencode($_REQUEST['database']); - $url .= '&what=' . urlencode($_REQUEST['what']); - $url .= '&table=' . urlencode($_REQUEST['table']); - if ($data->hasSchemas()) $url .= '&schema=' . urlencode($_REQUEST['schema']); - $url .= '&sd_format=' . urlencode($_REQUEST['sd_format']); - $url .= '&output=' . urlencode($_REQUEST['output']); - if (isset($_REQUEST['sd_clean'])) $url .= '&sd_clean=' . urlencode($_REQUEST['sd_clean']); - if (isset($_REQUEST['sd_oids'])) $url .= '&sd_oids=' . urlencode($_REQUEST['sd_oids']); - $url .= "&" . SID; - - header("Location: {$url}"); + include('./dbexport.php'); exit; } else { @@ -101,7 +74,7 @@ if (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE') && isset($_SERVER['HTTPS'])) { header('Content-Type: text/plain'); } - else {
+ else { header('Content-Type: application/download'); if (isset($extensions[$format])) @@ -118,6 +91,11 @@ if (isset($_REQUEST['query'])) $_REQUEST['query'] = trim(unserialize($_REQUEST['query'])); + // Set the schema search path + if ($data->hasSchemas() && isset($_REQUEST['search_path'])) { + $data->setSearchPath(array_map('trim',explode(',',$_REQUEST['search_path']))); + } + // Set up the dump transaction $status = $data->beginDump(); @@ -321,14 +299,14 @@ $status = $data->endDump(); } else { - if (!isset($msg)) $msg = null; - // Include application functions include_once('./libraries/lib.inc.php'); - $misc->printHeader($lang['strexport']); - echo "<h2>", $misc->printVal($_REQUEST['database']), ": {$lang['strexport']}</h2>\n"; - $misc->printMsg($msg); + $misc->printHeader($lang['strexport']); + $misc->printBody(); + $misc->printTrail(isset($_REQUEST['subject']) ? $_REQUEST['subject'] : 'database'); + $misc->printTitle($lang['strexport']); + if (isset($msg)) $misc->printMsg($msg); echo "<form action=\"{$_SERVER['PHP_SELF']}\" method=\"post\">\n"; echo "<table>\n"; @@ -355,6 +333,9 @@ echo "<input type=\"hidden\" name=\"table\" value=\"", htmlspecialchars($_REQUEST['table']), "\" />\n"; } echo "<input type=\"hidden\" name=\"query\" value=\"", htmlspecialchars(serialize($_REQUEST['query'])), "\" />\n"; + if (isset($_REQUEST['search_path'])) { + echo "<input type=\"hidden\" name=\"search_path\" value=\"", htmlspecialchars($_REQUEST['search_path']), "\" />\n"; + } echo $misc->form; echo "<input type=\"submit\" value=\"{$lang['strexport']}\" /></p>\n"; echo "</form>\n"; diff --git a/dbexport.php b/dbexport.php index b4c9662f..18cc0017 100644 --- a/dbexport.php +++ b/dbexport.php @@ -3,7 +3,7 @@ * Does an export of a database or a table (via pg_dump) * to the screen or as a download. * - * $Id: dbexport.php,v 1.20 2005/04/12 01:52:16 chriskl Exp $ + * $Id: dbexport.php,v 1.21 2005/05/02 15:47:23 chriskl Exp $ */ // Prevent timeouts on large exports (non-safe mode only) @@ -40,36 +40,32 @@ } // Set environmental variables that pg_dump uses - putenv('PGPASSWORD=' . $_SESSION['webdbPassword']); - putenv('PGUSER=' . $_SESSION['webdbUsername']); - $hostname = $conf['servers'][$_SESSION['webdbServerID']]['host']; + $server_info = $misc->getServerInfo(); + putenv('PGPASSWORD=' . $server_info['password']); + putenv('PGUSER=' . $server_info['username']); + $hostname = $server_info['host']; if ($hostname !== null && $hostname != '') { putenv('PGHOST=' . $hostname); } - $port = $conf['servers'][$_SESSION['webdbServerID']]['port']; + $port = $server_info['port']; if ($port !== null && $port != '') { putenv('PGPORT=' . $port); } - if ($_REQUEST['mode'] == 'database') { - putenv('PGDATABASE=' . $_REQUEST['database']); - } - // Check if we're doing a cluster-wide dump or just a per-database dump - if ($_REQUEST['mode'] == 'database') { - // Get path of the pg_dump executable. - $exe = $misc->escapeShellCmd($conf['servers'][$_SESSION['webdbServerID']]['pg_dump_path']); - } - else { - // Get path of the pg_dumpall executable. - $exe = $misc->escapeShellCmd($conf['servers'][$_SESSION['webdbServerID']]['pg_dumpall_path']); - } + // Are we doing a cluster-wide dump or just a per-database dump + $dumpall = ($_REQUEST['subject'] == 'server'); + + // Get the path og the pg_dump/pg_dumpall executable + $exe = $misc->escapeShellCmd($server_info[$dumpall ? 'pg_dumpall_path' : 'pg_dump_path']); // Build command for executing pg_dump. '-i' means ignore version differences. $cmd = $exe . " -i"; - // Check for a table specified - if (isset($_REQUEST['table']) && $_REQUEST['mode'] == 'database') { - + + // Check for a specified table/view + switch ($_REQUEST['subject']) { + case 'table': + case 'view': // Obtain the pg_dump version number $version = array(); preg_match("/(\d+(?:\.\d+)?)(?:\.\d+)?.*$/", exec($exe . " --version"), $version); @@ -78,7 +74,7 @@ // set dump schema as well. Also, mixed case dumping has been fixed // then.. if (((float) $version[1]) >= 7.4) { - $cmd .= " -t " . $misc->escapeShellArg($_REQUEST['table']); + $cmd .= " -t " . $misc->escapeShellArg($_REQUEST[$_REQUEST['subject']]); // Even though they're using a schema-enabled pg_dump, the backend database // may not support schemas. if ($data->hasSchemas()) { @@ -88,12 +84,12 @@ else { // This is an annoying hack needed to work around a bug in dumping // mixed case tables in pg_dump prior to 7.4 - $cmd .= " -t " . $misc->escapeShellArg('"' . $_REQUEST['table'] . '"'); + $cmd .= " -t " . $misc->escapeShellArg('"' . $_REQUEST[$_REQUEST['subject']] . '"'); } } // Check for GZIP compression specified - if ($_REQUEST['output'] == 'gzipped' && $_REQUEST['mode'] == 'database') { + if ($_REQUEST['output'] == 'gzipped' && !$dumpall) { $cmd .= " -Z 9"; } @@ -113,6 +109,10 @@ if (isset($_REQUEST['sd_clean'])) $cmd .= ' -c'; break; } + + if (!$dumpall) { + putenv('PGDATABASE=' . $_REQUEST['database']); + } // Execute command and return the output to the screen passthru($cmd); diff --git a/display.php b/display.php index 4ade6141..fa335c1d 100644 --- a/display.php +++ b/display.php @@ -9,7 +9,7 @@ * @param $return_desc The return link name * @param $page The current page * - * $Id: display.php,v 1.48 2005/03/04 02:27:38 chriskl Exp $ + * $Id: display.php,v 1.49 2005/05/02 15:47:23 chriskl Exp $ */ // Prevent timeouts on large exports (non-safe mode only) @@ -398,8 +398,10 @@ // Report views don't set a schema, so we need to disable create view in that case if (isset($_REQUEST['schema'])) echo " | <a class=\"navlink\" href=\"views.php?action=create&formDefinition=", urlencode($_REQUEST['query']), "&{$misc->href}\">{$lang['strcreateview']}</a>\n"; - echo " | <a class=\"navlink\" href=\"dataexport.php?query=", - urlencode($_REQUEST['query']), "&{$misc->href}\">{$lang['strdownload']}</a>\n"; + echo " | <a class=\"navlink\" href=\"dataexport.php?query=", urlencode($_REQUEST['query']); + if (isset($_REQUEST['search_path'])) + echo "&search_path=", urlencode($_REQUEST['search_path']); + echo "&{$misc->href}\">{$lang['strdownload']}</a>\n"; } // Insert diff --git a/domains.php b/domains.php index f9d5ef3a..aa1d33a5 100644 --- a/domains.php +++ b/domains.php @@ -3,7 +3,7 @@ /** * Manage domains in a database * - * $Id: domains.php,v 1.19 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: domains.php,v 1.20 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -424,6 +424,35 @@ echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=create&{$misc->href}\">{$lang['strcreatedomain']}</a></p>\n"; } + + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data, $PHP_SELF; + + $domains = &$data->getDomains(); + + $reqvars = $misc->getRequestVars('domain'); + + $attrs = array( + 'text' => field('domname'), + 'icon' => 'domains', + 'toolTip'=> field('domcomment'), + 'action' => url('domains.php', + $reqvars, + array( + 'action' => 'properties', + 'domain' => field('domname') + ) + ) + ); + + $misc->printTreeXML($domains, $attrs); + exit; + } + + if ($action == 'tree') doTree(); $misc->printHeader($lang['strdomains']); $misc->printBody(); diff --git a/functions.php b/functions.php index ded185b8..d24e0fad 100644 --- a/functions.php +++ b/functions.php @@ -3,7 +3,7 @@ /** * Manage functions in a database * - * $Id: functions.php,v 1.47 2004/09/18 11:59:40 soranzo Exp $ + * $Id: functions.php,v 1.48 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -470,12 +470,6 @@ global $data, $conf, $misc, $func; global $PHP_SELF, $lang; - function fnPre(&$rowdata) { - global $data; - $rowdata->f['+proproto'] = $rowdata->f['proname'] . " (" . $rowdata->f['proarguments'] . ")"; - $rowdata->f['+proreturns'] = ($data->phpBool($rowdata->f['proretset']) ? 'setof ' : '') . $rowdata->f['proresult']; - } - $misc->printTrail('schema'); $misc->printTabs('schema','functions'); $misc->printMsg($msg); @@ -485,12 +479,12 @@ $columns = array( 'function' => array( 'title' => $lang['strfunction'], - 'field' => '+proproto', + 'field' => 'proproto', 'type' => 'verbatim', ), 'returns' => array( 'title' => $lang['strreturns'], - 'field' => '+proreturns', + 'field' => 'proreturns', 'type' => 'verbatim', ), 'proglanguage' => array( @@ -509,33 +503,65 @@ $actions = array( 'properties' => array( 'title' => $lang['strproperties'], - 'url' => "redirect.php?section=function&action=properties&{$misc->href}&", - 'vars' => array('function' => '+proproto', 'function_oid' => 'prooid'), + 'url' => "redirect.php?subject=function&action=properties&{$misc->href}&", + 'vars' => array('function' => 'proproto', 'function_oid' => 'prooid'), ), 'alter' => array( 'title' => $lang['stralter'], 'url' => "{$PHP_SELF}?action=edit&{$misc->href}&", - 'vars' => array('function' => '+proproto', 'function_oid' => 'prooid'), + 'vars' => array('function' => 'proproto', 'function_oid' => 'prooid'), ), 'drop' => array( 'title' => $lang['strdrop'], 'url' => "{$PHP_SELF}?action=confirm_drop&{$misc->href}&", - 'vars' => array('function' => '+proproto', 'function_oid' => 'prooid'), + 'vars' => array('function' => 'proproto', 'function_oid' => 'prooid'), ), 'privileges' => array( 'title' => $lang['strprivileges'], 'url' => "privileges.php?{$misc->href}&subject=function&", - 'vars' => array('function' => '+proproto', 'function_oid' => 'prooid'), + 'vars' => array('function' => 'proproto', 'function_oid' => 'prooid'), ), ); - $misc->printTable($funcs, $columns, $actions, $lang['strnofunctions'], 'fnPre'); + $misc->printTable($funcs, $columns, $actions, $lang['strnofunctions']); echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=create&{$misc->href}\">{$lang['strcreateplfunction']}</a> | "; echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=create&language=internal&{$misc->href}\">{$lang['strcreateinternalfunction']}</a> | "; echo "<a class=\"navlink\" href=\"{$PHP_SELF}?action=create&language=C&{$misc->href}\">{$lang['strcreatecfunction']}</a></p>\n"; } + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $funcs = &$data->getFunctions(); + + $proto = concat(field('proname'),' (',field('proarguments'),')'); + + $reqvars = $misc->getRequestVars('function'); + + $attrs = array( + 'text' => $proto, + 'icon' => 'functions', + 'toolTip' => field('procomment'), + 'action' => url('redirect.php', + $reqvars, + array( + 'action' => 'properties', + 'function' => $proto, + 'function_oid' => field('prooid') + ) + ) + ); + + $misc->printTreeXML($funcs, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['strfunctions']); $misc->printBody(); @@ -3,7 +3,7 @@ /** * Manage groups in a database cluster * - * $Id: groups.php,v 1.19 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: groups.php,v 1.20 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -41,6 +41,7 @@ echo "<p>", sprintf($lang['strconfdropmember'], $misc->printVal($_REQUEST['user']), $misc->printVal($_REQUEST['group'])), "</p>\n"; echo "<form action=\"{$PHP_SELF}\" method=\"post\">\n"; + echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"drop_member\" />\n"; echo "<input type=\"hidden\" name=\"group\" value=\"", htmlspecialchars($_REQUEST['group']), "\" />\n"; echo "<input type=\"hidden\" name=\"user\" value=\"", htmlspecialchars($_REQUEST['user']), "\" />\n"; @@ -105,7 +106,7 @@ echo "<input type=\"hidden\" name=\"action\" value=\"add_member\" />\n"; echo "</form>\n"; - echo "<p><a class=\"navlink\" href=\"$PHP_SELF\">{$lang['strshowallgroups']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?{$misc->href}\">{$lang['strshowallgroups']}</a></p>\n"; } /** @@ -122,6 +123,7 @@ echo "<p>", sprintf($lang['strconfdropgroup'], $misc->printVal($_REQUEST['group'])), "</p>\n"; echo "<form action=\"{$PHP_SELF}\" method=\"post\">\n"; + echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; echo "<input type=\"hidden\" name=\"group\" value=\"", htmlspecialchars($_REQUEST['group']), "\" />\n"; echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; @@ -155,6 +157,7 @@ $misc->printMsg($msg); echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table>\n"; echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n"; echo "\t\t<td class=\"data\"><input size=\"32\" maxlength=\"{$data->_maxNameLen}\" name=\"name\" value=\"", htmlspecialchars($_POST['name']), "\" /></td>\n\t</tr>\n"; @@ -162,7 +165,7 @@ echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strmembers']}</th>\n"; echo "\t\t<td class=\"data\">\n"; - echo "\t\t\t<select name=\"members[]\" multiple=\"multiple\" size=\"", min(6, $users->recordCount()), "\">\n"; + echo "\t\t\t<select name=\"members[]\" multiple=\"multiple\" size=\"", min(40, $users->recordCount()), "\">\n"; while (!$users->EOF) { $username = $users->f['usename']; echo "\t\t\t\t<option value=\"{$username}\"", @@ -238,7 +241,7 @@ $misc->printTable($groups, $columns, $actions, $lang['strnogroups']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create\">{$lang['strcreategroup']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=create&{$misc->href}\">{$lang['strcreategroup']}</a></p>\n"; } diff --git a/images/themes/default/I.png b/images/themes/default/I.png Binary files differnew file mode 100644 index 00000000..f56e3054 --- /dev/null +++ b/images/themes/default/I.png diff --git a/images/themes/default/L.png b/images/themes/default/L.png Binary files differnew file mode 100644 index 00000000..825498bb --- /dev/null +++ b/images/themes/default/L.png diff --git a/images/themes/default/Lminus.png b/images/themes/default/Lminus.png Binary files differnew file mode 100644 index 00000000..2ed7a192 --- /dev/null +++ b/images/themes/default/Lminus.png diff --git a/images/themes/default/Lplus.png b/images/themes/default/Lplus.png Binary files differnew file mode 100644 index 00000000..b50e9bb9 --- /dev/null +++ b/images/themes/default/Lplus.png diff --git a/images/themes/default/T.png b/images/themes/default/T.png Binary files differnew file mode 100644 index 00000000..b127a8c4 --- /dev/null +++ b/images/themes/default/T.png diff --git a/images/themes/default/Tminus.png b/images/themes/default/Tminus.png Binary files differnew file mode 100644 index 00000000..ca962d8e --- /dev/null +++ b/images/themes/default/Tminus.png diff --git a/images/themes/default/Tplus.png b/images/themes/default/Tplus.png Binary files differnew file mode 100644 index 00000000..0f9859da --- /dev/null +++ b/images/themes/default/Tplus.png diff --git a/images/themes/default/blank.png b/images/themes/default/blank.png Binary files differnew file mode 100644 index 00000000..fa9a36d9 --- /dev/null +++ b/images/themes/default/blank.png diff --git a/images/themes/default/file.png b/images/themes/default/file.png Binary files differnew file mode 100644 index 00000000..5e274c4d --- /dev/null +++ b/images/themes/default/file.png diff --git a/images/themes/default/folder.png b/images/themes/default/folder.png Binary files differnew file mode 100644 index 00000000..a65d0317 --- /dev/null +++ b/images/themes/default/folder.png diff --git a/images/themes/default/folderOpen.png b/images/themes/default/folderOpen.png Binary files differnew file mode 100644 index 00000000..a13a2edc --- /dev/null +++ b/images/themes/default/folderOpen.png diff --git a/images/themes/default/loading.gif b/images/themes/default/loading.gif Binary files differnew file mode 100644 index 00000000..f3f1963a --- /dev/null +++ b/images/themes/default/loading.gif diff --git a/images/themes/default/root.png b/images/themes/default/root.png Binary files differnew file mode 100644 index 00000000..a65d0317 --- /dev/null +++ b/images/themes/default/root.png diff --git a/images/themes/default/title.png b/images/themes/default/title.png Binary files differindex 2015f307..99a58e36 100644 --- a/images/themes/default/title.png +++ b/images/themes/default/title.png @@ -3,33 +3,36 @@ /** * Main access point to the app. * - * $Id: index.php,v 1.11 2004/07/12 04:18:40 chriskl Exp $ + * $Id: index.php,v 1.12 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions + $_no_db_connection = true; include_once('./libraries/lib.inc.php'); $misc->printHeader(); + + $rtl = (strcasecmp($lang['applangdir'], 'rtl') == 0); + + $cols = $rtl ? '*,'.$conf['left_width'] : $conf['left_width'].',*'; + $mainframe = '<frame src="intro.php" name="detail" id="detail" frameborder="0" />' ?> -<frameset rows="52,*,12"> - <frame src="topbar.php" name="topbar" scrolling="no" noresize="noresize" frameborder="0" /> -<?php if (strcasecmp($lang['applangdir'], 'rtl') == 0) : ?> - <frameset cols="*,<?php echo $conf['left_width'] ?>"> - <frame src="intro.php" name="detail" frameborder="0" /> - <frame src="browser.php" name="browser" frameborder="0" /> - </frameset> -<?php else: ?> - <frameset cols="<?php echo $conf['left_width'] ?>,*"> - <frame src="browser.php" name="browser" frameborder="0" /> - <frame src="intro.php" name="detail" frameborder="0" /> - </frameset> -<?php endif; ?> - <frame src="bottombar.php" name="bottombar" scrolling="no" noresize="noresize" frameborder="0" /> +<frameset cols="<?php echo $cols ?>"> + +<?php if ($rtl) echo $mainframe; ?> + + <frame src="browser.php" name="browser" id="browser" frameborder="0" /> + +<?php if (!$rtl) echo $mainframe; ?> + <noframes> <body> - <?php echo $lang['strnoframes'] ?> + <?php echo $lang['strnoframes'] ?><br /> + <a href="intro.php"><?php echo $lang['strnoframeslink'] ?></a> </body> </noframes> + </frameset> + <?php $misc->printFooter(false); ?> diff --git a/indexes.php b/indexes.php index a3c1d7c7..06c33d38 100644 --- a/indexes.php +++ b/indexes.php @@ -3,7 +3,7 @@ /** * List indexes on a table * - * $Id: indexes.php,v 1.34 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: indexes.php,v 1.35 2005/05/02 15:47:23 chriskl Exp $ */ // Include application functions @@ -308,7 +308,7 @@ $misc->printTable($indexes, $columns, $actions, $lang['strnoindexes'], 'indPre'); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create_index&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['strcreateindex']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create_index&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['strcreateindex']}</a></p>\n"; } $misc->printHeader($lang['strindexes'], "<script src=\"indexes.js\" type=\"text/javascript\"></script>"); @@ -3,7 +3,7 @@ /** * Intro screen * - * $Id: intro.php,v 1.14 2005/01/17 10:09:43 jollytoad Exp $ + * $Id: intro.php,v 1.15 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions (no db conn) @@ -12,26 +12,39 @@ $misc->printHeader(); $misc->printBody(); + + $misc->printTrail('root'); + $misc->printTabs('root','intro'); ?> <h1><?php echo "$appName $appVersion (PHP ". phpversion() .')' ?></h1> -<p><?php echo $lang['strintro'] ?></p> - -<ul> -<li><b><a href="all_db.php"><?php echo $lang['strdatabases'] ?></a></b></li> -<li><b><a href="http://phppgadmin.sourceforge.net/" target="_top"><?php echo $lang['strppahome'] ?></a></b></li> -<li><b><a href="<?php echo $lang['strpgsqlhome_url'] ?>" target="_top"><?php echo $lang['strpgsqlhome'] ?></a></b></li> +<form method="get" action="<?php echo $_SERVER['PHP_SELF'] ?>"> + <label> + <select name="language" onchange="this.form.submit()"> <?php - //if ( isset($conf['docdir'])) { - // echo "<li><b><a href=\"". $conf['docdir'] ."\" target=\"_top\">"; - // echo $lang['strlocaldocs'] ."</a></b></li>"; - //} + $language = isset($_SESSION['webdbLanguage']) ? $_SESSION['webdbLanguage'] : 'english'; + foreach ($appLangFiles as $k => $v) { + echo "<option value=\"{$k}\"", + ($k == $language) ? ' selected="selected"' : '', + ">{$v}</option>\n"; + } ?> -<li><b><a href="http://sourceforge.net/tracker/?group_id=37132&atid=418980" target="_top"><?php echo $lang['strreportbug'] ?></a></b></li> -<li><b><a href="<?php echo $lang['strviewfaq_url'] ?>" target="_top"><?php echo $lang['strviewfaq'] ?></a></b></li> + </select> + <noscript><input type="submit" value="<?php echo $lang['stralter'] ?>" /></noscript> + </label> +</form> + +<p><?php echo $lang['strintro'] ?></p> + +<ul class="intro"> +<li><a href="http://phppgadmin.sourceforge.net/" target="_top"><?php echo $lang['strppahome'] ?></a></li> +<li><a href="<?php echo $lang['strpgsqlhome_url'] ?>" target="_top"><?php echo $lang['strpgsqlhome'] ?></a></li> +<li><a href="http://sourceforge.net/tracker/?group_id=37132&atid=418980" target="_top"><?php echo $lang['strreportbug'] ?></a></li> +<li><a href="<?php echo $lang['strviewfaq_url'] ?>" target="_top"><?php echo $lang['strviewfaq'] ?></a></li> </ul> <?php + if (isset($_GET['language'])) $_reload_browser = true; $misc->printFooter(); ?> diff --git a/lang/english.php b/lang/english.php index b9ccfb0e..157b7920 100755 --- a/lang/english.php +++ b/lang/english.php @@ -4,7 +4,7 @@ * English language file for phpPgAdmin. Use this as a basis * for new translations. * - * $Id: english.php,v 1.174 2005/04/30 18:02:02 soranzo Exp $ + * $Id: english.php,v 1.175 2005/05/02 15:47:27 chriskl Exp $ */ // Language and character set @@ -29,6 +29,10 @@ $lang['strloginfailed'] = 'Login failed'; $lang['strlogindisallowed'] = 'Login disallowed for security reasons.'; $lang['strserver'] = 'Server'; + $lang['strservers'] = 'Servers'; + $lang['strintroduction'] = 'Introduction'; + $lang['strhost'] = 'Host'; + $lang['strport'] = 'Port'; $lang['strlogout'] = 'Logout'; $lang['strowner'] = 'Owner'; $lang['straction'] = 'Action'; @@ -128,7 +132,8 @@ $lang['strfileimported'] = 'File imported.'; // Error handling - $lang['strnoframes'] = 'You need a frames-enabled browser to use this application.'; + $lang['strnoframes'] = 'This application works best with a frames-enabled browser, but can be used without frames by following the link below.'; + $lang['strnoframeslink'] = 'Use without frames'; $lang['strbadconfig'] = 'Your config.inc.php is out of date. You will need to regenerate it from the new config.inc.php-dist.'; $lang['strnotloaded'] = 'Your PHP installation does not support PostgreSQL. You need to recompile PHP using the --with-pgsql configure option.'; $lang['strpostgresqlversionnotsupported'] = 'Version of PostgreSQL not supported. Please upgrade to version %s or later.'; @@ -639,5 +644,10 @@ $lang['strtimefmt'] = 'jS M, Y g:iA'; $lang['strhelp'] = 'Help'; $lang['strhelpicon'] = '?'; + $lang['strlogintitle'] = 'Login to %s'; + $lang['strlogoutmsg'] = 'Logged out of %s'; + $lang['strloading'] = 'Loading...'; + $lang['strerrorloading'] = 'Error Loading'; + $lang['strclicktoreload'] = 'Click to reload'; ?> diff --git a/lang/translations.php b/lang/translations.php new file mode 100644 index 00000000..4ff4d028 --- /dev/null +++ b/lang/translations.php @@ -0,0 +1,73 @@ +<?php + /** + * Supported Translations for phpPgAdmin + * + * $Id: translations.php,v 1.2 2005/05/02 15:47:27 chriskl Exp $ + */ + + + // List of language files, and encoded language name. + + $appLangFiles = array( + 'afrikaans' => 'Afrikaans', + 'arabic' => 'عربي', + 'chinese-tr' => '繁體中文', + 'chinese-sim' => '简体中文', + 'czech' => 'Česky', + 'danish' => 'Danish', + 'dutch' => 'Nederlands', + 'english' => 'English', + 'french' => 'Français', + 'german' => 'Deutsch', + 'hebrew' => 'Hebrew', + 'italian' => 'Italiano', + 'japanese' => '日本語', + 'hungarian' => 'Magyar', + 'mongol' => 'Mongolian', + 'polish' => 'Polski', + 'portuguese-br' => 'Português-Brasileiro', + 'romanian' => 'Română', + 'russian' => 'Русский', + 'slovak' => 'Slovensky', + 'swedish' => 'Svenska', + 'spanish' => 'Español', + 'turkish' => 'Türkçe', + 'ukrainian' => 'Укра╖нська' + ); + + + // ISO639 language code to language file mapping. + // See http://www.w3.org/WAI/ER/IG/ert/iso639.htm for language codes + + // If it's available 'language-country', but not general + // 'language' translation (eg. 'portuguese-br', but not 'portuguese') + // specify both 'la' => 'language-country' and 'la-co' => 'language-country'. + + $availableLanguages = array( + 'af' => 'afrikaans', + 'ar' => 'arabic', + 'zh' => 'chinese-tr', + 'zh-cn' => 'chinese-sim', + 'cs' => 'czech', + 'da' => 'danish', + 'nl' => 'dutch', + 'en' => 'english', + 'fr' => 'french', + 'de' => 'german', + 'he' => 'hebrew', + 'it' => 'italian', + 'ja' => 'japanese', + 'hu' => 'hungarian', + 'mn' => 'mongol', + 'pl' => 'polish', + 'pt' => 'portuguese-br', + 'pt-br' => 'portuguese-br', + 'ro' => 'romanian', + 'ru' => 'russian', + 'sk' => 'slovak', + 'sv' => 'swedish', + 'es' => 'spanish', + 'tr' => 'turkish', + 'uk' => 'ukrainian' + ); +?> diff --git a/libraries/decorator.inc.php b/libraries/decorator.inc.php new file mode 100644 index 00000000..3427f377 --- /dev/null +++ b/libraries/decorator.inc.php @@ -0,0 +1,206 @@ +<?php +// $Id: decorator.inc.php,v 1.2 2005/05/02 15:47:28 chriskl Exp $ + +// This group of functions and classes provides support for +// resolving values in a lazy manner (ie, as and when required) +// using the Decorator pattern. + +###TODO: Better documentation!!! + +// Construction functions: + +function field($fieldName, $default = null) { + return new FieldDecorator($fieldName, $default); +} + +function merge(/* ... */) { + return new ArrayMergeDecorator(func_get_args()); +} + +function concat(/* ... */) { + return new ConcatDecorator(func_get_args()); +} + +function callback($callback, $params = null) { + return new CallbackDecorator($callback, $params); +} + +function ifempty($value, $empty, $full = null) { + return new IfEmptyDecorator($value, $empty, $full); +} + +function url($base, $vars = null /* ... */) { + // If more than one array of vars is given, + // use an ArrayMergeDecorator to have them merged + // at value evaluation time. + if (func_num_args() > 2) { + $v = func_get_args(); + array_shift($v); + return new UrlDecorator($base, new ArrayMergeDecorator($v)); + } + return new UrlDecorator($base, $vars); +} + +function noEscape($value) { + if (is_a($value, 'Decorator')) { + $value->esc = false; + return $value; + } + return new Decorator($value, false); +} + +// Resolving functions: + +function value(&$var, &$fields, $esc = null) { + if (is_a($var, 'Decorator')) { + $val =& $var->value($fields); + if (!$var->esc) $esc = null; + } else { + $val =& $var; + } + if (is_string($val)) { + switch($esc) { + case 'xml': + return strtr($val, array( + '&' => '&', + "'" => ''', '"' => '"', + '<' => '<', '>' => '>' + )); + case 'html': + return htmlspecialchars($val); + case 'url': + return urlencode($val); + } + } + return $val; +} + +function value_xml(&$var, &$fields) { + return value($var, $fields, 'xml'); +} + +function value_xml_attr($attr, &$var, &$fields) { + $val = value($var, $fields, 'xml'); + if (!empty($val)) + return " {$attr}=\"{$val}\""; + else + return ''; +} + +function value_url(&$var, &$fields) { + return value($var, $fields, 'url'); +} + +// Underlying classes: + +class Decorator +{ + var $esc = true; + + function Decorator($value, $esc = true) { + $this->v = $value; + $this->esc = $esc; + } + + function value() { + return $this->v; + } +} + +class FieldDecorator extends Decorator +{ + function FieldDecorator($fieldName, $default = null) { + $this->f = $fieldName; + if ($default !== null) $this->d = $default; + } + + function value($fields) { + return isset($fields[$this->f]) ? $fields[$this->f] : (isset($this->d) ? $this->d : null); + } +} + +class ArrayMergeDecorator extends Decorator +{ + function ArrayMergeDecorator($arrays) { + $this->m = $arrays; + } + + function value($fields) { + $accum = array(); + foreach($this->m as $var) { + $accum = array_merge($accum, value($var, $fields)); + } + return $accum; + } +} + +class ConcatDecorator extends Decorator +{ + function ConcatDecorator($values) { + $this->c = $values; + } + + function value($fields) { + $accum = ''; + foreach($this->c as $var) { + $accum .= value($var, $fields); + } + return $accum; + } +} + +class CallbackDecorator extends Decorator +{ + function CallbackDecorator($callback, $param = null) { + $this->fn = $callback; + $this->p = $param; + } + + function value($fields) { + return call_user_func($this->fn, $fields, $this->p); + } +} + +class IfEmptyDecorator extends Decorator +{ + function IfEmptyDecorator($value, $empty, $full = null) { + $this->v = $value; + $this->e = $empty; + if ($full !== null) $this->f = $full; + } + + function value($fields) { + $val = value($this->v, $fields); + if (empty($val)) + return value($this->e, $fields); + else + return isset($this->f) ? value($this->f, $fields) : $val; + } +} + +class UrlDecorator extends Decorator +{ + function UrlDecorator($base, $queryVars = null) { + $this->b = $base; + if ($queryVars !== null) + $this->q = $queryVars; + } + + function value($fields) { + $url = value($this->b, $fields); + + if ($url === false) return ''; + + if (!empty($this->q)) { + $queryVars = value($this->q, $fields); + + $sep = '?'; + foreach ($queryVars as $var => $value) { + $url .= $sep . value_url($var, $fields) . '=' . value_url($value, $fields); + $sep = '&'; + } + } + return $url; + } +} +?> diff --git a/libraries/errorhandler.inc.php b/libraries/errorhandler.inc.php index 2e7b1d0e..5afdaeb2 100644 --- a/libraries/errorhandler.inc.php +++ b/libraries/errorhandler.inc.php @@ -3,7 +3,7 @@ /** * Overrides default ADODB error handler to provide nicer error handling. * - * $Id: errorhandler.inc.php,v 1.16 2004/07/19 03:01:54 chriskl Exp $ + * $Id: errorhandler.inc.php,v 1.17 2005/05/02 15:47:28 chriskl Exp $ */ define('ADODB_ERROR_HANDLER','Error_Handler'); @@ -38,6 +38,8 @@ function Error_Handler($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false) case 'PCONNECT': case 'CONNECT': $_failed = true; + unset($_SESSION['webdbLogin'][$_REQUEST['server']]); + $msg = $lang['strloginfailed']; include('./login.php'); exit; break; diff --git a/libraries/lib.inc.php b/libraries/lib.inc.php index f18c1283..79ab4713 100644 --- a/libraries/lib.inc.php +++ b/libraries/lib.inc.php @@ -3,8 +3,10 @@ /** * Function library read in upon startup * - * $Id: lib.inc.php,v 1.93 2005/03/16 01:49:11 chriskl Exp $ + * $Id: lib.inc.php,v 1.94 2005/05/02 15:47:28 chriskl Exp $ */ + include_once('decorator.inc.php'); + include_once('./lang/translations.php'); // Set error reporting level to max error_reporting(E_ALL); @@ -38,36 +40,6 @@ // backwards incompatible changes are made to config.inc.php-dist. $conf['base_version'] = 14; - // List of available language files. Remember to update login.php - // when you update this list. - $appLangFiles = array( - 'afrikaans' => 'Afrikaans', - 'arabic' => 'عربي', - 'chinese-tr' => '繁體中文', - 'chinese-sim' => '简体中文', - 'czech' => 'Česky', - 'danish' => 'Danish', - 'dutch' => 'Nederlands', - 'english' => 'English', - 'french' => 'Français', - 'german' => 'Deutsch', - 'hebrew' => 'Hebrew', - 'italian' => 'Italiano', - 'japanese' => '日本語', - 'hungarian' => 'Magyar', - 'mongol' => 'Mongolian', - 'polish' => 'Polski', - 'portuguese-br' => 'Português-Brasileiro', - 'portuguese-pt' => 'Português-Português', - 'romanian' => 'Română', - 'russian' => 'Русский', - 'slovak' => 'Slovensky', - 'swedish' => 'Svenska', - 'spanish' => 'Español', - 'turkish' => 'Türkçe', - 'ukrainian' => 'Укра╖нська' - ); - // Always include english.php, since it's the master language file if (!isset($conf['default_lang'])) $conf['default_lang'] = 'english'; $lang = array(); @@ -102,32 +74,64 @@ ini_set('arg_separator.output', '&'); // If login action is set, then set session variables - if (isset($_POST['formServer']) && isset($_POST['formUsername']) && - isset($_POST['formPassword']) && isset($_POST['formLanguage'])) { - $_SESSION['webdbServerID'] = $_POST['formServer']; - $_SESSION['webdbUsername'] = $_POST['formUsername']; - $_SESSION['webdbPassword'] = $_POST['formPassword']; - $_SESSION['webdbLanguage'] = $_POST['formLanguage']; + if (isset($_POST['loginServer']) && isset($_POST['loginUsername']) && + isset($_POST['loginPassword'])) { + + $_server_info = $misc->getServerInfo($_POST['loginServer']); + + $_server_info['username'] = $_POST['loginUsername']; + $_server_info['password'] = $_POST['loginPassword']; + + $misc->setServerInfo(null, $_server_info, $_POST['loginServer']); + + $_reload_browser = true; } - // If the logged in settings aren't present, put up the login screen. - if (!isset($_SESSION['webdbUsername']) - || !isset($_SESSION['webdbPassword']) - || !isset($_SESSION['webdbServerID']) - || !isset($_SESSION['webdbLanguage']) - || !isset($conf['servers'][$_SESSION['webdbServerID']])) { - include('./login.php'); - exit; + // Determine language file to import: + + // 1. Check for the language from a request var + if (isset($_REQUEST['language'])) { + $_language = strtolower($_REQUEST['language']); + if (!isset($appLangFiles[$_language])) + unset($_language); } - - // Import language file - include('./lang/recoded/' . strtolower($_SESSION['webdbLanguage']) . '.php'); - - // If extra login check fails, back to the login screen - $_allowed = $misc->checkExtraSecurity(); - if (!$_allowed) { - include('./login.php'); - exit; + + // 2. Check for language session var + if (!isset($_language) && isset($_SESSION['webdbLanguage']) && isset($appLangFiles[$_SESSION['webdbLanguage']])) { + $_language = $_SESSION['webdbLanguage']; + } + + // 3. Check for acceptable languages in HTTP_ACCEPT_LANGUAGE var + if (!isset($_language) && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + // extract acceptable language tags + // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4) + preg_match_all('/\s*([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;q=([01](?:.[0-9]{0,3})?))?\s*(?:,|$)/', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']), $_m, PREG_SET_ORDER); + foreach($_m as $_l) { // $_l[1] = language tag, [2] = quality + if (!isset($_l[2])) $_l[2] = 1; // Default quality to 1 + if ($_l[2] > 0 && $_l[2] <= 1 && isset($availableLanguages[$_l[1]])) { + // Build up array of (quality => language_file) + $_acceptLang[$_l[2]] = $availableLanguages[$_l[1]]; + } + } + unset($_m); + unset($_l); + if (isset($_acceptLang)) { + // Sort acceptable languages by quality + krsort($_acceptLang, SORT_NUMERIC); + $_language = reset($_acceptLang); + unset($_acceptLang); + } + } + + // 4. Otherwise resort to the default set in the config file + if (!isset($_language) && isset($appLangFiles[$conf['default_lang']])) { + $_language = $conf['default_lang']; + } + + // Import the language file + if (isset($_language)) { + include("./lang/recoded/{$_language}.php"); + $_SESSION['webdbLanguage'] = $_language; } // Check database support is properly compiled in @@ -138,36 +142,30 @@ // Create data accessor object, if necessary if (!isset($_no_db_connection)) { + if (!isset($_REQUEST['server'])) { + die('No server supplied!'); + # TODO: nice error + } + + $_server_info = $misc->getServerInfo(); + + // Redirect to the login form if not logged in + if (!isset($_server_info['username'])) { + include('./login.php'); + exit; + } + // Connect to the current database, or if one is not specified // then connect to the default database. if (isset($_REQUEST['database'])) $_curr_db = $_REQUEST['database']; else - $_curr_db = $conf['servers'][$_SESSION['webdbServerID']]['defaultdb']; + $_curr_db = $_server_info['defaultdb']; - // Create the connection object and make the connection include_once('./classes/database/Connection.php'); - $_connection = new Connection( - $conf['servers'][$_SESSION['webdbServerID']]['host'], - $conf['servers'][$_SESSION['webdbServerID']]['port'], - $_SESSION['webdbUsername'], - $_SESSION['webdbPassword'], - $_curr_db - ); - - // Get the name of the database driver we need to use. The description - // of the server is returned and placed into the conf array. - $_type = $_connection->getDriver($conf['description']); - if ($_type === null) { - printf($lang['strpostgresqlversionnotsupported'], $postgresqlMinVer); - exit; - } - - // Create a database wrapper class for easy manipulation of the - // connection. - require_once('./classes/database/' . $_type . '.php'); - $data = new $_type($_connection->conn); - $data->platform = $_connection->platform; + + // Connect to database and set the global $data variable + $data =& $misc->getDatabaseAccessor($_curr_db); // If schema is defined and database supports schemas, then set the // schema explicitly. @@ -3,175 +3,51 @@ /** * Login screen * - * $Id: login.php,v 1.24 2005/03/16 01:48:59 chriskl Exp $ + * $Id: login.php,v 1.25 2005/05/02 15:47:24 chriskl Exp $ */ // This needs to be an include once to prevent lib.inc.php infinite recursive includes. // Check to see if the configuration file exists, if not, explain require_once('./libraries/lib.inc.php'); + + $misc->printHeader($lang['strlogin']); + $misc->printBody(); + $misc->printTrail('root'); + + $server_info = $misc->getServerInfo($_REQUEST['server']); + + $misc->printTitle(sprintf($lang['strlogintitle'], $server_info['desc'])); + + $loginServer = htmlspecialchars($_REQUEST['server']); + $loginUsername = ''; + + if (isset($msg)) $misc->printMsg($msg); +?> - // Prepare form variables - if (!isset($_POST['formServer'])) $_POST['formServer'] = ''; - if (!isset($_POST['formLanguage'])) { - // Parse the user acceptable language in HTTP_ACCEPT_LANGUAGE - // ( http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 ) - // If there's one available, then overwrite the default language. - if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $userLanguage = ''; - $userLanguages = array(); - $acceptableLanguages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); - foreach ($acceptableLanguages as $accLang) { - $languageInfos = explode(';', trim($accLang)); - $languageRange = strtolower($languageInfos[0]); - if (isset($languageInfos[1]) && substr($languageInfos[1], 0, 2) == 'q=') - $languageQuality = (float)substr($languageInfos[1], 2, 5); - else - $languageQuality = 1; - // If the language is already in the array, check that we - // don't overwrite its quality value with a lower one - if ((!array_key_exists($languageRange, $userLanguages)) - || ($userLanguages[$languageRange] < $languageQuality)) - $userLanguages[$languageRange] = $languageQuality; - } - arsort($userLanguages, SORT_NUMERIC); - - // if it's available 'language-country', but not general 'language' translation - // (eg. 'portuguese-br', but not 'portuguese') - // specify both 'la' => 'language-country' and 'la-co' => 'language-country'. - // See http://www.w3.org/WAI/ER/IG/ert/iso639.htm for language codes - $availableLanguages = array( - 'af' => 'afrikaans', - 'ar' => 'arabic', - 'zh' => 'chinese-tr', - 'zh-cn' => 'chinese-sim', - 'cs' => 'czech', - 'da' => 'danish', - 'nl' => 'dutch', - 'en' => 'english', - 'fr' => 'french', - 'de' => 'german', - 'he' => 'hebrew', - 'it' => 'italian', - 'ja' => 'japanese', - 'hu' => 'hungarian', - 'mn' => 'mongol', - 'pl' => 'polish', - 'pt' => 'portuguese-pt', - 'pt-br' => 'portuguese-br', - 'pt-pt' => 'portuguese-pt', - 'ro' => 'romanian', - 'ru' => 'russian', - 'sk' => 'slovak', - 'sv' => 'swedish', - 'es' => 'spanish', - 'tr' => 'turkish', - 'uk' => 'ukrainian' - ); - - reset($userLanguages); - do { - $languageRange = key($userLanguages); - if (array_key_exists($languageRange, $availableLanguages)) { - $userLanguage = $availableLanguages[$languageRange]; - } - } while ($userLanguage == '' && next($userLanguages)); - if ($userLanguage != '') $conf['default_lang'] = $userLanguage; - } - $_POST['formLanguage'] = $conf['default_lang']; - // Include default language over english. - include_once('./lang/recoded/' . strtolower($conf['default_lang']) . '.php'); - } - - // Check for config file version mismatch - if (!isset($conf['version']) || $conf['base_version'] > $conf['version']) { - echo $lang['strbadconfig']; - exit; - } - - // Force encoding to UTF-8 - $lang['appcharset'] = 'UTF-8'; - - // Output header - if (isset($_failed) && $_failed) { - $misc->printHeader($lang['strlogin'], "<script type=\"text/javascript\"><!-- - // show login form in top frame - if (top != self) { - window.top.location.href='./index.php?{$_SERVER['QUERY_STRING']}'; - } - //--> -</script>"); - } else { - $misc->printHeader($lang['strlogin']); +<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="post" name="login_form"> +<?php + if (!empty($_POST)) $vars =& $_POST; + else $vars =& $_GET; + // Pass request vars through form (is this a security risk???) + foreach ($vars as $key => $val) { + if (substr($key,0,5) == 'login') continue; + echo "<input type=\"hidden\" name=\"", htmlspecialchars($key), "\" value=\"", htmlspecialchars($val), "\" />\n"; } - $misc->printBody(); ?> + <input type="hidden" name="loginServer" value="<?php echo $loginServer; ?>" /> + <table class="navbar" border="0" cellpadding="5" cellspacing="3"> + <tr> + <td><?php echo $lang['strusername']; ?></td> + <td><input type="text" name="loginUsername" value="<?php echo $loginUsername; ?>" size="24" /></td> + </tr> + <tr> + <td><?php echo $lang['strpassword']; ?></td> + <td><input type="password" name="loginPassword" size="24" /></td> + </tr> + </table> + <p><input type="submit" name="loginSubmit" value="<?php echo $lang['strlogin']; ?>" /></p> +</form> - <table class="navbar" border="0" cellpadding="0" cellspacing="0" style="width: 100%; height: 100%"> - <tr> - <td height="115" align="center" valign="middle"> - <center> - <h1><?php echo $appName ?> <?php echo $appVersion ?> <?php echo $lang['strlogin'] ?></h1> - <?php - if (isset($_failed) && $_failed) - echo "<p class=\"message\">{$lang['strloginfailed']}</p>"; - elseif (isset($_allowed) && !$_allowed) { - echo "<p class=\"message\">{$lang['strlogindisallowed']}\n"; - echo "<br /><a href=\"{$lang['strviewfaq_url']}\">{$lang['strviewfaq']}</a></p>"; - } - ?> - <form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="post" name="login_form"> - <table class="navbar" border="0" cellpadding="5" cellspacing="3"> - <tr> - <th><?php echo $lang['strusername'] ?>:</th> - <td><input type="text" name="formUsername" value="<?php echo (isset($_POST['formUsername'])) ? htmlspecialchars($_POST['formUsername']) : '' ?>" size="24" /></td> - </tr> - <tr> - <th><?php echo $lang['strpassword'] ?>:</th> - <td><input type="password" name="formPassword" size="24" /></td> - </tr> - <tr> - <th><?php echo $lang['strserver'] ?>:</th> - <td><select name="formServer"> - <?php - for ($i = 0; $i < sizeof($conf['servers']); $i++) { - echo "<option value=\"{$i}\"", - ($i == $_POST['formServer']) ? ' selected="selected"' : '', - ">", htmlspecialchars($conf['servers'][$i]['desc']), "</option>\n"; - } - ?> - </select></td> - </tr> - <tr> - <th><?php echo $lang['strlanguage'] ?>:</th> - <td><select name="formLanguage"> - <?php - // Language name already encoded - foreach ($appLangFiles as $k => $v) { - echo "<option value=\"{$k}\"", - ($k == $_POST['formLanguage']) ? ' selected="selected"' : '', - ">{$v}</option>\n"; - } - ?> - </select></td> - </tr> - </table> - <p><input type="submit" name="submitLogin" value="<?php echo $lang['strlogin'] ?>" /></p> - </form> - </center> - <script type="text/javascript"> - <!-- - var uname = document.login_form.formUsername; - var pword = document.login_form.formPassword; - if (uname.value == "") { - uname.focus(); - } else { - pword.focus(); - } - //--> - </script> - </td> - </tr> - </table> <?php // Output footer $misc->printFooter(); diff --git a/opclasses.php b/opclasses.php index 99243582..5db50573 100644 --- a/opclasses.php +++ b/opclasses.php @@ -3,7 +3,7 @@ /** * Manage opclasss in a database * - * $Id: opclasses.php,v 1.6 2004/09/01 16:35:59 jollytoad Exp $ + * $Id: opclasses.php,v 1.7 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -53,7 +53,30 @@ $misc->printTable($opclasses, $columns, $actions, $lang['strnoopclasses']); } - + + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $opclasses = &$data->getOpClasses(); + + // OpClass prototype: "op_class/access_method" + $proto = concat(field('opcname'),'/',field('amname')); + + $attrs = array( + 'text' => $proto, + 'icon' => 'operators', + 'toolTip'=> field('opccomment'), + ); + + $misc->printTreeXML($opclasses, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['stropclasses']); $misc->printBody(); diff --git a/operators.php b/operators.php index 75300e26..5130a815 100644 --- a/operators.php +++ b/operators.php @@ -3,7 +3,7 @@ /** * Manage operators in a database * - * $Id: operators.php,v 1.17 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: operators.php,v 1.18 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -156,6 +156,42 @@ // echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}\">{$lang['strcreateoperator']}</a></p>\n"; } + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data, $PHP_SELF; + + $operators = &$data->getOperators(); + + // Operator prototype: "type operator type" + $proto = concat(field('oprleftname'), ' ', field('oprname'), ' ', field('oprrightname')); + + // Alternative prototype: "operator (type,type)" + #$proto = concat(field('oprname'), ' (', field('oprleftname','NONE'), ',', field('oprrightname','NONE'), ')'); + + $reqvars = $misc->getRequestVars('operator'); + + $attrs = array( + 'text' => $proto, + 'icon' => 'operators', + 'toolTip'=> field('oprcomment'), + 'action' => url('operators.php', + $reqvars, + array( + 'action' => 'properties', + 'operator' => $proto, + 'operator_oid' => field('oid') + ) + ) + ); + + $misc->printTreeXML($operators, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['stroperators']); $misc->printBody(); diff --git a/redirect.php b/redirect.php index b864a315..2e07187f 100644 --- a/redirect.php +++ b/redirect.php @@ -1,7 +1,12 @@ <?php + $subject = isset($_REQUEST['subject']) ? $_REQUEST['subject'] : 'root'; + + if ($subject == 'root') + $_no_db_connection = true; + include_once('./libraries/lib.inc.php'); - $url = parse_url($misc->getLastTabURL($_REQUEST['section'])); + $url = parse_url($misc->getLastTabURL($subject)); $_SERVER['PHP_SELF'] = $url['path']; diff --git a/reports.php b/reports.php index df78fe6c..05a24b3d 100644 --- a/reports.php +++ b/reports.php @@ -3,7 +3,7 @@ /** * List reports in a database * - * $Id: reports.php,v 1.19 2004/09/02 13:53:56 jollytoad Exp $ + * $Id: reports.php,v 1.20 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -37,6 +37,7 @@ $misc->printMsg($msg); echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table width=\"100%\">\n"; echo "<tr><th class=\"data left required\">{$lang['strname']}</th>\n"; echo "<td class=\"data1\"><input name=\"report_name\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", @@ -117,8 +118,8 @@ } else echo "<p>{$lang['strinvalidparam']}</p>\n"; - echo "<p><a class=\"navlink\" href=\"$PHP_SELF\">{$lang['strshowallreports']}</a> |\n"; - echo "<a class=\"navlink\" href=\"$PHP_SELF?action=edit&report_id={$report->f['report_id']}\">{$lang['stredit']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?{$misc->href}\">{$lang['strshowallreports']}</a> |\n"; + echo "<a class=\"navlink\" href=\"$PHP_SELF?action=edit&{$misc->href}&report_id={$report->f['report_id']}\">{$lang['stredit']}</a></p>\n"; } /** @@ -140,6 +141,7 @@ $misc->printMsg($msg); echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table width=\"100%\">\n"; echo "<tr><th class=\"data left required\">{$lang['strname']}</th>\n"; echo "<td class=\"data1\"><input name=\"report_name\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", @@ -210,6 +212,7 @@ echo "<p>", sprintf($lang['strconfdropreport'], $misc->printVal($report->f['report_name'])), "</p>\n"; echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; echo "<input type=\"hidden\" name=\"report_id\" value=\"", htmlspecialchars($_REQUEST['report_id']), "\" />\n"; echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; @@ -234,7 +237,7 @@ global $PHP_SELF, $lang; $misc->printTrail('server'); - $misc->printTitle($lang['strreports']); + $misc->printTabs('server','reports'); $misc->printMsg($msg); $reports = &$reportsdb->getReports(); @@ -261,32 +264,34 @@ ), ); + $return_url = urlencode("{$PHP_SELF}?{$misc->href}"); + $actions = array( 'properties' => array( 'title' => $lang['strproperties'], - 'url' => "{$PHP_SELF}?action=properties&", + 'url' => "{$PHP_SELF}?action=properties&{$misc->href}&", 'vars' => array('report_id' => 'report_id'), ), 'run' => array( 'title' => $lang['strrun'], - 'url' => "display.php?subject=report&return_url={$PHP_SELF}&return_desc=".urlencode($lang['strback'])."&", + 'url' => "display.php?subject=report&{$misc->href}&return_url={$return_url}&return_desc=".urlencode($lang['strback'])."&", 'vars' => array('report' => 'report_name', 'database' => 'db_name', 'query' => 'report_sql'), ), 'edit' => array( 'title' => $lang['stredit'], - 'url' => "{$PHP_SELF}?action=edit&", + 'url' => "{$PHP_SELF}?action=edit&{$misc->href}&", 'vars' => array('report_id' => 'report_id'), ), 'drop' => array( 'title' => $lang['strdrop'], - 'url' => "{$PHP_SELF}?action=confirm_drop&", + 'url' => "{$PHP_SELF}?action=confirm_drop&{$misc->href}&", 'vars' => array('report_id' => 'report_id'), ), ); $misc->printTable($reports, $columns, $actions, $lang['strnoreports']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create\">{$lang['strcreatereport']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=create&{$misc->href}\">{$lang['strcreatereport']}</a></p>\n"; } $misc->printHeader($lang['strreports']); @@ -296,7 +301,9 @@ include_once('./classes/Reports.php'); $reportsdb = new Reports($status); if ($status != 0) { - echo "<p>{$lang['strnoreportsdb']}</p>\n"; + $misc->printTrail('server'); + $misc->printTabs('server','reports'); + $misc->printMsg($lang['strnoreportsdb']); } else { switch ($action) { diff --git a/sequences.php b/sequences.php index ac4a8096..b5b27d1b 100644 --- a/sequences.php +++ b/sequences.php @@ -3,7 +3,7 @@ /** * Manage sequences in a database * - * $Id: sequences.php,v 1.27 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: sequences.php,v 1.28 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -69,6 +69,33 @@ } /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $sequences = &$data->getSequences(); + + $reqvars = $misc->getRequestVars('sequence'); + + $attrs = array( + 'text' => field('seqname'), + 'icon' => 'sequences', + 'toolTip'=> field('seqcomment'), + 'action' => url('sequences.php', + $reqvars, + array ( + 'action' => 'properties', + 'sequence' => field('seqname') + ) + ) + ); + + $misc->printTreeXML($sequences, $attrs); + exit; + } + + /** * Display the properties of a sequence */ function doProperties($msg = '') { @@ -250,6 +277,8 @@ doProperties($lang['strsequenceresetbad']); } + if ($action == 'tree') doTree(); + // Print header $misc->printHeader($lang['strsequences']); $misc->printBody(); diff --git a/servers.php b/servers.php new file mode 100644 index 00000000..ee1b65f8 --- /dev/null +++ b/servers.php @@ -0,0 +1,133 @@ +<?php + + /** + * Manage servers + * + * $Id: servers.php,v 1.2 2005/05/02 15:47:24 chriskl Exp $ + */ + + // Include application functions + $_no_db_connection = true; + include_once('./libraries/lib.inc.php'); + + $action = (isset($_REQUEST['action'])) ? $_REQUEST['action'] : ''; + if (!isset($msg)) $msg = ''; + $PHP_SELF = $_SERVER['PHP_SELF']; + + function doLogout() { + global $misc, $lang, $_reload_browser; + + $server_info = $misc->getServerInfo($_REQUEST['logoutServer']); + $misc->setServerInfo(null,null,$_REQUEST['logoutServer']); + doDefault(sprintf($lang['strlogoutmsg'], $server_info['desc'])); + + $_reload_browser = true; + } + + function doDefault($msg = '') { + global $conf, $misc; + global $PHP_SELF, $lang; + + $misc->printTabs('root','servers'); + $misc->printMsg($msg); + + $servers =& $misc->getServers(true); + + function svPre(&$rowdata, $actions) { + $actions['logout']['disable'] = empty($rowdata->f['username']); + return $actions; + } + + $columns = array( + 'server' => array( + 'title' => $lang['strserver'], + 'field' => 'desc', + ), + 'host' => array( + 'title' => $lang['strhost'], + 'field' => 'host', + ), + 'port' => array( + 'title' => $lang['strport'], + 'field' => 'port', + ), + 'username' => array( + 'title' => $lang['strusername'], + 'field' => 'username', + ), + 'actions' => array( + 'title' => $lang['stractions'], + ), + ); + + $actions = array( + 'properties' => array( + 'title' => $lang['strproperties'], + 'url' => "redirect.php?subject=server&", + 'vars' => array('server' => 'id'), + ), + 'logout' => array( + 'title' => $lang['strlogout'], + 'url' => "{$PHP_SELF}?action=logout&", + 'vars' => array('logoutServer' => 'id'), + ), + ); + + $misc->printTable($servers, $columns, $actions, $lang['strnoobjects'], 'svPre'); + } + + function doTree() { + global $misc; + + $servers =& $misc->getServers(true); + + $reqvars = $misc->getRequestVars('server'); + + $attrs = array( + 'text' => field('desc'), + + // Show different icons for logged in/out + 'icon' => ifempty(field('username'), 'serverOut', 'server'), + + 'toolTip'=> field('id'), + + 'action' => url('redirect.php', + $reqvars, + array('server' => field('id')) + ), + + // Only create a branch url if the user has + // logged into the server. + 'branch' => ifempty(field('username'), false, + url('all_db.php', + $reqvars, + array( + 'action' => 'tree', + 'server' => field('id') + ) + ) + ), + ); + + $misc->printTreeXML($servers, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + + $misc->printHeader($lang['strservers']); + $misc->printBody(); + $misc->printTrail('root'); + + switch ($action) { + case 'logout': + doLogout(); + break; + case 'tree': + default: + doDefault($msg); + break; + } + + $misc->printFooter(); +?> diff --git a/sqledit.php b/sqledit.php index 1480b95e..4fce2925 100644 --- a/sqledit.php +++ b/sqledit.php @@ -3,7 +3,7 @@ /** * Alternative SQL editing window * - * $Id: sqledit.php,v 1.25 2004/09/30 16:32:05 jollytoad Exp $ + * $Id: sqledit.php,v 1.26 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -14,29 +14,51 @@ $PHP_SELF = $_SERVER['PHP_SELF']; /** - * Private function to display list of databases + * Private function to display server and list of databases */ - function _printDatabases() { + function _printConnection() { global $data, $lang, $conf, $action, $misc; - + + // The javascript action on the select box reloads the + // popup whenever the server or database is changed. + // This ensures that the correct page encoding is used. + $onchange = "onchange=\"location.href='sqledit.php?action=" . + urlencode($action) . "&server=' + encodeURI(server.options[server.selectedIndex].value) + '&database=' + encodeURI(database.options[database.selectedIndex].value) + "; + + // The exact URL to reload to is different between SQL and Find mode, however. + if ($action == 'find') { + $onchange .= "'&term=' + encodeURI(term.value) + '&filter=' + encodeURI(filter.value) + '&" . SID . "'\">\n"; + } else { + $onchange .= "'&query=' + encodeURI(query.value) "; + if ($data->hasSchemas()) $onchange .= "+ '&search_path=' + encodeURI(search_path.value) "; + $onchange .= "+ (paginate.checked ? '&paginate=on' : '') + '&" . SID . "'\""; + } + + echo "<table width=\"100%\"><tr><td>\n"; + echo "<label>"; + $misc->printHelp($lang['strserver'], 'pg.server'); + echo ": <select name=\"server\" {$onchange}>\n"; + + $servers = $misc->getServers(); + foreach($servers as $info) { + if (empty($info['username'])) continue; + echo "<option value=\"", htmlspecialchars($info['id']), "\"", + ((isset($_REQUEST['server']) && $info['id'] == $_REQUEST['server'])) ? ' selected="selected"' : '', ">", + htmlspecialchars("{$info['desc']} ({$info['id']})"), "</option>\n"; + } + echo "</select>\n</td><td align=\"right\">\n"; + // Get the list of all databases $databases = &$data->getDatabases(); - if ($databases->recordCount() > 0) { - // The javascript action on the select box reloads the popup whenever the database is changed. - // This ensures that the correct page encoding is used. The exact URL to reload to is different - // between SQL and Find mode, however. - if ($action == 'sql') { - echo "<p>"; - $misc->printHelp($lang['strdatabase'], 'pg.database'); - echo ": <select name=\"database\" onChange=\"location.href='sqledit.php?action=" . - urlencode($action) . "&database=' + encodeURI(options[selectedIndex].value) + '&query=' + encodeURI(query.value) "; - if ($data->hasSchemas()) echo "+ '&search_path=' + encodeURI(search_path.value) "; - echo "+ (paginate.checked ? '&paginate=on' : '') + '&" . SID . "'\">\n"; - } - else - echo "<p>{$lang['strdatabase']}: <select name=\"database\" onChange=\"location.href='sqledit.php?action=" . - urlencode($action) . "&database=' + encodeURI(options[selectedIndex].value) + '&term=' + encodeURI(term.value) + '&filter=' + encodeURI(filter.value) + '&" . SID . "'\">\n"; + if ($databases->recordCount() > 0) { + // The javascript action on the select box reloads + // the popup whenever the database is changed. + // This ensures that the correct page encoding is used. + + echo "<label>"; + $misc->printHelp($lang['strdatabase'], 'pg.database'); + echo ": <select name=\"database\" {$onchange}>\n"; while (!$databases->EOF) { $dbname = $databases->f['datname']; @@ -48,10 +70,13 @@ echo "</select></label>\n"; } else { + $server_info = $misc->getServerInfo(); echo "<input type=\"hidden\" name=\"database\" value=\"", - htmlspecialchars($conf['servers'][$_SESSION['webdbServerID']]['defaultdb']), "\" />\n"; - } - } + htmlspecialchars($server_info['defaultdb']), "\" />\n"; + } + + echo "</td></tr></table>\n"; + } /** * Searches for a named database object @@ -59,14 +84,19 @@ function doFind() { global $PHP_SELF, $data, $misc; global $lang, $conf; - + if (!isset($_GET['term'])) $_GET['term'] = ''; if (!isset($_GET['filter'])) $_GET['filter'] = ''; - + + $misc->printHeader($lang['strfind']); + + // Bring to the front always + echo "<body onload=\"window.focus();\">\n"; + $misc->printTabs($misc->getNavTabs('popup'), 'find'); echo "<form action=\"database.php\" method=\"get\" target=\"detail\">\n<p>"; - _printDatabases(); + _printConnection(); echo "</p><p><input name=\"term\" value=\"", htmlspecialchars($_GET['term']), "\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" />\n"; @@ -98,7 +128,6 @@ echo "</select>\n"; echo "<input type=\"submit\" value=\"{$lang['strfind']}\" />\n"; - echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"find\" /></p>\n"; echo "</form>\n"; @@ -112,49 +141,45 @@ function doDefault() { global $PHP_SELF, $data, $misc; global $lang, $conf; - + if (!isset($_REQUEST['query'])) $_REQUEST['query'] = ''; - + + $misc->printHeader($lang['strsql']); + + // Bring to the front always + echo "<body onload=\"window.focus();\">\n"; + $misc->printTabs($misc->getNavTabs('popup'), 'sql'); - + echo "<form action=\"sql.php\" method=\"post\" target=\"detail\">\n<p>"; - - _printDatabases(); - + _printConnection(); + echo "</p>\n"; if ($data->hasSchemas()) { if (!isset($_REQUEST['search_path'])) $_REQUEST['search_path'] = implode(',',$data->getSearchPath()); - echo "\n<label>"; + echo "<p><label>"; $misc->printHelp($lang['strsearchpath'], 'pg.schema.search_path'); - echo ": <input type=\"text\" name=\"search_path\" size=\"30\" value=\"", - htmlspecialchars($_REQUEST['search_path']), "\" /></label>"; + echo ": <input type=\"text\" name=\"search_path\" size=\"50\" value=\"", + htmlspecialchars($_REQUEST['search_path']), "\" /></label></p>\n"; } - echo "</p>\n<textarea style=\"width: 100%;\" rows=\"10\" cols=\"50\" name=\"query\">", + echo "<textarea style=\"width: 100%;\" rows=\"10\" cols=\"50\" name=\"query\">", htmlspecialchars($_REQUEST['query']), "</textarea>\n"; echo "<label><input type=\"checkbox\" name=\"paginate\"", (isset($_REQUEST['paginate']) ? ' checked="checked"' : ''), " /> {$lang['strpaginate']}</label>\n"; - + echo "<p><input type=\"submit\" value=\"{$lang['strgo']}\" />\n"; if ($data->hasFullExplain()) { echo "<input type=\"submit\" name=\"explain\" value=\"{$lang['strexplain']}\" />\n"; echo "<input type=\"submit\" name=\"explain_analyze\" value=\"{$lang['strexplainanalyze']}\" />\n"; } echo "<input type=\"reset\" value=\"{$lang['strreset']}\" /></p>\n"; - - echo $misc->form; - echo "</form>\n"; // Default focus $misc->setFocus('forms[0].query'); } - $misc->printHeader($lang['strsql']); - - // Bring to the front always - echo "<body onLoad=\"window.focus();\">\n"; - switch ($action) { case 'find': doFind(); @@ -165,6 +190,9 @@ break; } + // Set the name of the window + $misc->setWindowName('sqledit'); + $misc->printFooter(); ?> @@ -3,7 +3,7 @@ /** * List tables in a database * - * $Id: tables.php,v 1.71 2005/03/18 19:51:56 xzilla Exp $ + * $Id: tables.php,v 1.72 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -222,7 +222,7 @@ * Ask for select parameters and perform select */ function doSelectRows($confirm, $msg = '') { - global $data, $misc; + global $data, $misc, $_no_output; global $lang; global $PHP_SELF; @@ -311,7 +311,7 @@ } if (sizeof($_POST['show']) == 0) - doSelectRows(true, $lang['strselectneedscol']); + doSelectRows(true, $lang['strselectneedscol']); else { // Generate query SQL $query = $data->getSelectSQL($_REQUEST['table'], array_keys($_POST['show']), @@ -320,6 +320,7 @@ $_REQUEST['return_url'] = "tables.php?action=confselectrows&{$misc->href}&table={$_REQUEST['table']}"; $_REQUEST['return_desc'] = $lang['strback']; + $_no_output = true; include('./display.php'); exit; } @@ -578,7 +579,7 @@ $actions = array( 'properties' => array( 'title' => $lang['strproperties'], - 'url' => "redirect.php?section=table&{$misc->href}&", + 'url' => "redirect.php?subject=table&{$misc->href}&", 'vars' => array('table' => 'relname'), ), 'browse' => array( @@ -620,6 +621,32 @@ echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}\">{$lang['strcreatetable']}</a></p>\n"; } + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $tables = &$data->getTables(); + + $reqvars = $misc->getRequestVars('table'); + + $attrs = array( + 'text' => field('relname'), + 'icon' => 'tables', + 'toolTip'=> field('relcomment'), + 'action' => url('redirect.php', + $reqvars, + array('table' => field('relname')) + ) + ); + + $misc->printTreeXML($tables, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['strtables']); $misc->printBody(); diff --git a/tablespaces.php b/tablespaces.php index c31c3fbd..3c96590d 100755 --- a/tablespaces.php +++ b/tablespaces.php @@ -3,7 +3,7 @@ /** * Manage tablespaces in a database cluster * - * $Id: tablespaces.php,v 1.6 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: tablespaces.php,v 1.7 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -35,6 +35,7 @@ if (!isset($_POST['owner'])) $_POST['owner'] = $tablespace->f['spcowner']; echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table>\n"; echo "<tr><th class=\"data left required\">{$lang['strname']}</th>\n"; echo "<td class=\"data1\">"; @@ -52,7 +53,6 @@ echo "</table>\n"; echo "<p><input type=\"hidden\" name=\"action\" value=\"save_edit\" />\n"; echo "<input type=\"hidden\" name=\"tablespace\" value=\"", htmlspecialchars($_REQUEST['tablespace']), "\" />\n"; - echo $misc->form; echo "<input type=\"submit\" name=\"alter\" value=\"{$lang['stralter']}\" />\n"; echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; echo "</form>\n"; @@ -98,6 +98,7 @@ echo "<p>", sprintf($lang['strconfdroptablespace'], $misc->printVal($_REQUEST['tablespace'])), "</p>\n"; echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; echo "<input type=\"hidden\" name=\"tablespace\" value=\"", htmlspecialchars($_REQUEST['tablespace']), "\" />\n"; echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; @@ -120,8 +121,10 @@ global $data, $misc, $spcname; global $PHP_SELF, $lang; + $server_info = $misc->getServerInfo(); + if (!isset($_POST['formSpcname'])) $_POST['formSpcname'] = ''; - if (!isset($_POST['formOwner'])) $_POST['formOwner'] = $_SESSION['webdbUsername']; + if (!isset($_POST['formOwner'])) $_POST['formOwner'] = $server_info['username']; if (!isset($_POST['formLoc'])) $_POST['formLoc'] = ''; // Fetch all users @@ -132,6 +135,7 @@ $misc->printMsg($msg); echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table>\n"; echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n"; echo "\t\t<td class=\"data1\"><input size=\"32\" name=\"formSpcname\" maxlength=\"{$data->_maxNameLen}\" value=\"", htmlspecialchars($_POST['formSpcname']), "\" /></td>\n\t</tr>\n"; @@ -205,27 +209,29 @@ ) ); + $href = $misc->getHREF('database'); + $actions = array( 'alter' => array( 'title' => $lang['stralter'], - 'url' => "{$PHP_SELF}?action=edit&", + 'url' => "{$PHP_SELF}?action=edit&{$href}&", 'vars' => array('tablespace' => 'spcname') ), 'drop' => array( 'title' => $lang['strdrop'], - 'url' => "{$PHP_SELF}?action=confirm_drop&", + 'url' => "{$PHP_SELF}?action=confirm_drop&{$href}&", 'vars' => array('tablespace' => 'spcname') ), 'privileges' => array( 'title' => $lang['strprivileges'], - 'url' => "privileges.php?subject=tablespace&", + 'url' => "privileges.php?subject=tablespace&{$href}&", 'vars' => array('tablespace' => 'spcname') ) ); $misc->printTable($tablespaces, $columns, $actions, $lang['strnotablespaces']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create\">{$lang['strcreatetablespace']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=create&{$href}\">{$lang['strcreatetablespace']}</a></p>\n"; } diff --git a/tblproperties.php b/tblproperties.php index a11982dd..29fbda33 100644 --- a/tblproperties.php +++ b/tblproperties.php @@ -3,7 +3,7 @@ /** * List tables in a database * - * $Id: tblproperties.php,v 1.62 2004/11/02 03:33:35 chriskl Exp $ + * $Id: tblproperties.php,v 1.63 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -70,7 +70,9 @@ echo "<td class=\"data1\">"; echo "<input name=\"name\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", htmlspecialchars($_POST['name']), "\" /></td></tr>\n"; - if ($data->hasAlterTableOwner() && $data->isSuperUser($_SESSION['webdbUsername'])) { + + $server_info = $misc->getServerInfo(); + if ($data->hasAlterTableOwner() && $data->isSuperUser($server_info['username'])) { echo "<tr><th class=\"data left required\">{$lang['strowner']}</th>\n"; echo "<td class=\"data1\"><select name=\"owner\">"; while (!$users->EOF) { @@ -166,6 +168,7 @@ echo "<p><input type=\"hidden\" name=\"action\" value=\"export\" />\n"; echo $misc->form; + echo "<input type=\"hidden\" name=\"subject\" value=\"table\" />\n"; echo "<input type=\"hidden\" name=\"table\" value=\"", htmlspecialchars($_REQUEST['table']), "\" />\n"; echo "<input type=\"submit\" value=\"{$lang['strexport']}\" /></p>\n"; echo "</form>\n"; @@ -585,14 +588,14 @@ echo "<ul>\n"; $return_url = urlencode("tblproperties.php?{$misc->href}&table={$_REQUEST['table']}"); - echo "\t<li><a href=\"display.php?{$misc->href}&table=", urlencode($_REQUEST['table']), "&subject=table&return_url={$return_url}&return_desc=", + echo "\t<li><a href=\"display.php?{$misc->href}&table=", urlencode($_REQUEST['table']), "&subject=table&return_url={$return_url}&return_desc=", urlencode($lang['strback']), "\">{$lang['strbrowse']}</a></li>\n"; - echo "\t<li><a href=\"tables.php?action=confselectrows&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strselect']}</a></li>\n"; - echo "\t<li><a href=\"tables.php?action=confinsertrow&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strinsert']}</a></li>\n"; - echo "\t<li><a href=\"tables.php?action=confirm_empty&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strempty']}</a></li>\n"; - echo "\t<li><a href=\"tables.php?action=confirm_drop&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strdrop']}</a></li>\n"; - echo "\t<li><a href=\"{$PHP_SELF}?action=add_column&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['straddcolumn']}</a></li>\n"; - echo "\t<li><a href=\"{$PHP_SELF}?action=confirm_alter&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['stralter']}</a></li>\n"; + echo "\t<li><a href=\"tables.php?action=confselectrows&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strselect']}</a></li>\n"; + echo "\t<li><a href=\"tables.php?action=confinsertrow&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strinsert']}</a></li>\n"; + echo "\t<li><a href=\"tables.php?action=confirm_empty&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strempty']}</a></li>\n"; + echo "\t<li><a href=\"tables.php?action=confirm_drop&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['strdrop']}</a></li>\n"; + echo "\t<li><a href=\"{$PHP_SELF}?action=add_column&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['straddcolumn']}</a></li>\n"; + echo "\t<li><a href=\"{$PHP_SELF}?action=confirm_alter&{$misc->href}&table=", urlencode($_REQUEST['table']),"\">{$lang['stralter']}</a></li>\n"; echo "</ul>\n"; } diff --git a/themes/default/global.css b/themes/default/global.css index 1e0dbb63..495f9d26 100644 --- a/themes/default/global.css +++ b/themes/default/global.css @@ -1,7 +1,7 @@ /** * Default style sheet * - * $Id: global.css,v 1.31 2004/11/02 11:46:53 soranzo Exp $ + * $Id: global.css,v 1.32 2005/05/02 15:47:28 chriskl Exp $ */ /** ELEMENTS */ @@ -15,14 +15,18 @@ body, td font-size: smaller; /*0.8em;*/ } -body.topbar +img { border: none; } + +div.logo { background-color: #CECF9C; margin: 0px; padding: 0px; font-family: arial, tahoma, verdana, helvetica, sans-serif, serif; font-size: smaller; /* 1em; */ + border: none; border-bottom: 2px solid #000000; + margin-bottom: 2px; } body.browser @@ -194,7 +198,7 @@ td.opbutton2 padding: 2px 1em; } -.trail +.trail, .topbar { margin-bottom: 2px; } @@ -221,6 +225,19 @@ td.opbutton2 background-color: #E6E6CC; } +.topbar { + border: 2px solid #CECF9C; + padding: 2px 1em; +} + +.topbar, .topbar td { + background-color: #CECF9C; +} + +.topbar .platform, .topbar .host, .topbar .username { + font-weight: bold; +} + a:active { color: #989973; @@ -306,8 +323,42 @@ pre.data font-size: 100%; } +.intro li +{ + font-weight: bold; +} + /* Syntax highlighting */ .comment {color: #008080} .keyword {color: #FF8000} .literal {color: #808080} +/* Browser Tree using XLoadTree 2 */ +.webfx-tree-row { + white-space: nowrap; + font: arial, tahoma, verdana, helvetica, sans-serif, serif; +} + +.webfx-tree-children { + background-repeat: repeat-y; + background-position-y: 1px !important; /* IE only */ +} + +.webfx-tree-row img { + vertical-align: middle; + height: 20px; +} + +.webfx-tree-icon { + width: 20px; + cursor: hand; + cursor: pointer; +} + +.webfx-tree-expand-icon { + width: 20px; +} + +.webfx-tree-hide-root { + display: none; +} diff --git a/topbar.php b/topbar.php deleted file mode 100755 index c9a9d06d..00000000 --- a/topbar.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php - - /** - * Top menu for phpPgAdmin - * - * $Id: topbar.php,v 1.25 2004/07/12 04:18:40 chriskl Exp $ - */ - - // Include application functions - include_once('./libraries/lib.inc.php'); - - // To prevent SQL popup windows from conflicting - $window_id = 'sqledit_' . urlencode($conf['servers'][$_SESSION['webdbServerID']]['host'] .'_' . $conf['servers'][$_SESSION['webdbServerID']]['port']); - - $misc->printHeader(); - $misc->printBody('topbar'); - $dbselected = isset($_REQUEST['database']) ? '&database=' . $_REQUEST['database'] : ''; -?> -<table width="100%" border="0" cellspacing="0" cellpadding="0" class="topbar" dir="ltr"> - <tr> - <td width="211" rowspan="2"><a href="intro.php" target="detail"><img style="border: none" src="images/themes/<?php echo $conf['theme'] ?>/title.png" width="211" height="50" alt="<?php echo htmlspecialchars($appName) ?>" title="<?php echo htmlspecialchars($appName) ?>" /></a></td> - <td class="topbar" width="5" rowspan="2"> </td> - <td class="topbar"> - <?php echo sprintf($lang['strtopbar'], htmlspecialchars($conf['description']), - htmlspecialchars($conf['servers'][$_SESSION['webdbServerID']]['host']), - htmlspecialchars($conf['servers'][$_SESSION['webdbServerID']]['port']), - htmlspecialchars($_SESSION['webdbUsername']), - date($lang['strtimefmt'])) ?></td> - </tr> - <tr> - <td class="topbar"> -<?php - // For superuser, show user and group admin. For normal user, show change password. - if ($data->isSuperUser($_SESSION['webdbUsername'])) : -?> - <a class="toplink" href="users.php" target="detail"><?php echo $lang['strusers'] ?></a> | - <a class="toplink" href="groups.php" target="detail"><?php echo $lang['strgroups'] ?></a> | -<?php - endif; -?> - <a class="toplink" href="users.php?action=account" target="detail"><?php echo $lang['straccount'] ?></a> | -<?php if ($data->hasTablespaces()) : ?> - <a class="toplink" href="tablespaces.php" target="detail"><?php echo $lang['strtablespaces'] ?></a> | -<?php endif; ?> -<?php if ($conf['show_reports']) : ?> - <a class="toplink" href="reports.php" target="detail"><?php echo $lang['strreports'] ?></a> | -<?php endif; ?> - <a class="toplink" href="sqledit.php" target="sqledit" onclick="window.open('sqledit.php?action=sql<?php echo $dbselected ?>&<?php echo SID ?>','<?php echo htmlspecialchars($window_id) ?>','toolbar=no,width=600,height=400,resizable=yes,scrollbars=no').focus(); return false;"><?php echo $lang['strsql'] ?></a> | - <a class="toplink" href="sqledit.php" target="sqledit" onclick="window.open('sqledit.php?action=find<?php echo $dbselected ?>&<?php echo SID ?>','<?php echo htmlspecialchars($window_id) ?>','toolbar=no,width=600,height=400,resizable=yes,scrollbars=no').focus(); return false;"><?php echo $lang['strfind'] ?></a> | - <a class="toplink" href="logout.php" target="_parent"><?php echo $lang['strlogout'] ?></a> - </td> - </tr> -</table> -<?php - $misc->printFooter(); -?> diff --git a/triggers.php b/triggers.php index c88e9775..4194178a 100644 --- a/triggers.php +++ b/triggers.php @@ -3,7 +3,7 @@ /** * List triggers on a table * - * $Id: triggers.php,v 1.25 2005/04/14 18:20:10 xzilla Exp $ + * $Id: triggers.php,v 1.26 2005/05/02 15:47:24 chriskl Exp $ */ // Include application functions @@ -245,7 +245,7 @@ $misc->printTable($triggers, $columns, $actions, $lang['strnotriggers'], 'tgPre'); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['strcreatetrigger']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}&table=", urlencode($_REQUEST['table']), "\">{$lang['strcreatetrigger']}</a></p>\n"; } $misc->printHeader($lang['strtables'] . ' - ' . $_REQUEST['table'] . ' - ' . $lang['strtriggers']); @@ -3,7 +3,7 @@ /** * Manage types in a database * - * $Id: types.php,v 1.25 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: types.php,v 1.26 2005/05/02 15:47:25 chriskl Exp $ */ // Include application functions @@ -27,14 +27,14 @@ $misc->printTitle($lang['strproperties'], 'pg.type'); $misc->printMsg($msg); + function attPre(&$rowdata) { + global $data; + $rowdata->f['+type'] = $data->formatType($rowdata->f['type'], $rowdata->f['atttypmod']); + } + if ($typedata->recordCount() > 0) { switch ($typedata->f['typtype']) { case 'c': - function attPre(&$rowdata) { - global $data; - $rowdata->f['+type'] = $data->formatType($rowdata->f['type'], $rowdata->f['atttypmod']); - } - $attrs = &$data->getTableAttributes($_REQUEST['type']); $columns = array( @@ -76,8 +76,8 @@ echo "</table>\n"; } - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?{$misc->href}\">{$lang['strshowalltypes']}</a></p>\n"; } - else + echo "<p><a class=\"navlink\" href=\"$PHP_SELF?{$misc->href}\">{$lang['strshowalltypes']}</a></p>\n"; + } else doDefault($lang['strinvalidparam']); } @@ -457,7 +457,36 @@ echo "</p>\n"; } - + + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $types = &$data->getTypes(); + + $reqvars = $misc->getRequestVars('type'); + + $attrs = array( + 'text' => field('basename'), + 'icon' => 'types', + 'toolTip'=> field('typcomment'), + 'action' => url('types.php', + $reqvars, + array( + 'action' => 'properties', + 'type' => field('basename') + ) + ) + ); + + $misc->printTreeXML($types, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['strtypes']); $misc->printBody(); @@ -3,7 +3,7 @@ /** * Manage users in a database cluster * - * $Id: users.php,v 1.29 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: users.php,v 1.30 2005/05/02 15:47:25 chriskl Exp $ */ // Include application functions @@ -23,11 +23,13 @@ global $data, $misc; global $PHP_SELF, $lang; - $userdata = &$data->getUser($_SESSION['webdbUsername']); - $_REQUEST['user'] = $_SESSION['webdbUsername']; + $server_info = $misc->getServerInfo(); + + $userdata = &$data->getUser($server_info['username']); + $_REQUEST['user'] = $server_info['username']; $misc->printTrail('user'); - $misc->printTitle($lang['straccount'],'pg.user'); + $misc->printTabs('server','account'); $misc->printMsg($msg); if ($userdata->recordCount() > 0) { @@ -46,7 +48,7 @@ } else echo "<p>{$lang['strnodata']}</p>\n"; - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=confchangepassword\">{$lang['strchangepassword']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=confchangepassword&{$misc->href}\">{$lang['strchangepassword']}</a></p>\n"; } /** @@ -55,9 +57,11 @@ function doChangePassword($confirm, $msg = '') { global $data, $misc; global $PHP_SELF, $lang, $conf; - + + $server_info = $misc->getServerInfo(); + if ($confirm) { - $_REQUEST['user'] = $_SESSION['webdbUsername']; + $_REQUEST['user'] = $server_info['username']; $misc->printTrail('user'); $misc->printTitle($lang['strchangepassword'],'pg.user.alter'); $misc->printMsg($msg); @@ -66,6 +70,7 @@ if (!isset($_POST['confirm'])) $_POST['confirm'] = ''; echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table>\n"; echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strpassword']}</th>\n"; echo "\t\t<td><input type=\"password\" name=\"password\" size=\"32\" value=\"", @@ -86,7 +91,7 @@ elseif ($_POST['password'] != $_POST['confirm']) doChangePassword(true, $lang['strpasswordconfirm']); else { - $status = $data->changePassword($_SESSION['webdbUsername'], + $status = $data->changePassword($server_info['username'], $_POST['password']); if ($status == 0) doAccount($lang['strpasswordchanged']); @@ -110,7 +115,8 @@ $userdata = &$data->getUser($_REQUEST['username']); if ($userdata->recordCount() > 0) { - $canRename = $data->hasUserRename() && ($_REQUEST['username'] != $_SESSION['webdbUsername']); + $server_info = $misc->getServerInfo(); + $canRename = $data->hasUserRename() && ($_REQUEST['username'] != $server_info['username']); $userdata->f['usesuper'] = $data->phpBool($userdata->f['usesuper']); $userdata->f['usecreatedb'] = $data->phpBool($userdata->f['usecreatedb']); @@ -123,6 +129,7 @@ } echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table>\n"; echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strusername']}</th>\n"; echo "\t\t<td class=\"data1\">", ($canRename ? "<input name=\"newname\" size=\"15\" value=\"" . htmlspecialchars($_POST['newname']) . "\" />" : $misc->printVal($userdata->f['usename'])), "</td>\n\t</tr>\n"; @@ -183,6 +190,7 @@ echo "<p>", sprintf($lang['strconfdropuser'], $misc->printVal($_REQUEST['username'])), "</p>\n"; echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; echo "<input type=\"hidden\" name=\"username\" value=\"", htmlspecialchars($_REQUEST['username']), "\" />\n"; echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; @@ -215,6 +223,7 @@ $misc->printMsg($msg); echo "<form action=\"$PHP_SELF\" method=\"post\">\n"; + echo $misc->form; echo "<table>\n"; echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strusername']}</th>\n"; echo "\t\t<td class=\"data1\"><input size=\"15\" name=\"formUsername\" value=\"", htmlspecialchars($_POST['formUsername']), "\" /></td>\n\t</tr>\n"; @@ -323,7 +332,7 @@ $misc->printTable($users, $columns, $actions, $lang['strnousers']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create\">{$lang['strcreateuser']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"{$PHP_SELF}?action=create&{$misc->href}\">{$lang['strcreateuser']}</a></p>\n"; } diff --git a/viewproperties.php b/viewproperties.php index cb52ba94..9d0ccab7 100755 --- a/viewproperties.php +++ b/viewproperties.php @@ -3,7 +3,7 @@ /** * List views in a database * - * $Id: viewproperties.php,v 1.13 2004/09/07 13:58:21 jollytoad Exp $ + * $Id: viewproperties.php,v 1.14 2005/05/02 15:47:25 chriskl Exp $ */ // Include application functions @@ -119,7 +119,8 @@ echo "<p><input type=\"hidden\" name=\"action\" value=\"export\" />\n"; echo $misc->form; - echo "<input type=\"hidden\" name=\"table\" value=\"", htmlspecialchars($_REQUEST['view']), "\" />\n"; + echo "<input type=\"hidden\" name=\"subject\" value=\"view\" />\n"; + echo "<input type=\"hidden\" name=\"view\" value=\"", htmlspecialchars($_REQUEST['view']), "\" />\n"; echo "<input type=\"submit\" value=\"{$lang['strexport']}\" /></p>\n"; echo "</form>\n"; } @@ -302,11 +303,11 @@ echo "<br />\n"; echo "<ul>\n"; - $return_url = urlencode("viewproperties.php?{$misc->href}&view=" . urlencode($_REQUEST['view'])); - echo "\t<li><a href=\"display.php?{$misc->href}&view=", urlencode($_REQUEST['view']), "&subject=view&return_url={$return_url}&return_desc=", + $return_url = urlencode("viewproperties.php?{$misc->href}&view=" . urlencode($_REQUEST['view'])); + echo "\t<li><a href=\"display.php?{$misc->href}&view=", urlencode($_REQUEST['view']), "&subject=view&return_url={$return_url}&return_desc=", urlencode($lang['strback']), "\">{$lang['strbrowse']}</a></li>\n"; - echo "\t<li><a href=\"views.php?action=confselectrows&{$misc->href}&view=", urlencode($_REQUEST['view']),"\">{$lang['strselect']}</a></li>\n"; - echo "\t<li><a href=\"views.php?action=confirm_drop&{$misc->href}&view=", urlencode($_REQUEST['view']),"\">{$lang['strdrop']}</a></li>\n"; + echo "\t<li><a href=\"views.php?action=confselectrows&{$misc->href}&view=", urlencode($_REQUEST['view']),"\">{$lang['strselect']}</a></li>\n"; + echo "\t<li><a href=\"views.php?action=confirm_drop&{$misc->href}&view=", urlencode($_REQUEST['view']),"\">{$lang['strdrop']}</a></li>\n"; echo "</ul>\n"; } @@ -3,7 +3,7 @@ /** * Manage views in a database * - * $Id: views.php,v 1.52 2005/01/23 12:42:35 soranzo Exp $ + * $Id: views.php,v 1.53 2005/05/02 15:47:25 chriskl Exp $ */ // Include application functions @@ -548,7 +548,7 @@ $actions = array( 'properties' => array( 'title' => $lang['strproperties'], - 'url' => "redirect.php?section=view&{$misc->href}&", + 'url' => "redirect.php?subject=view&{$misc->href}&", 'vars' => array('view' => 'relname'), ), 'browse' => array( @@ -578,11 +578,37 @@ $misc->printTable($views, $columns, $actions, $lang['strnoviews']); - echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}\">{$lang['strcreateview']}</a> |\n"; - echo "<a class=\"navlink\" href=\"$PHP_SELF?action=wiz_create&{$misc->href}\">{$lang['strcreateviewwiz']}</a></p>\n"; + echo "<p><a class=\"navlink\" href=\"$PHP_SELF?action=create&{$misc->href}\">{$lang['strcreateview']}</a> |\n"; + echo "<a class=\"navlink\" href=\"$PHP_SELF?action=wiz_create&{$misc->href}\">{$lang['strcreateviewwiz']}</a></p>\n"; } - + + /** + * Generate XML for the browser tree. + */ + function doTree() { + global $misc, $data; + + $views = &$data->getViews(); + + $reqvars = $misc->getRequestVars('view'); + + $attrs = array( + 'text' => field('relname'), + 'icon' => 'views', + 'toolTip'=> field('relcomment'), + 'action' => url('redirect.php', + $reqvars, + array('view' => field('relname')) + ) + ); + + $misc->printTreeXML($views, $attrs); + exit; + } + + if ($action == 'tree') doTree(); + $misc->printHeader($lang['strviews']); $misc->printBody(); diff --git a/xloadtree/xloadtree2.js b/xloadtree/xloadtree2.js new file mode 100644 index 00000000..23461327 --- /dev/null +++ b/xloadtree/xloadtree2.js @@ -0,0 +1,534 @@ +/*----------------------------------------------------------------------------\
+| XLoadTree 2 PRE RELEASE |
+| |
+| This is a pre release and redistribution is discouraged. |
+| Watch http://webfx.eae.net for the final version |
+| |
+|-----------------------------------------------------------------------------|
+| Created by Erik Arvidsson & Emil A Eklund |
+| (http://webfx.eae.net/contact.html#erik) |
+| (http://webfx.eae.net/contact.html#emil) |
+| For WebFX (http://webfx.eae.net/) |
+|-----------------------------------------------------------------------------|
+| A tree menu system for IE 5.5+, Mozilla 1.4+, Opera 7.5+ |
+|-----------------------------------------------------------------------------|
+| Copyright (c) 1999 - 2004 Erik Arvidsson & Emil A Eklund |
+|-----------------------------------------------------------------------------|
+| This software is provided "as is", without warranty of any kind, express or |
+| implied, including but not limited to the warranties of merchantability, |
+| fitness for a particular purpose and noninfringement. In no event shall the |
+| authors or copyright holders be liable for any claim, damages or other |
+| liability, whether in an action of contract, tort or otherwise, arising |
+| from, out of or in connection with the software or the use or other |
+| dealings in the software. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| This software is available under the three different licenses mentioned |
+| below. To use this software you must chose, and qualify, for one of those. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| The WebFX Non-Commercial License http://webfx.eae.net/license.html |
+| Permits anyone the right to use the software in a non-commercial context |
+| free of charge. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| The WebFX Commercial license http://webfx.eae.net/commercial.html |
+| Permits the license holder the right to use the software in a commercial |
+| context. Such license must be specifically obtained, however it's valid for |
+| any number of implementations of the licensed software. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| GPL - The GNU General Public License http://www.gnu.org/licenses/gpl.txt |
+| Permits anyone the right to use and modify the software without limitations |
+| as long as proper credits are given and the original and modified source |
+| code are included. Requires that the final product, software derivate from |
+| the original source or any software utilizing a GPL component, such as |
+| this, is also licensed under the GPL license. |
+|-----------------------------------------------------------------------------|
+| 2004-02-21 | Pre release distributed to a few selected tester |
+|-----------------------------------------------------------------------------|
+| Dependencies: xtree2.js Supplies the tree control |
+|-----------------------------------------------------------------------------|
+| Created 2003-??-?? | All changes are in the log above. | Updated 2004-02-21 |
+\----------------------------------------------------------------------------*/
+
+
+webFXTreeConfig.loadingText = "Loading...";
+webFXTreeConfig.loadingIcon = "images/loading.gif";
+webFXTreeConfig.errorIcon = "images/exclamation.16.gif";
+webFXTreeConfig.errorLoadingText = "Error Loading";
+webFXTreeConfig.reloadText = "Click to reload";
+
+
+function WebFXLoadTree(sText, sXmlSrc, oAction, sBehavior, sIcon, sOpenIcon)
+{
+ WebFXTree.call(this, sText, oAction, sBehavior, sIcon, sOpenIcon);
+
+ // setup default property values
+ this.src = sXmlSrc;
+ this.loading = !sXmlSrc;
+ this.loaded = !sXmlSrc;
+ this.errorText = "";
+
+ if (this.src)
+ {
+ /// add loading Item
+ this._loadingItem = WebFXLoadTree.createLoadingItem();
+ this.add(this._loadingItem);
+
+ if (this.getExpanded())
+ WebFXLoadTree.loadXmlDocument(this);
+ }
+}
+
+WebFXLoadTree.createLoadingItem = function ()
+{
+ return new WebFXTreeItem(webFXTreeConfig.loadingText, null, null,
+ webFXTreeConfig.loadingIcon);
+};
+
+WebFXLoadTree.prototype = new WebFXTree;
+
+WebFXLoadTree.prototype.setExpanded = function (b)
+{
+ WebFXTree.prototype.setExpanded.call(this, b);
+
+ if (this.src && b)
+ {
+ if (!this.loaded && !this.loading)
+ {
+ // load
+ WebFXLoadTree.loadXmlDocument(this);
+ }
+ }
+};
+
+function WebFXLoadTreeItem(sText, sXmlSrc, oAction, eParent, sIcon, sOpenIcon)
+{
+ WebFXTreeItem.call(this, sText, oAction, eParent, sIcon, sOpenIcon);
+
+// setup default property values
+ this.src = sXmlSrc;
+ this.loading = !sXmlSrc;
+ this.loaded = !sXmlSrc;
+ this.errorText = "";
+
+ if (this.src)
+ {
+ /// add loading Item
+ this._loadingItem = WebFXLoadTree.createLoadingItem();
+ this.add(this._loadingItem);
+
+ if (this.getExpanded())
+ WebFXLoadTree.loadXmlDocument(this);
+ }
+}
+
+WebFXLoadTreeItem.prototype = new WebFXTreeItem;
+
+WebFXLoadTreeItem.prototype.setExpanded = function (b)
+{
+ WebFXTreeItem.prototype.setExpanded.call(this, b);
+
+ if (this.src && b)
+ {
+ if (!this.loaded && !this.loading)
+ {
+ // load
+ WebFXLoadTree.loadXmlDocument(this);
+ }
+ }
+};
+
+// reloads the src file if already loaded
+WebFXLoadTree.prototype.reload =
+WebFXLoadTreeItem.prototype.reload = function ()
+{
+ // if loading do nothing
+ if (this.loaded)
+ {
+ var t = this.getTree();
+ var expanded = this.getExpanded();
+ var sr = t.getSuspendRedraw();
+ t.setSuspendRedraw(true);
+
+ // remove
+ while (this.childNodes.length > 0)
+ this.remove(this.childNodes[this.childNodes.length - 1]);
+
+ this.loaded = false;
+
+ this._loadingItem = WebFXLoadTree.createLoadingItem();
+ this.add(this._loadingItem);
+
+ if (expanded)
+ this.setExpanded(true);
+
+ t.setSuspendRedraw(sr);
+ this.update();
+ }
+ else if (this.open && !this.loading)
+ WebFXLoadTree.loadXmlDocument(this);
+};
+
+
+
+WebFXLoadTree.prototype.setSrc =
+WebFXLoadTreeItem.prototype.setSrc = function (sSrc)
+{
+ var oldSrc = this.src;
+ if (sSrc == oldSrc) return;
+
+ var expanded = this.getExpanded();
+
+ // remove all
+ this._callSuspended(function ()
+ {
+ // remove
+ while (this.childNodes.length > 0)
+ this.remove(this.childNodes[this.childNodes.length - 1]);
+ });
+ this.update();
+
+ this.loaded = false;
+ this.loading = false;
+ if (this._loadingItem)
+ {
+ this._loadingItem.dispose();
+ this._loadingItem = null;
+ }
+ this.src = sSrc;
+
+ if (sSrc)
+ {
+ this._loadingItem = WebFXLoadTree.createLoadingItem();
+ this.add(this._loadingItem);
+ }
+
+ this.setExpanded(expanded);
+};
+
+WebFXLoadTree.prototype.getSrc =
+WebFXLoadTreeItem.prototype.getSrc = function ()
+{
+ return this.src;
+};
+
+WebFXLoadTree.prototype.dispose = function ()
+{
+ WebFXTree.prototype.dispose.call(this);
+ if (this._xmlHttp)
+ {
+ if (this._xmlHttp.dispose)
+ this._xmlHttp.dispose();
+ try
+ {
+ this._xmlHttp.onreadystatechange = null;
+ this._xmlHttp.abort();
+ }
+ catch (ex) {}
+ this._xmlHttp = null;
+ }
+};
+
+WebFXLoadTreeItem.prototype.dispose = function ()
+{
+ WebFXTreeItem.prototype.dispose.call(this);
+ if (this._xmlHttp)
+ {
+ if (this._xmlHttp.dispose)
+ this._xmlHttp.dispose();
+ try
+ {
+ this._xmlHttp.onreadystatechange = null;
+ this._xmlHttp.abort();
+ }
+ catch (ex) {}
+ this._xmlHttp = null;
+ }
+};
+
+
+// The path is divided by '/' and the item is identified by the text
+WebFXLoadTree.prototype.openPath =
+WebFXLoadTreeItem.prototype.openPath = function (sPath, bSelect, bFocus)
+{
+ // remove any old pending paths to open
+ delete this._pathToOpen;
+ //delete this._pathToOpenById;
+ this._selectPathOnLoad = bSelect;
+ this._focusPathOnLoad = bFocus;
+
+ if (sPath == "")
+ {
+ if (bSelect)
+ this.select();
+ if (bFocus)
+ window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.getId() + "\")", 10);
+ return;
+ }
+
+ var parts = sPath.split("/");
+ var remainingPath = parts.slice(1).join("/");
+
+ if (sPath.charAt(0) == "/")
+ {
+ this.getTree().openPath(remainingPath, bSelect, bFocus);
+ }
+ else
+ {
+ // open
+ this.setExpanded(true);
+ if (this.loaded)
+ {
+ parts = sPath.split("/");
+ var ti = this.findChildByText(parts[0]);
+ if (!ti)
+ throw "Could not find child node with text \"" + parts[0] + "\"";
+
+ ti.openPath(remainingPath, bSelect, bFocus);
+ }
+ else
+ {
+ this._pathToOpen = sPath;
+ }
+ }
+};
+
+
+// Opera has some serious attribute problems. We need to use getAttribute
+// for certain attributes
+WebFXLoadTree._attrs = ["text", "src", "action", "id", "target"];
+
+WebFXLoadTree.createItemFromElement = function (oNode)
+{
+ var jsAttrs = {};
+ var domAttrs = oNode.attributes;
+ var i, l;
+
+ l = domAttrs.length;
+ for (i = 0; i < l; i++)
+ {
+ if (domAttrs[i] == null)
+ {
+ continue;
+ }
+ jsAttrs[domAttrs[i].nodeName] = domAttrs[i].nodeValue;
+ }
+
+
+ var name, val;
+ for (i = 0; i < WebFXLoadTree._attrs.length; i++)
+ {
+ name = WebFXLoadTree._attrs[i];
+ value = oNode.getAttribute(name);
+ if (value)
+ jsAttrs[name] = value;
+ }
+
+ var action;
+ if (jsAttrs.onaction)
+ action = new Function(jsAttrs.onaction);
+ else if (jsAttrs.action)
+ action = jsAttrs.action;
+ var jsNode = new WebFXLoadTreeItem(jsAttrs.html || "", jsAttrs.src, action,
+ null, jsAttrs.icon, jsAttrs.openIcon);
+ if (jsAttrs.text)
+ jsNode.setText(jsAttrs.text);
+
+ if (jsAttrs.target)
+ jsNode.target = jsAttrs.target;
+ if (jsAttrs.id)
+ jsNode.setId(jsAttrs.id);
+ if (jsAttrs.toolTip)
+ jsNode.toolTip = jsAttrs.toolTip;
+ if (jsAttrs.expanded)
+ jsNode.setExpanded(jsAttrs.expanded != "false");
+ if (jsAttrs.onload)
+ jsNode.onload = new Function(jsAttrs.onload);
+ if (jsAttrs.onerror)
+ jsNode.onerror = new Function(jsAttrs.onerror);
+
+ jsNode.attributes = jsAttrs;
+
+ // go through childNodes
+ var cs = oNode.childNodes;
+ l = cs.length;
+ for (i = 0; i < l; i++)
+ {
+ if (cs[i].tagName == "tree")
+ jsNode.add(WebFXLoadTree.createItemFromElement(cs[i]));
+ }
+
+ return jsNode;
+};
+
+WebFXLoadTree.loadXmlDocument = function (jsNode)
+{
+ if (jsNode.loading || jsNode.loaded)
+ return;
+ jsNode.loading = true;
+ var id = jsNode.getId();
+ jsNode._xmlHttp = XmlHttp.create();
+ jsNode._xmlHttp.open("GET", jsNode.src, true); // async
+ jsNode._xmlHttp.onreadystatechange = new Function("WebFXLoadTree._onload(\"" + id + "\")");
+
+ // call in new thread to allow ui to update
+ window.setTimeout("WebFXLoadTree._ontimeout(\"" + id + "\")", 10);
+};
+
+WebFXLoadTree._onload = function (sId)
+{
+ var jsNode = webFXTreeHandler.all[sId];
+ if (jsNode._xmlHttp.readyState == 4)
+ {
+ WebFXLoadTree.documentLoaded(jsNode);
+ webFXLoadTreeQueue.remove(jsNode);
+ if (jsNode._xmlHttp.dispose)
+ jsNode._xmlHttp.dispose();
+ jsNode._xmlHttp = null;
+ }
+};
+
+WebFXLoadTree._ontimeout = function (sId)
+{
+ var jsNode = webFXTreeHandler.all[sId];
+ webFXLoadTreeQueue.add(jsNode);
+};
+
+
+
+// Inserts an xml document as a subtree to the provided node
+WebFXLoadTree.documentLoaded = function (jsNode)
+{
+ if (jsNode.loaded)
+ return;
+
+ jsNode.errorText = "";
+ jsNode.loaded = true;
+ jsNode.loading = false;
+
+ var t = jsNode.getTree();
+ var oldSuspend = t.getSuspendRedraw();
+ t.setSuspendRedraw(true);
+
+ var doc = jsNode._xmlHttp.responseXML;
+
+ // check that the load of the xml file went well
+ if(!doc || doc.parserError && doc.parseError.errorCode != 0 || !doc.documentElement)
+ {
+ if (!doc || doc.parseError.errorCode == 0)
+ {
+ jsNode.errorText = webFXTreeConfig.errorLoadingText + " " + jsNode.src + " (" + jsNode._xmlHttp.status + ": " + jsNode._xmlHttp.statusText + ")";
+ }
+ else
+ {
+ jsNode.errorText = webFXTreeConfig.errorLoadingText + " " + jsNode.src + " (" + doc.parseError.reason + ")";
+ }
+ }
+ else
+ {
+ // there is one extra level of tree elements
+ var root = doc.documentElement;
+
+ // loop through all tree children
+ var count = 0;
+ var cs = root.childNodes;
+ var l = cs.length;
+ for (var i = 0; i < l; i++)
+ {
+ if (cs[i].tagName == "tree")
+ {
+ jsNode.add(WebFXLoadTree.createItemFromElement(cs[i]));
+ count++;
+ }
+ }
+
+ // if no children we got an error
+ if (count == 0)
+ {
+ jsNode.errorText = webFXTreeConfig.errorLoadingText + " " + jsNode.src + " (???)";
+ }
+ }
+
+ if (jsNode.errorText != "")
+ {
+ jsNode._loadingItem.icon = webFXTreeConfig.errorIcon;
+ jsNode._loadingItem.text = jsNode.errorText;
+ jsNode._loadingItem.action = WebFXLoadTree._reloadParent;
+ jsNode._loadingItem.toolTip = webFXTreeConfig.reloadText;
+
+ t.setSuspendRedraw(oldSuspend);
+
+ jsNode._loadingItem.update();
+
+ if (typeof jsNode.onerror == "function")
+ jsNode.onerror();
+ }
+ else
+ {
+ // remove dummy
+ if (jsNode._loadingItem != null)
+ jsNode.remove(jsNode._loadingItem);
+
+ if (jsNode._pathToOpen)
+ jsNode.openPath(jsNode._pathToOpen, jsNode._selectPathOnLoad, jsNode._focusPathOnLoad);
+
+ t.setSuspendRedraw(oldSuspend);
+ jsNode.update();
+ if (typeof jsNode.onload == "function")
+ jsNode.onload();
+ }
+};
+
+WebFXLoadTree._reloadParent = function ()
+{
+ this.getParent().reload();
+};
+
+
+
+
+
+
+
+var webFXLoadTreeQueue = {
+ _nodes: [],
+ _ie: /msie/i.test(navigator.userAgent),
+ _opera: /opera/i.test(navigator.userAgent),
+
+ add: function (jsNode)
+ {
+ if (this._ie || this._opera)
+ {
+ this._nodes.push(jsNode);
+ if (this._nodes.length == 1)
+ this._send();
+ }
+ else
+ {
+ jsNode._xmlHttp.send(null);
+ }
+ },
+
+
+ remove: function (jsNode)
+ {
+ if (this._ie || this._opera)
+ {
+ arrayHelper.remove(this._nodes, jsNode);
+ if (this._nodes.length > 0)
+ this._send();
+ }
+ },
+
+ // IE only
+ _send: function ()
+ {
+ var id = this._nodes[0].getId();
+ var jsNode = webFXTreeHandler.all[id];
+ if (!jsNode)
+ return;
+ // if no _xmlHttp then remove it
+ if (!jsNode._xmlHttp)
+ this.remove(jsNode);
+ else
+ jsNode._xmlHttp.send(null);
+ }
+};
diff --git a/xloadtree/xmlextras.js b/xloadtree/xmlextras.js new file mode 100644 index 00000000..6a675121 --- /dev/null +++ b/xloadtree/xmlextras.js @@ -0,0 +1,232 @@ +/*----------------------------------------------------------------------------\
+| XML Extras 1.01 |
+|-----------------------------------------------------------------------------|
+| Created by Erik Arvidsson |
+| (http://webfx.eae.net/contact.html#erik) |
+| For WebFX (http://webfx.eae.net/) |
+|-----------------------------------------------------------------------------|
+| A library that makes working with XML documents in Mozilla more similar to |
+| working with MSXML. |
+|-----------------------------------------------------------------------------|
+| Copyright (c) 1999 - 2003 Erik Arvidsson |
+|-----------------------------------------------------------------------------|
+| This software is provided "as is", without warranty of any kind, express or |
+| implied, including but not limited to the warranties of merchantability, |
+| fitness for a particular purpose and noninfringement. In no event shall the |
+| authors or copyright holders be liable for any claim, damages or other |
+| liability, whether in an action of contract, tort or otherwise, arising |
+| from, out of or in connection with the software or the use or other |
+| dealings in the software. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| This software is available under the three different licenses mentioned |
+| below. To use this software you must chose, and qualify, for one of those. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| The WebFX Non-Commercial License http://webfx.eae.net/license.html |
+| Permits anyone the right to use the software in a non-commercial context |
+| free of charge. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| The WebFX Commercial license http://webfx.eae.net/commercial.html |
+| Permits the license holder the right to use the software in a commercial |
+| context. Such license must be specifically obtained, however it's valid for |
+| any number of implementations of the licensed software. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| GPL - The GNU General Public License http://www.gnu.org/licenses/gpl.txt |
+| Permits anyone the right to use and modify the software without limitations |
+| as long as proper credits are given and the original and modified source |
+| code are included. Requires that the final product, software derivate from |
+| the original source or any software utilizing a GPL component, such as |
+| this, is also licensed under the GPL license. |
+|-----------------------------------------------------------------------------|
+| ????-??-?? | Original Version Posted. |
+| 2003-09-25 | Added support for parseError getters. Also changed to extend |
+| | only XMLDocument instead of Document |
+|-----------------------------------------------------------------------------|
+| Created ????-??-?? | All changes are in the log above. | Updated 2003-09-25 |
+\----------------------------------------------------------------------------*/
+
+
+//////////////////
+// Helper Stuff //
+//////////////////
+
+// used to find the Automation server name
+function getDomDocumentPrefix() {
+ if (getDomDocumentPrefix.prefix)
+ return getDomDocumentPrefix.prefix;
+
+ var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
+ var o;
+ for (var i = 0; i < prefixes.length; i++) {
+ try {
+ // try to create the objects
+ o = new ActiveXObject(prefixes[i] + ".DomDocument");
+ return getDomDocumentPrefix.prefix = prefixes[i];
+ }
+ catch (ex) {};
+ }
+
+ throw new Error("Could not find an installed XML parser");
+}
+
+function getXmlHttpPrefix() {
+ if (getXmlHttpPrefix.prefix)
+ return getXmlHttpPrefix.prefix;
+
+ var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
+ var o;
+ for (var i = 0; i < prefixes.length; i++) {
+ try {
+ // try to create the objects
+ o = new ActiveXObject(prefixes[i] + ".XmlHttp");
+ return getXmlHttpPrefix.prefix = prefixes[i];
+ }
+ catch (ex) {};
+ }
+
+ throw new Error("Could not find an installed XML parser");
+}
+
+//////////////////////////
+// Start the Real stuff //
+//////////////////////////
+
+
+// XmlHttp factory
+function XmlHttp() {}
+
+XmlHttp.create = function () {
+ try {
+ if (window.XMLHttpRequest) {
+ var req = new XMLHttpRequest();
+
+ // some versions of Moz do not support the readyState property
+ // and the onreadystate event so we patch it!
+ if (req.readyState == null) {
+ req.readyState = 1;
+ req.addEventListener("load", function () {
+ req.readyState = 4;
+ if (typeof req.onreadystatechange == "function")
+ req.onreadystatechange();
+ }, false);
+ }
+
+ return req;
+ }
+ if (window.ActiveXObject) {
+ return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
+ }
+ }
+ catch (ex) {}
+ // fell through
+ throw new Error("Your browser does not support XmlHttp objects");
+};
+
+// XmlDocument factory
+function XmlDocument() {}
+
+XmlDocument.create = function () {
+ try {
+ // DOM2
+ if (document.implementation && document.implementation.createDocument) {
+ var doc = document.implementation.createDocument("", "", null);
+
+ // some versions of Moz do not support the readyState property
+ // and the onreadystate event so we patch it!
+ if (doc.readyState == null) {
+ doc.readyState = 1;
+ doc.addEventListener("load", function () {
+ doc.readyState = 4;
+ if (typeof doc.onreadystatechange == "function")
+ doc.onreadystatechange();
+ }, false);
+ }
+
+ return doc;
+ }
+ if (window.ActiveXObject)
+ return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
+ }
+ catch (ex) {}
+ throw new Error("Your browser does not support XmlDocument objects");
+};
+
+// Create the loadXML method and xml getter for Mozilla
+if (window.DOMParser &&
+ window.XMLSerializer &&
+ window.Node && Node.prototype && Node.prototype.__defineGetter__) {
+
+ // XMLDocument did not extend the Document interface in some versions
+ // of Mozilla. Extend both!
+ //XMLDocument.prototype.loadXML =
+ XMLDocument.prototype.loadXML = function (s) {
+
+ // parse the string to a new doc
+ var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
+
+ // remove all initial children
+ while (this.hasChildNodes())
+ this.removeChild(this.lastChild);
+
+ // insert and import nodes
+ for (var i = 0; i < doc2.childNodes.length; i++) {
+ this.appendChild(this.importNode(doc2.childNodes[i], true));
+ }
+ };
+
+
+ /*
+ * xml getter
+ *
+ * This serializes the DOM tree to an XML String
+ *
+ * Usage: var sXml = oNode.xml
+ *
+ */
+
+ // Node, should really be XMLNode but there is no such interface
+ Node.prototype.__defineGetter__("xml", function () {
+ return (new XMLSerializer()).serializeToString(this);
+ });
+
+ XMLDocument.prototype.__defineGetter__("parseError", function () {
+ var hasError = !this.documentElement ||
+ this.documentElement.localName == "parsererror" &&
+ this.documentElement.getAttribute("xmlns") == "http://www.mozilla.org/newlayout/xml/parsererror.xml";
+ var res = {
+ errorCode: 0,
+ filepos: 0, // not supported
+ line: 0,
+ linepos: 0,
+ reason: "",
+ srcText: "",
+ url: ""
+ };
+ if (hasError) {
+ res.errorCode = -1;
+ try {
+ res.srcText = this.getElementsByTagName("sourcetext")[0].firstChild.data;
+ res.srcText = res.srcText.replace( /\n\-\^$/, "");
+ }
+ catch (ex) {
+ res.srcText = "";
+ }
+
+ try {
+ // now we need to parse the first text node
+ var s = this.documentElement.firstChild.data;
+
+ var re = /XML Parsing Error\: (.+)\nLocation\: (.+)\nLine Number (\d+)\, Column (\d+)/;
+ var a = re.exec( s );
+ res.reason = a[1];
+ res.url = a[2];
+ res.line = a[3];
+ res.linepos = a[4];
+ }
+ catch (ex) {
+ res.reason = "Uknown";
+ }
+ }
+
+ return res;
+ });
+}
\ No newline at end of file diff --git a/xloadtree/xtree2.js b/xloadtree/xtree2.js new file mode 100644 index 00000000..26244bae --- /dev/null +++ b/xloadtree/xtree2.js @@ -0,0 +1,1664 @@ +/*----------------------------------------------------------------------------\ +| XTree 2 PRE RELEASE | +| | +| This is a pre release and redistribution is discouraged. | +| Watch http://webfx.eae.net for the final version | +| | +|-----------------------------------------------------------------------------| +| Created by Erik Arvidsson & Emil A Eklund | +| (http://webfx.eae.net/contact.html#erik) | +| (http://webfx.eae.net/contact.html#emil) | +| For WebFX (http://webfx.eae.net/) | +|-----------------------------------------------------------------------------| +| A tree menu system for IE 5.5+, Mozilla 1.4+, Opera 7, KHTML | +|-----------------------------------------------------------------------------| +| Copyright (c) 1999 - 2004 Erik Arvidsson & Emil A Eklund | +|-----------------------------------------------------------------------------| +| This software is provided "as is", without warranty of any kind, express or | +| implied, including but not limited to the warranties of merchantability, | +| fitness for a particular purpose and noninfringement. In no event shall the | +| authors or copyright holders be liable for any claim, damages or other | +| liability, whether in an action of contract, tort or otherwise, arising | +| from, out of or in connection with the software or the use or other | +| dealings in the software. | +| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | +| This software is available under the three different licenses mentioned | +| below. To use this software you must chose, and qualify, for one of those. | +| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | +| The WebFX Non-Commercial License http://webfx.eae.net/license.html | +| Permits anyone the right to use the software in a non-commercial context | +| free of charge. | +| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | +| The WebFX Commercial license http://webfx.eae.net/commercial.html | +| Permits the license holder the right to use the software in a commercial | +| context. Such license must be specifically obtained, however it's valid for | +| any number of implementations of the licensed software. | +| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | +| GPL - The GNU General Public License http://www.gnu.org/licenses/gpl.txt | +| Permits anyone the right to use and modify the software without limitations | +| as long as proper credits are given and the original and modified source | +| code are included. Requires that the final product, software derivate from | +| the original source or any software utilizing a GPL component, such as | +| this, is also licensed under the GPL license. | +|-----------------------------------------------------------------------------| +| 2004-02-21 | Pre release distributed to a few selected tester | +|-----------------------------------------------------------------------------| +| Dependencies: xtree2.css Used to define the look and feel | +|-----------------------------------------------------------------------------| +| Created 2003-??-?? | All changes are in the log above. | Updated 2004-02-21 | +\----------------------------------------------------------------------------*/ + + +// +// WebFXTreePersisitance +function WebFXTreePersistence() {} +WebFXTreePersistence.prototype.getExpanded = function (oNode) { return false; }; +WebFXTreePersistence.prototype.setExpanded = function (oNode, bOpen) {}; + + + +// Cookie handling +function WebFXCookie() {} + +WebFXCookie.prototype.setCookie = function (sName, sValue, nDays) +{ + var expires = ""; + if (typeof nDays == "number") + { + var d = new Date(); + d.setTime(d.getTime() + nDays * 24 * 60 * 60 * 1000); + expires = "; expires=" + d.toGMTString(); + } + + document.cookie = sName + "=" + escape(sValue) + expires + "; path=/"; +}; + +WebFXCookie.prototype.getCookie = function (sName) +{ + var re = new RegExp("(\;|^)[^;]*(" + sName + ")\=([^;]*)(;|$)"); + var res = re.exec(document.cookie); + return res != null ? unescape(res[3]) : null; +}; + +WebFXCookie.prototype.removeCookie = function (name) +{ + this.setCookie(name, "", -1); +}; + + +// +// persistence using cookies +// +// This is uses one cookie with the ids of the expanded nodes separated using '+' +// +function WebFXTreeCookiePersistence() +{ + this._openedMap = {}; + this._cookies = new WebFXCookie; + var s = this._cookies.getCookie(this.cookieName); + if (s) + { + var a = s.split("+"); + for (var i = a.length - 1; i >= 0; i--) + this._openedMap[a[i]] = true; + } +} + +WebFXTreeCookiePersistence.prototype = new WebFXTreePersistence; + +WebFXTreeCookiePersistence.prototype.cookieName = "webfx-tree-cookie-persistence" + +WebFXTreeCookiePersistence.prototype.getExpanded = function (oNode) +{ + return oNode.id in this._openedMap; +}; + +WebFXTreeCookiePersistence.prototype.setExpanded = function (oNode, bOpen) +{ + var old = this.getExpanded(oNode); + if (old != bOpen) + { + if (bOpen) + this._openedMap[oNode.id] = true; + else + delete this._openedMap[oNode.id]; + + var res = []; + var i = 0; + for (var id in this._openedMap) + res[i++] = id; + this._cookies.setCookie(this.cookieName, res.join("+")); + } +}; + + + +// this object provides a few useful methods when working with arrays +var arrayHelper = +{ + indexOf: function (a, o) + { + for (var i = 0; i < a.length; i++) + { + if (a[i] == o) + return i; + } + return -1; + }, + + insertBefore: function (a, o, o2) + { + var i = this.indexOf(a, o2); + if (i == -1) + a.push(o); + else + a.splice(i, 0, o); + }, + + remove: function (a, o) + { + var i = this.indexOf(a, o); + if (i != -1) + a.splice(i, 1); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// WebFX Tree Config object // +/////////////////////////////////////////////////////////////////////////////// +var webFXTreeConfig = { + rootIcon : 'images/folder.png', + openRootIcon : 'images/openfolder.png', + folderIcon : 'images/folder.png', + openFolderIcon : 'images/openfolder.png', + fileIcon : 'images/file.png', + iIcon : 'images/I.png', + lIcon : 'images/L.png', + lMinusIcon : 'images/Lminus.png', + lPlusIcon : 'images/Lplus.png', + tIcon : 'images/T.png', + tMinusIcon : 'images/Tminus.png', + tPlusIcon : 'images/Tplus.png', + plusIcon : 'images/plus.png', + minusIcon : 'images/minus.png', + blankIcon : 'images/blank.png', + defaultText : 'Tree Item', + defaultAction : null, + defaultBehavior : 'classic', + usePersistence : true +}; + +/////////////////////////////////////////////////////////////////////////////// +// WebFX Tree Handler object // +/////////////////////////////////////////////////////////////////////////////// + +var webFXTreeHandler = { + ie: /msie/i.test(navigator.userAgent), + idCounter : 0, + idPrefix : "wfxt-", + getUniqueId: function () + { + return this.idPrefix + this.idCounter++; + }, + all : {}, + getNodeById: function (sId) + { + return all[sId]; + }, + addNode: function (oNode) + { + this.all[oNode.id] = oNode; + }, + removeNode: function (oNode) + { + delete this.all[oNode.id]; + }, + + handleEvent: function (e) + { + var el = e.target || e.srcElement; + while (el != null && !this.all[el.id]) + el = el.parentNode; + + if (el == null) + return false; + var node = this.all[el.id]; + switch (e.type) + { + case "mousedown": + return node._onMouseDown(e); + case "click": + return node._onClick(e); + case "dblclick": + return node._onDblClick(e); + case "focus": + return node._onFocus(e); + case "blur": + return node._onBlur(e); + case "keydown": + return node._onKeyDown(e); + case "keypress": + return node._onKeyPress(e); + } + return false; + }, + + dispose: function () + { + if (this.disposed) return; + for (var id in this.all) + this.all[id].dispose(); + this.disposed = true; + }, + + opera: /opera/i.test(navigator.userAgent), + + htmlToText: function (s) + { + return String(s).replace(/\s+|<([^>])+>|&|<|>|"| /gi, this._htmlToText); + }, + + _htmlToText: function (s) + { + switch (s) + { + case "&": + return "&"; + case "<": + return "<"; + case ">": + return ">"; + case """: + return "\""; + case " ": + return String.fromCharCode(160); + default: + if (/\s+/.test(s)) + return " "; + if (/^<BR/gi.test(s)) + return "\n"; + return ""; + } + }, + + textToHtml: function (s) + { + return String(s).replace(/&|<|>|\n|\"\u00A0/g, this._textToHtml); + }, + + _textToHtml: function (s) + { + switch (s) + { + case "&": + return "&"; + case "<": + return "<"; + case ">": + return ">"; + case "\n": + return "<BR>"; + case "\"": + return """; // so we can use this in attributes + default: + return " "; + } + }, + + persistenceManager: new WebFXTreeCookiePersistence() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// WebFXTreeAbstractNode +/////////////////////////////////////////////////////////////////////////////// + +function WebFXTreeAbstractNode(sText, oAction) +{ + this.childNodes = []; + if (sText) this.text = sText; + if (oAction) this.action = oAction; + this.id = webFXTreeHandler.getUniqueId(); + if (webFXTreeConfig.usePersistence) + this.open = webFXTreeHandler.persistenceManager.getExpanded(this); + webFXTreeHandler.addNode(this); +} + + +var _p = WebFXTreeAbstractNode.prototype; +_p._selected = false; +_p.indentWidth = 19; +_p.open = false; +_p.text = webFXTreeConfig.defaultText; +_p.action = null; +_p.target = null; +_p.toolTip = null; +_p._focused = false; + +/* begin tree model */ + +_p.add = function (oChild, oBefore) +{ + var oldLast; + var emptyBefore = this.childNodes.length == 0; + var p = oChild.parentNode; + + if (oBefore == null) + { // append + if (p != null) + p.remove(oChild); + oldLast = this.getLastChild(); + this.childNodes.push(oChild); + } + else + { // insertBefore + if (oBefore.parentNode != this) + throw new Error("Can only add nodes before siblings"); + if (p != null) + p.remove(oChild); + + arrayHelper.insertBefore(this.childNodes, oChild, oBefore); + } + + oChild.parentNode = this; + var t = this.getTree(); + if (t) + oChild.tree = t; + var d = this.getDepth(); + if (d != null) + oChild.depth = d + 1; + + if (this.getCreated() && !t.getSuspendRedraw()) + { + var el = this.getChildrenElement(); + var newEl = oChild.create(); + var refEl = oBefore ? oBefore.getElement() : null; + el.insertBefore(newEl, refEl); + + if (oldLast) + { + oldLast.updateExpandIcon(); + } + if (emptyBefore) + { + this.setExpanded(this.getExpanded()); + // if we are using classic expand will not update icon + if (t && t.getBehavior() != "classic") + this.updateIcon(); + } + } + + return oChild; +}; + + + +_p.remove = function (oChild) +{ + // backwards compatible. If no argument remove the node + if (arguments.length == 0) + { + if (this.parentNode) + return this.parentNode.remove(this); + return null; + } + + // if we remove selected or tree with the selected we should select this + var t = this.getTree(); + var si = t ? t.getSelected() : null; + if (si == oChild || oChild.contains(si)) + { + if (si.getFocused()) + { + this.select(); + window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10); + } + else + this.select(); + } + + var wasLast = oChild.isLastSibling(); + + if (oChild.parentNode != this) + throw new Error("Can only remove children"); + arrayHelper.remove(this.childNodes, oChild); + + oChild.parentNode = null; + oChild.tree = null; + oChild.depth = null; + + if (t && this.getCreated() && !t.getSuspendRedraw()) + { + var el = this.getChildrenElement(); + var childEl = oChild.getElement(); + el.removeChild(childEl); + if (wasLast) + { + var newLast = this.getLastChild(); + if (newLast) + newLast.updateExpandIcon(); + } + if (!this.hasChildren()) + { + //this.setExpanded(this.getExpanded()); + el.style.display = "none"; + this.updateExpandIcon(); + this.updateIcon(); + } + } + + return oChild; +}; + +WebFXTreeAbstractNode._onTimeoutFocus = function (sId) +{ + var jsNode = webFXTreeHandler.all[sId]; + jsNode.focus(); +}; + +_p.getId = function () +{ + return this.id; +}; + +_p.getTree = function () +{ + throw new Error("getTree called on Abstract Node"); +}; + +_p.getDepth = function () +{ + throw new Error("getDepth called on Abstract Node"); +}; + +_p.getCreated = function () +{ + var t = this.getTree(); + return t && t.rendered; +}; + +_p.getParent = function () +{ + return this.parentNode; +}; + +_p.contains = function (oDescendant) +{ + if (oDescendant == null) return false; + if (oDescendant == this) return true; + var p = oDescendant.parentNode; + return this.contains(p); +}; + +_p.getChildren = _p.getChildNodes = function () +{ + return this.childNodes; +}; + +_p.getFirstChild = function () +{ + return this.childNodes[0]; +}; + +_p.getLastChild = function () +{ + return this.childNodes[this.childNodes.length - 1]; +}; + +_p.getPreviousSibling = function () +{ + var p = this.parentNode; + if (p == null) return null; + var cs = p.childNodes; + return cs[arrayHelper.indexOf(cs, this) - 1] +}; + +_p.getNextSibling = function () +{ + var p = this.parentNode; + if (p == null) return null; + var cs = p.childNodes; + return cs[arrayHelper.indexOf(cs, this) + 1] +}; + +_p.hasChildren = function () +{ + return this.childNodes.length > 0; +}; + + +_p.isLastSibling = function () +{ + return this.parentNode && this == this.parentNode.getLastChild(); +}; + +_p.findChildByText = function (s, n) +{ + if (!n) + n = 0; + var isRe = s instanceof RegExp; + for (var i = 0; i < this.childNodes.length; i++) + { + if (isRe && s.test(this.childNodes[i].getText()) || this.childNodes[i].getText() == s) + { + if (n == 0) + return this.childNodes[i]; + n--; + } + } + return null; +}; + +_p.findNodeByText = function (s, n) +{ + if (!n) + n = 0; + var isRe = s instanceof RegExp; + + if (isRe && s.test(this.getText()) || this.getText() == s) + { + if (n == 0) + return this.childNodes[i]; + n--; + } + + var res; + for (var i = 0; i < this.childNodes.length; i++) + { + res = this.childNodes[i].findNodeByText(s, n); + if (res) + return res; + } + return null; +}; + +/* end tree model */ + +_p.setId = function (sId) +{ + var el = this.getElement(); + webFXTreeHandler.removeNode(this); + this.id = sId; + if (el) + el.id = sId; + webFXTreeHandler.addNode(this); +}; + +_p.isSelected = function () +{ + return this._selected; +}; + +_p.select = function () { this._setSelected(true); }; +_p.deselect = function () { this._setSelected(false); }; + +_p._setSelected = function (b) +{ + var t = this.getTree(); + if (!t) return; + if (this._selected != b) + { + this._selected = b; + + var wasFocused = false; // used to keep focus state + var si = t.getSelected(); + if (b && si != null && si != this) + { + var oldFireChange = t._fireChange; + wasFocused = si._focused; + t._fireChange = false; + si._setSelected(false); + t._fireChange = oldFireChange; + } + + var el = this.getRowElement(); + if (el) + { + el.className = this.getRowClassName(); + } + if (b) + { + t._selectedItem = this; + t._fireOnChange(); + t.setSelected(this); + if (wasFocused) + this.focus(); + } + + if (t.getBehavior() != "classic") + this.updateIcon(); + } +}; + + +_p.getExpanded = function () +{ + return this.open; +}; + +_p.setExpanded = function (b) +{ + var ce; + this.open = b; + var t = this.getTree(); + if (this.hasChildren()) + { + var si = t ? t.getSelected() : null; + if (!b && this.contains(si)) + this.select(); + + var el = this.getElement(); + if (el) + { + ce = this.getChildrenElement(); + if (ce) + ce.style.display = b ? "block" : "none"; + var eie = this.getExpandIconElement(); + if (eie) + eie.src = this.getExpandIconSrc(); + } + + if (webFXTreeConfig.usePersistence) + webFXTreeHandler.persistenceManager.setExpanded(this, b); + } + else + { + ce = this.getChildrenElement(); + if (ce) + ce.style.display = "none"; + } + if (t && t.getBehavior() == "classic") + this.updateIcon(); +}; + +_p.toggle = function () +{ + this.setExpanded(!this.getExpanded()); +}; + +_p.expand = function () +{ + this.setExpanded(true); +}; + +_p.collapse = function () +{ + this.setExpanded(false); +}; + +_p.collapseChildren = function() +{ + var cs = this.childNodes; + for (var i = 0; i < cs.length; i++) + cs[i].collapseAll(); +}; + +_p.collapseAll = function() +{ + this.collapseChildren(); + this.collapse(); +}; + +_p.expandChildren = function() +{ + var cs = this.childNodes; + for (var i = 0; i < cs.length; i++) + cs[i].expandAll(); +}; + +_p.expandAll = function () +{ + this.expandChildren(); + this.expand(); +}; + +_p.reveal = function () +{ + var p = this.getParent(); + if (p) + { + p.setExpanded(true); + p.reveal(); + } +}; + +_p.openPath = function (sPath, bSelect, bFocus) +{ + if (sPath == "") + { + if (bSelect) + this.select(); + if (bFocus) + window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10); + return; + } + + var parts = sPath.split("/"); + var remainingPath = parts.slice(1).join("/"); + var t = this.getTree(); + if (sPath.charAt(0) == "/") + { + if (t) + t.openPath(remainingPath, bSelect, bFocus); + else + throw "Invalid path"; + } + else + { + // open + this.setExpanded(true); + parts = sPath.split("/"); + var ti = this.findChildByText(parts[0]); + if (!ti) + throw "Could not find child node with text \"" + parts[0] + "\""; + ti.openPath(remainingPath, bSelect, bFocus); + } +}; + +_p.focus = function () +{ + var el = this.getLabelElement(); + if (el) + el.focus(); +}; + +_p.getFocused = function () +{ + return this._focused; +}; + +// HTML generation + +_p.toHtml = function () +{ + var childrenSb = []; + var cs = this.childNodes; + var l = cs.length; + for (var y = 0; y < l; y++) + childrenSb[y] = cs[y].toHtml(); + + var t = this.getTree(); + var hideLines = !t.getShowLines() || t == this.parentNode && !t.getShowRootLines(); + + var childrenHtml = "<div class=\"webfx-tree-children" + + (hideLines ? "-nolines" : "") + "\" style=\"" + + this.getLineStyle() + + (this.getExpanded() && this.hasChildren() ? "" : "display:none;") + + "\">" + + childrenSb.join("") + + "</div>"; + + return "<div class=\"webfx-tree-item\" id=\"" + + this.id + "\"" + this.getEventHandlersHtml() + ">" + + this.getRowHtml() + + childrenHtml + + "</div>"; +}; + +_p.getRowHtml = function () +{ + var t = this.getTree(); + return "<div class=\"" + this.getRowClassName() + "\" style=\"padding-left:" + + (this.getDepth() - 1) * this.indentWidth + "px\">" + + this.getExpandIconHtml() + + //"<span class=\"webfx-tree-icon-and-label\">" + + this.getIconHtml() + + this.getLabelHtml() + + //"</span>" + + "</div>"; +}; + +_p.getRowClassName = function () +{ + return "webfx-tree-row" + (this.isSelected() ? " selected" : "") + + (this.action ? "" : " no-action"); +}; + +_p.getLabelHtml = function () +{ + var toolTip = this.getToolTip(); + var target = this.getTarget(); + return "<a href=\"" + webFXTreeHandler.textToHtml(this._getHref()) + + "\" class=\"webfx-tree-item-label\"" + + (toolTip ? " title=\"" + webFXTreeHandler.textToHtml(toolTip) + "\"" : "") + + (target ? " target=\"" + target + "\"" : "") + + " onfocus=\"webFXTreeHandler.handleEvent(event)\"" + + " onblur=\"webFXTreeHandler.handleEvent(event)\">" + + this.getHtml() + "</a>"; +}; + +_p._getHref = function () +{ + if (typeof this.action == "string") + return this.action; + else + return "#"; +}; + +_p.getEventHandlersHtml = function () +{ + return ""; +}; + +_p.getIconHtml = function () +{ + // here we are not using textToHtml since the file names rarerly contains + // HTML... + return "<img class=\"webfx-tree-icon\" src=\"" + this.getIconSrc() + "\">"; +}; + +_p.getIconSrc = function () +{ + throw new Error("getIconSrc called on Abstract Node"); +}; + +_p.getExpandIconHtml = function () +{ + // here we are not using textToHtml since the file names rarerly contains + // HTML... + return "<img class=\"webfx-tree-expand-icon\" src=\"" + + this.getExpandIconSrc() + "\">"; +}; + + +_p.getExpandIconSrc = function () +{ + var src; + var t = this.getTree(); + var hideLines = !t.getShowLines() || t == this.parentNode && !t.getShowRootLines(); + + if (this.hasChildren()) + { + var bits = 0; + /* + Bitmap used to determine which icon to use + 1 Plus + 2 Minus + 4 T Line + 8 L Line + */ + + if (t && t.getShowExpandIcons()) + { + if (this.getExpanded()) + bits = 2; + else + bits = 1; + } + + if (t && !hideLines) + { + if (this.isLastSibling()) + bits += 4; + else + bits += 8; + } + + switch (bits) + { + case 1: + return webFXTreeConfig.plusIcon; + case 2: + return webFXTreeConfig.minusIcon; + case 4: + return webFXTreeConfig.lIcon; + case 5: + return webFXTreeConfig.lPlusIcon; + case 6: + return webFXTreeConfig.lMinusIcon; + case 8: + return webFXTreeConfig.tIcon; + case 9: + return webFXTreeConfig.tPlusIcon; + case 10: + return webFXTreeConfig.tMinusIcon; + default: // 0 + return webFXTreeConfig.blankIcon; + } + } + else + { + if (t && hideLines) + return webFXTreeConfig.blankIcon; + else if (this.isLastSibling()) + return webFXTreeConfig.lIcon; + else + return webFXTreeConfig.tIcon; + } +}; + +_p.getLineStyle = function () +{ + return "background-position:" + this.getLineStyle2() + ";"; +}; + +_p.getLineStyle2 = function () +{ + return (this.isLastSibling() ? "-100" : (this.getDepth() - 1) * this.indentWidth) + "px 0"; +}; + +// End HTML generation + +// DOM +// this returns the div for the tree node +_p.getElement = function () +{ + return document.getElementById(this.id); +}; + +// the row is the div that is used to draw the node without the children +_p.getRowElement = function () +{ + var el = this.getElement(); + if (!el) return null; + return el.firstChild; +}; + +// plus/minus image +_p.getExpandIconElement = function () +{ + var el = this.getRowElement(); + if (!el) return null; + return el.firstChild; +}; + +_p.getIconElement = function () +{ + var el = this.getRowElement(); + if (!el) return null; + return el.childNodes[1]; +}; + +// anchor element +_p.getLabelElement = function () +{ + var el = this.getRowElement(); + if (!el) return null; + return el.lastChild; +}; + +// the div containing the children +_p.getChildrenElement = function () +{ + var el = this.getElement(); + if (!el) return null; + return el.lastChild; +}; + + +// IE uses about:blank if not attached to document and this can cause Win2k3 +// to fail +if (webFXTreeHandler.ie) +{ + _p.create = function () + { + var dummy = document.createElement("div"); + dummy.style.display = "none"; + document.body.appendChild(dummy); + dummy.innerHTML = this.toHtml(); + var res = dummy.removeChild(dummy.firstChild); + document.body.removeChild(dummy); + return res; + }; +} +else +{ + _p.create = function () + { + var dummy = document.createElement("div"); + dummy.innerHTML = this.toHtml(); + return dummy.removeChild(dummy.firstChild); + }; + +} + +// Getters and setters for some common fields + +_p.setIcon = function (s) +{ + this.icon = s; + if (this.getCreated()) + this.updateIcon(); +}; + +_p.getIcon = function () +{ + return this.icon; +}; + +_p.setOpenIcon = function (s) +{ + this.openIcon = s; + if (this.getCreated()) + this.updateIcon(); +}; + +_p.getOpenIcon = function () +{ + return this.openIcon; +}; + +_p.setText = function (s) +{ + this.setHtml(webFXTreeHandler.textToHtml(s)); +}; + +_p.getText = function () +{ + return webFXTreeHandler.htmlToText(this.getHtml()); +}; + +_p.setHtml = function (s) +{ + this.text = s; + var el = this.getLabelElement(); + if (el) + el.innerHTML = s; +}; + +_p.getHtml = function () +{ + return this.text; +}; + +_p.setTarget = function (s) +{ + this.target = s; +}; + +_p.getTarget = function () +{ + return this.target; +}; + +_p.setToolTip = function (s) +{ + this.toolTip = s; + var el = this.getLabelElement(); + if (el) + el.title = s; +}; + +_p.getToolTip = function () +{ + return this.toolTip; +}; + +_p.setAction = function (oAction) +{ + this.action = oAction; + var el = this.getLabelElement(); + if (el) + el.href = this._getHref(); + el = this.getRowElement(); + if (el) + el.className = this.getRowClassName(); +}; + +_p.getAction = function () +{ + return this.action; +}; + +// update methods + +_p.update = function () +{ + var t = this.getTree(); + if (t.suspendRedraw) return; + var el = this.getElement(); + if (!el || !el.parentNode) return; + var newEl = this.create(); + el.parentNode.replaceChild(newEl, el); + + var si = t.getSelected(); + if (si && si.getFocused()) + si.focus(); +}; + +_p.updateExpandIcon = function () +{ + var t = this.getTree(); + if (t.suspendRedraw) return; + var img = this.getExpandIconElement(); + img.src = this.getExpandIconSrc(); + var cel = this.getChildrenElement(); + cel.style.backgroundPosition = this.getLineStyle2(); +}; + +_p.updateIcon = function () +{ + var t = this.getTree(); + if (t.suspendRedraw) return; + var img = this.getIconElement(); + img.src = this.getIconSrc(); +}; + +// End DOM + + +_p._callSuspended = function (f) +{ + var t = this.getTree(); + var sr = t.getSuspendRedraw(); + t.setSuspendRedraw(true); + f.call(this); + t.setSuspendRedraw(sr); +}; + +// Event handlers + +_p._onMouseDown = function (e) +{ + var el = e.target || e.srcElement; + // expand icon + if (/webfx-tree-expand-icon/.test(el.className) && this.hasChildren()) + { + this.toggle(); + if ( webFXTreeHandler.ie ) + window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10); + return false; + } + + this.select(); + if (!/webfx-tree-item-label/.test(el.className) && !webFXTreeHandler.opera) // opera cancels the click if focus is called + { + // in case we are not clicking on the label + if (webFXTreeHandler.ie) + window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10); + else + this.focus(); + } + var rowEl = this.getRowElement(); + if (rowEl) + rowEl.className = this.getRowClassName(); + + return false; +}; + +_p._onClick = function (e) +{ + var el = e.target || e.srcElement; + // expand icon + if (/webfx-tree-expand-icon/.test(el.className) && this.hasChildren()) + return false; + + if (typeof this.action == "function") + this.action(); + else if (this.action != null) + window.open(this.action, this.target || "_self"); + return false; +}; + + +_p._onDblClick = function (e) +{ + var el = e.target || e.srcElement; + // expand icon + if (/webfx-tree-expand-icon/.test(el.className) && this.hasChildren()) + return; + + this.toggle(); +}; + +_p._onFocus = function (e) +{ + this.select(); + this._focused = true; +}; + +_p._onBlur = function (e) +{ + this._focused = false; +}; + +_p._onKeyDown = function (e) +{ + var n; + var rv = true; + switch (e.keyCode) + { + case 39: // RIGHT + if (e.altKey) + { + rv = true; + break; + } + if (this.hasChildren()) + { + if (!this.getExpanded()) + this.setExpanded(true); + else + { + this.getFirstChild().focus(); + } + } + rv = false; + break; + case 37: // LEFT + if (e.altKey) + { + rv = true; + break; + } + if (this.hasChildren() && this.getExpanded()) + this.setExpanded(false); + else + { + var p = this.getParent(); + var t = this.getTree(); + // don't go to root if hidden + if (p && (t.showRootNode || p != t)) + { + p.focus(); + } + } + rv = false; + break; + + case 40: // DOWN + n = this.getNextShownNode(); + if (n) + { + n.focus(); + } + rv = false; + break; + case 38: // UP + n = this.getPreviousShownNode() + if (n) + { + n.focus(); + } + rv = false; + break; + } + + if (!rv && e.preventDefault) + e.preventDefault(); + e.returnValue = rv; + return rv; +}; + +_p._onKeyPress = function (e) +{ + if (!e.altKey && e.keyCode >= 37 && e.keyCode <= 40) + { + if (e.preventDefault) + e.preventDefault(); + e.returnValue = false; + return false; + } +}; + +// End event handlers + +_p.dispose = function () +{ + if (this.disposed) return; + for (var i = this.childNodes.length - 1; i >= 0; i--) + this.childNodes[i].dispose(); + this.tree = null; + this.parentNode = null; + this.childNodes = null; + this.disposed = true; +}; + +// Some methods that are usable when navigating the tree using the arrows +_p.getLastShownDescendant = function () +{ + if (!this.getExpanded() || !this.hasChildren()) + return this; + // we know there is at least 1 child + return this.getLastChild().getLastShownDescendant(); +}; + +_p.getNextShownNode = function () +{ + if (this.hasChildren() && this.getExpanded()) + return this.getFirstChild(); + else + { + var p = this; + var next; + while (p != null) + { + next = p.getNextSibling(); + if (next != null) + return next; + p = p.getParent(); + } + return null; + } +}; + +_p.getPreviousShownNode = function () +{ + var ps = this.getPreviousSibling(); + if (ps != null) + { + return ps.getLastShownDescendant(); + } + var p = this.getParent(); + var t = this.getTree(); + if (!t.showRootNode && p == t) + return null; + return p; +}; + + + + + + + +/////////////////////////////////////////////////////////////////////////////// +// WebFXTree +/////////////////////////////////////////////////////////////////////////////// + +function WebFXTree(sText, oAction, sBehavior, sIcon, sOpenIcon) +{ + WebFXTreeAbstractNode.call(this, sText, oAction); + + if (sIcon) + this.icon = sIcon; + if (sOpenIcon) + this.openIcon = sOpenIcon; + if (sBehavior) + this.behavior = sBehavior; +} + +_p = WebFXTree.prototype = new WebFXTreeAbstractNode; +_p.indentWidth = 19; +_p.open = true; +_p._selectedItem = null; +_p._fireChange = true; +_p.rendered = false; +_p.suspendRedraw = false; +_p.showLines = true; +_p.showExpandIcons = true; +_p.showRootNode = true; +_p.showRootLines = true; + +_p.getTree = function () +{ + return this; +}; + +_p.getDepth = function () +{ + return 0; +}; + +_p.getCreated = function () +{ + return this.rendered; +}; + + +/* end tree model */ + +_p.getExpanded = function () +{ + return !this.showRootNode || WebFXTreeAbstractNode.prototype.getExpanded.call(this); +}; + +_p.setExpanded = function (b) +{ + if (!this.showRootNode) + this.open = b; + else + WebFXTreeAbstractNode.prototype.setExpanded.call(this, b); +}; + +_p.getExpandIconHtml = function () +{ + return ""; +}; + +// we don't have an expand icon here +_p.getIconElement = function () +{ + var el = this.getRowElement(); + if (!el) return null; + return el.firstChild; +}; + +// no expand icon for root element +_p.getExpandIconElement = function (oDoc) +{ + return null; +}; + +_p.updateExpandIcon = function () +{ + // no expand icon +}; + +_p.getRowClassName = function () +{ + return WebFXTreeAbstractNode.prototype.getRowClassName.call(this) + + (this.showRootNode ? "" : " webfx-tree-hide-root"); +}; + + +// if classic then the openIcon is used for expanded, otherwise openIcon is used +// for selected + +_p.getIconSrc = function () +{ + var behavior = this.getTree() ? this.getTree().getBehavior() : webFXTreeConfig.defaultBehavior; + var open = behavior == "classic" && this.getExpanded() || + behavior != "classic" && this.isSelected(); + if (open && this.openIcon) + return this.openIcon; + if (!open && this.icon) + return this.icon; + // fall back on default icons + return open ? webFXTreeConfig.openRootIcon : webFXTreeConfig.rootIcon; +}; + +_p.getEventHandlersHtml = function () +{ + return " onclick=\"return webFXTreeHandler.handleEvent(event)\" " + + "onmousedown=\"return webFXTreeHandler.handleEvent(event)\" " + + "ondblclick=\"return webFXTreeHandler.handleEvent(event)\" " + + "onkeydown=\"return webFXTreeHandler.handleEvent(event)\" " + + "onkeypress=\"return webFXTreeHandler.handleEvent(event)\""; +}; + +_p.setSelected = function (o) +{ + if (this._selectedItem != o) + { + if (o) + o._setSelected(true); + } +}; + +_p._fireOnChange = function () +{ + if (this._fireChange && typeof this.onchange == "function") + this.onchange(); +}; + +_p.getSelected = function () +{ + return this._selectedItem; +}; + +_p.setBehavior = function (s) +{ + this.behavior = s; +}; + +_p.getBehavior = function () +{ + return this.behavior || webFXTreeConfig.defaultBehavior; +}; + +_p.setShowLines = function (b) +{ + if (this.showLines != b) + { + this.showLines = b; + if (this.rendered) + this.update(); + } +}; + +_p.getShowLines = function () +{ + return this.showLines; +}; + +_p.setShowRootLines = function (b) +{ + if (this.showRootLines != b) + { + this.showRootLines = b; + if (this.rendered) + this.update(); + } +}; + +_p.getShowRootLines = function () +{ + return this.showRootLines; +}; + +_p.setShowExpandIcons = function (b) +{ + if (this.showExpandIcons != b) + { + this.showExpandIcons = b; + if (this.rendered) + this.getTree().update(); + } +}; + +_p.getShowExpandIcons = function () +{ + return this.showExpandIcons; +}; + +_p.setShowRootNode = function (b) +{ + if (this.showRootNode != b) + { + this.showRootNode = b; + if (this.rendered) + this.getTree().update(); + } +}; + +_p.getShowRoootNode = function () +{ + return this.showRootNode; +}; + +_p.onchange = function () {}; + +_p.create = function () +{ + var el = WebFXTreeAbstractNode.prototype.create.call(this); + this.rendered = true; + return el; +}; + +_p.write = function () +{ + document.write(this.toHtml()); + this.rendered = true; +}; + +_p.setSuspendRedraw = function (b) +{ + this.suspendRedraw = b; +}; + +_p.getSuspendRedraw = function () +{ + return this.suspendRedraw; +}; + + + +/////////////////////////////////////////////////////////////////////////////// +// WebFXTreeItem +/////////////////////////////////////////////////////////////////////////////// + +function WebFXTreeItem(sText, oAction, eParent, sIcon, sOpenIcon) +{ + WebFXTreeAbstractNode.call(this, sText, oAction); + if (sIcon) + this.icon = sIcon; + if (sOpenIcon) + this.openIcon = sOpenIcon; + if (eParent) + eParent.add(this); +} + +_p = WebFXTreeItem.prototype = new WebFXTreeAbstractNode; +_p.tree = null; + +/* tree model */ + +_p.getDepth = function () +{ + if (this.depth != null) + return this.depth; + if (this.parentNode) + { + var pd = this.parentNode.getDepth(); + return this.depth = (pd != null ? pd + 1 : null); + } + return null; +}; + +_p.getTree = function () +{ + if (this.tree) + return this.tree; + if (this.parentNode) + return this.tree = this.parentNode.getTree(); + return null; +}; + +_p.getCreated = function () +{ + var t = this.getTree(); + return t && t.getCreated(); +}; + +// if classic then the openIcon is used for expanded, otherwise openIcon is used +// for selected +_p.getIconSrc = function () +{ + var behavior = this.getTree() ? this.getTree().getBehavior() : webFXTreeConfig.defaultBehavior; + var open = behavior == "classic" && this.getExpanded() || + behavior != "classic" && this.isSelected(); + if (open && this.openIcon) + return this.openIcon; + if (!open && this.icon) + return this.icon; + + // fall back on default icons + if (this.hasChildren()) + return open ? webFXTreeConfig.openFolderIcon : webFXTreeConfig.folderIcon; + return webFXTreeConfig.fileIcon; +}; + +/* end tree model */ + + + + +if (window.attachEvent) +{ + window.attachEvent("onunload", function () + { + for (var id in webFXTreeHandler.all) + webFXTreeHandler.all[id].dispose(); + }); +} |