1. Ralph Bean
  2. tw2.jqplugins.fg

Commits

Ralph Bean  committed c868cc9

big refactor in namespace

  • Participants
  • Parent commits 61adaf1
  • Branches default

Comments (0)

Files changed (32)

File MANIFEST.in

View file
  • Ignore whitespace
-recursive-include tw2/jquery_fg/static *
-recursive-include tw2/jquery_fg/templates *
+recursive-include tw2/jquery/plugins/fg/static *
+recursive-include tw2/jquery/plugins/fg/templates *
 include README.rst

File README.rst

View file
  • Ignore whitespace
-tw2.jquery_fg
-=============
+tw2.jquery.plugins.fg
+=====================
 
 :Author: Ralph Bean <ralph.bean@gmail.com>
 
 .. _jQuery: http://jquery.com/
 .. _filament group: http://www.filamentgroup.com/
 
-tw2.jquery_fg is a `toscawidgets2 (tw2)`_ wrapper for a bunch of random widgets and tools from the awesome `filament group`_.
+tw2.jquery.plugins.fg is a `toscawidgets2 (tw2)`_ wrapper for a bunch of random widgets and tools from the awesome `filament group`_.
 
 Live Demo
 ---------
-Peep the `live demonstration <http://craftsman.rc.rit.edu/module?module=tw2.jquery_fg>`_.
+Peep the `live demonstration <http://craftsman.rc.rit.edu/module?module=tw2.jquery.plugins.fg>`_.
 
 Links
 -----
-Get the `source from github <http://github.com/ralphbean/tw2.jquery_fg>`_.
+Get the `source from github <http://github.com/ralphbean/tw2.jquery.plugins.fg>`_.
 
-`PyPI page <http://pypi.python.org/pypi/tw2.jquery_fg>`_
-and `bugs <http://github.com/ralphbean/tw2.jquery_fg/issues/>`_
+`PyPI page <http://pypi.python.org/pypi/tw2.jquery.plugins.fg>`_
+and `bugs <http://github.com/ralphbean/tw2.jquery.plugins.fg/issues/>`_
 
 Description
 -----------
 applications, mobile devices and touchscreen kiosks that are simple
 and accessible to everyone.
 
-This module, tw2.jquery_fg, provides `toscawidgets2 (tw2)`_ access to random `filament group`_ widgets.
+This module, tw2.jquery.plugins.fg, provides `toscawidgets2 (tw2)`_ access to random `filament group`_ widgets.

File development-deps/develop-tw2-destroy-and-setup.sh

View file
  • Ignore whitespace
 pushd $devbase
 
 pip install genshi
+pip install mako
 pip install formencode
 
 hg clone http://bitbucket.org/paj/tw2core || \
         (pushd tw2core && hg pull && popd)
 hg clone http://bitbucket.org/paj/tw2devtools || \
         (pushd tw2devtools && hg pull && popd)
-git clone git://github.com/ralphbean/tw2.jquery_core.git || \
-        (pushd tw2.jquery_core && git pull && popd)
-git clone git://github.com/ralphbean/tw2.jquery_ui.git || \
-        (pushd tw2.jquery_ui && git pull && popd)
+hg clone http://bitbucket.org/paj/tw2forms || \
+        (pushd tw2forms && hg pull && popd)
+hg clone http://bitbucket.org/toscawidgets/tw2jquery || \
+        (pushd tw2jquery && hg pull && popd)
+git clone http://github.com/ralphbean/tw2.jquery.plugins.ui.git || \
+        (pushd tw2.jquery.plugins.ui && git pull && popd)
+#hg clone https://ralphbean@bitbucket.org/toscawidgets/tw2jquery || \
+#        (pushd tw2jquery && hg pull && popd)
 
-pushd tw2core ;  python setup.py develop ; popd
-pushd tw2devtools ; python setup.py develop ; popd
-pushd tw2.jquery_core ; python setup.py develop ; popd
-pushd tw2.jquery_ui ; python setup.py develop ; popd
+pushd tw2core ;  python setup.py install ; popd
+pushd tw2forms ; python setup.py install ; popd
+pushd tw2devtools ; python setup.py install ; popd
+pushd tw2jquery ; python setup.py install_lib install_egg_info ; popd
+pushd tw2.jquery.plugins.ui ; python setup.py install_lib install_egg_info ; popd
 
 popd # $devbase

File development-deps/develop-tw2-start.sh

View file
  • Ignore whitespace
 venv=$devbase/virtualenv-tw2.jquery
 source $venv/bin/activate
 
-python setup.py develop && paster tw2.browser
+python setup.py install_lib install_egg_info && paster tw2.browser
 
 
 

File setup.py

