[pLog-svn] r2767 - in plog/trunk: class/template/menu js
js/jscookmenu js/jscookmenu/themeoffice js/prototype js/rico
js/ui styles templates/admin
mark at devel.lifetype.net
mark at devel.lifetype.net
Wed Jan 11 10:39:11 GMT 2006
Author: mark
Date: 2006-01-11 10:39:10 +0000 (Wed, 11 Jan 2006)
New Revision: 2767
Added:
plog/trunk/js/jscookmenu/
plog/trunk/js/jscookmenu/JSCookMenu.js
plog/trunk/js/jscookmenu/themeoffice/
plog/trunk/js/jscookmenu/themeoffice/arrow.gif
plog/trunk/js/jscookmenu/themeoffice/arrowdown.gif
plog/trunk/js/jscookmenu/themeoffice/blank.gif
plog/trunk/js/jscookmenu/themeoffice/copy.gif
plog/trunk/js/jscookmenu/themeoffice/copyshadow.gif
plog/trunk/js/jscookmenu/themeoffice/cut.gif
plog/trunk/js/jscookmenu/themeoffice/cutshadow.gif
plog/trunk/js/jscookmenu/themeoffice/help.gif
plog/trunk/js/jscookmenu/themeoffice/helpshadow.gif
plog/trunk/js/jscookmenu/themeoffice/new.gif
plog/trunk/js/jscookmenu/themeoffice/open.gif
plog/trunk/js/jscookmenu/themeoffice/openshadow.gif
plog/trunk/js/jscookmenu/themeoffice/paste.gif
plog/trunk/js/jscookmenu/themeoffice/pasteshadow.gif
plog/trunk/js/jscookmenu/themeoffice/save.gif
plog/trunk/js/jscookmenu/themeoffice/saveshadow.gif
plog/trunk/js/jscookmenu/themeoffice/spacer.gif
plog/trunk/js/jscookmenu/themeoffice/theme.css
plog/trunk/js/jscookmenu/themeoffice/theme.js
plog/trunk/js/rico/
plog/trunk/js/rico/rico.js
Modified:
plog/trunk/class/template/menu/menurenderer.class.php
plog/trunk/js/prototype/prototype.js
plog/trunk/js/ui/plogui.js
plog/trunk/styles/admin.css
plog/trunk/templates/admin/editpost.template
plog/trunk/templates/admin/header.template
plog/trunk/templates/admin/newpost.template
Log:
This is another big commit about UI:
1. Change the admin.css for better tab effect
2. Add JsCookMenu.js for adding the drop down menu to LifeType
3. Change the header.template to enable the Drop-Down menu. The default is disable.
4. Change the header.template to include the rico ajax library
5. Add show/hide capability to newpost/editpost page based on Rico Ajax library
6. Upgrade prototype.js to 1.4.0
That's All!
ToDo:
1. Add a new blogsetting to control to use the original menu or drop-down menu
2. Add cookie to record user behavior about hide/show option (or how about use blogsetting to remember it, too?)
Modified: plog/trunk/class/template/menu/menurenderer.class.php
===================================================================
--- plog/trunk/class/template/menu/menurenderer.class.php 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/class/template/menu/menurenderer.class.php 2006-01-11 10:39:10 UTC (rev 2767)
@@ -1,209 +1,294 @@
-<?php
-
-
- include_once( PLOG_CLASS_PATH."class/locale/locales.class.php" );
- include_once( PLOG_CLASS_PATH."class/template/templateservice.class.php" );
- include_once( PLOG_CLASS_PATH."class/template/menu/menu.class.php" );
- include_once( PLOG_CLASS_PATH."class/template/menu/menuentry.class.php" );
- include_once( PLOG_CLASS_PATH."class/locale/locales.class.php" );
-
- /**
- * \ingroup Template
- *
- * dumps the contents of the menu in a tree-fashion way using unordered html lists. It is necessary
- * to use some additional CSS styling to give some formatting to the menu.
- *
- * This class is only used at the presentation layer of pLog to generate the menu structure,
- * and class users should never need to create an instance of this class.
- *
- * See the "Menu API reference" document in the wiki for more information:
- * http://wiki.plogworld.net/index.php/PLog_1.0/The_Menu_API
- */
- class MenuRenderer
- {
- var $_menu;
- var $_blogInfo;
- var $_userInfo;
-
- /**
- * Initializes the renderer
- *
- * @param menu A vaid Menu object
- * @param blogInfo A reference to a BlogInfo object containing information of the blog for whom
- * we are going to render this menu tree.
- * @param userInfo A reference to a UserInfo object containing information of the user for whom
- * we are going to render this menu tree, because we need to know which options he/she is allowed
- * to see and which not.
- */
- function MenuRenderer( $menu, $blogInfo, $userInfo )
- {
-
- $this->_menu = $menu;
- $this->_blogInfo = $blogInfo;
- $this->_userInfo = $userInfo;
-
- $config =& Config::getConfig();
-
- // load the right locale
- if( $blogInfo != null ) {
- $this->_locale =& $blogInfo->getLocale();
- }
- else {
- $localeCode = $config->getValue( "default_locale" );
- $this->_locale =& Locales::getLocale( $localeCode );
- }
- }
-
- /**
- * renders the contents of the menu
- *
- * @param depth How many depth levels we should generate.
- */
- function generate( $depth = 99 )
- {
- $node = $this->_menu->getRoot();
- return $this->_render( $node, $depth );
- }
-
- /**
- * Generates a tree starting from another node which can be different than the
- * root node
- *
- * @param nodeId
- * @param depth
- * @param activeOpt
- */
- function generateAt( $nodeId, $depth = 1, $activeOpt = "" )
- {
- $nodePath = $this->_menu->entryPath( $nodeId );
- $node = $this->_menu->getEntryAt( $nodePath );
- return $this->_render( $node, $depth, $template );
- }
-
- /**
- * returns true if the user has enough permissions to see this node from the menu
- *
- * @param node
- * @param userInfo
- * @return true if the user can, false otherwise
- */
- function userCanSee( $node, $userInfo )
- {
- // check if the node is for admins and if the user is an admin
- $nodeIsAdminOnly = $node->getAttribute( "siteAdmin" );
- if( $nodeIsAdminOnly && !$userInfo->isSiteAdmin())
- return false;
-
- // check if the node is only for blog owners and if the user is a blog owner
- $nodeIsBlogOwnerOnly = $node->getAttribute( "blogOwner" );
- if( $nodeIsBlogOwnerOnly && ( $this->_blogInfo->getOwner() != $userInfo->getId()))
- return false;
-
- // if none of the above is true, then the user does not have enough permissions!
- return true;
- }
-
- /**
- * @private
- * Used by render() to really render the tree
- */
- function _render( $node, $depth = 0, $activeOpt = "" )
- {
- $result = "<ul class=\"menuTop\">";
- $depth--;
- foreach( $node->children as $child ) {
- if( $child->name != "" ) {
- // check whether the user has the right permissions to see this
- if( $this->userCanSee( $child, $this->_userInfo )) {
- $url = $child->getAttribute( "url" );
- $localeId = $this->getLocaleId( $child );
- $cssClass = "Level_".$depth;
- if( $url != "" )
- $result .= "<li class=\"$cssClass\"><a href=\"".$child->getAttribute("url")."\">".$this->_locale->tr($localeId)."</a></li>";
- else
- $result .= "<li class=\"$cssClass\">".$this->_locale->tr($child->name)."</li>";
-
- if( $depth > 0 )
- $result .= $this->_render( $child, $depth, $activeOpt );
- }
- }
- }
- $result .= "</ul>";
-
- return $result;
- }
-
- /**
- * gets the locale id, given a node. The locale id can be either the value of the
- * "localeId" attribute if specified or the name of the tag otherwise
- *
- * @param entry A valid menu node
- * @return the locale identifier
- */
- function getLocaleId( $entry )
- {
- $localeId = $entry->getAttribute("localeId");
- if( $localeId == "" )
- $localeId = $entry->name;
-
- return $localeId;
- }
-
- /**
- * simple version of a "breadcrumbs" feature
- *
- * @param entryId
- */
- function breadCrumbs( $entryId )
- {
- $nodePath = $this->_menu->entryPath( $entryId );
- $path = "";
-
- if( $nodePath ) {
- $parts = explode( "/", $nodePath );
- $totalParts = count($parts);
- if( $totalParts == 1 ) $insertBlogLink = true;
- else $insertBlogLink = false;
-
- $count=0;
- foreach( $parts as $part ) {
- $path .= $part;
- $menuEntry = $this->_menu->getEntryAt( $path );
- if( $menuEntry->getAttribute("ignoreBreadCrumbs") != "1" ) {
- $localeId = $this->getLocaleId( $menuEntry );
- if( $entryId == $part ) $result .= "<b>";
- if( $menuEntry->getAttribute("url") != "" )
- $result .= "<a href=\"".$menuEntry->getAttribute("url")."\">".$this->_locale->tr($localeId)."</a>";
- else
- $result .= $this->_locale->tr($part);
- if( $entryId == $part ) $result .= "</b>";
- if( $count == 0 ) $result .= " » <a href=\"?op=blogSelect&blogId=".$this->_blogInfo->getId()."\">".$this->_blogInfo->getBlog()."</a>";
- if( $count < $totalParts-1 ) $result .= " » ";
- }
- $count++;
- $path .= "/";
- }
- }
-
- return $result;
- }
-
- /**
- * @param entryId
- */
- function getOpts( $entryId)
- {
- $nodePath = $this->_menu->entryPath( $entryId );
- $parts = explode( "/", $nodePath );
- array_pop( $parts );
- $parentPath = implode( "/", $parts );
-
- $parentNode = $this->_menu->getNodeAt( $parentPath );
-
- $children = $parentNode->children;
-
- // the children of my parent are... my brothers :)))
- return $children;
- }
- }
-?>
+<?php
+
+
+ include_once( PLOG_CLASS_PATH."class/locale/locales.class.php" );
+ include_once( PLOG_CLASS_PATH."class/template/templateservice.class.php" );
+ include_once( PLOG_CLASS_PATH."class/template/menu/menu.class.php" );
+ include_once( PLOG_CLASS_PATH."class/template/menu/menuentry.class.php" );
+ include_once( PLOG_CLASS_PATH."class/locale/locales.class.php" );
+
+ /**
+ * \ingroup Template
+ *
+ * dumps the contents of the menu in a tree-fashion way using unordered html lists. It is necessary
+ * to use some additional CSS styling to give some formatting to the menu.
+ *
+ * This class is only used at the presentation layer of pLog to generate the menu structure,
+ * and class users should never need to create an instance of this class.
+ *
+ * See the "Menu API reference" document in the wiki for more information:
+ * http://wiki.plogworld.net/index.php/PLog_1.0/The_Menu_API
+ */
+ class MenuRenderer
+ {
+ var $_menu;
+ var $_blogInfo;
+ var $_userInfo;
+
+ /**
+ * Initializes the renderer
+ *
+ * @param menu A vaid Menu object
+ * @param blogInfo A reference to a BlogInfo object containing information of the blog for whom
+ * we are going to render this menu tree.
+ * @param userInfo A reference to a UserInfo object containing information of the user for whom
+ * we are going to render this menu tree, because we need to know which options he/she is allowed
+ * to see and which not.
+ */
+ function MenuRenderer( $menu, $blogInfo, $userInfo )
+ {
+
+ $this->_menu = $menu;
+ $this->_blogInfo = $blogInfo;
+ $this->_userInfo = $userInfo;
+
+ $config =& Config::getConfig();
+
+ // load the right locale
+ if( $blogInfo != null ) {
+ $this->_locale =& $blogInfo->getLocale();
+ }
+ else {
+ $localeCode = $config->getValue( "default_locale" );
+ $this->_locale =& Locales::getLocale( $localeCode );
+ }
+ }
+
+ /**
+ * renders the contents of the menu
+ *
+ * @param depth How many depth levels we should generate.
+ * @param renderFunc render method for menu tree , the value is "JavaScript" and "Plain"
+ */
+ function generate( $depth = 99, $renderFunc = "Plain" )
+ {
+ $node = $this->_menu->getRoot();
+
+ if ( $renderFunc != "JavaScript" ) {
+ return $this->_render( $node, $depth );
+ } else {
+ $menu = "<SCRIPT LANGUAGE=\"JavaScript\" SRC=\"js/JSCookMenu/JSCookMenu.js\"></SCRIPT>\n";
+ $menu .= "<LINK REL=\"stylesheet\" HREF=\"js/JSCookMenu/ThemeOffice/theme.css\" TYPE=\"text/css\">";
+ $menu .= "<SCRIPT LANGUAGE=\"JavaScript\" SRC=\"js/JSCookMenu/ThemeOffice/theme.js\"></SCRIPT>";
+ $menu .= "<SCRIPT LANGUAGE=\"JavaScript\">\n";
+ $menu .= "<!-- \n";
+ $menu .= "var mainMenu = [\n";
+ $menu .= $this->_renderJS( $node, $depth );
+ $menu .= "];\n";
+ $menu .= " -->\n";
+ $menu .= "</SCRIPT>\n";
+
+ $menu .= "<SCRIPT LANGUAGE=\"JavaScript\">\n";
+ $menu .= "<!--\n";
+ $menu .= "cmDraw ('menu', mainMenu, 'hbr', cmThemeOffice, 'ThemeOffice');\n";
+ $menu .= "-->\n";
+ $menu .= "</SCRIPT>\n";
+
+ return $menu;
+ }
+ }
+
+ /**
+ * Generates a tree starting from another node which can be different than the
+ * root node
+ *
+ * @param nodeId
+ * @param depth
+ * @param activeOpt
+ * @param renderFunc render method for menu tree , the value is "JavaScript" and "Plain"
+ */
+ function generateAt( $nodeId, $depth = 1, $activeOpt = "", $renderFunc = "Plain" )
+ {
+ $nodePath = $this->_menu->entryPath( $nodeId );
+ $node = $this->_menu->getEntryAt( $nodePath );
+ $start = 0;
+
+ if ( $renderFunc != "JavaScript" ) {
+ return $this->_render( $node, $depth, $activeOpt );
+ } else {
+ $menu = "<SCRIPT LANGUAGE=\"JavaScript\" SRC=\"js/JSCookMenu/JSCookMenu.js\"></SCRIPT>\n";
+ $menu .= "<LINK REL=\"stylesheet\" HREF=\"js/JSCookMenu/ThemeOffice/theme.css\" TYPE=\"text/css\">";
+ $menu .= "<SCRIPT LANGUAGE=\"JavaScript\" SRC=\"js/JSCookMenu/ThemeOffice/theme.js\"></SCRIPT>";
+ $menu .= "<SCRIPT LANGUAGE=\"JavaScript\">\n";
+ $menu .= "<!-- \n";
+ $menu .= "var mainMenu = [\n";
+ $menu .= $this->_renderJS( $node, $depth, $start, $activeOpt );
+ $menu .= "];\n";
+ $menu .= " -->\n";
+ $menu .= "</SCRIPT>\n";
+
+ $menu .= "<SCRIPT LANGUAGE=\"JavaScript\">\n";
+ $menu .= "<!--\n";
+ $menu .= "cmDraw ('menu', mainMenu, 'hbr', cmThemeOffice, 'ThemeOffice');\n";
+ $menu .= "-->\n";
+ $menu .= "</SCRIPT>\n";
+
+ return $menu;
+ }
+ }
+
+ /**
+ * returns true if the user has enough permissions to see this node from the menu
+ *
+ * @param node
+ * @param userInfo
+ * @return true if the user can, false otherwise
+ */
+ function userCanSee( $node, $userInfo )
+ {
+ // check if the node is for admins and if the user is an admin
+ $nodeIsAdminOnly = $node->getAttribute( "siteAdmin" );
+ if( $nodeIsAdminOnly && !$userInfo->isSiteAdmin())
+ return false;
+
+ // check if the node is only for blog owners and if the user is a blog owner
+ $nodeIsBlogOwnerOnly = $node->getAttribute( "blogOwner" );
+ if( $nodeIsBlogOwnerOnly && ( $this->_blogInfo->getOwner() != $userInfo->getId()))
+ return false;
+
+ // if none of the above is true, then the user does not have enough permissions!
+ return true;
+ }
+
+ /**
+ * @private
+ * Used by render() to really render the tree
+ */
+ function _render( $node, $depth = 0, $activeOpt = "" )
+ {
+ $result = "<ul class=\"menuTop\">";
+ $depth--;
+ foreach( $node->children as $child ) {
+ if( $child->name != "" ) {
+ // check whether the user has the right permissions to see this
+ if( $this->userCanSee( $child, $this->_userInfo )) {
+ $url = $child->getAttribute( "url" );
+ $localeId = $this->getLocaleId( $child );
+ $cssClass = "Level_".$depth;
+ if( $url != "" )
+ $result .= "<li class=\"$cssClass\"><a href=\"".$child->getAttribute("url")."\">".$this->_locale->tr($localeId)."</a></li>";
+ else
+ $result .= "<li class=\"$cssClass\">".$this->_locale->tr($child->name)."</li>";
+
+ if( $depth > 0 )
+ $result .= $this->_render( $child, $depth, $activeOpt );
+ }
+ }
+ }
+ $result .= "</ul>";
+
+ return $result;
+ }
+
+ /**
+ * @private
+ * Used by renderJS() to really render the Javascriipt menu tree
+ */
+ function _renderJS( $node, $depth = 0, $start = 0, $activeOpt = "" )
+ {
+ $result = "";
+ $depth--;
+ foreach( $node->children as $child ) {
+ if( $child->name != "" ) {
+ // check whether the user has the right permissions to see this
+ if( $this->userCanSee( $child, $this->_userInfo )) {
+ if( $start == 0 ) {
+ $result .= "[";
+ $start = 1;
+ } else {
+ $result .= ",[";
+ }
+
+ $url = $child->getAttribute( "url" );
+ $localeId = $this->getLocaleId( $child );
+
+ if( $url != "" )
+ $result .= "null, '".$this->_locale->tr($localeId)."', '".$child->getAttribute("url")."', '_self', null";
+ else
+ $result .= "null, '".$this->_locale->tr($localeId)."', '#', '_self', null";
+
+ if( $depth > 0 )
+ $result .= $this->_renderJS( $child, $depth, $start, $activeOpt );
+
+ $result .= "]";
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * gets the locale id, given a node. The locale id can be either the value of the
+ * "localeId" attribute if specified or the name of the tag otherwise
+ *
+ * @param entry A valid menu node
+ * @return the locale identifier
+ */
+ function getLocaleId( $entry )
+ {
+ $localeId = $entry->getAttribute("localeId");
+ if( $localeId == "" )
+ $localeId = $entry->name;
+
+ return $localeId;
+ }
+
+ /**
+ * simple version of a "breadcrumbs" feature
+ *
+ * @param entryId
+ */
+ function breadCrumbs( $entryId )
+ {
+ $nodePath = $this->_menu->entryPath( $entryId );
+ $path = "";
+
+ if( $nodePath ) {
+ $parts = explode( "/", $nodePath );
+ $totalParts = count($parts);
+ if( $totalParts == 1 ) $insertBlogLink = true;
+ else $insertBlogLink = false;
+
+ $count=0;
+ foreach( $parts as $part ) {
+ $path .= $part;
+ $menuEntry = $this->_menu->getEntryAt( $path );
+ if( $menuEntry->getAttribute("ignoreBreadCrumbs") != "1" ) {
+ $localeId = $this->getLocaleId( $menuEntry );
+ if( $entryId == $part ) $result .= "<b>";
+ if( $menuEntry->getAttribute("url") != "" )
+ $result .= "<a href=\"".$menuEntry->getAttribute("url")."\">".$this->_locale->tr($localeId)."</a>";
+ else
+ $result .= $this->_locale->tr($part);
+ if( $entryId == $part ) $result .= "</b>";
+ if( $count == 0 ) $result .= " » <a href=\"?op=blogSelect&blogId=".$this->_blogInfo->getId()."\">".$this->_blogInfo->getBlog()."</a>";
+ if( $count < $totalParts-1 ) $result .= " » ";
+ }
+ $count++;
+ $path .= "/";
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param entryId
+ */
+ function getOpts( $entryId)
+ {
+ $nodePath = $this->_menu->entryPath( $entryId );
+ $parts = explode( "/", $nodePath );
+ array_pop( $parts );
+ $parentPath = implode( "/", $parts );
+
+ $parentNode = $this->_menu->getNodeAt( $parentPath );
+
+ $children = $parentNode->children;
+
+ // the children of my parent are... my brothers :)))
+ return $children;
+ }
+ }
+?>
Added: plog/trunk/js/jscookmenu/JSCookMenu.js
===================================================================
--- plog/trunk/js/jscookmenu/JSCookMenu.js 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/js/jscookmenu/JSCookMenu.js 2006-01-11 10:39:10 UTC (rev 2767)
@@ -0,0 +1,1146 @@
+/*
+ JSCookMenu v1.4.4. (c) Copyright 2002-2005 by Heng Yuan
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ ITNESS 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.
+*/
+
+// Globals
+var _cmIDCount = 0;
+var _cmIDName = 'cmSubMenuID'; // for creating submenu id
+
+var _cmTimeOut = null; // how long the menu would stay
+var _cmCurrentItem = null; // the current menu item being selected;
+
+var _cmNoAction = new Object (); // indicate that the item cannot be hovered.
+var _cmNoClick = new Object (); // similar to _cmNoAction but does not respond to mouseup/mousedown events
+var _cmSplit = new Object (); // indicate that the item is a menu split
+
+var _cmItemList = new Array (); // a simple list of items
+
+// default node properties
+var _cmNodeProperties =
+{
+ // main menu display attributes
+ //
+ // Note. When the menu bar is horizontal,
+ // mainFolderLeft and mainFolderRight are
+ // put in <span></span>. When the menu
+ // bar is vertical, they would be put in
+ // a separate TD cell.
+
+ // HTML code to the left of the folder item
+ mainFolderLeft: '',
+ // HTML code to the right of the folder item
+ mainFolderRight: '',
+ // HTML code to the left of the regular item
+ mainItemLeft: '',
+ // HTML code to the right of the regular item
+ mainItemRight: '',
+
+ // sub menu display attributes
+
+ // HTML code to the left of the folder item
+ folderLeft: '',
+ // HTML code to the right of the folder item
+ folderRight: '',
+ // HTML code to the left of the regular item
+ itemLeft: '',
+ // HTML code to the right of the regular item
+ itemRight: '',
+ // cell spacing for main menu
+ mainSpacing: 0,
+ // cell spacing for sub menus
+ subSpacing: 0,
+ // auto disappear time for submenus in milli-seconds
+ delay: 500,
+
+ // act on click to open sub menu
+ // not yet implemented
+ // 0 : use default behavior
+ // 1 : hover open in all cases
+ // 2 : click on main, hover on sub
+ // 3 : click open in all cases
+ clickOpen: 1
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Drawing Functions and Utility Functions
+//
+//////////////////////////////////////////////////////////////////////
+
+//
+// produce a new unique id
+//
+function cmNewID ()
+{
+ return _cmIDName + (++_cmIDCount);
+}
+
+//
+// return the property string for the menu item
+//
+function cmActionItem (item, prefix, isMain, idSub, orient, nodeProperties)
+{
+ var clickOpen = _cmNodeProperties.clickOpen;
+ if (nodeProperties.clickOpen)
+ clickOpen = nodeProperties.clickOpen;
+
+ // var index = _cmItemList.push (item) - 1;
+ _cmItemList[_cmItemList.length] = item;
+ var index = _cmItemList.length - 1;
+ idSub = (!idSub) ? 'null' : ('\'' + idSub + '\'');
+ orient = '\'' + orient + '\'';
+ prefix = '\'' + prefix + '\'';
+ var onClick = (clickOpen == 3) || (clickOpen == 2 && isMain);
+ var returnStr;
+ if (onClick)
+ returnStr = ' onmouseover="cmItemMouseOver (this,' + prefix + ',' + isMain + ',' + idSub + ',' + index + ')" onmousedown="cmItemMouseDownOpenSub (this,' + index + ',' + prefix + ',' + orient + ',' + idSub + ')"';
+ else
+ returnStr = ' onmouseover="cmItemMouseOverOpenSub (this,' + prefix + ',' + isMain + ',' + idSub + ',' + orient + ',' + index + ')" onmousedown="cmItemMouseDown (this,' + index + ')"';
+ return returnStr + ' onmouseout="cmItemMouseOut (this,' + nodeProperties.delay + ')" onmouseup="cmItemMouseUp (this,' + index + ')"';
+}
+
+//
+// this one is used by _cmNoClick to only take care of onmouseover and onmouseout
+// events which are associated with menu but not actions associated with menu clicking/closing
+//
+function cmNoClickItem (item, prefix, isMain, idSub, orient, nodeProperties)
+{
+ // var index = _cmItemList.push (item) - 1;
+ _cmItemList[_cmItemList.length] = item;
+ var index = _cmItemList.length - 1;
+ idSub = (!idSub) ? 'null' : ('\'' + idSub + '\'');
+ orient = '\'' + orient + '\'';
+ prefix = '\'' + prefix + '\'';
+ return ' onmouseover="cmItemMouseOver (this,' + prefix + ',' + isMain + ',' + idSub + ',' + index + ')" onmouseout="cmItemMouseOut (this,' + nodeProperties.delay + ')"';
+}
+
+function cmNoActionItem (item, prefix)
+{
+ return item[1];
+}
+
+function cmSplitItem (prefix, isMain, vertical)
+{
+ var classStr = 'cm' + prefix;
+ if (isMain)
+ {
+ classStr += 'Main';
+ if (vertical)
+ classStr += 'HSplit';
+ else
+ classStr += 'VSplit';
+ }
+ else
+ classStr += 'HSplit';
+ return eval (classStr);
+}
+
+//
+// draw the sub menu recursively
+//
+function cmDrawSubMenu (subMenu, prefix, id, orient, nodeProperties)
+{
+ var str = '<div class="' + prefix + 'SubMenu" id="' + id + '"><table summary="sub menu" cellspacing="' + nodeProperties.subSpacing + '" class="' + prefix + 'SubMenuTable">';
+ var strSub = '';
+
+ var item;
+ var idSub;
+ var hasChild;
+
+ var i;
+
+ var classStr;
+
+ for (i = 5; i < subMenu.length; ++i)
+ {
+ item = subMenu[i];
+ if (!item)
+ continue;
+
+ if (item == _cmSplit)
+ item = cmSplitItem (prefix, 0, true);
+
+ hasChild = (item.length > 5);
+ idSub = hasChild ? cmNewID () : null;
+
+ str += '<tr class="' + prefix + 'MenuItem"';
+ if (item[0] != _cmNoClick)
+ str += cmActionItem (item, prefix, 0, idSub, orient, nodeProperties);
+ else
+ str += cmNoClickItem (item, prefix, 0, idSub, orient, nodeProperties);
+ str += '>'
+
+ if (item[0] == _cmNoAction || item[0] == _cmNoClick)
+ {
+ str += cmNoActionItem (item, prefix);
+ str += '</tr>';
+ continue;
+ }
+
+ classStr = prefix + 'Menu';
+ classStr += hasChild ? 'Folder' : 'Item';
+
+ str += '<td class="' + classStr + 'Left">';
+
+ if (item[0] != null)
+ str += item[0];
+ else
+ str += hasChild ? nodeProperties.folderLeft : nodeProperties.itemLeft;
+
+ str += '</td><td class="' + classStr + 'Text">' + item[1];
+
+ str += '</td><td class="' + classStr + 'Right">';
+
+ if (hasChild)
+ {
+ str += nodeProperties.folderRight;
+ strSub += cmDrawSubMenu (item, prefix, idSub, orient, nodeProperties);
+ }
+ else
+ str += nodeProperties.itemRight;
+ str += '</td></tr>';
+ }
+
+ str += '</table></div>' + strSub;
+ return str;
+}
+
+//
+// The function that builds the menu inside the specified element id.
+//
+// @param id id of the element
+// orient orientation of the menu in [hv][ab][lr] format
+// menu the menu object to be drawn
+// nodeProperties properties for each menu node
+//
+function cmDraw (id, menu, orient, nodeProperties, prefix)
+{
+ var obj = cmGetObject (id);
+
+ if (!nodeProperties)
+ nodeProperties = _cmNodeProperties;
+ if (!prefix)
+ prefix = '';
+
+ var str = '<table summary="main menu" class="' + prefix + 'Menu" cellspacing="' + nodeProperties.mainSpacing + '">';
+ var strSub = '';
+
+ if (!orient)
+ orient = 'hbr';
+
+ var orientStr = String (orient);
+ var orientSub;
+ var vertical;
+
+ // draw the main menu items
+ if (orientStr.charAt (0) == 'h')
+ {
+ // horizontal menu
+ orientSub = 'v' + orientStr.substr (1, 2);
+ str += '<tr>';
+ vertical = false;
+ }
+ else
+ {
+ // vertical menu
+ orientSub = 'v' + orientStr.substr (1, 2);
+ vertical = true;
+ }
+
+ var i;
+ var item;
+ var idSub;
+ var hasChild;
+
+ var classStr;
+
+ for (i = 0; i < menu.length; ++i)
+ {
+ item = menu[i];
+
+ if (!item)
+ continue;
+
+ str += vertical ? '<tr' : '<td';
+ str += ' class="' + prefix + 'MainItem"';
+
+ hasChild = (item.length > 5);
+ idSub = hasChild ? cmNewID () : null;
+
+ str += cmActionItem (item, prefix, 1, idSub, orient, nodeProperties) + '>';
+
+ if (item == _cmSplit)
+ item = cmSplitItem (prefix, 1, vertical);
+
+ if (item[0] == _cmNoAction || item[0] == _cmNoClick)
+ {
+ str += cmNoActionItem (item, prefix);
+ str += vertical? '</tr>' : '</td>';
+ continue;
+ }
+
+ classStr = prefix + 'Main' + (hasChild ? 'Folder' : 'Item');
+
+ str += vertical ? '<td' : '<span';
+ str += ' class="' + classStr + 'Left">';
+
+ str += (item[0] == null) ? (hasChild ? nodeProperties.mainFolderLeft : nodeProperties.mainItemLeft)
+ : item[0];
+ str += vertical ? '</td>' : '</span>';
+
+ str += vertical ? '<td' : '<span';
+ str += ' class="' + classStr + 'Text">';
+ str += item[1];
+
+ str += vertical ? '</td>' : '</span>';
+
+ str += vertical ? '<td' : '<span';
+ str += ' class="' + classStr + 'Right">';
+
+ str += hasChild ? nodeProperties.mainFolderRight : nodeProperties.mainItemRight;
+
+ str += vertical ? '</td>' : '</span>';
+
+ str += vertical ? '</tr>' : '</td>';
+
+ if (hasChild)
+ strSub += cmDrawSubMenu (item, prefix, idSub, orientSub, nodeProperties);
+ }
+ if (!vertical)
+ str += '</tr>';
+ str += '</table>' + strSub;
+ obj.innerHTML = str;
+ //document.write ("<xmp>" + str + "</xmp>");
+}
+
+//
+// The function builds the menu inside the specified element id.
+//
+// This function is similar to cmDraw except that menu is taken from HTML node
+// rather a javascript tree. This feature allows links to be scanned by search
+// bots.
+//
+// This function basically converts HTML node to a javascript tree, and then calls
+// cmDraw to draw the actual menu, replacing the hidden menu tree.
+//
+// Format:
+// <div id="menu">
+// <ul style="visibility: hidden">
+// <li><span>icon</span><a href="link" title="description">main menu text</a>
+// <ul>
+// <li><span>icon</span><a href="link" title="description">submenu item</a>
+// </li>
+// </ul>
+// </li>
+// </ul>
+// </div>
+//
+function cmDrawFromText (id, orient, nodeProperties, prefix)
+{
+ var domMenu = cmGetObject (id);
+ var menu = null;
+ for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
+ {
+ if (!currentDomItem.tagName || currentDomItem.tagName.toLowerCase () != 'ul')
+ continue;
+ menu = cmDrawFromTextSubMenu (currentDomItem);
+ break;
+ }
+ if (menu)
+ cmDraw (id, menu, orient, nodeProperties, prefix);
+}
+
+//
+// a recursive function that build menu tree structure
+//
+function cmDrawFromTextSubMenu (domMenu)
+{
+ var items = new Array ();
+ for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
+ {
+ if (!currentDomItem.tagName || currentDomItem.tagName.toLowerCase () != 'li')
+ continue;
+ if (currentDomItem.firstChild == null)
+ {
+ items[items.length] = _cmSplit;
+ continue;
+ }
+ var item = new Array ();
+ var currentItem = currentDomItem.firstChild;
+ for (; currentItem; currentItem = currentItem.nextSibling)
+ {
+ // scan for span tag
+ if (!currentItem.tagName || currentItem.tagName.toLowerCase () != 'span')
+ continue;
+ if (!currentItem.firstChild)
+ item[0] = null;
+ else
+ item[0] = currentItem.innerHTML;
+ break;
+ }
+ if (!currentItem)
+ continue;
+ for (; currentItem; currentItem = currentItem.nextSibling)
+ {
+ // scan for span tag
+ if (!currentItem.tagName || currentItem.tagName.toLowerCase () != 'a')
+ continue;
+ item[1] = currentItem.innerHTML;
+ item[2] = currentItem.href;
+ item[3] = currentItem.target;
+ item[4] = currentItem.title;
+ if (item[4] == '')
+ item[4] = null;
+ break;
+ }
+
+ for (; currentItem; currentItem = currentItem.nextSibling)
+ {
+ // scan for span tag
+ if (!currentItem.tagName || currentItem.tagName.toLowerCase () != 'ul')
+ continue;
+ var subMenuItems = cmDrawFromTextSubMenu (currentItem);
+ for (i = 0; i < subMenuItems.length; ++i)
+ item[i + 5] = subMenuItems[i];
+ break;
+ }
+ items[items.length] = item;
+ }
+ return items;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Mouse Event Handling Functions
+//
+//////////////////////////////////////////////////////////////////////
+
+//
+// action should be taken for mouse moving in to the menu item
+//
+// Here we just do things concerning this menu item, w/o opening sub menus.
+//
+function cmItemMouseOver (obj, prefix, isMain, idSub, index)
+{
+ clearTimeout (_cmTimeOut);
+
+ if (!obj.cmPrefix)
+ {
+ obj.cmPrefix = prefix;
+ obj.cmIsMain = isMain;
+ }
+
+ var thisMenu = cmGetThisMenu (obj, prefix);
+
+ // insert obj into cmItems if cmItems doesn't have obj
+ if (!thisMenu.cmItems)
+ thisMenu.cmItems = new Array ();
+ var i;
+ for (i = 0; i < thisMenu.cmItems.length; ++i)
+ {
+ if (thisMenu.cmItems[i] == obj)
+ break;
+ }
+ if (i == thisMenu.cmItems.length)
+ {
+ //thisMenu.cmItems.push (obj);
+ thisMenu.cmItems[i] = obj;
+ }
+
+ // hide the previous submenu that is not this branch
+ if (_cmCurrentItem)
+ {
+ // occationally, we get this case when user
+ // move the mouse slowly to the border
+ if (_cmCurrentItem == obj || _cmCurrentItem == thisMenu)
+ {
+ var item = _cmItemList[index];
+ cmSetStatus (item);
+ return;
+ }
+
+ var thatPrefix = _cmCurrentItem.cmPrefix;
+ var thatMenu = cmGetThisMenu (_cmCurrentItem, thatPrefix);
+
+ if (thatMenu != thisMenu.cmParentMenu)
+ {
+ if (_cmCurrentItem.cmIsMain)
+ _cmCurrentItem.className = thatPrefix + 'MainItem';
+ else
+ _cmCurrentItem.className = thatPrefix + 'MenuItem';
+ if (thatMenu.id != idSub)
+ cmHideMenu (thatMenu, thisMenu, thatPrefix);
+ }
+ }
+
+ // okay, set the current menu to this obj
+ _cmCurrentItem = obj;
+
+ // just in case, reset all items in this menu to MenuItem
+ cmResetMenu (thisMenu, prefix);
+
+ var item = _cmItemList[index];
+ var isDefaultItem = cmIsDefaultItem (item);
+
+ if (isDefaultItem)
+ {
+ if (isMain)
+ obj.className = prefix + 'MainItemHover';
+ else
+ obj.className = prefix + 'MenuItemHover';
+ }
+
+ cmSetStatus (item);
+}
+
+//
+// action should be taken for mouse moving in to the menu item
+//
+// This function also opens sub menu
+//
+function cmItemMouseOverOpenSub (obj, prefix, isMain, idSub, orient, index)
+{
+ cmItemMouseOver (obj, prefix, isMain, idSub, index);
+
+ if (idSub)
+ {
+ var subMenu = cmGetObject (idSub);
+ cmShowSubMenu (obj, prefix, subMenu, orient);
+ }
+}
+
+//
+// action should be taken for mouse moving out of the menu item
+//
+function cmItemMouseOut (obj, delayTime)
+{
+ if (!delayTime)
+ delayTime = _cmNodeProperties.delay;
+ _cmTimeOut = window.setTimeout ('cmHideMenuTime ()', delayTime);
+ window.defaultStatus = '';
+}
+
+//
+// action should be taken for mouse button down at a menu item
+//
+function cmItemMouseDown (obj, index)
+{
+ if (cmIsDefaultItem (_cmItemList[index]))
+ {
+ if (obj.cmIsMain)
+ obj.className = obj.cmPrefix + 'MainItemActive';
+ else
+ obj.className = obj.cmPrefix + 'MenuItemActive';
+ }
+}
+
+//
+// action should be taken for mouse button down at a menu item
+// this is one also opens submenu if needed
+//
+function cmItemMouseDownOpenSub (obj, index, prefix, orient, idSub)
+{
+ cmItemMouseDown (obj, index);
+
+ if (idSub)
+ {
+ var subMenu = cmGetObject (idSub);
+ cmShowSubMenu (obj, prefix, subMenu, orient);
+ }
+}
+
+//
+// action should be taken for mouse button up at a menu item
+//
+function cmItemMouseUp (obj, index)
+{
+ var item = _cmItemList[index];
+
+ var link = null, target = '_self';
+
+ if (item.length > 2)
+ link = item[2];
+ if (item.length > 3 && item[3])
+ target = item[3];
+
+ if (link != null)
+ {
+ window.open (link, target);
+ }
+
+ var prefix = obj.cmPrefix;
+ var thisMenu = cmGetThisMenu (obj, prefix);
+
+ var hasChild = (item.length > 5);
+ if (!hasChild)
+ {
+ if (cmIsDefaultItem (item))
+ {
+ if (obj.cmIsMain)
+ obj.className = prefix + 'MainItem';
+ else
+ obj.className = prefix + 'MenuItem';
+ }
+ cmHideMenu (thisMenu, null, prefix);
+ }
+ else
+ {
+ if (cmIsDefaultItem (item))
+ {
+ if (obj.cmIsMain)
+ obj.className = prefix + 'MainItemHover';
+ else
+ obj.className = prefix + 'MenuItemHover';
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Mouse Event Support Utility Functions
+//
+//////////////////////////////////////////////////////////////////////
+
+//
+// move submenu to the appropriate location
+//
+// @param obj the menu item that opens up the subMenu
+// subMenu the sub menu to be shown
+// orient the orientation of the subMenu
+//
+function cmMoveSubMenu (obj, subMenu, orient)
+{
+ var mode = String (orient);
+ var p = subMenu.offsetParent;
+ var subMenuWidth = cmGetWidth (subMenu);
+ var horiz = cmGetHorizontalAlign (obj, mode, p, subMenuWidth);
+ if (mode.charAt (0) == 'h')
+ {
+ if (mode.charAt (1) == 'b')
+ subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj)) + 'px';
+ else
+ subMenu.style.top = (cmGetYAt (obj, p) - cmGetHeight (subMenu)) + 'px';
+ if (horiz == 'r')
+ subMenu.style.left = (cmGetXAt (obj, p)) + 'px';
+ else
+ subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) - subMenuWidth) + 'px';
+ }
+ else
+ {
+ if (horiz == 'r')
+ subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj)) + 'px';
+ else
+ subMenu.style.left = (cmGetXAt (obj, p) - subMenuWidth) + 'px';
+ if (mode.charAt (1) == 'b')
+ subMenu.style.top = (cmGetYAt (obj, p)) + 'px';
+ else
+ subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj) - cmGetHeight (subMenu)) + 'px';
+ }
+}
+
+//
+// automatically re-adjust the menu position based on available screen size.
+//
+function cmGetHorizontalAlign (obj, mode, p, subMenuWidth)
+{
+ var horiz = mode.charAt (2);
+ if (!(document.body))
+ return horiz;
+ var body = document.body;
+ var browserLeft;
+ var browserRight;
+ if (window.innerWidth)
+ {
+ // DOM window attributes
+ browserLeft = window.pageXOffset;
+ browserRight = window.innerWidth + browserLeft;
+ }
+ else if (body.clientWidth)
+ {
+ // IE attributes
+ browserLeft = body.clientLeft;
+ browserRight = body.clientWidth + browserLeft;
+ }
+ else
+ return horiz;
+ if (mode.charAt (0) == 'h')
+ {
+ if (horiz == 'r' && (cmGetXAt (obj) + subMenuWidth) > browserRight)
+ horiz = 'l';
+ if (horiz == 'l' && (cmGetXAt (obj) + cmGetWidth (obj) - subMenuWidth) < browserLeft)
+ horiz = 'r';
+ return horiz;
+ }
+ else
+ {
+ if (horiz == 'r' && (cmGetXAt (obj, p) + cmGetWidth (obj) + subMenuWidth) > browserRight)
+ horiz = 'l';
+ if (horiz == 'l' && (cmGetXAt (obj, p) - subMenuWidth) < browserLeft)
+ horiz = 'r';
+ return horiz;
+ }
+}
+
+//
+// show the subMenu w/ specified orientation
+// also move it to the correct coordinates
+//
+// @param obj the menu item that opens up the subMenu
+// subMenu the sub menu to be shown
+// orient the orientation of the subMenu
+//
+function cmShowSubMenu (obj, prefix, subMenu, orient)
+{
+ if (!subMenu.cmParentMenu)
+ {
+ // establish the tree w/ back edge
+ var thisMenu = cmGetThisMenu (obj, prefix);
+ subMenu.cmParentMenu = thisMenu;
+ if (!thisMenu.cmSubMenu)
+ thisMenu.cmSubMenu = new Array ();
+ //thisMenu.cmSubMenu.push (subMenu);
+ thisMenu.cmSubMenu[thisMenu.cmSubMenu.length] = subMenu;
+ }
+
+ // position the sub menu
+ cmMoveSubMenu (obj, subMenu, orient);
+ subMenu.style.visibility = 'visible';
+
+ //
+ // On IE, controls such as SELECT, OBJECT, IFRAME (before 5.5)
+ // are window based controls. So, if the sub menu and these
+ // controls overlap, sub menu would be hidden behind them. Thus
+ // one needs to turn the visibility of these controls off when the
+ // sub menu is showing, and turn their visibility back on
+ // when the sub menu is hiding.
+ //
+ if (document.all) // it is IE
+ {
+ /* part of Felix Zaslavskiy's fix on hiding controls
+ not really sure if this part is necessary, but shouldn't
+ hurt. */
+ if (!subMenu.cmOverlap)
+ subMenu.cmOverlap = new Array ();
+/*@cc_on @*/
+/*@if (@_jscript_version >= 5.5)
+ at else @*/
+ cmHideControl ("IFRAME", subMenu);
+/*@end @*/
+ cmHideControl ("SELECT", subMenu);
+ cmHideControl ("OBJECT", subMenu);
+ }
+}
+
+//
+// reset all the menu items to class MenuItem in thisMenu
+//
+function cmResetMenu (thisMenu, prefix)
+{
+ if (thisMenu.cmItems)
+ {
+ var i;
+ var str;
+ var items = thisMenu.cmItems;
+ for (i = 0; i < items.length; ++i)
+ {
+ if (items[i].cmIsMain)
+ str = prefix + 'MainItem';
+ else
+ str = prefix + 'MenuItem';
+ if (items[i].className != str)
+ items[i].className = str;
+ }
+ }
+}
+
+//
+// called by the timer to hide the menu
+//
+function cmHideMenuTime ()
+{
+ if (_cmCurrentItem)
+ {
+ var prefix = _cmCurrentItem.cmPrefix;
+ cmHideMenu (cmGetThisMenu (_cmCurrentItem, prefix), null, prefix);
+ _cmCurrentItem = null;
+ }
+}
+
+//
+// hide thisMenu, children of thisMenu, as well as the ancestor
+// of thisMenu until currentMenu is encountered. currentMenu
+// will not be hidden
+//
+function cmHideMenu (thisMenu, currentMenu, prefix)
+{
+ var str = prefix + 'SubMenu';
+
+ // hide the down stream menus
+ if (thisMenu.cmSubMenu)
+ {
+ var i;
+ for (i = 0; i < thisMenu.cmSubMenu.length; ++i)
+ {
+ cmHideSubMenu (thisMenu.cmSubMenu[i], prefix);
+ }
+ }
+
+ // hide the upstream menus
+ while (thisMenu && thisMenu != currentMenu)
+ {
+ cmResetMenu (thisMenu, prefix);
+ if (thisMenu.className == str)
+ {
+ thisMenu.style.visibility = 'hidden';
+ cmShowControl (thisMenu);
+ }
+ else
+ break;
+ thisMenu = cmGetThisMenu (thisMenu.cmParentMenu, prefix);
+ }
+}
+
+//
+// hide thisMenu as well as its sub menus if thisMenu is not
+// already hidden
+//
+function cmHideSubMenu (thisMenu, prefix)
+{
+ if (thisMenu.style.visibility == 'hidden')
+ return;
+ if (thisMenu.cmSubMenu)
+ {
+ var i;
+ for (i = 0; i < thisMenu.cmSubMenu.length; ++i)
+ {
+ cmHideSubMenu (thisMenu.cmSubMenu[i], prefix);
+ }
+ }
+ cmResetMenu (thisMenu, prefix);
+ thisMenu.style.visibility = 'hidden';
+ cmShowControl (thisMenu);
+}
+
+//
+// hide a control such as IFRAME
+//
+function cmHideControl (tagName, subMenu)
+{
+ var x = cmGetX (subMenu);
+ var y = cmGetY (subMenu);
+ var w = subMenu.offsetWidth;
+ var h = subMenu.offsetHeight;
+
+ var i;
+ for (i = 0; i < document.all.tags(tagName).length; ++i)
+ {
+ var obj = document.all.tags(tagName)[i];
+ if (!obj || !obj.offsetParent)
+ continue;
+
+ // check if the object and the subMenu overlap
+
+ var ox = cmGetX (obj);
+ var oy = cmGetY (obj);
+ var ow = obj.offsetWidth;
+ var oh = obj.offsetHeight;
+
+ if (ox > (x + w) || (ox + ow) < x)
+ continue;
+ if (oy > (y + h) || (oy + oh) < y)
+ continue;
+
+ // if object is already made hidden by a different
+ // submenu then we dont want to put it on overlap list of
+ // of a submenu a second time.
+ // - bug fixed by Felix Zaslavskiy
+ if(obj.style.visibility == "hidden")
+ continue;
+
+ //subMenu.cmOverlap.push (obj);
+ subMenu.cmOverlap[subMenu.cmOverlap.length] = obj;
+ obj.style.visibility = "hidden";
+ }
+}
+
+//
+// show the control hidden by the subMenu
+//
+function cmShowControl (subMenu)
+{
+ if (subMenu.cmOverlap)
+ {
+ var i;
+ for (i = 0; i < subMenu.cmOverlap.length; ++i)
+ subMenu.cmOverlap[i].style.visibility = "";
+ }
+ subMenu.cmOverlap = null;
+}
+
+//
+// returns the main menu or the submenu table where this obj (menu item)
+// is in
+//
+function cmGetThisMenu (obj, prefix)
+{
+ var str1 = prefix + 'SubMenu';
+ var str2 = prefix + 'Menu';
+ while (obj)
+ {
+ if (obj.className == str1 || obj.className == str2)
+ return obj;
+ obj = obj.parentNode;
+ }
+ return null;
+}
+
+//
+// return true if this item is handled using default handlers
+//
+function cmIsDefaultItem (item)
+{
+ if (item == _cmSplit || item[0] == _cmNoAction || item[0] == _cmNoClick)
+ return false;
+ return true;
+}
+
+//
+// returns the object baring the id
+//
+function cmGetObject (id)
+{
+ if (document.all)
+ return document.all[id];
+ return document.getElementById (id);
+}
+
+//
+// functions that obtain the width of an HTML element.
+//
+function cmGetWidth (obj)
+{
+ var width = obj.offsetWidth;
+ if (width > 0 || !cmIsTRNode (obj))
+ return width;
+ if (!obj.firstChild)
+ return 0;
+ // use TABLE's length can cause an extra pixel gap
+ //return obj.parentNode.parentNode.offsetWidth;
+
+ // use the left and right child instead
+ return obj.lastChild.offsetLeft - obj.firstChild.offsetLeft + cmGetWidth (obj.lastChild);
+}
+
+//
+// functions that obtain the height of an HTML element.
+//
+function cmGetHeight (obj)
+{
+ var height = obj.offsetHeight;
+ if (height > 0 || !cmIsTRNode (obj))
+ return height;
+ if (!obj.firstChild)
+ return 0;
+ // use the first child's height
+ return obj.firstChild.offsetHeight;
+}
+
+//
+// functions that obtain the coordinates of an HTML element
+//
+function cmGetX (obj)
+{
+ var x = 0;
+
+ do
+ {
+ x += obj.offsetLeft;
+ obj = obj.offsetParent;
+ }
+ while (obj);
+ return x;
+}
+
+function cmGetXAt (obj, elm)
+{
+ var x = 0;
+
+ while (obj && obj != elm)
+ {
+ x += obj.offsetLeft;
+ obj = obj.offsetParent;
+ }
+ if (obj == elm)
+ return x;
+ return x - cmGetX (elm);
+}
+
+function cmGetY (obj)
+{
+ var y = 0;
+ do
+ {
+ y += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+ while (obj);
+ return y;
+}
+
+function cmIsTRNode (obj)
+{
+ var tagName = obj.tagName;
+ return tagName == "TR" || tagName == "tr" || tagName == "Tr" || tagName == "tR";
+}
+
+//
+// get the Y position of the object. In case of TR element though,
+// we attempt to adjust the value.
+//
+function cmGetYAt (obj, elm)
+{
+ var y = 0;
+
+ if (!obj.offsetHeight && cmIsTRNode (obj))
+ {
+ var firstTR = obj.parentNode.firstChild;
+ obj = obj.firstChild;
+ y -= firstTR.firstChild.offsetTop;
+ }
+
+ while (obj && obj != elm)
+ {
+ y += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ if (obj == elm)
+ return y;
+ return y - cmGetY (elm);
+}
+
+//
+// extract description from the menu item and set the status text
+// @param item the menu item
+//
+function cmSetStatus (item)
+{
+ var descript = '';
+ if (item.length > 4)
+ descript = (item[4] != null) ? item[4] : (item[2] ? item[2] : descript);
+ else if (item.length > 2)
+ descript = (item[2] ? item[2] : descript);
+
+ window.defaultStatus = descript;
+}
+
+//
+// debug function, ignore :)
+//
+function cmGetProperties (obj)
+{
+ if (obj == undefined)
+ return 'undefined';
+ if (obj == null)
+ return 'null';
+
+ var msg = obj + ':\n';
+ var i;
+ for (i in obj)
+ msg += i + ' = ' + obj[i] + '; ';
+ return msg;
+}
+
+/* v1.4.4 1. a quick fix for a bug for _cmSplit checking. reported by
+ Son Nguyen.
+*/
+/* v1.4.3 1. changed how _cmSplit is handled a bit so that _cmNoClick can work
+ properly. All splits in predefined themes are changed to use
+ _cmNoClick instead of _cmNoAction.
+*/
+/* v1.4.2 1. fixed _cmNoClick mouse hoover bug.
+ 2. fixed a statusbar text problem that cause text to disappear when
+ hoovering mouse within the same menu item.
+ 3. changed the behavior of cmDrawFromText s.t. if the title of the
+ of a link is empty, the actual url is used as text. To clear
+ this link information, title needs to be ' '.
+*/
+/* v1.4.1 1. fixed a problem introduced in 1.4 where re-entering a main menu
+ item which doesn't have a child can disable its hover setting.
+ Apparently I deleted an extra line of code when I was doing
+ cleaning up. Reported by David Maliachi and a few others.
+*/
+/* JSCookMenu v1.4 1. fixed a minor td cell closure problem. Thanks to Georg Lorenz
+ <georg at lonux.de> for discovering that.
+ 2. added clickOpen to nodeProperties. See _cmNodeProperties for
+ description. Basically menus can be opened on click only.
+ 3. added an ability to draw menu from an html node instead of a javascript
+ tree, making this script search bot friendly (I hope?).
+*/
+/* JSCookMenu v1.31 1. fix a bug on IE with causes submenus to display at the top
+ left corner due to doctype. The fix was provided by
+ Burton Strauss <Burton at ntopsupport.com>.
+*/
+/* JSCookMenu v1.3 1. automatically realign (left and right) the submenu when
+ client space is not enough.
+ 2. add _cmNoClick to get rid of menu closing behavior
+ on the particular menu item, to make it possible for things
+ such as search box to be inside the menu.
+*/
+/* JSCookMenu v1.25 1. fix Safari positioning issue. The problem is that all TR elements are located
+ at the top left corner. Thus, need to obtain the "virtual"
+ position of these element could be at.
+*/
+/* JSCookMenu v1.24 1. fix window based control hiding bug
+ thanks to Felix Zaslavskiy <felix at bebinary.com> for the fix.
+*/
+/* JSCookMenu v1.23 1. correct a position bug when the container is positioned.
+ thanks to Andre <anders at netspace.net.au> for narrowing down
+ the problem.
+*/
+/* JSCookMenu v1.22 1. change Array.push (obj) call to Array[length] = obj.
+ Suggestion from Dick van der Kaaden <dick at netrex.nl> to
+ make the script compatible with IE 5.0
+ 2. Changed theme files a little to add z-index: 100 for sub
+ menus. This change is necessary for Netscape to avoid
+ a display problem.
+ 3. some changes to the DOM structure to make this menu working
+ on Netscape 6.0 (tested). The main reason is that NN6 does
+ not do absolute positioning with tables. Therefore an extra
+ div layer must be put around the table.
+*/
+/* JSCookMenu v1.21 1. fixed a bug that didn't add 'px' as part of coordinates.
+ JSCookMenu should be XHTML validator friendly now.
+ 2. removed unnecessary display attribute and corresponding
+ theme entry to fix a problem that Netscape sometimes
+ render Office theme incorrectly
+*/
+/* JSCookMenu v1.2. 1. fix the problem of showing status in Netscape
+ 2. changed the handler parameters a bit to allow
+ string literals to be passed to javascript based
+ links
+ 3. having null in target field would cause the link
+ to be opened in the current window, but this behavior
+ could change in the future releases
+*/
+/* JSCookMenu v1.1. added ability to hide controls in IE to show submenus properly */
+/* JSCookMenu v1.01. cmDraw generates XHTML code */
+/* JSCookMenu v1.0. (c) Copyright 2002 by Heng Yuan */
Added: plog/trunk/js/jscookmenu/themeoffice/arrow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/arrow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/arrowdown.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/arrowdown.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/blank.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/blank.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/copy.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/copy.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/copyshadow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/copyshadow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/cut.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/cut.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/cutshadow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/cutshadow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/help.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/help.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/helpshadow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/helpshadow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/new.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/new.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/open.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/open.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/openshadow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/openshadow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/paste.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/paste.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/pasteshadow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/pasteshadow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/save.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/save.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/saveshadow.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/saveshadow.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/spacer.gif
===================================================================
(Binary files differ)
Property changes on: plog/trunk/js/jscookmenu/themeoffice/spacer.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: plog/trunk/js/jscookmenu/themeoffice/theme.css
===================================================================
--- plog/trunk/js/jscookmenu/themeoffice/theme.css 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/js/jscookmenu/themeoffice/theme.css 2006-01-11 10:39:10 UTC (rev 2767)
@@ -0,0 +1,291 @@
+/* ThemeOfficeMenu Style Sheet */
+
+.ThemeOfficeMenu,.ThemeOfficeSubMenuTable
+{
+ padding: 0;
+
+ white-space: nowrap;
+ cursor: default;
+}
+
+.ThemeOfficeSubMenu
+{
+ position: absolute;
+ visibility: hidden;
+
+ /*
+ Netscape/Mozilla renders borders by increasing
+ their z-index. The following line is necessary
+ to cover any borders underneath
+ */
+ z-index: 100;
+ border: 0;
+ padding: 0;
+
+ overflow: visible;
+ border: 1px solid #8C867B;
+
+ filter:progid:DXImageTransform.Microsoft.Shadow(color=#BDC3BD, Direction=135, Strength=4);
+}
+
+.ThemeOfficeSubMenuTable
+{
+ overflow: visible;
+}
+
+.ThemeOfficeMainItem,.ThemeOfficeMainItemHover,.ThemeOfficeMainItemActive,
+.ThemeOfficeMenuItem,.ThemeOfficeMenuItemHover,.ThemeOfficeMenuItemActive
+{
+ border: 0;
+ cursor: default;
+ white-space: nowrap;
+}
+
+.ThemeOfficeMainItem
+{
+ background-color: inherit;
+ font-weight: bold;
+}
+
+.ThemeOfficeMainItemHover,.ThemeOfficeMainItemActive
+{
+ background-color: #C6D3EF;
+ font-weight: bold;
+}
+
+.ThemeOfficeMenuItem
+{
+ background-color: WHITE;
+}
+
+.ThemeOfficeMenuItemHover,.ThemeOfficeMenuItemActive
+{
+ background-color: #C6D3EF;
+}
+
+
+/* horizontal main menu */
+
+.ThemeOfficeMainItem
+{
+ padding: 1px;
+ border: 0;
+}
+
+td.ThemeOfficeMainItemHover,td.ThemeOfficeMainItemActive
+{
+ padding: 0px;
+ border: 1px solid #3169C6;
+}
+
+.ThemeOfficeMainFolderLeft,.ThemeOfficeMainItemLeft,
+.ThemeOfficeMainFolderText,.ThemeOfficeMainItemText,
+.ThemeOfficeMainFolderRight,.ThemeOfficeMainItemRight
+{
+ background-color: inherit;
+}
+
+/* vertical main menu sub components */
+
+td.ThemeOfficeMainFolderLeft,td.ThemeOfficeMainItemLeft
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 2px;
+
+ border-top: 1px solid #3169C6;
+ border-bottom: 1px solid #3169C6;
+ border-left: 1px solid #3169C6;
+
+ background-color: inherit;
+}
+
+td.ThemeOfficeMainFolderText,td.ThemeOfficeMainItemText
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+
+ border-top: 1px solid #3169C6;
+ border-bottom: 1px solid #3169C6;
+
+ background-color: inherit;
+ white-space: nowrap;
+}
+
+td.ThemeOfficeMainFolderRight,td.ThemeOfficeMainItemRight
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+
+ border-top: 1px solid #3169C6;
+ border-bottom: 1px solid #3169C6;
+ border-right: 1px solid #3169C6;
+
+ background-color: inherit;
+}
+
+tr.ThemeOfficeMainItem td.ThemeOfficeMainFolderLeft,
+tr.ThemeOfficeMainItem td.ThemeOfficeMainItemLeft
+{
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 1px;
+ padding-right: 2px;
+
+ white-space: nowrap;
+
+ border: 0;
+ background-color: inherit;
+}
+
+tr.ThemeOfficeMainItem td.ThemeOfficeMainFolderText,
+tr.ThemeOfficeMainItem td.ThemeOfficeMainItemText
+{
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 5px;
+ padding-right: 5px;
+
+ border: 0;
+ background-color: inherit;
+}
+
+tr.ThemeOfficeMainItem td.ThemeOfficeMainItemRight,
+tr.ThemeOfficeMainItem td.ThemeOfficeMainFolderRight
+{
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 0px;
+ padding-right: 1px;
+
+ border: 0;
+ background-color: inherit;
+}
+
+/* sub menu sub components */
+
+.ThemeOfficeMenuFolderLeft,.ThemeOfficeMenuItemLeft
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 1px;
+ padding-right: 3px;
+
+ border-top: 1px solid #3169C6;
+ border-bottom: 1px solid #3169C6;
+ border-left: 1px solid #3169C6;
+
+ background-color: inherit;
+ white-space: nowrap;
+}
+
+.ThemeOfficeMenuFolderText,.ThemeOfficeMenuItemText
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+
+ border-top: 1px solid #3169C6;
+ border-bottom: 1px solid #3169C6;
+
+ background-color: inherit;
+ white-space: nowrap;
+}
+
+.ThemeOfficeMenuFolderRight,.ThemeOfficeMenuItemRight
+{
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+
+ border-top: 1px solid #3169C6;
+ border-bottom: 1px solid #3169C6;
+ border-right: 1px solid #3169C6;
+
+ background-color: inherit;
+ white-space: nowrap;
+}
+
+.ThemeOfficeMenuItem .ThemeOfficeMenuFolderLeft,
+.ThemeOfficeMenuItem .ThemeOfficeMenuItemLeft
+{
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 2px;
+ padding-right: 3px;
+
+ white-space: nowrap;
+
+ border: 0;
+ background-color: #EFEFDE;
+}
+
+.ThemeOfficeMenuItem .ThemeOfficeMenuFolderText,
+.ThemeOfficeMenuItem .ThemeOfficeMenuItemText
+{
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 5px;
+ padding-right: 5px;
+
+ border: 0;
+ background-color: inherit;
+}
+
+.ThemeOfficeMenuItem .ThemeOfficeMenuFolderRight,
+.ThemeOfficeMenuItem .ThemeOfficeMenuItemRight
+{
+ padding-top: 1px;
+ padding-bottom: 1px;
+ padding-left: 0px;
+ padding-right: 1px;
+
+ border: 0;
+ background-color: inherit;
+}
+
+/* menu splits */
+
+.ThemeOfficeMenuSplit
+{
+ margin: 2px;
+ height: 1px;
+ overflow: hidden;
+ background-color: inherit;
+ border-top: 1px solid #C6C3BD;
+}
+
+/* image shadow animation */
+
+/*
+ seq1: image for normal
+ seq2: image for hover and active
+
+ To use, in the icon field, input the following:
+ <img class="seq1" src="normal.gif" /><img class="seq2" src="hover.gif" />
+*/
+
+.ThemeOfficeMenuItem img.seq1
+{
+ display: inline;
+}
+
+.ThemeOfficeMenuItemHover seq2,
+.ThemeOfficeMenuItemActive seq2
+{
+ display: inline;
+}
+
+.ThemeOfficeMenuItem .seq2,
+.ThemeOfficeMenuItemHover .seq1,
+.ThemeOfficeMenuItemActive .seq1
+{
+ display: none;
+}
Added: plog/trunk/js/jscookmenu/themeoffice/theme.js
===================================================================
--- plog/trunk/js/jscookmenu/themeoffice/theme.js 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/js/jscookmenu/themeoffice/theme.js 2006-01-11 10:39:10 UTC (rev 2767)
@@ -0,0 +1,58 @@
+
+// directory of where all the images are
+var cmThemeOfficeBase = 'js/jscookmenu/themeoffice/';
+
+// the follow block allows user to re-define theme base directory
+// before it is loaded.
+try
+{
+ if (myThemeOfficeBase)
+ {
+ cmThemeOfficeBase = myThemeOfficeBase;
+ }
+}
+catch (e)
+{
+}
+
+var cmThemeOffice =
+{
+ // main menu display attributes
+ //
+ // Note. When the menu bar is horizontal,
+ // mainFolderLeft and mainFolderRight are
+ // put in <span></span>. When the menu
+ // bar is vertical, they would be put in
+ // a separate TD cell.
+
+ // HTML code to the left of the folder item
+ mainFolderLeft: ' ',
+ // HTML code to the right of the folder item
+ mainFolderRight: ' ',
+ // HTML code to the left of the regular item
+ mainItemLeft: ' ',
+ // HTML code to the right of the regular item
+ mainItemRight: ' ',
+
+ // sub menu display attributes
+
+ // 0, HTML code to the left of the folder item
+ folderLeft: '<img alt="" src="' + cmThemeOfficeBase + 'spacer.gif">',
+ // 1, HTML code to the right of the folder item
+ folderRight: '<img alt="" src="' + cmThemeOfficeBase + 'arrow.gif">',
+ // 2, HTML code to the left of the regular item
+ itemLeft: '<img alt="" src="' + cmThemeOfficeBase + 'spacer.gif">',
+ // 3, HTML code to the right of the regular item
+ itemRight: '<img alt="" src="' + cmThemeOfficeBase + 'blank.gif">',
+ // 4, cell spacing for main menu
+ mainSpacing: 0,
+ // 5, cell spacing for sub menus
+ subSpacing: 0,
+ // 6, auto dispear time for submenus in milli-seconds
+ delay: 500
+};
+
+// for horizontal menu split
+var cmThemeOfficeHSplit = [_cmNoClick, '<td class="ThemeOfficeMenuItemLeft"></td><td colspan="2"><div class="ThemeOfficeMenuSplit"></div></td>'];
+var cmThemeOfficeMainHSplit = [_cmNoClick, '<td class="ThemeOfficeMainItemLeft"></td><td colspan="2"><div class="ThemeOfficeMenuSplit"></div></td>'];
+var cmThemeOfficeMainVSplit = [_cmNoClick, '|'];
Modified: plog/trunk/js/prototype/prototype.js
===================================================================
--- plog/trunk/js/prototype/prototype.js 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/js/prototype/prototype.js 2006-01-11 10:39:10 UTC (rev 2767)
@@ -1,8 +1,8 @@
-/* Prototype JavaScript framework, version 1.3.1
+/* Prototype JavaScript framework, version 1.4.0
* (c) 2005 Sam Stephenson <sam at conio.net>
*
* THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
- * against the source tree, available from the Prototype darcs repository.
+ * against the source tree, available from the Prototype darcs repository.
*
* Prototype is freely distributable under the terms of an MIT-style license.
*
@@ -11,13 +11,16 @@
/*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.3.1',
- emptyFunction: function() {}
+ Version: '1.4.0',
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+
+ emptyFunction: function() {},
+ K: function(x) {return x}
}
var Class = {
create: function() {
- return function() {
+ return function() {
this.initialize.apply(this, arguments);
}
}
@@ -32,30 +35,48 @@
return destination;
}
-Object.prototype.extend = function(object) {
- return Object.extend.apply(this, [this, object]);
+Object.inspect = function(object) {
+ try {
+ if (object == undefined) return 'undefined';
+ if (object == null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
}
-Function.prototype.bind = function(object) {
- var __method = this;
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
return function() {
- __method.apply(object, arguments);
+ return __method.apply(object, args.concat($A(arguments)));
}
}
Function.prototype.bindAsEventListener = function(object) {
var __method = this;
return function(event) {
- __method.call(object, event || window.event);
+ return __method.call(object, event || window.event);
}
}
-Number.prototype.toColorPart = function() {
- var digits = this.toString(16);
- if (this < 16) return '0' + digits;
- return digits;
-}
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
var Try = {
these: function() {
var returnValue;
@@ -90,10 +111,10 @@
onTimerEvent: function() {
if (!this.currentlyExecuting) {
- try {
+ try {
this.currentlyExecuting = true;
- this.callback();
- } finally {
+ this.callback();
+ } finally {
this.currentlyExecuting = false;
}
}
@@ -110,7 +131,7 @@
if (typeof element == 'string')
element = document.getElementById(element);
- if (arguments.length == 1)
+ if (arguments.length == 1)
return element;
elements.push(element);
@@ -118,38 +139,25 @@
return elements;
}
+Object.extend(String.prototype, {
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
-if (!Array.prototype.push) {
- Array.prototype.push = function() {
- var startLength = this.length;
- for (var i = 0; i < arguments.length; i++)
- this[startLength + i] = arguments[i];
- return this.length;
- }
-}
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
-if (!Function.prototype.apply) {
- // Based on code from http://www.youngpup.net/
- Function.prototype.apply = function(object, parameters) {
- var parameterStrings = new Array();
- if (!object) object = window;
- if (!parameters) parameters = new Array();
-
- for (var i = 0; i < parameters.length; i++)
- parameterStrings[i] = 'parameters[' + i + ']';
-
- object.__apply__ = this;
- var result = eval('object.__apply__(' +
- parameterStrings.join(', ') + ')');
- object.__apply__ = null;
-
- return result;
- }
-}
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
-String.prototype.extend({
- stripTags: function() {
- return this.replace(/<\/?[^>]+>/gi, '');
+ evalScripts: function() {
+ return this.extractScripts().map(eval);
},
escapeHTML: function() {
@@ -162,10 +170,382 @@
unescapeHTML: function() {
var div = document.createElement('div');
div.innerHTML = this.stripTags();
- return div.childNodes[0].nodeValue;
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+ },
+
+ toQueryParams: function() {
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
+ return pairs.inject({}, function(params, pairString) {
+ var pair = pairString.split('=');
+ params[pair[0]] = pair[1];
+ return params;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ camelize: function() {
+ var oStringList = this.split('-');
+ if (oStringList.length == 1) return oStringList[0];
+
+ var camelizedString = this.indexOf('-') == 0
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
+ : oStringList[0];
+
+ for (var i = 1, len = oStringList.length; i < len; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+
+ return camelizedString;
+ },
+
+ inspect: function() {
+ return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
}
});
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function (iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inject: function(memo, iterator) {
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.collect(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (value >= (result || value))
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (value <= (result || value))
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ return this.collect(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.collect(Prototype.K);
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (typeof args.last() == 'function')
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ iterator(value = collections.pluck(index));
+ return value;
+ });
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0; i < iterable.length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0; i < this.length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != undefined || value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0; i < this.length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ shift: function() {
+ var result = this[0];
+ for (var i = 0; i < this.length - 1; i++)
+ this[i] = this[i + 1];
+ this.length--;
+ return result;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+var Hash = {
+ _each: function(iterator) {
+ for (key in this) {
+ var value = this[key];
+ if (typeof value == 'function') continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ return pair.map(encodeURIComponent).join('=');
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+}
+
+function $H(object) {
+ var hash = Object.extend({}, object || {});
+ Object.extend(hash, Enumerable);
+ Object.extend(hash, Hash);
+ return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ do {
+ iterator(value);
+ value = value.succ();
+ } while (this.include(value));
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
var Ajax = {
getTransport: function() {
return Try.these(
@@ -173,9 +553,50 @@
function() {return new ActiveXObject('Microsoft.XMLHTTP')},
function() {return new XMLHttpRequest()}
) || false;
- }
+ },
+
+ activeRequestCount: 0
}
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responderToAdd) {
+ if (!this.include(responderToAdd))
+ this.responders.push(responderToAdd);
+ },
+
+ unregister: function(responderToRemove) {
+ this.responders = this.responders.without(responderToRemove);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (responder[callback] && typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) {}
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() {
+ Ajax.activeRequestCount++;
+ },
+
+ onComplete: function() {
+ Ajax.activeRequestCount--;
+ }
+});
+
Ajax.Base = function() {};
Ajax.Base.prototype = {
setOptions: function(options) {
@@ -183,12 +604,13 @@
method: 'post',
asynchronous: true,
parameters: ''
- }.extend(options || {});
+ }
+ Object.extend(this.options, options || {});
},
responseIsSuccess: function() {
return this.transport.status == undefined
- || this.transport.status == 0
+ || this.transport.status == 0
|| (this.transport.status >= 200 && this.transport.status < 300);
},
@@ -198,10 +620,10 @@
}
Ajax.Request = Class.create();
-Ajax.Request.Events =
+Ajax.Request.Events =
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-Ajax.Request.prototype = (new Ajax.Base()).extend({
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
initialize: function(url, options) {
this.transport = Ajax.getTransport();
this.setOptions(options);
@@ -213,10 +635,13 @@
if (parameters.length > 0) parameters += '&_=';
try {
- if (this.options.method == 'get')
- url += '?' + parameters;
+ this.url = url;
+ if (this.options.method == 'get' && parameters.length > 0)
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
- this.transport.open(this.options.method, url,
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.options.method, this.url,
this.options.asynchronous);
if (this.options.asynchronous) {
@@ -230,21 +655,22 @@
this.transport.send(this.options.method == 'post' ? body : null);
} catch (e) {
+ this.dispatchException(e);
}
},
setRequestHeaders: function() {
- var requestHeaders =
+ var requestHeaders =
['X-Requested-With', 'XMLHttpRequest',
'X-Prototype-Version', Prototype.Version];
if (this.options.method == 'post') {
- requestHeaders.push('Content-type',
+ requestHeaders.push('Content-type',
'application/x-www-form-urlencoded');
/* Force "Connection: close" for Mozilla browsers to work around
* a bug where XMLHttpReqeuest sends an incorrect Content-length
- * header. See Mozilla Bugzilla #246651.
+ * header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType)
requestHeaders.push('Connection', 'close');
@@ -263,26 +689,64 @@
this.respondToReadyState(this.transport.readyState);
},
+ header: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {}
+ },
+
+ evalJSON: function() {
+ try {
+ return eval(this.header('X-JSON'));
+ } catch (e) {}
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
respondToReadyState: function(readyState) {
var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
- if (event == 'Complete')
- (this.options['on' + this.transport.status]
- || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
- || Prototype.emptyFunction)(this.transport);
+ if (event == 'Complete') {
+ try {
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
- (this.options['on' + event] || Prototype.emptyFunction)(this.transport);
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
if (event == 'Complete')
this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
}
});
Ajax.Updater = Class.create();
-Ajax.Updater.ScriptFragment = '(?:<script.*?>)((\n|.)*?)(?:<\/script>)';
-Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
initialize: function(container, url, options) {
this.containers = {
success: container.success ? $(container.success) : $(container),
@@ -294,9 +758,9 @@
this.setOptions(options);
var onComplete = this.options.onComplete || Prototype.emptyFunction;
- this.options.onComplete = (function() {
+ this.options.onComplete = (function(transport, object) {
this.updateContent();
- onComplete(this.transport);
+ onComplete(transport, object);
}).bind(this);
this.request(url);
@@ -305,43 +769,34 @@
updateContent: function() {
var receiver = this.responseIsSuccess() ?
this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
- var match = new RegExp(Ajax.Updater.ScriptFragment, 'img');
- var response = this.transport.responseText.replace(match, '');
- var scripts = this.transport.responseText.match(match);
+ if (!this.options.evalScripts)
+ response = response.stripScripts();
if (receiver) {
if (this.options.insertion) {
new this.options.insertion(receiver, response);
} else {
- receiver.innerHTML = response;
+ Element.update(receiver, response);
}
}
if (this.responseIsSuccess()) {
if (this.onComplete)
- setTimeout((function() {this.onComplete(
- this.transport)}).bind(this), 10);
+ setTimeout(this.onComplete.bind(this), 10);
}
-
- if (this.options.evalScripts && scripts) {
- match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
- setTimeout((function() {
- for (var i = 0; i < scripts.length; i++)
- eval(scripts[i].match(match)[1]);
- }).bind(this), 10);
- }
}
});
Ajax.PeriodicalUpdater = Class.create();
-Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
initialize: function(container, url, options) {
this.setOptions(options);
this.onComplete = this.options.onComplete;
this.frequency = (this.options.frequency || 2);
- this.decay = 1;
+ this.decay = (this.options.decay || 1);
this.updater = {};
this.container = container;
@@ -358,17 +813,17 @@
stop: function() {
this.updater.onComplete = undefined;
clearTimeout(this.timer);
- (this.onComplete || Ajax.emptyFunction).apply(this, arguments);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
},
updateComplete: function(request) {
if (this.options.decay) {
- this.decay = (request.responseText == this.lastText ?
+ this.decay = (request.responseText == this.lastText ?
this.decay * this.options.decay : 1);
this.lastText = request.responseText;
}
- this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
this.decay * this.frequency * 1000);
},
@@ -376,23 +831,13 @@
this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
});
-
-document.getElementsByClassName = function(className) {
- var children = document.getElementsByTagName('*') || document.all;
- var elements = new Array();
-
- for (var i = 0; i < children.length; i++) {
- var child = children[i];
- var classNames = child.className.split(' ');
- for (var j = 0; j < classNames.length; j++) {
- if (classNames[j] == className) {
- elements.push(child);
- break;
- }
- }
- }
-
- return elements;
+document.getElementsByClassName = function(className, parentElement) {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ return $A(children).inject([], function(elements, child) {
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ elements.push(child);
+ return elements;
+ });
}
/*--------------------------------------------------------------------------*/
@@ -402,11 +847,14 @@
}
Object.extend(Element, {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
toggle: function() {
for (var i = 0; i < arguments.length; i++) {
var element = $(arguments[i]);
- element.style.display =
- (element.style.display == 'none' ? '' : 'none');
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
}
},
@@ -428,54 +876,142 @@
element = $(element);
element.parentNode.removeChild(element);
},
-
+
+ update: function(element, html) {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
getHeight: function(element) {
element = $(element);
- return element.offsetHeight;
+ return element.offsetHeight;
},
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
hasClassName: function(element, className) {
- element = $(element);
- if (!element)
- return;
- var a = element.className.split(' ');
- for (var i = 0; i < a.length; i++) {
- if (a[i] == className)
- return true;
- }
- return false;
+ if (!(element = $(element))) return;
+ return Element.classNames(element).include(className);
},
addClassName: function(element, className) {
- element = $(element);
- Element.removeClassName(element, className);
- element.className += ' ' + className;
+ if (!(element = $(element))) return;
+ return Element.classNames(element).add(className);
},
removeClassName: function(element, className) {
- element = $(element);
- if (!element)
- return;
- var newClassName = '';
- var a = element.className.split(' ');
- for (var i = 0; i < a.length; i++) {
- if (a[i] != className) {
- if (i > 0)
- newClassName += ' ';
- newClassName += a[i];
- }
- }
- element.className = newClassName;
+ if (!(element = $(element))) return;
+ return Element.classNames(element).remove(className);
},
-
+
// removes whitespace-only text node children
cleanWhitespace: function(element) {
- var element = $(element);
+ element = $(element);
for (var i = 0; i < element.childNodes.length; i++) {
var node = element.childNodes[i];
- if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
Element.remove(node);
}
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.match(/^\s*$/);
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var x = element.x ? element.x : element.offsetLeft,
+ y = element.y ? element.y : element.offsetTop;
+ window.scrollTo(x, y);
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ var value = element.style[style.camelize()];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style.camelize()];
+ }
+ }
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (name in style)
+ element.style[name.camelize()] = style[name];
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'display') != 'none')
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element._overflow = element.style.overflow;
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+ element.style.overflow = 'hidden';
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element.style.overflow = element._overflow;
+ element._overflow = undefined;
}
});
@@ -491,68 +1027,127 @@
Abstract.Insertion.prototype = {
initialize: function(element, content) {
this.element = $(element);
- this.content = content;
-
+ this.content = content.stripScripts();
+
if (this.adjacency && this.element.insertAdjacentHTML) {
- this.element.insertAdjacentHTML(this.adjacency, this.content);
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ if (this.element.tagName.toLowerCase() == 'tbody') {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
} else {
this.range = this.element.ownerDocument.createRange();
if (this.initializeRange) this.initializeRange();
- this.fragment = this.range.createContextualFragment(this.content);
- this.insertContent();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
}
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
}
}
var Insertion = new Object();
Insertion.Before = Class.create();
-Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
initializeRange: function() {
this.range.setStartBefore(this.element);
},
-
- insertContent: function() {
- this.element.parentNode.insertBefore(this.fragment, this.element);
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
}
});
Insertion.Top = Class.create();
-Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(true);
},
-
- insertContent: function() {
- this.element.insertBefore(this.fragment, this.element.firstChild);
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
}
});
Insertion.Bottom = Class.create();
-Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(this.element);
},
-
- insertContent: function() {
- this.element.appendChild(this.fragment);
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
}
});
Insertion.After = Class.create();
-Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
initializeRange: function() {
this.range.setStartAfter(this.element);
},
-
- insertContent: function() {
- this.element.parentNode.insertBefore(this.fragment,
- this.element.nextSibling);
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
}
});
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set(this.select(function(className) {
+ return className != classNameToRemove;
+ }).join(' '));
+ },
+
+ toString: function() {
+ return this.toArray().join(' ');
+ }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
var Field = {
clear: function() {
for (var i = 0; i < arguments.length; i++)
@@ -562,20 +1157,22 @@
focus: function(element) {
$(element).focus();
},
-
+
present: function() {
for (var i = 0; i < arguments.length; i++)
if ($(arguments[i]).value == '') return false;
return true;
},
-
+
select: function(element) {
$(element).select();
},
-
+
activate: function(element) {
- $(element).focus();
- $(element).select();
+ element = $(element);
+ element.focus();
+ if (element.select)
+ element.select();
}
}
@@ -585,18 +1182,18 @@
serialize: function(form) {
var elements = Form.getElements($(form));
var queryComponents = new Array();
-
+
for (var i = 0; i < elements.length; i++) {
var queryComponent = Form.Element.serialize(elements[i]);
if (queryComponent)
queryComponents.push(queryComponent);
}
-
+
return queryComponents.join('&');
},
-
+
getElements: function(form) {
- var form = $(form);
+ form = $(form);
var elements = new Array();
for (tagName in Form.Element.Serializers) {
@@ -606,19 +1203,19 @@
}
return elements;
},
-
+
getInputs: function(form, typeName, name) {
- var form = $(form);
+ form = $(form);
var inputs = form.getElementsByTagName('input');
-
+
if (!typeName && !name)
return inputs;
-
+
var matchingInputs = new Array();
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if ((typeName && input.type != typeName) ||
- (name && input.name != name))
+ (name && input.name != name))
continue;
matchingInputs.push(input);
}
@@ -643,16 +1240,15 @@
}
},
+ findFirstElement: function(form) {
+ return Form.getElements(form).find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
focusFirstElement: function(form) {
- var form = $(form);
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
- if (element.type != 'hidden' && !element.disabled) {
- Field.activate(element);
- break;
- }
- }
+ Field.activate(Form.findFirstElement(form));
},
reset: function(form) {
@@ -662,21 +1258,29 @@
Form.Element = {
serialize: function(element) {
- var element = $(element);
+ element = $(element);
var method = element.tagName.toLowerCase();
var parameter = Form.Element.Serializers[method](element);
-
- if (parameter)
- return encodeURIComponent(parameter[0]) + '=' +
- encodeURIComponent(parameter[1]);
+
+ if (parameter) {
+ var key = encodeURIComponent(parameter[0]);
+ if (key.length == 0) return;
+
+ if (parameter[1].constructor != Array)
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
},
-
+
getValue: function(element) {
- var element = $(element);
+ element = $(element);
var method = element.tagName.toLowerCase();
var parameter = Form.Element.Serializers[method](element);
-
- if (parameter)
+
+ if (parameter)
return parameter[1];
}
}
@@ -689,7 +1293,7 @@
case 'password':
case 'text':
return Form.Element.Serializers.textarea(element);
- case 'checkbox':
+ case 'checkbox':
case 'radio':
return Form.Element.Serializers.inputSelector(element);
}
@@ -706,17 +1310,30 @@
},
select: function(element) {
- var value = '';
- if (element.type == 'select-one') {
- var index = element.selectedIndex;
- if (index >= 0)
- value = element.options[index].value || element.options[index].text;
- } else {
- value = new Array();
- for (var i = 0; i < element.length; i++) {
- var opt = element.options[i];
- if (opt.selected)
- value.push(opt.value || opt.text);
+ return Form.Element.Serializers[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function(element) {
+ var value = '', opt, index = element.selectedIndex;
+ if (index >= 0) {
+ opt = element.options[index];
+ value = opt.value;
+ if (!value && !('value' in opt))
+ value = opt.text;
+ }
+ return [element.name, value];
+ },
+
+ selectMany: function(element) {
+ var value = new Array();
+ for (var i = 0; i < element.length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) {
+ var optValue = opt.value;
+ if (!optValue && !('value' in opt))
+ optValue = opt.text;
+ value.push(optValue);
}
}
return [element.name, value];
@@ -735,15 +1352,15 @@
this.frequency = frequency;
this.element = $(element);
this.callback = callback;
-
+
this.lastValue = this.getValue();
this.registerCallback();
},
-
+
registerCallback: function() {
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
-
+
onTimerEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
@@ -754,14 +1371,14 @@
}
Form.Element.Observer = Class.create();
-Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.Observer = Class.create();
-Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
getValue: function() {
return Form.serialize(this.element);
}
@@ -774,14 +1391,14 @@
initialize: function(element, callback) {
this.element = $(element);
this.callback = callback;
-
+
this.lastValue = this.getValue();
if (this.element.tagName.toLowerCase() == 'form')
this.registerFormCallbacks();
else
this.registerCallback(this.element);
},
-
+
onElementEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
@@ -789,57 +1406,45 @@
this.lastValue = value;
}
},
-
+
registerFormCallbacks: function() {
var elements = Form.getElements(this.element);
for (var i = 0; i < elements.length; i++)
this.registerCallback(elements[i]);
},
-
+
registerCallback: function(element) {
if (element.type) {
switch (element.type.toLowerCase()) {
- case 'checkbox':
+ case 'checkbox':
case 'radio':
- element.target = this;
- element.prev_onclick = element.onclick || Prototype.emptyFunction;
- element.onclick = function() {
- this.prev_onclick();
- this.target.onElementEvent();
- }
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
break;
case 'password':
case 'text':
case 'textarea':
case 'select-one':
case 'select-multiple':
- element.target = this;
- element.prev_onchange = element.onchange || Prototype.emptyFunction;
- element.onchange = function() {
- this.prev_onchange();
- this.target.onElementEvent();
- }
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
break;
}
- }
+ }
}
}
Form.Element.EventObserver = Class.create();
-Form.Element.EventObserver.prototype = (new Abstract.EventObserver()).extend({
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.EventObserver = Class.create();
-Form.EventObserver.prototype = (new Abstract.EventObserver()).extend({
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
getValue: function() {
return Form.serialize(this.element);
}
});
-
-
if (!window.Event) {
var Event = new Object();
}
@@ -865,21 +1470,22 @@
},
pointerX: function(event) {
- return event.pageX || (event.clientX +
+ return event.pageX || (event.clientX +
(document.documentElement.scrollLeft || document.body.scrollLeft));
},
pointerY: function(event) {
- return event.pageY || (event.clientY +
+ return event.pageY || (event.clientY +
(document.documentElement.scrollTop || document.body.scrollTop));
},
stop: function(event) {
- if (event.preventDefault) {
- event.preventDefault();
- event.stopPropagation();
+ if (event.preventDefault) {
+ event.preventDefault();
+ event.stopPropagation();
} else {
event.returnValue = false;
+ event.cancelBubble = true;
}
},
@@ -894,7 +1500,7 @@
},
observers: false,
-
+
_observeAndCache: function(element, name, observer, useCapture) {
if (!this.observers) this.observers = [];
if (element.addEventListener) {
@@ -905,7 +1511,7 @@
element.attachEvent('on' + name, observer);
}
},
-
+
unloadCache: function() {
if (!Event.observers) return;
for (var i = 0; i < Event.observers.length; i++) {
@@ -918,24 +1524,24 @@
observe: function(element, name, observer, useCapture) {
var element = $(element);
useCapture = useCapture || false;
-
+
if (name == 'keypress' &&
- ((navigator.appVersion.indexOf('AppleWebKit') > 0)
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.attachEvent))
name = 'keydown';
-
+
this._observeAndCache(element, name, observer, useCapture);
},
stopObserving: function(element, name, observer, useCapture) {
var element = $(element);
useCapture = useCapture || false;
-
+
if (name == 'keypress' &&
- ((navigator.appVersion.indexOf('AppleWebKit') > 0)
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.detachEvent))
name = 'keydown';
-
+
if (element.removeEventListener) {
element.removeEventListener(name, observer, useCapture);
} else if (element.detachEvent) {
@@ -946,24 +1552,22 @@
/* prevent memory leaks in IE */
Event.observe(window, 'unload', Event.unloadCache, false);
-
var Position = {
-
// set to true if needed, warning: firefox performance problems
// NOT neeeded for page scrolling, only if draggable contained in
// scrollable elements
- includeScrollOffsets: false,
+ includeScrollOffsets: false,
// must be called before calling withinIncludingScrolloffset, every time the
// page is scrolled
prepare: function() {
- this.deltaX = window.pageXOffset
- || document.documentElement.scrollLeft
- || document.body.scrollLeft
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
|| 0;
- this.deltaY = window.pageYOffset
- || document.documentElement.scrollTop
- || document.body.scrollTop
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
|| 0;
},
@@ -971,7 +1575,7 @@
var valueT = 0, valueL = 0;
do {
valueT += element.scrollTop || 0;
- valueL += element.scrollLeft || 0;
+ valueL += element.scrollLeft || 0;
element = element.parentNode;
} while (element);
return [valueL, valueT];
@@ -987,6 +1591,31 @@
return [valueL, valueT];
},
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ p = Element.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ offsetParent: function(element) {
+ if (element.offsetParent) return element.offsetParent;
+ if (element == document.body) return element;
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return element;
+
+ return document.body;
+ },
+
// caches x/y coordinate pair to use with overlap
within: function(element, x, y) {
if (this.includeScrollOffsets)
@@ -997,7 +1626,7 @@
return (y >= this.offset[1] &&
y < this.offset[1] + element.offsetHeight &&
- x >= this.offset[0] &&
+ x >= this.offset[0] &&
x < this.offset[0] + element.offsetWidth);
},
@@ -1010,18 +1639,18 @@
return (this.ycomp >= this.offset[1] &&
this.ycomp < this.offset[1] + element.offsetHeight &&
- this.xcomp >= this.offset[0] &&
+ this.xcomp >= this.offset[0] &&
this.xcomp < this.offset[0] + element.offsetWidth);
},
// within must be called directly before
- overlap: function(mode, element) {
- if (!mode) return 0;
- if (mode == 'vertical')
- return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
element.offsetHeight;
if (mode == 'horizontal')
- return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
element.offsetWidth;
},
@@ -1034,5 +1663,123 @@
target.style.left = offsets[0] + 'px';
target.style.width = source.offsetWidth + 'px';
target.style.height = source.offsetHeight + 'px';
+ },
+
+ page: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent==document.body)
+ if (Element.getStyle(element,'position')=='absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ } while (element = element.parentNode);
+
+ return [valueL, valueT];
+ },
+
+ clone: function(source, target) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || {})
+
+ // find page position of source
+ source = $(source);
+ var p = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(target,'position') == 'absolute') {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.style.position == 'absolute') return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';;
+ element.style.left = left + 'px';;
+ element.style.width = width + 'px';;
+ element.style.height = height + 'px';;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.style.position == 'relative') return;
+ Position.prepare();
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
}
}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ Position.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return [valueL, valueT];
+ }
+}
\ No newline at end of file
Added: plog/trunk/js/rico/rico.js
===================================================================
--- plog/trunk/js/rico/rico.js 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/js/rico/rico.js 2006-01-11 10:39:10 UTC (rev 2767)
@@ -0,0 +1,2933 @@
+/**
+ *
+ * Copyright 2005 Sabre Airline Solutions
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ **/
+
+
+//-------------------- rico.js
+var Rico = {
+ Version: '1.1.0',
+ prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
+}
+
+if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
+ throw("Rico requires the Prototype JavaScript framework >= 1.3");
+
+Rico.ArrayExtensions = new Array();
+
+if (Object.prototype.extend) {
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}else{
+ Object.prototype.extend = function(object) {
+ return Object.extend.apply(this, [this, object]);
+ }
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}
+
+if (Array.prototype.push) {
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
+}
+
+if (!Array.prototype.remove) {
+ Array.prototype.remove = function(dx) {
+ if( isNaN(dx) || dx > this.length )
+ return false;
+ for( var i=0,n=0; i<this.length; i++ )
+ if( i != dx )
+ this[n++]=this[i];
+ this.length-=1;
+ };
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
+}
+
+if (!Array.prototype.removeItem) {
+ Array.prototype.removeItem = function(item) {
+ for ( var i = 0 ; i < this.length ; i++ )
+ if ( this[i] == item ) {
+ this.remove(i);
+ break;
+ }
+ };
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
+}
+
+if (!Array.prototype.indices) {
+ Array.prototype.indices = function() {
+ var indexArray = new Array();
+ for ( index in this ) {
+ var ignoreThis = false;
+ for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
+ if ( this[index] == Rico.ArrayExtensions[i] ) {
+ ignoreThis = true;
+ break;
+ }
+ }
+ if ( !ignoreThis )
+ indexArray[ indexArray.length ] = index;
+ }
+ return indexArray;
+ }
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
+}
+
+// Create the loadXML method and xml getter for Mozilla
+if ( window.DOMParser &&
+ window.XMLSerializer &&
+ window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
+
+ if (!Document.prototype.loadXML) {
+ Document.prototype.loadXML = function (s) {
+ var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
+ while (this.hasChildNodes())
+ this.removeChild(this.lastChild);
+
+ for (var i = 0; i < doc2.childNodes.length; i++) {
+ this.appendChild(this.importNode(doc2.childNodes[i], true));
+ }
+ };
+ }
+
+ Document.prototype.__defineGetter__( "xml",
+ function () {
+ return (new XMLSerializer()).serializeToString(this);
+ }
+ );
+}
+
+document.getElementsByTagAndClassName = function(tagName, className) {
+ if ( tagName == null )
+ tagName = '*';
+
+ var children = document.getElementsByTagName(tagName) || document.all;
+ var elements = new Array();
+
+ if ( className == null )
+ return children;
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ var classNames = child.className.split(' ');
+ for (var j = 0; j < classNames.length; j++) {
+ if (classNames[j] == className) {
+ elements.push(child);
+ break;
+ }
+ }
+ }
+
+ return elements;
+}
+
+
+//-------------------- ricoAccordion.js
+Rico.Accordion = Class.create();
+
+Rico.Accordion.prototype = {
+
+ initialize: function(container, options) {
+ this.container = $(container);
+ this.lastExpandedTab = null;
+ this.accordionTabs = new Array();
+ this.setOptions(options);
+ this._attachBehaviors();
+ if(!container) return;
+
+ this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
+ // validate onloadShowTab
+ if (this.options.onLoadShowTab >= this.accordionTabs.length)
+ this.options.onLoadShowTab = 0;
+
+ // set the initial visual state...
+ for ( var i=0 ; i < this.accordionTabs.length ; i++ )
+ {
+ if (i != this.options.onLoadShowTab){
+ this.accordionTabs[i].collapse();
+ this.accordionTabs[i].content.style.display = 'none';
+ }
+ }
+ this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
+ if (this.options.panelHeight == 'auto'){
+ var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0;
+ var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
+ if (isNaN(titleBarSize))
+ titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;
+
+ var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
+ var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height'));
+ if (isNaN(parentHeight))
+ parentHeight = this.container.parentNode.offsetHeight;
+
+ this.options.panelHeight = parentHeight - totalTitleBarSize-2;
+ }
+
+ this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
+ this.lastExpandedTab.showExpanded();
+ this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
+
+ },
+
+ setOptions: function(options) {
+ this.options = {
+ expandedBg : '#63699c',
+ hoverBg : '#63699c',
+ collapsedBg : '#6b79a5',
+ expandedTextColor : '#ffffff',
+ expandedFontWeight : 'bold',
+ hoverTextColor : '#ffffff',
+ collapsedTextColor : '#ced7ef',
+ collapsedFontWeight : 'normal',
+ hoverTextColor : '#ffffff',
+ borderColor : '#1f669b',
+ panelHeight : 200,
+ onHideTab : null,
+ onShowTab : null,
+ onLoadShowTab : 0
+ }
+ Object.extend(this.options, options || {});
+ },
+
+ showTabByIndex: function( anIndex, animate ) {
+ var doAnimate = arguments.length == 1 ? true : animate;
+ this.showTab( this.accordionTabs[anIndex], doAnimate );
+ },
+
+ showTab: function( accordionTab, animate ) {
+
+ var doAnimate = arguments.length == 1 ? true : animate;
+
+ if ( this.options.onHideTab )
+ this.options.onHideTab(this.lastExpandedTab);
+
+ this.lastExpandedTab.showCollapsed();
+ var accordion = this;
+ var lastExpandedTab = this.lastExpandedTab;
+
+ this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
+ accordionTab.content.style.display = '';
+
+ accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
+
+ if ( doAnimate ) {
+ new Rico.Effect.AccordionSize( this.lastExpandedTab.content,
+ accordionTab.content,
+ 1,
+ this.options.panelHeight,
+ 100, 10,
+ { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
+ this.lastExpandedTab = accordionTab;
+ }
+ else {
+ this.lastExpandedTab.content.style.height = "1px";
+ accordionTab.content.style.height = this.options.panelHeight + "px";
+ this.lastExpandedTab = accordionTab;
+ this.showTabDone(lastExpandedTab);
+ }
+ },
+
+ showTabDone: function(collapsedTab) {
+ collapsedTab.content.style.display = 'none';
+ this.lastExpandedTab.showExpanded();
+ if ( this.options.onShowTab )
+ this.options.onShowTab(this.lastExpandedTab);
+ },
+
+ _attachBehaviors: function() {
+ var panels = this._getDirectChildrenByTag(this.container, 'DIV');
+ for ( var i = 0 ; i < panels.length ; i++ ) {
+
+ var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
+ if ( tabChildren.length != 2 )
+ continue; // unexpected
+
+ var tabTitleBar = tabChildren[0];
+ var tabContentBox = tabChildren[1];
+ this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
+ }
+ },
+
+ _getDirectChildrenByTag: function(e, tagName) {
+ var kids = new Array();
+ var allKids = e.childNodes;
+ for( var i = 0 ; i < allKids.length ; i++ )
+ if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
+ kids.push(allKids[i]);
+ return kids;
+ }
+
+};
+
+Rico.Accordion.Tab = Class.create();
+
+Rico.Accordion.Tab.prototype = {
+
+ initialize: function(accordion, titleBar, content) {
+ this.accordion = accordion;
+ this.titleBar = titleBar;
+ this.content = content;
+ this._attachBehaviors();
+ },
+
+ collapse: function() {
+ this.showCollapsed();
+ this.content.style.height = "1px";
+ },
+
+ showCollapsed: function() {
+ this.expanded = false;
+ this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
+ this.titleBar.style.color = this.accordion.options.collapsedTextColor;
+ this.titleBar.style.fontWeight = this.accordion.options.collapsedFontWeight;
+ this.content.style.overflow = "hidden";
+ },
+
+ showExpanded: function() {
+ this.expanded = true;
+ this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
+ this.titleBar.style.color = this.accordion.options.expandedTextColor;
+ this.content.style.overflow = "visible";
+ },
+
+ titleBarClicked: function(e) {
+ if ( this.accordion.lastExpandedTab == this )
+ return;
+ this.accordion.showTab(this);
+ },
+
+ hover: function(e) {
+ this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
+ this.titleBar.style.color = this.accordion.options.hoverTextColor;
+ },
+
+ unhover: function(e) {
+ if ( this.expanded ) {
+ this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
+ this.titleBar.style.color = this.accordion.options.expandedTextColor;
+ }
+ else {
+ this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
+ this.titleBar.style.color = this.accordion.options.collapsedTextColor;
+ }
+ },
+
+ _attachBehaviors: function() {
+ this.content.style.border = "1px solid " + this.accordion.options.borderColor;
+ this.content.style.borderTopWidth = "0px";
+ this.content.style.borderBottomWidth = "0px";
+ this.content.style.margin = "0px";
+
+ this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this);
+ this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
+ this.titleBar.onmouseout = this.unhover.bindAsEventListener(this);
+ }
+
+};
+
+
+//-------------------- ricoAjaxEngine.js
+Rico.AjaxEngine = Class.create();
+
+Rico.AjaxEngine.prototype = {
+
+ initialize: function() {
+ this.ajaxElements = new Array();
+ this.ajaxObjects = new Array();
+ this.requestURLS = new Array();
+ this.options = {};
+ },
+
+ registerAjaxElement: function( anId, anElement ) {
+ if ( !anElement )
+ anElement = $(anId);
+ this.ajaxElements[anId] = anElement;
+ },
+
+ registerAjaxObject: function( anId, anObject ) {
+ this.ajaxObjects[anId] = anObject;
+ },
+
+ registerRequest: function (requestLogicalName, requestURL) {
+ this.requestURLS[requestLogicalName] = requestURL;
+ },
+
+ sendRequest: function(requestName, options) {
+ // Allow for backwards Compatibility
+ if ( arguments.length >= 2 )
+ if (typeof arguments[1] == 'string')
+ options = {parameters: this._createQueryString(arguments, 1)};
+ this.sendRequestWithData(requestName, null, options);
+ },
+
+ sendRequestWithData: function(requestName, xmlDocument, options) {
+ var requestURL = this.requestURLS[requestName];
+ if ( requestURL == null )
+ return;
+
+ // Allow for backwards Compatibility
+ if ( arguments.length >= 3 )
+ if (typeof arguments[2] == 'string')
+ options.parameters = this._createQueryString(arguments, 2);
+
+ new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
+ },
+
+ sendRequestAndUpdate: function(requestName,container,options) {
+ // Allow for backwards Compatibility
+ if ( arguments.length >= 3 )
+ if (typeof arguments[2] == 'string')
+ options.parameters = this._createQueryString(arguments, 2);
+
+ this.sendRequestWithDataAndUpdate(requestName, null, container, options);
+ },
+
+ sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
+ var requestURL = this.requestURLS[requestName];
+ if ( requestURL == null )
+ return;
+
+ // Allow for backwards Compatibility
+ if ( arguments.length >= 4 )
+ if (typeof arguments[3] == 'string')
+ options.parameters = this._createQueryString(arguments, 3);
+
+ var updaterOptions = this._requestOptions(options,xmlDocument);
+
+ new Ajax.Updater(container, requestURL, updaterOptions);
+ },
+
+ // Private -- not part of intended engine API --------------------------------------------------------------------
+
+ _requestOptions: function(options,xmlDoc) {
+ var requestHeaders = ['X-Rico-Version', Rico.Version ];
+ var sendMethod = 'post';
+ if ( xmlDoc == null )
+ if (Rico.prototypeVersion < 1.4)
+ requestHeaders.push( 'Content-type', 'text/xml' );
+ else
+ sendMethod = 'get';
+ (!options) ? options = {} : '';
+
+ if (!options._RicoOptionsProcessed){
+ // Check and keep any user onComplete functions
+ if (options.onComplete)
+ options.onRicoComplete = options.onComplete;
+ // Fix onComplete
+ if (options.overrideOnComplete)
+ options.onComplete = options.overrideOnComplete;
+ else
+ options.onComplete = this._onRequestComplete.bind(this);
+ options._RicoOptionsProcessed = true;
+ }
+
+ // Set the default options and extend with any user options
+ this.options = {
+ requestHeaders: requestHeaders,
+ parameters: options.parameters,
+ postBody: xmlDoc,
+ method: sendMethod,
+ onComplete: options.onComplete
+ };
+ // Set any user options:
+ Object.extend(this.options, options);
+ return this.options;
+ },
+
+ _createQueryString: function( theArgs, offset ) {
+ var queryString = ""
+ for ( var i = offset ; i < theArgs.length ; i++ ) {
+ if ( i != offset )
+ queryString += "&";
+
+ var anArg = theArgs[i];
+
+ if ( anArg.name != undefined && anArg.value != undefined ) {
+ queryString += anArg.name + "=" + escape(anArg.value);
+ }
+ else {
+ var ePos = anArg.indexOf('=');
+ var argName = anArg.substring( 0, ePos );
+ var argValue = anArg.substring( ePos + 1 );
+ queryString += argName + "=" + escape(argValue);
+ }
+ }
+ return queryString;
+ },
+
+ _onRequestComplete : function(request) {
+ if(!request)
+ return;
+ // User can set an onFailure option - which will be called by prototype
+ if (request.status != 200)
+ return;
+
+ var response = request.responseXML.getElementsByTagName("ajax-response");
+ if (response == null || response.length != 1)
+ return;
+ this._processAjaxResponse( response[0].childNodes );
+
+ // Check if user has set a onComplete function
+ var onRicoComplete = this.options.onRicoComplete;
+ if (onRicoComplete != null)
+ onRicoComplete();
+ },
+
+ _processAjaxResponse: function( xmlResponseElements ) {
+ for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
+ var responseElement = xmlResponseElements[i];
+
+ // only process nodes of type element.....
+ if ( responseElement.nodeType != 1 )
+ continue;
+
+ var responseType = responseElement.getAttribute("type");
+ var responseId = responseElement.getAttribute("id");
+
+ if ( responseType == "object" )
+ this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
+ else if ( responseType == "element" )
+ this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
+ else
+ alert('unrecognized AjaxResponse type : ' + responseType );
+ }
+ },
+
+ _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
+ ajaxObject.ajaxUpdate( responseElement );
+ },
+
+ _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
+ ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
+ }
+
+}
+
+var ajaxEngine = new Rico.AjaxEngine();
+
+
+//-------------------- ricoColor.js
+Rico.Color = Class.create();
+
+Rico.Color.prototype = {
+
+ initialize: function(red, green, blue) {
+ this.rgb = { r: red, g : green, b : blue };
+ },
+
+ setRed: function(r) {
+ this.rgb.r = r;
+ },
+
+ setGreen: function(g) {
+ this.rgb.g = g;
+ },
+
+ setBlue: function(b) {
+ this.rgb.b = b;
+ },
+
+ setHue: function(h) {
+
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.h = h;
+
+ // convert back to RGB...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setSaturation: function(s) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.s = s;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setBrightness: function(b) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.b = b;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+ },
+
+ darken: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+ },
+
+ brighten: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+ },
+
+ blend: function(other) {
+ this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+ this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+ this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+ },
+
+ isBright: function() {
+ var hsb = this.asHSB();
+ return this.asHSB().b > 0.5;
+ },
+
+ isDark: function() {
+ return ! this.isBright();
+ },
+
+ asRGB: function() {
+ return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+ },
+
+ asHex: function() {
+ return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
+ },
+
+ asHSB: function() {
+ return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+ },
+
+ toString: function() {
+ return this.asHex();
+ }
+
+};
+
+Rico.Color.createFromHex = function(hexCode) {
+ if(hexCode.length==4) {
+ var shortHexCode = hexCode;
+ var hexCode = '#';
+ for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) +
+shortHexCode.charAt(i));
+ }
+ if ( hexCode.indexOf('#') == 0 )
+ hexCode = hexCode.substring(1);
+ var red = hexCode.substring(0,2);
+ var green = hexCode.substring(2,4);
+ var blue = hexCode.substring(4,6);
+ return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+}
+
+/**
+ * Factory method for creating a color from the background of
+ * an HTML element.
+ */
+Rico.Color.createColorFromBackground = function(elem) {
+
+ var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
+
+ if ( actualColor == "transparent" && elem.parentNode )
+ return Rico.Color.createColorFromBackground(elem.parentNode);
+
+ if ( actualColor == null )
+ return new Rico.Color(255,255,255);
+
+ if ( actualColor.indexOf("rgb(") == 0 ) {
+ var colors = actualColor.substring(4, actualColor.length - 1 );
+ var colorArray = colors.split(",");
+ return new Rico.Color( parseInt( colorArray[0] ),
+ parseInt( colorArray[1] ),
+ parseInt( colorArray[2] ) );
+
+ }
+ else if ( actualColor.indexOf("#") == 0 ) {
+ return Rico.Color.createFromHex(actualColor);
+ }
+ else
+ return new Rico.Color(255,255,255);
+}
+
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+
+ if (saturation == 0) {
+ red = parseInt(brightness * 255.0 + 0.5);
+ green = red;
+ blue = red;
+ }
+ else {
+ var h = (hue - Math.floor(hue)) * 6.0;
+ var f = h - Math.floor(h);
+ var p = brightness * (1.0 - saturation);
+ var q = brightness * (1.0 - saturation * f);
+ var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+ switch (parseInt(h)) {
+ case 0:
+ red = (brightness * 255.0 + 0.5);
+ green = (t * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 1:
+ red = (q * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 2:
+ red = (p * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (t * 255.0 + 0.5);
+ break;
+ case 3:
+ red = (p * 255.0 + 0.5);
+ green = (q * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 4:
+ red = (t * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 5:
+ red = (brightness * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (q * 255.0 + 0.5);
+ break;
+ }
+ }
+
+ return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+}
+
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+ var hue;
+ var saturation;
+ var brightness;
+
+ var cmax = (r > g) ? r : g;
+ if (b > cmax)
+ cmax = b;
+
+ var cmin = (r < g) ? r : g;
+ if (b < cmin)
+ cmin = b;
+
+ brightness = cmax / 255.0;
+ if (cmax != 0)
+ saturation = (cmax - cmin)/cmax;
+ else
+ saturation = 0;
+
+ if (saturation == 0)
+ hue = 0;
+ else {
+ var redc = (cmax - r)/(cmax - cmin);
+ var greenc = (cmax - g)/(cmax - cmin);
+ var bluec = (cmax - b)/(cmax - cmin);
+
+ if (r == cmax)
+ hue = bluec - greenc;
+ else if (g == cmax)
+ hue = 2.0 + redc - bluec;
+ else
+ hue = 4.0 + greenc - redc;
+
+ hue = hue / 6.0;
+ if (hue < 0)
+ hue = hue + 1.0;
+ }
+
+ return { h : hue, s : saturation, b : brightness };
+}
+
+
+//-------------------- ricoCorner.js
+Rico.Corner = {
+
+ round: function(e, options) {
+ var e = $(e);
+ this._setOptions(options);
+
+ var color = this.options.color;
+ if ( this.options.color == "fromElement" )
+ color = this._background(e);
+
+ var bgColor = this.options.bgColor;
+ if ( this.options.bgColor == "fromParent" )
+ bgColor = this._background(e.offsetParent);
+
+ this._roundCornersImpl(e, color, bgColor);
+ },
+
+ _roundCornersImpl: function(e, color, bgColor) {
+ if(this.options.border)
+ this._renderBorder(e,bgColor);
+ if(this._isTopRounded())
+ this._roundTopCorners(e,color,bgColor);
+ if(this._isBottomRounded())
+ this._roundBottomCorners(e,color,bgColor);
+ },
+
+ _renderBorder: function(el,bgColor) {
+ var borderValue = "1px solid " + this._borderColor(bgColor);
+ var borderL = "border-left: " + borderValue;
+ var borderR = "border-right: " + borderValue;
+ var style = "style='" + borderL + ";" + borderR + "'";
+ el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
+ },
+
+ _roundTopCorners: function(el, color, bgColor) {
+ var corner = this._createCorner(bgColor);
+ for(var i=0 ; i < this.options.numSlices ; i++ )
+ corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
+ el.style.paddingTop = 0;
+ el.insertBefore(corner,el.firstChild);
+ },
+
+ _roundBottomCorners: function(el, color, bgColor) {
+ var corner = this._createCorner(bgColor);
+ for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
+ corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
+ el.style.paddingBottom = 0;
+ el.appendChild(corner);
+ },
+
+ _createCorner: function(bgColor) {
+ var corner = document.createElement("div");
+ corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+ return corner;
+ },
+
+ _createCornerSlice: function(color,bgColor, n, position) {
+ var slice = document.createElement("span");
+
+ var inStyle = slice.style;
+ inStyle.backgroundColor = color;
+ inStyle.display = "block";
+ inStyle.height = "1px";
+ inStyle.overflow = "hidden";
+ inStyle.fontSize = "1px";
+
+ var borderColor = this._borderColor(color,bgColor);
+ if ( this.options.border && n == 0 ) {
+ inStyle.borderTopStyle = "solid";
+ inStyle.borderTopWidth = "1px";
+ inStyle.borderLeftWidth = "0px";
+ inStyle.borderRightWidth = "0px";
+ inStyle.borderBottomWidth = "0px";
+ inStyle.height = "0px"; // assumes css compliant box model
+ inStyle.borderColor = borderColor;
+ }
+ else if(borderColor) {
+ inStyle.borderColor = borderColor;
+ inStyle.borderStyle = "solid";
+ inStyle.borderWidth = "0px 1px";
+ }
+
+ if ( !this.options.compact && (n == (this.options.numSlices-1)) )
+ inStyle.height = "2px";
+
+ this._setMargin(slice, n, position);
+ this._setBorder(slice, n, position);
+ return slice;
+ },
+
+ _setOptions: function(options) {
+ this.options = {
+ corners : "all",
+ color : "fromElement",
+ bgColor : "fromParent",
+ blend : true,
+ border : false,
+ compact : false
+ }
+ Object.extend(this.options, options || {});
+
+ this.options.numSlices = this.options.compact ? 2 : 4;
+ if ( this._isTransparent() )
+ this.options.blend = false;
+ },
+
+ _whichSideTop: function() {
+ if ( this._hasString(this.options.corners, "all", "top") )
+ return "";
+
+ if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
+ return "";
+
+ if (this.options.corners.indexOf("tl") >= 0)
+ return "left";
+ else if (this.options.corners.indexOf("tr") >= 0)
+ return "right";
+ return "";
+ },
+
+ _whichSideBottom: function() {
+ if ( this._hasString(this.options.corners, "all", "bottom") )
+ return "";
+
+ if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
+ return "";
+
+ if(this.options.corners.indexOf("bl") >=0)
+ return "left";
+ else if(this.options.corners.indexOf("br")>=0)
+ return "right";
+ return "";
+ },
+
+ _borderColor : function(color,bgColor) {
+ if ( color == "transparent" )
+ return bgColor;
+ else if ( this.options.border )
+ return this.options.border;
+ else if ( this.options.blend )
+ return this._blend( bgColor, color );
+ else
+ return "";
+ },
+
+
+ _setMargin: function(el, n, corners) {
+ var marginSize = this._marginSize(n);
+ var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+ if ( whichSide == "left" ) {
+ el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
+ }
+ else if ( whichSide == "right" ) {
+ el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px";
+ }
+ else {
+ el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
+ }
+ },
+
+ _setBorder: function(el,n,corners) {
+ var borderSize = this._borderSize(n);
+ var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+ if ( whichSide == "left" ) {
+ el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
+ }
+ else if ( whichSide == "right" ) {
+ el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px";
+ }
+ else {
+ el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+ }
+ if (this.options.border != false)
+ el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+ },
+
+ _marginSize: function(n) {
+ if ( this._isTransparent() )
+ return 0;
+
+ var marginSizes = [ 5, 3, 2, 1 ];
+ var blendedMarginSizes = [ 3, 2, 1, 0 ];
+ var compactMarginSizes = [ 2, 1 ];
+ var smBlendedMarginSizes = [ 1, 0 ];
+
+ if ( this.options.compact && this.options.blend )
+ return smBlendedMarginSizes[n];
+ else if ( this.options.compact )
+ return compactMarginSizes[n];
+ else if ( this.options.blend )
+ return blendedMarginSizes[n];
+ else
+ return marginSizes[n];
+ },
+
+ _borderSize: function(n) {
+ var transparentBorderSizes = [ 5, 3, 2, 1 ];
+ var blendedBorderSizes = [ 2, 1, 1, 1 ];
+ var compactBorderSizes = [ 1, 0 ];
+ var actualBorderSizes = [ 0, 2, 0, 0 ];
+
+ if ( this.options.compact && (this.options.blend || this._isTransparent()) )
+ return 1;
+ else if ( this.options.compact )
+ return compactBorderSizes[n];
+ else if ( this.options.blend )
+ return blendedBorderSizes[n];
+ else if ( this.options.border )
+ return actualBorderSizes[n];
+ else if ( this._isTransparent() )
+ return transparentBorderSizes[n];
+ return 0;
+ },
+
+ _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
+ _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
+ _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
+ _isTransparent: function() { return this.options.color == "transparent"; },
+ _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
+ _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
+ _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
+}
+
+
+//-------------------- ricoDragAndDrop.js
+Rico.DragAndDrop = Class.create();
+
+Rico.DragAndDrop.prototype = {
+
+ initialize: function() {
+ this.dropZones = new Array();
+ this.draggables = new Array();
+ this.currentDragObjects = new Array();
+ this.dragElement = null;
+ this.lastSelectedDraggable = null;
+ this.currentDragObjectVisible = false;
+ this.interestedInMotionEvents = false;
+ this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
+ this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
+ this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
+ },
+
+ registerDropZone: function(aDropZone) {
+ this.dropZones[ this.dropZones.length ] = aDropZone;
+ },
+
+ deregisterDropZone: function(aDropZone) {
+ var newDropZones = new Array();
+ var j = 0;
+ for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
+ if ( this.dropZones[i] != aDropZone )
+ newDropZones[j++] = this.dropZones[i];
+ }
+
+ this.dropZones = newDropZones;
+ },
+
+ clearDropZones: function() {
+ this.dropZones = new Array();
+ },
+
+ registerDraggable: function( aDraggable ) {
+ this.draggables[ this.draggables.length ] = aDraggable;
+ this._addMouseDownHandler( aDraggable );
+ },
+
+ clearSelection: function() {
+ for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+ this.currentDragObjects[i].deselect();
+ this.currentDragObjects = new Array();
+ this.lastSelectedDraggable = null;
+ },
+
+ hasSelection: function() {
+ return this.currentDragObjects.length > 0;
+ },
+
+ setStartDragFromElement: function( e, mouseDownElement ) {
+ this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
+ this.startx = e.screenX - this.origPos.x
+ this.starty = e.screenY - this.origPos.y
+ //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
+ //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
+ //this.adjustedForDraggableSize = false;
+
+ this.interestedInMotionEvents = this.hasSelection();
+ this._terminateEvent(e);
+ },
+
+ updateSelection: function( draggable, extendSelection ) {
+ if ( ! extendSelection )
+ this.clearSelection();
+
+ if ( draggable.isSelected() ) {
+ this.currentDragObjects.removeItem(draggable);
+ draggable.deselect();
+ if ( draggable == this.lastSelectedDraggable )
+ this.lastSelectedDraggable = null;
+ }
+ else {
+ this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
+ draggable.select();
+ this.lastSelectedDraggable = draggable;
+ }
+ },
+
+ _mouseDownHandler: function(e) {
+ if ( arguments.length == 0 )
+ e = event;
+
+ // if not button 1 ignore it...
+ var nsEvent = e.which != undefined;
+ if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+ return;
+
+ var eventTarget = e.target ? e.target : e.srcElement;
+ var draggableObject = eventTarget.draggable;
+
+ var candidate = eventTarget;
+ while (draggableObject == null && candidate.parentNode) {
+ candidate = candidate.parentNode;
+ draggableObject = candidate.draggable;
+ }
+
+ if ( draggableObject == null )
+ return;
+
+ this.updateSelection( draggableObject, e.ctrlKey );
+
+ // clear the drop zones postion cache...
+ if ( this.hasSelection() )
+ for ( var i = 0 ; i < this.dropZones.length ; i++ )
+ this.dropZones[i].clearPositionCache();
+
+ this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
+ },
+
+
+ _mouseMoveHandler: function(e) {
+ var nsEvent = e.which != undefined;
+ if ( !this.interestedInMotionEvents ) {
+ //this._terminateEvent(e);
+ return;
+ }
+
+ if ( ! this.hasSelection() )
+ return;
+
+ if ( ! this.currentDragObjectVisible )
+ this._startDrag(e);
+
+ if ( !this.activatedDropZones )
+ this._activateRegisteredDropZones();
+
+ //if ( !this.adjustedForDraggableSize )
+ // this._adjustForDraggableSize(e);
+
+ this._updateDraggableLocation(e);
+ this._updateDropZonesHover(e);
+
+ this._terminateEvent(e);
+ },
+
+ _makeDraggableObjectVisible: function(e)
+ {
+ if ( !this.hasSelection() )
+ return;
+
+ var dragElement;
+ if ( this.currentDragObjects.length > 1 )
+ dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
+ else
+ dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
+
+ // go ahead and absolute position it...
+ if ( RicoUtil.getElementsComputedStyle(dragElement, "position") != "absolute" )
+ dragElement.style.position = "absolute";
+
+ // need to parent him into the document...
+ if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
+ document.body.appendChild(dragElement);
+
+ this.dragElement = dragElement;
+ this._updateDraggableLocation(e);
+
+ this.currentDragObjectVisible = true;
+ },
+
+ /**
+ _adjustForDraggableSize: function(e) {
+ var dragElementWidth = this.dragElement.offsetWidth;
+ var dragElementHeight = this.dragElement.offsetHeight;
+ if ( this.startComponentX > dragElementWidth )
+ this.startx -= this.startComponentX - dragElementWidth + 2;
+ if ( e.offsetY ) {
+ if ( this.startComponentY > dragElementHeight )
+ this.starty -= this.startComponentY - dragElementHeight + 2;
+ }
+ this.adjustedForDraggableSize = true;
+ },
+ **/
+
+ _leftOffset: function(e) {
+ return e.offsetX ? document.body.scrollLeft : 0
+ },
+
+ _topOffset: function(e) {
+ return e.offsetY ? document.body.scrollTop:0
+ },
+
+
+ _updateDraggableLocation: function(e) {
+ var dragObjectStyle = this.dragElement.style;
+ dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
+ dragObjectStyle.top = (e.screenY + this._topOffset(e) - this.starty) + "px";
+ },
+
+ _updateDropZonesHover: function(e) {
+ var n = this.dropZones.length;
+ for ( var i = 0 ; i < n ; i++ ) {
+ if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
+ this.dropZones[i].hideHover();
+ }
+
+ for ( var i = 0 ; i < n ; i++ ) {
+ if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+ if ( this.dropZones[i].canAccept(this.currentDragObjects) )
+ this.dropZones[i].showHover();
+ }
+ }
+ },
+
+ _startDrag: function(e) {
+ for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+ this.currentDragObjects[i].startDrag();
+
+ this._makeDraggableObjectVisible(e);
+ },
+
+ _mouseUpHandler: function(e) {
+ if ( ! this.hasSelection() )
+ return;
+
+ var nsEvent = e.which != undefined;
+ if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+ return;
+
+ this.interestedInMotionEvents = false;
+
+ if ( this.dragElement == null ) {
+ this._terminateEvent(e);
+ return;
+ }
+
+ if ( this._placeDraggableInDropZone(e) )
+ this._completeDropOperation(e);
+ else {
+ this._terminateEvent(e);
+ new Rico.Effect.Position( this.dragElement,
+ this.origPos.x,
+ this.origPos.y,
+ 200,
+ 20,
+ { complete : this._doCancelDragProcessing.bind(this) } );
+ }
+
+ Event.stopObserving(document.body, "mousemove", this._mouseMove);
+ Event.stopObserving(document.body, "mouseup", this._mouseUp);
+ },
+
+ _retTrue: function () {
+ return true;
+ },
+
+ _completeDropOperation: function(e) {
+ if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
+ if ( this.dragElement.parentNode != null )
+ this.dragElement.parentNode.removeChild(this.dragElement);
+ }
+
+ this._deactivateRegisteredDropZones();
+ this._endDrag();
+ this.clearSelection();
+ this.dragElement = null;
+ this.currentDragObjectVisible = false;
+ this._terminateEvent(e);
+ },
+
+ _doCancelDragProcessing: function() {
+ this._cancelDrag();
+
+ if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
+ if ( this.dragElement.parentNode != null )
+ this.dragElement.parentNode.removeChild(this.dragElement);
+
+
+ this._deactivateRegisteredDropZones();
+ this.dragElement = null;
+ this.currentDragObjectVisible = false;
+ },
+
+ _placeDraggableInDropZone: function(e) {
+ var foundDropZone = false;
+ var n = this.dropZones.length;
+ for ( var i = 0 ; i < n ; i++ ) {
+ if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+ if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
+ this.dropZones[i].hideHover();
+ this.dropZones[i].accept(this.currentDragObjects);
+ foundDropZone = true;
+ break;
+ }
+ }
+ }
+
+ return foundDropZone;
+ },
+
+ _cancelDrag: function() {
+ for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+ this.currentDragObjects[i].cancelDrag();
+ },
+
+ _endDrag: function() {
+ for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+ this.currentDragObjects[i].endDrag();
+ },
+
+ _mousePointInDropZone: function( e, dropZone ) {
+
+ var absoluteRect = dropZone.getAbsoluteRect();
+
+ return e.clientX > absoluteRect.left + this._leftOffset(e) &&
+ e.clientX < absoluteRect.right + this._leftOffset(e) &&
+ e.clientY > absoluteRect.top + this._topOffset(e) &&
+ e.clientY < absoluteRect.bottom + this._topOffset(e);
+ },
+
+ _addMouseDownHandler: function( aDraggable )
+ {
+ htmlElement = aDraggable.getMouseDownHTMLElement();
+ if ( htmlElement != null ) {
+ htmlElement.draggable = aDraggable;
+ Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
+ Event.observe(htmlElement, "mousedown", this._mouseDown);
+ }
+ },
+
+ _activateRegisteredDropZones: function() {
+ var n = this.dropZones.length;
+ for ( var i = 0 ; i < n ; i++ ) {
+ var dropZone = this.dropZones[i];
+ if ( dropZone.canAccept(this.currentDragObjects) )
+ dropZone.activate();
+ }
+
+ this.activatedDropZones = true;
+ },
+
+ _deactivateRegisteredDropZones: function() {
+ var n = this.dropZones.length;
+ for ( var i = 0 ; i < n ; i++ )
+ this.dropZones[i].deactivate();
+ this.activatedDropZones = false;
+ },
+
+ _onmousedown: function () {
+ Event.observe(document.body, "mousemove", this._mouseMove);
+ Event.observe(document.body, "mouseup", this._mouseUp);
+ },
+
+ _terminateEvent: function(e) {
+ if ( e.stopPropagation != undefined )
+ e.stopPropagation();
+ else if ( e.cancelBubble != undefined )
+ e.cancelBubble = true;
+
+ if ( e.preventDefault != undefined )
+ e.preventDefault();
+ else
+ e.returnValue = false;
+ },
+
+
+ initializeEventHandlers: function() {
+ if ( typeof document.implementation != "undefined" &&
+ document.implementation.hasFeature("HTML", "1.0") &&
+ document.implementation.hasFeature("Events", "2.0") &&
+ document.implementation.hasFeature("CSS", "2.0") ) {
+ document.addEventListener("mouseup", this._mouseUpHandler.bindAsEventListener(this), false);
+ document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
+ }
+ else {
+ document.attachEvent( "onmouseup", this._mouseUpHandler.bindAsEventListener(this) );
+ document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
+ }
+ }
+ }
+
+ var dndMgr = new Rico.DragAndDrop();
+ dndMgr.initializeEventHandlers();
+
+
+//-------------------- ricoDraggable.js
+Rico.Draggable = Class.create();
+
+Rico.Draggable.prototype = {
+
+ initialize: function( type, htmlElement ) {
+ this.type = type;
+ this.htmlElement = $(htmlElement);
+ this.selected = false;
+ },
+
+ /**
+ * Returns the HTML element that should have a mouse down event
+ * added to it in order to initiate a drag operation
+ *
+ **/
+ getMouseDownHTMLElement: function() {
+ return this.htmlElement;
+ },
+
+ select: function() {
+ this.selected = true;
+
+ if ( this.showingSelected )
+ return;
+
+ var htmlElement = this.getMouseDownHTMLElement();
+
+ var color = Rico.Color.createColorFromBackground(htmlElement);
+ color.isBright() ? color.darken(0.033) : color.brighten(0.033);
+
+ this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
+ htmlElement.style.backgroundColor = color.asHex();
+ this.showingSelected = true;
+ },
+
+ deselect: function() {
+ this.selected = false;
+ if ( !this.showingSelected )
+ return;
+
+ var htmlElement = this.getMouseDownHTMLElement();
+
+ htmlElement.style.backgroundColor = this.saveBackground;
+ this.showingSelected = false;
+ },
+
+ isSelected: function() {
+ return this.selected;
+ },
+
+ startDrag: function() {
+ },
+
+ cancelDrag: function() {
+ },
+
+ endDrag: function() {
+ },
+
+ getSingleObjectDragGUI: function() {
+ return this.htmlElement;
+ },
+
+ getMultiObjectDragGUI: function( draggables ) {
+ return this.htmlElement;
+ },
+
+ getDroppedGUI: function() {
+ return this.htmlElement;
+ },
+
+ toString: function() {
+ return this.type + ":" + this.htmlElement + ":";
+ }
+
+}
+
+
+//-------------------- ricoDropzone.js
+Rico.Dropzone = Class.create();
+
+Rico.Dropzone.prototype = {
+
+ initialize: function( htmlElement ) {
+ this.htmlElement = $(htmlElement);
+ this.absoluteRect = null;
+ },
+
+ getHTMLElement: function() {
+ return this.htmlElement;
+ },
+
+ clearPositionCache: function() {
+ this.absoluteRect = null;
+ },
+
+ getAbsoluteRect: function() {
+ if ( this.absoluteRect == null ) {
+ var htmlElement = this.getHTMLElement();
+ var pos = RicoUtil.toViewportPosition(htmlElement);
+
+ this.absoluteRect = {
+ top: pos.y,
+ left: pos.x,
+ bottom: pos.y + htmlElement.offsetHeight,
+ right: pos.x + htmlElement.offsetWidth
+ };
+ }
+ return this.absoluteRect;
+ },
+
+ activate: function() {
+ var htmlElement = this.getHTMLElement();
+ if (htmlElement == null || this.showingActive)
+ return;
+
+ this.showingActive = true;
+ this.saveBackgroundColor = htmlElement.style.backgroundColor;
+
+ var fallbackColor = "#ffea84";
+ var currentColor = Rico.Color.createColorFromBackground(htmlElement);
+ if ( currentColor == null )
+ htmlElement.style.backgroundColor = fallbackColor;
+ else {
+ currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
+ htmlElement.style.backgroundColor = currentColor.asHex();
+ }
+ },
+
+ deactivate: function() {
+ var htmlElement = this.getHTMLElement();
+ if (htmlElement == null || !this.showingActive)
+ return;
+
+ htmlElement.style.backgroundColor = this.saveBackgroundColor;
+ this.showingActive = false;
+ this.saveBackgroundColor = null;
+ },
+
+ showHover: function() {
+ var htmlElement = this.getHTMLElement();
+ if ( htmlElement == null || this.showingHover )
+ return;
+
+ this.saveBorderWidth = htmlElement.style.borderWidth;
+ this.saveBorderStyle = htmlElement.style.borderStyle;
+ this.saveBorderColor = htmlElement.style.borderColor;
+
+ this.showingHover = true;
+ htmlElement.style.borderWidth = "1px";
+ htmlElement.style.borderStyle = "solid";
+ //htmlElement.style.borderColor = "#ff9900";
+ htmlElement.style.borderColor = "#ffff00";
+ },
+
+ hideHover: function() {
+ var htmlElement = this.getHTMLElement();
+ if ( htmlElement == null || !this.showingHover )
+ return;
+
+ htmlElement.style.borderWidth = this.saveBorderWidth;
+ htmlElement.style.borderStyle = this.saveBorderStyle;
+ htmlElement.style.borderColor = this.saveBorderColor;
+ this.showingHover = false;
+ },
+
+ canAccept: function(draggableObjects) {
+ return true;
+ },
+
+ accept: function(draggableObjects) {
+ var htmlElement = this.getHTMLElement();
+ if ( htmlElement == null )
+ return;
+
+ n = draggableObjects.length;
+ for ( var i = 0 ; i < n ; i++ )
+ {
+ var theGUI = draggableObjects[i].getDroppedGUI();
+ if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
+ {
+ theGUI.style.position = "static";
+ theGUI.style.top = "";
+ theGUI.style.top = "";
+ }
+ htmlElement.appendChild(theGUI);
+ }
+ }
+}
+
+
+//-------------------- ricoEffects.js
+
+/**
+ * Use the Effect namespace for effects. If using scriptaculous effects
+ * this will already be defined, otherwise we'll just create an empty
+ * object for it...
+ **/
+if ( window.Effect == undefined )
+ Rico.Effect = {};
+
+Rico.Effect.SizeAndPosition = Class.create();
+Rico.Effect.SizeAndPosition.prototype = {
+
+ initialize: function(element, x, y, w, h, duration, steps, options) {
+ this.element = $(element);
+ this.x = x;
+ this.y = y;
+ this.w = w;
+ this.h = h;
+ this.duration = duration;
+ this.steps = steps;
+ this.options = arguments[7] || {};
+
+ this.sizeAndPosition();
+ },
+
+ sizeAndPosition: function() {
+ if (this.isFinished()) {
+ if(this.options.complete) this.options.complete(this);
+ return;
+ }
+
+ if (this.timer)
+ clearTimeout(this.timer);
+
+ var stepDuration = Math.round(this.duration/this.steps) ;
+
+ // Get original values: x,y = top left corner; w,h = width height
+ var currentX = this.element.offsetLeft;
+ var currentY = this.element.offsetTop;
+ var currentW = this.element.offsetWidth;
+ var currentH = this.element.offsetHeight;
+
+ // If values not set, or zero, we do not modify them, and take original as final as well
+ this.x = (this.x) ? this.x : currentX;
+ this.y = (this.y) ? this.y : currentY;
+ this.w = (this.w) ? this.w : currentW;
+ this.h = (this.h) ? this.h : currentH;
+
+ // how much do we need to modify our values for each step?
+ var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0;
+ var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0;
+ var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0;
+ var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0;
+
+ this.moveBy(difX, difY);
+ this.resizeBy(difW, difH);
+
+ this.duration -= stepDuration;
+ this.steps--;
+
+ this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
+ },
+
+ isFinished: function() {
+ return this.steps <= 0;
+ },
+
+ moveBy: function( difX, difY ) {
+ var currentLeft = this.element.offsetLeft;
+ var currentTop = this.element.offsetTop;
+ var intDifX = parseInt(difX);
+ var intDifY = parseInt(difY);
+
+ var style = this.element.style;
+ if ( intDifX != 0 )
+ style.left = (currentLeft + intDifX) + "px";
+ if ( intDifY != 0 )
+ style.top = (currentTop + intDifY) + "px";
+ },
+
+ resizeBy: function( difW, difH ) {
+ var currentWidth = this.element.offsetWidth;
+ var currentHeight = this.element.offsetHeight;
+ var intDifW = parseInt(difW);
+ var intDifH = parseInt(difH);
+
+ var style = this.element.style;
+ if ( intDifW != 0 )
+ style.width = (currentWidth + intDifW) + "px";
+ if ( intDifH != 0 )
+ style.height = (currentHeight + intDifH) + "px";
+ }
+}
+
+Rico.Effect.Size = Class.create();
+Rico.Effect.Size.prototype = {
+
+ initialize: function(element, w, h, duration, steps, options) {
+ new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
+ }
+}
+
+Rico.Effect.Position = Class.create();
+Rico.Effect.Position.prototype = {
+
+ initialize: function(element, x, y, duration, steps, options) {
+ new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
+ }
+}
+
+Rico.Effect.Round = Class.create();
+Rico.Effect.Round.prototype = {
+
+ initialize: function(tagName, className, options) {
+ var elements = document.getElementsByTagAndClassName(tagName,className);
+ for ( var i = 0 ; i < elements.length ; i++ )
+ Rico.Corner.round( elements[i], options );
+ }
+};
+
+Rico.Effect.FadeTo = Class.create();
+Rico.Effect.FadeTo.prototype = {
+
+ initialize: function( element, opacity, duration, steps, options) {
+ this.element = $(element);
+ this.opacity = opacity;
+ this.duration = duration;
+ this.steps = steps;
+ this.options = arguments[4] || {};
+ this.fadeTo();
+ },
+
+ fadeTo: function() {
+ if (this.isFinished()) {
+ if(this.options.complete) this.options.complete(this);
+ return;
+ }
+
+ if (this.timer)
+ clearTimeout(this.timer);
+
+ var stepDuration = Math.round(this.duration/this.steps) ;
+ var currentOpacity = this.getElementOpacity();
+ var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
+
+ this.changeOpacityBy(delta);
+ this.duration -= stepDuration;
+ this.steps--;
+
+ this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
+ },
+
+ changeOpacityBy: function(v) {
+ var currentOpacity = this.getElementOpacity();
+ var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
+ this.element.ricoOpacity = newOpacity;
+
+ this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
+ this.element.style.opacity = newOpacity; /*//*/;
+ },
+
+ isFinished: function() {
+ return this.steps <= 0;
+ },
+
+ getElementOpacity: function() {
+ if ( this.element.ricoOpacity == undefined ) {
+ var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
+ this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
+ }
+ return parseFloat(this.element.ricoOpacity);
+ }
+}
+
+Rico.Effect.AccordionSize = Class.create();
+
+Rico.Effect.AccordionSize.prototype = {
+
+ initialize: function(e1, e2, start, end, duration, steps, options) {
+ this.e1 = $(e1);
+ this.e2 = $(e2);
+ this.start = start;
+ this.end = end;
+ this.duration = duration;
+ this.steps = steps;
+ this.options = arguments[6] || {};
+
+ this.accordionSize();
+ },
+
+ accordionSize: function() {
+
+ if (this.isFinished()) {
+ // just in case there are round errors or such...
+ this.e1.style.height = this.start + "px";
+ this.e2.style.height = this.end + "px";
+
+ if(this.options.complete)
+ this.options.complete(this);
+ return;
+ }
+
+ if (this.timer)
+ clearTimeout(this.timer);
+
+ var stepDuration = Math.round(this.duration/this.steps) ;
+
+ var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
+ this.resizeBy(diff);
+
+ this.duration -= stepDuration;
+ this.steps--;
+
+ this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
+ },
+
+ isFinished: function() {
+ return this.steps <= 0;
+ },
+
+ resizeBy: function(diff) {
+ var h1Height = this.e1.offsetHeight;
+ var h2Height = this.e2.offsetHeight;
+ var intDiff = parseInt(diff);
+ if ( diff != 0 ) {
+ this.e1.style.height = (h1Height - intDiff) + "px";
+ this.e2.style.height = (h2Height + intDiff) + "px";
+ }
+ }
+
+};
+
+
+//-------------------- ricoLiveGrid.js
+// Rico.LiveGridMetaData -----------------------------------------------------
+
+Rico.LiveGridMetaData = Class.create();
+
+Rico.LiveGridMetaData.prototype = {
+
+ initialize: function( pageSize, totalRows, columnCount, options ) {
+ this.pageSize = pageSize;
+ this.totalRows = totalRows;
+ this.setOptions(options);
+ this.ArrowHeight = 16;
+ this.columnCount = columnCount;
+ },
+
+ setOptions: function(options) {
+ this.options = {
+ largeBufferSize : 7.0, // 7 pages
+ nearLimitFactor : 0.2 // 20% of buffer
+ };
+ Object.extend(this.options, options || {});
+ },
+
+ getPageSize: function() {
+ return this.pageSize;
+ },
+
+ getTotalRows: function() {
+ return this.totalRows;
+ },
+
+ setTotalRows: function(n) {
+ this.totalRows = n;
+ },
+
+ getLargeBufferSize: function() {
+ return parseInt(this.options.largeBufferSize * this.pageSize);
+ },
+
+ getLimitTolerance: function() {
+ return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
+ }
+};
+
+// Rico.LiveGridScroller -----------------------------------------------------
+
+Rico.LiveGridScroller = Class.create();
+
+Rico.LiveGridScroller.prototype = {
+
+ initialize: function(liveGrid, viewPort) {
+ this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
+ this.liveGrid = liveGrid;
+ this.metaData = liveGrid.metaData;
+ this.createScrollBar();
+ this.scrollTimeout = null;
+ this.lastScrollPos = 0;
+ this.viewPort = viewPort;
+ this.rows = new Array();
+ },
+
+ isUnPlugged: function() {
+ return this.scrollerDiv.onscroll == null;
+ },
+
+ plugin: function() {
+ this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
+ },
+
+ unplug: function() {
+ this.scrollerDiv.onscroll = null;
+ },
+
+ sizeIEHeaderHack: function() {
+ if ( !this.isIE ) return;
+ var headerTable = $(this.liveGrid.tableId + "_header");
+ if ( headerTable )
+ headerTable.rows[0].cells[0].style.width =
+ (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
+ },
+
+ createScrollBar: function() {
+ var visibleHeight = this.liveGrid.viewPort.visibleHeight();
+ // create the outer div...
+ this.scrollerDiv = document.createElement("div");
+ var scrollerStyle = this.scrollerDiv.style;
+ scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight;
+ scrollerStyle.position = "relative";
+ scrollerStyle.left = this.isIE ? "-6px" : "-3px";
+ scrollerStyle.width = "19px";
+ scrollerStyle.height = visibleHeight + "px";
+ scrollerStyle.overflow = "auto";
+
+ // create the inner div...
+ this.heightDiv = document.createElement("div");
+ this.heightDiv.style.width = "1px";
+
+ this.heightDiv.style.height = parseInt(visibleHeight *
+ this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
+ this.scrollerDiv.appendChild(this.heightDiv);
+ this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
+
+ var table = this.liveGrid.table;
+ table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
+ var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll";
+ Event.observe(table, eventName,
+ function(evt) {
+ if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up
+ this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight);
+ else
+ this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight);
+ this.handleScroll(false);
+ }.bindAsEventListener(this),
+ false);
+ },
+
+ updateSize: function() {
+ var table = this.liveGrid.table;
+ var visibleHeight = this.viewPort.visibleHeight();
+ this.heightDiv.style.height = parseInt(visibleHeight *
+ this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
+ },
+
+ rowToPixel: function(rowOffset) {
+ return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
+ },
+
+ moveScroll: function(rowOffset) {
+ this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
+ if ( this.metaData.options.onscroll )
+ this.metaData.options.onscroll( this.liveGrid, rowOffset );
+ },
+
+ handleScroll: function() {
+ if ( this.scrollTimeout )
+ clearTimeout( this.scrollTimeout );
+
+ var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
+ if (scrollDiff != 0.00) {
+ var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
+ if (r != 0) {
+ this.unplug();
+ if ( scrollDiff < 0 ) {
+ this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
+ } else {
+ this.scrollerDiv.scrollTop -= r;
+ }
+ this.plugin();
+ }
+ }
+ var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
+ this.liveGrid.requestContentRefresh(contentOffset);
+ this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
+
+ if ( this.metaData.options.onscroll )
+ this.metaData.options.onscroll( this.liveGrid, contentOffset );
+
+ this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
+ this.lastScrollPos = this.scrollerDiv.scrollTop;
+
+ },
+
+ scrollIdle: function() {
+ if ( this.metaData.options.onscrollidle )
+ this.metaData.options.onscrollidle();
+ }
+};
+
+// Rico.LiveGridBuffer -----------------------------------------------------
+
+Rico.LiveGridBuffer = Class.create();
+
+Rico.LiveGridBuffer.prototype = {
+
+ initialize: function(metaData, viewPort) {
+ this.startPos = 0;
+ this.size = 0;
+ this.metaData = metaData;
+ this.rows = new Array();
+ this.updateInProgress = false;
+ this.viewPort = viewPort;
+ this.maxBufferSize = metaData.getLargeBufferSize() * 2;
+ this.maxFetchSize = metaData.getLargeBufferSize();
+ this.lastOffset = 0;
+ },
+
+ getBlankRow: function() {
+ if (!this.blankRow ) {
+ this.blankRow = new Array();
+ for ( var i=0; i < this.metaData.columnCount ; i++ )
+ this.blankRow[i] = " ";
+ }
+ return this.blankRow;
+ },
+
+ loadRows: function(ajaxResponse) {
+ var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
+ this.updateUI = rowsElement.getAttribute("update_ui") == "true"
+ var newRows = new Array()
+ var trs = rowsElement.getElementsByTagName("tr");
+ for ( var i=0 ; i < trs.length; i++ ) {
+ var row = newRows[i] = new Array();
+ var cells = trs[i].getElementsByTagName("td");
+ for ( var j=0; j < cells.length ; j++ ) {
+ var cell = cells[j];
+ var convertSpaces = cell.getAttribute("convert_spaces") == "true";
+ var cellContent = RicoUtil.getContentAsString(cell);
+ row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
+ if (!row[j])
+ row[j] = ' ';
+ }
+ }
+ return newRows;
+ },
+
+ update: function(ajaxResponse, start) {
+ var newRows = this.loadRows(ajaxResponse);
+ if (this.rows.length == 0) { // initial load
+ this.rows = newRows;
+ this.size = this.rows.length;
+ this.startPos = start;
+ return;
+ }
+ if (start > this.startPos) { //appending
+ if (this.startPos + this.rows.length < start) {
+ this.rows = newRows;
+ this.startPos = start;//
+ } else {
+ this.rows = this.rows.concat( newRows.slice(0, newRows.length));
+ if (this.rows.length > this.maxBufferSize) {
+ var fullSize = this.rows.length;
+ this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
+ this.startPos = this.startPos + (fullSize - this.rows.length);
+ }
+ }
+ } else { //prepending
+ if (start + newRows.length < this.startPos) {
+ this.rows = newRows;
+ } else {
+ this.rows = newRows.slice(0, this.startPos).concat(this.rows);
+ if (this.rows.length > this.maxBufferSize)
+ this.rows = this.rows.slice(0, this.maxBufferSize)
+ }
+ this.startPos = start;
+ }
+ this.size = this.rows.length;
+ },
+
+ clear: function() {
+ this.rows = new Array();
+ this.startPos = 0;
+ this.size = 0;
+ },
+
+ isOverlapping: function(start, size) {
+ return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
+ },
+
+ isInRange: function(position) {
+ return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos());
+ //&& this.size() != 0;
+ },
+
+ isNearingTopLimit: function(position) {
+ return position - this.startPos < this.metaData.getLimitTolerance();
+ },
+
+ endPos: function() {
+ return this.startPos + this.rows.length;
+ },
+
+ isNearingBottomLimit: function(position) {
+ return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
+ },
+
+ isAtTop: function() {
+ return this.startPos == 0;
+ },
+
+ isAtBottom: function() {
+ return this.endPos() == this.metaData.getTotalRows();
+ },
+
+ isNearingLimit: function(position) {
+ return ( !this.isAtTop() && this.isNearingTopLimit(position)) ||
+ ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
+ },
+
+ getFetchSize: function(offset) {
+ var adjustedOffset = this.getFetchOffset(offset);
+ var adjustedSize = 0;
+ if (adjustedOffset >= this.startPos) { //apending
+ var endFetchOffset = this.maxFetchSize + adjustedOffset;
+ if (endFetchOffset > this.metaData.totalRows)
+ endFetchOffset = this.metaData.totalRows;
+ adjustedSize = endFetchOffset - adjustedOffset;
+ if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){
+ adjustedSize = this.maxFetchSize;
+ }
+ } else {//prepending
+ var adjustedSize = this.startPos - adjustedOffset;
+ if (adjustedSize > this.maxFetchSize)
+ adjustedSize = this.maxFetchSize;
+ }
+ return adjustedSize;
+ },
+
+ getFetchOffset: function(offset) {
+ var adjustedOffset = offset;
+ if (offset > this.startPos) //apending
+ adjustedOffset = (offset > this.endPos()) ? offset : this.endPos();
+ else { //prepending
+ if (offset + this.maxFetchSize >= this.startPos) {
+ var adjustedOffset = this.startPos - this.maxFetchSize;
+ if (adjustedOffset < 0)
+ adjustedOffset = 0;
+ }
+ }
+ this.lastOffset = adjustedOffset;
+ return adjustedOffset;
+ },
+
+ getRows: function(start, count) {
+ var begPos = start - this.startPos
+ var endPos = begPos + count
+
+ // er? need more data...
+ if ( endPos > this.size )
+ endPos = this.size
+
+ var results = new Array()
+ var index = 0;
+ for ( var i=begPos ; i < endPos; i++ ) {
+ results[index++] = this.rows[i]
+ }
+ return results
+ },
+
+ convertSpaces: function(s) {
+ return s.split(" ").join(" ");
+ }
+
+};
+
+
+//Rico.GridViewPort --------------------------------------------------
+Rico.GridViewPort = Class.create();
+
+Rico.GridViewPort.prototype = {
+
+ initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
+ this.lastDisplayedStartPos = 0;
+ this.div = table.parentNode;
+ this.table = table
+ this.rowHeight = rowHeight;
+ this.div.style.height = this.rowHeight * visibleRows;
+ this.div.style.overflow = "hidden";
+ this.buffer = buffer;
+ this.liveGrid = liveGrid;
+ this.visibleRows = visibleRows + 1;
+ this.lastPixelOffset = 0;
+ this.startPos = 0;
+ },
+
+ populateRow: function(htmlRow, row) {
+ for (var j=0; j < row.length; j++) {
+ htmlRow.cells[j].innerHTML = row[j]
+ }
+ },
+
+ bufferChanged: function() {
+ this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
+ },
+
+ clearRows: function() {
+ if (!this.isBlank) {
+ this.liveGrid.table.className = this.liveGrid.options.loadingClass;
+ for (var i=0; i < this.visibleRows; i++)
+ this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
+ this.isBlank = true;
+ }
+ },
+
+ clearContents: function() {
+ this.clearRows();
+ this.scrollTo(0);
+ this.startPos = 0;
+ this.lastStartPos = -1;
+ },
+
+ refreshContents: function(startPos) {
+ if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
+ return;
+ }
+ if ((startPos + this.visibleRows < this.buffer.startPos)
+ || (this.buffer.startPos + this.buffer.size < startPos)
+ || (this.buffer.size == 0)) {
+ this.clearRows();
+ return;
+ }
+ this.isBlank = false;
+ var viewPrecedesBuffer = this.buffer.startPos > startPos
+ var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos;
+ var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows)
+ ? this.buffer.startPos + this.buffer.size
+ : startPos + this.visibleRows;
+ var rowSize = contentEndPos - contentStartPos;
+ var rows = this.buffer.getRows(contentStartPos, rowSize );
+ var blankSize = this.visibleRows - rowSize;
+ var blankOffset = viewPrecedesBuffer ? 0: rowSize;
+ var contentOffset = viewPrecedesBuffer ? blankSize: 0;
+
+ for (var i=0; i < rows.length; i++) {//initialize what we have
+ this.populateRow(this.table.rows[i + contentOffset], rows[i]);
+ }
+ for (var i=0; i < blankSize; i++) {// blank out the rest
+ this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
+ }
+ this.isPartialBlank = blankSize > 0;
+ this.lastRowPos = startPos;
+
+ this.liveGrid.table.className = this.liveGrid.options.tableClass;
+ // Check if user has set a onRefreshComplete function
+ var onRefreshComplete = this.liveGrid.options.onRefreshComplete;
+ if (onRefreshComplete != null)
+ onRefreshComplete();
+ },
+
+ scrollTo: function(pixelOffset) {
+ if (this.lastPixelOffset == pixelOffset)
+ return;
+
+ this.refreshContents(parseInt(pixelOffset / this.rowHeight))
+ this.div.scrollTop = pixelOffset % this.rowHeight
+
+ this.lastPixelOffset = pixelOffset;
+ },
+
+ visibleHeight: function() {
+ return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height'));
+ }
+
+};
+
+
+Rico.LiveGridRequest = Class.create();
+Rico.LiveGridRequest.prototype = {
+ initialize: function( requestOffset, options ) {
+ this.requestOffset = requestOffset;
+ }
+};
+
+// Rico.LiveGrid -----------------------------------------------------
+
+Rico.LiveGrid = Class.create();
+
+Rico.LiveGrid.prototype = {
+
+ initialize: function( tableId, visibleRows, totalRows, url, options, ajaxOptions ) {
+
+ this.options = {
+ tableClass: $(tableId).className,
+ loadingClass: $(tableId).className,
+ scrollerBorderRight: '1px solid #ababab',
+ bufferTimeout: 20000,
+ sortAscendImg: 'images/sort_asc.gif',
+ sortDescendImg: 'images/sort_desc.gif',
+ sortImageWidth: 9,
+ sortImageHeight: 5,
+ ajaxSortURLParms: [],
+ onRefreshComplete: null,
+ requestParameters: null,
+ inlineStyles: true
+ };
+ Object.extend(this.options, options || {});
+
+ this.ajaxOptions = {parameters: null};
+ Object.extend(this.ajaxOptions, ajaxOptions || {});
+
+ this.tableId = tableId;
+ this.table = $(tableId);
+
+ this.addLiveGridHtml();
+
+ var columnCount = this.table.rows[0].cells.length;
+ this.metaData = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
+ this.buffer = new Rico.LiveGridBuffer(this.metaData);
+
+ var rowCount = this.table.rows.length;
+ this.viewPort = new Rico.GridViewPort(this.table,
+ this.table.offsetHeight/rowCount,
+ visibleRows,
+ this.buffer, this);
+ this.scroller = new Rico.LiveGridScroller(this,this.viewPort);
+ this.options.sortHandler = this.sortHandler.bind(this);
+
+ if ( $(tableId + '_header') )
+ this.sort = new Rico.LiveGridSort(tableId + '_header', this.options)
+
+ this.processingRequest = null;
+ this.unprocessedRequest = null;
+
+ this.initAjax(url);
+ if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) {
+ var offset = 0;
+ if (this.options.offset ) {
+ offset = this.options.offset;
+ this.scroller.moveScroll(offset);
+ this.viewPort.scrollTo(this.scroller.rowToPixel(offset));
+ }
+ if (this.options.sortCol) {
+ this.sortCol = options.sortCol;
+ this.sortDir = options.sortDir;
+ }
+ this.requestContentRefresh(offset);
+ }
+ },
+
+ addLiveGridHtml: function() {
+ // Check to see if need to create a header table.
+ if (this.table.getElementsByTagName("thead").length > 0){
+ // Create Table this.tableId+'_header'
+ var tableHeader = this.table.cloneNode(true);
+ tableHeader.setAttribute('id', this.tableId+'_header');
+ tableHeader.setAttribute('class', this.table.className+'_header');
+
+ // Clean up and insert
+ for( var i = 0; i < tableHeader.tBodies.length; i++ )
+ tableHeader.removeChild(tableHeader.tBodies[i]);
+ this.table.deleteTHead();
+ this.table.parentNode.insertBefore(tableHeader,this.table);
+ }
+
+ new Insertion.Before(this.table, "<div id='"+this.tableId+"_container'></div>");
+ this.table.previousSibling.appendChild(this.table);
+ new Insertion.Before(this.table,"<div id='"+this.tableId+"_viewport' style='float:left;'></div>");
+ this.table.previousSibling.appendChild(this.table);
+ },
+
+
+ resetContents: function() {
+ this.scroller.moveScroll(0);
+ this.buffer.clear();
+ this.viewPort.clearContents();
+ },
+
+ sortHandler: function(column) {
+ if(!column) return ;
+ this.sortCol = column.name;
+ this.sortDir = column.currentSort;
+
+ this.resetContents();
+ this.requestContentRefresh(0)
+ },
+
+ adjustRowSize: function() {
+
+ },
+
+ setTotalRows: function( newTotalRows ) {
+ this.resetContents();
+ this.metaData.setTotalRows(newTotalRows);
+ this.scroller.updateSize();
+ },
+
+ initAjax: function(url) {
+ ajaxEngine.registerRequest( this.tableId + '_request', url );
+ ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
+ },
+
+ invokeAjax: function() {
+ },
+
+ handleTimedOut: function() {
+ //server did not respond in 4 seconds... assume that there could have been
+ //an error or something, and allow requests to be processed again...
+ this.processingRequest = null;
+ this.processQueuedRequest();
+ },
+
+ fetchBuffer: function(offset) {
+ if ( this.buffer.isInRange(offset) &&
+ !this.buffer.isNearingLimit(offset)) {
+ return;
+ }
+ if (this.processingRequest) {
+ this.unprocessedRequest = new Rico.LiveGridRequest(offset);
+ return;
+ }
+ var bufferStartPos = this.buffer.getFetchOffset(offset);
+ this.processingRequest = new Rico.LiveGridRequest(offset);
+ this.processingRequest.bufferOffset = bufferStartPos;
+ var fetchSize = this.buffer.getFetchSize(offset);
+ var partialLoaded = false;
+
+ var queryString
+ if (this.options.requestParameters)
+ queryString = this._createQueryString(this.options.requestParameters, 0);
+
+ queryString = (queryString == null) ? '' : queryString+'&';
+ queryString = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos;
+ if (this.sortCol)
+ queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir;
+
+ this.ajaxOptions.parameters = queryString;
+
+ ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions );
+
+ this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
+
+ },
+
+ setRequestParams: function() {
+ this.options.requestParameters = [];
+ for ( var i=0 ; i < arguments.length ; i++ )
+ this.options.requestParameters[i] = arguments[i];
+ },
+
+ requestContentRefresh: function(contentOffset) {
+ this.fetchBuffer(contentOffset);
+ },
+
+ ajaxUpdate: function(ajaxResponse) {
+ try {
+ clearTimeout( this.timeoutHandler );
+ this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
+ this.viewPort.bufferChanged();
+ }
+ catch(err) {}
+ finally {this.processingRequest = null; }
+ this.processQueuedRequest();
+ },
+
+ _createQueryString: function( theArgs, offset ) {
+ var queryString = ""
+ if (!theArgs)
+ return queryString;
+
+ for ( var i = offset ; i < theArgs.length ; i++ ) {
+ if ( i != offset )
+ queryString += "&";
+
+ var anArg = theArgs[i];
+
+ if ( anArg.name != undefined && anArg.value != undefined ) {
+ queryString += anArg.name + "=" + escape(anArg.value);
+ }
+ else {
+ var ePos = anArg.indexOf('=');
+ var argName = anArg.substring( 0, ePos );
+ var argValue = anArg.substring( ePos + 1 );
+ queryString += argName + "=" + escape(argValue);
+ }
+ }
+ return queryString;
+ },
+
+ processQueuedRequest: function() {
+ if (this.unprocessedRequest != null) {
+ this.requestContentRefresh(this.unprocessedRequest.requestOffset);
+ this.unprocessedRequest = null
+ }
+ }
+};
+
+
+//-------------------- ricoLiveGridSort.js
+Rico.LiveGridSort = Class.create();
+
+Rico.LiveGridSort.prototype = {
+
+ initialize: function(headerTableId, options) {
+ this.headerTableId = headerTableId;
+ this.headerTable = $(headerTableId);
+ this.options = options;
+ this.setOptions();
+ this.applySortBehavior();
+
+ if ( this.options.sortCol ) {
+ this.setSortUI( this.options.sortCol, this.options.sortDir );
+ }
+ },
+
+ setSortUI: function( columnName, sortDirection ) {
+ var cols = this.options.columns;
+ for ( var i = 0 ; i < cols.length ; i++ ) {
+ if ( cols[i].name == columnName ) {
+ this.setColumnSort(i, sortDirection);
+ break;
+ }
+ }
+ },
+
+ setOptions: function() {
+ // preload the images...
+ new Image().src = this.options.sortAscendImg;
+ new Image().src = this.options.sortDescendImg;
+
+ this.sort = this.options.sortHandler;
+ if ( !this.options.columns )
+ this.options.columns = this.introspectForColumnInfo();
+ else {
+ // allow client to pass { columns: [ ["a", true], ["b", false] ] }
+ // and convert to an array of Rico.TableColumn objs...
+ this.options.columns = this.convertToTableColumns(this.options.columns);
+ }
+ },
+
+ applySortBehavior: function() {
+ var headerRow = this.headerTable.rows[0];
+ var headerCells = headerRow.cells;
+ for ( var i = 0 ; i < headerCells.length ; i++ ) {
+ this.addSortBehaviorToColumn( i, headerCells[i] );
+ }
+ },
+
+ addSortBehaviorToColumn: function( n, cell ) {
+ if ( this.options.columns[n].isSortable() ) {
+ cell.id = this.headerTableId + '_' + n;
+ cell.style.cursor = 'pointer';
+ cell.onclick = this.headerCellClicked.bindAsEventListener(this);
+ cell.innerHTML = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
+ + ' </span>';
+ }
+ },
+
+ // event handler....
+ headerCellClicked: function(evt) {
+ var eventTarget = evt.target ? evt.target : evt.srcElement;
+ var cellId = eventTarget.id;
+ var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
+ var sortedColumnIndex = this.getSortedColumnIndex();
+ if ( sortedColumnIndex != -1 ) {
+ if ( sortedColumnIndex != columnNumber ) {
+ this.removeColumnSort(sortedColumnIndex);
+ this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
+ }
+ else
+ this.toggleColumnSort(sortedColumnIndex);
+ }
+ else
+ this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
+
+ if (this.options.sortHandler) {
+ this.options.sortHandler(this.options.columns[columnNumber]);
+ }
+ },
+
+ removeColumnSort: function(n) {
+ this.options.columns[n].setUnsorted();
+ this.setSortImage(n);
+ },
+
+ setColumnSort: function(n, direction) {
+ if(isNaN(n)) return ;
+ this.options.columns[n].setSorted(direction);
+ this.setSortImage(n);
+ },
+
+ toggleColumnSort: function(n) {
+ this.options.columns[n].toggleSort();
+ this.setSortImage(n);
+ },
+
+ setSortImage: function(n) {
+ var sortDirection = this.options.columns[n].getSortDirection();
+
+ var sortImageSpan = $( this.headerTableId + '_img_' + n );
+ if ( sortDirection == Rico.TableColumn.UNSORTED )
+ sortImageSpan.innerHTML = ' ';
+ else if ( sortDirection == Rico.TableColumn.SORT_ASC )
+ sortImageSpan.innerHTML = ' <img width="' + this.options.sortImageWidth + '" ' +
+ 'height="'+ this.options.sortImageHeight + '" ' +
+ 'src="' + this.options.sortAscendImg + '"/>';
+ else if ( sortDirection == Rico.TableColumn.SORT_DESC )
+ sortImageSpan.innerHTML = ' <img width="' + this.options.sortImageWidth + '" ' +
+ 'height="'+ this.options.sortImageHeight + '" ' +
+ 'src="' + this.options.sortDescendImg + '"/>';
+ },
+
+ getSortedColumnIndex: function() {
+ var cols = this.options.columns;
+ for ( var i = 0 ; i < cols.length ; i++ ) {
+ if ( cols[i].isSorted() )
+ return i;
+ }
+
+ return -1;
+ },
+
+ introspectForColumnInfo: function() {
+ var columns = new Array();
+ var headerRow = this.headerTable.rows[0];
+ var headerCells = headerRow.cells;
+ for ( var i = 0 ; i < headerCells.length ; i++ )
+ columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
+ return columns;
+ },
+
+ convertToTableColumns: function(cols) {
+ var columns = new Array();
+ for ( var i = 0 ; i < cols.length ; i++ )
+ columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
+ return columns;
+ },
+
+ deriveColumnNameFromCell: function(cell,columnNumber) {
+ var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
+ return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
+ }
+};
+
+Rico.TableColumn = Class.create();
+
+Rico.TableColumn.UNSORTED = 0;
+Rico.TableColumn.SORT_ASC = "ASC";
+Rico.TableColumn.SORT_DESC = "DESC";
+
+Rico.TableColumn.prototype = {
+ initialize: function(name, sortable) {
+ this.name = name;
+ this.sortable = sortable;
+ this.currentSort = Rico.TableColumn.UNSORTED;
+ },
+
+ isSortable: function() {
+ return this.sortable;
+ },
+
+ isSorted: function() {
+ return this.currentSort != Rico.TableColumn.UNSORTED;
+ },
+
+ getSortDirection: function() {
+ return this.currentSort;
+ },
+
+ toggleSort: function() {
+ if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
+ this.currentSort = Rico.TableColumn.SORT_ASC;
+ else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
+ this.currentSort = Rico.TableColumn.SORT_DESC;
+ },
+
+ setUnsorted: function(direction) {
+ this.setSorted(Rico.TableColumn.UNSORTED);
+ },
+
+ setSorted: function(direction) {
+ // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC...
+ this.currentSort = direction;
+ }
+
+};
+
+
+//-------------------- ricoUtil.js
+Rico.ArrayExtensions = new Array();
+
+if (Object.prototype.extend) {
+ // in prototype.js...
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}else{
+ Object.prototype.extend = function(object) {
+ return Object.extend.apply(this, [this, object]);
+ }
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}
+
+if (Array.prototype.push) {
+ // in prototype.js...
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
+}
+
+if (!Array.prototype.remove) {
+ Array.prototype.remove = function(dx) {
+ if( isNaN(dx) || dx > this.length )
+ return false;
+ for( var i=0,n=0; i<this.length; i++ )
+ if( i != dx )
+ this[n++]=this[i];
+ this.length-=1;
+ };
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
+}
+
+if (!Array.prototype.removeItem) {
+ Array.prototype.removeItem = function(item) {
+ for ( var i = 0 ; i < this.length ; i++ )
+ if ( this[i] == item ) {
+ this.remove(i);
+ break;
+ }
+ };
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
+}
+
+if (!Array.prototype.indices) {
+ Array.prototype.indices = function() {
+ var indexArray = new Array();
+ for ( index in this ) {
+ var ignoreThis = false;
+ for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
+ if ( this[index] == Rico.ArrayExtensions[i] ) {
+ ignoreThis = true;
+ break;
+ }
+ }
+ if ( !ignoreThis )
+ indexArray[ indexArray.length ] = index;
+ }
+ return indexArray;
+ }
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
+}
+
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.unique;
+ Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.inArray;
+
+
+// Create the loadXML method and xml getter for Mozilla
+if ( window.DOMParser &&
+ window.XMLSerializer &&
+ window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
+
+ if (!Document.prototype.loadXML) {
+ Document.prototype.loadXML = function (s) {
+ var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
+ while (this.hasChildNodes())
+ this.removeChild(this.lastChild);
+
+ for (var i = 0; i < doc2.childNodes.length; i++) {
+ this.appendChild(this.importNode(doc2.childNodes[i], true));
+ }
+ };
+ }
+
+ Document.prototype.__defineGetter__( "xml",
+ function () {
+ return (new XMLSerializer()).serializeToString(this);
+ }
+ );
+}
+
+document.getElementsByTagAndClassName = function(tagName, className) {
+ if ( tagName == null )
+ tagName = '*';
+
+ var children = document.getElementsByTagName(tagName) || document.all;
+ var elements = new Array();
+
+ if ( className == null )
+ return children;
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ var classNames = child.className.split(' ');
+ for (var j = 0; j < classNames.length; j++) {
+ if (classNames[j] == className) {
+ elements.push(child);
+ break;
+ }
+ }
+ }
+
+ return elements;
+}
+
+var RicoUtil = {
+
+ getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
+ if ( arguments.length == 2 )
+ mozillaEquivalentCSS = cssProperty;
+
+ var el = $(htmlElement);
+ if ( el.currentStyle )
+ return el.currentStyle[cssProperty];
+ else
+ return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
+ },
+
+ createXmlDocument : function() {
+ if (document.implementation && document.implementation.createDocument) {
+ var doc = document.implementation.createDocument("", "", null);
+
+ 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 Try.these(
+ function() { return new ActiveXObject('MSXML2.DomDocument') },
+ function() { return new ActiveXObject('Microsoft.DomDocument')},
+ function() { return new ActiveXObject('MSXML.DomDocument') },
+ function() { return new ActiveXObject('MSXML3.DomDocument') }
+ ) || false;
+
+ return null;
+ },
+
+ getContentAsString: function( parentNode ) {
+ return parentNode.xml != undefined ?
+ this._getContentAsStringIE(parentNode) :
+ this._getContentAsStringMozilla(parentNode);
+ },
+
+ _getContentAsStringIE: function(parentNode) {
+ var contentStr = "";
+ for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+ var n = parentNode.childNodes[i];
+ if (n.nodeType == 4) {
+ contentStr += n.nodeValue;
+ }
+ else {
+ contentStr += n.xml;
+ }
+ }
+ return contentStr;
+ },
+
+ _getContentAsStringMozilla: function(parentNode) {
+ var xmlSerializer = new XMLSerializer();
+ var contentStr = "";
+ for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+ var n = parentNode.childNodes[i];
+ if (n.nodeType == 4) { // CDATA node
+ contentStr += n.nodeValue;
+ }
+ else {
+ contentStr += xmlSerializer.serializeToString(n);
+ }
+ }
+ return contentStr;
+ },
+
+ toViewportPosition: function(element) {
+ return this._toAbsolute(element,true);
+ },
+
+ toDocumentPosition: function(element) {
+ return this._toAbsolute(element,false);
+ },
+
+ /**
+ * Compute the elements position in terms of the window viewport
+ * so that it can be compared to the position of the mouse (dnd)
+ * This is additions of all the offsetTop,offsetLeft values up the
+ * offsetParent hierarchy, ...taking into account any scrollTop,
+ * scrollLeft values along the way...
+ *
+ * IE has a bug reporting a correct offsetLeft of elements within a
+ * a relatively positioned parent!!!
+ **/
+ _toAbsolute: function(element,accountForDocScroll) {
+
+ if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
+ return this._toAbsoluteMozilla(element,accountForDocScroll);
+
+ var x = 0;
+ var y = 0;
+ var parent = element;
+ while ( parent ) {
+
+ var borderXOffset = 0;
+ var borderYOffset = 0;
+ if ( parent != element ) {
+ var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
+ var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
+ borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
+ borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
+ }
+
+ x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
+ y += parent.offsetTop - parent.scrollTop + borderYOffset;
+ parent = parent.offsetParent;
+ }
+
+ if ( accountForDocScroll ) {
+ x -= this.docScrollLeft();
+ y -= this.docScrollTop();
+ }
+
+ return { x:x, y:y };
+ },
+
+ /**
+ * Mozilla did not report all of the parents up the hierarchy via the
+ * offsetParent property that IE did. So for the calculation of the
+ * offsets we use the offsetParent property, but for the calculation of
+ * the scrollTop/scrollLeft adjustments we navigate up via the parentNode
+ * property instead so as to get the scroll offsets...
+ *
+ **/
+ _toAbsoluteMozilla: function(element,accountForDocScroll) {
+ var x = 0;
+ var y = 0;
+ var parent = element;
+ while ( parent ) {
+ x += parent.offsetLeft;
+ y += parent.offsetTop;
+ parent = parent.offsetParent;
+ }
+
+ parent = element;
+ while ( parent &&
+ parent != document.body &&
+ parent != document.documentElement ) {
+ if ( parent.scrollLeft )
+ x -= parent.scrollLeft;
+ if ( parent.scrollTop )
+ y -= parent.scrollTop;
+ parent = parent.parentNode;
+ }
+
+ if ( accountForDocScroll ) {
+ x -= this.docScrollLeft();
+ y -= this.docScrollTop();
+ }
+
+ return { x:x, y:y };
+ },
+
+ docScrollLeft: function() {
+ if ( window.pageXOffset )
+ return window.pageXOffset;
+ else if ( document.documentElement && document.documentElement.scrollLeft )
+ return document.documentElement.scrollLeft;
+ else if ( document.body )
+ return document.body.scrollLeft;
+ else
+ return 0;
+ },
+
+ docScrollTop: function() {
+ if ( window.pageYOffset )
+ return window.pageYOffset;
+ else if ( document.documentElement && document.documentElement.scrollTop )
+ return document.documentElement.scrollTop;
+ else if ( document.body )
+ return document.body.scrollTop;
+ else
+ return 0;
+ }
+
+};
Modified: plog/trunk/js/ui/plogui.js
===================================================================
--- plog/trunk/js/ui/plogui.js 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/js/ui/plogui.js 2006-01-11 10:39:10 UTC (rev 2767)
@@ -102,3 +102,19 @@
$( 'newArticleCategory' ).value = '';
}
}
+
+/**
+ * this function is the one called when clicking the "add category" button
+ */
+function hideOptionPanel()
+{
+ Element.hide($('optionPanel'));
+ startWidth = $('mainPanel').offsetWidth;
+ new Rico.Effect.Size( $('mainPanel'), 660, null, 500, 10, {complete:function() {}} );
+}
+
+function showOptionPanel()
+{
+ startWidth = $('mainPanel').offsetWidth;
+ new Rico.Effect.Size( $('mainPanel'), 489, null, 500, 10, {complete:function() { Element.show($('optionPanel')); }} );
+}
\ No newline at end of file
Modified: plog/trunk/styles/admin.css
===================================================================
--- plog/trunk/styles/admin.css 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/styles/admin.css 2006-01-11 10:39:10 UTC (rev 2767)
@@ -254,7 +254,7 @@
#tablist
{
- padding : 3px 0;
+ padding : 3px 5px;
margin-left : 0;
font : 11px trebuchet ms, verdana, tahoma, arial, sans-serif;
border-bottom : 1px solid #DEDEDE;
@@ -270,7 +270,7 @@
#tablist li a
{
padding : 3px 0.5em;
- margin-left : 3px;
+ margin-left : 0px;
border : 1px solid #DEDEDE;
background : #F0F0F0;
text-decoration : none;
@@ -297,6 +297,7 @@
{
background : white;
border-bottom : 1px solid white;
+ border-top : 3px solid #FFCC33;
}
.menuTop_level1 ul, li
Modified: plog/trunk/templates/admin/editpost.template
===================================================================
--- plog/trunk/templates/admin/editpost.template 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/templates/admin/editpost.template 2006-01-11 10:39:10 UTC (rev 2767)
@@ -21,7 +21,8 @@
<form name="newPost" id="editPost" action="admin.php" method="post">
<fieldset class="inputField">
<legend>{$locale->tr("editPost")}</legend>
- <div style="float:left; width: 73%; border-right: 1px solid #DEDEDE;">
+ <a href="#" onclick="hideOptionPanel()">Hide</a> | <a href="#" onclick="showOptionPanel()">Show</a>
+ <div name="mainPanel" id="mainPanel" style="float:left; width: 73%; border-right: 1px solid #DEDEDE;">
{include file="$admintemplatepath/formvalidate.template" message=$locale->tr("error_updating_post")}
<div class="field">
@@ -68,7 +69,7 @@
{include file="$admintemplatepath/newpost_customfields.template" type=2 fields=$customfields}
</div>
- <div style="float:left; width: 23%; margin-left: 8px;">
+ <div name="optionPanel" id="optionPanel" style="float:left; width: 23%; margin-left: 8px;">
<div class="field">
<label for="postSlug">{$locale->tr("post_slug")}</label>
Modified: plog/trunk/templates/admin/header.template
===================================================================
--- plog/trunk/templates/admin/header.template 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/templates/admin/header.template 2006-01-11 10:39:10 UTC (rev 2767)
@@ -30,6 +30,7 @@
var plogAdminBaseUrl = "{$url->getBaseUrl(false)}/admin.php";
</script>
<script type="text/javascript" src="js/prototype/prototype.js"></script>
+<script type="text/javascript" src="js/rico/rico.js"></script>
</head>
<body>
@@ -57,6 +58,9 @@
{$menu->generateAt("menu",1)}
</div>
</div>
+ {if $useDownMenuEnabled}
+ {$menu->generateAt("menu","3","","JavaScript")}
+ {/if}
<div style="text-align: right;">
<img style="vertical-align: middle;" src="imgs/admin/icon_home-24.png" alt="Blog" />
Modified: plog/trunk/templates/admin/newpost.template
===================================================================
--- plog/trunk/templates/admin/newpost.template 2006-01-10 15:27:10 UTC (rev 2766)
+++ plog/trunk/templates/admin/newpost.template 2006-01-11 10:39:10 UTC (rev 2767)
@@ -42,9 +42,9 @@
<form name="newPost" id="newPost" action="admin.php" method="post">
<fieldset class="inputField">
<legend>{$locale->tr("newPost")}</legend>
- <div style="float:left; width: 73%; border-right: 1px solid #DEDEDE;">
+ <a href="#" onclick="hideOptionPanel()">Hide</a> | <a href="#" onclick="showOptionPanel()">Show</a>
+ <div name="mainPanel" id="mainPanel" style="float:left; width: 73%; border-right: 1px solid #DEDEDE;">
{include file="$admintemplatepath/formvalidate.template" message=$locale->tr("error_adding_post")}
-
<div class="field">
<label for="postTopic">{$locale->tr("topic")}</label>
<span class="required">*</span>
@@ -87,9 +87,9 @@
<!-- text area custom fields -->
{include file="$admintemplatepath/newpost_customfields.template" type=2 fields=$customfields}
</div>
+
+ <div name="optionPanel" id="optionPanel" style="float:left; width: 23%; margin-left: 8px;">
- <div style="float:left; width: 23%; margin-left: 8px;">
-
<div class="field">
<label for="postSlug">{$locale->tr("post_slug")}</label>
<div class="formHelp">{$locale->tr("post_slug_help")}</div>
More information about the pLog-svn
mailing list