View file
  • Ignore whitespace
 f.close()
 
 setup(
-    name='tw2.jquery_fg',
+    name='tw2.jquery.plugins.fg',
     version='2.0a6',
     description='toscawidgets2 wrapper for random filament group tools',
     long_description=long_description,
     author='Ralph Bean',
     author_email='ralph.bean@gmail.com',
     license='MIT',
-    url='http://github.com/ralphbean/tw2.jquery_fg',
+    url='http://github.com/ralphbean/tw2.jquery.plugins.fg',
     install_requires=[
-        "tw2.core>=2.0b2",
-        "tw2.jquery_core",
-        "tw2.jquery_ui",
+        #"tw2.core>=2.0b2",
+        #"tw2.jquery_core",
+        #"tw2.jquery_ui",
         "genshi",
         "mako",
         ],
     entry_points="""
         [tw2.widgets]
         # Register your widgets so they can be listed in the WidgetBrowser
-        widgets = tw2.jquery_fg
+        widgets = tw2.jquery.plugins.fg
     """,
     keywords = [
         'toscawidgets.widgets',

File tests/test_widgets.py

View file
  • Ignore whitespace
-from tw2.jquery_core.widgets import JQueryWidget
 from webob import Request
 from webob.multidict import NestedMultiDict
 from tw2.core.testbase import assert_in_xml, assert_eq_xml, WidgetTest
 else:
     from webob.multidict import NestedMultiDict
 
-import tw2.jquery_ui
-import tw2.jquery_fg.widgets as w
+import tw2.jquery.plugins.ui
+import tw2.jquery.plugins.fg.widgets as w
 
 class TestMenuWidget(WidgetTest):
     widget = w.MenuWidget
     attrs = {'id' : 'foo'}
     params = {
-        'child' : tw2.jquery_ui.ButtonWidget(id='blahah'),
+        'child' : tw2.jquery.plugins.ui.ButtonWidget(id='blahah'),
         'items' : [
             {'name' : "Breaking News",
              'children' : [

File tw2/jquery/__init__.py

View file
  • Ignore whitespace
+from tw2.jquery.widgets import *

File tw2/jquery/plugins/__init__.py

View file
  • Ignore whitespace
+__import__('pkg_resources').declare_namespace(__name__)

File tw2/jquery/plugins/fg/__init__.py

View file
  • Ignore whitespace
+""" TW2 wrappers for the widgets from 'filament group' widgets
+
+Get the source from http://github.com/ralphbean/tw2.jquery_fg
+"""
+
+from widgets import *

File tw2/jquery/plugins/fg/base.py

View file
  • Ignore whitespace
+
+# TW2 proper imports
+import tw2.core as twc
+from tw2.core.resources import encoder
+
+# tw2.jquery core imports
+from tw2.jquery.base import jQueryJSLink, jQueryPluginLinkMixin
+from tw2.jquery.version import JSLinkMixin
+
+# import from *this* package
+from tw2.jquery.plugins.fg import defaults
+
+### Links, etc...
+class jQueryFGMixin(jQueryPluginLinkMixin):
+    dirname = defaults._fg_dirname_
+    basename='fg.menu'
+    modname = 'tw2.jquery.plugins.fg'
+
+class jQueryFGJSLink(twc.JSLink, jQueryFGMixin):
+    subdir = 'js'
+
+class jQueryFGCSSLink(jQueryFGMixin, twc.CSSLink):
+    subdir = 'css'
+    extension = 'css'
+
+### Resources
+jquery_js = jQueryJSLink()
+jquery_fg_css = jQueryFGCSSLink()
+jquery_fg_js = jQueryFGJSLink()

File tw2/jquery/plugins/fg/defaults.py

View file
  • Ignore whitespace
+#jQuery.ui
+_fg_dirname_        = 'jquery/fg/%(subdir)s'

File tw2/jquery/plugins/fg/samples.py

View file
  • Ignore whitespace
+"""
+Here you can create samples of your widgets by providing default parameters,
+inserting them in a container widget, mixing them with other widgets, etc...
+These samples will appear in the WidgetBrowser
+
+See http://toscawidgets.org/documentation/WidgetBrowser for more information
+"""
+
+import tw2.jquery.plugins.ui
+from widgets import MenuWidget
+
+some_items = [
+    {'name' : "Breaking News",
+        'children' : [ 
+            {'name' : "Entertainment",},
+            {'name' : "Politics",},
+            {'name' : "A&E",},
+            {'name' : "Sports", 
+                'children' : [ 
+                    {'name' : "Baseball",},
+                    {'name' : "Basketball",},
+                    {'name' : "A really long label would wrap nicely as you can see",},
+                    {'name' : "Swimming", 
+                        'children' : [ 
+                            {'name' : "High School",},
+                            {'name' : "College",},
+                            {'name' : "Professional", 
+                                'children' : [ 
+                                    {'name' : "Mens Swimming", 
+                                        'children' : [ 
+                                            {'name' : "News",},
+                                            {'name' : "Events",},
+                                            {'name' : "Awards",},
+                                            {'name' : "Schedule",},
+                                            {'name' : "Team Members",},
+                                            {'name' : "Fan Site",},
+                                        ]
+                                    }, 
+                                    {'name' : "Womens Swimming", 
+                                        'children' : [ 
+                                            {'name' : "News",},
+                                            {'name' : "Events",},
+                                            {'name' : "Awards",},
+                                            {'name' : "Schedule",},
+                                            {'name' : "Team Members",},
+                                            {'name' : "Fan Site",},
+                                        ]
+                                    }, 
+                                ]
+                            }, 
+                            {'name' : "Adult Recreational",},
+                            {'name' : "Youth Recreational",},
+                            {'name' : "Senior Recreational",},
+                        ]
+                    }, 
+                    {'name' : "Tennis",},
+                    {'name' : "Ice Skating",},
+                    {'name' : "Javascript Programming",},
+                    {'name' : "Running",},
+                    {'name' : "Walking",},
+                ]
+            }, 
+            {'name' : "Local",},
+            {'name' : "Health",},
+        ],
+    }, 
+    {'name' : "Entertainment", 
+    'children' : [ 
+        {'name' : "Celebrity news",},
+        {'name' : "Gossip",},
+        {'name' : "Movies",},
+        {'name' : "Music", 
+        'children' : [ 
+            {'name' : "Alternative",},
+            {'name' : "Country",},
+            {'name' : "Dance",},
+            {'name' : "Electronica",},
+            {'name' : "Metal",},
+            {'name' : "Pop",},
+            {'name' : "Rock", 
+                'children' : [ 
+                    {'name' : "Bands", 
+                        'children' : [ 
+                            {'name' : "Dokken",},
+                        ],
+                    }, 
+                    {'name' : "Fan Clubs",},
+                    {'name' : "Songs",},
+                ],
+            }, 
+        ],
+        }, 
+        {'name' : "Slide shows",},
+        {'name' : "Red carpet",},
+    ],
+    }, 
+    {'name' : "Finance", 
+    'children' : [ 
+        {'name' : "Personal", 
+        'children' : [ 
+            {'name' : "Loans",},
+            {'name' : "Savings",},
+            {'name' : "Mortgage",},
+            {'name' : "Debt",},
+        ],
+        }, 
+        {'name' : "Business",},
+    ],
+    }, 
+    {'name' : "Food &#38; Cooking", 
+    'children' : [ 
+        {'name' : "Breakfast",},
+        {'name' : "Lunch",},
+        {'name' : "Dinner",},
+        {'name' : "Dessert", 
+            'children' : [ 
+                {'name' : "Dump Cake",},
+                {'name' : "Doritos",},
+                {'name' : "Both please.",},
+            ],
+        }, 
+    ],
+    }, 
+    {'name' : "Lifestyle",},
+    {'name' : "News",},
+    {'name' : "Politics",},
+    {'name' : "Sports", 
+        'children' : [ 
+            {'name' : "Baseball",},
+            {'name' : "Basketball",},
+            {'name' : "Swimming", 
+            'children' : [ 
+                {'name' : "High School",},
+                {'name' : "College",},
+                {'name' : "Professional", 
+                'children' : [ 
+                    {'name' : "Mens Swimming", 
+                    'children' : [ 
+                            {'name' : "News",},
+                            {'name' : "Events",},
+                            {'name' : "Awards",},
+                            {'name' : "Schedule",},
+                            {'name' : "Team Members",},
+                            {'name' : "Fan Site",},
+                    ],
+                    }, 
+                    {'name' : "Womens Swimming", 
+                    'children' : [ 
+                        {'name' : "News",},
+                        {'name' : "Events",},
+                        {'name' : "Awards",},
+                        {'name' : "Schedule",},
+                        {'name' : "Team Members",},
+                        {'name' : "Fan Site",},
+                    ],
+                    },
+                ],
+                }, 
+                {'name' : "Adult Recreational",},
+                {'name' : "Youth Recreational",},
+                {'name' : "Senior Recreational",},
+            ],
+            }, 
+            {'name' : "Tennis",},
+            {'name' : "Ice Skating",},
+            {'name' : "Javascript Programming",},
+            {'name' : "Running",},
+            {'name' : "Walking",},
+        ],
+        }, 
+    ]
+
+class DemoMenuWidget(MenuWidget):
+    items = some_items
+    options = {
+        'backLink' : False,
+        'maxHeight' : 300,
+        'width' : 250,
+    }
+    child = tw2.jquery.plugins.ui.ButtonWidget(
+        options={
+            'label' : 'A Menu',
+            'icons' : {
+                'primary' : 'ui-icon-triangle-1-s'
+            }
+        }
+    )
+

File tw2/jquery/plugins/fg/static/jquery/fg/css/fg.menu.css

View file
  • Ignore whitespace
+/* Styles for jQuery menu widget
+Author:	Maggie Wachs, maggie@filamentgroup.com
+Date:		September 2008
+
+Slightly modified by Ralph Bean, October 2010
+
+*/
+
+    .hidden { position:absolute; top:0; left:-9999px; width:1px; height:1px; overflow:hidden; }
+    .fg-button { clear:left; margin:0 4px 40px 20px; padding: .4em 1em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
+    .fg-button .ui-icon { position: absolute; top: 50%; margin-top: -8px; left: 50%; margin-left: -8px; }
+    a.fg-button { float:left;  }
+    button.fg-button { width:auto; overflow:visible; } /* removes extra button width in IE */
+
+    .fg-button-icon-left { padding-left: 2.1em; }
+    .fg-button-icon-right { padding-right: 2.1em; }
+    .fg-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; }
+    .fg-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; }
+    .fg-button-icon-solo { display:block; width:8px; text-indent: -9999px; }     /* solo icon buttons must have block properties for the text-indent to work */
+
+    .fg-button.ui-state-loading .ui-icon { background: url(spinner_bar.gif) no-repeat 0 0; }
+
+
+/* REQUIRED STYLES - the menus will only render correctly with these rules */	
+
+.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em;  overflow: hidden; }
+.fg-menu-container.fg-menu-flyout { overflow: visible; }
+
+.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
+
+.fg-menu { position:relative; }
+.fg-menu-flyout .fg-menu { position:static; }
+
+.fg-menu ul { position:absolute; top:0; }
+.fg-menu ul ul { top:-1px; }
+
+.fg-menu-container.fg-menu-ipod .fg-menu-content, 
+.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
+
+.fg-menu.fg-menu-scroll,
+.fg-menu ul.fg-menu-scroll { overflow: scroll;  overflow-x: hidden; }
+
+.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }	
+.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
+
+.fg-menu-flyout ul ul { padding: .4em; }
+.fg-menu-flyout li { position:relative; }
+
+.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
+
+.fg-menu-breadcrumb { margin: 0; padding: 0; }
+
+.fg-menu-footer {  margin-top: .4em; padding: .4em; }
+.fg-menu-header {  margin-bottom: .4em; padding: .4em; }
+
+.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
+.fg-menu-breadcrumb li.fg-menu-prev-list,
+.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
+.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
+
+.fg-menu-breadcrumb a, 
+.fg-menu-breadcrumb span { float: left; }
+
+.fg-menu-footer a:link,
+.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
+.fg-menu-footer a:hover,
+.fg-menu-footer a:active {  }
+
+.fg-menu-footer a span { float:left; cursor: pointer; }
+
+.fg-menu-breadcrumb .fg-menu-prev-list a:link,
+.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
+.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
+.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
+	
+.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
+.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
+	
+.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
+.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
+.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
+.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
+
+
+
+/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into 
+	selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right	*/
+
+.fg-menu a:link,
+.fg-menu a:visited,
+.fg-menu a:hover,
+.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
+
+.fg-menu a { border: 1px dashed transparent; }
+
+.fg-menu a.ui-state-default:link,
+.fg-menu a.ui-state-default:visited,
+.fg-menu a.ui-state-default:hover,
+.fg-menu a.ui-state-default:active,
+.fg-menu a.ui-state-hover:link,
+.fg-menu a.ui-state-hover:visited,
+.fg-menu a.ui-state-hover:hover,
+.fg-menu a.ui-state-hover:active,
+ .fg-menu a.ui-state-active:link,
+ .fg-menu a.ui-state-active:visited,
+ .fg-menu a.ui-state-active:hover,
+.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
+
+.fg-menu a span { display:block; cursor:pointer; }
+
+
+ /* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */	
+ 
+.fg-menu-indicator span { float:left; }
+.fg-menu-indicator span.ui-icon { float:right; }
+
+.fg-menu-content.ui-widget-content, 
+.fg-menu-content ul.ui-widget-content { border:0; }
+
+
+/* ICONS AND DIVIDERS */
+
+.fg-menu.fg-menu-has-icons a:link,
+.fg-menu.fg-menu-has-icons a:visited,
+.fg-menu.fg-menu-has-icons a:hover,
+.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
+
+.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
+.fg-menu .horizontal-divider hr { border:0; height:1px; }
+.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }
+

File tw2/jquery/plugins/fg/static/jquery/fg/js/fg.menu.js

View file
  • Ignore whitespace
+/*-------------------------------------------------------------------- 
+Scripts for creating and manipulating custom fgmenus based on standard <ul> markup
+Version: 3.0, 03.31.2009
+
+By: Maggie Costello Wachs (maggie@filamentgroup.com) and Scott Jehl (scott@filamentgroup.com)
+	http://www.filamentgroup.com
+	* reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_fgmenu/
+		
+Copyright (c) 2009 Filament Group
+Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
+--------------------------------------------------------------------*/
+
+
+var allUIMenus = [];
+
+$.fn.fgmenu = function(options){
+	var caller = this;
+	var options = options;
+	var m = new Menu(caller, options);	
+	allUIMenus.push(m);
+	
+	$(this)
+	.mousedown(function(){
+		if (!m.fgmenuOpen) { m.showLoading(); };
+	})	
+	.click(function(){
+		if (m.fgmenuOpen == false) { m.showMenu(); }
+		else { m.kill(); };
+		return false;
+	});	
+};
+
+function Menu(caller, options){
+	var fgmenu = this;
+	var caller = $(caller);
+	var container = $('<div class="fg-menu-container ui-widget ui-widget-content ui-corner-all">'+options.content+'</div>');
+	
+	this.fgmenuOpen = false;
+	this.fgmenuExists = false;
+	
+	var options = jQuery.extend({
+		content: null,
+		width: 180, // width of fgmenu container, must be set or passed in to calculate widths of child fgmenus
+		maxHeight: 180, // max height of fgmenu (if a drilldown: height does not include breadcrumb)
+		positionOpts: {
+			posX: 'left', 
+			posY: 'bottom',
+			offsetX: 0,
+			offsetY: 0,
+			directionH: 'right',
+			directionV: 'down', 
+			detectH: true, // do horizontal collision detection  
+			detectV: true, // do vertical collision detection
+			linkToFront: false
+		},
+		showSpeed: 200, // show/hide speed in milliseconds
+		callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the fgmenu is showing
+		loadingState: 'ui-state-loading', // class added to the link/button while the fgmenu is created
+		linkHover: 'ui-state-hover', // class for fgmenu option hover state
+		linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level fgmenus		
+	// ----- multi-level fgmenu defaults -----
+		crossSpeed: 200, // cross-fade speed for multi-level fgmenus
+		crumbDefaultText: 'Choose an option:',
+		backLink: true, // in the ipod-style fgmenu: instead of breadcrumbs, show only a 'back' link
+		backLinkText: 'Back',
+		flyOut: false, // multi-level fgmenus are ipod-style by default; this parameter overrides to make a flyout instead
+		flyOutOnState: 'ui-state-default',
+		nextMenuLink: 'ui-icon-triangle-1-e', // class to style the link (specifically, a span within the link) used in the multi-level fgmenu to show the next level
+		topLinkText: 'All',
+		nextCrumbLink: 'ui-icon-carat-1-e'	
+	}, options);
+	
+	var killAllMenus = function(){
+		$.each(allUIMenus, function(i){
+			if (allUIMenus[i].fgmenuOpen) { allUIMenus[i].kill(); };	
+		});
+	};
+	
+	this.kill = function(){
+		caller
+			.removeClass(options.loadingState)
+			.removeClass('fg-menu-open')
+			.removeClass(options.callerOnState);	
+		container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);		
+		if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };	
+		if (options.callerOnState) { 	caller.removeClass(options.callerOnState); };			
+		if (container.is('.fg-menu-ipod')) { fgmenu.resetDrilldownMenu(); };
+		if (container.is('.fg-menu-flyout')) { fgmenu.resetFlyoutMenu(); };	
+		container.parent().hide();	
+		fgmenu.fgmenuOpen = false;
+		$(document).unbind('click', killAllMenus);
+		$(document).unbind('keydown');
+	};
+	
+	this.showLoading = function(){
+		caller.addClass(options.loadingState);
+	};
+
+	this.showMenu = function(){
+		killAllMenus();
+		if (!fgmenu.fgmenuExists) { fgmenu.create() };
+		caller
+			.addClass('fg-menu-open')
+			.addClass(options.callerOnState);
+		container.parent().show().click(function(){ fgmenu.kill(); return false; });
+		container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
+		fgmenu.fgmenuOpen = true;
+		caller.removeClass(options.loadingState);
+		$(document).click(killAllMenus);
+		
+		// assign key events
+		$(document).keydown(function(event){
+			var e;
+			if (event.which !="") { e = event.which; }
+			else if (event.charCode != "") { e = event.charCode; }
+			else if (event.keyCode != "") { e = event.keyCode; }
+			
+			var fgmenuType = ($(event.target).parents('div').is('.fg-menu-flyout')) ? 'flyout' : 'ipod' ;
+			
+			switch(e) {
+				case 37: // left arrow 
+					if (fgmenuType == 'flyout') {
+						$(event.target).trigger('mouseout');
+						if ($('.'+options.flyOutOnState).size() > 0) { $('.'+options.flyOutOnState).trigger('mouseover'); };
+					};
+					
+					if (fgmenuType == 'ipod') {
+						$(event.target).trigger('mouseout');
+						if ($('.fg-menu-footer').find('a').size() > 0) { $('.fg-menu-footer').find('a').trigger('click'); };
+						if ($('.fg-menu-header').find('a').size() > 0) { $('.fg-menu-current-crumb').prev().find('a').trigger('click'); };
+						if ($('.fg-menu-current').prev().is('.fg-menu-indicator')) {
+							$('.fg-menu-current').prev().trigger('mouseover');							
+						};						
+					};
+					return false;
+					break;
+					
+				case 38: // up arrow 
+					if ($(event.target).is('.' + options.linkHover)) {	
+						var prevLink = $(event.target).parent().prev().find('a:eq(0)');						
+						if (prevLink.size() > 0) {
+							$(event.target).trigger('mouseout');
+							prevLink.trigger('mouseover');
+						};						
+					}
+					else { container.find('a:eq(0)').trigger('mouseover'); }
+					return false;
+					break;
+					
+				case 39: // right arrow 
+					if ($(event.target).is('.fg-menu-indicator')) {						
+						if (fgmenuType == 'flyout') {
+							$(event.target).next().find('a:eq(0)').trigger('mouseover');
+						}
+						else if (fgmenuType == 'ipod') {
+							$(event.target).trigger('click');						
+							setTimeout(function(){
+								$(event.target).next().find('a:eq(0)').trigger('mouseover');
+							}, options.crossSpeed);
+						};				
+					}; 
+					return false;
+					break;
+					
+				case 40: // down arrow 
+					if ($(event.target).is('.' + options.linkHover)) {
+						var nextLink = $(event.target).parent().next().find('a:eq(0)');						
+						if (nextLink.size() > 0) {							
+							$(event.target).trigger('mouseout');
+							nextLink.trigger('mouseover');
+						};				
+					}
+					else { container.find('a:eq(0)').trigger('mouseover'); }		
+					return false;						
+					break;
+					
+				case 27: // escape
+					killAllMenus();
+					break;
+					
+				case 13: // enter
+					if ($(event.target).is('.fg-menu-indicator') && fgmenuType == 'ipod') {							
+						$(event.target).trigger('click');						
+						setTimeout(function(){
+							$(event.target).next().find('a:eq(0)').trigger('mouseover');
+						}, options.crossSpeed);					
+					}; 
+					break;
+			};			
+		});
+	};
+	
+	this.create = function(){	
+		container.css({ width: options.width }).appendTo('body').find('ul:first').not('.fg-menu-breadcrumb').addClass('fg-menu');
+		container.find('ul, li a').addClass('ui-corner-all');
+		
+		// aria roles & attributes
+		container.find('ul').attr('role', 'fgmenu').eq(0).attr('aria-activedescendant','active-menuitem').attr('aria-labelledby', caller.attr('id'));
+		container.find('li').attr('role', 'fgmenuitem');
+		container.find('li:has(ul)').attr('aria-haspopup', 'true').find('ul').attr('aria-expanded', 'false');
+		container.find('a').attr('tabindex', '-1');
+		
+		// when there are multiple levels of hierarchy, create flyout or drilldown fgmenu
+		if (container.find('ul').size() > 1) {
+			if (options.flyOut) { fgmenu.flyout(container, options); }
+			else { fgmenu.drilldown(container, options); }	
+		}
+		else {
+			container.find('a').click(function(){
+				fgmenu.chooseItem(this);
+				return false;
+			});
+		};	
+		
+		if (options.linkHover) {
+			var allLinks = container.find('.fg-menu li a');
+			allLinks.hover(
+				function(){
+					var fgmenuitem = $(this);
+					$('.'+options.linkHover).removeClass(options.linkHover).blur().parent().removeAttr('id');
+					$(this).addClass(options.linkHover).focus().parent().attr('id','active-menuitem');
+				},
+				function(){
+					$(this).removeClass(options.linkHover).blur().parent().removeAttr('id');
+				}
+			);
+		};
+		
+		if (options.linkHoverSecondary) {
+			container.find('.fg-menu li').hover(
+				function(){
+					$(this).siblings('li').removeClass(options.linkHoverSecondary);
+					if (options.flyOutOnState) { $(this).siblings('li').find('a').removeClass(options.flyOutOnState); }
+					$(this).addClass(options.linkHoverSecondary);
+				},
+				function(){ $(this).removeClass(options.linkHoverSecondary); }
+			);
+		};	
+		
+		fgmenu.setPosition(container, caller, options);
+		fgmenu.fgmenuExists = true;
+	};
+	
+	this.chooseItem = function(item){
+		fgmenu.kill();
+		// edit this for your own custom function/callback:
+		$('#fgmenuSelection').text($(item).text());	
+		location.href = $(item).attr('href');
+	};
+};
+
+Menu.prototype.flyout = function(container, options) {
+	var fgmenu = this;
+	
+	this.resetFlyoutMenu = function(){
+		var allLists = container.find('ul ul');
+		allLists.removeClass('ui-widget-content').hide();	
+	};
+	
+	container.addClass('fg-menu-flyout').find('li:has(ul)').each(function(){
+		var linkWidth = container.width();
+		var showTimer, hideTimer;
+		var allSubLists = $(this).find('ul');		
+		
+		allSubLists.css({ left: linkWidth, width: linkWidth }).hide();
+			
+		$(this).find('a:eq(0)').addClass('fg-menu-indicator').html('<span>' + $(this).find('a:eq(0)').text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>').hover(
+			function(){
+				clearTimeout(hideTimer);
+				var subList = $(this).next();
+				if (!fitVertical(subList, $(this).offset().top)) { subList.css({ top: 'auto', bottom: 0 }); };
+				if (!fitHorizontal(subList, $(this).offset().left + 100)) { subList.css({ left: 'auto', right: linkWidth, 'z-index': 999 }); };
+				showTimer = setTimeout(function(){
+					subList.addClass('ui-widget-content').show(options.showSpeed).attr('aria-expanded', 'true');	
+				}, 300);	
+			},
+			function(){
+				clearTimeout(showTimer);
+				var subList = $(this).next();
+				hideTimer = setTimeout(function(){
+					subList.removeClass('ui-widget-content').hide(options.showSpeed).attr('aria-expanded', 'false');
+				}, 400);	
+			}
+		);
+
+		$(this).find('ul a').hover(
+			function(){
+				clearTimeout(hideTimer);
+				if ($(this).parents('ul').prev().is('a.fg-menu-indicator')) {
+					$(this).parents('ul').prev().addClass(options.flyOutOnState);
+				}
+			},
+			function(){
+				hideTimer = setTimeout(function(){
+					allSubLists.hide(options.showSpeed);
+					container.find(options.flyOutOnState).removeClass(options.flyOutOnState);
+				}, 500);	
+			}
+		);	
+	});
+	
+	container.find('a').click(function(){
+		fgmenu.chooseItem(this);
+		return false;
+	});
+};
+
+
+Menu.prototype.drilldown = function(container, options) {
+	var fgmenu = this;	
+	var topList = container.find('.fg-menu');	
+	var breadcrumb = $('<ul class="fg-menu-breadcrumb ui-widget-header ui-corner-all ui-helper-clearfix"></ul>');
+	var crumbDefaultHeader = $('<li class="fg-menu-breadcrumb-text">'+options.crumbDefaultText+'</li>');
+	var firstCrumbText = (options.backLink) ? options.backLinkText : options.topLinkText;
+	var firstCrumbClass = (options.backLink) ? 'fg-menu-prev-list' : 'fg-menu-all-lists';
+	var firstCrumbLinkClass = (options.backLink) ? 'ui-state-default ui-corner-all' : '';
+	var firstCrumbIcon = (options.backLink) ? '<span class="ui-icon ui-icon-triangle-1-w"></span>' : '';
+	var firstCrumb = $('<li class="'+firstCrumbClass+'"><a href="#" class="'+firstCrumbLinkClass+'">'+firstCrumbIcon+firstCrumbText+'</a></li>');
+	
+	container.addClass('fg-menu-ipod');
+	
+	if (options.backLink) { breadcrumb.addClass('fg-menu-footer').appendTo(container).hide(); }
+	else { breadcrumb.addClass('fg-menu-header').prependTo(container); };
+	breadcrumb.append(crumbDefaultHeader);
+	
+	var checkMenuHeight = function(el){
+		if (el.height() > options.maxHeight) { el.addClass('fg-menu-scroll') };	
+		el.css({ height: options.maxHeight });
+	};
+	
+	var resetChildMenu = function(el){ el.removeClass('fg-menu-scroll').removeClass('fg-menu-current').height('auto'); };
+	
+	this.resetDrilldownMenu = function(){
+		$('.fg-menu-current').removeClass('fg-menu-current');
+		topList.animate({ left: 0 }, options.crossSpeed, function(){
+			$(this).find('ul').each(function(){
+				$(this).hide();
+				resetChildMenu($(this));				
+			});
+			topList.addClass('fg-menu-current');			
+		});		
+		$('.fg-menu-all-lists').find('span').remove();	
+		breadcrumb.empty().append(crumbDefaultHeader);		
+		$('.fg-menu-footer').empty().hide();	
+		checkMenuHeight(topList);		
+	};
+	
+	topList
+		.addClass('fg-menu-content fg-menu-current ui-widget-content ui-helper-clearfix')
+		.css({ width: container.width() })
+		.find('ul')
+			.css({ width: container.width(), left: container.width() })
+			.addClass('ui-widget-content')
+			.hide();		
+	checkMenuHeight(topList);	
+	
+	topList.find('a').each(function(){
+		// if the link opens a child fgmenu:
+		if ($(this).next().is('ul')) {
+			$(this)
+				.addClass('fg-menu-indicator')
+				.each(function(){ $(this).html('<span>' + $(this).text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>'); })
+				.click(function(){ // ----- show the next fgmenu			
+					var nextList = $(this).next();
+		    		var parentUl = $(this).parents('ul:eq(0)');   		
+		    		var parentLeft = (parentUl.is('.fg-menu-content')) ? 0 : parseFloat(topList.css('left'));    		
+		    		var nextLeftVal = Math.round(parentLeft - parseFloat(container.width()));
+		    		var footer = $('.fg-menu-footer');
+		    		
+		    		// show next fgmenu   		
+		    		resetChildMenu(parentUl);
+		    		checkMenuHeight(nextList);
+					topList.animate({ left: nextLeftVal }, options.crossSpeed);						
+		    		nextList.show().addClass('fg-menu-current').attr('aria-expanded', 'true');    
+		    		
+		    		var setPrevMenu = function(backlink){
+		    			var b = backlink;
+		    			var c = $('.fg-menu-current');
+			    		var prevList = c.parents('ul:eq(0)');
+			    		c.hide().attr('aria-expanded', 'false');
+		    			resetChildMenu(c);
+		    			checkMenuHeight(prevList);
+			    		prevList.addClass('fg-menu-current').attr('aria-expanded', 'true');
+			    		if (prevList.hasClass('fg-menu-content')) { b.remove(); footer.hide(); };
+		    		};		
+		
+					// initialize "back" link
+					if (options.backLink) {
+						if (footer.find('a').size() == 0) {
+							footer.show();
+							$('<a href="#"><span class="ui-icon ui-icon-triangle-1-w"></span> <span>Back</span></a>')
+								.appendTo(footer)
+								.click(function(){ // ----- show the previous fgmenu
+									var b = $(this);
+						    		var prevLeftVal = parseFloat(topList.css('left')) + container.width();		    						    		
+						    		topList.animate({ left: prevLeftVal },  options.crossSpeed, function(){
+						    			setPrevMenu(b);
+						    		});			
+									return false;
+								});
+						}
+					}
+					// or initialize top breadcrumb
+		    		else { 
+		    			if (breadcrumb.find('li').size() == 1){				
+							breadcrumb.empty().append(firstCrumb);
+							firstCrumb.find('a').click(function(){
+								fgmenu.resetDrilldownMenu();
+								return false;
+							});
+						}
+						$('.fg-menu-current-crumb').removeClass('fg-menu-current-crumb');
+						var crumbText = $(this).find('span:eq(0)').text();
+						var newCrumb = $('<li class="fg-menu-current-crumb"><a href="javascript://" class="fg-menu-crumb">'+crumbText+'</a></li>');	
+						newCrumb
+							.appendTo(breadcrumb)
+							.find('a').click(function(){
+								if ($(this).parent().is('.fg-menu-current-crumb')){
+									fgmenu.chooseItem(this);
+								}
+								else {
+									var newLeftVal = - ($('.fg-menu-current').parents('ul').size() - 1) * 180;
+									topList.animate({ left: newLeftVal }, options.crossSpeed, function(){
+										setPrevMenu();
+									});
+								
+									// make this the current crumb, delete all breadcrumbs after this one, and navigate to the relevant fgmenu
+									$(this).parent().addClass('fg-menu-current-crumb').find('span').remove();
+									$(this).parent().nextAll().remove();									
+								};
+								return false;
+							});
+						newCrumb.prev().append(' <span class="ui-icon '+options.nextCrumbLink+'"></span>');
+		    		};			
+		    		return false;    		
+    			});
+		}
+		// if the link is a leaf node (doesn't open a child fgmenu)
+		else {
+			$(this).click(function(){
+				fgmenu.chooseItem(this);
+				return false;
+			});
+		};
+	});
+};
+
+
+/* Menu.prototype.setPosition parameters (defaults noted with *):
+	referrer = the link (or other element) used to show the overlaid object 
+	settings = can override the defaults:
+		- posX/Y: where the top left corner of the object should be positioned in relation to its referrer.
+				X: left*, center, right
+				Y: top, center, bottom*
+		- offsetX/Y: the number of pixels to be offset from the x or y position.  Can be a positive or negative number.
+		- directionH/V: where the entire fgmenu should appear in relation to its referrer.
+				Horizontal: left*, right
+				Vertical: up, down*
+		- detectH/V: detect the viewport horizontally / vertically
+		- linkToFront: copy the fgmenu link and place it on top of the fgmenu (visual effect to make it look like it overlaps the object) */
+
+Menu.prototype.setPosition = function(widget, caller, options) { 
+	var el = widget;
+	var referrer = caller;
+	var dims = {
+		refX: referrer.offset().left,
+		refY: referrer.offset().top,
+		refW: referrer.getTotalWidth(),
+		refH: referrer.getTotalHeight()
+	};	
+	var options = options;
+	var xVal, yVal;
+	
+	var helper = $('<div class="positionHelper"></div>');
+	helper.css({ position: 'absolute', left: dims.refX, top: dims.refY, width: dims.refW, height: dims.refH });
+	el.wrap(helper);
+	
+	// get X pos
+	switch(options.positionOpts.posX) {
+		case 'left': 	xVal = 0; 
+			break;				
+		case 'center': xVal = dims.refW / 2;
+			break;				
+		case 'right': xVal = dims.refW;
+			break;
+	};
+	
+	// get Y pos
+	switch(options.positionOpts.posY) {
+		case 'top': 	yVal = 0;
+			break;				
+		case 'center': yVal = dims.refH / 2;
+			break;				
+		case 'bottom': yVal = dims.refH;
+			break;
+	};
+	
+	// add the offsets (zero by default)
+	xVal += options.positionOpts.offsetX;
+	yVal += options.positionOpts.offsetY;
+	
+	// position the object vertically
+	if (options.positionOpts.directionV == 'up') {
+		el.css({ top: 'auto', bottom: yVal });
+		if (options.positionOpts.detectV && !fitVertical(el)) {
+			el.css({ bottom: 'auto', top: yVal });
+		}
+	} 
+	else {
+		el.css({ bottom: 'auto', top: yVal });
+		if (options.positionOpts.detectV && !fitVertical(el)) {
+			el.css({ top: 'auto', bottom: yVal });
+		}
+	};
+	
+	// and horizontally
+	if (options.positionOpts.directionH == 'left') {
+		el.css({ left: 'auto', right: xVal });
+		if (options.positionOpts.detectH && !fitHorizontal(el)) {
+			el.css({ right: 'auto', left: xVal });
+		}
+	} 
+	else {
+		el.css({ right: 'auto', left: xVal });
+		if (options.positionOpts.detectH && !fitHorizontal(el)) {
+			el.css({ left: 'auto', right: xVal });
+		}
+	};
+	
+	// if specified, clone the referring element and position it so that it appears on top of the fgmenu
+	if (options.positionOpts.linkToFront) {
+		referrer.clone().addClass('linkClone').css({
+			position: 'absolute', 
+			top: 0, 
+			right: 'auto', 
+			bottom: 'auto', 
+			left: 0, 
+			width: referrer.width(), 
+			height: referrer.height()
+		}).insertAfter(el);
+	};
+};
+
+
+/* Utilities to sort and find viewport dimensions */
+
+function sortBigToSmall(a, b) { return b - a; };
+
+jQuery.fn.getTotalWidth = function(){
+	return $(this).width() + parseInt($(this).css('paddingRight')) + parseInt($(this).css('paddingLeft')) + parseInt($(this).css('borderRightWidth')) + parseInt($(this).css('borderLeftWidth'));
+};
+
+jQuery.fn.getTotalHeight = function(){
+	return $(this).height() + parseInt($(this).css('paddingTop')) + parseInt($(this).css('paddingBottom')) + parseInt($(this).css('borderTopWidth')) + parseInt($(this).css('borderBottomWidth'));
+};
+
+function getScrollTop(){
+	return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
+};
+
+function getScrollLeft(){
+	return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
+};
+
+function getWindowHeight(){
+	var de = document.documentElement;
+	return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
+};
+
+function getWindowWidth(){
+	var de = document.documentElement;
+	return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
+};
+
+/* Utilities to test whether an element will fit in the viewport
+	Parameters:
+	el = element to position, required
+	leftOffset / topOffset = optional parameter if the offset cannot be calculated (i.e., if the object is in the DOM but is set to display: 'none') */
+	
+function fitHorizontal(el, leftOffset){
+	var leftVal = parseInt(leftOffset) || $(el).offset().left;
+	return (leftVal + $(el).width() <= getWindowWidth() + getScrollLeft() && leftVal - getScrollLeft() >= 0);
+};
+
+function fitVertical(el, topOffset){
+	var topVal = parseInt(topOffset) || $(el).offset().top;
+	return (topVal + $(el).height() <= getWindowHeight() + getScrollTop() && topVal - getScrollTop() >= 0);
+};
+
+/*-------------------------------------------------------------------- 
+ * javascript method: "pxToEm"
+ * by:
+   Scott Jehl (scott@filamentgroup.com) 
+   Maggie Wachs (maggie@filamentgroup.com)
+   http://www.filamentgroup.com
+ *
+ * Copyright (c) 2008 Filament Group
+ * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
+ *
+ * Description: Extends the native Number and String objects with pxToEm method. pxToEm converts a pixel value to ems depending on inherited font size.  
+ * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
+ * Demo: http://www.filamentgroup.com/examples/pxToEm/	 	
+ *							
+ * Options:  	 								
+ 		scope: string or jQuery selector for font-size scoping
+ 		reverse: Boolean, true reverses the conversion to em-px
+ * Dependencies: jQuery library						  
+ * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
+ *
+ * Version: 2.0, 08.01.2008 
+ * Changelog:
+ *		08.02.2007 initial Version 1.0
+ *		08.01.2008 - fixed font-size calculation for IE
+--------------------------------------------------------------------*/
+
+Number.prototype.pxToEm = String.prototype.pxToEm = function(settings){
+	//set defaults
+	settings = jQuery.extend({
+		scope: 'body',
+		reverse: false
+	}, settings);
+	
+	var pxVal = (this == '') ? 0 : parseFloat(this);
+	var scopeVal;
+	var getWindowWidth = function(){
+		var de = document.documentElement;
+		return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
+	};	
+	
+	/* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size. 
+		For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size. 	
+		When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size) 
+		to get an accurate em value. */
+				
+	if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
+		var calcFontSize = function(){		
+			return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
+		};
+		scopeVal = calcFontSize();
+	}
+	else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); };
+			
+	var result = (settings.reverse == true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
+	return result;
+};

File tw2/jquery/plugins/fg/templates/__init__.py

  • Ignore whitespace
Empty file added.

File tw2/jquery/plugins/fg/templates/menu.html

View file
  • Ignore whitespace
+<div xmlns:py="http://genshi.edgewall.org/"
+     xmlns:xi="http://www.w3.org/2001/XInclude"
+     id="${w.attrs['id']}-wrapper">
+
+${w.child.display()}
+<div id="${w.attrs['id']}-target" class='hidden'>
+    <ul>
+    <py:for each="entry in w.items">
+        <xi:include href="recursive_menu.html" py:with="item=entry" />
+    </py:for>
+    </ul>
+</div>
+
+<script xmlns:py="http://genshi.edgewall.org/" type="text/javascript">
+$(function() {
+    $(document).ready( function () {
+        var opts = ${w.options};
+        opts['content'] = $('#${w.attrs["id"]}-target').html();
+        $("#${w.attrs['id']}").${w.jqmethod}(opts);
+        <py:if test="w.click">
+        $("#${w.attrs['id']}").click(${w.click});
+        </py:if>
+    });
+});
+</script>
+</div>

File tw2/jquery/plugins/fg/templates/menu.mak

View file
  • Ignore whitespace
+<%namespace name="tw" module="tw2.core.mako_util"/>
+<div id="${w.attrs['id']}-wrapper">
+${w.child.display()}
+<div id="${w.attrs['id']}-target" class='hidden'>
+    <ul>
+	% for entry in w.items:
+		<%include file="recursive_menu.mak" args="item=entry" />
+	% endfor
+    </ul>
+</div>
+
+<script type="text/javascript">
+$(function() {
+    $(document).ready( function () {
+        var opts = ${w.options};
+        opts['content'] = $('#${w.attrs["id"]}-target').html();
+        $("#${w.attrs['id']}").${w.jqmethod}(opts);
+		% if w.click:
+        $("#${w.attrs['id']}").click(${w.click});
+		% endif
+    });
+});
+</script>
+</div>

File tw2/jquery/plugins/fg/templates/recursive_menu.html

View file
  • Ignore whitespace
+
+<li xmlns:py="http://genshi.edgewall.org/"
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+    <a href="${item.get('href', '#')}">${item.get('name', None)}</a>
+    <ul py:if="len(item.get('children', [])) > 0">
+    <py:for each="child in item.get('children', [])">
+        <xi:include href="recursive_menu.html" py:with="item=child;" />
+    </py:for>
+    </ul>
+</li>

File tw2/jquery/plugins/fg/templates/recursive_menu.mak

View file
  • Ignore whitespace
+<%page args="item"/>
+<li>
+    <a href="${item.get('href', '#')}">${item.get('name', 'foo')}</a>
+	% if len(item.get('children', [])) > 0:
+    <ul>
+	% for child in item.get('children', []):
+        <%include file="recursive_menu.mak" args="item=child" />
+	% endfor
+	</ul>
+	% endif
+</li>

File tw2/jquery/plugins/fg/widgets.py

View file
  • Ignore whitespace
+
+# tw2-proper imports
+import tw2.core as twc
+from tw2.core.resources import encoder
+
+# imports from this package
+from tw2.jquery.plugins.ui import base as uibase
+from tw2.jquery.plugins.fg import base as fgbase
+import tw2.jquery.plugins.ui
+
+class MenuWidget(uibase.JQueryUIWidget, twc.DisplayOnlyWidget):
+    """
+    Configurable options - Default values are next to each option:
+        width: 180 - width of menu container. Required for hierarchical menus (flyout, ipod) to calculate widths of child menus
+
+        maxHeight: 180 - maximum height of menu (if ipod-style, height does not include breadcrumb, which can vary in height depending on content)
+
+        positionOpts (defaults listed below) - location and orientation of the menu, relative to the button/link used to open it
+            posX: 'left' - left side of the menu aligned with a side of the button, left or right
+
+            posY: 'bottom' - top of the menu aligned with a either top or bottom of the menu
+
+            offsetX: 0 - number of pixels to offset the menu left/right
+
+            offsetY: 0 - number of pixels to offset the menu top/bottom
+
+            directionH: 'right' - horizontal direction in which the menu will open, to the right or left
+
+            directionV: 'down' - vertical direction in which the menu will open, up or down
+
+            detectH: true - do horizontal collision detection
+
+            detectV: true - do vertical collision detection
+
+            linkToFront: false - set to "true," this option will create a clone of the button and place it over the menu for an overlapping visual effect
+
+        showSpeed: 200 - speed to show/hide the menu in milliseconds
+
+        callerOnState: 'ui-state-active' - class to change the appearance of the link/button when the menu is showing
+
+        loadingState: 'ui-state-loading' - class added to the link/button while the menu is created
+
+        linkHover: 'ui-state-hover' - class for menu option hover state
+
+        linkHoverSecondary: 'li-hover' - alternate hover class, may be used for multi-level menus
+
+    Hierarchical (iPod-style and flyout) menu defaults
+        crossSpeed: 200 - transition effect speed for multi-level menus
+        
+        crumbDefaultText: 'Choose an option:' - text that appears in the ipod-style footer before a child menu is opened
+        
+        backLink: true - when set to "true", this option shows a 'back' link under the menu instead of a full breadcrumb in the ipod-style menu
+        
+        backLinkText: 'Back' - text for the back link (i.e., could also say 'previous')
+        
+        flyOut: false - multi-level menus are ipod-style by default; set this option to "true" to override and make flyout the default instead
+        
+        flyOutOnState: 'ui-state-default' - class added to an option when its child menu is showing
+        
+        nextMenuLink: 'ui-icon-triangle-1-e' - class to style the link (specifically, a span within the link) used in the multi-level menu to show the next level
+        
+        topLinkText: 'All' - text for the first breadcrumb that navigates back to the start of the ipod-style menu
+        
+        nextCrumbLink: 'ui-icon-carat-1-e' - class for setting the background image that follows each breadcrumb link (currently a carat)
+    """
+    resources = [
+        fgbase.jquery_js,
+        uibase.jquery_ui_js,
+        uibase.jquery_ui_css,
+        fgbase.jquery_fg_js,
+        fgbase.jquery_fg_css,
+    ]
+
+
+    template = "tw2.jquery.plugins.fg.templates.menu"
+    jqmethod = 'fgmenu'
+
+    items = twc.Param('A recursive dictionary of menu entries', default=[])
+    child = twc.Param(
+        'A label for the menu (an instance of tw2.jquery.plugins.ui.ButtonWidget)',
+    )
+    def prepare(self):
+        super(MenuWidget, self).prepare()
+        if not hasattr(self, 'child') or getattr(self, 'child') == None:
+            raise ValueError, "MenuWidget must be supplied a child parameter" 
+        req_type = "ButtonWidget"
+        if not req_type in str(type(self.child)):
+            raise ValueError, "MenuWidget child must be of type %s not %s" % (
+                req_type, type(self.child))
+

File tw2/jquery_fg/__init__.py

  • Ignore whitespace
-""" TW2 wrappers for the widgets from 'filament group' widgets
-
-Get the source from http://github.com/ralphbean/tw2.jquery_fg
-"""
-
-from widgets import *

File tw2/jquery_fg/base.py

  • Ignore whitespace
-
-# TW2 proper imports
-import tw2.core as twc
-from tw2.core.resources import encoder
-
-# tw2.jquery_core imports
-from tw2.jquery_core import JQueryWidget
-from tw2.jquery_core.base import jQueryJSLink
-from tw2.jquery_core.base import jQueryPluginLinkMixin
-from tw2.jquery_core.version import JSLinkMixin
-
-# import from *this* package
-from tw2.jquery_fg import defaults
-
-### Links, etc...
-class jQueryFGMixin(jQueryPluginLinkMixin):
-    dirname = defaults._fg_dirname_
-    basename='fg.menu'
-    modname = 'tw2.jquery_fg'
-
-class jQueryFGJSLink(twc.JSLink, jQueryFGMixin):
-    subdir = 'js'
-
-class jQueryFGCSSLink(jQueryFGMixin, twc.CSSLink):
-    subdir = 'css'
-    extension = 'css'
-
-### Resources
-jquery_js = jQueryJSLink()
-jquery_fg_css = jQueryFGCSSLink()
-jquery_fg_js = jQueryFGJSLink()

File tw2/jquery_fg/defaults.py

  • Ignore whitespace
-#jQuery.ui
-_fg_dirname_        = 'jquery/fg/%(subdir)s'
-_fg_basename_       = 'jquery_fg'

File tw2/jquery_fg/samples.py

  • Ignore whitespace
-"""
-Here you can create samples of your widgets by providing default parameters,
-inserting them in a container widget, mixing them with other widgets, etc...
-These samples will appear in the WidgetBrowser
-
-See http://toscawidgets.org/documentation/WidgetBrowser for more information
-"""
-
-import tw2.jquery_ui
-from widgets import MenuWidget
-
-some_items = [
-    {'name' : "Breaking News",
-        'children' : [ 
-            {'name' : "Entertainment",},
-            {'name' : "Politics",},
-            {'name' : "A&E",},
-            {'name' : "Sports", 
-                'children' : [ 
-                    {'name' : "Baseball",},
-                    {'name' : "Basketball",},
-                    {'name' : "A really long label would wrap nicely as you can see",},
-                    {'name' : "Swimming", 
-                        'children' : [ 
-                            {'name' : "High School",},
-                            {'name' : "College",},
-                            {'name' : "Professional", 
-                                'children' : [ 
-                                    {'name' : "Mens Swimming", 
-                                        'children' : [ 
-                                            {'name' : "News",},
-                                            {'name' : "Events",},
-                                            {'name' : "Awards",},
-                                            {'name' : "Schedule",},
-                                            {'name' : "Team Members",},
-                                            {'name' : "Fan Site",},
-                                        ]
-                                    }, 
-                                    {'name' : "Womens Swimming", 
-                                        'children' : [ 
-                                            {'name' : "News",},
-                                            {'name' : "Events",},
-                                            {'name' : "Awards",},
-                                            {'name' : "Schedule",},
-                                            {'name' : "Team Members",},
-                                            {'name' : "Fan Site",},
-                                        ]
-                                    }, 
-                                ]
-                            }, 
-                            {'name' : "Adult Recreational",},
-                            {'name' : "Youth Recreational",},
-                            {'name' : "Senior Recreational",},
-                        ]
-                    }, 
-                    {'name' : "Tennis",},
-                    {'name' : "Ice Skating",},
-                    {'name' : "Javascript Programming",},
-                    {'name' : "Running",},
-                    {'name' : "Walking",},
-                ]
-            }, 
-            {'name' : "Local",},
-            {'name' : "Health",},
-        ],
-    }, 
-    {'name' : "Entertainment", 
-    'children' : [ 
-        {'name' : "Celebrity news",},
-        {'name' : "Gossip",},
-        {'name' : "Movies",},
-        {'name' : "Music", 
-        'children' : [ 
-            {'name' : "Alternative",},
-            {'name' : "Country",},
-            {'name' : "Dance",},
-            {'name' : "Electronica",},
-            {'name' : "Metal",},
-            {'name' : "Pop",},
-            {'name' : "Rock", 
-                'children' : [ 
-                    {'name' : "Bands", 
-                        'children' : [ 
-                            {'name' : "Dokken",},
-                        ],
-                    }, 
-                    {'name' : "Fan Clubs",},
-                    {'name' : "Songs",},
-                ],
-            }, 
-        ],
-        }, 
-        {'name' : "Slide shows",},
-        {'name' : "Red carpet",},
-    ],
-    }, 
-    {'name' : "Finance", 
-    'children' : [ 
-        {'name' : "Personal", 
-        'children' : [ 
-            {'name' : "Loans",},
-            {'name' : "Savings",},
-            {'name' : "Mortgage",},
-            {'name' : "Debt",},
-        ],
-        }, 
-        {'name' : "Business",},
-    ],
-    }, 
-    {'name' : "Food &#38; Cooking", 
-    'children' : [ 
-        {'name' : "Breakfast",},
-        {'name' : "Lunch",},
-        {'name' : "Dinner",},
-        {'name' : "Dessert", 
-            'children' : [ 
-                {'name' : "Dump Cake",},
-                {'name' : "Doritos",},
-                {'name' : "Both please.",},
-            ],
-        }, 
-    ],
-    }, 
-    {'name' : "Lifestyle",},
-    {'name' : "News",},
-    {'name' : "Politics",},
-    {'name' : "Sports", 
-        'children' : [ 
-            {'name' : "Baseball",},
-            {'name' : "Basketball",},
-            {'name' : "Swimming", 
-            'children' : [ 
-                {'name' : "High School",},
-                {'name' : "College",},
-                {'name' : "Professional", 
-                'children' : [ 
-                    {'name' : "Mens Swimming", 
-                    'children' : [ 
-                            {'name' : "News",},
-                            {'name' : "Events",},
-                            {'name' : "Awards",},
-                            {'name' : "Schedule",},
-                            {'name' : "Team Members",},
-                            {'name' : "Fan Site",},
-                    ],
-                    }, 
-                    {'name' : "Womens Swimming", 
-                    'children' : [ 
-                        {'name' : "News",},
-                        {'name' : "Events",},
-                        {'name' : "Awards",},
-                        {'name' : "Schedule",},
-                        {'name' : "Team Members",},
-                        {'name' : "Fan Site",},
-                    ],
-                    },
-                ],
-                }, 
-                {'name' : "Adult Recreational",},
-                {'name' : "Youth Recreational",},
-                {'name' : "Senior Recreational",},
-            ],
-            }, 
-            {'name' : "Tennis",},
-            {'name' : "Ice Skating",},
-            {'name' : "Javascript Programming",},
-            {'name' : "Running",},
-            {'name' : "Walking",},
-        ],
-        }, 
-    ]
-
-class DemoMenuWidget(MenuWidget):
-    items = some_items
-    options = {
-        'backLink' : False,
-        'maxHeight' : 300,
-        'width' : 250,
-    }
-    child = tw2.jquery_ui.ButtonWidget(
-        options={
-            'label' : 'A Menu',
-            'icons' : {
-                'primary' : 'ui-icon-triangle-1-s'
-            }
-        }
-    )
-

File tw2/jquery_fg/static/jquery/fg/css/fg.menu.css

  • Ignore whitespace
-/* Styles for jQuery menu widget
-Author:	Maggie Wachs, maggie@filamentgroup.com
-Date:		September 2008
-
-Slightly modified by Ralph Bean, October 2010
-
-*/
-
-    .hidden { position:absolute; top:0; left:-9999px; width:1px; height:1px; overflow:hidden; }
-    .fg-button { clear:left; margin:0 4px 40px 20px; padding: .4em 1em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
-    .fg-button .ui-icon { position: absolute; top: 50%; margin-top: -8px; left: 50%; margin-left: -8px; }
-    a.fg-button { float:left;  }
-    button.fg-button { width:auto; overflow:visible; } /* removes extra button width in IE */
-
-    .fg-button-icon-left { padding-left: 2.1em; }
-    .fg-button-icon-right { padding-right: 2.1em; }
-    .fg-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; }
-    .fg-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; }
-    .fg-button-icon-solo { display:block; width:8px; text-indent: -9999px; }     /* solo icon buttons must have block properties for the text-indent to work */
-
-    .fg-button.ui-state-loading .ui-icon { background: url(spinner_bar.gif) no-repeat 0 0; }
-
-
-/* REQUIRED STYLES - the menus will only render correctly with these rules */	
-
-.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em;  overflow: hidden; }
-.fg-menu-container.fg-menu-flyout { overflow: visible; }
-
-.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
-
-.fg-menu { position:relative; }
-.fg-menu-flyout .fg-menu { position:static; }
-
-.fg-menu ul { position:absolute; top:0; }
-.fg-menu ul ul { top:-1px; }
-
-.fg-menu-container.fg-menu-ipod .fg-menu-content, 
-.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
-
-.fg-menu.fg-menu-scroll,
-.fg-menu ul.fg-menu-scroll { overflow: scroll;  overflow-x: hidden; }
-
-.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }	
-.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
-
-.fg-menu-flyout ul ul { padding: .4em; }
-.fg-menu-flyout li { position:relative; }
-
-.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
-
-.fg-menu-breadcrumb { margin: 0; padding: 0; }
-
-.fg-menu-footer {  margin-top: .4em; padding: .4em; }
-.fg-menu-header {  margin-bottom: .4em; padding: .4em; }
-
-.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
-.fg-menu-breadcrumb li.fg-menu-prev-list,
-.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
-.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
-
-.fg-menu-breadcrumb a, 
-.fg-menu-breadcrumb span { float: left; }
-
-.fg-menu-footer a:link,
-.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
-.fg-menu-footer a:hover,
-.fg-menu-footer a:active {  }
-
-.fg-menu-footer a span { float:left; cursor: pointer; }
-
-.fg-menu-breadcrumb .fg-menu-prev-list a:link,
-.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
-.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
-.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
-	
-.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
-.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
-	
-.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
-.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
-.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
-.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
-
-
-
-/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into 
-	selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right	*/
-
-.fg-menu a:link,
-.fg-menu a:visited,
-.fg-menu a:hover,
-.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
-
-.fg-menu a { border: 1px dashed transparent; }
-
-.fg-menu a.ui-state-default:link,
-.fg-menu a.ui-state-default:visited,
-.fg-menu a.ui-state-default:hover,
-.fg-menu a.ui-state-default:active,
-.fg-menu a.ui-state-hover:link,
-.fg-menu a.ui-state-hover:visited,
-.fg-menu a.ui-state-hover:hover,
-.fg-menu a.ui-state-hover:active,
- .fg-menu a.ui-state-active:link,
- .fg-menu a.ui-state-active:visited,
- .fg-menu a.ui-state-active:hover,
-.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
-
-.fg-menu a span { display:block; cursor:pointer; }
-
-
- /* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */	
- 
-.fg-menu-indicator span { float:left; }
-.fg-menu-indicator span.ui-icon { float:right; }
-
-.fg-menu-content.ui-widget-content, 
-.fg-menu-content ul.ui-widget-content { border:0; }
-
-
-/* ICONS AND DIVIDERS */
-
-.fg-menu.fg-menu-has-icons a:link,
-.fg-menu.fg-menu-has-icons a:visited,
-.fg-menu.fg-menu-has-icons a:hover,
-.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
-
-.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
-.fg-menu .horizontal-divider hr { border:0; height:1px; }
-.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }
-

File tw2/jquery_fg/static/jquery/fg/js/fg.menu.js

  • Ignore whitespace
-/*-------------------------------------------------------------------- 
-Scripts for creating and manipulating custom fgmenus based on standard <ul> markup
-Version: 3.0, 03.31.2009
-
-By: Maggie Costello Wachs (maggie@filamentgroup.com) and Scott Jehl (scott@filamentgroup.com)
-	http://www.filamentgroup.com
-	* reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_fgmenu/
-		
-Copyright (c) 2009 Filament Group
-Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
---------------------------------------------------------------------*/
-
-
-var allUIMenus = [];
-
-$.fn.fgmenu = function(options){
-	var caller = this;
-	var options = options;
-	var m = new Menu(caller, options);	
-	allUIMenus.push(m);
-	
-	$(this)
-	.mousedown(function(){
-		if (!m.fgmenuOpen) { m.showLoading(); };
-	})	
-	.click(function(){
-		if (m.fgmenuOpen == false) { m.showMenu(); }
-		else { m.kill(); };
-		return false;
-	});	
-};
-
-function Menu(caller, options){
-	var fgmenu = this;
-	var caller = $(caller);
-	var container = $('<div class="fg-menu-container ui-widget ui-widget-content ui-corner-all">'+options.content+'</div>');
-	
-	this.fgmenuOpen = false;
-	this.fgmenuExists = false;
-	
-	var options = jQuery.extend({
-		content: null,
-		width: 180, // width of fgmenu container, must be set or passed in to calculate widths of child fgmenus
-		maxHeight: 180, // max height of fgmenu (if a drilldown: height does not include breadcrumb)
-		positionOpts: {
-			posX: 'left', 
-			posY: 'bottom',
-			offsetX: 0,
-			offsetY: 0,
-			directionH: 'right',
-			directionV: 'down', 
-			detectH: true, // do horizontal collision detection  
-			detectV: true, // do vertical collision detection
-			linkToFront: false
-		},
-		showSpeed: 200, // show/hide speed in milliseconds
-		callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the fgmenu is showing
-		loadingState: 'ui-state-loading', // class added to the link/button while the fgmenu is created
-		linkHover: 'ui-state-hover', // class for fgmenu option hover state
-		linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level fgmenus		
-	// ----- multi-level fgmenu defaults -----
-		crossSpeed: 200, // cross-fade speed for multi-level fgmenus
-		crumbDefaultText: 'Choose an option:',
-		backLink: true, // in the ipod-style fgmenu: instead of breadcrumbs, show only a 'back' link
-		backLinkText: 'Back',
-		flyOut: false, // multi-level fgmenus are ipod-style by default; this parameter overrides to make a flyout instead
-		flyOutOnState: 'ui-state-default',
-		nextMenuLink: 'ui-icon-triangle-1-e', // class to style the link (specifically, a span within the link) used in the multi-level fgmenu to show the next level
-		topLinkText: 'All',
-		nextCrumbLink: 'ui-icon-carat-1-e'	
-	}, options);
-	
-	var killAllMenus = function(){
-		$.each(allUIMenus, function(i){
-			if (allUIMenus[i].fgmenuOpen) { allUIMenus[i].kill(); };	
-		});
-	};
-	
-	this.kill = function(){
-		caller
-			.removeClass(options.loadingState)
-			.removeClass('fg-menu-open')
-			.removeClass(options.callerOnState);	
-		container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);		
-		if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };	
-		if (options.callerOnState) { 	caller.removeClass(options.callerOnState); };			
-		if (container.is('.fg-menu-ipod')) { fgmenu.resetDrilldownMenu(); };
-		if (container.is('.fg-menu-flyout')) { fgmenu.resetFlyoutMenu(); };	
-		container.parent().hide();	
-		fgmenu.fgmenuOpen = false;
-		$(document).unbind('click', killAllMenus);
-		$(document).unbind('keydown');
-	};
-	
-	this.showLoading = function(){
-		caller.addClass(options.loadingState);
-	};
-
-	this.showMenu = function(){
-		killAllMenus();
-		if (!fgmenu.fgmenuExists) { fgmenu.create() };
-		caller
-			.addClass('fg-menu-open')
-			.addClass(options.callerOnState);
-		container.parent().show().click(function(){ fgmenu.kill(); return false; });
-		container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
-		fgmenu.fgmenuOpen = true;