docs/main
by Luke Macken
docs/main/LiveWidget.rst | 44 +++++++++++++++++++-------------------------
1 file changed, 19 insertions(+), 25 deletions(-)
New commits:
commit dff14a2249fb223cc853270ff49519cc7d216188
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 06:48:21 2009 -0500
Some Live Widget documentation improvements
diff --git a/docs/main/LiveWidget.rst b/docs/main/LiveWidget.rst
index d0d9ba8..f1d9709 100644
--- a/docs/main/LiveWidget.rst
+++ b/docs/main/LiveWidget.rst
@@ -23,8 +23,12 @@ the 'stuff' message topic, and will perform an `alert` upon new messages.
template = "Hi, I'm a live widget!"
-The Live Feed Widget
---------------------
+Live Feeds
+----------
+
+A Live Feed Demo Widget
+~~~~~~~~~~~~~~~~~~~~~~~
+
.. code-block:: python
@@ -34,9 +38,11 @@ The Live Feed Widget
:tabs: demo, source, template, parameters
:size: large
---------------------------------------------------------------------------------
+The Live Feed Widget
+~~~~~~~~~~~~~~~~~~~~
-Moksha provides an example :class:`LiveFeedWidget` that displays messages from the `feed_example` topic, using jQuery.
+The :class:`LiveFeedWidget` itself is just a simple :class:`LiveWidget` that
+uses a little bit of jQuery to add and remove feed entries from a list.
.. code-block:: python
@@ -45,32 +51,20 @@ Moksha provides an example :class:`LiveFeedWidget` that displays messages from t
class LiveFeedWidget(LiveWidget):
""" A live streaming feed widget """
- topic = 'feed_example'
+ params = {
+ 'url': 'The feed URL',
+ 'topic': 'A topic or list of topics to subscribe to',
+ 'feed': 'A moksha Feed object',
+ }
+ template = '${feed(id=id, url=url)}'
onmessage = """
$.each(json, function() {
$("#${id} ul li:last").remove();
- $("<li/>").hide().html(
+ $("<li/>").html(
$("<a/>")
.attr("href", this.link)
.text(this.title))
- .prependTo($("#${id} ul"))
- .show();
+ .prependTo($("#${id} ul"));
});
"""
- template = '${feed()}'
- url = None
-
- def update_params(self, d):
- super(LiveFeedWidget, self).update_params(d)
- d['feed'] = Feed(d['id'], url=d.url)
-
-Using the LiveFeedWidget
-------------------------
-
-.. code-block:: python
-
- from moksha.api.widgets.feed import LiveFeedWidget
-
- class MyLiveWidget(LiveFeedWidget):
- topic = 'feeds.myfeed'
- url = 'http://foo.com/bar.xml'
+ feed = Feed()
15 years, 4 months
18 commits - development.ini docs/conf.py docs/index.rst docs/main moksha/api moksha/controllers moksha/middleware moksha/templates moksha/widgetbrowser moksha/widgets setup.py start-moksha
by Luke Macken
development.ini | 15
docs/conf.py | 6
docs/index.rst | 1
docs/main/Development.rst | 5
docs/main/Feeds.rst | 14
docs/main/LiveWidget.rst | 10
moksha/api/menus/default.py | 4
moksha/api/widgets/feed/live.py | 18
moksha/controllers/root.py | 9
moksha/middleware/extensionpoint.py | 1
moksha/templates/widget_browser/show_widget.html | 11
moksha/widgetbrowser/paster.ini | 21
moksha/widgetbrowser/setup.cfg | 14
moksha/widgetbrowser/setup.py | 38
moksha/widgetbrowser/widgetbrowser/__init__.py | 2
moksha/widgetbrowser/widgetbrowser/command.py | 54
moksha/widgetbrowser/widgetbrowser/repl.py | 305
moksha/widgetbrowser/widgetbrowser/sphinx_ext.py | 43
moksha/widgetbrowser/widgetbrowser/static/httprepl.css | 78
moksha/widgetbrowser/widgetbrowser/static/httprepl.js | 432 +
moksha/widgetbrowser/widgetbrowser/static/jquery.js | 3436 ++++++++++
moksha/widgetbrowser/widgetbrowser/static/loading.gif |binary
moksha/widgetbrowser/widgetbrowser/static/pygments.css | 59
moksha/widgetbrowser/widgetbrowser/static/tab.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.accordion.css | 12
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.all.css | 9
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.calendar.css | 167
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.css | 2
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.datepicker.css | 179
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.dialog.css | 95
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.menu.css | 8
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.resizable.css | 20
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.slider.css | 11
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tablesorter.css | 40
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tabs.css | 105
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toasterLite.css | 106
moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toolbar.css | 241
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-act.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-over.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-act.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-over.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-act.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-over.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/asc.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/bg.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/desc.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-e.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-n.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-ne.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-nw.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-s.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-se.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-sw.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-title.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-w.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/menu-submenu.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-e.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-n.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-ne.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-nw.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-s.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-se.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-sw.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-w.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/shadow.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-1.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-2.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-handle.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/tabs.png |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-e.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-n.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-ne.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-nw.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-s.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-se.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-sw.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-w.gif |binary
moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif |binary
moksha/widgetbrowser/widgetbrowser/static/ui.base.js | 204
moksha/widgetbrowser/widgetbrowser/static/ui.dialog.js | 459 +
moksha/widgetbrowser/widgetbrowser/static/ui.draggable.js | 572 +
moksha/widgetbrowser/widgetbrowser/static/ui.resizable.js | 710 ++
moksha/widgetbrowser/widgetbrowser/static/ui.tabs.css | 114
moksha/widgetbrowser/widgetbrowser/static/ui.tabs.js | 616 +
moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.css | 9
moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.js | 13
moksha/widgetbrowser/widgetbrowser/templates/home.html | 60
moksha/widgetbrowser/widgetbrowser/templates/list_widgets.html | 15
moksha/widgetbrowser/widgetbrowser/templates/show_widget.html | 16
moksha/widgetbrowser/widgetbrowser/templates/validation_result.html | 13
moksha/widgetbrowser/widgetbrowser/templates/widget_browser_tabs.html | 12
moksha/widgetbrowser/widgetbrowser/templates/widget_index.html | 18
moksha/widgetbrowser/widgetbrowser/templates/widget_parameters.html | 21
moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.html | 1
moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.mak | 1
moksha/widgetbrowser/widgetbrowser/tests/dummy_template.html | 1
moksha/widgetbrowser/widgetbrowser/tests/test_app.txt | 50
moksha/widgetbrowser/widgetbrowser/tests/test_sphinx_ext.py | 26
moksha/widgetbrowser/widgetbrowser/tests/testdocs/conf.py | 149
moksha/widgetbrowser/widgetbrowser/tests/testdocs/index.rst | 12
moksha/widgetbrowser/widgetbrowser/tests/widgets.py | 25
moksha/widgetbrowser/widgetbrowser/util.py | 242
moksha/widgetbrowser/widgetbrowser/widgets.py | 71
moksha/widgetbrowser/widgetbrowser/wsgiapp.py | 235
moksha/widgets/demos.py | 10
setup.py | 7
start-moksha | 7
112 files changed, 9233 insertions(+), 27 deletions(-)
New commits:
commit 8449fdbe647808c36d4ec6fa70ea117aedb0b44f
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:39:37 2009 -0500
Add the widget_browser templates directory...
diff --git a/moksha/templates/widget_browser/show_widget.html b/moksha/templates/widget_browser/show_widget.html
new file mode 100644
index 0000000..7f391dc
--- /dev/null
+++ b/moksha/templates/widget_browser/show_widget.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: ${widget_name}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widget_browser">
+ <div py:replace="widget_output" />
+ </body>
+</html>
commit d9391f6ad1ed13f8d1387656d5a934471a7ba10e
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:39:14 2009 -0500
Link to moksha's internal documentation, which is now being served by the WidgetBrowser
diff --git a/moksha/api/menus/default.py b/moksha/api/menus/default.py
index 7d68bcf..e7e0628 100644
--- a/moksha/api/menus/default.py
+++ b/moksha/api/menus/default.py
@@ -27,7 +27,7 @@ class MokshaContextMenu(MokshaContextualMenu):
<img src="/images/moksha-icon.png" style="position:absolute;margin-top:-20px; margin-left:-25px;margin-bottom:10px"/><br/>
</a>
<a href="http://moksha.fedorahosted.org" target="_blank">Moksha Homepage</a>
- <a href="http://lmacken.fedorapeople.org/moksha/">Documentation</a>
+ <a href="/widget">Documentation</a>
<a href="https://fedorahosted.org/moksha/report/3">Tickets</a>
<a href="https://fedorahosted.org/moksha/">Wiki</a>
"""
@@ -68,7 +68,7 @@ class MokshaDefaultMenu(MokshaMenu):
</a>
<a rel="separator"></a>
<a href="http://moksha.fedorahosted.org" target="_blank">Moksha Homepage</a>
- <a href="http://lmacken.fedorapeople.org/moksha/">Documentation</a>
+ <a href="/widget">Documentation</a>
<a href="https://fedorahosted.org/moksha/report/3">Tickets</a>
<a href="https://fedorahosted.org/moksha/">Wiki</a>
"""
commit 80e7fb12eaaf42a6ccc6de822cf380d3f0f79d6e
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:35:43 2009 -0500
Update our start-moksha script install the WidgetBrowser, and the latest TG2 beta
diff --git a/start-moksha b/start-moksha
index 2a4c1d7..78b8e32 100755
--- a/start-moksha
+++ b/start-moksha
@@ -5,11 +5,12 @@ if [ ! $VIRTUAL_ENV ]; then
if [ ! -d tg2env ]; then
echo "Initializing a TurboGears2 virtual environment"
virtualenv --no-site-packages tg2env
+ #virtualenv tg2env
source tg2env/bin/activate
- easy_install -U WebOb
+ #easy_install -i http://www.turbogears.org/2.0/downloads/2.0b5/index tg.devtools
easy_install -i http://www.turbogears.org/2.0/downloads/current/index tg.devtools
- easy_install tgext.crud
- easy_install tw.jquery==dev
+ easy_install "tw.jquery==dev"
+ pushd moksha/widgetbrowser; python setup.py develop; popd
else
source tg2env/bin/activate
fi
commit 49dbf4e2d8975c68a4cf0af7e86199b934f8d629
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:33:42 2009 -0500
Remove our global_resources widgetbrowser hack, and just just register the
resources in our BaseController, before we hit the WidgetBrowser WSGI app.
diff --git a/moksha/lib/base.py b/moksha/lib/base.py
index c5c8a3d..8332c1d 100644
--- a/moksha/lib/base.py
+++ b/moksha/lib/base.py
@@ -44,7 +44,7 @@ class BaseController(TGController):
tmpl_context.get_url = url
## Inject our global resources
- if request.path.startswith('/appz') or request.path.startswith('/widget'):
+ if request.path.startswith('/appz') or request.path.startswith('/widgets'):
# Don't inject global resources for apps or widgets.
tmpl_context.moksha_global_resources = lambda: ''
else:
diff --git a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
index a89a137..266a826 100644
--- a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
+++ b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
@@ -11,8 +11,6 @@ import tw
from tw.api import Widget, WidgetType, make_middleware
from widgetbrowser import util, widgets, repl
-from moksha.api.widgets.global_resources import global_resources as moksha_global_resources
-
try:
from formencode import Invalid
have_formencode = True
@@ -82,7 +80,6 @@ class WidgetBrowser(object):
app = StaticURLParser(self.built_docs)
resources = widgets.widgetbrowser_js.retrieve_resources()
tw.framework.register_resources(resources)
- moksha_global_resources.register_resources()
return app(environ, start_response)
_widget_controllers = {}
commit 71c39c535f1444b745d46b7b7e6e7dc549cc1b9e
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:30:22 2009 -0500
Remove the LiveFlotWidget from the setup.py in favor of the demo
diff --git a/setup.py b/setup.py
index 2eb5756..2f17bc3 100644
--- a/setup.py
+++ b/setup.py
@@ -58,13 +58,14 @@ setup(
chat = moksha.api.widgets.chat.controllers:ChatController
[moksha.widget]
+ livefeed_demo = moksha.widgets.demos:LiveFeedDemo
liveflot = moksha.api.widgets.flot:LiveFlotWidget
- livefeed = moksha.api.widgets.feed.live:LiveFeedWidget
chat = moksha.api.widgets.chat:LiveChatWidget
#livegraph = moksha.examples.livegraph:LiveGraphWidget
#grid = moksha.api.widgets:Grid
ptd = moksha.widgets.misc.ptd:ProcessedTowerDefense
+
[moksha.global]
# The pipeline for our live widgets
stomp_js = moksha.api.widgets.stomp:stomp_js
@@ -86,8 +87,8 @@ setup(
blueprint_screen_css = moksha.widgets.blueprint:blueprint_screen_css
blueprint_print_css = moksha.widgets.blueprint:blueprint_print_css
- # Blueprint plugins
- blueprint_fancytype_css = moksha.widgets.blueprint:blueprint_plugin_fancytype_css
+ ## Blueprint plugins
+ #blueprint_fancytype_css = moksha.widgets.blueprint:blueprint_plugin_fancytype_css
konami_js = moksha.widgets.misc.ptd:konami
commit b33b8c1bf1c40e7a7ccc5c55707dc10291194e13
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:24:27 2009 -0500
Re-organize our WidgetBrowser module
diff --git a/docs/conf.py b/docs/conf.py
index f2ea061..4e2bb91 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -155,5 +155,5 @@ code_path = test_path = os.path.dirname(os.path.abspath(__file__)) + os.path.sep
#
# Enable the ToscaWidgets WidgetBrowser
#
-import moksha.widgetbrowser
-extensions.append("moksha.widgetbrowser.sphinx_ext")
+import widgetbrowser
+extensions.append("widgetbrowser.sphinx_ext")
diff --git a/moksha/lib/base.py b/moksha/lib/base.py
index 8332c1d..c5c8a3d 100644
--- a/moksha/lib/base.py
+++ b/moksha/lib/base.py
@@ -44,7 +44,7 @@ class BaseController(TGController):
tmpl_context.get_url = url
## Inject our global resources
- if request.path.startswith('/appz') or request.path.startswith('/widgets'):
+ if request.path.startswith('/appz') or request.path.startswith('/widget'):
# Don't inject global resources for apps or widgets.
tmpl_context.moksha_global_resources = lambda: ''
else:
diff --git a/moksha/widgetbrowser/__init__.py b/moksha/widgetbrowser/__init__.py
deleted file mode 100644
index c037ed3..0000000
--- a/moksha/widgetbrowser/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from wsgiapp import WidgetBrowser
-from util import widget_url
diff --git a/moksha/widgetbrowser/command.py b/moksha/widgetbrowser/command.py
deleted file mode 100644
index 4b15fbe..0000000
--- a/moksha/widgetbrowser/command.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from wsgiref.simple_server import make_server
-from optparse import OptionParser
-
-from widgetbrowser.wsgiapp import WidgetBrowser
-
-
-_parser = OptionParser(usage = "%prog [OPTIONS] [widget_url]")
-_parser.add_option("-i", "--interactive",
- dest="interactive",
- action="store_true",
- default=False)
-_parser.add_option("-b", "--browser",
- dest="browser",
- action="store_true",
- default=False)
-_parser.add_option("-d", "--docs",
- dest="docs",
- default=None)
-_parser.add_option("-p", "--port",
- dest="port",
- default=8000)
-
-def browser_command(argv=None):
- """Command line interface to launch the widgetbrowser"""
- opts, args = _parser.parse_args(argv)
-
- # Only allow passing display arguments in debug mode
- if args:
- widget_url = args[0] + '/'
- else:
- widget_url = ''
- app = WidgetBrowser(interactive=opts.interactive, docs_dir=opts.docs)
- if opts.interactive:
- try:
- from weberror.evalexception import EvalException
- app = EvalException(app)
- except ImportError:
- raise ImportError("You need to install WebError for interactive "
- "debugging")
- url = "http://127.0.0.1:%s/" % opts.port
- if opts.browser:
- import webbrowser
- webbrowser.open(url + widget_url)
- server = make_server('127.0.0.1', int(opts.port), app)
- print "Server started at " + url
- try:
- server.serve_forever()
- except (KeyboardInterrupt, SystemExit):
- pass
-
-if __name__ == '__main__':
- import sys
- sys.exit(browser_command(sys.argv))
-
diff --git a/moksha/widgetbrowser/paster.ini b/moksha/widgetbrowser/paster.ini
new file mode 100644
index 0000000..c1b4d92
--- /dev/null
+++ b/moksha/widgetbrowser/paster.ini
@@ -0,0 +1,21 @@
+#
+# Sample PasteDeploy ini file to launch the WidgetBrowser.
+#
+# This is most useful while developing and debugging widgets since paster can autoreload the WidgetBrowser
+# whenever any imported module's source is modified. To enable reloading do:
+#
+# $ paster serve --reload paster.ini
+#
+# The %(here)s variable will be replaced with the parent directory of this file
+#
+
+[server:main]
+use = egg:Paste#http
+# Bind only to the loopback interface since we're starting in intercative mode.
+host = 127.0.0.1
+port = 8000
+
+[app:main]
+use = egg:WidgetBrowser
+# Enable interactive mode so WebError (needs to be easy_installed first) and the Terminal are available
+interactive = true
diff --git a/moksha/widgetbrowser/repl.py b/moksha/widgetbrowser/repl.py
deleted file mode 100644
index 5855068..0000000
--- a/moksha/widgetbrowser/repl.py
+++ /dev/null
@@ -1,305 +0,0 @@
-"""
-Robert Brewer was the original author of the module this module has heavily
-inspired from. http://www.aminus.net/wiki/HTTPREPL
-"""
-import warnings
-from itertools import count
-import codeop
-import inspect
-import os
-import re
-
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-
-import sys
-import traceback
-
-from webob import Request, Response, exc
-
-try:
- from formencode import Invalid
- have_formencode = True
-except ImportError:
- have_formencode = False
-
-from genshi.util import LRUCache
-import tw
-from tw.api import make_middleware, Widget
-
-from widgetbrowser import util, widgets
-
-class HTTPREPL:
-
- def __init__(self, locals=None):
- self.locals = {}
- if locals:
- self.locals.update(locals)
- self.buffer = []
-
- def push(self, line):
- """Push 'line' and return exec results (None if more input needed)."""
- if line == "help":
- return "Type help(object) for help about object."
- if line == "help()":
- return "You cannot call help() without an argument."
-
- self.buffer.append(line)
- source = "\n".join(self.buffer)
-
- try:
- code = codeop.compile_command(source, "<HTTP input>", 'single')
- except (OverflowError, SyntaxError, ValueError):
- self.buffer = []
- return traceback.format_exc()
-
- if code is None:
- # More lines needed.
- return None
-
- self.buffer = []
- return self.execute(code)
-
- def execute(self, code):
- """Execute the given code in self.locals and return any stdout/sterr."""
- out = StringIO()
- oldout = sys.stdout
- olderr = sys.stderr
- sys.stdout = sys.stderr = out
- try:
- try:
- exec code in self.locals
- except:
- result = traceback.format_exc()
- else:
- result = out.getvalue()
- finally:
- # FormEncode will break if _ is left in __builtins__ and it tries
- # to use it as a translator
- __builtins__.pop('_', None)
- sys.stdout = oldout
- sys.stderr = olderr
- out.close()
- return result
-
- def dir(self, line):
- """Examine a partial line and provide attr list of final expr."""
- line = re.split(r"\s", line)[-1].strip()
- # Support lines like "thing.attr" as "thing.", because the browser
- # may not finish calculating the partial line until after the user
- # has clicked on a few more keys.
- line = ".".join(line.split(".")[:-1])
- try:
- result = eval("dir(%s)" % line, {}, self.locals)
- except:
- return []
- return result
-
- def doc(self, line):
- """Examine a partial line and provide sig+doc of final expr."""
- line = re.split(r"\s", line)[-1].strip()
- # Support lines like "func(text" as "func(", because the browser
- # may not finish calculating the partial line until after the user
- # has clicked on a few more keys.
- line = "(".join(line.split("(")[:-1])
- try:
- result = eval(line, {}, self.locals)
- try:
- if isinstance(result, type):
- func = result.__init__
- else:
- func = result
- args, varargs, varkw, defaults = inspect.getargspec(func)
- except TypeError:
- if callable(result):
- doc = getattr(result, "__doc__", "") or ""
- return "%s\n\n%s" % (line, doc)
- return None
- except:
- return None
-
- if args and args[0] == 'self':
- args.pop(0)
- missing = object()
- defaults = defaults or []
- defaults = ([missing] * (len(args) - len(defaults))) + list(defaults)
- arglist = []
- for a, d in zip(args, defaults):
- if d is missing:
- arglist.append(a)
- else:
- arglist.append("%s=%s" % (a, d))
- if varargs:
- arglist.append("*%s" % varargs)
- if varkw:
- arglist.append("**%s" % varkw)
- doc = getattr(result, "__doc__", "") or ""
- return "%s(%s)\n%s" % (line, ", ".join(arglist), doc)
-
-
-class DeferredDisplay(object):
- """Wraps a widget and the args passed to display/render so we can defer
- its display to another request.
-
- .. note::
- The JS code is dependent on the output of __repr__ since it parses it
- to know a widget is being displayed so it can open an overlay.
- """
- _counter = count(0)
- def __init__(self, widget, value, **kw):
- self.id = self._counter.next()
- self.value = value
- self.widget = widget
- self.kw = kw
-
- def display(self):
- """
- Displays the widget as it was intended to be displayed when it was
- wrapped.
- """
- return self.widget.display(self.value, **self.kw)
-
- __call__ = display
-
- def __repr__(self):
- data = (self.id, self.widget.__class__)
- return self.__class__.__name__ + repr(data)
-
-
-class WidgetReplApp(object):
- def __init__(self, locals=None, widget_browser=None, max_dialogs=10):
- self.repl = HTTPREPL(locals)
- warnings.warn("\n"*2 + "*"*79 + "\n"
- "DISCLAIMER:\n"
- "Running this app poses a significant security threat "
- "if accessible to an \nattacker. Make sure the server is "
- "bound to the loopback interface or behind\na firewall "
- "and that there are no local untrusted users.\n" + "*"*79)
- if widget_browser:
- self.widget_browser = widget_browser
- self.displayed_widgets = LRUCache(max_dialogs)
- self.setup_tw()
-
- def setup_tw(repl_app):
- # Stack TW's middleware configured with dummy default_view to signal
- # that a widget is being displayed so we can wrap and register its
- # output.
- conf = {'toscawidgets.framework.default_view' : 'tw_repl',
- 'toscawidgets.middleware.inject_resources' : True}
- repl_app.app = make_middleware(repl_app.app, conf)
- # monkey-patch display and render to hijack output
- def wrap(f):
- if f.func_name == 'wrapper':
- return f
- def wrapper(self, value=None, **kw):
- if self.displays_on == 'tw_repl':
- o = DeferredDisplay(self, value, **kw)
- repl_app.displayed_widgets[o.id] = o
- else:
- o = f(self, value, **kw)
- return o
- return wrapper
- Widget.display = wrap(Widget.display)
- Widget.render = wrap(Widget.render)
-
- def __call__(self, environ, start_response):
- assert not environ['wsgi.multiprocess'], "Cannot run in a multiprocess"\
- " environment"
- return self.app(environ, start_response)
-
- def app(self, environ, start_response):
- """Main dispatcher. pops PATH_INFO and delegates to exposed methods."""
- req = Request(environ.copy())
- resp = Response(request=req, content_type='text/html; charset=UTF8')
- first_part = req.path_info_pop() or 'index'
- method = getattr(self, first_part, None)
- if getattr(method, 'exposed', False):
- output = method(req, resp)
- if isinstance(output, unicode):
- resp.body = output.encode('utf-8')
- elif isinstance(output, str):
- resp.body = output
- elif output:
- resp = output
- else:
- resp = exc.HTTPNotImplemented()
- return resp(environ, start_response)
-
- def index(self, req, resp):
- """Return an HTTP-based Read-Eval-Print-Loop terminal."""
- # Override default_view so resources display properly
- tw.framework.default_view = 'toscawidgets'
- tpl = '<html><head><title>"%(title)s</title></head>' \
- '<body class="flora">%(repl)s</body></html>'
- prefix = req.script_name + '/'
- return tpl % {'title': 'WidgetBrowser Terminal',
- 'repl': widgets.repl(prefix=req.script_name + '/')}
- index.exposed = True
-
- def push(self, req, resp):
- """Push 'line' and return exec results as a bare response."""
- line = req.params['line']
- result = self.repl.push(line)
- if result is None:
- # More input lines needed.
- resp.status_int = 204
- return result
- push.exposed = True
-
- def dir(self, req, resp):
- """Push 'line' and return result of eval on the final expr."""
- line = req.params['line']
- result = self.repl.dir(line)
- if not result:
- resp.status_int = 204
- return
- return repr(result)
- dir.exposed = True
-
- def doc(self, req, resp):
- """Push 'line' and return result of getargspec on the final expr."""
- line = req.params['line']
- result = self.repl.doc(line)
- if not result:
- resp.status_int = 204
- return result
- doc.exposed = True
-
- def enrich_namespace(self, ns, request):
-
- _disp = request.GET.get('_disp', '')
-
- if not "_disp" in ns:
- ns["_disp"]=_disp
- if not "interactive" in ns:
- ns["interactive"]=True
- return ns
-
- def widget_output(self, req, resp):
- try:
- key = int(req.path_info.strip('/'))
- dd = self.displayed_widgets[key]
- except KeyError:
- resp.status_int = 404
- return "There's now widget output at this URL. Maybe it has "\
- "expired? Try increasing the 'max_dialogs' parameter"
-
- widget = dd.widget
- widget_name = widget.__class__.__name__
- render = self.widget_browser.render
- if have_formencode and req.method.upper() == "POST":
- # A widget submission, try to validate.
- try:
- value = widget.validate(req.POST)
- value = util.pretty_print(value)
- return render('validation_result.html', locals())
- except Invalid, error:
- pass
- # Override default_view because WidgetBrowser renders on Genshi, not
- # 'tw_repl', this is needed so widget and resources display properly
- tw.framework.default_view = 'genshi'
- widget_output = dd.display()
- return render('show_widget.html', self.enrich_namespace(locals(),request=req))
- widget_output.exposed = True
diff --git a/moksha/widgetbrowser/setup.cfg b/moksha/widgetbrowser/setup.cfg
new file mode 100644
index 0000000..929d7b2
--- /dev/null
+++ b/moksha/widgetbrowser/setup.cfg
@@ -0,0 +1,14 @@
+[aliases]
+release = egg_info -RDb "" sdist bdist_egg register upload
+test = nosetests
+cover = nosetests --with-coverage
+
+[egg_info]
+tag_build = dev
+tag_date = true
+
+[nosetests]
+with-coverage = false
+cover-package = widgetbrowser
+doctest-extension = .txt
+with-doctest = true
diff --git a/moksha/widgetbrowser/setup.py b/moksha/widgetbrowser/setup.py
new file mode 100644
index 0000000..41c24a0
--- /dev/null
+++ b/moksha/widgetbrowser/setup.py
@@ -0,0 +1,38 @@
+from setuptools import setup, find_packages
+import sys, os
+
+version = '0.1'
+
+setup(name='WidgetBrowser',
+ version=version,
+ description="ToscaWidgets browser",
+ long_description="""\
+""",
+ classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+ keywords='toscawidgets',
+ author='Alberto Valverde Gonzalez',
+ author_email='alberto(a)toscat.net',
+ url='http://toscawidgets.org/',
+ license='MIT',
+ packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+ include_package_data=True,
+ zip_safe=True,
+ install_requires=[
+ "ToscaWidgets>=0.9.2dev-20080602",
+ "Genshi",
+ "WebOb",
+ ],
+ tests_require = ['nose', 'formencode', 'sphinx'],
+ extras_require = {
+ 'full': ['Sphinx', 'Pygments', 'docutils', 'nose', 'WebTest',
+ 'WebError', 'coverage', 'FormEncode'],
+ },
+ entry_points="""
+ [console_scripts]
+ twbrowser = widgetbrowser.command:browser_command
+ [paste.app_factory]
+ main = widgetbrowser.wsgiapp:WidgetBrowser
+ [toscawidgets.widgets]
+ widgets = widgetbrowser.widgets
+ """,
+ )
diff --git a/moksha/widgetbrowser/sphinx_ext.py b/moksha/widgetbrowser/sphinx_ext.py
deleted file mode 100644
index f0c9bea..0000000
--- a/moksha/widgetbrowser/sphinx_ext.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import os
-from docutils import nodes, utils
-from docutils.parsers.rst import directives
-
-from widgetbrowser import util, widgets
-
-widget_tabs = widgets.WidgetBrowserTabs(in_sphinx=True)
-
-def widgetbrowser_directive(dirname, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- """Processes the `widgetbrowser` reStructuredText directive.
-
- When generating the URL for the widget it peeks into os.environ for the
- 'TW_BROWSER_PREFIX' environment variable.
- """
- widget_path = arguments[0]
- widget = util.import_widget(widget_path)
- if not widget:
- reporter = state.document.reporter
- msg = reporter.warning(
- 'No widget found at %r' % widget_path, line=lineno)
- prb = nodes.problematic(block_text, block_text, msg)
- return [msg, prb]
- tabs = options.get('tabs') or widget_tabs.tabs
- prefix = os.environ.get('TW_BROWSER_PREFIX')
- size = options.get('size')
- html = widget_tabs(widget, tabs=tabs, prefix=prefix, size=size)
- node = nodes.raw('', html, format='html')
- return [node]
-
-
-def _get_tabs(arg):
- if arg is None:
- return []
- return [s.strip() for s in arg.split(',')]
-
-def _get_size(arg):
- return arg or "small"
-
-def setup(app):
- browser_options = {'tabs': _get_tabs, 'size':_get_size}
- app.add_directive('widgetbrowser', widgetbrowser_directive, 1, (1, 0, 1),
- **browser_options)
diff --git a/moksha/widgetbrowser/static/httprepl.css b/moksha/widgetbrowser/static/httprepl.css
deleted file mode 100644
index 6eda851..0000000
--- a/moksha/widgetbrowser/static/httprepl.css
+++ /dev/null
@@ -1,78 +0,0 @@
-.httprepl .output pre {
- font: 10pt monospace;
- margin: 0;
- padding: 1px;
- border: 1px solid #E0E0FF;
- background-color: #F8F8FF;
-
- white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
- white-space: -pre-wrap; /* Opera 4 - 6 */
- white-space: -o-pre-wrap; /* Opera 7 */
- white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
- http://www.w3.org/TR/css3-text/#white-space */
- word-wrap: break-word; /* IE 5.5+ */
-}
-
-.httprepl .output pre.stdin {
- border: none;
- background-color: transparent;
-}
-
-form {
- font: 10pt monospace;
- margin: 0;
-}
-
-.httprepl .input {
- font: 10pt monospace;
- width: 95%;
- border-top: none;
- border-right: 1px dotted #E0E0FF;
- border-bottom: none;
- border-left: 1px dotted #E0E0FF;
-}
-
-.httprepl .tipbar {
- position: fixed;
- top: 10px;
-
- /* See http://annevankesteren.nl/test/examples/ie/position-fixed.html */
- _position:absolute;
- _top:expression(eval(document.body.scrollTop) + 10);
-
- right: 10px;
-
- max-width: 50%;
- max-height: 80%;
- /* See http://www.svendtofte.com/code/max_width_in_ie/ */
- width: expression(document.body.clientWidth / 2);
- height: expression(document.body.clientHeight * 0.8);
-
- border: 2px outset #DDCCBB;
- background-color: #FFEEDD;
- font: 9pt monospace;
-
- margin: 0;
- padding: 4px;
-
- white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
- white-space: -pre-wrap; /* Opera 4 - 6 */
- white-space: -o-pre-wrap; /* Opera 7 */
- white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
- http://www.w3.org/TR/css3-text/#white-space */
- word-wrap: break-word; /* IE 5.5+ */
-
- display: none;
- overflow: auto;
-}
-
-.httprepl .tipbar a {
- padding: 4px;
- text-decoration: none;
- color: #666666;
-}
-
-.widget-dialog {
- background: #fff;
- z-index: 9999;
-}
diff --git a/moksha/widgetbrowser/static/httprepl.js b/moksha/widgetbrowser/static/httprepl.js
deleted file mode 100644
index a85f1ef..0000000
--- a/moksha/widgetbrowser/static/httprepl.js
+++ /dev/null
@@ -1,432 +0,0 @@
-var HTTPRepl = (function ($) {
- function http() {
- var h;
- if (typeof(XMLHttpRequest) != "undefined") {
- h = new XMLHttpRequest();
- } else {
- try { h = new ActiveXObject("Msxml2.XMLHTTP"); }
- catch (e) {
- try { h = new ActiveXObject("Microsoft.XMLHTTP"); }
- catch (E) { alert("Your browser is not supported."); }
- }
- }
- return h
- }
-
-
- // HISTORY NAVIGATION //
-
- function use_history(elem) {
- var content = get_text(elem);
- // Strip the leading prompt
- if (elem.className == 'stdin') content = content.substr(4);
- input.value = content;
- input.focus();
- }
-
- function history_hook() {
- use_history(this);
- }
-
- var current_history = undefined;
-
- function prev_history() {
- if (current_history == undefined) {
- var prev = output.lastChild;
- } else {
- var prev = current_history.previousSibling;
- }
- while (prev != null && prev.className != 'stdin') {
- prev = prev.previousSibling;
- }
- if (prev != null) {
- current_history = prev;
- use_history(prev);
- }
- }
-
- function next_history() {
- if (current_history == undefined) return;
-
- var next = current_history.nextSibling;
- while (next != null && next.className != 'stdin') {
- next = next.nextSibling;
- }
- if (next != null) {
- current_history = next;
- use_history(next);
- }
- }
-
-
- // CODE COMPLETION //
-
- current_range = undefined;
-
- function partial_line() {
- if (document.selection) {
- // Internet Explorer
- current_range = document.selection.createRange();
- var end = current_range.getBookmark().charCodeAt(2) - 2;
- } else {
- var end = input.selectionEnd;
- }
- return input.value.substring(0, end);
- }
-
- function insert_text(newtext) {
- if (document.selection) {
- // Internet Explorer
- current_range.text = newtext;
- current_range.select();
- } else {
- var start = input.selectionStart;
- input.value = input.value.substring(0, start) + newtext + input.value.substr(input.selectionEnd);
- var end = start + newtext.length;
- input.setSelectionRange(end, end);
- }
- }
-
- function clear_tips() {
- tipbar.style.display = '';
- while (tipbar.hasChildNodes()) {
- tipbar.removeChild(tipbar.lastChild);
- }
- }
-
- function show_tips() {
- tipbar.style.display = 'block';
- }
-
- var intip = false;
-
- function use_tip() {
- insert_text(get_text(this));
- clear_tips();
- intip = true;
- input.focus();
- }
-
- function dir() {
- var data = partial_line();
-
- clear_tips();
-
- var h = http();
- h.onreadystatechange = function() {
- if (h.readyState == 4) {
- try {
- var status = h.status;
- } catch(e) {
- var status = "NO HTTP RESPONSE";
- }
- switch (status) {
- case 200:
- var tips = eval(h.responseText);
- for (var i=0; i < tips.length; i++) {
- var tiplink = document.createElement("a");
- tiplink.onclick = use_tip;
- tiplink.href = "javascript:void(0)";
- set_text(tiplink, tips[i]);
- tipbar.appendChild(tiplink);
- tipbar.appendChild(document.createElement("br"));
- }
- show_tips()
- input.focus();
- break;
- // Internet Explorer might return 1223 for 204
- case 1223:
- case 204:
- // No tips available
- break;
- case 12029:
- // Internet Explorer client could not connect to server
- status = "NO HTTP RESPONSE";
- case 403:
- stdout_write("Interactive mode is disabled", false);
- break;
- default:
- stdout_write(status + "\n" + h.responseText, false);
- }
- }
- }
- h.open("GET", prefix + "dir?line=" + escape(data), true);
- h.send(null);
- }
-
- function doc() {
- var data = partial_line();
-
- clear_tips();
-
- var h = http();
- h.onreadystatechange = function() {
- if (h.readyState == 4) {
- try {
- var status = h.status;
- } catch(e) {
- var status = "NO HTTP RESPONSE";
- }
- switch (status) {
- case 200:
- tipbar.appendChild(document.createTextNode(h.responseText));
- show_tips();
- input.focus();
- break;
- // Internet Explorer might return 1223 for 204
- case 1223:
- case 403:
- stdout_write("Interactive mode is disabled", false);
- break;
- case 204:
- // No tips available
- break;
- case 12029:
- // Internet Explorer client could not connect to server
- status = "NO HTTP RESPONSE";
- default:
- stdout_write(status + "\n" + h.responseText, false);
- }
- }
- }
- h.open("GET", prefix + "doc?line=" + escape(data), true);
- h.send(null);
- }
-
- // COMMAND EXECUTION //
-
- function get_text(elem) {
- if (elem.innerText != undefined) {
- // Internet Explorer
- return elem.innerText;
- } else {
- // Mozilla
- return elem.textContent;
- }
- }
-
- function set_text(elem, newvalue) {
- if (elem.innerText != undefined) {
- // Internet Explorer
- elem.innerText = newvalue;
- } else {
- // Mozilla
- elem.textContent = newvalue;
- }
- }
-
- function get_prompt() {
- return get_text(prompt_);
- }
-
- function set_prompt(newvalue) {
- set_text(prompt_, newvalue);
- }
-
- function stdout_write(content, stdin) {
- current_history = undefined;
- if (content == "") return;
-
- var block = document.createElement("pre");
- block.ondblclick = history_hook;
- if (stdin) {
- content = get_prompt() + content;
- block.className = 'stdin';
- }
- if (block.innerText != undefined) {
- // Internet Explorer quirkiness
- block.innerText = content;
- } else {
- block.appendChild(document.createTextNode(content));
- }
- output.appendChild(block);
- }
-
- whitespace = /^\s+$/;
-
- function push() {
- var data = input.value;
- // Uncomment to treat a line with only whitespace like a blank line
- // if (whitespace.test(data)) data = "";
-
- input.value = "";
-
- var h = http();
- h.onreadystatechange = function() {
- if (h.readyState == 4) {
- stdout_write(data, true);
- try {
- var status = h.status;
- } catch(e) {
- var status = "NO HTTP RESPONSE";
- }
- switch (status) {
- case 200:
- set_prompt(">>> ");
- var response = h.responseText;
- if (!handle_widget_output(response)) {
- stdout_write(response, false);
- }
- break;
- // Internet Explorer might return 1223 for 204
- case 1223:
- case 204:
- set_prompt("... ");
- // input.value *should* be blank, but just in case...
- input.value = " " + input.value;
- break;
- case 403:
- stdout_write("Interactive mode is disabled", false);
- break;
- case 12029:
- // Internet Explorer client could not connect to server
- status = "NO HTTP RESPONSE";
- default:
- stdout_write(status + "\n" + h.responseText, false);
- }
- input.focus();
- }
- }
- h.open("POST", prefix + "push", true);
- h.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- h.send("line=" + escape(data));
- }
-
-
- function escape(data) {
- data = data.replace(/%/gi, "%25");
- data = data.replace(/&/gi, "%26");
- data = data.replace(/[+]/gi, "%2B");
- data = data.replace(/;/gi, "%3B");
- return data;
- }
-
-
- // SETUP //
-
- function mapKeys(key_code) {
- if (intip) {
- intip = false;
- // Trap the bubbling keyup event from a tiplink. This means that,
- // if you actually click a tiplink instead of tab and hit 'enter',
- // you have to hit 'enter' twice to push the line. :(
- if (key_code == 13) return;
- }
- switch(key_code) {
- case 8: // backspace
- clear_tips();
- break;
- case 13: // enter
- clear_tips();
- push();
- break;
- case 38: // up arrow
- prev_history();
- break;
- case 40: // down arrow
- next_history();
- break;
- case 48: // close paren "("
- clear_tips();
- break;
- case 57: // open paren "("
- doc();
- break;
- case 190: // period "."
- dir();
- break;
- }
- }
-
- function trapKeys(e) {
- if (!e) var e = window.event;
- mapKeys(e.keyCode);
- }
-
- // WIDGET DIALOGS //
-
- var new_id = (function make_counter(value) {
- var state = {value: value || 0};
- function next() {
- state.value ++;
- return 'widget-dialog-' + state.value;
- }
- return next;
- })();
-
- function open_dialog(config) {
- var c = $.extend({}, {height:450, width:600}, config);
- var iframe = $('<iframe><iframe>');
- iframe.attr({id: new_id(), 'class': 'widget-dialog'});
- function setSize(size) {
- var attr = {
- height: Math.max(0, Math.round(size.height-60)),
- width: Math.max(0, Math.round(size.width-40))
- }
- iframe.attr(attr);
- }
- function onResizeStart(event, data) {
- // Hide the iframe so it doesn't captute mouse events while dragging
- // the resize handlers
- iframe.hide();
- }
- function onResizeStop(event, data) {
- setSize(data.instance.size);
- iframe.show();
- }
- function onClose() {
- iframe.remove();
- input.focus();
- }
- iframe.appendTo(httprepl).dialog(config)
- .bind('dialogclose', onClose)
- .trigger('setData.dialog', ['resizeStart', onResizeStart])
- .trigger('setData.dialog', ['resizeStop', onResizeStop])
- .attr('src', config.url)
- .dialog('open');
- setSize(c);
- }
-
- var displayed_widget = /DeferredDisplay\((\d+)[^']*'([^']+)'/;
-
- function handle_widget_output(response) {
- var match = displayed_widget(response);
- if (match) {
- var config = {
- url: prefix + 'widget_output/' + match[1],
- height: 500,
- width: 750,
- title: match[2]
- }
- open_dialog(config);
- return true;
- }
- return false;
- }
- var httprepl = $(''
- +'<div class="httprepl">'
- + '<div class="output"></div>'
- + '<form action="" class="terminal">'
- + '<div class="tipbar"></div>'
- + '<nobr>'
- + '<span class="prompt">>>> </span>'
- + '<input type="text" class="input" size=60" />'
- + '</nobr>'
- + '</form>'
- +'</div>'
- );
- var prefix = '';
- var input = $('.input', httprepl)[0];
- input.onkeyup = trapKeys;
- var output = $('.output', httprepl)[0];
- var tipbar = $('.tipbar', httprepl)[0];
- var prompt_ = $('.prompt', httprepl)[0];
- $('form', httprepl).submit(function() { return false });
-
- return {
- render: function(el, config) {
- prefix = config.prefix || '';
- httprepl.appendTo($(el));
- }
- }
-})(jQuery);
diff --git a/moksha/widgetbrowser/static/jquery.js b/moksha/widgetbrowser/static/jquery.js
deleted file mode 100644
index ea64073..0000000
--- a/moksha/widgetbrowser/static/jquery.js
+++ /dev/null
@@ -1,3436 +0,0 @@
-(function(){
-/*
- * jQuery 1.2.4a - New Wave Javascript
- *
- * Copyright (c) 2008 John Resig (jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * $Date: 2008-04-08 13:40:03 -0300 (ter, 08 abr 2008) $
- * $Rev: 5214 $
- */
-
-// Map over jQuery in case of overwrite
-if ( window.jQuery )
- var _jQuery = window.jQuery;
-
-var jQuery = window.jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.prototype.init( selector, context );
-};
-
-// Map over the $ in case of overwrite
-if ( window.$ )
- var _$ = window.$;
-
-// Map the jQuery namespace to the '$' one
-window.$ = jQuery;
-
-// A simple way to check for HTML strings or ID strings
-// (both of which we optimize for)
-var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
-
-// Is it a simple selector
-var isSimple = /^.[^:#\[\.]*$/;
-
-jQuery.fn = jQuery.prototype = {
- init: function( selector, context ) {
- // Make sure that a selection was provided
- selector = selector || document;
-
- // Handle $(DOMElement)
- if ( selector.nodeType ) {
- this[0] = selector;
- this.length = 1;
- return this;
-
- // Handle HTML strings
- } else if ( typeof selector == "string" ) {
- // Are we dealing with HTML string or an ID?
- var match = quickExpr.exec( selector );
-
- // Verify a match, and that no context was specified for #id
- if ( match && (match[1] || !context) ) {
-
- // HANDLE: $(html) -> $(array)
- if ( match[1] )
- selector = jQuery.clean( [ match[1] ], context );
-
- // HANDLE: $("#id")
- else {
- var elem = document.getElementById( match[3] );
-
- // Make sure an element was located
- if ( elem )
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id != match[3] )
- return jQuery().find( selector );
-
- // Otherwise, we inject the element directly into the jQuery object
- else {
- this[0] = elem;
- this.length = 1;
- return this;
- }
-
- else
- selector = [];
- }
-
- // HANDLE: $(expr, [context])
- // (which is just equivalent to: $(content).find(expr)
- } else
- return new jQuery( context ).find( selector );
-
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) )
- return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
-
- return this.setArray(
- // HANDLE: $(array)
- selector.constructor == Array && selector ||
-
- // HANDLE: $(arraylike)
- // Watch for when an array-like object, contains DOM nodes, is passed in as the selector
- (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) ||
-
- // HANDLE: $(*)
- [ selector ] );
- },
-
- // The current version of jQuery being used
- jquery: "1.2.4a",
-
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
- // The number of elements contained in the matched element set
- length: 0,
-
- // Get the Nth element in the matched element set OR
- // Get the whole matched element set as a clean array
- get: function( num ) {
- return num == undefined ?
-
- // Return a 'clean' array
- jQuery.makeArray( this ) :
-
- // Return just the object
- this[ num ];
- },
-
- // Take an array of elements and push it onto the stack
- // (returning the new matched element set)
- pushStack: function( elems ) {
- // Build a new jQuery matched element set
- var ret = jQuery( elems );
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
-
- // Return the newly-formed element set
- return ret;
- },
-
- // Force the current matched set of elements to become
- // the specified array of elements (destroying the stack in the process)
- // You should use pushStack() in order to do this, but maintain the stack
- setArray: function( elems ) {
- // Resetting the length to 0, then using the native Array push
- // is a super-fast way to populate an object with array-like properties
- this.length = 0;
- Array.prototype.push.apply( this, elems );
-
- return this;
- },
-
- // Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
- },
-
- // Determine the position of an element within
- // the matched set of elements
- index: function( elem ) {
- var ret = -1;
-
- // Locate the position of the desired element
- this.each(function(i){
- if ( this == elem )
- ret = i;
- });
-
- return ret;
- },
-
- attr: function( name, value, type ) {
- var options = name;
-
- // Look for the case where we're accessing a style value
- if ( name.constructor == String )
- if ( value == undefined )
- return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined;
-
- else {
- options = {};
- options[ name ] = value;
- }
-
- // Check to see if we're setting style values
- return this.each(function(i){
- // Set all the styles
- for ( name in options )
- jQuery.attr(
- type ?
- this.style :
- this,
- name, jQuery.prop( this, options[ name ], type, i, name )
- );
- });
- },
-
- css: function( key, value ) {
- // ignore negative width and height values
- if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
- value = undefined;
- return this.attr( key, value, "curCSS" );
- },
-
- text: function( text ) {
- if ( typeof text != "object" && text != null )
- return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
-
- var ret = "";
-
- jQuery.each( text || this, function(){
- jQuery.each( this.childNodes, function(){
- if ( this.nodeType != 8 )
- ret += this.nodeType != 1 ?
- this.nodeValue :
- jQuery.fn.text( [ this ] );
- });
- });
-
- return ret;
- },
-
- wrapAll: function( html ) {
- if ( this[0] )
- // The elements to wrap the target around
- jQuery( html, this[0].ownerDocument )
- .clone()
- .insertBefore( this[0] )
- .map(function(){
- var elem = this;
-
- while ( elem.firstChild )
- elem = elem.firstChild;
-
- return elem;
- })
- .append(this);
-
- return this;
- },
-
- wrapInner: function( html ) {
- return this.each(function(){
- jQuery( this ).contents().wrapAll( html );
- });
- },
-
- wrap: function( html ) {
- return this.each(function(){
- jQuery( this ).wrapAll( html );
- });
- },
-
- append: function() {
- return this.domManip(arguments, true, false, function(elem){
- if (this.nodeType == 1)
- this.appendChild( elem );
- });
- },
-
- prepend: function() {
- return this.domManip(arguments, true, true, function(elem){
- if (this.nodeType == 1)
- this.insertBefore( elem, this.firstChild );
- });
- },
-
- before: function() {
- return this.domManip(arguments, false, false, function(elem){
- this.parentNode.insertBefore( elem, this );
- });
- },
-
- after: function() {
- return this.domManip(arguments, false, true, function(elem){
- this.parentNode.insertBefore( elem, this.nextSibling );
- });
- },
-
- end: function() {
- return this.prevObject || jQuery( [] );
- },
-
- find: function( selector ) {
- var elems = jQuery.map(this, function(elem){
- return jQuery.find( selector, elem );
- });
-
- return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
- jQuery.unique( elems ) :
- elems );
- },
-
- clone: function( events ) {
- // Do the clone
- var ret = this.map(function(){
- if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
- // IE copies events bound via attachEvent when
- // using cloneNode. Calling detachEvent on the
- // clone will also remove the events from the orignal
- // In order to get around this, we use innerHTML.
- // Unfortunately, this means some modifications to
- // attributes in IE that are actually only stored
- // as properties will not be copied (such as the
- // the name attribute on an input).
- var clone = this.cloneNode(true),
- container = document.createElement("div");
- container.appendChild(clone);
- return jQuery.clean([container.innerHTML])[0];
- } else
- return this.cloneNode(true);
- });
-
- // Need to set the expando to null on the cloned set if it exists
- // removeData doesn't work here, IE removes it from the original as well
- // this is primarily for IE but the data expando shouldn't be copied over in any browser
- var clone = ret.find("*").andSelf().each(function(){
- if ( this[ expando ] != undefined )
- this[ expando ] = null;
- });
-
- // Copy the events from the original to the clone
- if ( events === true )
- this.find("*").andSelf().each(function(i){
- if (this.nodeType == 3)
- return;
- var events = jQuery.data( this, "events" );
-
- for ( var type in events )
- for ( var handler in events[ type ] )
- jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
- });
-
- // Return the cloned set
- return ret;
- },
-
- filter: function( selector ) {
- return this.pushStack(
- jQuery.isFunction( selector ) &&
- jQuery.grep(this, function(elem, i){
- return selector.call( elem, i );
- }) ||
-
- jQuery.multiFilter( selector, this ) );
- },
-
- not: function( selector ) {
- if ( selector.constructor == String )
- // test special case where just one selector is passed in
- if ( isSimple.test( selector ) )
- return this.pushStack( jQuery.multiFilter( selector, this, true ) );
- else
- selector = jQuery.multiFilter( selector, this );
-
- var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
- return this.filter(function() {
- return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
- });
- },
-
- add: function( selector ) {
- return !selector ? this : this.pushStack( jQuery.merge(
- this.get(),
- selector.constructor == String ?
- jQuery( selector ).get() :
- selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ?
- selector : [selector] ) );
- },
-
- is: function( selector ) {
- return selector ?
- jQuery.multiFilter( selector, this ).length > 0 :
- false;
- },
-
- hasClass: function( selector ) {
- return this.is( "." + selector );
- },
-
- val: function( value ) {
- if ( value == undefined ) {
-
- if ( this.length ) {
- var elem = this[0];
-
- // We need to handle select boxes special
- if ( jQuery.nodeName( elem, "select" ) ) {
- var index = elem.selectedIndex,
- values = [],
- options = elem.options,
- one = elem.type == "select-one";
-
- // Nothing was selected
- if ( index < 0 )
- return null;
-
- // Loop through all the selected options
- for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
- var option = options[ i ];
-
- if ( option.selected ) {
- // Get the specifc value for the option
- value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
-
- // We don't need an array for one selects
- if ( one )
- return value;
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- return values;
-
- // Everything else, we just grab the value
- } else
- return (this[0].value || "").replace(/\r/g, "");
-
- }
-
- return undefined;
- }
-
- return this.each(function(){
- if ( this.nodeType != 1 )
- return;
-
- if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
- this.checked = (jQuery.inArray(this.value, value) >= 0 ||
- jQuery.inArray(this.name, value) >= 0);
-
- else if ( jQuery.nodeName( this, "select" ) ) {
- var values = value.constructor == Array ?
- value :
- [ value ];
-
- jQuery( "option", this ).each(function(){
- this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
- jQuery.inArray( this.text, values ) >= 0);
- });
-
- if ( !values.length )
- this.selectedIndex = -1;
-
- } else
- this.value = value;
- });
- },
-
- html: function( value ) {
- return value == undefined ?
- (this.length ?
- this[0].innerHTML :
- null) :
- this.empty().append( value );
- },
-
- replaceWith: function( value ) {
- return this.after( value ).remove();
- },
-
- eq: function( i ) {
- return this.slice( i, i + 1 );
- },
-
- slice: function() {
- return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function(elem, i){
- return callback.call( elem, i, elem );
- }));
- },
-
- andSelf: function() {
- return this.add( this.prevObject );
- },
-
- data: function( key, value ){
- var parts = key.split(".");
- parts[1] = parts[1] ? "." + parts[1] : "";
-
- if ( value == null ) {
- var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
- if ( data == undefined && this.length )
- data = jQuery.data( this[0], key );
-
- return data == null && parts[1] ?
- this.data( parts[0] ) :
- data;
- } else
- return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
- jQuery.data( this, key, value );
- });
- },
-
- removeData: function( key ){
- return this.each(function(){
- jQuery.removeData( this, key );
- });
- },
-
- domManip: function( args, table, reverse, callback ) {
- var clone = this.length > 1, elems;
-
- return this.each(function(){
- if ( !elems ) {
- elems = jQuery.clean( args, this.ownerDocument );
-
- if ( reverse )
- elems.reverse();
- }
-
- var obj = this;
-
- if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
- obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
-
- var scripts = jQuery( [] );
-
- jQuery.each(elems, function(){
- var elem = clone ?
- jQuery( this ).clone( true )[0] :
- this;
-
- // execute all scripts after the elements have been injected
- if ( jQuery.nodeName( elem, "script" ) ) {
- scripts = scripts.add( elem );
- } else {
- // Remove any inner scripts for later evaluation
- if ( elem.nodeType == 1 )
- scripts = scripts.add( jQuery( "script", elem ).remove() );
-
- // Inject the elements into the document
- callback.call( obj, elem );
- }
- });
-
- scripts.each( evalScript );
- });
- }
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.prototype.init.prototype = jQuery.prototype;
-
-function evalScript( i, elem ) {
- if ( elem.src )
- jQuery.ajax({
- url: elem.src,
- async: false,
- dataType: "script"
- });
-
- else
- jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
-
- if ( elem.parentNode )
- elem.parentNode.removeChild( elem );
-}
-
-jQuery.extend = jQuery.fn.extend = function() {
- // copy reference to target object
- var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
-
- // Handle a deep copy situation
- if ( target.constructor == Boolean ) {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
-
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target != "object" && typeof target != "function" )
- target = {};
-
- // extend jQuery itself if only one argument is passed
- if ( length == 1 ) {
- target = this;
- i = 0;
- }
-
- for ( ; i < length; i++ )
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null )
- // Extend the base object
- for ( var name in options ) {
- // Prevent never-ending loop
- if ( target === options[ name ] )
- continue;
-
- // Recurse if we're merging object values
- if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType )
- target[ name ] = jQuery.extend( deep, target[ name ], options[ name ] );
-
- // Don't bring in undefined values
- else if ( options[ name ] != undefined )
- target[ name ] = options[ name ];
-
- }
-
- // Return the modified object
- return target;
-};
-
-var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {};
-
-// exclude the following css properties to add px
-var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;
-
-jQuery.extend({
- noConflict: function( deep ) {
- window.$ = _$;
-
- if ( deep )
- window.jQuery = _jQuery;
-
- return jQuery;
- },
-
- // See test/unit/core.js for details concerning this function.
- isFunction: function( fn ) {
- return !!fn && typeof fn != "string" && !fn.nodeName &&
- fn.constructor != Array && /function/i.test( fn + "" );
- },
-
- // check if an element is in a (or is an) XML document
- isXMLDoc: function( elem ) {
- return elem.documentElement && !elem.body ||
- elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
- },
-
- // Evalulates a script in a global context
- globalEval: function( data ) {
- data = jQuery.trim( data );
-
- if ( data ) {
- // Inspired by code by Andrea Giammarchi
- // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom...
- var head = document.getElementsByTagName("head")[0] || document.documentElement,
- script = document.createElement("script");
-
- script.type = "text/javascript";
- if ( jQuery.browser.msie )
- script.text = data;
- else
- script.appendChild( document.createTextNode( data ) );
-
- head.appendChild( script );
- head.removeChild( script );
- }
- },
-
- nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
- },
-
- cache: {},
-
- data: function( elem, name, data ) {
- elem = elem == window ?
- windowData :
- elem;
-
- var id = elem[ expando ];
-
- // Compute a unique ID for the element
- if ( !id )
- id = elem[ expando ] = ++uuid;
-
- // Only generate the data cache if we're
- // trying to access or manipulate it
- if ( name && !jQuery.cache[ id ] )
- jQuery.cache[ id ] = {};
-
- // Prevent overriding the named cache with undefined values
- if ( data != undefined )
- jQuery.cache[ id ][ name ] = data;
-
- // Return the named cache data, or the ID for the element
- return name ?
- jQuery.cache[ id ][ name ] :
- id;
- },
-
- removeData: function( elem, name ) {
- elem = elem == window ?
- windowData :
- elem;
-
- var id = elem[ expando ];
-
- // If we want to remove a specific section of the element's data
- if ( name ) {
- if ( jQuery.cache[ id ] ) {
- // Remove the section of cache data
- delete jQuery.cache[ id ][ name ];
-
- // If we've removed all the data, remove the element's cache
- name = "";
-
- for ( name in jQuery.cache[ id ] )
- break;
-
- if ( !name )
- jQuery.removeData( elem );
- }
-
- // Otherwise, we want to remove all of the element's data
- } else {
- // Clean up the element expando
- try {
- delete elem[ expando ];
- } catch(e){
- // IE has trouble directly removing the expando
- // but it's ok with using removeAttribute
- if ( elem.removeAttribute )
- elem.removeAttribute( expando );
- }
-
- // Completely remove the data cache
- delete jQuery.cache[ id ];
- }
- },
-
- // args is for internal usage only
- each: function( object, callback, args ) {
- if ( args ) {
- if ( object.length == undefined ) {
- for ( var name in object )
- if ( callback.apply( object[ name ], args ) === false )
- break;
- } else
- for ( var i = 0, length = object.length; i < length; i++ )
- if ( callback.apply( object[ i ], args ) === false )
- break;
-
- // A special, fast, case for the most common use of each
- } else {
- if ( object.length == undefined ) {
- for ( var name in object )
- if ( callback.call( object[ name ], name, object[ name ] ) === false )
- break;
- } else
- for ( var i = 0, length = object.length, value = object[0];
- i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
- }
-
- return object;
- },
-
- prop: function( elem, value, type, i, name ) {
- // Handle executable functions
- if ( jQuery.isFunction( value ) )
- value = value.call( elem, i );
-
- // Handle passing in a number to a CSS property
- return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
- value + "px" :
- value;
- },
-
- className: {
- // internal only, use addClass("class")
- add: function( elem, classNames ) {
- jQuery.each((classNames || "").split(/\s+/), function(i, className){
- if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
- elem.className += (elem.className ? " " : "") + className;
- });
- },
-
- // internal only, use removeClass("class")
- remove: function( elem, classNames ) {
- if (elem.nodeType == 1)
- elem.className = classNames != undefined ?
- jQuery.grep(elem.className.split(/\s+/), function(className){
- return !jQuery.className.has( classNames, className );
- }).join(" ") :
- "";
- },
-
- // internal only, use is(".class")
- has: function( elem, className ) {
- return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
- }
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations
- swap: function( elem, options, callback ) {
- var old = {};
- // Remember the old values, and insert the new ones
- for ( var name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- callback.call( elem );
-
- // Revert the old values
- for ( var name in options )
- elem.style[ name ] = old[ name ];
- },
-
- css: function( elem, name, force ) {
- if ( name == "width" || name == "height" ) {
- var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
-
- function getWH() {
- val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
- var padding = 0, border = 0;
- jQuery.each( which, function() {
- padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
- border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
- });
- val -= Math.round(padding + border);
- }
-
- if ( jQuery(elem).is(":visible") )
- getWH();
- else
- jQuery.swap( elem, props, getWH );
-
- return Math.max(0, val);
- }
-
- return jQuery.curCSS( elem, name, force );
- },
-
- curCSS: function( elem, name, force ) {
- var ret;
-
- // A helper method for determining if an element's values are broken
- function color( elem ) {
- if ( !jQuery.browser.safari )
- return false;
-
- var ret = document.defaultView.getComputedStyle( elem, null );
- return !ret || ret.getPropertyValue("color") == "";
- }
-
- // We need to handle opacity special in IE
- if ( name == "opacity" && jQuery.browser.msie ) {
- ret = jQuery.attr( elem.style, "opacity" );
-
- return ret == "" ?
- "1" :
- ret;
- }
- // Opera sometimes will give the wrong display answer, this fixes it, see #2037
- if ( jQuery.browser.opera && name == "display" ) {
- var save = elem.style.outline;
- elem.style.outline = "0 solid black";
- elem.style.outline = save;
- }
-
- // Make sure we're using the right name for getting the float value
- if ( name.match( /float/i ) )
- name = styleFloat;
-
- if ( !force && elem.style && elem.style[ name ] )
- ret = elem.style[ name ];
-
- else if ( document.defaultView && document.defaultView.getComputedStyle ) {
-
- // Only "float" is needed here
- if ( name.match( /float/i ) )
- name = "float";
-
- name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
-
- var getComputedStyle = document.defaultView.getComputedStyle( elem, null );
-
- if ( getComputedStyle && !color( elem ) )
- ret = getComputedStyle.getPropertyValue( name );
-
- // If the element isn't reporting its values properly in Safari
- // then some display: none elements are involved
- else {
- var swap = [], stack = [];
-
- // Locate all of the parent display: none elements
- for ( var a = elem; a && color(a); a = a.parentNode )
- stack.unshift(a);
-
- // Go through and make them visible, but in reverse
- // (It would be better if we knew the exact display type that they had)
- for ( var i = 0; i < stack.length; i++ )
- if ( color( stack[ i ] ) ) {
- swap[ i ] = stack[ i ].style.display;
- stack[ i ].style.display = "block";
- }
-
- // Since we flip the display style, we have to handle that
- // one special, otherwise get the value
- ret = name == "display" && swap[ stack.length - 1 ] != null ?
- "none" :
- ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || "";
-
- // Finally, revert the display styles back
- for ( var i = 0; i < swap.length; i++ )
- if ( swap[ i ] != null )
- stack[ i ].style.display = swap[ i ];
- }
-
- // We should always get a number back from opacity
- if ( name == "opacity" && ret == "" )
- ret = "1";
-
- } else if ( elem.currentStyle ) {
- var camelCase = name.replace(/\-(\w)/g, function(all, letter){
- return letter.toUpperCase();
- });
-
- ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
-
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
- // Remember the original values
- var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left;
-
- // Put in the new values to get a computed value out
- elem.runtimeStyle.left = elem.currentStyle.left;
- elem.style.left = ret || 0;
- ret = elem.style.pixelLeft + "px";
-
- // Revert the changed values
- elem.style.left = style;
- elem.runtimeStyle.left = runtimeStyle;
- }
- }
-
- return ret;
- },
-
- clean: function( elems, context ) {
- var ret = [];
- context = context || document;
- // !context.createElement fails in IE with an error but returns typeof 'object'
- if (typeof context.createElement == 'undefined')
- context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
-
- jQuery.each(elems, function(i, elem){
- if ( !elem )
- return;
-
- if ( elem.constructor == Number )
- elem = elem.toString();
-
- // Convert html string into DOM nodes
- if ( typeof elem == "string" ) {
- // Fix "XHTML"-style tags in all browsers
- elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
- return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
- all :
- front + "></" + tag + ">";
- });
-
- // Trim whitespace, otherwise indexOf won't work as expected
- var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
-
- var wrap =
- // option or optgroup
- !tags.indexOf("<opt") &&
- [ 1, "<select multiple='multiple'>", "</select>" ] ||
-
- !tags.indexOf("<leg") &&
- [ 1, "<fieldset>", "</fieldset>" ] ||
-
- tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
- [ 1, "<table>", "</table>" ] ||
-
- !tags.indexOf("<tr") &&
- [ 2, "<table><tbody>", "</tbody></table>" ] ||
-
- // <thead> matched above
- (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
- [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
-
- !tags.indexOf("<col") &&
- [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
-
- // IE can't serialize <link> and <script> tags normally
- jQuery.browser.msie &&
- [ 1, "div<div>", "</div>" ] ||
-
- [ 0, "", "" ];
-
- // Go to html and back, then peel off extra wrappers
- div.innerHTML = wrap[1] + elem + wrap[2];
-
- // Move to the right depth
- while ( wrap[0]-- )
- div = div.lastChild;
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( jQuery.browser.msie ) {
-
- // String was a <table>, *may* have spurious <tbody>
- var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
- div.firstChild && div.firstChild.childNodes :
-
- // String was a bare <thead> or <tfoot>
- wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
- div.childNodes :
- [];
-
- for ( var j = tbody.length - 1; j >= 0 ; --j )
- if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
- tbody[ j ].parentNode.removeChild( tbody[ j ] );
-
- // IE completely kills leading whitespace when innerHTML is used
- if ( /^\s/.test( elem ) )
- div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
-
- }
-
- elem = jQuery.makeArray( div.childNodes );
- }
-
- if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
- return;
-
- if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
- ret.push( elem );
-
- else
- ret = jQuery.merge( ret, elem );
-
- });
-
- return ret;
- },
-
- attr: function( elem, name, value ) {
- // don't set attributes on text and comment nodes
- if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
- return undefined;
-
- var fix = jQuery.isXMLDoc( elem ) ?
- {} :
- jQuery.props;
-
- // Safari mis-reports the default selected property of a hidden option
- // Accessing the parent's selectedIndex property fixes it
- if ( name == "selected" && jQuery.browser.safari )
- elem.parentNode.selectedIndex;
-
- // Certain attributes only work when accessed via the old DOM 0 way
- if ( fix[ name ] ) {
- if ( value != undefined )
- elem[ fix[ name ] ] = value;
-
- return elem[ fix[ name ] ];
-
- } else if ( jQuery.browser.msie && name == "style" )
- return jQuery.attr( elem.style, "cssText", value );
-
- else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName( elem, "form" ) && (name == "action" || name == "method") )
- return elem.getAttributeNode( name ).nodeValue;
-
- // IE elem.getAttribute passes even for style
- else if ( elem.tagName ) {
-
- if ( value != undefined ) {
- // We can't allow the type property to be changed (since it causes problems in IE)
- if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
- throw "type property can't be changed";
-
- // convert the value to a string (all browsers do this but IE) see #1070
- elem.setAttribute( name, "" + value );
- }
-
- if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) )
- return elem.getAttribute( name, 2 );
-
- return elem.getAttribute( name );
-
- // elem is actually elem.style ... set the style
- } else {
- // IE actually uses filters for opacity
- if ( name == "opacity" && jQuery.browser.msie ) {
- if ( value != undefined ) {
- // IE has trouble with opacity if it does not have layout
- // Force it by setting the zoom level
- elem.zoom = 1;
-
- // Set the alpha filter to set the opacity
- elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
- (parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
- }
-
- return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
- (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() :
- "";
- }
-
- name = name.replace(/-([a-z])/ig, function(all, letter){
- return letter.toUpperCase();
- });
-
- if ( value != undefined )
- elem[ name ] = value;
-
- return elem[ name ];
- }
- },
-
- trim: function( text ) {
- return (text || "").replace( /^\s+|\s+$/g, "" );
- },
-
- makeArray: function( array ) {
- var ret = [];
-
- // Need to use typeof to fight Safari childNodes crashes
- if ( array.constructor != Array )
- for ( var i = 0, length = array.length; i < length; i++ )
- ret.push( array[ i ] );
- else
- ret = array.slice( 0 );
-
- return ret;
- },
-
- inArray: function( elem, array ) {
- for ( var i = 0, length = array.length; i < length; i++ )
- if ( array[ i ] == elem )
- return i;
-
- return -1;
- },
-
- merge: function( first, second ) {
- // We have to loop this way because IE & Opera overwrite the length
- // expando of getElementsByTagName
-
- // Also, we need to make sure that the correct elements are being returned
- // (IE returns comment nodes in a '*' query)
- if ( jQuery.browser.msie ) {
- for ( var i = 0; second[ i ]; i++ )
- if ( second[ i ].nodeType != 8 )
- first.push( second[ i ] );
-
- } else
- for ( var i = 0; second[ i ]; i++ )
- first.push( second[ i ] );
-
- return first;
- },
-
- unique: function( array ) {
- var ret = [], done = {};
-
- try {
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- var id = jQuery.data( array[ i ] );
-
- if ( !done[ id ] ) {
- done[ id ] = true;
- ret.push( array[ i ] );
- }
- }
-
- } catch( e ) {
- ret = array;
- }
-
- return ret;
- },
-
- grep: function( elems, callback, inv ) {
- var ret = [];
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( var i = 0, length = elems.length; i < length; i++ )
- if ( !inv && callback( elems[ i ], i ) || inv && !callback( elems[ i ], i ) )
- ret.push( elems[ i ] );
-
- return ret;
- },
-
- map: function( elems, callback ) {
- var ret = [];
-
- // Go through the array, translating each of the items to their
- // new value (or values).
- for ( var i = 0, length = elems.length; i < length; i++ ) {
- var value = callback( elems[ i ], i );
-
- if ( value !== null && value != undefined ) {
- if ( value.constructor != Array )
- value = [ value ];
-
- ret = ret.concat( value );
- }
- }
-
- return ret;
- }
-});
-
-var userAgent = navigator.userAgent.toLowerCase();
-
-// Figure out what browser is being used
-jQuery.browser = {
- version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
- safari: /webkit/.test( userAgent ),
- opera: /opera/.test( userAgent ),
- msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
- mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
-};
-
-var styleFloat = jQuery.browser.msie ?
- "styleFloat" :
- "cssFloat";
-
-jQuery.extend({
- // Check to see if the W3C box model is being used
- boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
-
- props: {
- "for": "htmlFor",
- "class": "className",
- "float": styleFloat,
- cssFloat: styleFloat,
- styleFloat: styleFloat,
- innerHTML: "innerHTML",
- className: "className",
- value: "value",
- disabled: "disabled",
- checked: "checked",
- readonly: "readOnly",
- selected: "selected",
- maxlength: "maxLength",
- selectedIndex: "selectedIndex",
- defaultValue: "defaultValue",
- tagName: "tagName",
- nodeName: "nodeName"
- }
-});
-
-jQuery.each({
- parent: function(elem){return elem.parentNode;},
- parents: function(elem){return jQuery.dir(elem,"parentNode");},
- next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
- prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
- nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
- prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
- siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
- children: function(elem){return jQuery.sibling(elem.firstChild);},
- contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
-}, function(name, fn){
- jQuery.fn[ name ] = function( selector ) {
- var ret = jQuery.map( this, fn );
-
- if ( selector && typeof selector == "string" )
- ret = jQuery.multiFilter( selector, ret );
-
- return this.pushStack( jQuery.unique( ret ) );
- };
-});
-
-jQuery.each({
- appendTo: "append",
- prependTo: "prepend",
- insertBefore: "before",
- insertAfter: "after",
- replaceAll: "replaceWith"
-}, function(name, original){
- jQuery.fn[ name ] = function() {
- var args = arguments;
-
- return this.each(function(){
- for ( var i = 0, length = args.length; i < length; i++ )
- jQuery( args[ i ] )[ original ]( this );
- });
- };
-});
-
-jQuery.each({
- removeAttr: function( name ) {
- jQuery.attr( this, name, "" );
- if (this.nodeType == 1)
- this.removeAttribute( name );
- },
-
- addClass: function( classNames ) {
- jQuery.className.add( this, classNames );
- },
-
- removeClass: function( classNames ) {
- jQuery.className.remove( this, classNames );
- },
-
- toggleClass: function( classNames ) {
- jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
- },
-
- remove: function( selector ) {
- if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
- // Prevent memory leaks
- jQuery( "*", this ).add(this).each(function(){
- jQuery.event.remove(this);
- jQuery.removeData(this);
- });
- if (this.parentNode)
- this.parentNode.removeChild( this );
- }
- },
-
- empty: function() {
- // Remove element nodes and prevent memory leaks
- jQuery( ">*", this ).remove();
-
- // Remove any remaining nodes
- while ( this.firstChild )
- this.removeChild( this.firstChild );
- }
-}, function(name, fn){
- jQuery.fn[ name ] = function(){
- return this.each( fn, arguments );
- };
-});
-
-jQuery.each([ "Height", "Width" ], function(i, name){
- var type = name.toLowerCase();
-
- jQuery.fn[ type ] = function( size ) {
- // Get window width or height
- return this[0] == window ?
- // Opera reports document.body.client[Width/Height] properly in both quirks and standards
- jQuery.browser.opera && document.body[ "client" + name ] ||
-
- // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
- jQuery.browser.safari && window[ "inner" + name ] ||
-
- // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
- document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
-
- // Get document width or height
- this[0] == document ?
- // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
- Math.max(
- Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
- Math.max(document.body["offset" + name], document.documentElement["offset" + name])
- ) :
-
- // Get or set width or height on the element
- size == undefined ?
- // Get width or height on the element
- (this.length ? jQuery.css( this[0], type ) : null) :
-
- // Set the width or height on the element (default to pixels if value is unitless)
- this.css( type, size.constructor == String ? size : size + "px" );
- };
-});
-
-var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
- "(?:[\\w*_-]|\\\\.)" :
- "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
- quickChild = new RegExp("^>\\s*(" + chars + "+)"),
- quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
- quickClass = new RegExp("^([#.]?)(" + chars + "*)");
-
-jQuery.extend({
- expr: {
- "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
- "#": function(a,i,m){return a.getAttribute("id")==m[2];},
- ":": {
- // Position Checks
- lt: function(a,i,m){return i<m[3]-0;},
- gt: function(a,i,m){return i>m[3]-0;},
- nth: function(a,i,m){return m[3]-0==i;},
- eq: function(a,i,m){return m[3]-0==i;},
- first: function(a,i){return i==0;},
- last: function(a,i,m,r){return i==r.length-1;},
- even: function(a,i){return i%2==0;},
- odd: function(a,i){return i%2;},
-
- // Child Checks
- "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
- "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
- "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
-
- // Parent Checks
- parent: function(a){return a.firstChild;},
- empty: function(a){return !a.firstChild;},
-
- // Text Check
- contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
-
- // Visibility
- visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
- hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
-
- // Form attributes
- enabled: function(a){return !a.disabled;},
- disabled: function(a){return a.disabled;},
- checked: function(a){return a.checked;},
- selected: function(a){return a.selected||jQuery.attr(a,"selected");},
-
- // Form elements
- text: function(a){return "text"==a.type;},
- radio: function(a){return "radio"==a.type;},
- checkbox: function(a){return "checkbox"==a.type;},
- file: function(a){return "file"==a.type;},
- password: function(a){return "password"==a.type;},
- submit: function(a){return "submit"==a.type;},
- image: function(a){return "image"==a.type;},
- reset: function(a){return "reset"==a.type;},
- button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
- input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
-
- // :has()
- has: function(a,i,m){return jQuery.find(m[3],a).length;},
-
- // :header
- header: function(a){return /h\d/i.test(a.nodeName);},
-
- // :animated
- animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
- }
- },
-
- // The regular expressions that power the parsing engine
- parse: [
- // Match: [@value='test'], [@foo]
- /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
-
- // Match: :contains('foo')
- /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
-
- // Match: :even, :last-chlid, #id, .class
- new RegExp("^([:.#]*)(" + chars + "+)")
- ],
-
- multiFilter: function( expr, elems, not ) {
- var old, cur = [];
-
- while ( expr && expr != old ) {
- old = expr;
- var f = jQuery.filter( expr, elems, not );
- expr = f.t.replace(/^\s*,\s*/, "" );
- cur = not ? elems = f.r : jQuery.merge( cur, f.r );
- }
-
- return cur;
- },
-
- find: function( t, context ) {
- // Quickly handle non-string expressions
- if ( typeof t != "string" )
- return [ t ];
-
- // check to make sure context is a DOM element or a document
- if ( context && context.nodeType != 1 && context.nodeType != 9)
- return [ ];
-
- // Set the correct context (if none is provided)
- context = context || document;
-
- // Initialize the search
- var ret = [context], done = [], last, nodeName;
-
- // Continue while a selector expression exists, and while
- // we're no longer looping upon ourselves
- while ( t && last != t ) {
- var r = [];
- last = t;
-
- t = jQuery.trim(t);
-
- var foundToken = false;
-
- // An attempt at speeding up child selectors that
- // point to a specific element tag
- var re = quickChild;
- var m = re.exec(t);
-
- if ( m ) {
- nodeName = m[1].toUpperCase();
-
- // Perform our own iteration and filter
- for ( var i = 0; ret[i]; i++ )
- for ( var c = ret[i].firstChild; c; c = c.nextSibling )
- if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
- r.push( c );
-
- ret = r;
- t = t.replace( re, "" );
- if ( t.indexOf(" ") == 0 ) continue;
- foundToken = true;
- } else {
- re = /^([>+~])\s*(\w*)/i;
-
- if ( (m = re.exec(t)) != null ) {
- r = [];
-
- var merge = {};
- nodeName = m[2].toUpperCase();
- m = m[1];
-
- for ( var j = 0, rl = ret.length; j < rl; j++ ) {
- var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
- for ( ; n; n = n.nextSibling )
- if ( n.nodeType == 1 ) {
- var id = jQuery.data(n);
-
- if ( m == "~" && merge[id] ) break;
-
- if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
- if ( m == "~" ) merge[id] = true;
- r.push( n );
- }
-
- if ( m == "+" ) break;
- }
- }
-
- ret = r;
-
- // And remove the token
- t = jQuery.trim( t.replace( re, "" ) );
- foundToken = true;
- }
- }
-
- // See if there's still an expression, and that we haven't already
- // matched a token
- if ( t && !foundToken ) {
- // Handle multiple expressions
- if ( !t.indexOf(",") ) {
- // Clean the result set
- if ( context == ret[0] ) ret.shift();
-
- // Merge the result sets
- done = jQuery.merge( done, ret );
-
- // Reset the context
- r = ret = [context];
-
- // Touch up the selector string
- t = " " + t.substr(1,t.length);
-
- } else {
- // Optimize for the case nodeName#idName
- var re2 = quickID;
- var m = re2.exec(t);
-
- // Re-organize the results, so that they're consistent
- if ( m ) {
- m = [ 0, m[2], m[3], m[1] ];
-
- } else {
- // Otherwise, do a traditional filter check for
- // ID, class, and element selectors
- re2 = quickClass;
- m = re2.exec(t);
- }
-
- m[2] = m[2].replace(/\\/g, "");
-
- var elem = ret[ret.length-1];
-
- // Try to do a global search by ID, where we can
- if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
- // Optimization for HTML document case
- var oid = elem.getElementById(m[2]);
-
- // Do a quick check for the existence of the actual ID attribute
- // to avoid selecting by the name attribute in IE
- // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
- if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
- oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
-
- // Do a quick check for node name (where applicable) so
- // that div#foo searches will be really fast
- ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
- } else {
- // We need to find all descendant elements
- for ( var i = 0; ret[i]; i++ ) {
- // Grab the tag name being searched for
- var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
-
- // Handle IE7 being really dumb about <object>s
- if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
- tag = "param";
-
- r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
- }
-
- // It's faster to filter by class and be done with it
- if ( m[1] == "." )
- r = jQuery.classFilter( r, m[2] );
-
- // Same with ID filtering
- if ( m[1] == "#" ) {
- var tmp = [];
-
- // Try to find the element with the ID
- for ( var i = 0; r[i]; i++ )
- if ( r[i].getAttribute("id") == m[2] ) {
- tmp = [ r[i] ];
- break;
- }
-
- r = tmp;
- }
-
- ret = r;
- }
-
- t = t.replace( re2, "" );
- }
-
- }
-
- // If a selector string still exists
- if ( t ) {
- // Attempt to filter it
- var val = jQuery.filter(t,r);
- ret = r = val.r;
- t = jQuery.trim(val.t);
- }
- }
-
- // An error occurred with the selector;
- // just return an empty set instead
- if ( t )
- ret = [];
-
- // Remove the root context
- if ( ret && context == ret[0] )
- ret.shift();
-
- // And combine the results
- done = jQuery.merge( done, ret );
-
- return done;
- },
-
- classFilter: function(r,m,not){
- m = " " + m + " ";
- var tmp = [];
- for ( var i = 0; r[i]; i++ ) {
- var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
- if ( !not && pass || not && !pass )
- tmp.push( r[i] );
- }
- return tmp;
- },
-
- filter: function(t,r,not) {
- var last;
-
- // Look for common filter expressions
- while ( t && t != last ) {
- last = t;
-
- var p = jQuery.parse, m;
-
- for ( var i = 0; p[i]; i++ ) {
- m = p[i].exec( t );
-
- if ( m ) {
- // Remove what we just matched
- t = t.substring( m[0].length );
-
- m[2] = m[2].replace(/\\/g, "");
- break;
- }
- }
-
- if ( !m )
- break;
-
- // :not() is a special case that can be optimized by
- // keeping it out of the expression list
- if ( m[1] == ":" && m[2] == "not" )
- // optimize if only one selector found (most common case)
- r = isSimple.test( m[3] ) ?
- jQuery.filter(m[3], r, true).r :
- jQuery( r ).not( m[3] );
-
- // We can get a big speed boost by filtering by class here
- else if ( m[1] == "." )
- r = jQuery.classFilter(r, m[2], not);
-
- else if ( m[1] == "[" ) {
- var tmp = [], type = m[3];
-
- for ( var i = 0, rl = r.length; i < rl; i++ ) {
- var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
-
- if ( z == null || /href|src|selected/.test(m[2]) )
- z = jQuery.attr(a,m[2]) || '';
-
- if ( (type == "" && !!z ||
- type == "=" && z == m[5] ||
- type == "!=" && z != m[5] ||
- type == "^=" && z && !z.indexOf(m[5]) ||
- type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
- (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
- tmp.push( a );
- }
-
- r = tmp;
-
- // We can get a speed boost by handling nth-child here
- } else if ( m[1] == ":" && m[2] == "nth-child" ) {
- var merge = {}, tmp = [],
- // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
- test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
- m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
- !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
- // calculate the numbers (first)n+(last) including if they are negative
- first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
-
- // loop through all the elements left in the jQuery object
- for ( var i = 0, rl = r.length; i < rl; i++ ) {
- var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
-
- if ( !merge[id] ) {
- var c = 1;
-
- for ( var n = parentNode.firstChild; n; n = n.nextSibling )
- if ( n.nodeType == 1 )
- n.nodeIndex = c++;
-
- merge[id] = true;
- }
-
- var add = false;
-
- if ( first == 0 ) {
- if ( node.nodeIndex == last )
- add = true;
- } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
- add = true;
-
- if ( add ^ not )
- tmp.push( node );
- }
-
- r = tmp;
-
- // Otherwise, find the expression to execute
- } else {
- var fn = jQuery.expr[ m[1] ];
- if ( typeof fn == "object" )
- fn = fn[ m[2] ];
-
- if ( typeof fn == "string" )
- fn = eval("false||function(a,i){return " + fn + ";}");
-
- // Execute it against the current filter
- r = jQuery.grep( r, function(elem, i){
- return fn(elem, i, m, r);
- }, not );
- }
- }
-
- // Return an array of filtered elements (r)
- // and the modified expression string (t)
- return { r: r, t: t };
- },
-
- dir: function( elem, dir ){
- var matched = [];
- var cur = elem[dir];
- while ( cur && cur != document ) {
- if ( cur.nodeType == 1 )
- matched.push( cur );
- cur = cur[dir];
- }
- return matched;
- },
-
- nth: function(cur,result,dir,elem){
- result = result || 1;
- var num = 0;
-
- for ( ; cur; cur = cur[dir] )
- if ( cur.nodeType == 1 && ++num == result )
- break;
-
- return cur;
- },
-
- sibling: function( n, elem ) {
- var r = [];
-
- for ( ; n; n = n.nextSibling ) {
- if ( n.nodeType == 1 && (!elem || n != elem) )
- r.push( n );
- }
-
- return r;
- }
-});
-
-/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code orignated from
- * Dean Edwards' addEvent library.
- */
-jQuery.event = {
-
- // Bind an event to an element
- // Original by Dean Edwards
- add: function(elem, types, handler, data) {
- if ( elem.nodeType == 3 || elem.nodeType == 8 )
- return;
-
- // For whatever reason, IE has trouble passing the window object
- // around, causing it to be cloned in the process
- if ( jQuery.browser.msie && elem.setInterval != undefined )
- elem = window;
-
- // Make sure that the function being executed has a unique ID
- if ( !handler.guid )
- handler.guid = this.guid++;
-
- // if data is passed, bind to handler
- if( data != undefined ) {
- // Create temporary function pointer to original handler
- var fn = handler;
-
- // Create unique handler function, wrapped around original handler
- handler = function() {
- // Pass arguments and context to original handler
- return fn.apply(this, arguments);
- };
-
- // Store data in unique handler
- handler.data = data;
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- handler.guid = fn.guid;
- }
-
- // Init the element's event structure
- var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
- handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
- // returned undefined or false
- var val;
-
- // Handle the second event of a trigger and when
- // an event is called after a page has unloaded
- if ( typeof jQuery == "undefined" || jQuery.event.triggered )
- return val;
-
- val = jQuery.event.handle.apply(arguments.callee.elem, arguments);
-
- return val;
- });
- // Add elem as a property of the handle function
- // This is to prevent a memory leak with non-native
- // event in IE.
- handle.elem = elem;
-
- // Handle multiple events seperated by a space
- // jQuery(...).bind("mouseover mouseout", fn);
- jQuery.each(types.split(/\s+/), function(index, type) {
- // Namespaced event handlers
- var parts = type.split(".");
- type = parts[0];
- handler.type = parts[1];
-
- // Get the current list of functions bound to this event
- var handlers = events[type];
-
- // Init the event handler queue
- if (!handlers) {
- handlers = events[type] = {};
-
- // Check for a special event handler
- // Only use addEventListener/attachEvent if the special
- // events handler returns false
- if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
- // Bind the global event handler to the element
- if (elem.addEventListener)
- elem.addEventListener(type, handle, false);
- else if (elem.attachEvent)
- elem.attachEvent("on" + type, handle);
- }
- }
-
- // Add the function to the element's handler list
- handlers[handler.guid] = handler;
-
- // Keep track of which events have been used, for global triggering
- jQuery.event.global[type] = true;
- });
-
- // Nullify elem to prevent memory leaks in IE
- elem = null;
- },
-
- guid: 1,
- global: {},
-
- // Detach an event or set of events from an element
- remove: function(elem, types, handler) {
- // don't do events on text and comment nodes
- if ( elem.nodeType == 3 || elem.nodeType == 8 )
- return;
-
- var events = jQuery.data(elem, "events"), ret, index;
-
- if ( events ) {
- // Unbind all events for the element
- if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
- for ( var type in events )
- this.remove( elem, type + (types || "") );
- else {
- // types is actually an event object here
- if ( types.type ) {
- handler = types.handler;
- types = types.type;
- }
-
- // Handle multiple events seperated by a space
- // jQuery(...).unbind("mouseover mouseout", fn);
- jQuery.each(types.split(/\s+/), function(index, type){
- // Namespaced event handlers
- var parts = type.split(".");
- type = parts[0];
-
- if ( events[type] ) {
- // remove the given handler for the given type
- if ( handler )
- delete events[type][handler.guid];
-
- // remove all handlers for the given type
- else
- for ( handler in events[type] )
- // Handle the removal of namespaced events
- if ( !parts[1] || events[type][handler].type == parts[1] )
- delete events[type][handler];
-
- // remove generic event handler if no more handlers exist
- for ( ret in events[type] ) break;
- if ( !ret ) {
- if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
- if (elem.removeEventListener)
- elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
- else if (elem.detachEvent)
- elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
- }
- ret = null;
- delete events[type];
- }
- }
- });
- }
-
- // Remove the expando if it's no longer used
- for ( ret in events ) break;
- if ( !ret ) {
- var handle = jQuery.data( elem, "handle" );
- if ( handle ) handle.elem = null;
- jQuery.removeData( elem, "events" );
- jQuery.removeData( elem, "handle" );
- }
- }
- },
-
- trigger: function(type, data, elem, donative, extra) {
- // Clone the incoming data, if any
- data = jQuery.makeArray(data || []);
-
- if ( type.indexOf("!") >= 0 ) {
- type = type.slice(0, -1);
- var exclusive = true;
- }
-
- // Handle a global trigger
- if ( !elem ) {
- // Only trigger if we've ever bound an event for it
- if ( this.global[type] )
- jQuery("*").add([window, document]).trigger(type, data);
-
- // Handle triggering a single element
- } else {
- // don't do events on text and comment nodes
- if ( elem.nodeType == 3 || elem.nodeType == 8 )
- return undefined;
-
- var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
- // Check to see if we need to provide a fake event, or not
- event = !data[0] || !data[0].preventDefault;
-
- // Pass along a fake event
- if ( event )
- data.unshift( this.fix({ type: type, target: elem }) );
-
- // Enforce the right trigger type
- data[0].type = type;
- if ( exclusive )
- data[0].exclusive = true;
-
- // Trigger the event
- if ( jQuery.isFunction( jQuery.data(elem, "handle") ) )
- val = jQuery.data(elem, "handle").apply( elem, data );
-
- // Handle triggering native .onfoo handlers
- if ( !fn && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
- val = false;
-
- // Extra functions don't get the custom event object
- if ( event )
- data.shift();
-
- // Handle triggering of extra function
- if ( extra && jQuery.isFunction( extra ) ) {
- // call the extra function and tack the current return value on the end for possible inspection
- ret = extra.apply( elem, val == null ? data : data.concat( val ) );
- // if anything is returned, give it precedence and have it overwrite the previous value
- if (ret !== undefined)
- val = ret;
- }
-
- // Trigger the native events (except for clicks on links)
- if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
- this.triggered = true;
- try {
- elem[ type ]();
- // prevent IE from throwing an error for some hidden elements
- } catch (e) {}
- }
-
- this.triggered = false;
- }
-
- return val;
- },
-
- handle: function(event) {
- // returned undefined or false
- var val;
-
- // Empty object is for triggered events with no data
- event = jQuery.event.fix( event || window.event || {} );
-
- // Namespaced event handlers
- var parts = event.type.split(".");
- event.type = parts[0];
-
- var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
- args.unshift( event );
-
- for ( var j in handlers ) {
- var handler = handlers[j];
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- args[0].handler = handler;
- args[0].data = handler.data;
-
- // Filter the functions by class
- if ( !parts[1] && !event.exclusive || handler.type == parts[1] ) {
- var ret = handler.apply( this, args );
-
- if ( val !== false )
- val = ret;
-
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
-
- // Clean up added properties in IE to prevent memory leak
- if (jQuery.browser.msie)
- event.target = event.preventDefault = event.stopPropagation =
- event.handler = event.data = null;
-
- return val;
- },
-
- fix: function(event) {
- // store a copy of the original event object
- // and clone to set read-only properties
- var originalEvent = event;
- event = jQuery.extend({}, originalEvent);
-
- // add preventDefault and stopPropagation since
- // they will not work on the clone
- event.preventDefault = function() {
- // if preventDefault exists run it on the original event
- if (originalEvent.preventDefault)
- originalEvent.preventDefault();
- // otherwise set the returnValue property of the original event to false (IE)
- originalEvent.returnValue = false;
- };
- event.stopPropagation = function() {
- // if stopPropagation exists run it on the original event
- if (originalEvent.stopPropagation)
- originalEvent.stopPropagation();
- // otherwise set the cancelBubble property of the original event to true (IE)
- originalEvent.cancelBubble = true;
- };
-
- // Fix target property, if necessary
- if ( !event.target )
- event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
-
- // check if target is a textnode (safari)
- if ( event.target.nodeType == 3 )
- event.target = originalEvent.target.parentNode;
-
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && event.fromElement )
- event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && event.clientX != null ) {
- var doc = document.documentElement, body = document.body;
- event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
- event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
- }
-
- // Add which for key events
- if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
- event.which = event.charCode || event.keyCode;
-
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if ( !event.metaKey && event.ctrlKey )
- event.metaKey = event.ctrlKey;
-
- // Add which for click: 1 == left; 2 == middle; 3 == right
- // Note: button is not normalized, so don't use it
- if ( !event.which && event.button )
- event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
-
- return event;
- },
-
- special: {
- ready: {
- setup: function() {
- // Make sure the ready event is setup
- bindReady();
- return;
- },
-
- teardown: function() { return; }
- },
-
- mouseenter: {
- setup: function() {
- if ( jQuery.browser.msie ) return false;
- jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
- return true;
- },
-
- teardown: function() {
- if ( jQuery.browser.msie ) return false;
- jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
- return true;
- },
-
- handler: function(event) {
- // If we actually just moused on to a sub-element, ignore it
- if ( withinElement(event, this) ) return true;
- // Execute the right handlers by setting the event type to mouseenter
- arguments[0].type = "mouseenter";
- return jQuery.event.handle.apply(this, arguments);
- }
- },
-
- mouseleave: {
- setup: function() {
- if ( jQuery.browser.msie ) return false;
- jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
- return true;
- },
-
- teardown: function() {
- if ( jQuery.browser.msie ) return false;
- jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
- return true;
- },
-
- handler: function(event) {
- // If we actually just moused on to a sub-element, ignore it
- if ( withinElement(event, this) ) return true;
- // Execute the right handlers by setting the event type to mouseleave
- arguments[0].type = "mouseleave";
- return jQuery.event.handle.apply(this, arguments);
- }
- }
- }
-};
-
-jQuery.fn.extend({
- bind: function( type, data, fn ) {
- return type == "unload" ? this.one(type, data, fn) : this.each(function(){
- jQuery.event.add( this, type, fn || data, fn && data );
- });
- },
-
- one: function( type, data, fn ) {
- return this.each(function(){
- jQuery.event.add( this, type, function(event) {
- jQuery(this).unbind(event);
- return (fn || data).apply( this, arguments);
- }, fn && data);
- });
- },
-
- unbind: function( type, fn ) {
- return this.each(function(){
- jQuery.event.remove( this, type, fn );
- });
- },
-
- trigger: function( type, data, fn ) {
- return this.each(function(){
- jQuery.event.trigger( type, data, this, true, fn );
- });
- },
-
- triggerHandler: function( type, data, fn ) {
- if ( this[0] )
- return jQuery.event.trigger( type, data, this[0], false, fn );
- return undefined;
- },
-
- toggle: function() {
- // Save reference to arguments for access in closure
- var args = arguments;
-
- return this.click(function(event) {
- // Figure out which function to execute
- this.lastToggle = 0 == this.lastToggle ? 1 : 0;
-
- // Make sure that clicks stop
- event.preventDefault();
-
- // and execute the function
- return args[this.lastToggle].apply( this, arguments ) || false;
- });
- },
-
- hover: function(fnOver, fnOut) {
- return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
- },
-
- ready: function(fn) {
- // Attach the listeners
- bindReady();
-
- // If the DOM is already ready
- if ( jQuery.isReady )
- // Execute the function immediately
- fn.call( document, jQuery );
-
- // Otherwise, remember the function for later
- else
- // Add the function to the wait list
- jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
-
- return this;
- }
-});
-
-jQuery.extend({
- isReady: false,
- readyList: [],
- // Handle when the DOM is ready
- ready: function() {
- // Make sure that the DOM is not already loaded
- if ( !jQuery.isReady ) {
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If there are functions bound, to execute
- if ( jQuery.readyList ) {
- // Execute all of them
- jQuery.each( jQuery.readyList, function(){
- this.apply( document );
- });
-
- // Reset the list of functions
- jQuery.readyList = null;
- }
-
- // Trigger any bound ready events
- jQuery(document).triggerHandler("ready");
- }
- }
-});
-
-var readyBound = false;
-
-function bindReady(){
- if ( readyBound ) return;
- readyBound = true;
-
- // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
- if ( document.addEventListener && !jQuery.browser.opera)
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
-
- // If IE is used and is not in a frame
- // Continually check to see if the document is ready
- if ( jQuery.browser.msie && window == top ) (function(){
- if (jQuery.isReady) return;
- try {
- // If IE is used, use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- document.documentElement.doScroll("left");
- } catch( error ) {
- setTimeout( arguments.callee, 0 );
- return;
- }
- // and execute any waiting functions
- jQuery.ready();
- })();
-
- if ( jQuery.browser.opera )
- document.addEventListener( "DOMContentLoaded", function () {
- if (jQuery.isReady) return;
- for (var i = 0; i < document.styleSheets.length; i++)
- if (document.styleSheets[i].disabled) {
- setTimeout( arguments.callee, 0 );
- return;
- }
- // and execute any waiting functions
- jQuery.ready();
- }, false);
-
- if ( jQuery.browser.safari ) {
- var numStyles;
- (function(){
- if (jQuery.isReady) return;
- if ( document.readyState != "loaded" && document.readyState != "complete" ) {
- setTimeout( arguments.callee, 0 );
- return;
- }
- if ( numStyles === undefined )
- numStyles = jQuery("style, link[rel=stylesheet]").length;
- if ( document.styleSheets.length != numStyles ) {
- setTimeout( arguments.callee, 0 );
- return;
- }
- // and execute any waiting functions
- jQuery.ready();
- })();
- }
-
- // A fallback to window.onload, that will always work
- jQuery.event.add( window, "load", jQuery.ready );
-}
-
-jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
- "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
- "submit,keydown,keypress,keyup,error").split(","), function(i, name){
-
- // Handle event binding
- jQuery.fn[name] = function(fn){
- return fn ? this.bind(name, fn) : this.trigger(name);
- };
-});
-
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function(event, elem) {
- // Check if mouse(over|out) are still within the same parent element
- var parent = event.relatedTarget;
- // Traverse up the tree
- while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
- // Return true if we actually just moused on to a sub-element
- return parent == elem;
-};
-
-// Prevent memory leaks in IE
-// And prevent errors on refresh with events like mouseover in other browsers
-// Window isn't included so as not to unbind existing unload events
-jQuery(window).bind("unload", function() {
- jQuery("*").add(document).unbind();
-});
-jQuery.fn.extend({
- load: function( url, params, callback ) {
- if ( jQuery.isFunction( url ) )
- return this.bind("load", url);
-
- var off = url.indexOf(" ");
- if ( off >= 0 ) {
- var selector = url.slice(off, url.length);
- url = url.slice(0, off);
- }
-
- callback = callback || function(){};
-
- // Default to a GET request
- var type = "GET";
-
- // If the second parameter was provided
- if ( params )
- // If it's a function
- if ( jQuery.isFunction( params ) ) {
- // We assume that it's the callback
- callback = params;
- params = null;
-
- // Otherwise, build a param string
- } else {
- params = jQuery.param( params );
- type = "POST";
- }
-
- var self = this;
-
- // Request the remote document
- jQuery.ajax({
- url: url,
- type: type,
- dataType: "html",
- data: params,
- complete: function(res, status){
- // If successful, inject the HTML into all the matched elements
- if ( status == "success" || status == "notmodified" )
- // See if a selector was specified
- self.html( selector ?
- // Create a dummy div to hold the results
- jQuery("<div/>")
- // inject the contents of the document in, removing the scripts
- // to avoid any 'Permission Denied' errors in IE
- .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
-
- // Locate the specified elements
- .find(selector) :
-
- // If not, just inject the full result
- res.responseText );
-
- self.each( callback, [res.responseText, status, res] );
- }
- });
- return this;
- },
-
- serialize: function() {
- return jQuery.param(this.serializeArray());
- },
- serializeArray: function() {
- return this.map(function(){
- return jQuery.nodeName(this, "form") ?
- jQuery.makeArray(this.elements) : this;
- })
- .filter(function(){
- return this.name && !this.disabled &&
- (this.checked || /select|textarea/i.test(this.nodeName) ||
- /text|hidden|password/i.test(this.type));
- })
- .map(function(i, elem){
- var val = jQuery(this).val();
- return val == null ? null :
- val.constructor == Array ?
- jQuery.map( val, function(val, i){
- return {name: elem.name, value: val};
- }) :
- {name: elem.name, value: val};
- }).get();
- }
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
- jQuery.fn[o] = function(f){
- return this.bind(o, f);
- };
-});
-
-var jsc = (new Date).getTime();
-
-jQuery.extend({
- get: function( url, data, callback, type ) {
- // shift arguments if data argument was ommited
- if ( jQuery.isFunction( data ) ) {
- callback = data;
- data = null;
- }
-
- return jQuery.ajax({
- type: "GET",
- url: url,
- data: data,
- success: callback,
- dataType: type
- });
- },
-
- getScript: function( url, callback ) {
- return jQuery.get(url, null, callback, "script");
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get(url, data, callback, "json");
- },
-
- post: function( url, data, callback, type ) {
- if ( jQuery.isFunction( data ) ) {
- callback = data;
- data = {};
- }
-
- return jQuery.ajax({
- type: "POST",
- url: url,
- data: data,
- success: callback,
- dataType: type
- });
- },
-
- ajaxSetup: function( settings ) {
- jQuery.extend( jQuery.ajaxSettings, settings );
- },
-
- ajaxSettings: {
- global: true,
- type: "GET",
- timeout: 0,
- contentType: "application/x-www-form-urlencoded",
- processData: true,
- async: true,
- data: null,
- username: null,
- password: null,
- accepts: {
- xml: "application/xml, text/xml",
- html: "text/html",
- script: "text/javascript, application/javascript",
- json: "application/json, text/javascript",
- text: "text/plain",
- _default: "*/*"
- }
- },
-
- // Last-Modified header cache for next request
- lastModified: {},
-
- ajax: function( s ) {
- var jsonp, jsre = /=\?(&|$)/g, status, data;
-
- // Extend the settings, but re-extend 's' so that it can be
- // checked again later (in the test suite, specifically)
- s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
-
- // convert data if not already a string
- if ( s.data && s.processData && typeof s.data != "string" )
- s.data = jQuery.param(s.data);
-
- // Handle JSONP Parameter Callbacks
- if ( s.dataType == "jsonp" ) {
- if ( s.type.toLowerCase() == "get" ) {
- if ( !s.url.match(jsre) )
- s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
- } else if ( !s.data || !s.data.match(jsre) )
- s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
- s.dataType = "json";
- }
-
- // Build temporary JSONP function
- if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
- jsonp = "jsonp" + jsc++;
-
- // Replace the =? sequence both in the query string and the data
- if ( s.data )
- s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
- s.url = s.url.replace(jsre, "=" + jsonp + "$1");
-
- // We need to make sure
- // that a JSONP style response is executed properly
- s.dataType = "script";
-
- // Handle JSONP-style loading
- window[ jsonp ] = function(tmp){
- data = tmp;
- success();
- complete();
- // Garbage collect
- window[ jsonp ] = undefined;
- try{ delete window[ jsonp ]; } catch(e){}
- if ( head )
- head.removeChild( script );
- };
- }
-
- if ( s.dataType == "script" && s.cache == null )
- s.cache = false;
-
- if ( s.cache === false && s.type.toLowerCase() == "get" ) {
- var ts = (new Date()).getTime();
- // try replacing _= if it is there
- var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
- // if nothing was replaced, add timestamp to the end
- s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
- }
-
- // If data is available, append data to url for get requests
- if ( s.data && s.type.toLowerCase() == "get" ) {
- s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
-
- // IE likes to send both get and post data, prevent this
- s.data = null;
- }
-
- // Watch for a new set of requests
- if ( s.global && ! jQuery.active++ )
- jQuery.event.trigger( "ajaxStart" );
-
- // If we're requesting a remote document
- // and trying to load JSON or Script with a GET
- if ( (!s.url.indexOf("http") || !s.url.indexOf("//")) && s.dataType == "script" && s.type.toLowerCase() == "get" ) {
- var head = document.getElementsByTagName("head")[0];
- var script = document.createElement("script");
- script.src = s.url;
- if (s.scriptCharset)
- script.charset = s.scriptCharset;
-
- // Handle Script loading
- if ( !jsonp ) {
- var done = false;
-
- // Attach handlers for all browsers
- script.onload = script.onreadystatechange = function(){
- if ( !done && (!this.readyState ||
- this.readyState == "loaded" || this.readyState == "complete") ) {
- done = true;
- success();
- complete();
- head.removeChild( script );
- }
- };
- }
-
- head.appendChild(script);
-
- // We handle everything using the script element injection
- return undefined;
- }
-
- var requestDone = false;
-
- // Create the request object; Microsoft failed to properly
- // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
- var xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
-
- // Open the socket
- xml.open(s.type, s.url, s.async, s.username, s.password);
-
- // Need an extra try/catch for cross domain requests in Firefox 3
- try {
- // Set the correct header, if data is being sent
- if ( s.data )
- xml.setRequestHeader("Content-Type", s.contentType);
-
- // Set the If-Modified-Since header, if ifModified mode.
- if ( s.ifModified )
- xml.setRequestHeader("If-Modified-Since",
- jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
-
- // Set header so the called script knows that it's an XMLHttpRequest
- xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-
- // Set the Accepts header for the server, depending on the dataType
- xml.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
- s.accepts[ s.dataType ] + ", */*" :
- s.accepts._default );
- } catch(e){}
-
- // Allow custom headers/mimetypes
- if ( s.beforeSend )
- s.beforeSend(xml);
-
- if ( s.global )
- jQuery.event.trigger("ajaxSend", [xml, s]);
-
- // Wait for a response to come back
- var onreadystatechange = function(isTimeout){
- // The transfer is complete and the data is available, or the request timed out
- if ( !requestDone && xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
- requestDone = true;
-
- // clear poll interval
- if (ival) {
- clearInterval(ival);
- ival = null;
- }
-
- status = isTimeout == "timeout" && "timeout" ||
- !jQuery.httpSuccess( xml ) && "error" ||
- s.ifModified && jQuery.httpNotModified( xml, s.url ) && "notmodified" ||
- "success";
-
- if ( status == "success" ) {
- // Watch for, and catch, XML document parse errors
- try {
- // process the data (runs the xml through httpData regardless of callback)
- data = jQuery.httpData( xml, s.dataType );
- } catch(e) {
- status = "parsererror";
- }
- }
-
- // Make sure that the request was successful or notmodified
- if ( status == "success" ) {
- // Cache Last-Modified header, if ifModified mode.
- var modRes;
- try {
- modRes = xml.getResponseHeader("Last-Modified");
- } catch(e) {} // swallow exception thrown by FF if header is not available
-
- if ( s.ifModified && modRes )
- jQuery.lastModified[s.url] = modRes;
-
- // JSONP handles its own success callback
- if ( !jsonp )
- success();
- } else
- jQuery.handleError(s, xml, status);
-
- // Fire the complete handlers
- complete();
-
- // Stop memory leaks
- if ( s.async )
- xml = null;
- }
- };
-
- if ( s.async ) {
- // don't attach the handler to the request, just poll it instead
- var ival = setInterval(onreadystatechange, 13);
-
- // Timeout checker
- if ( s.timeout > 0 )
- setTimeout(function(){
- // Check to see if the request is still happening
- if ( xml ) {
- // Cancel the request
- xml.abort();
-
- if( !requestDone )
- onreadystatechange( "timeout" );
- }
- }, s.timeout);
- }
-
- // Send the data
- try {
- xml.send(s.data);
- } catch(e) {
- jQuery.handleError(s, xml, null, e);
- }
-
- // firefox 1.5 doesn't fire statechange for sync requests
- if ( !s.async )
- onreadystatechange();
-
- function success(){
- // If a local callback was specified, fire it and pass it the data
- if ( s.success )
- s.success( data, status );
-
- // Fire the global callback
- if ( s.global )
- jQuery.event.trigger( "ajaxSuccess", [xml, s] );
- }
-
- function complete(){
- // Process result
- if ( s.complete )
- s.complete(xml, status);
-
- // The request was completed
- if ( s.global )
- jQuery.event.trigger( "ajaxComplete", [xml, s] );
-
- // Handle the global AJAX counter
- if ( s.global && ! --jQuery.active )
- jQuery.event.trigger( "ajaxStop" );
- }
-
- // return XMLHttpRequest to allow aborting the request etc.
- return xml;
- },
-
- handleError: function( s, xml, status, e ) {
- // If a local callback was specified, fire it
- if ( s.error ) s.error( xml, status, e );
-
- // Fire the global callback
- if ( s.global )
- jQuery.event.trigger( "ajaxError", [xml, s, e] );
- },
-
- // Counter for holding the number of active queries
- active: 0,
-
- // Determines if an XMLHttpRequest was successful or not
- httpSuccess: function( r ) {
- try {
- // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
- return !r.status && location.protocol == "file:" ||
- ( r.status >= 200 && r.status < 300 ) || r.status == 304 || r.status == 1223 ||
- jQuery.browser.safari && r.status == undefined;
- } catch(e){}
- return false;
- },
-
- // Determines if an XMLHttpRequest returns NotModified
- httpNotModified: function( xml, url ) {
- try {
- var xmlRes = xml.getResponseHeader("Last-Modified");
-
- // Firefox always returns 200. check Last-Modified date
- return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
- jQuery.browser.safari && xml.status == undefined;
- } catch(e){}
- return false;
- },
-
- httpData: function( r, type ) {
- var ct = r.getResponseHeader("content-type");
- var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0;
- var data = xml ? r.responseXML : r.responseText;
-
- if ( xml && data.documentElement.tagName == "parsererror" )
- throw "parsererror";
-
- // If the type is "script", eval it in global context
- if ( type == "script" )
- jQuery.globalEval( data );
-
- // Get the JavaScript object, if JSON is used.
- if ( type == "json" )
- data = eval("(" + data + ")");
-
- return data;
- },
-
- // Serialize an array of form elements or a set of
- // key/values into a query string
- param: function( a ) {
- var s = [];
-
- // If an array was passed in, assume that it is an array
- // of form elements
- if ( a.constructor == Array || a.jquery )
- // Serialize the form elements
- jQuery.each( a, function(){
- s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
- });
-
- // Otherwise, assume that it's an object of key/value pairs
- else
- // Serialize the key/values
- for ( var j in a )
- // If the value is an array then the key names need to be repeated
- if ( a[j] && a[j].constructor == Array )
- jQuery.each( a[j], function(){
- s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
- });
- else
- s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );
-
- // Return the resulting serialization
- return s.join("&").replace(/%20/g, "+");
- }
-
-});
-jQuery.fn.extend({
- show: function(speed,callback){
- return speed ?
- this.animate({
- height: "show", width: "show", opacity: "show"
- }, speed, callback) :
-
- this.filter(":hidden").each(function(){
- this.style.display = this.oldblock || "";
- if ( jQuery.css(this,"display") == "none" ) {
- var elem = jQuery("<" + this.tagName + " />").appendTo("body");
- this.style.display = elem.css("display");
- // handle an edge condition where css is - div { display:none; } or similar
- if (this.style.display == "none")
- this.style.display = "block";
- elem.remove();
- }
- }).end();
- },
-
- hide: function(speed,callback){
- return speed ?
- this.animate({
- height: "hide", width: "hide", opacity: "hide"
- }, speed, callback) :
-
- this.filter(":visible").each(function(){
- this.oldblock = this.oldblock || jQuery.css(this,"display");
- this.style.display = "none";
- }).end();
- },
-
- // Save the old toggle function
- _toggle: jQuery.fn.toggle,
-
- toggle: function( fn, fn2 ){
- return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
- this._toggle( fn, fn2 ) :
- fn ?
- this.animate({
- height: "toggle", width: "toggle", opacity: "toggle"
- }, fn, fn2) :
- this.each(function(){
- jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
- });
- },
-
- slideDown: function(speed,callback){
- return this.animate({height: "show"}, speed, callback);
- },
-
- slideUp: function(speed,callback){
- return this.animate({height: "hide"}, speed, callback);
- },
-
- slideToggle: function(speed, callback){
- return this.animate({height: "toggle"}, speed, callback);
- },
-
- fadeIn: function(speed, callback){
- return this.animate({opacity: "show"}, speed, callback);
- },
-
- fadeOut: function(speed, callback){
- return this.animate({opacity: "hide"}, speed, callback);
- },
-
- fadeTo: function(speed,to,callback){
- return this.animate({opacity: to}, speed, callback);
- },
-
- animate: function( prop, speed, easing, callback ) {
- var optall = jQuery.speed(speed, easing, callback);
-
- return this[ optall.queue === false ? "each" : "queue" ](function(){
- if ( this.nodeType != 1)
- return false;
-
- var opt = jQuery.extend({}, optall);
- var hidden = jQuery(this).is(":hidden"), self = this;
-
- for ( var p in prop ) {
- if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
- return jQuery.isFunction(opt.complete) && opt.complete.apply(this);
-
- if ( p == "height" || p == "width" ) {
- // Store display property
- opt.display = jQuery.css(this, "display");
-
- // Make sure that nothing sneaks out
- opt.overflow = this.style.overflow;
- }
- }
-
- if ( opt.overflow != null )
- this.style.overflow = "hidden";
-
- opt.curAnim = jQuery.extend({}, prop);
-
- jQuery.each( prop, function(name, val){
- var e = new jQuery.fx( self, opt, name );
-
- if ( /toggle|show|hide/.test(val) )
- e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
- else {
- var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
- start = e.cur(true) || 0;
-
- if ( parts ) {
- var end = parseFloat(parts[2]),
- unit = parts[3] || "px";
-
- // We need to compute starting value
- if ( unit != "px" ) {
- self.style[ name ] = (end || 1) + unit;
- start = ((end || 1) / e.cur(true)) * start;
- self.style[ name ] = start + unit;
- }
-
- // If a +=/-= token was provided, we're doing a relative animation
- if ( parts[1] )
- end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
-
- e.custom( start, end, unit );
- } else
- e.custom( start, val, "" );
- }
- });
-
- // For JS strict compliance
- return true;
- });
- },
-
- queue: function(type, fn){
- if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
- fn = type;
- type = "fx";
- }
-
- if ( !type || (typeof type == "string" && !fn) )
- return queue( this[0], type );
-
- return this.each(function(){
- if ( fn.constructor == Array )
- queue(this, type, fn);
- else {
- queue(this, type).push( fn );
-
- if ( queue(this, type).length == 1 )
- fn.apply(this);
- }
- });
- },
-
- stop: function(clearQueue, gotoEnd){
- var timers = jQuery.timers;
-
- if (clearQueue)
- this.queue([]);
-
- this.each(function(){
- // go in reverse order so anything added to the queue during the loop is ignored
- for ( var i = timers.length - 1; i >= 0; i-- )
- if ( timers[i].elem == this ) {
- if (gotoEnd)
- // force the next step to be the last
- timers[i](true);
- timers.splice(i, 1);
- }
- });
-
- // start the next in the queue if the last step wasn't forced
- if (!gotoEnd)
- this.dequeue();
-
- return this;
- }
-
-});
-
-var queue = function( elem, type, array ) {
- if ( !elem )
- return undefined;
-
- type = type || "fx";
-
- var q = jQuery.data( elem, type + "queue" );
-
- if ( !q || array )
- q = jQuery.data( elem, type + "queue",
- array ? jQuery.makeArray(array) : [] );
-
- return q;
-};
-
-jQuery.fn.dequeue = function(type){
- type = type || "fx";
-
- return this.each(function(){
- var q = queue(this, type);
-
- q.shift();
-
- if ( q.length )
- q[0].apply( this );
- });
-};
-
-jQuery.extend({
-
- speed: function(speed, easing, fn) {
- var opt = speed && speed.constructor == Object ? speed : {
- complete: fn || !fn && easing ||
- jQuery.isFunction( speed ) && speed,
- duration: speed,
- easing: fn && easing || easing && easing.constructor != Function && easing
- };
-
- opt.duration = (opt.duration && opt.duration.constructor == Number ?
- opt.duration :
- { slow: 600, fast: 200 }[opt.duration]) || 400;
-
- // Queueing
- opt.old = opt.complete;
- opt.complete = function(){
- if ( opt.queue !== false )
- jQuery(this).dequeue();
- if ( jQuery.isFunction( opt.old ) )
- opt.old.apply( this );
- };
-
- return opt;
- },
-
- easing: {
- linear: function( p, n, firstNum, diff ) {
- return firstNum + diff * p;
- },
- swing: function( p, n, firstNum, diff ) {
- return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
- }
- },
-
- timers: [],
- timerId: null,
-
- fx: function( elem, options, prop ){
- this.options = options;
- this.elem = elem;
- this.prop = prop;
-
- if ( !options.orig )
- options.orig = {};
- }
-
-});
-
-jQuery.fx.prototype = {
-
- // Simple function for setting a style value
- update: function(){
- if ( this.options.step )
- this.options.step.apply( this.elem, [ this.now, this ] );
-
- (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
-
- // Set display property to block for height/width animations
- if ( this.prop == "height" || this.prop == "width" )
- this.elem.style.display = "block";
- },
-
- // Get the current size
- cur: function(force){
- if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
- return this.elem[ this.prop ];
-
- var r = parseFloat(jQuery.css(this.elem, this.prop, force));
- return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
- },
-
- // Start an animation from one number to another
- custom: function(from, to, unit){
- this.startTime = (new Date()).getTime();
- this.start = from;
- this.end = to;
- this.unit = unit || this.unit || "px";
- this.now = this.start;
- this.pos = this.state = 0;
- this.update();
-
- var self = this;
- function t(gotoEnd){
- return self.step(gotoEnd);
- }
-
- t.elem = this.elem;
-
- jQuery.timers.push(t);
-
- if ( jQuery.timerId == null ) {
- jQuery.timerId = setInterval(function(){
- var timers = jQuery.timers;
-
- for ( var i = 0; i < timers.length; i++ )
- if ( !timers[i]() )
- timers.splice(i--, 1);
-
- if ( !timers.length ) {
- clearInterval( jQuery.timerId );
- jQuery.timerId = null;
- }
- }, 13);
- }
- },
-
- // Simple 'show' function
- show: function(){
- // Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
- this.options.show = true;
-
- // Begin the animation
- this.custom(0, this.cur());
-
- // Make sure that we start at a small width/height to avoid any
- // flash of content
- if ( this.prop == "width" || this.prop == "height" )
- this.elem.style[this.prop] = "1px";
-
- // Start by showing the element
- jQuery(this.elem).show();
- },
-
- // Simple 'hide' function
- hide: function(){
- // Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
- this.options.hide = true;
-
- // Begin the animation
- this.custom(this.cur(), 0);
- },
-
- // Each step of an animation
- step: function(gotoEnd){
- var t = (new Date()).getTime();
-
- if ( gotoEnd || t > this.options.duration + this.startTime ) {
- this.now = this.end;
- this.pos = this.state = 1;
- this.update();
-
- this.options.curAnim[ this.prop ] = true;
-
- var done = true;
- for ( var i in this.options.curAnim )
- if ( this.options.curAnim[i] !== true )
- done = false;
-
- if ( done ) {
- if ( this.options.display != null ) {
- // Reset the overflow
- this.elem.style.overflow = this.options.overflow;
-
- // Reset the display
- this.elem.style.display = this.options.display;
- if ( jQuery.css(this.elem, "display") == "none" )
- this.elem.style.display = "block";
- }
-
- // Hide the element if the "hide" operation was done
- if ( this.options.hide )
- this.elem.style.display = "none";
-
- // Reset the properties, if the item has been hidden or shown
- if ( this.options.hide || this.options.show )
- for ( var p in this.options.curAnim )
- jQuery.attr(this.elem.style, p, this.options.orig[p]);
- }
-
- // If a callback was provided, execute it
- if ( done && jQuery.isFunction( this.options.complete ) )
- // Execute the complete function
- this.options.complete.apply( this.elem );
-
- return false;
- } else {
- var n = t - this.startTime;
- this.state = n / this.options.duration;
-
- // Perform the easing function, defaults to swing
- this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
- this.now = this.start + ((this.end - this.start) * this.pos);
-
- // Perform the next step of the animation
- this.update();
- }
-
- return true;
- }
-
-};
-
-jQuery.fx.step = {
- scrollLeft: function(fx){
- fx.elem.scrollLeft = fx.now;
- },
-
- scrollTop: function(fx){
- fx.elem.scrollTop = fx.now;
- },
-
- opacity: function(fx){
- jQuery.attr(fx.elem.style, "opacity", fx.now);
- },
-
- _default: function(fx){
- fx.elem.style[ fx.prop ] = fx.now + fx.unit;
- }
-};
-// The Offset Method
-// Originally By Brandon Aaron, part of the Dimension Plugin
-// http://jquery.com/plugins/project/dimensions
-jQuery.fn.offset = function() {
- var left = 0, top = 0, elem = this[0], results;
-
- if ( elem ) with ( jQuery.browser ) {
- var parent = elem.parentNode,
- offsetChild = elem,
- offsetParent = elem.offsetParent,
- doc = elem.ownerDocument,
- safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
- fixed = jQuery.css(elem, "position") == "fixed";
-
- // Use getBoundingClientRect if available
- if ( elem.getBoundingClientRect ) {
- var box = elem.getBoundingClientRect();
-
- // Add the document scroll offsets
- add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
- box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
-
- // IE adds the HTML element's border, by default it is medium which is 2px
- // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
- // IE 7 standards mode, the border is always 2px
- // This border/offset is typically represented by the clientLeft and clientTop properties
- // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
- // Therefore this method will be off by 2px in IE while in quirksmode
- add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
-
- // Otherwise loop through the offsetParents and parentNodes
- } else {
-
- // Initial element offsets
- add( elem.offsetLeft, elem.offsetTop );
-
- // Get parent offsets
- while ( offsetParent ) {
- // Add offsetParent offsets
- add( offsetParent.offsetLeft, offsetParent.offsetTop );
-
- // Mozilla and Safari > 2 does not include the border on offset parents
- // However Mozilla adds the border for table or table cells
- if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
- border( offsetParent );
-
- // Add the document scroll offsets if position is fixed on any offsetParent
- if ( !fixed && jQuery.css(offsetParent, "position") == "fixed" )
- fixed = true;
-
- // Set offsetChild to previous offsetParent unless it is the body element
- offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
- // Get next offsetParent
- offsetParent = offsetParent.offsetParent;
- }
-
- // Get parent scroll offsets
- while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
- // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
- if ( !/^inline|table.*$/i.test(jQuery.css(parent, "display")) )
- // Subtract parent scroll offsets
- add( -parent.scrollLeft, -parent.scrollTop );
-
- // Mozilla does not add the border for a parent that has overflow != visible
- if ( mozilla && jQuery.css(parent, "overflow") != "visible" )
- border( parent );
-
- // Get next parent
- parent = parent.parentNode;
- }
-
- // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
- // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
- if ( (safari2 && (fixed || jQuery.css(offsetChild, "position") == "absolute")) ||
- (mozilla && jQuery.css(offsetChild, "position") != "absolute") )
- add( -doc.body.offsetLeft, -doc.body.offsetTop );
-
- // Add the document scroll offsets if position is fixed
- if ( fixed )
- add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
- Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
- }
-
- // Return an object with top and left properties
- results = { top: top, left: left };
- }
-
- function border(elem) {
- add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
- }
-
- function add(l, t) {
- left += parseInt(l) || 0;
- top += parseInt(t) || 0;
- }
-
- return results;
-};
-
-// Create innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each(["Height", "Width"], function(i, name){
-
- var tl = name == "Height" ? "Top" : "Left", // top or left
- br = name == "Height" ? "Bottom" : "Right"; // bottom or right
-
- // innerHeight and innerWidth
- jQuery.fn["inner" + name] = function(){
- return this[ name.toLowerCase() ]() +
- num(this, "padding" + tl) +
- num(this, "padding" + br);
- };
-
- // outerHeight and outerWidth
- jQuery.fn["outer" + name] = function(margin) {
- return this["inner" + name]() +
- num(this, "border" + tl + "Width") +
- num(this, "border" + br + "Width") +
- (!!margin ?
- num(this, "margin" + tl) + num(this, "margin" + br) : 0);
- };
-
-});
-
-function num(elem, prop) {
- elem = elem.jquery ? elem[0] : elem;
- return elem && parseInt( jQuery.curCSS(elem, prop, true) ) || 0;
-}})();
diff --git a/moksha/widgetbrowser/static/loading.gif b/moksha/widgetbrowser/static/loading.gif
deleted file mode 100644
index 85b99d4..0000000
Binary files a/moksha/widgetbrowser/static/loading.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/pygments.css b/moksha/widgetbrowser/static/pygments.css
deleted file mode 100644
index a55a324..0000000
--- a/moksha/widgetbrowser/static/pygments.css
+++ /dev/null
@@ -1,59 +0,0 @@
-.c { color: #408090; font-style: italic } /* Comment */
-.err { border: 1px solid #FF0000 } /* Error */
-.k { color: #007020; font-weight: bold } /* Keyword */
-.o { color: #666666 } /* Operator */
-.cm { color: #408090; font-style: italic } /* Comment.Multiline */
-.cp { color: #007020 } /* Comment.Preproc */
-.c1 { color: #408090; font-style: italic } /* Comment.Single */
-.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
-.gd { color: #A00000 } /* Generic.Deleted */
-.ge { font-style: italic } /* Generic.Emph */
-.gr { color: #FF0000 } /* Generic.Error */
-.gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.gi { color: #00A000 } /* Generic.Inserted */
-.go { color: #303030 } /* Generic.Output */
-.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
-.gs { font-weight: bold } /* Generic.Strong */
-.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.gt { color: #0040D0 } /* Generic.Traceback */
-.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
-.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
-.kp { color: #007020 } /* Keyword.Pseudo */
-.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
-.kt { color: #902000 } /* Keyword.Type */
-.m { color: #208050 } /* Literal.Number */
-.s { color: #4070a0 } /* Literal.String */
-.na { color: #4070a0 } /* Name.Attribute */
-.nb { color: #007020 } /* Name.Builtin */
-.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
-.no { color: #60add5 } /* Name.Constant */
-.nd { color: #555555; font-weight: bold } /* Name.Decorator */
-.ni { color: #d55537; font-weight: bold } /* Name.Entity */
-.ne { color: #007020 } /* Name.Exception */
-.nf { color: #06287e } /* Name.Function */
-.nl { color: #002070; font-weight: bold } /* Name.Label */
-.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
-.nt { color: #062873; font-weight: bold } /* Name.Tag */
-.nv { color: #bb60d5 } /* Name.Variable */
-.ow { color: #007020; font-weight: bold } /* Operator.Word */
-.w { color: #bbbbbb } /* Text.Whitespace */
-.mf { color: #208050 } /* Literal.Number.Float */
-.mh { color: #208050 } /* Literal.Number.Hex */
-.mi { color: #208050 } /* Literal.Number.Integer */
-.mo { color: #208050 } /* Literal.Number.Oct */
-.sb { color: #4070a0 } /* Literal.String.Backtick */
-.sc { color: #4070a0 } /* Literal.String.Char */
-.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
-.s2 { color: #4070a0 } /* Literal.String.Double */
-.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
-.sh { color: #4070a0 } /* Literal.String.Heredoc */
-.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
-.sx { color: #c65d09 } /* Literal.String.Other */
-.sr { color: #235388 } /* Literal.String.Regex */
-.s1 { color: #4070a0 } /* Literal.String.Single */
-.ss { color: #517918 } /* Literal.String.Symbol */
-.bp { color: #007020 } /* Name.Builtin.Pseudo */
-.vc { color: #bb60d5 } /* Name.Variable.Class */
-.vg { color: #bb60d5 } /* Name.Variable.Global */
-.vi { color: #bb60d5 } /* Name.Variable.Instance */
-.il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/tab.png b/moksha/widgetbrowser/static/tab.png
deleted file mode 100644
index 413c755..0000000
Binary files a/moksha/widgetbrowser/static/tab.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.accordion.css b/moksha/widgetbrowser/static/themes/flora/flora.accordion.css
deleted file mode 100644
index f45ed75..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.accordion.css
+++ /dev/null
@@ -1,12 +0,0 @@
-ul.ui-accordion { margin: 0; padding: 0; list-style-type: none; }
-ul.ui-accordion li { margin: 0; margin-bottom: 2px; padding: 0; background-image: url(i/accordion-left.png); background-repeat: no-repeat; }
-ul.ui-accordion li a.ui-accordion-header { display: block; padding-left: 5px; margin-right: 3px; height: 28px; background-image: url(i/accordion-middle.png); color: #000; text-decoration: none; line-height: 28px; }
-ul.ui-accordion li .ui-accordion-right { display: block; background-image: url(i/accordion-right.png); position: absolute; top: 0px; right: 0px; height: 28px; width: 3px; }
-
-ul.ui-accordion li:hover { background-image: url(i/accordion-left-over.png); }
-ul.ui-accordion li:hover a.ui-accordion-header { background-image: url(i/accordion-middle-over.png); }
-ul.ui-accordion li:hover .ui-accordion-right { background-image: url(i/accordion-right-over.png); }
-
-ul.ui-accordion li.active { background-image: url(i/accordion-left-act.png); }
-ul.ui-accordion li.active a.ui-accordion-header { background-image: url(i/accordion-middle-act.png); }
-ul.ui-accordion li.active .ui-accordion-right { background-image: url(i/accordion-right-act.png); }
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.all.css b/moksha/widgetbrowser/static/themes/flora/flora.all.css
deleted file mode 100644
index 3de5386..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.all.css
+++ /dev/null
@@ -1,9 +0,0 @@
-@import "flora.css";
-@import "flora.shadow.css";
-@import "flora.resizable.css";
-@import "flora.slider.css";
-@import "flora.accordion.css";
-@import "flora.tabs.css";
-@import "flora.dialog.css";
-@import "flora.tablesorter.css";
-@import "flora.datepicker.css";
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.calendar.css b/moksha/widgetbrowser/static/themes/flora/flora.calendar.css
deleted file mode 100644
index dedcf0c..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.calendar.css
+++ /dev/null
@@ -1,167 +0,0 @@
-/* Main Style Sheet for jQuery Calendar */
-#calendar_div, .calendar_inline {
- font-family: Arial, Helvetica, sans-serif;
- font-size: 14px;
- padding: 0;
- margin: 0;
- background: #ddd;
-}
-#calendar_div {
- display: none;
- border: 1px solid #FF9900;
- z-index: 10; /*must have*/
-}
-#calendar_div, .calendar_control, .calendar_links, .calendar_header, .calendar {
- width: 185px;
-}
-.calendar_inline {
- float: left;
- display: block;
- border: 0;
-}
-.calendar_dialog {
- padding: 5px !important;
- border: 4px ridge #ddd !important;
-}
-button.calendar_trigger {
- width: 25px;
-}
-img.calendar_trigger {
- margin: 2px;
- vertical-align: middle;
-}
-.calendar_prompt {
- float: left;
- width: 181px;
- padding: 2px;
- background: #ddd;
- color: #000;
-}
-* html .calendar_prompt {
- width: 185px;
-}
-.calendar_control, .calendar_links, .calendar_header, .calendar {
- clear: both;
- float: left;
- color: #fff;
-}
-.calendar_control {
- background: #FF9900;
-}
-.calendar_links {
- background: #E0F4D7;
-}
-.calendar_control, .calendar_links {
- font-weight: bold;
- font-size: 80%;
- letter-spacing: 1px;
-}
-.calendar_links label { /* disabled links */
- padding: 2px 5px;
- color: #888;
-}
-.calendar_clear, .calendar_prev {
- float: left;
-}
-.calendar_current {
- float: left;
- width: 35%;
- text-align: center;
-}
-.calendar_close, .calendar_next {
- float: right;
-}
-.calendar_header {
- background: #83C948;
- text-align: center;
- font-weight: bold;
-}
-.calendar_header select {
- background: #83C948;
- color: #000;
- border: 0px;
- font-weight: bold;
-}
-.calendar {
- background: #ccc;
- text-align: center;
- font-size: 100%;
-}
-.calendar a {
- display: block;
- width: 100%;
-}
-.calendar .calendar_titleRow {
- background: #B1DB87;
- color: #000 !important;
-}
-.calendar .calendar_daysRow {
- background: #FFF;
- color: #666;
-}
-.calendar .calendar_daysCell {
- color: #000;
- border: 1px solid #ddd;
-}
-#calendar .calendar_daysCell a{
- display: block;
-}
-.calendar .calendar_weekEndCell {
- background: #E0F4D7;
-}
-.calendar .calendar_daysCellOver {
- background: #fff;
- border: 1px solid #777;
-}
-.calendar .calendar_unselectable {
- color: #888;
-}
-.calendar_today {
- background: #ccc !important;
-}
-.calendar_currentDay {
- background: #999 !important;
-}
-
-/* ________ CALENDAR LINKS _______
-
-** Reset link properties and then override them with !important */
-#calendar_div a, .calendar_inline a {
- cursor: pointer;
- margin: 0;
- padding: 0;
- background: none;
- color: #000;
-}
-.calendar_inline .calendar_links a {
- padding: 0 5px !important;
-}
-.calendar_control a, .calendar_links a {
- padding: 2px 5px !important;
- color: #000 !important;
-}
-.calendar_titleRow a {
- color: #000 !important;
-}
-.calendar_control a:hover {
- /*background: #fdd !important;*/
- color: #333 !important;
-}
-.calendar_links a:hover, .calendar_titleRow a:hover {
- background: #FFF !important;
- color: #333 !important;
-}
-
-/* ___________ IE6 IFRAME FIX ________ */
-
-.calendar_cover {
- display: none; /*sorry for IE5*/
- display/**/: block; /*sorry for IE5*/
- position: absolute; /*must have*/
- z-index: -1; /*must have*/
- filter: mask(); /*must have*/
- top: -4px; /*must have*/
- left: -4px; /*must have*/
- width: 193px; /*must have to match width and borders*/
- height: 200px; /*must have to match maximum height*/
-}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.css b/moksha/widgetbrowser/static/themes/flora/flora.css
deleted file mode 100644
index 761217d..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.css
+++ /dev/null
@@ -1,2 +0,0 @@
-.ui-wrapper { border: 1px solid #50A029; }
-.ui-wrapper input, .ui-wrapper textarea { border: 0; }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.datepicker.css b/moksha/widgetbrowser/static/themes/flora/flora.datepicker.css
deleted file mode 100644
index 34ea650..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.datepicker.css
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Main Flora Style Sheet for jQuery UI Datepicker */
-#datepicker_div, .datepicker_inline {
- font-family: Arial,Helvetica,sans-serif;
- font-size: 14px;
- padding: 0;
- margin: 0;
- background: #DDD;
- width: 185px;
-}
-#datepicker_div {
- display: none;
- border: 1px solid #FF9900;
- z-index: 10;
-}
-.datepicker_inline {
- float: left;
- display: block;
- border: 0;
-}
-.datepicker_dialog {
- padding: 5px !important;
- border: 4px ridge #DDD !important;
-}
-button.datepicker_trigger {
- width: 25px;
-}
-img.datepicker_trigger {
- margin: 2px;
- vertical-align: middle;
-}
-.datepicker_prompt {
- float: left;
- padding: 2px;
- background: #DDD;
- color: #000;
-}
-*html .datepicker_prompt {
- width: 185px;
-}
-.datepicker_control, .datepicker_links, .datepicker_header, .datepicker {
- clear: both;
- float: left;
- width: 100%;
- color: #FFF;
-}
-.datepicker_control {
- background: #FF9900;
- padding: 2px 0px;
-}
-.datepicker_links {
- background: #E0F4D7;
- padding: 2px 0px;
-}
-.datepicker_control, .datepicker_links {
- font-weight: bold;
- font-size: 80%;
- letter-spacing: 1px;
-}
-.datepicker_links label {
- padding: 2px 5px;
- color: #888;
-}
-.datepicker_clear, .datepicker_prev {
- float: left;
- width: 34%;
-}
-.datepicker_current {
- float: left;
- width: 30%;
- text-align: center;
-}
-.datepicker_close, .datepicker_next {
- float: right;
- width: 34%;
- text-align: right;
-}
-.datepicker_header {
- padding: 1px 0 3px;
- background: #83C948;
- text-align: center;
- font-weight: bold;
- height: 1.3em;
-}
-.datepicker_header select {
- background: #83C948;
- color: #000;
- border: 0px;
- font-weight: bold;
-}
-.datepicker {
- background: #CCC;
- text-align: center;
- font-size: 100%;
-}
-.datepicker a {
- display: block;
- width: 100%;
-}
-.datepicker .datepicker_titleRow {
- background: #B1DB87;
- color: #000;
-}
-.datepicker .datepicker_daysRow {
- background: #FFF;
- color: #666;
-}
-.datepicker_weekCol {
- background: #B1DB87;
- color: #000;
-}
-.datepicker .datepicker_daysCell {
- color: #000;
- border: 1px solid #DDD;
-}
-#datepicker .datepicker_daysCell a {
- display: block;
-}
-.datepicker .datepicker_weekEndCell {
- background: #E0F4D7;
-}
-.datepicker .datepicker_daysCellOver {
- background: #FFF;
- border: 1px solid #777;
-}
-.datepicker .datepicker_unselectable {
- color: #888;
-}
-.datepicker_today {
- background: #B1DB87 !important;
-}
-.datepicker_currentDay {
- background: #83C948 !important;
-}
-#datepicker_div a, .datepicker_inline a {
- cursor: pointer;
- margin: 0;
- padding: 0;
- background: none;
- color: #000;
-}
-.datepicker_inline .datepicker_links a {
- padding: 0 5px !important;
-}
-.datepicker_control a, .datepicker_links a {
- padding: 2px 5px !important;
- color: #000 !important;
-}
-.datepicker_titleRow a {
- color: #000 !important;
-}
-.datepicker_control a:hover {
- background: #FDD !important;
- color: #333 !important;
-}
-.datepicker_links a:hover, .datepicker_titleRow a:hover {
- background: #FFF !important;
- color: #333 !important;
-}
-.datepicker_multi .datepicker {
- border: 1px solid #83C948;
-}
-.datepicker_oneMonth {
- float: left;
- width: 185px;
-}
-.datepicker_newRow {
- clear: left;
-}
-.datepicker_cover {
- display: none;
- display/**/: block;
- position: absolute;
- z-index: -1;
- filter: mask();
- top: -4px;
- left: -4px;
- width: 193px;
- height: 200px;
-}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.dialog.css b/moksha/widgetbrowser/static/themes/flora/flora.dialog.css
deleted file mode 100644
index efef1c4..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.dialog.css
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This file skins dialog */
-
-.flora .ui-dialog,
-.flora.ui-dialog {
- background-color: #e6f7d4;
-}
-
-.flora .ui-dialog .ui-dialog-titlebar,
-.flora.ui-dialog .ui-dialog-titlebar {
- border-bottom: 1px solid #d8d2aa;
- background: #ff9900 url(i/dialog-title.gif) repeat-x;
- padding: 0px;
- height: 28px;
- _height: 29px;
-}
-
-.flora .ui-dialog.ui-draggable .ui-dialog-titlebar,
-.flora.ui-dialog.ui-draggable .ui-dialog-titlebar {
- cursor: move;
-}
-
-.flora .ui-dialog .ui-dialog-titlebar-close,
-.flora.ui-dialog .ui-dialog-titlebar-close {
- width: 16px;
- height: 16px;
- background: url(i/dialog-titlebar-close.png) no-repeat;
- position:absolute;
- top: 6px;
- right: 7px;
- cursor: default;
-}
-
-.flora .ui-dialog .ui-dialog-titlebar-close span,
-.flora.ui-dialog .ui-dialog-titlebar-close span {
- display: none;
-}
-
-.flora .ui-dialog .ui-dialog-titlebar-close-hover,
-.flora.ui-dialog .ui-dialog-titlebar-close-hover {
- background: url(i/dialog-titlebar-close-hover.png) no-repeat;
-}
-
-.flora .ui-dialog .ui-dialog-title,
-.flora.ui-dialog .ui-dialog-title {
- margin-left: 5px;
- color: white;
- font-weight: bold;
- position: relative;
- top: 7px;
- left: 4px;
-}
-
-.flora .ui-dialog .ui-dialog-content,
-.flora.ui-dialog .ui-dialog-content {
- margin: 1.2em;
-}
-
-.flora .ui-dialog .ui-dialog-buttonpane,
-.flora.ui-dialog .ui-dialog-buttonpane {
- position: absolute;
- bottom: 8px;
- right: 12px;
- width: 100%;
- text-align: right;
-}
-
-.flora .ui-dialog .ui-dialog-buttonpane button,
-.flora.ui-dialog .ui-dialog-buttonpane button {
- margin: 6px;
-}
-
-/* Dialog handle styles */
-.flora .ui-dialog .ui-resizable-n,
-.flora.ui-dialog .ui-resizable-n { cursor: n-resize; height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/dialog-n.gif) repeat scroll center top; }
-
-.flora .ui-dialog .ui-resizable-s,
-.flora.ui-dialog .ui-resizable-s { cursor: s-resize; height: 8px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/dialog-s.gif) repeat scroll center top; }
-
-.flora .ui-dialog .ui-resizable-e,
-.flora.ui-dialog .ui-resizable-e { cursor: e-resize; width: 7px; right: 0px; top: 0px; height: 100%; background: transparent url(i/dialog-e.gif) repeat scroll right center; }
-
-.flora .ui-dialog .ui-resizable-w,
-.flora.ui-dialog .ui-resizable-w { cursor: w-resize; width: 7px; left: 0px; top: 0px; height: 100%; background: transparent url(i/dialog-w.gif) repeat scroll right center; }
-
-.flora .ui-dialog .ui-resizable-se,
-.flora.ui-dialog .ui-resizable-se { cursor: se-resize; width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/dialog-se.gif); }
-
-.flora .ui-dialog .ui-resizable-sw,
-.flora.ui-dialog .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/dialog-sw.gif); }
-
-.flora .ui-dialog .ui-resizable-nw,
-.flora.ui-dialog .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 29px; left: 0px; top: 0px; background: transparent url(i/dialog-nw.gif); }
-
-.flora .ui-dialog .ui-resizable-ne,
-.flora.ui-dialog .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 29px; right: 0px; top: 0px; background: transparent url(i/dialog-ne.gif); }
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.menu.css b/moksha/widgetbrowser/static/themes/flora/flora.menu.css
deleted file mode 100644
index 6d2dd21..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.menu.css
+++ /dev/null
@@ -1,8 +0,0 @@
-.ui-menu-toolbar {z-index:500; list-style:none;}
-.ui-menu-toolbar-button {float:left; padding:4px 20px; cursor:pointer;}
-.ui-menu-toolbar-button:hover {}
-.ui-menu-toolbar-button a {text-decoration:none;}
-.ui-menu-items {display:none; padding:0; z-index:500; list-style:none; padding:1px 4px; min-width:80px; *width:80px;}
-.ui-menu-item a { text-decoration:none;}
-.ui-menu-item-parent { background: url('i/menu-submenu.gif') no-repeat center right; }
-.ui-menu-item-disabled {}
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.resizable.css b/moksha/widgetbrowser/static/themes/flora/flora.resizable.css
deleted file mode 100644
index 5e30c0c..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.resizable.css
+++ /dev/null
@@ -1,20 +0,0 @@
-/* This file skins resizables */
-
-.ui-resizable { position: relative; }
-
-/* Global handle styles */
-.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; }
-.ui-resizable .ui-resizable-handle { display: block; }
-body .ui-resizable-disabled .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
-body .ui-resizable-autohide .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
-
-.ui-resizable-n { cursor: n-resize; height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/resizable-n.gif) repeat scroll center top; }
-.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/resizable-s.gif) repeat scroll center top; }
-
-.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%; background: transparent url(i/resizable-e.gif) repeat scroll right center; }
-.ui-resizable-w { cursor: w-resize; width: 6px; left: 0px; top: 0px; height: 100%; background: transparent url(i/resizable-w.gif) repeat scroll right center; }
-
-.ui-resizable-se { cursor: se-resize; width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/resizable-se.gif); }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/resizable-sw.gif); }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: 0px; top: 0px; background: transparent url(i/resizable-nw.gif); }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: 0px; top: 0px; background: transparent url(i/resizable-ne.gif); }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.slider.css b/moksha/widgetbrowser/static/themes/flora/flora.slider.css
deleted file mode 100644
index 94827b3..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.slider.css
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This file skins sliders */
-
-.ui-slider { width: 200px; height: 23px; position: relative; background-repeat: no-repeat; background-position: center center; }
-.ui-slider-handle { position: absolute; z-index: 1; height: 23px; width: 12px; top: 0px; left: 0px; background-image: url(i/slider-handle.gif); }
-.ui-slider-handle-active { border: 1px dotted black; }
-.ui-slider-disabled .ui-slider-handle { opacity: 0.5; filter: alpha(opacity=50); }
-.ui-slider-range { position: absolute; background: #50A029; opacity: 0.3; filter: alpha(opacity=30); width: 100%; height: 100%; }
-
-/* Default slider backgrounds */
-.ui-slider, .ui-slider-1 { background-image: url(i/slider-bg-1.png); }
-.ui-slider-2 { background-image: url(i/slider-bg-2.png); }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.tablesorter.css b/moksha/widgetbrowser/static/themes/flora/flora.tablesorter.css
deleted file mode 100644
index 7d805a7..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.tablesorter.css
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file skins tableSorter */
-
-table.tablesorter {
- font-family:arial;
- background-color: #CDCDCD;
- margin:10px 0pt 15px;
- font-size: 8pt;
- width: 100%;
- text-align: left;
-}
-table.tablesorter thead tr th, table.tablesorter tfoot tr th {
- background-color: #B1DB87;
- border: 1px solid #FFF;
- font-size: 8pt;
- padding: 4px;
-}
-table.tablesorter thead tr .header {
- background-image: url(i/bg.gif);
- background-repeat: no-repeat;
- background-position: center right;
- cursor: pointer;
-}
-table.tablesorter tbody td {
- color: #3D3D3D;
- padding: 4px;
- background-color: #FFF;
- vertical-align: top;
-}
-table.tablesorter tbody tr.odd td {
- background-color:#E0F4D7;
-}
-table.tablesorter thead tr .headerSortUp {
- background-image: url(i/asc.gif);
-}
-table.tablesorter thead tr .headerSortDown {
- background-image: url(i/desc.gif);
-}
-table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
-background-color: #83C948;
-}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.tabs.css b/moksha/widgetbrowser/static/themes/flora/flora.tabs.css
deleted file mode 100644
index c79a17e..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.tabs.css
+++ /dev/null
@@ -1,105 +0,0 @@
-@import "flora.css";
-
-/* Caution! Ensure accessibility in print and other media types... */
-@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
- .ui-tabs-hide {
- display: none;
- }
-}
-
-/* Hide useless elements in print layouts... */
-@media print {
- .ui-tabs-nav {
- display: none;
- }
-}
-
-/* Skin */
-.ui-tabs-nav, .ui-tabs-panel {
- font-family: "Trebuchet MS", Trebuchet, Verdana, Helvetica, Arial, sans-serif;
- font-size: 12px;
-}
-.ui-tabs-nav {
- list-style: none;
- margin: 0;
- padding: 0 0 0 3px;
-}
-.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
- display: block;
- clear: both;
- content: " ";
-}
-.ui-tabs-nav li {
- float: left;
- margin: 0 0 0 2px;
- font-weight: bold;
-}
-.ui-tabs-nav a, .ui-tabs-nav a span {
- float: left; /* fixes dir=ltr problem and other quirks IE */
- padding: 0 12px;
- background: url(i/tabs.png) no-repeat;
-}
-.ui-tabs-nav a {
- margin: 5px 0 0; /* position: relative makes opacity fail for disabled tab in IE */
- padding-left: 0;
- background-position: 100% 0;
- text-decoration: none;
- white-space: nowrap; /* @ IE 6 */
- outline: 0; /* @ Firefox, prevent dotted border after click */
-}
-.ui-tabs-nav a:link, .ui-tabs-nav a:visited {
- color: #fff;
-}
-.ui-tabs-nav .ui-tabs-selected a {
- position: relative;
- top: 1px;
- z-index: 2;
- margin-top: 0;
- background-position: 100% -23px;
-}
-.ui-tabs-nav a span {
- padding-top: 1px;
- padding-right: 0;
- height: 20px;
- background-position: 0 0;
- line-height: 20px;
-}
-.ui-tabs-nav .ui-tabs-selected a span {
- padding-top: 0;
- height: 27px;
- background-position: 0 -23px;
- line-height: 27px;
-}
-.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited,
-.ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
- cursor: text;
-}
-.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active,
-.ui-tabs-nav .ui-tabs-unselect a:hover, .ui-tabs-nav .ui-tabs-unselect a:focus, .ui-tabs-nav .ui-tabs-unselect a:active { /* @ Opera, we need to be explicit again here now... */
- cursor: pointer;
-}
-.ui-tabs-disabled {
- opacity: .4;
- filter: alpha(opacity=40);
-}
-.ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited {
- color: #000;
-}
-.ui-tabs-panel {
- border: 1px solid #519e2d;
- padding: 10px;
- background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
-}
-/*.ui-tabs-loading em {
- padding: 0 0 0 20px;
- background: url(loading.gif) no-repeat 0 50%;
-}*/
-
-/* Additional IE specific bug fixes... */
-* html .ui-tabs-nav { /* auto clear @ IE 6 & IE 7 Quirks Mode */
- display: inline-block;
-}
-*:first-child+html .ui-tabs-nav { /* auto clear @ IE 7 Standards Mode - do not group selectors, otherwise IE 6 will ignore complete rule (because of the unknown + combinator)... */
- display: inline-block;
-}
-
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.toasterLite.css b/moksha/widgetbrowser/static/themes/flora/flora.toasterLite.css
deleted file mode 100644
index 6f2b55f..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.toasterLite.css
+++ /dev/null
@@ -1,106 +0,0 @@
-/* This file skins toasterLite */
-
-.flora .ui-toasterLite,
-.flora.ui-toasterLite {
- background-color: #e6f7d4;
- width: 100px;
- display: block;
-}
-
-.flora .ui-toasterLite .ui-toasterLite-titlebar,
-.flora.ui-toasterLite .ui-toasterLite-titlebar {
- border-bottom: 1px solid #d8d2aa;
- background: #ff9900 url(i/dialog-title.gif) repeat-x;
- padding: 0px;
- height: 28px;
- z-index: 5;
- position: relative;
-}
-
-.flora .ui-toasterLite .ui-toasterLite-title,
-.flora.ui-toasterLite .ui-toasterLite-title {
- margin-left: 5px;
- color: white;
- font-weight: bold;
- position: relative;
- top: 7px;
- left: 4px;
-}
-
-.flora .ui-toasterLite .ui-toasterLite-content,
-.flora.ui-toasterLite .ui-toasterLite-content {
- margin: 1.2em;
- padding-bottom: 12px;
-}
-
-/* Toaster handle styles */
-.flora .ui-toasterLite .ui-toasterLite-n,
-.flora.ui-toasterLite .ui-toasterLite-n { height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/toaster-n.gif) repeat scroll center top; z-index: 6; }
-
-.flora .ui-toasterLite .ui-toasterLite-s,
-.flora.ui-toasterLite .ui-toasterLite-s { height: 8px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/toaster-s.gif) repeat scroll center top; z-index: 1; }
-
-.flora .ui-toasterLite .ui-toasterLite-e,
-.flora.ui-toasterLite .ui-toasterLite-e { width: 7px; right: 0px; top: 0px; height: 100%; background: transparent url(i/toaster-e.gif) repeat scroll right center; }
-
-.flora .ui-toasterLite .ui-toasterLite-w,
-.flora.ui-toasterLite .ui-toasterLite-w { width: 7px; left: 0px; top: 0px; height: 100%; background: url(i/toaster-w.gif) repeat scroll right center; }
-
-.flora .ui-toasterLite .ui-toasterLite-se,
-.flora.ui-toasterLite .ui-toasterLite-se { width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/toaster-se.gif); z-index: 2; }
-
-.flora .ui-toasterLite .ui-toasterLite-sw,
-.flora.ui-toasterLite .ui-toasterLite-sw { width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/toaster-sw.gif); z-index: 2; }
-
-.flora .ui-toasterLite .ui-toasterLite-nw,
-.flora.ui-toasterLite .ui-toasterLite-nw { width: 9px; height: 29px; left: 0px; top: 0px; background: transparent url(i/toaster-nw.gif); z-index: 6; }
-
-.flora .ui-toasterLite .ui-toasterLite-ne,
-.flora.ui-toasterLite .ui-toasterLite-ne { width: 9px; height: 29px; right: 0px; top: 0px; background: transparent url(i/toaster-ne.gif); z-index: 6; }
-
-/* Global handle styles */
-.ui-toasterLite-corner { position: absolute; font-size: 0.1px; }
-
-.flora .ui-toasterLite-holder,
-.flora.ui-toasterLite-holder {
- position: absolute;
-}
-.flora .ui-toasterLite-holder-pos-tr,
-.flora.ui-toasterLite-holder-pos-tr {
- top: 10px;
- right: 10px;
-}
-
-.flora .ui-toasterLite-holder-pos-tl,
-.flora.ui-toasterLite-holder-pos-tl {
- top: 10px;
- left: 10px;
-}
-
-.flora .ui-toasterLite-holder-pos-br,
-.flora.ui-toasterLite-holder-pos-br {
- bottom: 10px;
- right: 10px;
-}
-
-.flora .ui-toasterLite-holder-pos-bl,
-.flora.ui-toasterLite-holder-pos-bl {
- bottom: 10px;
- left: 10px;
-}
-
-.flora .ui-toasterLite .ui-toasterLite-titlebar-close,
-.flora.ui-toasterLite .ui-toasterLite-titlebar-close {
- width: 16px;
- height: 16px;
- background: url(i/dialog-titlebar-close.png) no-repeat;
- position:absolute;
- top: 6px;
- right: 7px;
- cursor: default;
-}
-
-.flora .ui-toasterLite .ui-toasterLite-titlebar-close-hover,
-.flora.ui-toasterLite .ui-toasterLite-titlebar-close-hover {
- background: url(i/dialog-titlebar-close-hover.png) no-repeat;
-}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.toolbar.css b/moksha/widgetbrowser/static/themes/flora/flora.toolbar.css
deleted file mode 100644
index 8ad0588..0000000
--- a/moksha/widgetbrowser/static/themes/flora/flora.toolbar.css
+++ /dev/null
@@ -1,241 +0,0 @@
-/* light.toolbar.css
- *
- * Written: 05/09/07 4:38:01 PM
- * Revision: 1.0.0
- *
- *
- * Credits:
- * Miksago: Full Coding.
- */
-
-.flora .ui-toolbar {
- position:relative;
- padding:0px;
- margin:0px;
-}
-.flora .ui-toolbar ul {
- background:#E6F7D4;
- padding:0px;
- margin:0px;
-}
- .flora .ui-toolbar ul li {
- list-style-type: none;
- }
- .flora .ui-toolbar ul.ui-toolbar-horiz {
- border-top:1px solid #5AB500;
- background:#E6F7D4 url("i/toolbars-bot-bg.gif") repeat-x bottom left;
- }
- .flora .ui-toolbar ul.ui-toolbar-horiz li {
- display:inline;
- }
- .flora .ui-toolbar ul.ui-toolbar-vert {
- padding: 0.025em 0em;
- border-left: 1px solid #111;
- border-right: 1px solid #444;
- }
- .flora .ui-toolbar ul.ui-toolbar-vert li {
- display:block;
- }
- /* This hides the text on buttons in a icon only toolbar */
- .flora .ui-toolbar ul.ui-toolbar-icons li .ui-toolbar-btn-desc {
- display:none;
- }
- /* This hides the icon on buttons in a text only toolbar */
- .flora .ui-toolbar ul.ui-toolbar-text li .ui-toolbar-btn-icon {
- display:none;
- }
- /* This is just for icon sizes, not really needed, but it's there so if icon sizes are defined.. */
- .flora .ui-toolbar ul li.ui-toolbar-btn-icon-sixteen .ui-toolbar-btn-icon {
- width:16px; height:16px;
- overflow:hidden;
- padding:2px;
- padding-left:16px;
- background:no-repeat;
- background-position:50% 50%;
- }
-
-/************************************************
- * Factory Elements:
- * - These are different kinds of items that
- * can be in a toolbar.
- *
- * Includes:
- * @ ui-toolbar-btn
- * toolbar buttons.
- * @ ui-toolbar-sep
- * toolbar separators.
- *
-*/
-
-
-
-/************************************************
- * UI-TOOLBAR-BTN
- *
- * STRUCTURE:
- * <li class="ui-toolbar-btn">
- * <span class="ui-toolbar-btn-left"><i> </i></span>
- * <span class="ui-toolbar-btn-center">
- * <button><span>{{text}}</span></button>
- * </span>
- * <span class="ui-toolbar-btn-right"><i> </i></span>
- * </li>
- *
- ************************************************/
-
-
- .flora .ui-toolbar ul li.ui-toolbar-btn {
- cursor:pointer;
- white-space: nowrap;
- position:relative;
- }
- .flora .ui-toolbar ul li .ui-toolbar-btn-left {
- width:3px;
- padding:5px 0px 1px 0;
- position:absolute;
- top:-3px;
- bottom:0px;
- left:-3px;
- height:100%;
- }
- .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left i,
- .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left i{
- width:3px; height:5px;
- padding:0px 0px 0px 0px;
- position:absolute;
- bottom:0px;
- left:0px;
- }
- .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-center,
- .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-center{
- background:url("i/accordion-middle-over.png") repeat-x left top;
- }
- .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left,
- .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left {
- background:url("i/accordion-left-over.png") no-repeat left top;
- }
- .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left i,
- .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left i{
- background:url("i/accordion-left-over.png") no-repeat left bottom;
- }
- .flora .ui-toolbar ul li .ui-toolbar-btn-center {
- padding: 0.2em 0em;
- line-height:2.2em;
- }
- .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-btn {
- vertical-align: middle;
- margin:0.3em 0.2em;
- }
- .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-btn {
- margin:0.2em;
- line-height:1.6em;
- vertical-align: middle;
- }
- .flora .ui-toolbar ul li button {
- vertical-align: middle;
- background:transparent;
- color:#000;
- border:0px none;
- cursor:pointer;
- overflow:visible;
- -moz-outline:0 none;
- outline:0 none;
- padding: 0.1em 0.1em;
- }
- .flora .ui-toolbar ul li.ui-toolbar-btn button span {
- vertical-align: middle;
- }
- /* This hides the text on buttons in a icon only toolbar */
- .flora .ui-toolbar ul.ui-toobar-iconOnly li.ui-toolbar-btn button span {
- display:none;
- }
-
- .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-center button,
- .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-center button {
- background: url("i/accordion-middle-over.png") repeat-x left bottom;
- }
- .flora .ui-toolbar ul li.ui-toolbar-btn-active {
-
- }
-
- .flora .ui-toolbar ul li.ui-toolbar-btn-disabled {
- opacity:0.2;
- }
-
-/************************************************
- * UI-TOOLBAR-BTN
- *
- * STRUCTURE:
- * <li class="ui-toolbar-sep">
- * <span>
- *
- * </span>
- * </li>
- *
- ************************************************/
- .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-sep {
- border-left:1px solid #444;
- border-right:1px solid #111;
- }
- .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-sep {
- border-top:1px solid #111;
- border-bottom:1px solid #444;
- }
-
-/************************************************
- * UI-TOOLBAR-SLIDER
- *
- * STRUCTURE:
- * <li class="ui-toolbar-slider">
- * <div class="ui-toolbar-slider-track ui-slider-track">
- * <div class="ui-slider-handle"></div>
- * </div>
- * </li>
- *
- ************************************************/
-
-.flora .ui-toolbar ul li.ui-toolbar-slider .ui-toolbar-slider-track {
- height: 20px!important;
-}
-
-/************************************************
- * UI-TOOLBAR-RADIOGRP
- *
- * STRUCTURE:
- * <li class="ui-toolbar-radioGrp">
- * <ul class="DIRECTION">
- * <li class="ui-toolbar-btn">
- * <span class="ui-toolbar-btn-left"><i> </i></span>
- * <span class="ui-toolbar-btn-center">
- * <button><span>{{text}}</span></button>
- * </span>
- * <span class="ui-toolbar-btn-right"><i> </i></span>
- * </li>
- * </ul>
- * </li>
- *
- *
- ************************************************/
-
- .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp,
- .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul,
- .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul li{
- display:inline;
- }
- .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul {
- margin:0px;
- padding:0px;
- }
-
- .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp,
- .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul,
- .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul li{
- display:block;
- }
- .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul {
- margin:0px;
- padding:0px;
- }
-
-
-/* END OF FILE */
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-left-act.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-left-act.png
deleted file mode 100644
index bf6ee99..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-left-act.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-left-over.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-left-over.png
deleted file mode 100644
index 66378e0..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-left-over.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-left.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-left.png
deleted file mode 100644
index 13344fc..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-left.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-act.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-act.png
deleted file mode 100644
index cecf4f1..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-act.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-over.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-over.png
deleted file mode 100644
index 251ad11..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-over.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle.png
deleted file mode 100644
index 5238fd4..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-right-act.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-right-act.png
deleted file mode 100644
index 1fa4792..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-right-act.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-right-over.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-right-over.png
deleted file mode 100644
index d676dad..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-right-over.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-right.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-right.png
deleted file mode 100644
index 543991a..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/accordion-right.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/asc.gif b/moksha/widgetbrowser/static/themes/flora/i/asc.gif
deleted file mode 100644
index 7415786..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/asc.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/bg.gif b/moksha/widgetbrowser/static/themes/flora/i/bg.gif
deleted file mode 100644
index fac668f..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/bg.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/desc.gif b/moksha/widgetbrowser/static/themes/flora/i/desc.gif
deleted file mode 100644
index 3b30b3c..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/desc.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-e.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-e.gif
deleted file mode 100644
index 3b8b521..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-e.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-n.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-n.gif
deleted file mode 100644
index 70887b8..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-n.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-ne.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-ne.gif
deleted file mode 100644
index ab9c38e..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-ne.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-nw.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-nw.gif
deleted file mode 100644
index e934073..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-nw.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-s.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-s.gif
deleted file mode 100644
index d5f6b99..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-s.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-se.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-se.gif
deleted file mode 100644
index 186a864..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-se.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-sw.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-sw.gif
deleted file mode 100644
index 025dfda..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-sw.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-title.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-title.gif
deleted file mode 100644
index 156c59b..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-title.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png b/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png
deleted file mode 100644
index 67c1303..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png b/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png
deleted file mode 100644
index cec974c..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-w.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-w.gif
deleted file mode 100644
index 931ff4a..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/dialog-w.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/menu-submenu.gif b/moksha/widgetbrowser/static/themes/flora/i/menu-submenu.gif
deleted file mode 100644
index 77647d8..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/menu-submenu.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-e.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-e.gif
deleted file mode 100644
index 7acf248..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-e.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-n.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-n.gif
deleted file mode 100644
index 59110f6..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-n.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-ne.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-ne.gif
deleted file mode 100644
index 515a3f8..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-ne.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-nw.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-nw.gif
deleted file mode 100644
index 665f318..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-nw.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-s.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-s.gif
deleted file mode 100644
index da2fb35..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-s.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-se.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-se.gif
deleted file mode 100644
index 6c258ef..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-se.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-sw.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-sw.gif
deleted file mode 100644
index 2fd8de4..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-sw.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-w.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-w.gif
deleted file mode 100644
index 34b875b..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/resizable-w.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/shadow.png b/moksha/widgetbrowser/static/themes/flora/i/shadow.png
deleted file mode 100644
index 4c58c7f..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/shadow.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/slider-bg-1.png b/moksha/widgetbrowser/static/themes/flora/i/slider-bg-1.png
deleted file mode 100644
index b7d806e..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/slider-bg-1.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/slider-bg-2.png b/moksha/widgetbrowser/static/themes/flora/i/slider-bg-2.png
deleted file mode 100644
index 8b24cf0..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/slider-bg-2.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/slider-handle.gif b/moksha/widgetbrowser/static/themes/flora/i/slider-handle.gif
deleted file mode 100644
index 9b89f26..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/slider-handle.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/tabs.png b/moksha/widgetbrowser/static/themes/flora/i/tabs.png
deleted file mode 100644
index 8018e41..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/tabs.png and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-e.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-e.gif
deleted file mode 100644
index 55dcb2c..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-e.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-n.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-n.gif
deleted file mode 100644
index b0fbeb9..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-n.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-ne.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-ne.gif
deleted file mode 100644
index ab9c38e..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-ne.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-nw.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-nw.gif
deleted file mode 100644
index e934073..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-nw.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-s.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-s.gif
deleted file mode 100644
index 15640e8..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-s.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-se.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-se.gif
deleted file mode 100644
index fb7a7df..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-se.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-sw.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-sw.gif
deleted file mode 100644
index ad1ae1c..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-sw.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-w.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-w.gif
deleted file mode 100644
index 8489de8..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toaster-w.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif b/moksha/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif
deleted file mode 100644
index 15640e8..0000000
Binary files a/moksha/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif and /dev/null differ
diff --git a/moksha/widgetbrowser/static/ui.base.js b/moksha/widgetbrowser/static/ui.base.js
deleted file mode 100644
index 17115f0..0000000
--- a/moksha/widgetbrowser/static/ui.base.js
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * jQuery UI @VERSION
- *
- * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI
- *
- * $Date: 2008-04-01 09:23:47 -0400 (Tue, 01 Apr 2008) $
- * $Rev: 5174 $
- */
-;(function($) {
-
- //If the UI scope is not available, add it
- $.ui = $.ui || {};
-
- //Add methods that are vital for all mouse interaction stuff (plugin registering)
- $.extend($.ui, {
- plugin: {
- add: function(module, option, set) {
- var proto = $.ui[module].prototype;
- for(var i in set) {
- proto.plugins[i] = proto.plugins[i] || [];
- proto.plugins[i].push([option, set[i]]);
- }
- },
- call: function(instance, name, arguments) {
- var set = instance.plugins[name]; if(!set) return;
- for (var i = 0; i < set.length; i++) {
- if (instance.options[set[i][0]]) set[i][1].apply(instance.element, arguments);
- }
- }
- },
- cssCache: {},
- css: function(name) {
- if ($.ui.cssCache[name]) return $.ui.cssCache[name];
- var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
-
- //if (!$.browser.safari)
- //tmp.appendTo('body');
-
- //Opera and Safari set width and height to 0px instead of auto
- //Safari returns rgba(0,0,0,0) when bgcolor is not set
- $.ui.cssCache[name] = !!(
- (!/auto|default/.test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) ||
- !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
- );
- try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){}
- return $.ui.cssCache[name];
- },
- disableSelection: function(e) {
- e.unselectable = "on";
- e.onselectstart = function() { return false; };
- if (e.style) e.style.MozUserSelect = "none";
- },
- enableSelection: function(e) {
- e.unselectable = "off";
- e.onselectstart = function() { return true; };
- if (e.style) e.style.MozUserSelect = "";
- },
- hasScroll: function(e, a) {
- var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
- if (e[scroll] > 0) return true; e[scroll] = 1;
- has = e[scroll] > 0 ? true : false; e[scroll] = 0;
- return has;
- }
- });
-
- /******* fn scope modifications ********/
-
- $.each( ['Left', 'Top'], function(i, name) {
- if(!$.fn['scroll'+name]) $.fn['scroll'+name] = function(v) {
- return v != undefined ?
- this.each(function() { this == window || this == document ? window.scrollTo(name == 'Left' ? v : $(window)['scrollLeft'](), name == 'Top' ? v : $(window)['scrollTop']()) : this['scroll'+name] = v; }) :
- this[0] == window || this[0] == document ? self[(name == 'Left' ? 'pageXOffset' : 'pageYOffset')] || $.boxModel && document.documentElement['scroll'+name] || document.body['scroll'+name] : this[0][ 'scroll' + name ];
- };
- });
-
- var _remove = $.fn.remove;
- $.fn.extend({
- position: function() {
- var offset = this.offset();
- var offsetParent = this.offsetParent();
- var parentOffset = offsetParent.offset();
-
- return {
- top: offset.top - num(this[0], 'marginTop') - parentOffset.top - num(offsetParent, 'borderTopWidth'),
- left: offset.left - num(this[0], 'marginLeft') - parentOffset.left - num(offsetParent, 'borderLeftWidth')
- };
- },
- offsetParent: function() {
- var offsetParent = this[0].offsetParent;
- while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
- offsetParent = offsetParent.offsetParent;
- return $(offsetParent);
- },
- mouseInteraction: function(o) {
- return this.each(function() {
- new $.ui.mouseInteraction(this, o);
- });
- },
- removeMouseInteraction: function(o) {
- return this.each(function() {
- if($.data(this, "ui-mouse"))
- $.data(this, "ui-mouse").destroy();
- });
- },
- remove: function() {
- jQuery("*", this).add(this).trigger("remove");
- return _remove.apply(this, arguments );
- }
- });
-
- function num(el, prop) {
- return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
- };
-
-
- /********** Mouse Interaction Plugin *********/
-
- $.ui.mouseInteraction = function(element, options) {
-
- var self = this;
- this.element = element;
-
- $.data(this.element, "ui-mouse", this);
- this.options = $.extend({}, options);
-
- $(element).bind('mousedown.draggable', function() { return self.click.apply(self, arguments); });
- if($.browser.msie) $(element).attr('unselectable', 'on'); //Prevent text selection in IE
-
- // prevent draggable-options-delay bug #2553
- $(element).mouseup(function() {
- if(self.timer) clearInterval(self.timer);
- });
- };
-
- $.extend($.ui.mouseInteraction.prototype, {
-
- destroy: function() { $(this.element).unbind('mousedown.draggable'); },
- trigger: function() { return this.click.apply(this, arguments); },
- click: function(e) {
-
- if(
- e.which != 1 //only left click starts dragging
- || $.inArray(e.target.nodeName.toLowerCase(), this.options.dragPrevention || []) != -1 // Prevent execution on defined elements
- || (this.options.condition && !this.options.condition.apply(this.options.executor || this, [e, this.element])) //Prevent execution on condition
- ) return true;
-
- var self = this;
- var initialize = function() {
- self._MP = { left: e.pageX, top: e.pageY }; // Store the click mouse position
- $(document).bind('mouseup.draggable', function() { return self.stop.apply(self, arguments); });
- $(document).bind('mousemove.draggable', function() { return self.drag.apply(self, arguments); });
-
- if(!self.initalized && Math.abs(self._MP.left-e.pageX) >= self.options.distance || Math.abs(self._MP.top-e.pageY) >= self.options.distance) {
- if(self.options.start) self.options.start.call(self.options.executor || self, e, self.element);
- if(self.options.drag) self.options.drag.call(self.options.executor || self, e, this.element); //This is actually not correct, but expected
- self.initialized = true;
- }
- };
-
- if(this.options.delay) {
- if(this.timer) clearInterval(this.timer);
- this.timer = setTimeout(initialize, this.options.delay);
- } else {
- initialize();
- }
-
- return false;
-
- },
- stop: function(e) {
-
- var o = this.options;
- if(!this.initialized) return $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
-
- if(this.options.stop) this.options.stop.call(this.options.executor || this, e, this.element);
- $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
- this.initialized = false;
- return false;
-
- },
- drag: function(e) {
-
- var o = this.options;
- if ($.browser.msie && !e.button) return this.stop.apply(this, [e]); // IE mouseup check
-
- if(!this.initialized && (Math.abs(this._MP.left-e.pageX) >= o.distance || Math.abs(this._MP.top-e.pageY) >= o.distance)) {
- if(this.options.start) this.options.start.call(this.options.executor || this, e, this.element);
- this.initialized = true;
- } else {
- if(!this.initialized) return false;
- }
-
- if(o.drag) o.drag.call(this.options.executor || this, e, this.element);
- return false;
-
- }
- });
-
-})(jQuery);
-
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/ui.dialog.js b/moksha/widgetbrowser/static/ui.dialog.js
deleted file mode 100644
index 7a907bd..0000000
--- a/moksha/widgetbrowser/static/ui.dialog.js
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * jQuery UI Dialog
- *
- * Copyright (c) 2008 Richard D. Worth (rdworth.org)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Dialog
- *
- * Depends:
- * ui.base.js
- * ui.draggable.js
- * ui.resizable.js
- *
- * Revision: $Id: ui.dialog.js 5185 2008-04-03 15:39:51Z scott.gonzalez $
- */
-;(function($) {
-
- $.fn.extend({
- dialog: function(options) {
- var args = Array.prototype.slice.call(arguments, 1);
-
- return this.each(function() {
- if (typeof options == "string") {
- var elem = $(this).is('.ui-dialog')
- ? this
- : $(this).parents(".ui-dialog:first").find(".ui-dialog-content")[0];
- var dialog = elem ? $.data(elem, "dialog") : {};
- if (dialog[options])
- dialog[options].apply(dialog, args);
- // INIT with optional options
- } else if (!$(this).is(".ui-dialog-content"))
- new $.ui.dialog(this, options);
- });
- }
- });
-
- $.ui.dialog = function(el, options) {
-
- this.options = options = $.extend({}, $.ui.dialog.defaults, options);
- this.element = el;
- var self = this; //Do bindings
-
- $.data(this.element, "dialog", this);
-
- $(el).bind("remove", function() {
- self.destroy();
- });
-
- $(el).bind("setData.dialog", function(event, key, value){
- switch (key) {
- case "draggable":
- uiDialog.draggable(value ? 'enable' : 'disable');
- break;
- case "dragStart":
- uiDialog.data('start.draggable', value);
- break;
- case "drag":
- uiDialog.data('drag.draggable', value);
- break;
- case "dragStop":
- uiDialog.data('stop.draggable', value);
- break;
- case "height":
- uiDialog.height(value);
- break;
- case "maxHeight":
- case "minHeight":
- case "maxWidth":
- case "minWidth":
- uiDialog.data(key + ".resizable", value);
- break;
- case "position":
- self.position(value);
- break;
- case "resizable":
- uiDialog.resizable(value ? 'enable' : 'disable');
- break;
- case "resizeStart":
- uiDialog.data('start.resizable', value);
- break;
- case "resize":
- uiDialog.data('resize.resizable', value);
- break;
- case "resizeStop":
- uiDialog.data('stop.resizable', value);
- break;
- case "title":
- $(".ui-dialog-title", uiDialogTitlebar).text(value);
- break;
- case "width":
- break;
- }
- options[key] = value;
- }).bind("getData.dialog", function(event, key){
- return options[key];
- });
-
- var uiDialogContent = $(el).addClass('ui-dialog-content');
-
- if (!uiDialogContent.parent().length) {
- uiDialogContent.appendTo('body');
- }
- uiDialogContent
- .wrap(document.createElement('div'))
- .wrap(document.createElement('div'));
- var uiDialogContainer = uiDialogContent.parent().addClass('ui-dialog-container').css({position: 'relative'});
- var uiDialog = this.uiDialog = uiDialogContainer.parent().hide()
- .addClass('ui-dialog')
- .css({position: 'absolute', width: options.width, height: options.height, overflow: 'hidden'});
-
- var classNames = uiDialogContent.attr('className').split(' ');
-
- // Add content classes to dialog, to inherit theme at top level of element
- $.each(classNames, function(i, className) {
- if (className != 'ui-dialog-content')
- uiDialog.addClass(className);
- });
-
- if ($.fn.resizable) {
- uiDialog.append('<div class="ui-resizable-n ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-s ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-e ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-w ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-ne ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-se ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-sw ui-resizable-handle"></div>')
- .append('<div class="ui-resizable-nw ui-resizable-handle"></div>');
- uiDialog.resizable({
- maxWidth: options.maxWidth,
- maxHeight: options.maxHeight,
- minWidth: options.minWidth,
- minHeight: options.minHeight,
- start: options.resizeStart,
- resize: options.resize,
- stop: function(e, ui) {
- options.resizeStop && options.resizeStop.apply(this, arguments);
- $.ui.dialog.overlay.resize();
- }
- });
- if (!options.resizable)
- uiDialog.resizable('disable');
- }
-
- uiDialogContainer.prepend('<div class="ui-dialog-titlebar"></div>');
- var uiDialogTitlebar = $('.ui-dialog-titlebar', uiDialogContainer);
- var title = (options.title) ? options.title : (uiDialogContent.attr('title')) ? uiDialogContent.attr('title') : '';
- uiDialogTitlebar.append('<span class="ui-dialog-title">' + title + '</span>');
- uiDialogTitlebar.append('<a href="#" class="ui-dialog-titlebar-close"><span>X</span></a>');
- this.uiDialogTitlebarClose = $('.ui-dialog-titlebar-close', uiDialogTitlebar)
- .hover(function() { $(this).addClass('ui-dialog-titlebar-close-hover'); },
- function() { $(this).removeClass('ui-dialog-titlebar-close-hover'); })
- .mousedown(function(ev) {
- ev.stopPropagation();
- })
- .click(function() {
- self.close();
- return false;
- })
- .keydown(function(ev) {
- var ESC = 27;
- ev.keyCode && ev.keyCode == ESC && self.close();
- });
-
- var l = 0;
- $.each(options.buttons, function() { l = 1; return false; });
- if (l == 1) {
- uiDialog.append('<div class="ui-dialog-buttonpane"></div>');
- var uiDialogButtonPane = $('.ui-dialog-buttonpane', uiDialog);
- $.each(options.buttons, function(name, value) {
- var btn = $(document.createElement('button')).text(name).click(value);
- uiDialogButtonPane.append(btn);
- });
- }
-
- if ($.fn.draggable) {
- uiDialog.draggable({
- handle: '.ui-dialog-titlebar',
- start: function(e, ui) {
- self.activate();
- options.dragStart && options.dragStart.apply(this, arguments);
- },
- drag: options.drag,
- stop: function(e, ui) {
- options.dragStop && options.dragStop.apply(this, arguments);
- $.ui.dialog.overlay.resize();
- }
- });
- if (!options.draggable)
- uiDialog.draggable('disable')
- }
-
- uiDialog.mousedown(function() {
- self.activate();
- });
- uiDialogTitlebar.click(function() {
- self.activate();
- });
-
- options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe();
-
- this.position = function(pos) {
- var wnd = $(window), doc = $(document), top = doc.scrollTop(), left = doc.scrollLeft();
- if (pos.constructor == Array) {
- // [x, y]
- top += pos[1];
- left += pos[0];
- } else {
- switch (pos) {
- case 'center':
- top += (wnd.height() / 2) - (uiDialog.height() / 2);
- left += (wnd.width() / 2) - (uiDialog.width() / 2);
- break;
- case 'top':
- top += 0;
- left += (wnd.width() / 2) - (uiDialog.width() / 2);
- break;
- case 'right':
- top += (wnd.height() / 2) - (uiDialog.height() / 2);
- left += (wnd.width()) - (uiDialog.width());
- break;
- case 'bottom':
- top += (wnd.height()) - (uiDialog.height());
- left += (wnd.width() / 2) - (uiDialog.width() / 2);
- break;
- case 'left':
- top += (wnd.height() / 2) - (uiDialog.height() / 2);
- left += 0;
- break;
- default:
- //center
- top += (wnd.height() / 2) - (uiDialog.height() / 2);
- left += (wnd.width() / 2) - (uiDialog.width() / 2);
- }
- }
- top = top < doc.scrollTop() ? doc.scrollTop() : top;
- uiDialog.css({top: top, left: left});
- }
-
- this.open = function() {
- this.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
- uiDialog.appendTo('body');
- this.position(options.position);
- uiDialog.show();
- self.moveToTop();
- self.activate();
-
- // CALLBACK: open
- var openEV = null;
- var openUI = {
- options: options
- };
- this.uiDialogTitlebarClose.focus();
- $(this.element).triggerHandler("dialogopen", [openEV, openUI], options.open);
- };
-
- this.activate = function() {
- // Move modeless dialogs to the top when they're activated. Even
- // if there is a modal dialog in the window, the modeless dialog
- // should be on top because it must have been opened after the modal
- // dialog. Modal dialogs don't get moved to the top because that
- // would make any modeless dialogs that it spawned unusable until
- // the modal dialog is closed.
- !options.modal && this.moveToTop();
- };
-
- this.moveToTop = function() {
- var maxZ = options.zIndex;
- $('.ui-dialog:visible').each(function() {
- maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10) || options.zIndex);
- });
- this.overlay && this.overlay.$el.css('z-index', ++maxZ);
- uiDialog.css('z-index', ++maxZ);
- };
-
- this.close = function() {
- this.overlay && this.overlay.destroy();
- uiDialog.hide();
-
- // CALLBACK: close
- var closeEV = null;
- var closeUI = {
- options: options
- };
- $(this.element).triggerHandler("dialogclose", [closeEV, closeUI], options.close);
- $.ui.dialog.overlay.resize();
- };
-
- this.destroy = function() {
- this.overlay && this.overlay.destroy();
- uiDialog.hide();
- $(el).unbind('.dialog').removeClass('ui-dialog-content').hide().appendTo('body');
- uiDialog.remove();
- $.removeData(this.element, "dialog");
- };
-
- if (options.autoOpen) {
- this.open();
- };
- };
-
- $.extend($.ui.dialog, {
- defaults: {
- autoOpen: true,
- bgiframe: false,
- buttons: [],
- draggable: true,
- height: 200,
- minHeight: 100,
- minWidth: 150,
- modal: false,
- overlay: {},
- position: 'center',
- resizable: true,
- width: 300,
- zIndex: 1000
- },
-
- overlay: function(dialog) {
- this.$el = $.ui.dialog.overlay.create(dialog);
- }
- });
-
- $.extend($.ui.dialog.overlay, {
- instances: [],
- events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
- function(e) { return e + '.dialog-overlay'; }).join(' '),
- create: function(dialog) {
- if (this.instances.length === 0) {
- // prevent use of anchors and inputs
- $('a, :input').bind(this.events, function() {
- // allow use of the element if inside a dialog and
- // - there are no modal dialogs
- // - there are modal dialogs, but we are in front of the
- // topmost modal dialog
- var allow = false;
- var $dialog = $(this).parents('.ui-dialog');
- if ($dialog.length) {
- var $overlays = $('.ui-dialog-overlay');
- if ($overlays.length) {
- var maxZ = parseInt($overlays.css('z-index'), 10);
- $overlays.each(function() {
- maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10));
- });
- allow = parseInt($dialog.css('z-index'), 10) > maxZ;
- } else {
- allow = true;
- }
- }
- return allow;
- });
-
- // allow closing by pressing the escape key
- $(document).bind('keydown.dialog-overlay', function(e) {
- var ESC = 27;
- e.keyCode && e.keyCode == ESC && dialog.close();
- });
-
- // handle window resize
- $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
- }
-
- var $el = $('<div/>').appendTo(document.body)
- .addClass('ui-dialog-overlay').css($.extend({
- borderWidth: 0, margin: 0, padding: 0,
- position: 'absolute', top: 0, left: 0,
- width: this.width(),
- height: this.height()
- }, dialog.options.overlay));
-
- dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe();
-
- this.instances.push($el);
- return $el;
- },
-
- destroy: function($el) {
- this.instances.splice($.inArray(this.instances, $el), 1);
-
- if (this.instances.length === 0) {
- $('a, :input').add([document, window]).unbind('.dialog-overlay');
- }
-
- $el.remove();
- },
-
- height: function() {
- if ($.browser.msie && $.browser.version < 7) {
- var scrollHeight = Math.max(
- document.documentElement.scrollHeight,
- document.body.scrollHeight
- );
- var offsetHeight = Math.max(
- document.documentElement.offsetHeight,
- document.body.offsetHeight
- );
-
- if (scrollHeight < offsetHeight) {
- return $(window).height() + 'px';
- } else {
- return scrollHeight + 'px';
- }
- } else {
- return $(document).height() + 'px';
- }
- },
-
- width: function() {
- if ($.browser.msie && $.browser.version < 7) {
- var scrollWidth = Math.max(
- document.documentElement.scrollWidth,
- document.body.scrollWidth
- );
- var offsetWidth = Math.max(
- document.documentElement.offsetWidth,
- document.body.offsetWidth
- );
-
- if (scrollWidth < offsetWidth) {
- return $(window).width() + 'px';
- } else {
- return scrollWidth + 'px';
- }
- } else {
- return $(document).width() + 'px';
- }
- },
-
- resize: function() {
- /* If the dialog is draggable and the user drags it past the
- * right edge of the window, the document becomes wider so we
- * need to stretch the overlay. If the user then drags the
- * dialog back to the left, the document will become narrower,
- * so we need to shrink the overlay to the appropriate size.
- * This is handled by shrinking the overlay before setting it
- * to the full document size.
- */
- var $overlays = $([]);
- $.each($.ui.dialog.overlay.instances, function() {
- $overlays = $overlays.add(this);
- });
-
- $overlays.css({
- width: 0,
- height: 0
- }).css({
- width: $.ui.dialog.overlay.width(),
- height: $.ui.dialog.overlay.height()
- });
- }
- });
-
- $.extend($.ui.dialog.overlay.prototype, {
- destroy: function() {
- $.ui.dialog.overlay.destroy(this.$el);
- }
- });
-
-})(jQuery);
diff --git a/moksha/widgetbrowser/static/ui.draggable.js b/moksha/widgetbrowser/static/ui.draggable.js
deleted file mode 100644
index ce209db..0000000
--- a/moksha/widgetbrowser/static/ui.draggable.js
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * jQuery UI Draggable
- *
- * Copyright (c) 2008 Paul Bakaus
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Draggables
- *
- * Depends:
- * ui.base.js
- *
- * Revision: $Id: ui.draggable.js 5194 2008-04-04 12:30:10Z paul.bakaus $
- */
-;(function($) {
-
- $.fn.extend({
- draggable: function(options) {
- var args = Array.prototype.slice.call(arguments, 1);
-
- return this.each(function() {
- if (typeof options == "string") {
- var drag = $.data(this, "draggable");
- if(drag) drag[options].apply(drag, args);
-
- } else if(!$.data(this, "draggable"))
- new $.ui.draggable(this, options);
- });
- }
- });
-
- $.ui.draggable = function(element, options) {
- //Initialize needed constants
- var self = this;
-
- this.element = $(element);
-
- $.data(element, "draggable", this);
- this.element.addClass("ui-draggable");
-
- //Prepare the passed options
- this.options = $.extend({}, options);
- var o = this.options;
- $.extend(o, {
- helper: o.ghosting == true ? 'clone' : (o.helper || 'original'),
- handle : o.handle ? ($(o.handle, element)[0] ? $(o.handle, element) : this.element) : this.element,
- appendTo: o.appendTo || 'parent'
- });
-
- $(element).bind("setData.draggable", function(event, key, value){
- self.options[key] = value;
- }).bind("getData.draggable", function(event, key){
- return self.options[key];
- });
-
- //Initialize mouse events for interaction
- $(o.handle).mouseInteraction({
- executor: this,
- delay: o.delay,
- distance: o.distance || 1,
- dragPrevention: o.cancel || o.cancel === '' ? o.cancel.toLowerCase().split(',') : ['input','textarea','button','select','option'],
- start: this.start,
- stop: this.stop,
- drag: this.drag,
- condition: function(e) { return !(e.target.className.indexOf("ui-resizable-handle") != -1 || this.options.disabled); }
- });
-
- //Position the node
- if(o.helper == 'original' && (this.element.css('position') == 'static' || this.element.css('position') == ''))
- this.element.css('position', 'relative');
-
- //Prepare cursorAt
- if(o.cursorAt && o.cursorAt.constructor == Array)
- o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] };
-
- };
-
- $.extend($.ui.draggable.prototype, {
- plugins: {},
- ui: function(e) {
- return {
- helper: this.helper,
- position: this.position,
- absolutePosition: this.positionAbs,
- instance: this,
- options: this.options,
- element: this.element
- };
- },
- propagate: function(n,e) {
- $.ui.plugin.call(this, n, [e, this.ui()]);
- return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [e, this.ui()], this.options[n]);
- },
- destroy: function() {
- if(!$.data(this.element[0], 'draggable')) return;
- this.options.handle.removeMouseInteraction();
- this.element
- .removeClass("ui-draggable ui-draggable-disabled")
- .removeData("draggable")
- .unbind(".draggable");
- },
- enable: function() {
- this.element.removeClass("ui-draggable-disabled");
- this.options.disabled = false;
- },
- disable: function() {
- this.element.addClass("ui-draggable-disabled");
- this.options.disabled = true;
- },
- setContrains: function(minLeft,maxLeft,minTop,maxTop) {
- this.minLeft = minLeft; this.maxLeft = maxLeft;
- this.minTop = minTop; this.maxTop = maxTop;
- this.constrainsSet = true;
- },
- checkConstrains: function() {
- if(!this.constrainsSet) return;
- if(this.position.left < this.minLeft) this.position.left = this.minLeft;
- if(this.position.left > this.maxLeft - this.helperProportions.width) this.position.left = this.maxLeft - this.helperProportions.width;
- if(this.position.top < this.minTop) this.position.top = this.minTop;
- if(this.position.top > this.maxTop - this.helperProportions.height) this.position.top = this.maxTop - this.helperProportions.height;
- },
- recallOffset: function(e) {
-
- var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top };
- var r = this.helper.css('position') == 'relative';
-
- //Generate the original position
- this.originalPosition = {
- left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)),
- top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop))
- };
-
- //Generate a flexible offset that will later be subtracted from e.pageX/Y
- this.offset = {left: this._pageX - this.originalPosition.left, top: this._pageY - this.originalPosition.top };
-
- },
- start: function(e) {
- var o = this.options;
- if($.ui.ddmanager) $.ui.ddmanager.current = this;
-
- //Create and append the visible helper
- this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone().appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)) : this.element);
- if(this.helper[0] != this.element[0]) this.helper.css('position', 'absolute');
- if(!this.helper.parents('body').length) this.helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
-
-
- //Find out the next positioned parent
- this.offsetParent = (function(cp) {
- while(cp) {
- if(cp.style && (/(absolute|relative|fixed)/).test($.css(cp,'position'))) return $(cp);
- cp = cp.parentNode ? cp.parentNode : null;
- }; return $("body");
- })(this.helper[0].parentNode);
-
- //Prepare variables for position generation
- this.elementOffset = this.element.offset();
- this.offsetParentOffset = this.offsetParent.offset();
- var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top };
- this._pageX = e.pageX; this._pageY = e.pageY;
- this.clickOffset = { left: e.pageX - this.elementOffset.left, top: e.pageY - this.elementOffset.top };
- var r = this.helper.css('position') == 'relative';
-
- //Generate the original position
- this.originalPosition = {
- left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)),
- top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop))
- };
-
- //If we have a fixed element, we must subtract the scroll offset again
- if(this.element.css('position') == 'fixed') {
- this.originalPosition.top -= this.offsetParent[0] == document.body ? $(document).scrollTop() : this.offsetParent[0].scrollTop;
- this.originalPosition.left -= this.offsetParent[0] == document.body ? $(document).scrollLeft() : this.offsetParent[0].scrollLeft;
- }
-
- //Generate a flexible offset that will later be subtracted from e.pageX/Y
- this.offset = {left: e.pageX - this.originalPosition.left, top: e.pageY - this.originalPosition.top };
-
- //Substract margins
- if(this.element[0] != this.helper[0]) {
- this.offset.left += parseInt(this.element.css('marginLeft'),10) || 0;
- this.offset.top += parseInt(this.element.css('marginTop'),10) || 0;
- }
-
- //Call plugins and callbacks
- this.propagate("start", e);
-
- this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };
- if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e);
-
- //If we have something in cursorAt, we'll use it
- if(o.cursorAt) {
- if(o.cursorAt.top != undefined || o.cursorAt.bottom != undefined) {
- this.offset.top -= this.clickOffset.top - (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom));
- this.clickOffset.top = (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom));
- }
- if(o.cursorAt.left != undefined || o.cursorAt.right != undefined) {
- this.offset.left -= this.clickOffset.left - (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right));
- this.clickOffset.left = (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right));
- }
- }
-
- return false;
-
- },
- clear: function() {
- if($.ui.ddmanager) $.ui.ddmanager.current = null;
- this.helper = null;
- },
- stop: function(e) {
-
- //If we are using droppables, inform the manager about the drop
- if ($.ui.ddmanager && !this.options.dropBehaviour)
- $.ui.ddmanager.drop(this, e);
-
- //Call plugins and trigger callbacks
- this.propagate("stop", e);
-
- if(this.cancelHelperRemoval) return false;
- if(this.options.helper != 'original') this.helper.remove();
- this.clear();
-
- return false;
- },
- drag: function(e) {
-
- //Compute the helpers position
- this.position = { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left };
- this.positionAbs = { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top };
-
- //Call plugins and callbacks
- this.checkConstrains();
- this.position = this.propagate("drag", e) || this.position;
- this.checkConstrains();
-
- $(this.helper).css({ left: this.position.left+'px', top: this.position.top+'px' }); // Stick the helper to the cursor
- if($.ui.ddmanager) $.ui.ddmanager.drag(this, e);
- return false;
-
- }
- });
-
-/*
- * Draggable Extensions
- */
-
- $.ui.plugin.add("draggable", "cursor", {
- start: function(e, ui) {
- var t = $('body');
- if (t.css("cursor")) ui.options._cursor = t.css("cursor");
- t.css("cursor", ui.options.cursor);
- },
- stop: function(e, ui) {
- if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
- }
- });
-
- $.ui.plugin.add("draggable", "zIndex", {
- start: function(e, ui) {
- var t = $(ui.helper);
- if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
- t.css('zIndex', ui.options.zIndex);
- },
- stop: function(e, ui) {
- if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
- }
- });
-
- $.ui.plugin.add("draggable", "opacity", {
- start: function(e, ui) {
- var t = $(ui.helper);
- if(t.css("opacity")) ui.options._opacity = t.css("opacity");
- t.css('opacity', ui.options.opacity);
- },
- stop: function(e, ui) {
- if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
- }
- });
-
-
- $.ui.plugin.add("draggable", "revert", {
- stop: function(e, ui) {
- var self = ui.instance, helper = $(self.helper);
- self.cancelHelperRemoval = true;
-
- $(ui.helper).animate({ left: self.originalPosition.left, top: self.originalPosition.top }, parseInt(ui.options.revert, 10) || 500, function() {
- if(ui.options.helper != 'original') helper.remove();
- if (!helper) self.clear();
- });
- }
- });
-
- $.ui.plugin.add("draggable", "iframeFix", {
- start: function(e, ui) {
-
- var o = ui.options;
- if(ui.instance.slowMode) return; // Make clones on top of iframes (only if we are not in slowMode)
-
- if(o.iframeFix.constructor == Array) {
- for(var i=0;i<o.iframeFix.length;i++) {
- var co = $(o.iframeFix[i]).offset({ border: false });
- $('<div class="DragDropIframeFix"" style="background: #fff;"></div>').css("width", $(o.iframeFix[i])[0].offsetWidth+"px").css("height", $(o.iframeFix[i])[0].offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body");
- }
- } else {
- $("iframe").each(function() {
- var co = $(this).offset({ border: false });
- $('<div class="DragDropIframeFix" style="background: #fff;"></div>').css("width", this.offsetWidth+"px").css("height", this.offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body");
- });
- }
-
- },
- stop: function(e, ui) {
- if(ui.options.iframeFix) $("div.DragDropIframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
- }
- });
-
- $.ui.plugin.add("draggable", "containment", {
- start: function(e, ui) {
-
- var o = ui.options;
- var self = ui.instance;
- if((o.containment.left != undefined || o.containment.constructor == Array) && !o._containment) return;
- if(!o._containment) o._containment = o.containment;
-
- if(o._containment == 'parent') o._containment = this[0].parentNode;
- if(o._containment == 'document') {
- o.containment = [
- 0,
- 0,
- $(document).width(),
- ($(document).height() || document.body.parentNode.scrollHeight)
- ];
- } else { //I'm a node, so compute top/left/right/bottom
-
- var ce = $(o._containment)[0];
- var co = $(o._containment).offset();
-
- o.containment = [
- co.left,
- co.top,
- co.left+(ce.offsetWidth || ce.scrollWidth),
- co.top+(ce.offsetHeight || ce.scrollHeight)
- ];
- }
-
- var c = o.containment;
- ui.instance.setContrains(
- c[0] - (self.offset.left - self.clickOffset.left), //min left
- c[2] - (self.offset.left - self.clickOffset.left), //max left
- c[1] - (self.offset.top - self.clickOffset.top), //min top
- c[3] - (self.offset.top - self.clickOffset.top) //max top
- );
-
- }
- });
-
- $.ui.plugin.add("draggable", "grid", {
- drag: function(e, ui) {
- var o = ui.options;
- var newLeft = ui.instance.originalPosition.left + Math.round((e.pageX - ui.instance._pageX) / o.grid[0]) * o.grid[0];
- var newTop = ui.instance.originalPosition.top + Math.round((e.pageY - ui.instance._pageY) / o.grid[1]) * o.grid[1];
-
- ui.instance.position.left = newLeft;
- ui.instance.position.top = newTop;
-
- }
- });
-
- $.ui.plugin.add("draggable", "axis", {
- drag: function(e, ui) {
- var o = ui.options;
- if(o.constraint) o.axis = o.constraint; //Legacy check
- switch (o.axis) {
- case 'x' : ui.instance.position.top = ui.instance.originalPosition.top; break;
- case 'y' : ui.instance.position.left = ui.instance.originalPosition.left; break;
- }
- }
- });
-
- $.ui.plugin.add("draggable", "scroll", {
- start: function(e, ui) {
- var o = ui.options;
- o.scrollSensitivity = o.scrollSensitivity || 20;
- o.scrollSpeed = o.scrollSpeed || 20;
-
- ui.instance.overflowY = function(el) {
- do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode);
- return $(document);
- }(this);
- ui.instance.overflowX = function(el) {
- do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode);
- return $(document);
- }(this);
- },
- drag: function(e, ui) {
-
- var o = ui.options;
- var i = ui.instance;
-
- if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') {
- if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)
- i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed;
- if((ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)
- i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed;
- } else {
- //$(document.body).append('<p>'+(e.pageY - $(document).scrollTop())+'</p>');
- if(e.pageY - $(document).scrollTop() < o.scrollSensitivity)
- $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
- if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity)
- $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
- }
-
- if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') {
- if(i.overflowX[0].offsetWidth - (ui.position.left - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity)
- i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed;
- if((ui.position.top - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity)
- i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed;
- } else {
- if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity)
- $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
- if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
- $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
- }
-
- ui.instance.recallOffset(e);
-
- }
- });
-
- $.ui.plugin.add("draggable", "snap", {
- start: function(e, ui) {
-
- ui.instance.snapElements = [];
- $(ui.options.snap === true ? '.ui-draggable' : ui.options.snap).each(function() {
- var $t = $(this); var $o = $t.offset();
- if(this != ui.instance.element[0]) ui.instance.snapElements.push({
- item: this,
- width: $t.outerWidth(),
- height: $t.outerHeight(),
- top: $o.top,
- left: $o.left
- });
- });
-
- },
- drag: function(e, ui) {
-
- var d = ui.options.snapTolerance || 20;
- var x1 = ui.absolutePosition.left, x2 = x1 + ui.instance.helperProportions.width,
- y1 = ui.absolutePosition.top, y2 = y1 + ui.instance.helperProportions.height;
-
- for (var i = ui.instance.snapElements.length - 1; i >= 0; i--){
-
- var l = ui.instance.snapElements[i].left, r = l + ui.instance.snapElements[i].width,
- t = ui.instance.snapElements[i].top, b = t + ui.instance.snapElements[i].height;
-
- //Yes, I know, this is insane ;)
- if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) continue;
-
- if(ui.options.snapMode != 'inner') {
- var ts = Math.abs(t - y2) <= 20;
- var bs = Math.abs(b - y1) <= 20;
- var ls = Math.abs(l - x2) <= 20;
- var rs = Math.abs(r - x1) <= 20;
- if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height;
- if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top;
- if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width;
- if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left;
- }
-
- if(ui.options.snapMode != 'outer') {
- var ts = Math.abs(t - y1) <= 20;
- var bs = Math.abs(b - y2) <= 20;
- var ls = Math.abs(l - x1) <= 20;
- var rs = Math.abs(r - x2) <= 20;
- if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top;
- if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height;
- if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left;
- if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width;
- }
-
- };
- }
- });
-
- $.ui.plugin.add("draggable", "connectToSortable", {
- start: function(e,ui) {
- ui.instance.sortable = $.data($(ui.options.connectToSortable)[0], 'sortable');
- ui.instance.sortableOffset = ui.instance.sortable.element.offset();
- ui.instance.sortableOuterWidth = ui.instance.sortable.element.outerWidth();
- ui.instance.sortableOuterHeight = ui.instance.sortable.element.outerHeight();
- if(ui.instance.sortable.options.revert) ui.instance.sortable.shouldRevert = true;
- },
- stop: function(e,ui) {
- //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
- var inst = ui.instance.sortable;
- if(inst.isOver) {
- inst.isOver = 0;
- ui.instance.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
- inst.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
- if(inst.shouldRevert) inst.options.revert = true; //revert here
- inst.stop(e);
- inst.options.helper = "original";
- }
- },
- drag: function(e,ui) {
- //This is handy: We reuse the intersectsWith method for checking if the current draggable helper
- //intersects with the sortable container
- var inst = ui.instance.sortable;
- ui.instance.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix
-
- if(inst.intersectsWith.call(ui.instance, {
- left: ui.instance.sortableOffset.left, top: ui.instance.sortableOffset.top,
- width: ui.instance.sortableOuterWidth, height: ui.instance.sortableOuterHeight
- })) {
- //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
- if(!inst.isOver) {
- inst.isOver = 1;
-
- //Cache the width/height of the new helper
- var height = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerHeight() : $(inst.options.items, inst.element).innerHeight();
- var width = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerWidth() : $(inst.options.items, inst.element).innerWidth();
-
- //Now we fake the start of dragging for the sortable instance,
- //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
- //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
- inst.currentItem = $(this).clone().appendTo(inst.element);
- inst.options.helper = function() { return ui.helper[0]; };
- inst.start(e);
-
- //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
- inst.clickOffset.top = ui.instance.clickOffset.top;
- inst.clickOffset.left = ui.instance.clickOffset.left;
- inst.offset.left -= ui.absolutePosition.left - inst.position.absolute.left;
- inst.offset.top -= ui.absolutePosition.top - inst.position.absolute.top;
-
- //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now)
- inst.helperProportions = { width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there
- ui.helper.animate({ height: height, width: width}, 500);
- ui.instance.propagate("toSortable", e);
-
- }
-
- //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
- if(inst.currentItem) inst.drag(e);
-
- } else {
-
- //If it doesn't intersect with the sortable, and it intersected before,
- //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
- if(inst.isOver) {
- inst.isOver = 0;
- inst.cancelHelperRemoval = true;
- inst.options.revert = false; //No revert here
- inst.stop(e);
- inst.options.helper = "original";
-
- //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
- inst.currentItem.remove();
- inst.placeholder.remove();
-
- ui.helper.animate({ height: this.innerHeight(), width: this.innerWidth() }, 500);
- ui.instance.propagate("fromSortable", e);
- }
-
- };
- }
- })
-
- //TODO: wrapHelper
-
-})(jQuery);
-
diff --git a/moksha/widgetbrowser/static/ui.resizable.js b/moksha/widgetbrowser/static/ui.resizable.js
deleted file mode 100644
index 409195e..0000000
--- a/moksha/widgetbrowser/static/ui.resizable.js
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * jQuery UI Resizable
- *
- * Copyright (c) 2008 Paul Bakaus
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Resizables
- *
- * Depends:
- * ui.base.js
- *
- * Revision: $Id: ui.resizable.js 5205 2008-04-06 16:12:50Z braeker $
- */
-;(function($) {
-
- $.fn.extend({
- resizable: function(options, data) {
- var args = Array.prototype.slice.call(arguments, 1);
-
- return this.each(function() {
- if (typeof options == "string") {
- var resize = $.data(this, "resizable");
- if (resize) resize[options].apply(resize, args);
-
- } else if(!$(this).is(".ui-resizable"))
- new $.ui.resizable(this, options);
- });
- }
- });
-
- $.ui.resizable = function(element, options) {
- //Initialize needed constants
- var self = this;
-
- this.element = $(element);
-
- $.data(element, "resizable", this);
-
- // simulate .ui-resizable { position: relative; }
- var elpos = this.element.css('position');
- this.element.addClass("ui-resizable").css({ position: /static/.test(elpos) ? 'relative' : elpos });
-
- //Prepare the passed options
- this.options = $.extend({
- preventDefault: true,
- transparent: false,
- minWidth: 10,
- minHeight: 10,
- aspectRatio: false,
- disableSelection: true,
- preserveCursor: true,
- autohide: false,
- knobHandles: false
- }, options);
-
- this.options._aspectRatio = !!(this.options.aspectRatio);
-
- // force proxy if helper is enabled
- this.options.proxy = this.options.proxy || this.options.ghost ? 'proxy' : null;
-
- // force proxy if animation is enabled
- this.options.proxy = this.options.proxy || this.options.animate ? 'proxy' : null;
-
- // if knobHandles equals true set to ui-resizable-knob-handle
- this.options.knobHandles = this.options.knobHandles === true ? 'ui-resizable-knob-handle' : this.options.knobHandles;
-
- $(element).bind("setData.resizable", function(event, key, value){
- self.options[key] = value;
- }).bind("getData.resizable", function(event, key){
- return self.options[key];
- });
-
- var o = this.options;
-
- //Default Theme
- var aBorder = '1px solid #DEDEDE';
-
- o.defaultTheme = {
- 'ui-resizable': { display: 'block' },
- 'ui-resizable-handle': { position: 'absolute', background: '#F2F2F2', fontSize: '0.1px' },
- 'ui-resizable-n': { cursor: 'n-resize', height: '4px', left: '0px', right: '0px', borderTop: aBorder },
- 'ui-resizable-s': { cursor: 's-resize', height: '4px', left: '0px', right: '0px', borderBottom: aBorder },
- 'ui-resizable-e': { cursor: 'e-resize', width: '4px', top: '0px', bottom: '0px', borderRight: aBorder },
- 'ui-resizable-w': { cursor: 'w-resize', width: '4px', top: '0px', bottom: '0px', borderLeft: aBorder },
- 'ui-resizable-se': { cursor: 'se-resize', width: '4px', height: '4px', borderRight: aBorder, borderBottom: aBorder },
- 'ui-resizable-sw': { cursor: 'sw-resize', width: '4px', height: '4px', borderBottom: aBorder, borderLeft: aBorder },
- 'ui-resizable-ne': { cursor: 'ne-resize', width: '4px', height: '4px', borderRight: aBorder, borderTop: aBorder },
- 'ui-resizable-nw': { cursor: 'nw-resize', width: '4px', height: '4px', borderLeft: aBorder, borderTop: aBorder }
- };
-
- o.knobTheme = {
- 'ui-resizable-handle': { background: '#F2F2F2', border: '1px solid #808080', height: '8px', width: '8px' },
- 'ui-resizable-n': { cursor: 'n-resize', top: '-4px', left: '45%' },
- 'ui-resizable-s': { cursor: 's-resize', bottom: '-4px', left: '45%' },
- 'ui-resizable-e': { cursor: 'e-resize', right: '-4px', top: '45%' },
- 'ui-resizable-w': { cursor: 'w-resize', left: '-4px', top: '45%' },
- 'ui-resizable-se': { cursor: 'se-resize', right: '-4px', bottom: '-4px' },
- 'ui-resizable-sw': { cursor: 'sw-resize', left: '-4px', bottom: '-4px' },
- 'ui-resizable-nw': { cursor: 'nw-resize', left: '-4px', top: '-4px' },
- 'ui-resizable-ne': { cursor: 'ne-resize', right: '-4px', top: '-4px' }
- };
-
- //Position the node
- if(!o.proxy && (this.element.css('position') == 'static' || this.element.css('position') === ''))
- this.element.css('position', 'relative');
-
- o._nodeName = element.nodeName;
-
- //Wrap the element if it cannot hold child nodes
- if(o._nodeName.match(/textarea|input|select|button|img/i)) {
- var el = this.element;
-
- //Opera fixing relative position
- if (/relative/.test(el.css('position')) && $.browser.opera)
- el.css({ position: 'relative', top: 'auto', left: 'auto' });
-
- //Create a wrapper element and set the wrapper to the new current internal element
- el.wrap(
- $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css( {
- position: el.css('position'),
- width: el.outerWidth(),
- height: el.outerHeight(),
- top: el.css('top'),
- left: el.css('left')
- })
- );
-
- var oel = this.element; element = element.parentNode; this.element = $(element);
-
- //Move margins to the wrapper
- this.element.css({ marginLeft: oel.css("marginLeft"), marginTop: oel.css("marginTop"),
- marginRight: oel.css("marginRight"), marginBottom: oel.css("marginBottom")
- });
-
- oel.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
-
- //Prevent Safari textarea resize
- if ($.browser.safari && o.preventDefault) oel.css('resize', 'none');
-
- o.proportionallyResize = oel.css({ position: 'static', zoom: 1, display: 'block' });
-
- // avoid IE jump
- this.element.css({ margin: oel.css('margin') });
-
- // fix handlers offset
- this._proportionallyResize();
- }
-
- if(!o.handles) o.handles = !$('.ui-resizable-handle', element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' };
- if(o.handles.constructor == String) {
-
- if(o.handles == 'all') o.handles = 'n,e,s,w,se,sw,ne,nw';
-
- var n = o.handles.split(","); o.handles = {};
-
- o.zIndex = o.zIndex || 1000;
-
- // insertions are applied when don't have theme loaded
- var insertionsDefault = {
- handle: 'position: absolute; display: none; overflow:hidden;',
- n: 'top: 0pt; width:100%;',
- e: 'right: 0pt; height:100%;',
- s: 'bottom: 0pt; width:100%;',
- w: 'left: 0pt; height:100%;',
- se: 'bottom: 0pt; right: 0px;',
- sw: 'bottom: 0pt; left: 0px;',
- ne: 'top: 0pt; right: 0px;',
- nw: 'top: 0pt; left: 0px;'
- };
-
- for(var i = 0; i < n.length; i++) {
- var handle = jQuery.trim(n[i]), dt = o.defaultTheme, hname = 'ui-resizable-'+handle, loadDefault = !$.ui.css(hname) && !o.knobHandles, userKnobClass = $.ui.css('ui-resizable-knob-handle'),
- allDefTheme = $.extend(dt[hname], dt['ui-resizable-handle']), allKnobTheme = $.extend(o.knobTheme[hname], !userKnobClass ? o.knobTheme['ui-resizable-handle'] : {});
-
- // increase zIndex of sw, se, ne, nw axis
- var applyZIndex = /sw|se|ne|nw/.test(handle) ? { zIndex: ++o.zIndex } : {};
-
- var defCss = (loadDefault ? insertionsDefault[handle] : ''),
- axis = $(['<div class="ui-resizable-handle ', hname, '" style="', defCss, insertionsDefault.handle, '"></div>'].join('')).css( applyZIndex );
- o.handles[handle] = '.ui-resizable-'+handle;
-
- this.element.append(
- //Theme detection, if not loaded, load o.defaultTheme
- axis.css( loadDefault ? allDefTheme : {} )
- // Load the knobHandle css, fix width, height, top, left...
- .css( o.knobHandles ? allKnobTheme : {} ).addClass(o.knobHandles ? 'ui-resizable-knob-handle' : '').addClass(o.knobHandles)
- );
- }
-
- if (o.knobHandles) this.element.addClass('ui-resizable-knob').css( !$.ui.css('ui-resizable-knob') ? { /*border: '1px #fff dashed'*/ } : {} );
- }
-
- this._renderAxis = function(target) {
- target = target || this.element;
-
- for(var i in o.handles) {
- if(o.handles[i].constructor == String)
- o.handles[i] = $(o.handles[i], element).show();
-
- if (o.transparent)
- o.handles[i].css({opacity:0});
-
- //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
- if (this.element.is('.ui-wrapper') &&
- o._nodeName.match(/textarea|input|select|button/i)) {
-
- var axis = $(o.handles[i], element), padWrapper = 0;
-
- //Checking the correct pad and border
- padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
-
- //The padding type i have to apply...
- var padPos = [ 'padding',
- /ne|nw|n/.test(i) ? 'Top' :
- /se|sw|s/.test(i) ? 'Bottom' :
- /^e$/.test(i) ? 'Right' : 'Left' ].join("");
-
- if (!o.transparent)
- target.css(padPos, padWrapper);
-
- this._proportionallyResize();
- }
- if(!$(o.handles[i]).length) continue;
- }
- };
-
- this._renderAxis(this.element);
- o._handles = $('.ui-resizable-handle', self.element);
-
- if (o.disableSelection)
- o._handles.each(function(i, e) { $.ui.disableSelection(e); });
-
- //Matching axis name
- o._handles.mouseover(function() {
- if (!o.resizing) {
- if (this.className)
- var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
- //Axis, default = se
- self.axis = o.axis = axis && axis[1] ? axis[1] : 'se';
- }
- });
-
- //If we want to auto hide the elements
- if (o.autohide) {
- o._handles.hide();
- $(self.element).addClass("ui-resizable-autohide").hover(function() {
- $(this).removeClass("ui-resizable-autohide");
- o._handles.show();
- },
- function(){
- if (!o.resizing) {
- $(this).addClass("ui-resizable-autohide");
- o._handles.hide();
- }
- });
- }
-
- //Initialize mouse events for interaction
- this.element.mouseInteraction({
- executor: this,
- delay: 0,
- distance: 0,
- dragPrevention: ['input','textarea','button','select','option'],
- start: this.start,
- stop: this.stop,
- drag: this.drag,
- condition: function(e) {
- if(this.disabled) return false;
- for(var i in this.options.handles) {
- if($(this.options.handles[i])[0] == e.target) return true;
- }
- return false;
- }
- });
- };
-
- $.extend($.ui.resizable.prototype, {
- plugins: {},
- ui: function() {
- return {
- instance: this,
- axis: this.options.axis,
- options: this.options
- };
- },
- _renderProxy: function() {
- var el = this.element, o = this.options;
- this.elementOffset = el.offset();
-
- if(o.proxy) {
- this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
-
- // fix ie6 offset
- var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
- pxyoffset = ( ie6 ? 2 : -1 );
-
- this.helper.addClass(o.proxy).css({
- width: el.outerWidth() + pxyoffset,
- height: el.outerHeight() + pxyoffset,
- position: 'absolute',
- left: this.elementOffset.left - ie6offset +'px',
- top: this.elementOffset.top - ie6offset +'px',
- zIndex: ++o.zIndex
- });
-
- this.helper.appendTo("body");
-
- if (o.disableSelection)
- $.ui.disableSelection(this.helper.get(0));
-
- } else {
- this.helper = el;
- }
- },
- propagate: function(n,e) {
- $.ui.plugin.call(this, n, [e, this.ui()]);
- this.element.triggerHandler(n == "resize" ? n : ["resize", n].join(""), [e, this.ui()], this.options[n]);
- },
- destroy: function() {
- var el = this.element, wrapped = el.children(".ui-resizable").get(0),
-
- _destroy = function(exp) {
- $(exp).removeClass("ui-resizable ui-resizable-disabled")
- .removeMouseInteraction().removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
- };
-
- _destroy(el);
-
- if (el.is('.ui-wrapper') && wrapped) {
- el.parent().append(
- $(wrapped).css({
- position: el.css('position'),
- width: el.outerWidth(),
- height: el.outerHeight(),
- top: el.css('top'),
- left: el.css('left')
- })
- ).end().remove();
-
- _destroy(wrapped);
- }
- },
- enable: function() {
- this.element.removeClass("ui-resizable-disabled");
- this.disabled = false;
- },
- disable: function() {
- this.element.addClass("ui-resizable-disabled");
- this.disabled = true;
- },
- start: function(e) {
- var o = this.options, iniPos = this.element.position(), el = this.element,
- num = function(v) { return parseInt(v, 10) || 0; }, ie6 = $.browser.msie && $.browser.version < 7;
- o.resizing = true;
- o.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
-
- // bugfix #1749
- if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
-
- // sOffset decides if document scrollOffset will be added to the top/left of the resizable element
- var sOffset = $.browser.msie && !o.containment && (/absolute/).test(el.css('position')) && !(/relative/).test(el.parent().css('position'));
- var dscrollt = sOffset ? o.documentScroll.top : 0, dscrolll = sOffset ? o.documentScroll.left : 0;
-
- el.css({ position: 'absolute', top: (iniPos.top + dscrollt), left: (iniPos.left + dscrolll) });
- }
-
- //Opera fixing relative position
- if (/relative/.test(el.css('position')) && $.browser.opera)
- el.css({ position: 'relative', top: 'auto', left: 'auto' });
-
- this._renderProxy();
-
- var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
-
- //Store needed variables
- this.offset = this.helper.offset();
- this.position = { left: curleft, top: curtop };
- this.size = o.proxy || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
- this.originalSize = o.proxy || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
- this.originalPosition = { left: curleft, top: curtop };
- this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
- this.originalMousePosition = { left: e.pageX, top: e.pageY };
-
- //Aspect Ratio
- o.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.height / this.originalSize.width)||1);
-
- if (o.preserveCursor)
- $('body').css('cursor', this.axis + '-resize');
-
- this.propagate("start", e);
- return false;
- },
- stop: function(e) {
- this.options.resizing = false;
- var o = this.options, num = function(v) { return parseInt(v, 10) || 0; }, self = this;
-
- if(o.proxy) {
- var pr = o.proportionallyResize, ista = pr && /textarea/i.test(pr.get(0).nodeName),
- soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
- soffsetw = ista ? 0 : self.sizeDiff.width;
-
- var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
- left = parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left),
- top = parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top);
-
- if (!o.animate)
- this.element.css($.extend(style, { top: top, left: left }));
-
- if (o.proxy && !o.animate) this._proportionallyResize();
- this.helper.remove();
- }
-
- if (o.preserveCursor)
- $('body').css('cursor', 'auto');
-
- this.propagate("stop", e);
- return false;
- },
- drag: function(e) {
- //Increase performance, avoid regex
- var el = this.helper, o = this.options, props = {},
- self = this, smp = this.originalMousePosition, a = this.axis;
-
- var dx = (e.pageX-smp.left)||0, dy = (e.pageY-smp.top)||0;
- var trigger = this.change[a];
- if (!trigger) return false;
-
- // Calculate the attrs that will be change
- var data = trigger.apply(this, [e, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
-
- if (o._aspectRatio || e.shiftKey)
- data = this._updateRatio(data, e);
-
- data = this._respectSize(data, e);
-
- this.propagate("resize", e);
-
- el.css({
- top: this.position.top + "px", left: this.position.left + "px",
- width: this.size.width + "px", height: this.size.height + "px"
- });
-
- if (!o.proxy && o.proportionallyResize)
- this._proportionallyResize();
-
- this._updateCache(data);
-
- return false;
- },
-
- _updateCache: function(data) {
- var o = this.options;
- this.offset = this.helper.offset();
- if (data.left) this.position.left = data.left;
- if (data.top) this.position.top = data.top;
- if (data.height) this.size.height = data.height;
- if (data.width) this.size.width = data.width;
- },
-
- _updateRatio: function(data, e) {
- var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
-
- if (data.height) data.width = Math.round(csize.height / o.aspectRatio);
- else if (data.width) data.height = Math.round(csize.width * o.aspectRatio);
-
- if (a == 'sw') {
- data.left = cpos.left + (csize.width - data.width);
- data.top = null;
- }
- if (a == 'nw') {
- data.top = cpos.top + (csize.height - data.height);
- data.left = cpos.left + (csize.width - data.width);
- }
-
- return data;
- },
-
- _respectSize: function(data, e) {
-
- var el = this.helper, o = this.options, pRatio = o._aspectRatio || e.shiftKey, a = this.axis,
- ismaxw = data.width && o.maxWidth && o.maxWidth < data.width, ismaxh = data.height && o.maxHeight && o.maxHeight < data.height,
- isminw = data.width && o.minWidth && o.minWidth > data.width, isminh = data.height && o.minHeight && o.minHeight > data.height;
-
- if (isminw) data.width = o.minWidth;
- if (isminh) data.height = o.minHeight;
- if (ismaxw) data.width = o.maxWidth;
- if (ismaxh) data.height = o.maxHeight;
-
- var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
- var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
-
- if (isminw && cw) data.left = dw - o.minWidth;
- if (ismaxw && cw) data.left = dw - o.maxWidth;
- if (isminh && ch) data.top = dh - o.minHeight;
- if (ismaxh && ch) data.top = dh - o.maxHeight;
-
- // fixing jump error on top/left - bug #2330
- var isNotwh = !data.width && !data.height;
- if (isNotwh && !data.left && data.top) data.top = null;
- else if (isNotwh && !data.top && data.left) data.left = null;
-
- return data;
- },
-
- _proportionallyResize: function() {
- var o = this.options;
- if (!o.proportionallyResize) return;
- var prel = o.proportionallyResize, el = this.helper || this.element;
-
- if (!o.borderDif) {
- var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
- p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
-
- o.borderDif = $.map(b, function(v, i) {
- var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
- return border + padding;
- });
- }
- prel.css({
- height: (el.height() - o.borderDif[0] - o.borderDif[2]) + "px",
- width: (el.width() - o.borderDif[1] - o.borderDif[3]) + "px"
- });
- },
-
- change: {
- e: function(e, dx, dy) {
- return { width: this.originalSize.width + dx };
- },
- w: function(e, dx, dy) {
- var o = this.options, cs = this.originalSize, sp = this.originalPosition;
- return { left: sp.left + dx, width: cs.width - dx };
- },
- n: function(e, dx, dy) {
- var o = this.options, cs = this.originalSize, sp = this.originalPosition;
- return { top: sp.top + dy, height: cs.height - dy };
- },
- s: function(e, dx, dy) {
- return { height: this.originalSize.height + dy };
- },
- se: function(e, dx, dy) {
- return $.extend(this.change.s.apply(this, arguments), this.change.e.apply(this, [e, dx, dy]));
- },
- sw: function(e, dx, dy) {
- return $.extend(this.change.s.apply(this, arguments), this.change.w.apply(this, [e, dx, dy]));
- },
- ne: function(e, dx, dy) {
- return $.extend(this.change.n.apply(this, arguments), this.change.e.apply(this, [e, dx, dy]));
- },
- nw: function(e, dx, dy) {
- return $.extend(this.change.n.apply(this, arguments), this.change.w.apply(this, [e, dx, dy]));
- }
- }
- });
-
-/*
- * Resizable Extensions
- */
-
- $.ui.plugin.add("resizable", "containment", {
-
- start: function(e, ui) {
- var o = ui.options, self = ui.instance, el = self.element;
- var oc = o.containment, ce = (oc instanceof jQuery) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
- if (!ce) return;
-
- if (/document/.test(oc) || oc == document) {
- self.containerOffset = { left: 0, top: 0 };
-
- self.parentData = {
- element: $(document), left: 0, top: 0, width: $(document).width(),
- height: $(document).height() || document.body.parentNode.scrollHeight
- };
- }
-
- // i'm a node, so compute top, left, right, bottom
- else{
- self.containerOffset = $(ce).offset(), self.containerSize = { height: $(ce).innerHeight(), width: $(ce).innerWidth() };
-
- var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
- width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
-
- self.parentData = {
- element: ce, left: co.left, top: co.top, width: width, height: height
- };
- }
- },
-
- resize: function(e, ui) {
- var o = ui.options, self = ui.instance, ps = self.containerSize,
- co = self.containerOffset, cs = self.size, cp = self.position,
- pRatio = o._aspectRatio || e.shiftKey;
-
- if (cp.left < (o.proxy ? co.left : 0)) {
- self.size.width = self.size.width + (o.proxy ? (self.position.left - co.left) : self.position.left);
- if (pRatio) self.size.height = self.size.width * o.aspectRatio;
- self.position.left = o.proxy ? co.left : 0;
- }
-
- if (cp.top < (o.proxy ? co.top : 0)) {
- self.size.height = self.size.height + (o.proxy ? (self.position.top - co.top) : self.position.top);
- if (pRatio) self.size.width = self.size.height / o.aspectRatio;
- self.position.top = o.proxy ? co.top : 0;
- }
-
- var woset = (o.proxy ? self.offset.left - co.left : self.position.left) + self.sizeDiff.width,
- hoset = (o.proxy ? self.offset.top - co.top : self.position.top) + self.sizeDiff.height;
-
- if (woset + self.size.width >= self.parentData.width) {
- self.size.width = self.parentData.width - woset;
- if (pRatio) self.size.height = self.size.width * o.aspectRatio;
- }
-
- if (hoset + self.size.height >= self.parentData.height) {
- self.size.height = self.parentData.height - hoset;
- if (pRatio) self.size.width = self.size.height / o.aspectRatio;
- }
- }
- });
-
- $.ui.plugin.add("resizable", "grid", {
-
- resize: function(e, ui) {
- var o = ui.options, self = ui.instance, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || e.shiftKey;
- o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
- var ox = Math.round((cs.width - os.width) / o.grid[0]) * o.grid[0], oy = Math.round((cs.height - os.height) / o.grid[1]) * o.grid[1];
-
- if (/^(se|s|e)$/.test(a)) {
- self.size.width = os.width + ox;
- self.size.height = os.height + oy;
- }
- else if (/^(ne)$/.test(a)) {
- self.size.width = os.width + ox;
- self.size.height = os.height + oy;
- self.position.top = op.top - oy;
- }
- else if (/^(sw)$/.test(a)) {
- self.size.width = os.width + ox;
- self.size.height = os.height + oy;
- self.position.left = op.left - ox;
- }
- else {
- self.size.width = os.width + ox;
- self.size.height = os.height + oy;
- self.position.top = op.top - oy;
- self.position.left = op.left - ox;
- }
- }
-
- });
-
- $.ui.plugin.add("resizable", "animate", {
-
- stop: function(e, ui) {
- var o = ui.options, self = ui.instance;
-
- var pr = o.proportionallyResize, ista = pr && /textarea/i.test(pr.get(0).nodeName),
- soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
- soffsetw = ista ? 0 : self.sizeDiff.width;
-
- var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
- left = parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left),
- top = parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top);
-
- self.element.animate(
- $.extend(style, { top: top, left: left }),
- {
- duration: o.animateDuration || "slow",
- easing: o.animateEasing || "swing",
- step: function() {
- if (pr) pr.css({ width: self.element.css('width'), height: self.element.css('height') });
- }
- }
- );
- }
-
- });
-
- $.ui.plugin.add("resizable", "ghost", {
-
- start: function(e, ui) {
- var o = ui.options, self = ui.instance, pr = o.proportionallyResize, cs = self.size;
-
- if (!pr) self.ghost = self.element.clone();
- else self.ghost = pr.clone();
-
- self.ghost.css(
- { opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }
- )
- .addClass('ui-resizable-ghost').addClass(typeof o.ghost == 'string' ? o.ghost : '');
-
- self.ghost.appendTo(self.helper);
-
- },
-
- resize: function(e, ui){
- var o = ui.options, self = ui.instance, pr = o.proportionallyResize;
-
- if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
-
- },
-
- stop: function(e, ui){
- var o = ui.options, self = ui.instance, pr = o.proportionallyResize;
- if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
- }
-
- });
-
-})(jQuery);
diff --git a/moksha/widgetbrowser/static/ui.tabs.css b/moksha/widgetbrowser/static/ui.tabs.css
deleted file mode 100644
index 0eabf94..0000000
--- a/moksha/widgetbrowser/static/ui.tabs.css
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Caution! Ensure accessibility in print and other media types... */
-@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
- .ui-tabs-hide {
- display: none;
- }
-}
-
-/* Hide useless elements in print layouts... */
-@media print {
- .ui-tabs-nav {
- display: none;
- }
-}
-
-/* Skin */
-.ui-tabs-nav {
- list-style: none;
- margin: 0 !important;
- padding: 0 0 0 4px;
-}
-.ui-tabs-nav li {
- list-style-image: none !important;
- margin: 0 !important;
- padding: 0 0 0 4px;
-}
-
-.ui-tabs-panel {
- border-top: #94ADA7 solid 1px;
- padding-top: 5px;
- clear: left;
-}
-
-/* IE6 hack */
-* html .ui-tabs-panel {
- margin-top: -1.2em;
-}
-
-.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
- display: block;
- clear: both;
- content: " ";
-}
-.ui-tabs-nav li {
- float: left;
- margin: 0 0 0 1px;
- min-width: 84px; /* be nice to Opera */
-}
-.ui-tabs-nav a, .ui-tabs-nav a span {
- display: block;
- padding: 0 10px;
- background: url(tab.png) no-repeat;
-}
-.ui-tabs-nav a {
- position: relative;
- top: 1px;
- z-index: 2;
- padding-left: 0;
- color: #27537a;
- font-size: 12px;
- font-weight: bold;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap; /* required in IE 6 */
-}
-.ui-tabs-nav .ui-tabs-selected a {
- color: #000;
-}
-.ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active {
- background-position: 100% -150px;
- outline: 0; /* prevent dotted border in Firefox */
-}
-.ui-tabs-nav a, .ui-tabs-nav .ui-tabs-disabled a:hover, .ui-tabs-nav .ui-tabs-disabled a:focus, .ui-tabs-nav .ui-tabs-disabled a:active {
- background-position: 100% -100px;
-}
-.ui-tabs-nav a span {
- width: 64px; /* IE 6 treats width as min-width */
- min-width: 64px;
- height: 18px; /* IE 6 treats height as min-height */
- min-height: 18px;
- padding-top: 6px;
- padding-right: 0;
-}
-*>.ui-tabs-nav a span { /* hide from IE 6 */
- width: auto;
- height: auto;
-}
-.ui-tabs-nav .ui-tabs-selected a span {
- padding-top: 7px;
-}
-.ui-tabs-nav .ui-tabs-selected a span, .ui-tabs-nav a:hover span, .ui-tabs-nav a:focus span, .ui-tabs-nav a:active span {
- background-position: 0 -50px;
-}
-.ui-tabs-nav a span, .ui-tabs-nav .ui-tabs-disabled a:hover span, .ui-tabs-nav .ui-tabs-disabled a:focus span, .ui-tabs-nav .ui-tabs-disabled a:active span {
- background-position: 0 0;
-}
-.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited, .ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
- cursor: text;
-}
-.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active { /* @ Opera, we need to be explicit again here now... */
- cursor: pointer;
-}
-.ui-tabs-nav .ui-tabs-disabled {
- opacity: .4;
-}
-.ui-tabs-container {
- border-top: 1px solid #97a5b0;
- padding: 1em 8px;
- background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
-}
-.ui-tabs-loading em {
- padding: 0 0 0 20px;
- background: url(loading.gif) no-repeat 0 50%;
-}
diff --git a/moksha/widgetbrowser/static/ui.tabs.js b/moksha/widgetbrowser/static/ui.tabs.js
deleted file mode 100644
index f595c10..0000000
--- a/moksha/widgetbrowser/static/ui.tabs.js
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * jQuery UI Tabs
- *
- * Copyright (c) 2007 Klaus Hartl (stilbuero.de)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Tabs
- *
- * Depends:
- * ui.base.js
- *
- * Revision: $Id: ui.tabs.js 5149 2008-03-31 10:51:18Z rdworth $
- */
-;(function($) {
-
- // tabs API methods
- $.fn.tabs = function() {
- var method = typeof arguments[0] == 'string' && arguments[0];
- var args = method && Array.prototype.slice.call(arguments, 1) || arguments;
-
- return method == 'length' ?
- $.data(this[0], 'tabs').$tabs.length :
- this.each(function() {
- if (method) {
- var tabs = $.data(this, 'tabs');
- if (tabs) tabs[method].apply(tabs, args);
- } else
- new $.ui.tabs(this, args[0] || {});
- });
- };
-
- // tabs class
- $.ui.tabs = function(el, options) {
- var self = this;
-
- this.options = $.extend({}, $.ui.tabs.defaults, options);
- this.element = el;
-
- // doesn't extend with null
- if (options.selected === null)
- this.options.selected = null;
-
- this.options.event += '.tabs'; // namespace event
-
- $(el).bind('setData.tabs', function(event, key, value) {
- if ((/^selected/).test(key))
- self.select(value);
- else {
- self.options[key] = value;
- self.tabify();
- }
- }).bind('getData.tabs', function(event, key) {
- return self.options[key];
- });
-
- // save instance for later
- $.data(el, 'tabs', this);
-
- // create tabs
- this.tabify(true);
- };
-
- $.ui.tabs.defaults = {
- // basic setup
- selected: 0,
- unselect: false,
- event: 'click',
- disabled: [],
- cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
- // TODO history: false,
-
- // Ajax
- spinner: 'Loading…',
- cache: false,
- idPrefix: 'ui-tabs-',
- ajaxOptions: {},
-
- // animations
- fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
-
- // templates
- tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
- panelTemplate: '<div></div>',
-
- // CSS classes
- navClass: 'ui-tabs-nav',
- selectedClass: 'ui-tabs-selected',
- unselectClass: 'ui-tabs-unselect',
- disabledClass: 'ui-tabs-disabled',
- panelClass: 'ui-tabs-panel',
- hideClass: 'ui-tabs-hide',
- loadingClass: 'ui-tabs-loading'
- };
-
- // instance methods
- $.extend($.ui.tabs.prototype, {
- tabId: function(a) {
- return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
- || this.options.idPrefix + $.data(a);
- },
- ui: function(tab, panel) {
- return {
- instance: this,
- options: this.options,
- tab: tab,
- panel: panel
- };
- },
- tabify: function(init) {
-
- this.$lis = $('li:has(a[href])', this.element);
- this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
- this.$panels = $([]);
-
- var self = this, o = this.options;
-
- this.$tabs.each(function(i, a) {
- // inline tab
- if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
- self.$panels = self.$panels.add(a.hash);
- // remote tab
- else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
- $.data(a, 'href.tabs', a.href); // required for restore on destroy
-
- var _cls = a.getAttribute('class');
- var use_iframe = _cls && (_cls.indexOf('use_iframe') > -1)? true: false;
- if (!use_iframe) {
- $.data(a, 'load.tabs', a.href); // mutable
- } else {
- $.data(a, 'load.iframe_src', a.href); // mutable
- }
-
-
- var id = self.tabId(a);
- a.href = '#' + id;
- var $panel = $('#' + id);
- var panelTemplate = use_iframe? '<div><iframe></iframe></div>': o.panelTemplate;
- if (!$panel.length) {
- $panel = $(panelTemplate).attr('id', id).addClass(o.panelClass)
- .insertAfter( self.$panels[i - 1] || self.element );
- $panel.data('destroy.tabs', true);
- }
- self.$panels = self.$panels.add( $panel );
- }
- // invalid tab href
- else
- o.disabled.push(i + 1);
- });
-
- if (init) {
-
- // attach necessary classes for styling if not present
- $(this.element).hasClass(o.navClass) || $(this.element).addClass(o.navClass);
- this.$panels.each(function() {
- var $this = $(this);
- $this.hasClass(o.panelClass) || $this.addClass(o.panelClass);
- });
-
- // Try to retrieve selected tab:
- // 1. from fragment identifier in url if present
- // 2. from cookie
- // 3. from selected class attribute on <li>
- // 4. otherwise use given "selected" option
- // 5. check if tab is disabled
- this.$tabs.each(function(i, a) {
- if (location.hash) {
- if (a.hash == location.hash) {
- o.selected = i;
- // prevent page scroll to fragment
- //if (($.browser.msie || $.browser.opera) && !o.remote) {
- if ($.browser.msie || $.browser.opera) {
- var $toShow = $(location.hash), toShowId = $toShow.attr('id');
- $toShow.attr('id', '');
- setTimeout(function() {
- $toShow.attr('id', toShowId); // restore id
- }, 500);
- }
- scrollTo(0, 0);
- return false; // break
- }
- } else if (o.cookie) {
- var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10);
- if (index && self.$tabs[index]) {
- o.selected = index;
- return false; // break
- }
- } else if ( self.$lis.eq(i).hasClass(o.selectedClass) ) {
- o.selected = i;
- return false; // break
- }
- });
-
- // highlight selected tab
- this.$panels.addClass(o.hideClass);
- this.$lis.removeClass(o.selectedClass);
- if (o.selected !== null) {
- this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
- this.$lis.eq(o.selected).addClass(o.selectedClass);
- }
-
- // load if remote tab
- var href = o.selected !== null && $.data(this.$tabs[o.selected], 'load.tabs');
- if (href)
- this.load(o.selected);
-
- // Take disabling tabs via class attribute from HTML
- // into account and update option properly...
- o.disabled = $.unique(o.disabled.concat(
- $.map(this.$lis.filter('.' + o.disabledClass),
- function(n, i) { return self.$lis.index(n); } )
- )).sort();
-
- // clean up to avoid memory leaks in certain versions of IE 6
- $(window).bind('unload', function() {
- self.$tabs.unbind('.tabs');
- self.$lis = self.$tabs = self.$panels = null;
- });
-
- }
-
- // disable tabs
- for (var i = 0, li; li = this.$lis[i]; i++)
- $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
-
- // reset cache if switching from cached to not cached
- if (o.cache === false)
- this.$tabs.removeData('cache.tabs');
-
- // set up animations
- var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
- if (o.fx && o.fx.constructor == Array)
- hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
- else
- hideFx = showFx = o.fx || baseFx;
-
- // reset some styles to maintain print style sheets etc.
- var resetCSS = { display: '', overflow: '', height: '' };
- if (!$.browser.msie) // not in IE to prevent ClearType font issue
- resetCSS.opacity = '';
-
- // Hide a tab, animation prevents browser scrolling to fragment,
- // $show is optional.
- function hideTab(clicked, $hide, $show) {
- $hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
- $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
- if ($.browser.msie && hideFx.opacity)
- $hide[0].style.filter = '';
- if ($show)
- showTab(clicked, $show, $hide);
- });
- }
-
- // Show a tab, animation prevents browser scrolling to fragment,
- // $hide is optional.
- function showTab(clicked, $show, $hide) {
- if (showFx === baseFx)
- $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
- $show.animate(showFx, showFx.duration || baseDuration, function() {
- $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
- if ($.browser.msie && showFx.opacity)
- $show[0].style.filter = '';
-
- // callback
- $(self.element).triggerHandler('tabsshow', [self.ui(clicked, $show[0])], o.show);
-
- });
- }
-
- // switch a tab
- function switchTab(clicked, $li, $hide, $show) {
- /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
- $.ajaxHistory.update(clicked.hash);
- }*/
- $li.addClass(o.selectedClass)
- .siblings().removeClass(o.selectedClass);
- hideTab(clicked, $hide, $show);
- }
-
- // attach tab event handler, unbind to avoid duplicates from former tabifying...
- this.$tabs.unbind('.tabs').bind(o.event, function() {
-
- //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
- var $li = $(this).parents('li:eq(0)'),
- $hide = self.$panels.filter(':visible'),
- $show = $(this.hash);
-
- // If tab is already selected and not unselectable or tab disabled or
- // or is already loading or click callback returns false stop here.
- // Check if click handler returns false last so that it is not executed
- // for a disabled or loading tab!
- if (($li.hasClass(o.selectedClass) && !o.unselect)
- || $li.hasClass(o.disabledClass)
- || $(this).hasClass(o.loadingClass)
- || $(self.element).triggerHandler('tabsselect', [self.ui(this, $show[0])], o.select) === false
- ) {
- this.blur();
- return false;
- }
-
- self.options.selected = self.$tabs.index(this);
-
- // if tab may be closed
- if (o.unselect) {
- if ($li.hasClass(o.selectedClass)) {
- self.options.selected = null;
- $li.removeClass(o.selectedClass);
- self.$panels.stop();
- hideTab(this, $hide);
- this.blur();
- return false;
- } else if (!$hide.length) {
- self.$panels.stop();
- var a = this;
- self.load(self.$tabs.index(this), function() {
- $li.addClass(o.selectedClass).addClass(o.unselectClass);
- showTab(a, $show);
- });
- this.blur();
- return false;
- }
- }
-
- if (o.cookie)
- $.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie);
-
- // stop possibly running animations
- self.$panels.stop();
-
- // show new tab
- if ($show.length) {
-
- // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
- /*if ($.browser.msie && o.bookmarkable) {
- var showId = this.hash.replace('#', '');
- $show.attr('id', '');
- setTimeout(function() {
- $show.attr('id', showId); // restore id
- }, 0);
- }*/
-
- var a = this;
- self.load(self.$tabs.index(this), $hide.length ?
- function() {
- switchTab(a, $li, $hide, $show);
- } :
- function() {
- $li.addClass(o.selectedClass);
- showTab(a, $show);
- }
- );
-
- // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
- /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
- var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
- setTimeout(function() {
- scrollTo(scrollX, scrollY);
- }, 0);*/
-
- } else
- throw 'jQuery UI Tabs: Mismatching fragment identifier.';
-
- // Prevent IE from keeping other link focussed when using the back button
- // and remove dotted border from clicked link. This is controlled in modern
- // browsers via CSS, also blur removes focus from address bar in Firefox
- // which can become a usability and annoying problem with tabsRotate.
- if ($.browser.msie)
- this.blur();
-
- //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
- return false;
-
- });
-
- // disable click if event is configured to something else
- if (!(/^click/).test(o.event))
- this.$tabs.bind('click.tabs', function() { return false; });
-
- },
- add: function(url, label, index) {
- if (index == undefined)
- index = this.$tabs.length; // append by default
-
- var o = this.options;
- var $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{label\}/, label));
- $li.data('destroy.tabs', true);
-
- var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );
-
- // try to find an existing element before creating a new one
- var $panel = $('#' + id);
- if (!$panel.length) {
- $panel = $(o.panelTemplate).attr('id', id)
- .addClass(o.panelClass).addClass(o.hideClass);
- $panel.data('destroy.tabs', true);
- }
- if (index >= this.$lis.length) {
- $li.appendTo(this.element);
- $panel.appendTo(this.element.parentNode);
- } else {
- $li.insertBefore(this.$lis[index]);
- $panel.insertBefore(this.$panels[index]);
- }
-
- o.disabled = $.map(o.disabled,
- function(n, i) { return n >= index ? ++n : n });
-
- this.tabify();
-
- if (this.$tabs.length == 1) {
- $li.addClass(o.selectedClass);
- $panel.removeClass(o.hideClass);
- var href = $.data(this.$tabs[0], 'load.tabs');
- if (href)
- this.load(index, href);
- }
-
- // callback
- $(this.element).triggerHandler('tabsadd',
- [this.ui(this.$tabs[index], this.$panels[index])], o.add
- );
- },
- remove: function(index) {
- var o = this.options, $li = this.$lis.eq(index).remove(),
- $panel = this.$panels.eq(index).remove();
-
- // If selected tab was removed focus tab to the right or
- // in case the last tab was removed the tab to the left.
- if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
- this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
-
- o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
- function(n, i) { return n >= index ? --n : n });
-
- this.tabify();
-
- // callback
- $(this.element).triggerHandler('tabsremove',
- [this.ui($li.find('a')[0], $panel[0])], o.remove
- );
- },
- enable: function(index) {
- var o = this.options;
- if ($.inArray(index, o.disabled) == -1)
- return;
-
- var $li = this.$lis.eq(index).removeClass(o.disabledClass);
- if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
- $li.css('display', 'inline-block');
- setTimeout(function() {
- $li.css('display', 'block');
- }, 0);
- }
-
- o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
-
- // callback
- $(this.element).triggerHandler('tabsenable',
- [this.ui(this.$tabs[index], this.$panels[index])], o.enable
- );
-
- },
- disable: function(index) {
- var self = this, o = this.options;
- if (index != o.selected) { // cannot disable already selected tab
- this.$lis.eq(index).addClass(o.disabledClass);
-
- o.disabled.push(index);
- o.disabled.sort();
-
- // callback
- $(this.element).triggerHandler('tabsdisable',
- [this.ui(this.$tabs[index], this.$panels[index])], o.disable
- );
- }
- },
- select: function(index) {
- if (typeof index == 'string')
- index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
- this.$tabs.eq(index).trigger(this.options.event);
- },
- load: function(index, callback) { // callback is for internal usage only
-
- var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
- bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
-
- callback = callback || function() {};
-
- // no remote or from cache - just finish with callback
- if (!url || ($.data(a, 'cache.tabs') && !bypassCache)) {
- callback();
- return;
- }
-
- // load remote from here on
- if (o.spinner) {
- var $span = $('span', a);
- $span.data('label.tabs', $span.html()).html('<em>' + o.spinner + '</em>');
- }
- var finish = function() {
- self.$tabs.filter('.' + o.loadingClass).each(function() {
- $(this).removeClass(o.loadingClass);
- if (o.spinner) {
- var $span = $('span', this);
- $span.html($span.data('label.tabs')).removeData('label.tabs');
- }
- });
- self.xhr = null;
- };
- var ajaxOptions = $.extend({}, o.ajaxOptions, {
- url: url,
- success: function(r, s) {
- $(a.hash).html(r);
- finish();
-
- // This callback is required because the switch has to take
- // place after loading has completed.
- callback();
-
- if (o.cache)
- $.data(a, 'cache.tabs', true); // if loaded once do not load them again
-
- // callback
- $(self.element).triggerHandler('tabsload',
- [self.ui(self.$tabs[index], self.$panels[index])], o.load
- );
-
- o.ajaxOptions.success && o.ajaxOptions.success(r, s);
- }
- });
- if (this.xhr) {
- // terminate pending requests from other tabs and restore tab label
- this.xhr.abort();
- finish();
- }
- $a.addClass(o.loadingClass);
- setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
- self.xhr = $.ajax(ajaxOptions);
- }, 0);
-
- },
- url: function(index, url) {
- this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
- },
- destroy: function() {
- var o = this.options;
- $(this.element).unbind('.tabs')
- .removeClass(o.navClass).removeData('tabs');
- this.$tabs.each(function() {
- var href = $.data(this, 'href.tabs');
- if (href)
- this.href = href;
- var $this = $(this).unbind('.tabs');
- $.each(['href', 'load', 'cache'], function(i, prefix) {
- $this.removeData(prefix + '.tabs');
- });
- });
- this.$lis.add(this.$panels).each(function() {
- if ($.data(this, 'destroy.tabs'))
- $(this).remove();
- else
- $(this).removeClass([o.selectedClass, o.unselectClass,
- o.disabledClass, o.panelClass, o.hideClass].join(' '));
- });
- }
- });
-
-/*
- * Tabs Extensions
- */
-
- /*
- * Rotate
- */
- $.extend($.ui.tabs.prototype, {
- rotation: null,
- rotate: function(ms, continuing) {
-
- continuing = continuing || false;
-
- var self = this, t = this.options.selected;
-
- function start() {
- self.rotation = setInterval(function() {
- t = ++t < self.$tabs.length ? t : 0;
- self.select(t);
- }, ms);
- }
-
- function stop(e) {
- if (!e || e.clientX) { // only in case of a true click
- clearInterval(self.rotation);
- }
- }
-
- // start interval
- if (ms) {
- start();
- if (!continuing)
- this.$tabs.bind(this.options.event, stop);
- else
- this.$tabs.bind(this.options.event, function() {
- stop();
- t = self.options.selected;
- start();
- });
- }
- // stop interval
- else {
- stop();
- this.$tabs.unbind(this.options.event, stop);
- }
- }
- });
-
-})(jQuery);
diff --git a/moksha/widgetbrowser/static/widgetbrowser.css b/moksha/widgetbrowser/static/widgetbrowser.css
deleted file mode 100644
index 21a046d..0000000
--- a/moksha/widgetbrowser/static/widgetbrowser.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.widgetbrowser iframe {
- width: 100%;
- border: 0;
-}
-div.small iframe { height: 50px; }
-div.medium iframe { height: 150px; }
-div.large iframe { height: 300px; }
-div.x-large iframe { height: 500px; }
-
diff --git a/moksha/widgetbrowser/static/widgetbrowser.js b/moksha/widgetbrowser/static/widgetbrowser.js
deleted file mode 100644
index c0b78e6..0000000
--- a/moksha/widgetbrowser/static/widgetbrowser.js
+++ /dev/null
@@ -1,13 +0,0 @@
-jQuery(function() {
- jQuery('.widgetbrowser > ul').tabs({
- selected: null,
- unselect: true,
- select: function (ui) {
- var url = jQuery.data(ui.tab, 'load.iframe_src');
- var iframe = jQuery('iframe', ui.panel);
- if (url && !iframe.attr('src')) {
- iframe.attr('src', url);
- }
- }
- })
-});
diff --git a/moksha/widgetbrowser/templates/__init__.py b/moksha/widgetbrowser/templates/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/moksha/widgetbrowser/templates/home.html b/moksha/widgetbrowser/templates/home.html
deleted file mode 100644
index 012ce08..0000000
--- a/moksha/widgetbrowser/templates/home.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<?python
-from widgetbrowser import widgets
-?>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
- xmlns:py="http://genshi.edgewall.org/">
- <head>
- <title>WidgetBrowser</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <style>
- .ui-tabs-panel {
- border-bottom: solid 1px #94ada7;
- padding-left: 1.5em;
- }
- .ui-tabs-panel iframe {
- width: 100%;
- border: 0;
- min-height: 500px;
- }
- #home {
- min-height: 450px;
- }
- </style>
- </head>
- <body class="flora">
- <div id="main">
- <ul>
- <li><a href="#home"><span>Home</span></a></li>
- <li><a href="#terminal" class="use_iframe"><span>Terminal</span></a></li>
- <li><a href="${url('/widgets/')}" class="use_iframe"><span>Widgets</span></a></li>
- </ul>
- <div id="home">
- <h1>Welcome to Toscawidgets' Browser</h1>
- <p>
- </p>
- </div>
- <div id="terminal">
- ${widgets.repl(prefix=url('_repl/'))}
- </div>
- </div>
- <div id="footer">
- <p>© 2008. Alberto Valverde González</p>
- </div>
- <script type="text/javascript">
- //<![CDATA[
- jQuery(function () {
- jQuery('#main > ul').tabs({
- select: function (ui) {
- var url = jQuery.data(ui.tab, 'load.iframe_src');
- var iframe = jQuery('iframe', ui.panel);
- if (url && !iframe.attr('src')) {
- iframe.attr('src', url);
- }
- }
- });
- });
- //]]>
- </script>
- </body>
-</html>
diff --git a/moksha/widgetbrowser/templates/list_widgets.html b/moksha/widgetbrowser/templates/list_widgets.html
deleted file mode 100644
index 2ef5dfe..0000000
--- a/moksha/widgetbrowser/templates/list_widgets.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
- xmlns:py="http://genshi.edgewall.org/">
- <head>
- <title>WidgetBrowser: Installed widgets</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- </head>
- <body id="widgets">
- <ul>
- <li py:for="path, url in widgets">
- <a href="$url">$path</a>
- </li>
- </ul>
- </body>
-</html>
diff --git a/moksha/widgetbrowser/templates/show_widget.html b/moksha/widgetbrowser/templates/show_widget.html
deleted file mode 100644
index b75e063..0000000
--- a/moksha/widgetbrowser/templates/show_widget.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
- xmlns:py="http://genshi.edgewall.org/">
- <head>
- <title>WidgetBrowser: ${widget_name}</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- </head>
- <body id="widget_browser">
- <form py:if="interactive" method="GET">
- <label for="display_args">Display arguments:</label>
- <input id="display_args" name="_disp" type="text" size="50" value="${_disp}" />
- <input type="submit" value="Display" />
- </form>
- <div py:replace="widget_output" />
- </body>
-</html>
diff --git a/moksha/widgetbrowser/templates/validation_result.html b/moksha/widgetbrowser/templates/validation_result.html
deleted file mode 100644
index e43da7b..0000000
--- a/moksha/widgetbrowser/templates/validation_result.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
- xmlns:py="http://genshi.edgewall.org/">
- <head>
- <title>WidgetBrowser: ${widget_name}</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- </head>
- <body id="widget_browser">
- <h1 class="title">Validated data:</h1>
- ${Markup(value)}
- <a href="">Back</a>
- </body>
-</html>
diff --git a/moksha/widgetbrowser/templates/widget_browser_tabs.html b/moksha/widgetbrowser/templates/widget_browser_tabs.html
deleted file mode 100644
index 7edb374..0000000
--- a/moksha/widgetbrowser/templates/widget_browser_tabs.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<div xmlns:py="http://genshi.edgewall.org/"
- class="widgetbrowser ${size}">
- <ul>
- <li py:for="text, url in tabs">
- <a href="${url}" class="${text == 'Demo' and 'use_iframe' or None}">
- <span>${text}</span>
- </a>
- </li>
- </ul>
-</div>
-
diff --git a/moksha/widgetbrowser/templates/widget_index.html b/moksha/widgetbrowser/templates/widget_index.html
deleted file mode 100644
index 4759c25..0000000
--- a/moksha/widgetbrowser/templates/widget_index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
- xmlns:py="http://genshi.edgewall.org/">
- <?python
- from widgetbrowser.widgets import WidgetBrowserTabs
- from widgetbrowser.util import widget_path
- browser = WidgetBrowserTabs(size='x-large')
- ?>
- <head>
- <title>WidgetBrowser: ${widget_path(widget)}</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- </head>
- <body>
- <h1>${widget_path(widget)}</h1>
- <p><a href="javascript:history.back()">Back</a></p>
- ${browser(widget)}
- </body>
-</html>
diff --git a/moksha/widgetbrowser/templates/widget_parameters.html b/moksha/widgetbrowser/templates/widget_parameters.html
deleted file mode 100644
index c95c195..0000000
--- a/moksha/widgetbrowser/templates/widget_parameters.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<div xmlns:py="http://genshi.edgewall.org/" class="widget_params">
- <div py:if="parameters.local" class="widget_params local_params">
- <h3>This widget's</h3>
- <dl>
- <py:for each="k in sorted(parameters.local)">
- <dt>${k} <span class="default_param">(default = ${parameters.get_default(k)})</span></dt>
- <dd py:content="parameters.get_doc(k, 'Undocumented')" />
- </py:for>
- </dl>
- </div>
- <div py:if="parameters.inherited" class="widget_param inherited_params">
- <h3>Inherited</h3>
- <dl>
- <py:for each="k in sorted(parameters.inherited)">
- <dt>${k} <span class="default_param">(default = ${parameters.get_default(k)})</span></dt>
- <dd py:content="parameters.get_doc(k, 'Undocumented')" />
- </py:for>
- </dl>
- </div>
-</div>
diff --git a/moksha/widgetbrowser/tests/__init__.py b/moksha/widgetbrowser/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/moksha/widgetbrowser/tests/dummy_m_template.html b/moksha/widgetbrowser/tests/dummy_m_template.html
deleted file mode 100644
index 7c9c42c..0000000
--- a/moksha/widgetbrowser/tests/dummy_m_template.html
+++ /dev/null
@@ -1 +0,0 @@
-Dummy template $value
diff --git a/moksha/widgetbrowser/tests/dummy_m_template.mak b/moksha/widgetbrowser/tests/dummy_m_template.mak
deleted file mode 100644
index 1774ce6..0000000
--- a/moksha/widgetbrowser/tests/dummy_m_template.mak
+++ /dev/null
@@ -1 +0,0 @@
-Dummy template $value mako version
diff --git a/moksha/widgetbrowser/tests/dummy_template.html b/moksha/widgetbrowser/tests/dummy_template.html
deleted file mode 100644
index 7c9c42c..0000000
--- a/moksha/widgetbrowser/tests/dummy_template.html
+++ /dev/null
@@ -1 +0,0 @@
-Dummy template $value
diff --git a/moksha/widgetbrowser/tests/test_app.txt b/moksha/widgetbrowser/tests/test_app.txt
deleted file mode 100644
index bacbc39..0000000
--- a/moksha/widgetbrowser/tests/test_app.txt
+++ /dev/null
@@ -1,50 +0,0 @@
->>> from widgetbrowser import WidgetBrowser
->>> from webtest import TestApp
-
->>> app = TestApp(WidgetBrowser())
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo')
->>> assert 'default' in r
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/')
->>> assert 'Demo' in r
-
->>> r = app.get('/os.open/demo', status=404)
-
-Test that code isn't executed if not allowed
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo?_disp="foo"')
->>> assert 'default' in r
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/template')
->>> assert '$value' in r
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/source')
->>> assert 'class' in r
->>> assert 'TestWidget' in r
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/parameters')
->>> assert 'Inherited' in r
-
-Test posting:
-
->>> r = app.post('/widgetbrowser.tests.widgets.TestWidget/demo', {'some_key':'foo'})
->>> assert 'some_key' in r
-
-# the following is just to test the failed validation code-path
->>> r = app.post('/widgetbrowser.tests.widgets.TestWidget/demo', {'break':'y'})
->>> assert 'some_key' not in r
-
-Test unimplemented methods:
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/foobarize', status=501)
-
-Test custom controller
-
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/test')
->>> assert 'Testing TestWidget' in r
-
-Now with code execution
-
->>> app = TestApp(WidgetBrowser(interactive=True))
->>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo?_disp="foo"')
->>> assert 'foo' in r
diff --git a/moksha/widgetbrowser/tests/test_sphinx_ext.py b/moksha/widgetbrowser/tests/test_sphinx_ext.py
deleted file mode 100644
index fc2d10a..0000000
--- a/moksha/widgetbrowser/tests/test_sphinx_ext.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import os
-import shutil
-from unittest import TestCase
-from pkg_resources import resource_filename
-import sphinx
-
-doc_dir = resource_filename('widgetbrowser.tests', 'testdocs')
-
-class TestSphinxExt(TestCase):
- def setUp(self):
- self.dest_dir = os.tempnam()
- if not os.path.isdir(self.dest_dir):
- os.makedirs(self.dest_dir)
-
- def tearDown(self):
- try:
- shutil.rmtree(self.dest_dir)
- except OSError:
- pass
-
- def test_generate(self):
- out = sphinx.main(['sphinx-build', doc_dir, self.dest_dir])
- self.failUnless(not out, out)
- html = open(os.path.join(self.dest_dir, 'index.html')).read()
- self.failUnless('widgetbrowser' in html)
- self.failUnless('x-large' in html)
diff --git a/moksha/widgetbrowser/tests/testdocs/conf.py b/moksha/widgetbrowser/tests/testdocs/conf.py
deleted file mode 100644
index 4bd428a..0000000
--- a/moksha/widgetbrowser/tests/testdocs/conf.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# TestDocs documentation build configuration file, created by
-# sphinx-quickstart on Fri May 9 09:56:10 2008.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# The contents of this file are pickled, so don't put values in the namespace
-# that aren't pickleable (module imports are okay, they're removed automatically).
-#
-# All configuration values have a default value; values that are commented out
-# serve to show the default value.
-
-import sys, os
-
-# If your extensions are in another directory, add it here. If the directory
-# is relative to the documentation root, use os.path.abspath to make it
-# absolute, like shown here.
-#sys.path.append(os.path.abspath('some/directory'))
-
-# General configuration
-# ---------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['widgetbrowser.sphinx_ext']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = []
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General substitutions.
-project = 'TestDocs'
-copyright = '2008, Alberto'
-
-# The default replacements for |version| and |release|, also used in various
-# other places throughout the built documents.
-#
-# The short X.Y version.
-version = '0.1'
-# The full version, including alpha/beta/rc tags.
-release = '0.1'
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-
-# Options for HTML output
-# -----------------------
-
-# The style sheet to use for HTML and HTML Help pages. A file of that name
-# must exist either in Sphinx' static/ path, or in one of the custom paths
-# given in html_static_path.
-html_style = 'default.css'
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# The name of an image file (within the static path) to place at the top of
-# the sidebar.
-#html_logo = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_use_modindex = True
-
-# If true, the reST sources are included in the HTML build as _sources/<name>.
-#html_copy_source = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.
-#html_use_opensearch = False
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'TestDocsdoc'
-
-
-# Options for LaTeX output
-# ------------------------
-
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, document class [howto/manual]).
-latex_documents = [
- ('index', 'TestDocs.tex', 'TestDocs Documentation', 'Alberto', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_use_modindex = True
diff --git a/moksha/widgetbrowser/tests/testdocs/index.rst b/moksha/widgetbrowser/tests/testdocs/index.rst
deleted file mode 100644
index 6f70ced..0000000
--- a/moksha/widgetbrowser/tests/testdocs/index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. TestDocs documentation master file, created by sphinx-quickstart on Fri May 9 09:56:10 2008.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Testing the `widgetbroser` directive
-====================================
-
-Test an existing widget
------------------------
-.. widgetbrowser:: widgetbrowser.tests.widgets.TestWidget
- :tabs: source, demo, parameters, template
- :size: x-large
diff --git a/moksha/widgetbrowser/tests/widgets.py b/moksha/widgetbrowser/tests/widgets.py
deleted file mode 100644
index 149139d..0000000
--- a/moksha/widgetbrowser/tests/widgets.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from tw.api import Widget
-from widgetbrowser import WidgetBrowser
-from formencode.api import Invalid
-
-class TestWidget(Widget):
- template = "$value"
- default = "default"
-
- def validate(self, value, *args, **kw):
- if 'break' in value.keys():
- raise Invalid("Validation failed", value, None)
- return value
-
-(a)WidgetBrowser.register_controller(TestWidget, 'test')
-def test_controller(request, response):
- response.headers['Content-Type'] = 'text/plain'
- return "Testing " + request.widget.__class__.__name__
-
-class TestWidgetExternalTemplate(Widget):
- template = "toscawidgets:widgetbrowser.tests.dummy_template"
- default = "default"
-
-class TestWidgetMultipleExternalTemplate(Widget):
- template = "toscawidgets:widgetbrowser.tests.dummy_m_template"
- default = "default"
diff --git a/moksha/widgetbrowser/util.py b/moksha/widgetbrowser/util.py
deleted file mode 100644
index 648cd8c..0000000
--- a/moksha/widgetbrowser/util.py
+++ /dev/null
@@ -1,242 +0,0 @@
-import logging
-import os
-import errno
-import sys
-import pprint
-
-from pkg_resources import EntryPoint, iter_entry_points, resource_string
-
-import tw
-from tw.api import Widget, WidgetType
-from tw.core import view
-
-log = logging.getLogger(__name__)
-
-def import_widget(path):
- """Import a widget given a dotted or entry point notation path.
-
- Can import both widget instances or classes.
-
- >>> import_widget('tw.core.base.Widget')
- <class 'tw.core.base.Widget'>
- >>> import_widget('tw.core.base:Widget')
- <class 'tw.core.base.Widget'>
- >>> import_widget('os.popen')
-
- """
- if ':' not in path:
- parts = path.split('.')
- path = '.'.join(parts[:-1]) + ':' + parts[-1]
- widget = EntryPoint.parse("x="+path).load(False)
- if not isinstance(widget, (WidgetType, Widget)):
- widget = None
- return widget
-
-
-def widget_path(widget):
- """Returns the path of a widget instance or subclass
-
- >>> from tw.api import Widget
- >>> widget_path(Widget)
- 'tw.core.base.Widget'
- >>> widget_path(Widget())
- 'tw.core.base.Widget'
- """
- if not isinstance(widget, (WidgetType, Widget)):
- raise TypeError("Only widgets are allowed")
- if isinstance(widget, Widget):
- widget = widget.__class__
- return '.'.join([widget.__module__, widget.__name__])
-
-def format_code(code, format='python'):
- """Formats a chunk of code as html. If pygments is installed it will
- pygmentize it.
-
- >>> code = "from __future__ import teletransportation"
- >>> '<pre' in format_code(code)
- True
- """
- try:
- from pygments import highlight, formatters, lexers
- except ImportError:
- log.info("Pygments is not available to colorize")
- return '<pre>' + code + '</pre>'
- lexer = lexers.get_lexer_by_name(format)
- formatter = formatters.get_formatter_by_name('html')
- return highlight(code, lexer, formatter)
-
-#TODO: Memoize this function
-def widget_template(widget, extension='.html'):
- """Returns the template of a widget as a string.
-
- Loads external templates if needed.
-
- >>> from widgetbrowser.tests.widgets import *
- >>> widget_template(TestWidgetExternalTemplate())
- 'Dummy template $value\\n'
-
- If more than one is available, it will use the extension to disambiguate.
-
- >>> from widgetbrowser.tests.widgets import TestWidgetExternalTemplate
- >>> widget_template(TestWidgetMultipleExternalTemplate(), '.html')
- 'Dummy template $value\\n'
- >>> widget_template(TestWidgetMultipleExternalTemplate(), '.mak')
- 'Dummy template $value mako version\\n'
- """
- template = widget.template
- if template and not view._is_inline_template(template):
- # Template seems to refer to a file, look it up
- parts = template.split('.')
- possible_extensions = set(".html .mak .mako".split())
- possible_extensions.remove(extension)
- possible_extensions = [extension] + list(possible_extensions)
- for ext in possible_extensions:
- try:
- return resource_string('.'.join(parts[:-1]), parts[-1]+ext)
- except IOError, e:
- if e.errno not in (0, errno.ENOENT):
- raise
- return None
- return template
-
-def pretty_print(obj):
- """Pretty prints an object returning pygmentized code if possible."""
- return format_code(pprint.pformat(obj), 'python')
-
-def display_widget(widget, argstr='', ctx=None):
- """Displays a widget with optional arguments as a string.
-
-
- .. warning:: IT IS VERY UNSAFE TO EXECUTE UNTRUSTED CODE
-
- Example::
-
- >>> from tw.api import Widget
- >>> class TestWidget(Widget):
- ... params = ['param']
- ... template = "$value-$param"
- >>> display_widget(TestWidget())
- u'None-None'
- >>> display_widget(TestWidget(), '"hello", param=2')
- u'hello-2'
- """
- ctx = ctx or {}
- ctx['_w'] = widget
- code = "_o = _w(%s)" % argstr
- exec code in ctx
- return ctx['_o']
-
-def widget_url(widget, action='', prefix=None):
- """Returns the URL of the controller to perform `action` on `widget`.
-
- If no `prefix` is passed the it will be tried to be fetched from
- `tw.framework.request_local` where the :class:`WidgetBrowser` leaves it
- on every request.
-
- Example::
-
- >>> from tw.core.base import Widget
- >>> widget_url(Widget)
- '/tw.core.base.Widget/'
- >>> widget_url(Widget())
- '/tw.core.base.Widget/'
-
- You can also pass the `path` of the widget::
-
- >>> widget_url('tw.api.Widget')
- '/tw.api.Widget/'
- >>> widget_url('tw.api.Widget', 'show')
- '/tw.api.Widget/show'
- >>> widget_url('tw.api.Widget', 'show', prefix='/widget')
- '/widget/tw.api.Widget/show'
-
- .. note::
-
- You can pass any path the widget can be imported from when passing a
- string but if you pass a widget instance or subclass then the real
- module where it is defined will be generated.
- """
- if isinstance(widget, (Widget, WidgetType)):
- widgeturi = widget_path(widget)
- else:
- widgeturi = widget
- if import_widget(widgeturi) is None:
- return
- if prefix is None:
- prefix = getattr(tw.framework.request_local, 'browser_prefix', '')
- return '/'.join([prefix.rstrip('/'), widgeturi, action])
-
-def all_widgets():
- """Iterates over all the Widget subclasses in the modules
- that are declared as `toscawidgets.widgets` entrypoints
-
- >>> len(list(all_widgets())) > 0
- True
- """
- seen = set()
- for ep in iter_entry_points('toscawidgets.widgets'):
- try:
- mod = ep.load(False)
- except ImportError, e:
- log.error("Could not load %r: %s", ep, e)
- continue
- for name in dir(mod):
- obj = getattr(mod, name)
- if isinstance(obj, WidgetType) and obj not in seen:
- seen.add(obj)
- yield obj
-
-class WidgetParameters(object):
- """Wraps a widget and provides information on it's parameters.
-
- Example::
-
- >>> from tw.core.base import Widget
- >>> params = WidgetParameters(Widget)
- >>> len(params.all) > 0
- True
- >>> params.all - params.local == params.inherited
- True
- """
- def __init__(self, widget):
- if isinstance(widget, Widget):
- widget = widget.__class__
- self.widget = widget
- self.all = widget.params
- self.inherited = set()
- for b in self.widget.__mro__:
- if b is self.widget:
- continue
- self.inherited.update(getattr(b, 'params', set()))
- self.local = self.all - self.inherited
-
- def get_default(self, name, default=None):
- """Returns a string representation of a parameter default value.
-
- Example::
-
- >>> from tw.core.base import Widget
- >>> params = WidgetParameters(Widget)
- >>> type(params.get_default('id'))
- <type 'str'>
- """
- return repr(getattr(self.widget, name, default))
-
- def get_doc(self, name, default='Undocumented'):
- """Returns parameters's doc. If it is not documented it will return
- ``default``
-
- Example::
-
- >>> from tw.core.base import Widget
- >>> params = WidgetParameters(Widget)
- >>> type(params.get_doc('id'))
- <type 'str'>
- """
- return getattr(self.widget, name + '__doc', default)
-
-def build_docs(src, dst):
- import sphinx
- if not os.path.exists(dst):
- os.mkdir(dst)
- return sphinx.main(['sphinx-build', src, dst])
diff --git a/moksha/widgetbrowser/widgetbrowser/__init__.py b/moksha/widgetbrowser/widgetbrowser/__init__.py
new file mode 100644
index 0000000..c037ed3
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/__init__.py
@@ -0,0 +1,2 @@
+from wsgiapp import WidgetBrowser
+from util import widget_url
diff --git a/moksha/widgetbrowser/widgetbrowser/command.py b/moksha/widgetbrowser/widgetbrowser/command.py
new file mode 100644
index 0000000..4b15fbe
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/command.py
@@ -0,0 +1,54 @@
+from wsgiref.simple_server import make_server
+from optparse import OptionParser
+
+from widgetbrowser.wsgiapp import WidgetBrowser
+
+
+_parser = OptionParser(usage = "%prog [OPTIONS] [widget_url]")
+_parser.add_option("-i", "--interactive",
+ dest="interactive",
+ action="store_true",
+ default=False)
+_parser.add_option("-b", "--browser",
+ dest="browser",
+ action="store_true",
+ default=False)
+_parser.add_option("-d", "--docs",
+ dest="docs",
+ default=None)
+_parser.add_option("-p", "--port",
+ dest="port",
+ default=8000)
+
+def browser_command(argv=None):
+ """Command line interface to launch the widgetbrowser"""
+ opts, args = _parser.parse_args(argv)
+
+ # Only allow passing display arguments in debug mode
+ if args:
+ widget_url = args[0] + '/'
+ else:
+ widget_url = ''
+ app = WidgetBrowser(interactive=opts.interactive, docs_dir=opts.docs)
+ if opts.interactive:
+ try:
+ from weberror.evalexception import EvalException
+ app = EvalException(app)
+ except ImportError:
+ raise ImportError("You need to install WebError for interactive "
+ "debugging")
+ url = "http://127.0.0.1:%s/" % opts.port
+ if opts.browser:
+ import webbrowser
+ webbrowser.open(url + widget_url)
+ server = make_server('127.0.0.1', int(opts.port), app)
+ print "Server started at " + url
+ try:
+ server.serve_forever()
+ except (KeyboardInterrupt, SystemExit):
+ pass
+
+if __name__ == '__main__':
+ import sys
+ sys.exit(browser_command(sys.argv))
+
diff --git a/moksha/widgetbrowser/widgetbrowser/repl.py b/moksha/widgetbrowser/widgetbrowser/repl.py
new file mode 100644
index 0000000..5855068
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/repl.py
@@ -0,0 +1,305 @@
+"""
+Robert Brewer was the original author of the module this module has heavily
+inspired from. http://www.aminus.net/wiki/HTTPREPL
+"""
+import warnings
+from itertools import count
+import codeop
+import inspect
+import os
+import re
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+import sys
+import traceback
+
+from webob import Request, Response, exc
+
+try:
+ from formencode import Invalid
+ have_formencode = True
+except ImportError:
+ have_formencode = False
+
+from genshi.util import LRUCache
+import tw
+from tw.api import make_middleware, Widget
+
+from widgetbrowser import util, widgets
+
+class HTTPREPL:
+
+ def __init__(self, locals=None):
+ self.locals = {}
+ if locals:
+ self.locals.update(locals)
+ self.buffer = []
+
+ def push(self, line):
+ """Push 'line' and return exec results (None if more input needed)."""
+ if line == "help":
+ return "Type help(object) for help about object."
+ if line == "help()":
+ return "You cannot call help() without an argument."
+
+ self.buffer.append(line)
+ source = "\n".join(self.buffer)
+
+ try:
+ code = codeop.compile_command(source, "<HTTP input>", 'single')
+ except (OverflowError, SyntaxError, ValueError):
+ self.buffer = []
+ return traceback.format_exc()
+
+ if code is None:
+ # More lines needed.
+ return None
+
+ self.buffer = []
+ return self.execute(code)
+
+ def execute(self, code):
+ """Execute the given code in self.locals and return any stdout/sterr."""
+ out = StringIO()
+ oldout = sys.stdout
+ olderr = sys.stderr
+ sys.stdout = sys.stderr = out
+ try:
+ try:
+ exec code in self.locals
+ except:
+ result = traceback.format_exc()
+ else:
+ result = out.getvalue()
+ finally:
+ # FormEncode will break if _ is left in __builtins__ and it tries
+ # to use it as a translator
+ __builtins__.pop('_', None)
+ sys.stdout = oldout
+ sys.stderr = olderr
+ out.close()
+ return result
+
+ def dir(self, line):
+ """Examine a partial line and provide attr list of final expr."""
+ line = re.split(r"\s", line)[-1].strip()
+ # Support lines like "thing.attr" as "thing.", because the browser
+ # may not finish calculating the partial line until after the user
+ # has clicked on a few more keys.
+ line = ".".join(line.split(".")[:-1])
+ try:
+ result = eval("dir(%s)" % line, {}, self.locals)
+ except:
+ return []
+ return result
+
+ def doc(self, line):
+ """Examine a partial line and provide sig+doc of final expr."""
+ line = re.split(r"\s", line)[-1].strip()
+ # Support lines like "func(text" as "func(", because the browser
+ # may not finish calculating the partial line until after the user
+ # has clicked on a few more keys.
+ line = "(".join(line.split("(")[:-1])
+ try:
+ result = eval(line, {}, self.locals)
+ try:
+ if isinstance(result, type):
+ func = result.__init__
+ else:
+ func = result
+ args, varargs, varkw, defaults = inspect.getargspec(func)
+ except TypeError:
+ if callable(result):
+ doc = getattr(result, "__doc__", "") or ""
+ return "%s\n\n%s" % (line, doc)
+ return None
+ except:
+ return None
+
+ if args and args[0] == 'self':
+ args.pop(0)
+ missing = object()
+ defaults = defaults or []
+ defaults = ([missing] * (len(args) - len(defaults))) + list(defaults)
+ arglist = []
+ for a, d in zip(args, defaults):
+ if d is missing:
+ arglist.append(a)
+ else:
+ arglist.append("%s=%s" % (a, d))
+ if varargs:
+ arglist.append("*%s" % varargs)
+ if varkw:
+ arglist.append("**%s" % varkw)
+ doc = getattr(result, "__doc__", "") or ""
+ return "%s(%s)\n%s" % (line, ", ".join(arglist), doc)
+
+
+class DeferredDisplay(object):
+ """Wraps a widget and the args passed to display/render so we can defer
+ its display to another request.
+
+ .. note::
+ The JS code is dependent on the output of __repr__ since it parses it
+ to know a widget is being displayed so it can open an overlay.
+ """
+ _counter = count(0)
+ def __init__(self, widget, value, **kw):
+ self.id = self._counter.next()
+ self.value = value
+ self.widget = widget
+ self.kw = kw
+
+ def display(self):
+ """
+ Displays the widget as it was intended to be displayed when it was
+ wrapped.
+ """
+ return self.widget.display(self.value, **self.kw)
+
+ __call__ = display
+
+ def __repr__(self):
+ data = (self.id, self.widget.__class__)
+ return self.__class__.__name__ + repr(data)
+
+
+class WidgetReplApp(object):
+ def __init__(self, locals=None, widget_browser=None, max_dialogs=10):
+ self.repl = HTTPREPL(locals)
+ warnings.warn("\n"*2 + "*"*79 + "\n"
+ "DISCLAIMER:\n"
+ "Running this app poses a significant security threat "
+ "if accessible to an \nattacker. Make sure the server is "
+ "bound to the loopback interface or behind\na firewall "
+ "and that there are no local untrusted users.\n" + "*"*79)
+ if widget_browser:
+ self.widget_browser = widget_browser
+ self.displayed_widgets = LRUCache(max_dialogs)
+ self.setup_tw()
+
+ def setup_tw(repl_app):
+ # Stack TW's middleware configured with dummy default_view to signal
+ # that a widget is being displayed so we can wrap and register its
+ # output.
+ conf = {'toscawidgets.framework.default_view' : 'tw_repl',
+ 'toscawidgets.middleware.inject_resources' : True}
+ repl_app.app = make_middleware(repl_app.app, conf)
+ # monkey-patch display and render to hijack output
+ def wrap(f):
+ if f.func_name == 'wrapper':
+ return f
+ def wrapper(self, value=None, **kw):
+ if self.displays_on == 'tw_repl':
+ o = DeferredDisplay(self, value, **kw)
+ repl_app.displayed_widgets[o.id] = o
+ else:
+ o = f(self, value, **kw)
+ return o
+ return wrapper
+ Widget.display = wrap(Widget.display)
+ Widget.render = wrap(Widget.render)
+
+ def __call__(self, environ, start_response):
+ assert not environ['wsgi.multiprocess'], "Cannot run in a multiprocess"\
+ " environment"
+ return self.app(environ, start_response)
+
+ def app(self, environ, start_response):
+ """Main dispatcher. pops PATH_INFO and delegates to exposed methods."""
+ req = Request(environ.copy())
+ resp = Response(request=req, content_type='text/html; charset=UTF8')
+ first_part = req.path_info_pop() or 'index'
+ method = getattr(self, first_part, None)
+ if getattr(method, 'exposed', False):
+ output = method(req, resp)
+ if isinstance(output, unicode):
+ resp.body = output.encode('utf-8')
+ elif isinstance(output, str):
+ resp.body = output
+ elif output:
+ resp = output
+ else:
+ resp = exc.HTTPNotImplemented()
+ return resp(environ, start_response)
+
+ def index(self, req, resp):
+ """Return an HTTP-based Read-Eval-Print-Loop terminal."""
+ # Override default_view so resources display properly
+ tw.framework.default_view = 'toscawidgets'
+ tpl = '<html><head><title>"%(title)s</title></head>' \
+ '<body class="flora">%(repl)s</body></html>'
+ prefix = req.script_name + '/'
+ return tpl % {'title': 'WidgetBrowser Terminal',
+ 'repl': widgets.repl(prefix=req.script_name + '/')}
+ index.exposed = True
+
+ def push(self, req, resp):
+ """Push 'line' and return exec results as a bare response."""
+ line = req.params['line']
+ result = self.repl.push(line)
+ if result is None:
+ # More input lines needed.
+ resp.status_int = 204
+ return result
+ push.exposed = True
+
+ def dir(self, req, resp):
+ """Push 'line' and return result of eval on the final expr."""
+ line = req.params['line']
+ result = self.repl.dir(line)
+ if not result:
+ resp.status_int = 204
+ return
+ return repr(result)
+ dir.exposed = True
+
+ def doc(self, req, resp):
+ """Push 'line' and return result of getargspec on the final expr."""
+ line = req.params['line']
+ result = self.repl.doc(line)
+ if not result:
+ resp.status_int = 204
+ return result
+ doc.exposed = True
+
+ def enrich_namespace(self, ns, request):
+
+ _disp = request.GET.get('_disp', '')
+
+ if not "_disp" in ns:
+ ns["_disp"]=_disp
+ if not "interactive" in ns:
+ ns["interactive"]=True
+ return ns
+
+ def widget_output(self, req, resp):
+ try:
+ key = int(req.path_info.strip('/'))
+ dd = self.displayed_widgets[key]
+ except KeyError:
+ resp.status_int = 404
+ return "There's now widget output at this URL. Maybe it has "\
+ "expired? Try increasing the 'max_dialogs' parameter"
+
+ widget = dd.widget
+ widget_name = widget.__class__.__name__
+ render = self.widget_browser.render
+ if have_formencode and req.method.upper() == "POST":
+ # A widget submission, try to validate.
+ try:
+ value = widget.validate(req.POST)
+ value = util.pretty_print(value)
+ return render('validation_result.html', locals())
+ except Invalid, error:
+ pass
+ # Override default_view because WidgetBrowser renders on Genshi, not
+ # 'tw_repl', this is needed so widget and resources display properly
+ tw.framework.default_view = 'genshi'
+ widget_output = dd.display()
+ return render('show_widget.html', self.enrich_namespace(locals(),request=req))
+ widget_output.exposed = True
diff --git a/moksha/widgetbrowser/widgetbrowser/sphinx_ext.py b/moksha/widgetbrowser/widgetbrowser/sphinx_ext.py
new file mode 100644
index 0000000..f0c9bea
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/sphinx_ext.py
@@ -0,0 +1,43 @@
+import os
+from docutils import nodes, utils
+from docutils.parsers.rst import directives
+
+from widgetbrowser import util, widgets
+
+widget_tabs = widgets.WidgetBrowserTabs(in_sphinx=True)
+
+def widgetbrowser_directive(dirname, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Processes the `widgetbrowser` reStructuredText directive.
+
+ When generating the URL for the widget it peeks into os.environ for the
+ 'TW_BROWSER_PREFIX' environment variable.
+ """
+ widget_path = arguments[0]
+ widget = util.import_widget(widget_path)
+ if not widget:
+ reporter = state.document.reporter
+ msg = reporter.warning(
+ 'No widget found at %r' % widget_path, line=lineno)
+ prb = nodes.problematic(block_text, block_text, msg)
+ return [msg, prb]
+ tabs = options.get('tabs') or widget_tabs.tabs
+ prefix = os.environ.get('TW_BROWSER_PREFIX')
+ size = options.get('size')
+ html = widget_tabs(widget, tabs=tabs, prefix=prefix, size=size)
+ node = nodes.raw('', html, format='html')
+ return [node]
+
+
+def _get_tabs(arg):
+ if arg is None:
+ return []
+ return [s.strip() for s in arg.split(',')]
+
+def _get_size(arg):
+ return arg or "small"
+
+def setup(app):
+ browser_options = {'tabs': _get_tabs, 'size':_get_size}
+ app.add_directive('widgetbrowser', widgetbrowser_directive, 1, (1, 0, 1),
+ **browser_options)
diff --git a/moksha/widgetbrowser/widgetbrowser/static/httprepl.css b/moksha/widgetbrowser/widgetbrowser/static/httprepl.css
new file mode 100644
index 0000000..6eda851
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/httprepl.css
@@ -0,0 +1,78 @@
+.httprepl .output pre {
+ font: 10pt monospace;
+ margin: 0;
+ padding: 1px;
+ border: 1px solid #E0E0FF;
+ background-color: #F8F8FF;
+
+ white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
+ white-space: -pre-wrap; /* Opera 4 - 6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
+ http://www.w3.org/TR/css3-text/#white-space */
+ word-wrap: break-word; /* IE 5.5+ */
+}
+
+.httprepl .output pre.stdin {
+ border: none;
+ background-color: transparent;
+}
+
+form {
+ font: 10pt monospace;
+ margin: 0;
+}
+
+.httprepl .input {
+ font: 10pt monospace;
+ width: 95%;
+ border-top: none;
+ border-right: 1px dotted #E0E0FF;
+ border-bottom: none;
+ border-left: 1px dotted #E0E0FF;
+}
+
+.httprepl .tipbar {
+ position: fixed;
+ top: 10px;
+
+ /* See http://annevankesteren.nl/test/examples/ie/position-fixed.html */
+ _position:absolute;
+ _top:expression(eval(document.body.scrollTop) + 10);
+
+ right: 10px;
+
+ max-width: 50%;
+ max-height: 80%;
+ /* See http://www.svendtofte.com/code/max_width_in_ie/ */
+ width: expression(document.body.clientWidth / 2);
+ height: expression(document.body.clientHeight * 0.8);
+
+ border: 2px outset #DDCCBB;
+ background-color: #FFEEDD;
+ font: 9pt monospace;
+
+ margin: 0;
+ padding: 4px;
+
+ white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
+ white-space: -pre-wrap; /* Opera 4 - 6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
+ http://www.w3.org/TR/css3-text/#white-space */
+ word-wrap: break-word; /* IE 5.5+ */
+
+ display: none;
+ overflow: auto;
+}
+
+.httprepl .tipbar a {
+ padding: 4px;
+ text-decoration: none;
+ color: #666666;
+}
+
+.widget-dialog {
+ background: #fff;
+ z-index: 9999;
+}
diff --git a/moksha/widgetbrowser/widgetbrowser/static/httprepl.js b/moksha/widgetbrowser/widgetbrowser/static/httprepl.js
new file mode 100644
index 0000000..a85f1ef
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/httprepl.js
@@ -0,0 +1,432 @@
+var HTTPRepl = (function ($) {
+ function http() {
+ var h;
+ if (typeof(XMLHttpRequest) != "undefined") {
+ h = new XMLHttpRequest();
+ } else {
+ try { h = new ActiveXObject("Msxml2.XMLHTTP"); }
+ catch (e) {
+ try { h = new ActiveXObject("Microsoft.XMLHTTP"); }
+ catch (E) { alert("Your browser is not supported."); }
+ }
+ }
+ return h
+ }
+
+
+ // HISTORY NAVIGATION //
+
+ function use_history(elem) {
+ var content = get_text(elem);
+ // Strip the leading prompt
+ if (elem.className == 'stdin') content = content.substr(4);
+ input.value = content;
+ input.focus();
+ }
+
+ function history_hook() {
+ use_history(this);
+ }
+
+ var current_history = undefined;
+
+ function prev_history() {
+ if (current_history == undefined) {
+ var prev = output.lastChild;
+ } else {
+ var prev = current_history.previousSibling;
+ }
+ while (prev != null && prev.className != 'stdin') {
+ prev = prev.previousSibling;
+ }
+ if (prev != null) {
+ current_history = prev;
+ use_history(prev);
+ }
+ }
+
+ function next_history() {
+ if (current_history == undefined) return;
+
+ var next = current_history.nextSibling;
+ while (next != null && next.className != 'stdin') {
+ next = next.nextSibling;
+ }
+ if (next != null) {
+ current_history = next;
+ use_history(next);
+ }
+ }
+
+
+ // CODE COMPLETION //
+
+ current_range = undefined;
+
+ function partial_line() {
+ if (document.selection) {
+ // Internet Explorer
+ current_range = document.selection.createRange();
+ var end = current_range.getBookmark().charCodeAt(2) - 2;
+ } else {
+ var end = input.selectionEnd;
+ }
+ return input.value.substring(0, end);
+ }
+
+ function insert_text(newtext) {
+ if (document.selection) {
+ // Internet Explorer
+ current_range.text = newtext;
+ current_range.select();
+ } else {
+ var start = input.selectionStart;
+ input.value = input.value.substring(0, start) + newtext + input.value.substr(input.selectionEnd);
+ var end = start + newtext.length;
+ input.setSelectionRange(end, end);
+ }
+ }
+
+ function clear_tips() {
+ tipbar.style.display = '';
+ while (tipbar.hasChildNodes()) {
+ tipbar.removeChild(tipbar.lastChild);
+ }
+ }
+
+ function show_tips() {
+ tipbar.style.display = 'block';
+ }
+
+ var intip = false;
+
+ function use_tip() {
+ insert_text(get_text(this));
+ clear_tips();
+ intip = true;
+ input.focus();
+ }
+
+ function dir() {
+ var data = partial_line();
+
+ clear_tips();
+
+ var h = http();
+ h.onreadystatechange = function() {
+ if (h.readyState == 4) {
+ try {
+ var status = h.status;
+ } catch(e) {
+ var status = "NO HTTP RESPONSE";
+ }
+ switch (status) {
+ case 200:
+ var tips = eval(h.responseText);
+ for (var i=0; i < tips.length; i++) {
+ var tiplink = document.createElement("a");
+ tiplink.onclick = use_tip;
+ tiplink.href = "javascript:void(0)";
+ set_text(tiplink, tips[i]);
+ tipbar.appendChild(tiplink);
+ tipbar.appendChild(document.createElement("br"));
+ }
+ show_tips()
+ input.focus();
+ break;
+ // Internet Explorer might return 1223 for 204
+ case 1223:
+ case 204:
+ // No tips available
+ break;
+ case 12029:
+ // Internet Explorer client could not connect to server
+ status = "NO HTTP RESPONSE";
+ case 403:
+ stdout_write("Interactive mode is disabled", false);
+ break;
+ default:
+ stdout_write(status + "\n" + h.responseText, false);
+ }
+ }
+ }
+ h.open("GET", prefix + "dir?line=" + escape(data), true);
+ h.send(null);
+ }
+
+ function doc() {
+ var data = partial_line();
+
+ clear_tips();
+
+ var h = http();
+ h.onreadystatechange = function() {
+ if (h.readyState == 4) {
+ try {
+ var status = h.status;
+ } catch(e) {
+ var status = "NO HTTP RESPONSE";
+ }
+ switch (status) {
+ case 200:
+ tipbar.appendChild(document.createTextNode(h.responseText));
+ show_tips();
+ input.focus();
+ break;
+ // Internet Explorer might return 1223 for 204
+ case 1223:
+ case 403:
+ stdout_write("Interactive mode is disabled", false);
+ break;
+ case 204:
+ // No tips available
+ break;
+ case 12029:
+ // Internet Explorer client could not connect to server
+ status = "NO HTTP RESPONSE";
+ default:
+ stdout_write(status + "\n" + h.responseText, false);
+ }
+ }
+ }
+ h.open("GET", prefix + "doc?line=" + escape(data), true);
+ h.send(null);
+ }
+
+ // COMMAND EXECUTION //
+
+ function get_text(elem) {
+ if (elem.innerText != undefined) {
+ // Internet Explorer
+ return elem.innerText;
+ } else {
+ // Mozilla
+ return elem.textContent;
+ }
+ }
+
+ function set_text(elem, newvalue) {
+ if (elem.innerText != undefined) {
+ // Internet Explorer
+ elem.innerText = newvalue;
+ } else {
+ // Mozilla
+ elem.textContent = newvalue;
+ }
+ }
+
+ function get_prompt() {
+ return get_text(prompt_);
+ }
+
+ function set_prompt(newvalue) {
+ set_text(prompt_, newvalue);
+ }
+
+ function stdout_write(content, stdin) {
+ current_history = undefined;
+ if (content == "") return;
+
+ var block = document.createElement("pre");
+ block.ondblclick = history_hook;
+ if (stdin) {
+ content = get_prompt() + content;
+ block.className = 'stdin';
+ }
+ if (block.innerText != undefined) {
+ // Internet Explorer quirkiness
+ block.innerText = content;
+ } else {
+ block.appendChild(document.createTextNode(content));
+ }
+ output.appendChild(block);
+ }
+
+ whitespace = /^\s+$/;
+
+ function push() {
+ var data = input.value;
+ // Uncomment to treat a line with only whitespace like a blank line
+ // if (whitespace.test(data)) data = "";
+
+ input.value = "";
+
+ var h = http();
+ h.onreadystatechange = function() {
+ if (h.readyState == 4) {
+ stdout_write(data, true);
+ try {
+ var status = h.status;
+ } catch(e) {
+ var status = "NO HTTP RESPONSE";
+ }
+ switch (status) {
+ case 200:
+ set_prompt(">>> ");
+ var response = h.responseText;
+ if (!handle_widget_output(response)) {
+ stdout_write(response, false);
+ }
+ break;
+ // Internet Explorer might return 1223 for 204
+ case 1223:
+ case 204:
+ set_prompt("... ");
+ // input.value *should* be blank, but just in case...
+ input.value = " " + input.value;
+ break;
+ case 403:
+ stdout_write("Interactive mode is disabled", false);
+ break;
+ case 12029:
+ // Internet Explorer client could not connect to server
+ status = "NO HTTP RESPONSE";
+ default:
+ stdout_write(status + "\n" + h.responseText, false);
+ }
+ input.focus();
+ }
+ }
+ h.open("POST", prefix + "push", true);
+ h.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ h.send("line=" + escape(data));
+ }
+
+
+ function escape(data) {
+ data = data.replace(/%/gi, "%25");
+ data = data.replace(/&/gi, "%26");
+ data = data.replace(/[+]/gi, "%2B");
+ data = data.replace(/;/gi, "%3B");
+ return data;
+ }
+
+
+ // SETUP //
+
+ function mapKeys(key_code) {
+ if (intip) {
+ intip = false;
+ // Trap the bubbling keyup event from a tiplink. This means that,
+ // if you actually click a tiplink instead of tab and hit 'enter',
+ // you have to hit 'enter' twice to push the line. :(
+ if (key_code == 13) return;
+ }
+ switch(key_code) {
+ case 8: // backspace
+ clear_tips();
+ break;
+ case 13: // enter
+ clear_tips();
+ push();
+ break;
+ case 38: // up arrow
+ prev_history();
+ break;
+ case 40: // down arrow
+ next_history();
+ break;
+ case 48: // close paren "("
+ clear_tips();
+ break;
+ case 57: // open paren "("
+ doc();
+ break;
+ case 190: // period "."
+ dir();
+ break;
+ }
+ }
+
+ function trapKeys(e) {
+ if (!e) var e = window.event;
+ mapKeys(e.keyCode);
+ }
+
+ // WIDGET DIALOGS //
+
+ var new_id = (function make_counter(value) {
+ var state = {value: value || 0};
+ function next() {
+ state.value ++;
+ return 'widget-dialog-' + state.value;
+ }
+ return next;
+ })();
+
+ function open_dialog(config) {
+ var c = $.extend({}, {height:450, width:600}, config);
+ var iframe = $('<iframe><iframe>');
+ iframe.attr({id: new_id(), 'class': 'widget-dialog'});
+ function setSize(size) {
+ var attr = {
+ height: Math.max(0, Math.round(size.height-60)),
+ width: Math.max(0, Math.round(size.width-40))
+ }
+ iframe.attr(attr);
+ }
+ function onResizeStart(event, data) {
+ // Hide the iframe so it doesn't captute mouse events while dragging
+ // the resize handlers
+ iframe.hide();
+ }
+ function onResizeStop(event, data) {
+ setSize(data.instance.size);
+ iframe.show();
+ }
+ function onClose() {
+ iframe.remove();
+ input.focus();
+ }
+ iframe.appendTo(httprepl).dialog(config)
+ .bind('dialogclose', onClose)
+ .trigger('setData.dialog', ['resizeStart', onResizeStart])
+ .trigger('setData.dialog', ['resizeStop', onResizeStop])
+ .attr('src', config.url)
+ .dialog('open');
+ setSize(c);
+ }
+
+ var displayed_widget = /DeferredDisplay\((\d+)[^']*'([^']+)'/;
+
+ function handle_widget_output(response) {
+ var match = displayed_widget(response);
+ if (match) {
+ var config = {
+ url: prefix + 'widget_output/' + match[1],
+ height: 500,
+ width: 750,
+ title: match[2]
+ }
+ open_dialog(config);
+ return true;
+ }
+ return false;
+ }
+ var httprepl = $(''
+ +'<div class="httprepl">'
+ + '<div class="output"></div>'
+ + '<form action="" class="terminal">'
+ + '<div class="tipbar"></div>'
+ + '<nobr>'
+ + '<span class="prompt">>>> </span>'
+ + '<input type="text" class="input" size=60" />'
+ + '</nobr>'
+ + '</form>'
+ +'</div>'
+ );
+ var prefix = '';
+ var input = $('.input', httprepl)[0];
+ input.onkeyup = trapKeys;
+ var output = $('.output', httprepl)[0];
+ var tipbar = $('.tipbar', httprepl)[0];
+ var prompt_ = $('.prompt', httprepl)[0];
+ $('form', httprepl).submit(function() { return false });
+
+ return {
+ render: function(el, config) {
+ prefix = config.prefix || '';
+ httprepl.appendTo($(el));
+ }
+ }
+})(jQuery);
diff --git a/moksha/widgetbrowser/widgetbrowser/static/jquery.js b/moksha/widgetbrowser/widgetbrowser/static/jquery.js
new file mode 100644
index 0000000..ea64073
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/jquery.js
@@ -0,0 +1,3436 @@
+(function(){
+/*
+ * jQuery 1.2.4a - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-04-08 13:40:03 -0300 (ter, 08 abr 2008) $
+ * $Rev: 5214 $
+ */
+
+// Map over jQuery in case of overwrite
+if ( window.jQuery )
+ var _jQuery = window.jQuery;
+
+var jQuery = window.jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.prototype.init( selector, context );
+};
+
+// Map over the $ in case of overwrite
+if ( window.$ )
+ var _$ = window.$;
+
+// Map the jQuery namespace to the '$' one
+window.$ = jQuery;
+
+// A simple way to check for HTML strings or ID strings
+// (both of which we optimize for)
+var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
+
+// Is it a simple selector
+var isSimple = /^.[^:#\[\.]*$/;
+
+jQuery.fn = jQuery.prototype = {
+ init: function( selector, context ) {
+ // Make sure that a selection was provided
+ selector = selector || document;
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // Handle HTML strings
+ } else if ( typeof selector == "string" ) {
+ // Are we dealing with HTML string or an ID?
+ var match = quickExpr.exec( selector );
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] )
+ selector = jQuery.clean( [ match[1] ], context );
+
+ // HANDLE: $("#id")
+ else {
+ var elem = document.getElementById( match[3] );
+
+ // Make sure an element was located
+ if ( elem )
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id != match[3] )
+ return jQuery().find( selector );
+
+ // Otherwise, we inject the element directly into the jQuery object
+ else {
+ this[0] = elem;
+ this.length = 1;
+ return this;
+ }
+
+ else
+ selector = [];
+ }
+
+ // HANDLE: $(expr, [context])
+ // (which is just equivalent to: $(content).find(expr)
+ } else
+ return new jQuery( context ).find( selector );
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) )
+ return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
+
+ return this.setArray(
+ // HANDLE: $(array)
+ selector.constructor == Array && selector ||
+
+ // HANDLE: $(arraylike)
+ // Watch for when an array-like object, contains DOM nodes, is passed in as the selector
+ (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) ||
+
+ // HANDLE: $(*)
+ [ selector ] );
+ },
+
+ // The current version of jQuery being used
+ jquery: "1.2.4a",
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ // The number of elements contained in the matched element set
+ length: 0,
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == undefined ?
+
+ // Return a 'clean' array
+ jQuery.makeArray( this ) :
+
+ // Return just the object
+ this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+ // Build a new jQuery matched element set
+ var ret = jQuery( elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Force the current matched set of elements to become
+ // the specified array of elements (destroying the stack in the process)
+ // You should use pushStack() in order to do this, but maintain the stack
+ setArray: function( elems ) {
+ // Resetting the length to 0, then using the native Array push
+ // is a super-fast way to populate an object with array-like properties
+ this.length = 0;
+ Array.prototype.push.apply( this, elems );
+
+ return this;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ var ret = -1;
+
+ // Locate the position of the desired element
+ this.each(function(i){
+ if ( this == elem )
+ ret = i;
+ });
+
+ return ret;
+ },
+
+ attr: function( name, value, type ) {
+ var options = name;
+
+ // Look for the case where we're accessing a style value
+ if ( name.constructor == String )
+ if ( value == undefined )
+ return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined;
+
+ else {
+ options = {};
+ options[ name ] = value;
+ }
+
+ // Check to see if we're setting style values
+ return this.each(function(i){
+ // Set all the styles
+ for ( name in options )
+ jQuery.attr(
+ type ?
+ this.style :
+ this,
+ name, jQuery.prop( this, options[ name ], type, i, name )
+ );
+ });
+ },
+
+ css: function( key, value ) {
+ // ignore negative width and height values
+ if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
+ value = undefined;
+ return this.attr( key, value, "curCSS" );
+ },
+
+ text: function( text ) {
+ if ( typeof text != "object" && text != null )
+ return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+
+ var ret = "";
+
+ jQuery.each( text || this, function(){
+ jQuery.each( this.childNodes, function(){
+ if ( this.nodeType != 8 )
+ ret += this.nodeType != 1 ?
+ this.nodeValue :
+ jQuery.fn.text( [ this ] );
+ });
+ });
+
+ return ret;
+ },
+
+ wrapAll: function( html ) {
+ if ( this[0] )
+ // The elements to wrap the target around
+ jQuery( html, this[0].ownerDocument )
+ .clone()
+ .insertBefore( this[0] )
+ .map(function(){
+ var elem = this;
+
+ while ( elem.firstChild )
+ elem = elem.firstChild;
+
+ return elem;
+ })
+ .append(this);
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ return this.each(function(){
+ jQuery( this ).contents().wrapAll( html );
+ });
+ },
+
+ wrap: function( html ) {
+ return this.each(function(){
+ jQuery( this ).wrapAll( html );
+ });
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, false, function(elem){
+ if (this.nodeType == 1)
+ this.appendChild( elem );
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, true, function(elem){
+ if (this.nodeType == 1)
+ this.insertBefore( elem, this.firstChild );
+ });
+ },
+
+ before: function() {
+ return this.domManip(arguments, false, false, function(elem){
+ this.parentNode.insertBefore( elem, this );
+ });
+ },
+
+ after: function() {
+ return this.domManip(arguments, false, true, function(elem){
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ },
+
+ end: function() {
+ return this.prevObject || jQuery( [] );
+ },
+
+ find: function( selector ) {
+ var elems = jQuery.map(this, function(elem){
+ return jQuery.find( selector, elem );
+ });
+
+ return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
+ jQuery.unique( elems ) :
+ elems );
+ },
+
+ clone: function( events ) {
+ // Do the clone
+ var ret = this.map(function(){
+ if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
+ // IE copies events bound via attachEvent when
+ // using cloneNode. Calling detachEvent on the
+ // clone will also remove the events from the orignal
+ // In order to get around this, we use innerHTML.
+ // Unfortunately, this means some modifications to
+ // attributes in IE that are actually only stored
+ // as properties will not be copied (such as the
+ // the name attribute on an input).
+ var clone = this.cloneNode(true),
+ container = document.createElement("div");
+ container.appendChild(clone);
+ return jQuery.clean([container.innerHTML])[0];
+ } else
+ return this.cloneNode(true);
+ });
+
+ // Need to set the expando to null on the cloned set if it exists
+ // removeData doesn't work here, IE removes it from the original as well
+ // this is primarily for IE but the data expando shouldn't be copied over in any browser
+ var clone = ret.find("*").andSelf().each(function(){
+ if ( this[ expando ] != undefined )
+ this[ expando ] = null;
+ });
+
+ // Copy the events from the original to the clone
+ if ( events === true )
+ this.find("*").andSelf().each(function(i){
+ if (this.nodeType == 3)
+ return;
+ var events = jQuery.data( this, "events" );
+
+ for ( var type in events )
+ for ( var handler in events[ type ] )
+ jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
+ });
+
+ // Return the cloned set
+ return ret;
+ },
+
+ filter: function( selector ) {
+ return this.pushStack(
+ jQuery.isFunction( selector ) &&
+ jQuery.grep(this, function(elem, i){
+ return selector.call( elem, i );
+ }) ||
+
+ jQuery.multiFilter( selector, this ) );
+ },
+
+ not: function( selector ) {
+ if ( selector.constructor == String )
+ // test special case where just one selector is passed in
+ if ( isSimple.test( selector ) )
+ return this.pushStack( jQuery.multiFilter( selector, this, true ) );
+ else
+ selector = jQuery.multiFilter( selector, this );
+
+ var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
+ return this.filter(function() {
+ return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
+ });
+ },
+
+ add: function( selector ) {
+ return !selector ? this : this.pushStack( jQuery.merge(
+ this.get(),
+ selector.constructor == String ?
+ jQuery( selector ).get() :
+ selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ?
+ selector : [selector] ) );
+ },
+
+ is: function( selector ) {
+ return selector ?
+ jQuery.multiFilter( selector, this ).length > 0 :
+ false;
+ },
+
+ hasClass: function( selector ) {
+ return this.is( "." + selector );
+ },
+
+ val: function( value ) {
+ if ( value == undefined ) {
+
+ if ( this.length ) {
+ var elem = this[0];
+
+ // We need to handle select boxes special
+ if ( jQuery.nodeName( elem, "select" ) ) {
+ var index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type == "select-one";
+
+ // Nothing was selected
+ if ( index < 0 )
+ return null;
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ if ( option.selected ) {
+ // Get the specifc value for the option
+ value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
+
+ // We don't need an array for one selects
+ if ( one )
+ return value;
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+
+ // Everything else, we just grab the value
+ } else
+ return (this[0].value || "").replace(/\r/g, "");
+
+ }
+
+ return undefined;
+ }
+
+ return this.each(function(){
+ if ( this.nodeType != 1 )
+ return;
+
+ if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
+ this.checked = (jQuery.inArray(this.value, value) >= 0 ||
+ jQuery.inArray(this.name, value) >= 0);
+
+ else if ( jQuery.nodeName( this, "select" ) ) {
+ var values = value.constructor == Array ?
+ value :
+ [ value ];
+
+ jQuery( "option", this ).each(function(){
+ this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
+ jQuery.inArray( this.text, values ) >= 0);
+ });
+
+ if ( !values.length )
+ this.selectedIndex = -1;
+
+ } else
+ this.value = value;
+ });
+ },
+
+ html: function( value ) {
+ return value == undefined ?
+ (this.length ?
+ this[0].innerHTML :
+ null) :
+ this.empty().append( value );
+ },
+
+ replaceWith: function( value ) {
+ return this.after( value ).remove();
+ },
+
+ eq: function( i ) {
+ return this.slice( i, i + 1 );
+ },
+
+ slice: function() {
+ return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function(elem, i){
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ },
+
+ data: function( key, value ){
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value == null ) {
+ var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ if ( data == undefined && this.length )
+ data = jQuery.data( this[0], key );
+
+ return data == null && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ } else
+ return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
+ jQuery.data( this, key, value );
+ });
+ },
+
+ removeData: function( key ){
+ return this.each(function(){
+ jQuery.removeData( this, key );
+ });
+ },
+
+ domManip: function( args, table, reverse, callback ) {
+ var clone = this.length > 1, elems;
+
+ return this.each(function(){
+ if ( !elems ) {
+ elems = jQuery.clean( args, this.ownerDocument );
+
+ if ( reverse )
+ elems.reverse();
+ }
+
+ var obj = this;
+
+ if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
+ obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
+
+ var scripts = jQuery( [] );
+
+ jQuery.each(elems, function(){
+ var elem = clone ?
+ jQuery( this ).clone( true )[0] :
+ this;
+
+ // execute all scripts after the elements have been injected
+ if ( jQuery.nodeName( elem, "script" ) ) {
+ scripts = scripts.add( elem );
+ } else {
+ // Remove any inner scripts for later evaluation
+ if ( elem.nodeType == 1 )
+ scripts = scripts.add( jQuery( "script", elem ).remove() );
+
+ // Inject the elements into the document
+ callback.call( obj, elem );
+ }
+ });
+
+ scripts.each( evalScript );
+ });
+ }
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.prototype.init.prototype = jQuery.prototype;
+
+function evalScript( i, elem ) {
+ if ( elem.src )
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+
+ else
+ jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+
+ if ( elem.parentNode )
+ elem.parentNode.removeChild( elem );
+}
+
+jQuery.extend = jQuery.fn.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+ // Handle a deep copy situation
+ if ( target.constructor == Boolean ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target != "object" && typeof target != "function" )
+ target = {};
+
+ // extend jQuery itself if only one argument is passed
+ if ( length == 1 ) {
+ target = this;
+ i = 0;
+ }
+
+ for ( ; i < length; i++ )
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null )
+ // Extend the base object
+ for ( var name in options ) {
+ // Prevent never-ending loop
+ if ( target === options[ name ] )
+ continue;
+
+ // Recurse if we're merging object values
+ if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType )
+ target[ name ] = jQuery.extend( deep, target[ name ], options[ name ] );
+
+ // Don't bring in undefined values
+ else if ( options[ name ] != undefined )
+ target[ name ] = options[ name ];
+
+ }
+
+ // Return the modified object
+ return target;
+};
+
+var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {};
+
+// exclude the following css properties to add px
+var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ window.$ = _$;
+
+ if ( deep )
+ window.jQuery = _jQuery;
+
+ return jQuery;
+ },
+
+ // See test/unit/core.js for details concerning this function.
+ isFunction: function( fn ) {
+ return !!fn && typeof fn != "string" && !fn.nodeName &&
+ fn.constructor != Array && /function/i.test( fn + "" );
+ },
+
+ // check if an element is in a (or is an) XML document
+ isXMLDoc: function( elem ) {
+ return elem.documentElement && !elem.body ||
+ elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+ },
+
+ // Evalulates a script in a global context
+ globalEval: function( data ) {
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Inspired by code by Andrea Giammarchi
+ // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom...
+ var head = document.getElementsByTagName("head")[0] || document.documentElement,
+ script = document.createElement("script");
+
+ script.type = "text/javascript";
+ if ( jQuery.browser.msie )
+ script.text = data;
+ else
+ script.appendChild( document.createTextNode( data ) );
+
+ head.appendChild( script );
+ head.removeChild( script );
+ }
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
+ },
+
+ cache: {},
+
+ data: function( elem, name, data ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // Compute a unique ID for the element
+ if ( !id )
+ id = elem[ expando ] = ++uuid;
+
+ // Only generate the data cache if we're
+ // trying to access or manipulate it
+ if ( name && !jQuery.cache[ id ] )
+ jQuery.cache[ id ] = {};
+
+ // Prevent overriding the named cache with undefined values
+ if ( data != undefined )
+ jQuery.cache[ id ][ name ] = data;
+
+ // Return the named cache data, or the ID for the element
+ return name ?
+ jQuery.cache[ id ][ name ] :
+ id;
+ },
+
+ removeData: function( elem, name ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // If we want to remove a specific section of the element's data
+ if ( name ) {
+ if ( jQuery.cache[ id ] ) {
+ // Remove the section of cache data
+ delete jQuery.cache[ id ][ name ];
+
+ // If we've removed all the data, remove the element's cache
+ name = "";
+
+ for ( name in jQuery.cache[ id ] )
+ break;
+
+ if ( !name )
+ jQuery.removeData( elem );
+ }
+
+ // Otherwise, we want to remove all of the element's data
+ } else {
+ // Clean up the element expando
+ try {
+ delete elem[ expando ];
+ } catch(e){
+ // IE has trouble directly removing the expando
+ // but it's ok with using removeAttribute
+ if ( elem.removeAttribute )
+ elem.removeAttribute( expando );
+ }
+
+ // Completely remove the data cache
+ delete jQuery.cache[ id ];
+ }
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ if ( args ) {
+ if ( object.length == undefined ) {
+ for ( var name in object )
+ if ( callback.apply( object[ name ], args ) === false )
+ break;
+ } else
+ for ( var i = 0, length = object.length; i < length; i++ )
+ if ( callback.apply( object[ i ], args ) === false )
+ break;
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( object.length == undefined ) {
+ for ( var name in object )
+ if ( callback.call( object[ name ], name, object[ name ] ) === false )
+ break;
+ } else
+ for ( var i = 0, length = object.length, value = object[0];
+ i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
+ }
+
+ return object;
+ },
+
+ prop: function( elem, value, type, i, name ) {
+ // Handle executable functions
+ if ( jQuery.isFunction( value ) )
+ value = value.call( elem, i );
+
+ // Handle passing in a number to a CSS property
+ return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
+ value + "px" :
+ value;
+ },
+
+ className: {
+ // internal only, use addClass("class")
+ add: function( elem, classNames ) {
+ jQuery.each((classNames || "").split(/\s+/), function(i, className){
+ if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+ elem.className += (elem.className ? " " : "") + className;
+ });
+ },
+
+ // internal only, use removeClass("class")
+ remove: function( elem, classNames ) {
+ if (elem.nodeType == 1)
+ elem.className = classNames != undefined ?
+ jQuery.grep(elem.className.split(/\s+/), function(className){
+ return !jQuery.className.has( classNames, className );
+ }).join(" ") :
+ "";
+ },
+
+ // internal only, use is(".class")
+ has: function( elem, className ) {
+ return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ callback.call( elem );
+
+ // Revert the old values
+ for ( var name in options )
+ elem.style[ name ] = old[ name ];
+ },
+
+ css: function( elem, name, force ) {
+ if ( name == "width" || name == "height" ) {
+ var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
+
+ function getWH() {
+ val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
+ var padding = 0, border = 0;
+ jQuery.each( which, function() {
+ padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+ border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+ });
+ val -= Math.round(padding + border);
+ }
+
+ if ( jQuery(elem).is(":visible") )
+ getWH();
+ else
+ jQuery.swap( elem, props, getWH );
+
+ return Math.max(0, val);
+ }
+
+ return jQuery.curCSS( elem, name, force );
+ },
+
+ curCSS: function( elem, name, force ) {
+ var ret;
+
+ // A helper method for determining if an element's values are broken
+ function color( elem ) {
+ if ( !jQuery.browser.safari )
+ return false;
+
+ var ret = document.defaultView.getComputedStyle( elem, null );
+ return !ret || ret.getPropertyValue("color") == "";
+ }
+
+ // We need to handle opacity special in IE
+ if ( name == "opacity" && jQuery.browser.msie ) {
+ ret = jQuery.attr( elem.style, "opacity" );
+
+ return ret == "" ?
+ "1" :
+ ret;
+ }
+ // Opera sometimes will give the wrong display answer, this fixes it, see #2037
+ if ( jQuery.browser.opera && name == "display" ) {
+ var save = elem.style.outline;
+ elem.style.outline = "0 solid black";
+ elem.style.outline = save;
+ }
+
+ // Make sure we're using the right name for getting the float value
+ if ( name.match( /float/i ) )
+ name = styleFloat;
+
+ if ( !force && elem.style && elem.style[ name ] )
+ ret = elem.style[ name ];
+
+ else if ( document.defaultView && document.defaultView.getComputedStyle ) {
+
+ // Only "float" is needed here
+ if ( name.match( /float/i ) )
+ name = "float";
+
+ name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+
+ var getComputedStyle = document.defaultView.getComputedStyle( elem, null );
+
+ if ( getComputedStyle && !color( elem ) )
+ ret = getComputedStyle.getPropertyValue( name );
+
+ // If the element isn't reporting its values properly in Safari
+ // then some display: none elements are involved
+ else {
+ var swap = [], stack = [];
+
+ // Locate all of the parent display: none elements
+ for ( var a = elem; a && color(a); a = a.parentNode )
+ stack.unshift(a);
+
+ // Go through and make them visible, but in reverse
+ // (It would be better if we knew the exact display type that they had)
+ for ( var i = 0; i < stack.length; i++ )
+ if ( color( stack[ i ] ) ) {
+ swap[ i ] = stack[ i ].style.display;
+ stack[ i ].style.display = "block";
+ }
+
+ // Since we flip the display style, we have to handle that
+ // one special, otherwise get the value
+ ret = name == "display" && swap[ stack.length - 1 ] != null ?
+ "none" :
+ ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || "";
+
+ // Finally, revert the display styles back
+ for ( var i = 0; i < swap.length; i++ )
+ if ( swap[ i ] != null )
+ stack[ i ].style.display = swap[ i ];
+ }
+
+ // We should always get a number back from opacity
+ if ( name == "opacity" && ret == "" )
+ ret = "1";
+
+ } else if ( elem.currentStyle ) {
+ var camelCase = name.replace(/\-(\w)/g, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+ // Remember the original values
+ var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ elem.style.left = ret || 0;
+ ret = elem.style.pixelLeft + "px";
+
+ // Revert the changed values
+ elem.style.left = style;
+ elem.runtimeStyle.left = runtimeStyle;
+ }
+ }
+
+ return ret;
+ },
+
+ clean: function( elems, context ) {
+ var ret = [];
+ context = context || document;
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if (typeof context.createElement == 'undefined')
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+
+ jQuery.each(elems, function(i, elem){
+ if ( !elem )
+ return;
+
+ if ( elem.constructor == Number )
+ elem = elem.toString();
+
+ // Convert html string into DOM nodes
+ if ( typeof elem == "string" ) {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
+ return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
+ all :
+ front + "></" + tag + ">";
+ });
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
+
+ var wrap =
+ // option or optgroup
+ !tags.indexOf("<opt") &&
+ [ 1, "<select multiple='multiple'>", "</select>" ] ||
+
+ !tags.indexOf("<leg") &&
+ [ 1, "<fieldset>", "</fieldset>" ] ||
+
+ tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
+ [ 1, "<table>", "</table>" ] ||
+
+ !tags.indexOf("<tr") &&
+ [ 2, "<table><tbody>", "</tbody></table>" ] ||
+
+ // <thead> matched above
+ (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
+ [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
+
+ !tags.indexOf("<col") &&
+ [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
+
+ // IE can't serialize <link> and <script> tags normally
+ jQuery.browser.msie &&
+ [ 1, "div<div>", "</div>" ] ||
+
+ [ 0, "", "" ];
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( wrap[0]-- )
+ div = div.lastChild;
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( jQuery.browser.msie ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
+ div.childNodes :
+ [];
+
+ for ( var j = tbody.length - 1; j >= 0 ; --j )
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( /^\s/.test( elem ) )
+ div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+
+ }
+
+ elem = jQuery.makeArray( div.childNodes );
+ }
+
+ if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
+ return;
+
+ if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
+ ret.push( elem );
+
+ else
+ ret = jQuery.merge( ret, elem );
+
+ });
+
+ return ret;
+ },
+
+ attr: function( elem, name, value ) {
+ // don't set attributes on text and comment nodes
+ if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
+ return undefined;
+
+ var fix = jQuery.isXMLDoc( elem ) ?
+ {} :
+ jQuery.props;
+
+ // Safari mis-reports the default selected property of a hidden option
+ // Accessing the parent's selectedIndex property fixes it
+ if ( name == "selected" && jQuery.browser.safari )
+ elem.parentNode.selectedIndex;
+
+ // Certain attributes only work when accessed via the old DOM 0 way
+ if ( fix[ name ] ) {
+ if ( value != undefined )
+ elem[ fix[ name ] ] = value;
+
+ return elem[ fix[ name ] ];
+
+ } else if ( jQuery.browser.msie && name == "style" )
+ return jQuery.attr( elem.style, "cssText", value );
+
+ else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName( elem, "form" ) && (name == "action" || name == "method") )
+ return elem.getAttributeNode( name ).nodeValue;
+
+ // IE elem.getAttribute passes even for style
+ else if ( elem.tagName ) {
+
+ if ( value != undefined ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
+ throw "type property can't be changed";
+
+ // convert the value to a string (all browsers do this but IE) see #1070
+ elem.setAttribute( name, "" + value );
+ }
+
+ if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) )
+ return elem.getAttribute( name, 2 );
+
+ return elem.getAttribute( name );
+
+ // elem is actually elem.style ... set the style
+ } else {
+ // IE actually uses filters for opacity
+ if ( name == "opacity" && jQuery.browser.msie ) {
+ if ( value != undefined ) {
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ elem.zoom = 1;
+
+ // Set the alpha filter to set the opacity
+ elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
+ (parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+ }
+
+ return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+ (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() :
+ "";
+ }
+
+ name = name.replace(/-([a-z])/ig, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ if ( value != undefined )
+ elem[ name ] = value;
+
+ return elem[ name ];
+ }
+ },
+
+ trim: function( text ) {
+ return (text || "").replace( /^\s+|\s+$/g, "" );
+ },
+
+ makeArray: function( array ) {
+ var ret = [];
+
+ // Need to use typeof to fight Safari childNodes crashes
+ if ( array.constructor != Array )
+ for ( var i = 0, length = array.length; i < length; i++ )
+ ret.push( array[ i ] );
+ else
+ ret = array.slice( 0 );
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+ for ( var i = 0, length = array.length; i < length; i++ )
+ if ( array[ i ] == elem )
+ return i;
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ // We have to loop this way because IE & Opera overwrite the length
+ // expando of getElementsByTagName
+
+ // Also, we need to make sure that the correct elements are being returned
+ // (IE returns comment nodes in a '*' query)
+ if ( jQuery.browser.msie ) {
+ for ( var i = 0; second[ i ]; i++ )
+ if ( second[ i ].nodeType != 8 )
+ first.push( second[ i ] );
+
+ } else
+ for ( var i = 0; second[ i ]; i++ )
+ first.push( second[ i ] );
+
+ return first;
+ },
+
+ unique: function( array ) {
+ var ret = [], done = {};
+
+ try {
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ var id = jQuery.data( array[ i ] );
+
+ if ( !done[ id ] ) {
+ done[ id ] = true;
+ ret.push( array[ i ] );
+ }
+ }
+
+ } catch( e ) {
+ ret = array;
+ }
+
+ return ret;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [];
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ )
+ if ( !inv && callback( elems[ i ], i ) || inv && !callback( elems[ i ], i ) )
+ ret.push( elems[ i ] );
+
+ return ret;
+ },
+
+ map: function( elems, callback ) {
+ var ret = [];
+
+ // Go through the array, translating each of the items to their
+ // new value (or values).
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ var value = callback( elems[ i ], i );
+
+ if ( value !== null && value != undefined ) {
+ if ( value.constructor != Array )
+ value = [ value ];
+
+ ret = ret.concat( value );
+ }
+ }
+
+ return ret;
+ }
+});
+
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+ version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
+ safari: /webkit/.test( userAgent ),
+ opera: /opera/.test( userAgent ),
+ msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+ mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+
+var styleFloat = jQuery.browser.msie ?
+ "styleFloat" :
+ "cssFloat";
+
+jQuery.extend({
+ // Check to see if the W3C box model is being used
+ boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
+
+ props: {
+ "for": "htmlFor",
+ "class": "className",
+ "float": styleFloat,
+ cssFloat: styleFloat,
+ styleFloat: styleFloat,
+ innerHTML: "innerHTML",
+ className: "className",
+ value: "value",
+ disabled: "disabled",
+ checked: "checked",
+ readonly: "readOnly",
+ selected: "selected",
+ maxlength: "maxLength",
+ selectedIndex: "selectedIndex",
+ defaultValue: "defaultValue",
+ tagName: "tagName",
+ nodeName: "nodeName"
+ }
+});
+
+jQuery.each({
+ parent: function(elem){return elem.parentNode;},
+ parents: function(elem){return jQuery.dir(elem,"parentNode");},
+ next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
+ prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
+ nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
+ prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
+ siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
+ children: function(elem){return jQuery.sibling(elem.firstChild);},
+ contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
+}, function(name, fn){
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = jQuery.map( this, fn );
+
+ if ( selector && typeof selector == "string" )
+ ret = jQuery.multiFilter( selector, ret );
+
+ return this.pushStack( jQuery.unique( ret ) );
+ };
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function(name, original){
+ jQuery.fn[ name ] = function() {
+ var args = arguments;
+
+ return this.each(function(){
+ for ( var i = 0, length = args.length; i < length; i++ )
+ jQuery( args[ i ] )[ original ]( this );
+ });
+ };
+});
+
+jQuery.each({
+ removeAttr: function( name ) {
+ jQuery.attr( this, name, "" );
+ if (this.nodeType == 1)
+ this.removeAttribute( name );
+ },
+
+ addClass: function( classNames ) {
+ jQuery.className.add( this, classNames );
+ },
+
+ removeClass: function( classNames ) {
+ jQuery.className.remove( this, classNames );
+ },
+
+ toggleClass: function( classNames ) {
+ jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
+ },
+
+ remove: function( selector ) {
+ if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
+ // Prevent memory leaks
+ jQuery( "*", this ).add(this).each(function(){
+ jQuery.event.remove(this);
+ jQuery.removeData(this);
+ });
+ if (this.parentNode)
+ this.parentNode.removeChild( this );
+ }
+ },
+
+ empty: function() {
+ // Remove element nodes and prevent memory leaks
+ jQuery( ">*", this ).remove();
+
+ // Remove any remaining nodes
+ while ( this.firstChild )
+ this.removeChild( this.firstChild );
+ }
+}, function(name, fn){
+ jQuery.fn[ name ] = function(){
+ return this.each( fn, arguments );
+ };
+});
+
+jQuery.each([ "Height", "Width" ], function(i, name){
+ var type = name.toLowerCase();
+
+ jQuery.fn[ type ] = function( size ) {
+ // Get window width or height
+ return this[0] == window ?
+ // Opera reports document.body.client[Width/Height] properly in both quirks and standards
+ jQuery.browser.opera && document.body[ "client" + name ] ||
+
+ // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
+ jQuery.browser.safari && window[ "inner" + name ] ||
+
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
+
+ // Get document width or height
+ this[0] == document ?
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ Math.max(
+ Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
+ Math.max(document.body["offset" + name], document.documentElement["offset" + name])
+ ) :
+
+ // Get or set width or height on the element
+ size == undefined ?
+ // Get width or height on the element
+ (this.length ? jQuery.css( this[0], type ) : null) :
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ this.css( type, size.constructor == String ? size : size + "px" );
+ };
+});
+
+var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
+ "(?:[\\w*_-]|\\\\.)" :
+ "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
+ quickChild = new RegExp("^>\\s*(" + chars + "+)"),
+ quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
+ quickClass = new RegExp("^([#.]?)(" + chars + "*)");
+
+jQuery.extend({
+ expr: {
+ "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
+ "#": function(a,i,m){return a.getAttribute("id")==m[2];},
+ ":": {
+ // Position Checks
+ lt: function(a,i,m){return i<m[3]-0;},
+ gt: function(a,i,m){return i>m[3]-0;},
+ nth: function(a,i,m){return m[3]-0==i;},
+ eq: function(a,i,m){return m[3]-0==i;},
+ first: function(a,i){return i==0;},
+ last: function(a,i,m,r){return i==r.length-1;},
+ even: function(a,i){return i%2==0;},
+ odd: function(a,i){return i%2;},
+
+ // Child Checks
+ "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
+ "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
+ "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
+
+ // Parent Checks
+ parent: function(a){return a.firstChild;},
+ empty: function(a){return !a.firstChild;},
+
+ // Text Check
+ contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
+
+ // Visibility
+ visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
+ hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
+
+ // Form attributes
+ enabled: function(a){return !a.disabled;},
+ disabled: function(a){return a.disabled;},
+ checked: function(a){return a.checked;},
+ selected: function(a){return a.selected||jQuery.attr(a,"selected");},
+
+ // Form elements
+ text: function(a){return "text"==a.type;},
+ radio: function(a){return "radio"==a.type;},
+ checkbox: function(a){return "checkbox"==a.type;},
+ file: function(a){return "file"==a.type;},
+ password: function(a){return "password"==a.type;},
+ submit: function(a){return "submit"==a.type;},
+ image: function(a){return "image"==a.type;},
+ reset: function(a){return "reset"==a.type;},
+ button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
+ input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
+
+ // :has()
+ has: function(a,i,m){return jQuery.find(m[3],a).length;},
+
+ // :header
+ header: function(a){return /h\d/i.test(a.nodeName);},
+
+ // :animated
+ animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
+ }
+ },
+
+ // The regular expressions that power the parsing engine
+ parse: [
+ // Match: [@value='test'], [@foo]
+ /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
+
+ // Match: :contains('foo')
+ /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
+
+ // Match: :even, :last-chlid, #id, .class
+ new RegExp("^([:.#]*)(" + chars + "+)")
+ ],
+
+ multiFilter: function( expr, elems, not ) {
+ var old, cur = [];
+
+ while ( expr && expr != old ) {
+ old = expr;
+ var f = jQuery.filter( expr, elems, not );
+ expr = f.t.replace(/^\s*,\s*/, "" );
+ cur = not ? elems = f.r : jQuery.merge( cur, f.r );
+ }
+
+ return cur;
+ },
+
+ find: function( t, context ) {
+ // Quickly handle non-string expressions
+ if ( typeof t != "string" )
+ return [ t ];
+
+ // check to make sure context is a DOM element or a document
+ if ( context && context.nodeType != 1 && context.nodeType != 9)
+ return [ ];
+
+ // Set the correct context (if none is provided)
+ context = context || document;
+
+ // Initialize the search
+ var ret = [context], done = [], last, nodeName;
+
+ // Continue while a selector expression exists, and while
+ // we're no longer looping upon ourselves
+ while ( t && last != t ) {
+ var r = [];
+ last = t;
+
+ t = jQuery.trim(t);
+
+ var foundToken = false;
+
+ // An attempt at speeding up child selectors that
+ // point to a specific element tag
+ var re = quickChild;
+ var m = re.exec(t);
+
+ if ( m ) {
+ nodeName = m[1].toUpperCase();
+
+ // Perform our own iteration and filter
+ for ( var i = 0; ret[i]; i++ )
+ for ( var c = ret[i].firstChild; c; c = c.nextSibling )
+ if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
+ r.push( c );
+
+ ret = r;
+ t = t.replace( re, "" );
+ if ( t.indexOf(" ") == 0 ) continue;
+ foundToken = true;
+ } else {
+ re = /^([>+~])\s*(\w*)/i;
+
+ if ( (m = re.exec(t)) != null ) {
+ r = [];
+
+ var merge = {};
+ nodeName = m[2].toUpperCase();
+ m = m[1];
+
+ for ( var j = 0, rl = ret.length; j < rl; j++ ) {
+ var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
+ for ( ; n; n = n.nextSibling )
+ if ( n.nodeType == 1 ) {
+ var id = jQuery.data(n);
+
+ if ( m == "~" && merge[id] ) break;
+
+ if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
+ if ( m == "~" ) merge[id] = true;
+ r.push( n );
+ }
+
+ if ( m == "+" ) break;
+ }
+ }
+
+ ret = r;
+
+ // And remove the token
+ t = jQuery.trim( t.replace( re, "" ) );
+ foundToken = true;
+ }
+ }
+
+ // See if there's still an expression, and that we haven't already
+ // matched a token
+ if ( t && !foundToken ) {
+ // Handle multiple expressions
+ if ( !t.indexOf(",") ) {
+ // Clean the result set
+ if ( context == ret[0] ) ret.shift();
+
+ // Merge the result sets
+ done = jQuery.merge( done, ret );
+
+ // Reset the context
+ r = ret = [context];
+
+ // Touch up the selector string
+ t = " " + t.substr(1,t.length);
+
+ } else {
+ // Optimize for the case nodeName#idName
+ var re2 = quickID;
+ var m = re2.exec(t);
+
+ // Re-organize the results, so that they're consistent
+ if ( m ) {
+ m = [ 0, m[2], m[3], m[1] ];
+
+ } else {
+ // Otherwise, do a traditional filter check for
+ // ID, class, and element selectors
+ re2 = quickClass;
+ m = re2.exec(t);
+ }
+
+ m[2] = m[2].replace(/\\/g, "");
+
+ var elem = ret[ret.length-1];
+
+ // Try to do a global search by ID, where we can
+ if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
+ // Optimization for HTML document case
+ var oid = elem.getElementById(m[2]);
+
+ // Do a quick check for the existence of the actual ID attribute
+ // to avoid selecting by the name attribute in IE
+ // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
+ if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
+ oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
+
+ // Do a quick check for node name (where applicable) so
+ // that div#foo searches will be really fast
+ ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
+ } else {
+ // We need to find all descendant elements
+ for ( var i = 0; ret[i]; i++ ) {
+ // Grab the tag name being searched for
+ var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
+
+ // Handle IE7 being really dumb about <object>s
+ if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
+ tag = "param";
+
+ r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
+ }
+
+ // It's faster to filter by class and be done with it
+ if ( m[1] == "." )
+ r = jQuery.classFilter( r, m[2] );
+
+ // Same with ID filtering
+ if ( m[1] == "#" ) {
+ var tmp = [];
+
+ // Try to find the element with the ID
+ for ( var i = 0; r[i]; i++ )
+ if ( r[i].getAttribute("id") == m[2] ) {
+ tmp = [ r[i] ];
+ break;
+ }
+
+ r = tmp;
+ }
+
+ ret = r;
+ }
+
+ t = t.replace( re2, "" );
+ }
+
+ }
+
+ // If a selector string still exists
+ if ( t ) {
+ // Attempt to filter it
+ var val = jQuery.filter(t,r);
+ ret = r = val.r;
+ t = jQuery.trim(val.t);
+ }
+ }
+
+ // An error occurred with the selector;
+ // just return an empty set instead
+ if ( t )
+ ret = [];
+
+ // Remove the root context
+ if ( ret && context == ret[0] )
+ ret.shift();
+
+ // And combine the results
+ done = jQuery.merge( done, ret );
+
+ return done;
+ },
+
+ classFilter: function(r,m,not){
+ m = " " + m + " ";
+ var tmp = [];
+ for ( var i = 0; r[i]; i++ ) {
+ var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
+ if ( !not && pass || not && !pass )
+ tmp.push( r[i] );
+ }
+ return tmp;
+ },
+
+ filter: function(t,r,not) {
+ var last;
+
+ // Look for common filter expressions
+ while ( t && t != last ) {
+ last = t;
+
+ var p = jQuery.parse, m;
+
+ for ( var i = 0; p[i]; i++ ) {
+ m = p[i].exec( t );
+
+ if ( m ) {
+ // Remove what we just matched
+ t = t.substring( m[0].length );
+
+ m[2] = m[2].replace(/\\/g, "");
+ break;
+ }
+ }
+
+ if ( !m )
+ break;
+
+ // :not() is a special case that can be optimized by
+ // keeping it out of the expression list
+ if ( m[1] == ":" && m[2] == "not" )
+ // optimize if only one selector found (most common case)
+ r = isSimple.test( m[3] ) ?
+ jQuery.filter(m[3], r, true).r :
+ jQuery( r ).not( m[3] );
+
+ // We can get a big speed boost by filtering by class here
+ else if ( m[1] == "." )
+ r = jQuery.classFilter(r, m[2], not);
+
+ else if ( m[1] == "[" ) {
+ var tmp = [], type = m[3];
+
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
+
+ if ( z == null || /href|src|selected/.test(m[2]) )
+ z = jQuery.attr(a,m[2]) || '';
+
+ if ( (type == "" && !!z ||
+ type == "=" && z == m[5] ||
+ type == "!=" && z != m[5] ||
+ type == "^=" && z && !z.indexOf(m[5]) ||
+ type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
+ (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
+ tmp.push( a );
+ }
+
+ r = tmp;
+
+ // We can get a speed boost by handling nth-child here
+ } else if ( m[1] == ":" && m[2] == "nth-child" ) {
+ var merge = {}, tmp = [],
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
+ !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
+ // calculate the numbers (first)n+(last) including if they are negative
+ first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
+
+ // loop through all the elements left in the jQuery object
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
+
+ if ( !merge[id] ) {
+ var c = 1;
+
+ for ( var n = parentNode.firstChild; n; n = n.nextSibling )
+ if ( n.nodeType == 1 )
+ n.nodeIndex = c++;
+
+ merge[id] = true;
+ }
+
+ var add = false;
+
+ if ( first == 0 ) {
+ if ( node.nodeIndex == last )
+ add = true;
+ } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
+ add = true;
+
+ if ( add ^ not )
+ tmp.push( node );
+ }
+
+ r = tmp;
+
+ // Otherwise, find the expression to execute
+ } else {
+ var fn = jQuery.expr[ m[1] ];
+ if ( typeof fn == "object" )
+ fn = fn[ m[2] ];
+
+ if ( typeof fn == "string" )
+ fn = eval("false||function(a,i){return " + fn + ";}");
+
+ // Execute it against the current filter
+ r = jQuery.grep( r, function(elem, i){
+ return fn(elem, i, m, r);
+ }, not );
+ }
+ }
+
+ // Return an array of filtered elements (r)
+ // and the modified expression string (t)
+ return { r: r, t: t };
+ },
+
+ dir: function( elem, dir ){
+ var matched = [];
+ var cur = elem[dir];
+ while ( cur && cur != document ) {
+ if ( cur.nodeType == 1 )
+ matched.push( cur );
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function(cur,result,dir,elem){
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] )
+ if ( cur.nodeType == 1 && ++num == result )
+ break;
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType == 1 && (!elem || n != elem) )
+ r.push( n );
+ }
+
+ return r;
+ }
+});
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code orignated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function(elem, types, handler, data) {
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ // For whatever reason, IE has trouble passing the window object
+ // around, causing it to be cloned in the process
+ if ( jQuery.browser.msie && elem.setInterval != undefined )
+ elem = window;
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid )
+ handler.guid = this.guid++;
+
+ // if data is passed, bind to handler
+ if( data != undefined ) {
+ // Create temporary function pointer to original handler
+ var fn = handler;
+
+ // Create unique handler function, wrapped around original handler
+ handler = function() {
+ // Pass arguments and context to original handler
+ return fn.apply(this, arguments);
+ };
+
+ // Store data in unique handler
+ handler.data = data;
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ handler.guid = fn.guid;
+ }
+
+ // Init the element's event structure
+ var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+ handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+ // returned undefined or false
+ var val;
+
+ // Handle the second event of a trigger and when
+ // an event is called after a page has unloaded
+ if ( typeof jQuery == "undefined" || jQuery.event.triggered )
+ return val;
+
+ val = jQuery.event.handle.apply(arguments.callee.elem, arguments);
+
+ return val;
+ });
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native
+ // event in IE.
+ handle.elem = elem;
+
+ // Handle multiple events seperated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type) {
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+ handler.type = parts[1];
+
+ // Get the current list of functions bound to this event
+ var handlers = events[type];
+
+ // Init the event handler queue
+ if (!handlers) {
+ handlers = events[type] = {};
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
+ // Bind the global event handler to the element
+ if (elem.addEventListener)
+ elem.addEventListener(type, handle, false);
+ else if (elem.attachEvent)
+ elem.attachEvent("on" + type, handle);
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers[handler.guid] = handler;
+
+ // Keep track of which events have been used, for global triggering
+ jQuery.event.global[type] = true;
+ });
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ guid: 1,
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function(elem, types, handler) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ var events = jQuery.data(elem, "events"), ret, index;
+
+ if ( events ) {
+ // Unbind all events for the element
+ if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
+ for ( var type in events )
+ this.remove( elem, type + (types || "") );
+ else {
+ // types is actually an event object here
+ if ( types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Handle multiple events seperated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type){
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+
+ if ( events[type] ) {
+ // remove the given handler for the given type
+ if ( handler )
+ delete events[type][handler.guid];
+
+ // remove all handlers for the given type
+ else
+ for ( handler in events[type] )
+ // Handle the removal of namespaced events
+ if ( !parts[1] || events[type][handler].type == parts[1] )
+ delete events[type][handler];
+
+ // remove generic event handler if no more handlers exist
+ for ( ret in events[type] ) break;
+ if ( !ret ) {
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
+ if (elem.removeEventListener)
+ elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+ else if (elem.detachEvent)
+ elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+ }
+ ret = null;
+ delete events[type];
+ }
+ }
+ });
+ }
+
+ // Remove the expando if it's no longer used
+ for ( ret in events ) break;
+ if ( !ret ) {
+ var handle = jQuery.data( elem, "handle" );
+ if ( handle ) handle.elem = null;
+ jQuery.removeData( elem, "events" );
+ jQuery.removeData( elem, "handle" );
+ }
+ }
+ },
+
+ trigger: function(type, data, elem, donative, extra) {
+ // Clone the incoming data, if any
+ data = jQuery.makeArray(data || []);
+
+ if ( type.indexOf("!") >= 0 ) {
+ type = type.slice(0, -1);
+ var exclusive = true;
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // Only trigger if we've ever bound an event for it
+ if ( this.global[type] )
+ jQuery("*").add([window, document]).trigger(type, data);
+
+ // Handle triggering a single element
+ } else {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return undefined;
+
+ var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
+ // Check to see if we need to provide a fake event, or not
+ event = !data[0] || !data[0].preventDefault;
+
+ // Pass along a fake event
+ if ( event )
+ data.unshift( this.fix({ type: type, target: elem }) );
+
+ // Enforce the right trigger type
+ data[0].type = type;
+ if ( exclusive )
+ data[0].exclusive = true;
+
+ // Trigger the event
+ if ( jQuery.isFunction( jQuery.data(elem, "handle") ) )
+ val = jQuery.data(elem, "handle").apply( elem, data );
+
+ // Handle triggering native .onfoo handlers
+ if ( !fn && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+ val = false;
+
+ // Extra functions don't get the custom event object
+ if ( event )
+ data.shift();
+
+ // Handle triggering of extra function
+ if ( extra && jQuery.isFunction( extra ) ) {
+ // call the extra function and tack the current return value on the end for possible inspection
+ ret = extra.apply( elem, val == null ? data : data.concat( val ) );
+ // if anything is returned, give it precedence and have it overwrite the previous value
+ if (ret !== undefined)
+ val = ret;
+ }
+
+ // Trigger the native events (except for clicks on links)
+ if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
+ this.triggered = true;
+ try {
+ elem[ type ]();
+ // prevent IE from throwing an error for some hidden elements
+ } catch (e) {}
+ }
+
+ this.triggered = false;
+ }
+
+ return val;
+ },
+
+ handle: function(event) {
+ // returned undefined or false
+ var val;
+
+ // Empty object is for triggered events with no data
+ event = jQuery.event.fix( event || window.event || {} );
+
+ // Namespaced event handlers
+ var parts = event.type.split(".");
+ event.type = parts[0];
+
+ var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
+ args.unshift( event );
+
+ for ( var j in handlers ) {
+ var handler = handlers[j];
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ args[0].handler = handler;
+ args[0].data = handler.data;
+
+ // Filter the functions by class
+ if ( !parts[1] && !event.exclusive || handler.type == parts[1] ) {
+ var ret = handler.apply( this, args );
+
+ if ( val !== false )
+ val = ret;
+
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+
+ // Clean up added properties in IE to prevent memory leak
+ if (jQuery.browser.msie)
+ event.target = event.preventDefault = event.stopPropagation =
+ event.handler = event.data = null;
+
+ return val;
+ },
+
+ fix: function(event) {
+ // store a copy of the original event object
+ // and clone to set read-only properties
+ var originalEvent = event;
+ event = jQuery.extend({}, originalEvent);
+
+ // add preventDefault and stopPropagation since
+ // they will not work on the clone
+ event.preventDefault = function() {
+ // if preventDefault exists run it on the original event
+ if (originalEvent.preventDefault)
+ originalEvent.preventDefault();
+ // otherwise set the returnValue property of the original event to false (IE)
+ originalEvent.returnValue = false;
+ };
+ event.stopPropagation = function() {
+ // if stopPropagation exists run it on the original event
+ if (originalEvent.stopPropagation)
+ originalEvent.stopPropagation();
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ originalEvent.cancelBubble = true;
+ };
+
+ // Fix target property, if necessary
+ if ( !event.target )
+ event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType == 3 )
+ event.target = originalEvent.target.parentNode;
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement )
+ event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var doc = document.documentElement, body = document.body;
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
+ event.which = event.charCode || event.keyCode;
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey )
+ event.metaKey = event.ctrlKey;
+
+ // Add which for click: 1 == left; 2 == middle; 3 == right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button )
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
+ return event;
+ },
+
+ special: {
+ ready: {
+ setup: function() {
+ // Make sure the ready event is setup
+ bindReady();
+ return;
+ },
+
+ teardown: function() { return; }
+ },
+
+ mouseenter: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseenter
+ arguments[0].type = "mouseenter";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ },
+
+ mouseleave: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseleave
+ arguments[0].type = "mouseleave";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ }
+ }
+};
+
+jQuery.fn.extend({
+ bind: function( type, data, fn ) {
+ return type == "unload" ? this.one(type, data, fn) : this.each(function(){
+ jQuery.event.add( this, type, fn || data, fn && data );
+ });
+ },
+
+ one: function( type, data, fn ) {
+ return this.each(function(){
+ jQuery.event.add( this, type, function(event) {
+ jQuery(this).unbind(event);
+ return (fn || data).apply( this, arguments);
+ }, fn && data);
+ });
+ },
+
+ unbind: function( type, fn ) {
+ return this.each(function(){
+ jQuery.event.remove( this, type, fn );
+ });
+ },
+
+ trigger: function( type, data, fn ) {
+ return this.each(function(){
+ jQuery.event.trigger( type, data, this, true, fn );
+ });
+ },
+
+ triggerHandler: function( type, data, fn ) {
+ if ( this[0] )
+ return jQuery.event.trigger( type, data, this[0], false, fn );
+ return undefined;
+ },
+
+ toggle: function() {
+ // Save reference to arguments for access in closure
+ var args = arguments;
+
+ return this.click(function(event) {
+ // Figure out which function to execute
+ this.lastToggle = 0 == this.lastToggle ? 1 : 0;
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[this.lastToggle].apply( this, arguments ) || false;
+ });
+ },
+
+ hover: function(fnOver, fnOut) {
+ return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
+ },
+
+ ready: function(fn) {
+ // Attach the listeners
+ bindReady();
+
+ // If the DOM is already ready
+ if ( jQuery.isReady )
+ // Execute the function immediately
+ fn.call( document, jQuery );
+
+ // Otherwise, remember the function for later
+ else
+ // Add the function to the wait list
+ jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
+
+ return this;
+ }
+});
+
+jQuery.extend({
+ isReady: false,
+ readyList: [],
+ // Handle when the DOM is ready
+ ready: function() {
+ // Make sure that the DOM is not already loaded
+ if ( !jQuery.isReady ) {
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If there are functions bound, to execute
+ if ( jQuery.readyList ) {
+ // Execute all of them
+ jQuery.each( jQuery.readyList, function(){
+ this.apply( document );
+ });
+
+ // Reset the list of functions
+ jQuery.readyList = null;
+ }
+
+ // Trigger any bound ready events
+ jQuery(document).triggerHandler("ready");
+ }
+ }
+});
+
+var readyBound = false;
+
+function bindReady(){
+ if ( readyBound ) return;
+ readyBound = true;
+
+ // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
+ if ( document.addEventListener && !jQuery.browser.opera)
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
+
+ // If IE is used and is not in a frame
+ // Continually check to see if the document is ready
+ if ( jQuery.browser.msie && window == top ) (function(){
+ if (jQuery.isReady) return;
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch( error ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+
+ if ( jQuery.browser.opera )
+ document.addEventListener( "DOMContentLoaded", function () {
+ if (jQuery.isReady) return;
+ for (var i = 0; i < document.styleSheets.length; i++)
+ if (document.styleSheets[i].disabled) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ }, false);
+
+ if ( jQuery.browser.safari ) {
+ var numStyles;
+ (function(){
+ if (jQuery.isReady) return;
+ if ( document.readyState != "loaded" && document.readyState != "complete" ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ if ( numStyles === undefined )
+ numStyles = jQuery("style, link[rel=stylesheet]").length;
+ if ( document.styleSheets.length != numStyles ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+ }
+
+ // A fallback to window.onload, that will always work
+ jQuery.event.add( window, "load", jQuery.ready );
+}
+
+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
+ "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
+ "submit,keydown,keypress,keyup,error").split(","), function(i, name){
+
+ // Handle event binding
+ jQuery.fn[name] = function(fn){
+ return fn ? this.bind(name, fn) : this.trigger(name);
+ };
+});
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event, elem) {
+ // Check if mouse(over|out) are still within the same parent element
+ var parent = event.relatedTarget;
+ // Traverse up the tree
+ while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
+ // Return true if we actually just moused on to a sub-element
+ return parent == elem;
+};
+
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery(window).bind("unload", function() {
+ jQuery("*").add(document).unbind();
+});
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( jQuery.isFunction( url ) )
+ return this.bind("load", url);
+
+ var off = url.indexOf(" ");
+ if ( off >= 0 ) {
+ var selector = url.slice(off, url.length);
+ url = url.slice(0, off);
+ }
+
+ callback = callback || function(){};
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params )
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = null;
+
+ // Otherwise, build a param string
+ } else {
+ params = jQuery.param( params );
+ type = "POST";
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ complete: function(res, status){
+ // If successful, inject the HTML into all the matched elements
+ if ( status == "success" || status == "notmodified" )
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div/>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ res.responseText );
+
+ self.each( callback, [res.responseText, status, res] );
+ }
+ });
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param(this.serializeArray());
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ return jQuery.nodeName(this, "form") ?
+ jQuery.makeArray(this.elements) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ (this.checked || /select|textarea/i.test(this.nodeName) ||
+ /text|hidden|password/i.test(this.type));
+ })
+ .map(function(i, elem){
+ var val = jQuery(this).val();
+ return val == null ? null :
+ val.constructor == Array ?
+ jQuery.map( val, function(val, i){
+ return {name: elem.name, value: val};
+ }) :
+ {name: elem.name, value: val};
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
+ jQuery.fn[o] = function(f){
+ return this.bind(o, f);
+ };
+});
+
+var jsc = (new Date).getTime();
+
+jQuery.extend({
+ get: function( url, data, callback, type ) {
+ // shift arguments if data argument was ommited
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = null;
+ }
+
+ return jQuery.ajax({
+ type: "GET",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get(url, null, callback, "script");
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get(url, data, callback, "json");
+ },
+
+ post: function( url, data, callback, type ) {
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = {};
+ }
+
+ return jQuery.ajax({
+ type: "POST",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ ajaxSetup: function( settings ) {
+ jQuery.extend( jQuery.ajaxSettings, settings );
+ },
+
+ ajaxSettings: {
+ global: true,
+ type: "GET",
+ timeout: 0,
+ contentType: "application/x-www-form-urlencoded",
+ processData: true,
+ async: true,
+ data: null,
+ username: null,
+ password: null,
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ script: "text/javascript, application/javascript",
+ json: "application/json, text/javascript",
+ text: "text/plain",
+ _default: "*/*"
+ }
+ },
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+
+ ajax: function( s ) {
+ var jsonp, jsre = /=\?(&|$)/g, status, data;
+
+ // Extend the settings, but re-extend 's' so that it can be
+ // checked again later (in the test suite, specifically)
+ s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+
+ // convert data if not already a string
+ if ( s.data && s.processData && typeof s.data != "string" )
+ s.data = jQuery.param(s.data);
+
+ // Handle JSONP Parameter Callbacks
+ if ( s.dataType == "jsonp" ) {
+ if ( s.type.toLowerCase() == "get" ) {
+ if ( !s.url.match(jsre) )
+ s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+ } else if ( !s.data || !s.data.match(jsre) )
+ s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+ s.dataType = "json";
+ }
+
+ // Build temporary JSONP function
+ if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
+ jsonp = "jsonp" + jsc++;
+
+ // Replace the =? sequence both in the query string and the data
+ if ( s.data )
+ s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+ s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+ s.dataType = "script";
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = function(tmp){
+ data = tmp;
+ success();
+ complete();
+ // Garbage collect
+ window[ jsonp ] = undefined;
+ try{ delete window[ jsonp ]; } catch(e){}
+ if ( head )
+ head.removeChild( script );
+ };
+ }
+
+ if ( s.dataType == "script" && s.cache == null )
+ s.cache = false;
+
+ if ( s.cache === false && s.type.toLowerCase() == "get" ) {
+ var ts = (new Date()).getTime();
+ // try replacing _= if it is there
+ var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
+ }
+
+ // If data is available, append data to url for get requests
+ if ( s.data && s.type.toLowerCase() == "get" ) {
+ s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
+
+ // IE likes to send both get and post data, prevent this
+ s.data = null;
+ }
+
+ // Watch for a new set of requests
+ if ( s.global && ! jQuery.active++ )
+ jQuery.event.trigger( "ajaxStart" );
+
+ // If we're requesting a remote document
+ // and trying to load JSON or Script with a GET
+ if ( (!s.url.indexOf("http") || !s.url.indexOf("//")) && s.dataType == "script" && s.type.toLowerCase() == "get" ) {
+ var head = document.getElementsByTagName("head")[0];
+ var script = document.createElement("script");
+ script.src = s.url;
+ if (s.scriptCharset)
+ script.charset = s.scriptCharset;
+
+ // Handle Script loading
+ if ( !jsonp ) {
+ var done = false;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function(){
+ if ( !done && (!this.readyState ||
+ this.readyState == "loaded" || this.readyState == "complete") ) {
+ done = true;
+ success();
+ complete();
+ head.removeChild( script );
+ }
+ };
+ }
+
+ head.appendChild(script);
+
+ // We handle everything using the script element injection
+ return undefined;
+ }
+
+ var requestDone = false;
+
+ // Create the request object; Microsoft failed to properly
+ // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+ var xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+
+ // Open the socket
+ xml.open(s.type, s.url, s.async, s.username, s.password);
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ // Set the correct header, if data is being sent
+ if ( s.data )
+ xml.setRequestHeader("Content-Type", s.contentType);
+
+ // Set the If-Modified-Since header, if ifModified mode.
+ if ( s.ifModified )
+ xml.setRequestHeader("If-Modified-Since",
+ jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+
+ // Set header so the called script knows that it's an XMLHttpRequest
+ xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+ // Set the Accepts header for the server, depending on the dataType
+ xml.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+ s.accepts[ s.dataType ] + ", */*" :
+ s.accepts._default );
+ } catch(e){}
+
+ // Allow custom headers/mimetypes
+ if ( s.beforeSend )
+ s.beforeSend(xml);
+
+ if ( s.global )
+ jQuery.event.trigger("ajaxSend", [xml, s]);
+
+ // Wait for a response to come back
+ var onreadystatechange = function(isTimeout){
+ // The transfer is complete and the data is available, or the request timed out
+ if ( !requestDone && xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
+ requestDone = true;
+
+ // clear poll interval
+ if (ival) {
+ clearInterval(ival);
+ ival = null;
+ }
+
+ status = isTimeout == "timeout" && "timeout" ||
+ !jQuery.httpSuccess( xml ) && "error" ||
+ s.ifModified && jQuery.httpNotModified( xml, s.url ) && "notmodified" ||
+ "success";
+
+ if ( status == "success" ) {
+ // Watch for, and catch, XML document parse errors
+ try {
+ // process the data (runs the xml through httpData regardless of callback)
+ data = jQuery.httpData( xml, s.dataType );
+ } catch(e) {
+ status = "parsererror";
+ }
+ }
+
+ // Make sure that the request was successful or notmodified
+ if ( status == "success" ) {
+ // Cache Last-Modified header, if ifModified mode.
+ var modRes;
+ try {
+ modRes = xml.getResponseHeader("Last-Modified");
+ } catch(e) {} // swallow exception thrown by FF if header is not available
+
+ if ( s.ifModified && modRes )
+ jQuery.lastModified[s.url] = modRes;
+
+ // JSONP handles its own success callback
+ if ( !jsonp )
+ success();
+ } else
+ jQuery.handleError(s, xml, status);
+
+ // Fire the complete handlers
+ complete();
+
+ // Stop memory leaks
+ if ( s.async )
+ xml = null;
+ }
+ };
+
+ if ( s.async ) {
+ // don't attach the handler to the request, just poll it instead
+ var ival = setInterval(onreadystatechange, 13);
+
+ // Timeout checker
+ if ( s.timeout > 0 )
+ setTimeout(function(){
+ // Check to see if the request is still happening
+ if ( xml ) {
+ // Cancel the request
+ xml.abort();
+
+ if( !requestDone )
+ onreadystatechange( "timeout" );
+ }
+ }, s.timeout);
+ }
+
+ // Send the data
+ try {
+ xml.send(s.data);
+ } catch(e) {
+ jQuery.handleError(s, xml, null, e);
+ }
+
+ // firefox 1.5 doesn't fire statechange for sync requests
+ if ( !s.async )
+ onreadystatechange();
+
+ function success(){
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success )
+ s.success( data, status );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxSuccess", [xml, s] );
+ }
+
+ function complete(){
+ // Process result
+ if ( s.complete )
+ s.complete(xml, status);
+
+ // The request was completed
+ if ( s.global )
+ jQuery.event.trigger( "ajaxComplete", [xml, s] );
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active )
+ jQuery.event.trigger( "ajaxStop" );
+ }
+
+ // return XMLHttpRequest to allow aborting the request etc.
+ return xml;
+ },
+
+ handleError: function( s, xml, status, e ) {
+ // If a local callback was specified, fire it
+ if ( s.error ) s.error( xml, status, e );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxError", [xml, s, e] );
+ },
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Determines if an XMLHttpRequest was successful or not
+ httpSuccess: function( r ) {
+ try {
+ // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+ return !r.status && location.protocol == "file:" ||
+ ( r.status >= 200 && r.status < 300 ) || r.status == 304 || r.status == 1223 ||
+ jQuery.browser.safari && r.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ // Determines if an XMLHttpRequest returns NotModified
+ httpNotModified: function( xml, url ) {
+ try {
+ var xmlRes = xml.getResponseHeader("Last-Modified");
+
+ // Firefox always returns 200. check Last-Modified date
+ return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
+ jQuery.browser.safari && xml.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ httpData: function( r, type ) {
+ var ct = r.getResponseHeader("content-type");
+ var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0;
+ var data = xml ? r.responseXML : r.responseText;
+
+ if ( xml && data.documentElement.tagName == "parsererror" )
+ throw "parsererror";
+
+ // If the type is "script", eval it in global context
+ if ( type == "script" )
+ jQuery.globalEval( data );
+
+ // Get the JavaScript object, if JSON is used.
+ if ( type == "json" )
+ data = eval("(" + data + ")");
+
+ return data;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a ) {
+ var s = [];
+
+ // If an array was passed in, assume that it is an array
+ // of form elements
+ if ( a.constructor == Array || a.jquery )
+ // Serialize the form elements
+ jQuery.each( a, function(){
+ s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
+ });
+
+ // Otherwise, assume that it's an object of key/value pairs
+ else
+ // Serialize the key/values
+ for ( var j in a )
+ // If the value is an array then the key names need to be repeated
+ if ( a[j] && a[j].constructor == Array )
+ jQuery.each( a[j], function(){
+ s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
+ });
+ else
+ s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );
+
+ // Return the resulting serialization
+ return s.join("&").replace(/%20/g, "+");
+ }
+
+});
+jQuery.fn.extend({
+ show: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "show", width: "show", opacity: "show"
+ }, speed, callback) :
+
+ this.filter(":hidden").each(function(){
+ this.style.display = this.oldblock || "";
+ if ( jQuery.css(this,"display") == "none" ) {
+ var elem = jQuery("<" + this.tagName + " />").appendTo("body");
+ this.style.display = elem.css("display");
+ // handle an edge condition where css is - div { display:none; } or similar
+ if (this.style.display == "none")
+ this.style.display = "block";
+ elem.remove();
+ }
+ }).end();
+ },
+
+ hide: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "hide", width: "hide", opacity: "hide"
+ }, speed, callback) :
+
+ this.filter(":visible").each(function(){
+ this.oldblock = this.oldblock || jQuery.css(this,"display");
+ this.style.display = "none";
+ }).end();
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2 ){
+ return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+ this._toggle( fn, fn2 ) :
+ fn ?
+ this.animate({
+ height: "toggle", width: "toggle", opacity: "toggle"
+ }, fn, fn2) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ });
+ },
+
+ slideDown: function(speed,callback){
+ return this.animate({height: "show"}, speed, callback);
+ },
+
+ slideUp: function(speed,callback){
+ return this.animate({height: "hide"}, speed, callback);
+ },
+
+ slideToggle: function(speed, callback){
+ return this.animate({height: "toggle"}, speed, callback);
+ },
+
+ fadeIn: function(speed, callback){
+ return this.animate({opacity: "show"}, speed, callback);
+ },
+
+ fadeOut: function(speed, callback){
+ return this.animate({opacity: "hide"}, speed, callback);
+ },
+
+ fadeTo: function(speed,to,callback){
+ return this.animate({opacity: to}, speed, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed(speed, easing, callback);
+
+ return this[ optall.queue === false ? "each" : "queue" ](function(){
+ if ( this.nodeType != 1)
+ return false;
+
+ var opt = jQuery.extend({}, optall);
+ var hidden = jQuery(this).is(":hidden"), self = this;
+
+ for ( var p in prop ) {
+ if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+ return jQuery.isFunction(opt.complete) && opt.complete.apply(this);
+
+ if ( p == "height" || p == "width" ) {
+ // Store display property
+ opt.display = jQuery.css(this, "display");
+
+ // Make sure that nothing sneaks out
+ opt.overflow = this.style.overflow;
+ }
+ }
+
+ if ( opt.overflow != null )
+ this.style.overflow = "hidden";
+
+ opt.curAnim = jQuery.extend({}, prop);
+
+ jQuery.each( prop, function(name, val){
+ var e = new jQuery.fx( self, opt, name );
+
+ if ( /toggle|show|hide/.test(val) )
+ e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+ else {
+ var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
+ start = e.cur(true) || 0;
+
+ if ( parts ) {
+ var end = parseFloat(parts[2]),
+ unit = parts[3] || "px";
+
+ // We need to compute starting value
+ if ( unit != "px" ) {
+ self.style[ name ] = (end || 1) + unit;
+ start = ((end || 1) / e.cur(true)) * start;
+ self.style[ name ] = start + unit;
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] )
+ end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
+
+ e.custom( start, end, unit );
+ } else
+ e.custom( start, val, "" );
+ }
+ });
+
+ // For JS strict compliance
+ return true;
+ });
+ },
+
+ queue: function(type, fn){
+ if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
+ fn = type;
+ type = "fx";
+ }
+
+ if ( !type || (typeof type == "string" && !fn) )
+ return queue( this[0], type );
+
+ return this.each(function(){
+ if ( fn.constructor == Array )
+ queue(this, type, fn);
+ else {
+ queue(this, type).push( fn );
+
+ if ( queue(this, type).length == 1 )
+ fn.apply(this);
+ }
+ });
+ },
+
+ stop: function(clearQueue, gotoEnd){
+ var timers = jQuery.timers;
+
+ if (clearQueue)
+ this.queue([]);
+
+ this.each(function(){
+ // go in reverse order so anything added to the queue during the loop is ignored
+ for ( var i = timers.length - 1; i >= 0; i-- )
+ if ( timers[i].elem == this ) {
+ if (gotoEnd)
+ // force the next step to be the last
+ timers[i](true);
+ timers.splice(i, 1);
+ }
+ });
+
+ // start the next in the queue if the last step wasn't forced
+ if (!gotoEnd)
+ this.dequeue();
+
+ return this;
+ }
+
+});
+
+var queue = function( elem, type, array ) {
+ if ( !elem )
+ return undefined;
+
+ type = type || "fx";
+
+ var q = jQuery.data( elem, type + "queue" );
+
+ if ( !q || array )
+ q = jQuery.data( elem, type + "queue",
+ array ? jQuery.makeArray(array) : [] );
+
+ return q;
+};
+
+jQuery.fn.dequeue = function(type){
+ type = type || "fx";
+
+ return this.each(function(){
+ var q = queue(this, type);
+
+ q.shift();
+
+ if ( q.length )
+ q[0].apply( this );
+ });
+};
+
+jQuery.extend({
+
+ speed: function(speed, easing, fn) {
+ var opt = speed && speed.constructor == Object ? speed : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && easing.constructor != Function && easing
+ };
+
+ opt.duration = (opt.duration && opt.duration.constructor == Number ?
+ opt.duration :
+ { slow: 600, fast: 200 }[opt.duration]) || 400;
+
+ // Queueing
+ opt.old = opt.complete;
+ opt.complete = function(){
+ if ( opt.queue !== false )
+ jQuery(this).dequeue();
+ if ( jQuery.isFunction( opt.old ) )
+ opt.old.apply( this );
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p, n, firstNum, diff ) {
+ return firstNum + diff * p;
+ },
+ swing: function( p, n, firstNum, diff ) {
+ return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ }
+ },
+
+ timers: [],
+ timerId: null,
+
+ fx: function( elem, options, prop ){
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ if ( !options.orig )
+ options.orig = {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+
+ // Simple function for setting a style value
+ update: function(){
+ if ( this.options.step )
+ this.options.step.apply( this.elem, [ this.now, this ] );
+
+ (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+ // Set display property to block for height/width animations
+ if ( this.prop == "height" || this.prop == "width" )
+ this.elem.style.display = "block";
+ },
+
+ // Get the current size
+ cur: function(force){
+ if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
+ return this.elem[ this.prop ];
+
+ var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+ return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+ },
+
+ // Start an animation from one number to another
+ custom: function(from, to, unit){
+ this.startTime = (new Date()).getTime();
+ this.start = from;
+ this.end = to;
+ this.unit = unit || this.unit || "px";
+ this.now = this.start;
+ this.pos = this.state = 0;
+ this.update();
+
+ var self = this;
+ function t(gotoEnd){
+ return self.step(gotoEnd);
+ }
+
+ t.elem = this.elem;
+
+ jQuery.timers.push(t);
+
+ if ( jQuery.timerId == null ) {
+ jQuery.timerId = setInterval(function(){
+ var timers = jQuery.timers;
+
+ for ( var i = 0; i < timers.length; i++ )
+ if ( !timers[i]() )
+ timers.splice(i--, 1);
+
+ if ( !timers.length ) {
+ clearInterval( jQuery.timerId );
+ jQuery.timerId = null;
+ }
+ }, 13);
+ }
+ },
+
+ // Simple 'show' function
+ show: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ this.custom(0, this.cur());
+
+ // Make sure that we start at a small width/height to avoid any
+ // flash of content
+ if ( this.prop == "width" || this.prop == "height" )
+ this.elem.style[this.prop] = "1px";
+
+ // Start by showing the element
+ jQuery(this.elem).show();
+ },
+
+ // Simple 'hide' function
+ hide: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom(this.cur(), 0);
+ },
+
+ // Each step of an animation
+ step: function(gotoEnd){
+ var t = (new Date()).getTime();
+
+ if ( gotoEnd || t > this.options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ this.options.curAnim[ this.prop ] = true;
+
+ var done = true;
+ for ( var i in this.options.curAnim )
+ if ( this.options.curAnim[i] !== true )
+ done = false;
+
+ if ( done ) {
+ if ( this.options.display != null ) {
+ // Reset the overflow
+ this.elem.style.overflow = this.options.overflow;
+
+ // Reset the display
+ this.elem.style.display = this.options.display;
+ if ( jQuery.css(this.elem, "display") == "none" )
+ this.elem.style.display = "block";
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( this.options.hide )
+ this.elem.style.display = "none";
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( this.options.hide || this.options.show )
+ for ( var p in this.options.curAnim )
+ jQuery.attr(this.elem.style, p, this.options.orig[p]);
+ }
+
+ // If a callback was provided, execute it
+ if ( done && jQuery.isFunction( this.options.complete ) )
+ // Execute the complete function
+ this.options.complete.apply( this.elem );
+
+ return false;
+ } else {
+ var n = t - this.startTime;
+ this.state = n / this.options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
+ this.now = this.start + ((this.end - this.start) * this.pos);
+
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+
+};
+
+jQuery.fx.step = {
+ scrollLeft: function(fx){
+ fx.elem.scrollLeft = fx.now;
+ },
+
+ scrollTop: function(fx){
+ fx.elem.scrollTop = fx.now;
+ },
+
+ opacity: function(fx){
+ jQuery.attr(fx.elem.style, "opacity", fx.now);
+ },
+
+ _default: function(fx){
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ }
+};
+// The Offset Method
+// Originally By Brandon Aaron, part of the Dimension Plugin
+// http://jquery.com/plugins/project/dimensions
+jQuery.fn.offset = function() {
+ var left = 0, top = 0, elem = this[0], results;
+
+ if ( elem ) with ( jQuery.browser ) {
+ var parent = elem.parentNode,
+ offsetChild = elem,
+ offsetParent = elem.offsetParent,
+ doc = elem.ownerDocument,
+ safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
+ fixed = jQuery.css(elem, "position") == "fixed";
+
+ // Use getBoundingClientRect if available
+ if ( elem.getBoundingClientRect ) {
+ var box = elem.getBoundingClientRect();
+
+ // Add the document scroll offsets
+ add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+
+ // IE adds the HTML element's border, by default it is medium which is 2px
+ // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
+ // IE 7 standards mode, the border is always 2px
+ // This border/offset is typically represented by the clientLeft and clientTop properties
+ // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
+ // Therefore this method will be off by 2px in IE while in quirksmode
+ add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
+
+ // Otherwise loop through the offsetParents and parentNodes
+ } else {
+
+ // Initial element offsets
+ add( elem.offsetLeft, elem.offsetTop );
+
+ // Get parent offsets
+ while ( offsetParent ) {
+ // Add offsetParent offsets
+ add( offsetParent.offsetLeft, offsetParent.offsetTop );
+
+ // Mozilla and Safari > 2 does not include the border on offset parents
+ // However Mozilla adds the border for table or table cells
+ if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
+ border( offsetParent );
+
+ // Add the document scroll offsets if position is fixed on any offsetParent
+ if ( !fixed && jQuery.css(offsetParent, "position") == "fixed" )
+ fixed = true;
+
+ // Set offsetChild to previous offsetParent unless it is the body element
+ offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
+ // Get next offsetParent
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ // Get parent scroll offsets
+ while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
+ // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
+ if ( !/^inline|table.*$/i.test(jQuery.css(parent, "display")) )
+ // Subtract parent scroll offsets
+ add( -parent.scrollLeft, -parent.scrollTop );
+
+ // Mozilla does not add the border for a parent that has overflow != visible
+ if ( mozilla && jQuery.css(parent, "overflow") != "visible" )
+ border( parent );
+
+ // Get next parent
+ parent = parent.parentNode;
+ }
+
+ // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
+ // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
+ if ( (safari2 && (fixed || jQuery.css(offsetChild, "position") == "absolute")) ||
+ (mozilla && jQuery.css(offsetChild, "position") != "absolute") )
+ add( -doc.body.offsetLeft, -doc.body.offsetTop );
+
+ // Add the document scroll offsets if position is fixed
+ if ( fixed )
+ add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+ }
+
+ // Return an object with top and left properties
+ results = { top: top, left: left };
+ }
+
+ function border(elem) {
+ add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
+ }
+
+ function add(l, t) {
+ left += parseInt(l) || 0;
+ top += parseInt(t) || 0;
+ }
+
+ return results;
+};
+
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each(["Height", "Width"], function(i, name){
+
+ var tl = name == "Height" ? "Top" : "Left", // top or left
+ br = name == "Height" ? "Bottom" : "Right"; // bottom or right
+
+ // innerHeight and innerWidth
+ jQuery.fn["inner" + name] = function(){
+ return this[ name.toLowerCase() ]() +
+ num(this, "padding" + tl) +
+ num(this, "padding" + br);
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn["outer" + name] = function(margin) {
+ return this["inner" + name]() +
+ num(this, "border" + tl + "Width") +
+ num(this, "border" + br + "Width") +
+ (!!margin ?
+ num(this, "margin" + tl) + num(this, "margin" + br) : 0);
+ };
+
+});
+
+function num(elem, prop) {
+ elem = elem.jquery ? elem[0] : elem;
+ return elem && parseInt( jQuery.curCSS(elem, prop, true) ) || 0;
+}})();
diff --git a/moksha/widgetbrowser/widgetbrowser/static/loading.gif b/moksha/widgetbrowser/widgetbrowser/static/loading.gif
new file mode 100644
index 0000000..85b99d4
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/loading.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/pygments.css b/moksha/widgetbrowser/widgetbrowser/static/pygments.css
new file mode 100644
index 0000000..a55a324
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/pygments.css
@@ -0,0 +1,59 @@
+.c { color: #408090; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #007020; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.cp { color: #007020 } /* Comment.Preproc */
+.c1 { color: #408090; font-style: italic } /* Comment.Single */
+.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #303030 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.kp { color: #007020 } /* Keyword.Pseudo */
+.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #902000 } /* Keyword.Type */
+.m { color: #208050 } /* Literal.Number */
+.s { color: #4070a0 } /* Literal.String */
+.na { color: #4070a0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.no { color: #60add5 } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.ne { color: #007020 } /* Name.Exception */
+.nf { color: #06287e } /* Name.Function */
+.nl { color: #002070; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #062873; font-weight: bold } /* Name.Tag */
+.nv { color: #bb60d5 } /* Name.Variable */
+.ow { color: #007020; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #208050 } /* Literal.Number.Float */
+.mh { color: #208050 } /* Literal.Number.Hex */
+.mi { color: #208050 } /* Literal.Number.Integer */
+.mo { color: #208050 } /* Literal.Number.Oct */
+.sb { color: #4070a0 } /* Literal.String.Backtick */
+.sc { color: #4070a0 } /* Literal.String.Char */
+.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4070a0 } /* Literal.String.Double */
+.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #4070a0 } /* Literal.String.Heredoc */
+.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.sx { color: #c65d09 } /* Literal.String.Other */
+.sr { color: #235388 } /* Literal.String.Regex */
+.s1 { color: #4070a0 } /* Literal.String.Single */
+.ss { color: #517918 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #bb60d5 } /* Name.Variable.Class */
+.vg { color: #bb60d5 } /* Name.Variable.Global */
+.vi { color: #bb60d5 } /* Name.Variable.Instance */
+.il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/tab.png b/moksha/widgetbrowser/widgetbrowser/static/tab.png
new file mode 100644
index 0000000..413c755
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/tab.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.accordion.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.accordion.css
new file mode 100644
index 0000000..f45ed75
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.accordion.css
@@ -0,0 +1,12 @@
+ul.ui-accordion { margin: 0; padding: 0; list-style-type: none; }
+ul.ui-accordion li { margin: 0; margin-bottom: 2px; padding: 0; background-image: url(i/accordion-left.png); background-repeat: no-repeat; }
+ul.ui-accordion li a.ui-accordion-header { display: block; padding-left: 5px; margin-right: 3px; height: 28px; background-image: url(i/accordion-middle.png); color: #000; text-decoration: none; line-height: 28px; }
+ul.ui-accordion li .ui-accordion-right { display: block; background-image: url(i/accordion-right.png); position: absolute; top: 0px; right: 0px; height: 28px; width: 3px; }
+
+ul.ui-accordion li:hover { background-image: url(i/accordion-left-over.png); }
+ul.ui-accordion li:hover a.ui-accordion-header { background-image: url(i/accordion-middle-over.png); }
+ul.ui-accordion li:hover .ui-accordion-right { background-image: url(i/accordion-right-over.png); }
+
+ul.ui-accordion li.active { background-image: url(i/accordion-left-act.png); }
+ul.ui-accordion li.active a.ui-accordion-header { background-image: url(i/accordion-middle-act.png); }
+ul.ui-accordion li.active .ui-accordion-right { background-image: url(i/accordion-right-act.png); }
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.all.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.all.css
new file mode 100644
index 0000000..3de5386
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.all.css
@@ -0,0 +1,9 @@
+@import "flora.css";
+@import "flora.shadow.css";
+@import "flora.resizable.css";
+@import "flora.slider.css";
+@import "flora.accordion.css";
+@import "flora.tabs.css";
+@import "flora.dialog.css";
+@import "flora.tablesorter.css";
+@import "flora.datepicker.css";
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.calendar.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.calendar.css
new file mode 100644
index 0000000..dedcf0c
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.calendar.css
@@ -0,0 +1,167 @@
+/* Main Style Sheet for jQuery Calendar */
+#calendar_div, .calendar_inline {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 14px;
+ padding: 0;
+ margin: 0;
+ background: #ddd;
+}
+#calendar_div {
+ display: none;
+ border: 1px solid #FF9900;
+ z-index: 10; /*must have*/
+}
+#calendar_div, .calendar_control, .calendar_links, .calendar_header, .calendar {
+ width: 185px;
+}
+.calendar_inline {
+ float: left;
+ display: block;
+ border: 0;
+}
+.calendar_dialog {
+ padding: 5px !important;
+ border: 4px ridge #ddd !important;
+}
+button.calendar_trigger {
+ width: 25px;
+}
+img.calendar_trigger {
+ margin: 2px;
+ vertical-align: middle;
+}
+.calendar_prompt {
+ float: left;
+ width: 181px;
+ padding: 2px;
+ background: #ddd;
+ color: #000;
+}
+* html .calendar_prompt {
+ width: 185px;
+}
+.calendar_control, .calendar_links, .calendar_header, .calendar {
+ clear: both;
+ float: left;
+ color: #fff;
+}
+.calendar_control {
+ background: #FF9900;
+}
+.calendar_links {
+ background: #E0F4D7;
+}
+.calendar_control, .calendar_links {
+ font-weight: bold;
+ font-size: 80%;
+ letter-spacing: 1px;
+}
+.calendar_links label { /* disabled links */
+ padding: 2px 5px;
+ color: #888;
+}
+.calendar_clear, .calendar_prev {
+ float: left;
+}
+.calendar_current {
+ float: left;
+ width: 35%;
+ text-align: center;
+}
+.calendar_close, .calendar_next {
+ float: right;
+}
+.calendar_header {
+ background: #83C948;
+ text-align: center;
+ font-weight: bold;
+}
+.calendar_header select {
+ background: #83C948;
+ color: #000;
+ border: 0px;
+ font-weight: bold;
+}
+.calendar {
+ background: #ccc;
+ text-align: center;
+ font-size: 100%;
+}
+.calendar a {
+ display: block;
+ width: 100%;
+}
+.calendar .calendar_titleRow {
+ background: #B1DB87;
+ color: #000 !important;
+}
+.calendar .calendar_daysRow {
+ background: #FFF;
+ color: #666;
+}
+.calendar .calendar_daysCell {
+ color: #000;
+ border: 1px solid #ddd;
+}
+#calendar .calendar_daysCell a{
+ display: block;
+}
+.calendar .calendar_weekEndCell {
+ background: #E0F4D7;
+}
+.calendar .calendar_daysCellOver {
+ background: #fff;
+ border: 1px solid #777;
+}
+.calendar .calendar_unselectable {
+ color: #888;
+}
+.calendar_today {
+ background: #ccc !important;
+}
+.calendar_currentDay {
+ background: #999 !important;
+}
+
+/* ________ CALENDAR LINKS _______
+
+** Reset link properties and then override them with !important */
+#calendar_div a, .calendar_inline a {
+ cursor: pointer;
+ margin: 0;
+ padding: 0;
+ background: none;
+ color: #000;
+}
+.calendar_inline .calendar_links a {
+ padding: 0 5px !important;
+}
+.calendar_control a, .calendar_links a {
+ padding: 2px 5px !important;
+ color: #000 !important;
+}
+.calendar_titleRow a {
+ color: #000 !important;
+}
+.calendar_control a:hover {
+ /*background: #fdd !important;*/
+ color: #333 !important;
+}
+.calendar_links a:hover, .calendar_titleRow a:hover {
+ background: #FFF !important;
+ color: #333 !important;
+}
+
+/* ___________ IE6 IFRAME FIX ________ */
+
+.calendar_cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 193px; /*must have to match width and borders*/
+ height: 200px; /*must have to match maximum height*/
+}
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.css
new file mode 100644
index 0000000..761217d
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.css
@@ -0,0 +1,2 @@
+.ui-wrapper { border: 1px solid #50A029; }
+.ui-wrapper input, .ui-wrapper textarea { border: 0; }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.datepicker.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.datepicker.css
new file mode 100644
index 0000000..34ea650
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.datepicker.css
@@ -0,0 +1,179 @@
+/* Main Flora Style Sheet for jQuery UI Datepicker */
+#datepicker_div, .datepicker_inline {
+ font-family: Arial,Helvetica,sans-serif;
+ font-size: 14px;
+ padding: 0;
+ margin: 0;
+ background: #DDD;
+ width: 185px;
+}
+#datepicker_div {
+ display: none;
+ border: 1px solid #FF9900;
+ z-index: 10;
+}
+.datepicker_inline {
+ float: left;
+ display: block;
+ border: 0;
+}
+.datepicker_dialog {
+ padding: 5px !important;
+ border: 4px ridge #DDD !important;
+}
+button.datepicker_trigger {
+ width: 25px;
+}
+img.datepicker_trigger {
+ margin: 2px;
+ vertical-align: middle;
+}
+.datepicker_prompt {
+ float: left;
+ padding: 2px;
+ background: #DDD;
+ color: #000;
+}
+*html .datepicker_prompt {
+ width: 185px;
+}
+.datepicker_control, .datepicker_links, .datepicker_header, .datepicker {
+ clear: both;
+ float: left;
+ width: 100%;
+ color: #FFF;
+}
+.datepicker_control {
+ background: #FF9900;
+ padding: 2px 0px;
+}
+.datepicker_links {
+ background: #E0F4D7;
+ padding: 2px 0px;
+}
+.datepicker_control, .datepicker_links {
+ font-weight: bold;
+ font-size: 80%;
+ letter-spacing: 1px;
+}
+.datepicker_links label {
+ padding: 2px 5px;
+ color: #888;
+}
+.datepicker_clear, .datepicker_prev {
+ float: left;
+ width: 34%;
+}
+.datepicker_current {
+ float: left;
+ width: 30%;
+ text-align: center;
+}
+.datepicker_close, .datepicker_next {
+ float: right;
+ width: 34%;
+ text-align: right;
+}
+.datepicker_header {
+ padding: 1px 0 3px;
+ background: #83C948;
+ text-align: center;
+ font-weight: bold;
+ height: 1.3em;
+}
+.datepicker_header select {
+ background: #83C948;
+ color: #000;
+ border: 0px;
+ font-weight: bold;
+}
+.datepicker {
+ background: #CCC;
+ text-align: center;
+ font-size: 100%;
+}
+.datepicker a {
+ display: block;
+ width: 100%;
+}
+.datepicker .datepicker_titleRow {
+ background: #B1DB87;
+ color: #000;
+}
+.datepicker .datepicker_daysRow {
+ background: #FFF;
+ color: #666;
+}
+.datepicker_weekCol {
+ background: #B1DB87;
+ color: #000;
+}
+.datepicker .datepicker_daysCell {
+ color: #000;
+ border: 1px solid #DDD;
+}
+#datepicker .datepicker_daysCell a {
+ display: block;
+}
+.datepicker .datepicker_weekEndCell {
+ background: #E0F4D7;
+}
+.datepicker .datepicker_daysCellOver {
+ background: #FFF;
+ border: 1px solid #777;
+}
+.datepicker .datepicker_unselectable {
+ color: #888;
+}
+.datepicker_today {
+ background: #B1DB87 !important;
+}
+.datepicker_currentDay {
+ background: #83C948 !important;
+}
+#datepicker_div a, .datepicker_inline a {
+ cursor: pointer;
+ margin: 0;
+ padding: 0;
+ background: none;
+ color: #000;
+}
+.datepicker_inline .datepicker_links a {
+ padding: 0 5px !important;
+}
+.datepicker_control a, .datepicker_links a {
+ padding: 2px 5px !important;
+ color: #000 !important;
+}
+.datepicker_titleRow a {
+ color: #000 !important;
+}
+.datepicker_control a:hover {
+ background: #FDD !important;
+ color: #333 !important;
+}
+.datepicker_links a:hover, .datepicker_titleRow a:hover {
+ background: #FFF !important;
+ color: #333 !important;
+}
+.datepicker_multi .datepicker {
+ border: 1px solid #83C948;
+}
+.datepicker_oneMonth {
+ float: left;
+ width: 185px;
+}
+.datepicker_newRow {
+ clear: left;
+}
+.datepicker_cover {
+ display: none;
+ display/**/: block;
+ position: absolute;
+ z-index: -1;
+ filter: mask();
+ top: -4px;
+ left: -4px;
+ width: 193px;
+ height: 200px;
+}
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.dialog.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.dialog.css
new file mode 100644
index 0000000..efef1c4
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.dialog.css
@@ -0,0 +1,95 @@
+/* This file skins dialog */
+
+.flora .ui-dialog,
+.flora.ui-dialog {
+ background-color: #e6f7d4;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar,
+.flora.ui-dialog .ui-dialog-titlebar {
+ border-bottom: 1px solid #d8d2aa;
+ background: #ff9900 url(i/dialog-title.gif) repeat-x;
+ padding: 0px;
+ height: 28px;
+ _height: 29px;
+}
+
+.flora .ui-dialog.ui-draggable .ui-dialog-titlebar,
+.flora.ui-dialog.ui-draggable .ui-dialog-titlebar {
+ cursor: move;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar-close,
+.flora.ui-dialog .ui-dialog-titlebar-close {
+ width: 16px;
+ height: 16px;
+ background: url(i/dialog-titlebar-close.png) no-repeat;
+ position:absolute;
+ top: 6px;
+ right: 7px;
+ cursor: default;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar-close span,
+.flora.ui-dialog .ui-dialog-titlebar-close span {
+ display: none;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar-close-hover,
+.flora.ui-dialog .ui-dialog-titlebar-close-hover {
+ background: url(i/dialog-titlebar-close-hover.png) no-repeat;
+}
+
+.flora .ui-dialog .ui-dialog-title,
+.flora.ui-dialog .ui-dialog-title {
+ margin-left: 5px;
+ color: white;
+ font-weight: bold;
+ position: relative;
+ top: 7px;
+ left: 4px;
+}
+
+.flora .ui-dialog .ui-dialog-content,
+.flora.ui-dialog .ui-dialog-content {
+ margin: 1.2em;
+}
+
+.flora .ui-dialog .ui-dialog-buttonpane,
+.flora.ui-dialog .ui-dialog-buttonpane {
+ position: absolute;
+ bottom: 8px;
+ right: 12px;
+ width: 100%;
+ text-align: right;
+}
+
+.flora .ui-dialog .ui-dialog-buttonpane button,
+.flora.ui-dialog .ui-dialog-buttonpane button {
+ margin: 6px;
+}
+
+/* Dialog handle styles */
+.flora .ui-dialog .ui-resizable-n,
+.flora.ui-dialog .ui-resizable-n { cursor: n-resize; height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/dialog-n.gif) repeat scroll center top; }
+
+.flora .ui-dialog .ui-resizable-s,
+.flora.ui-dialog .ui-resizable-s { cursor: s-resize; height: 8px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/dialog-s.gif) repeat scroll center top; }
+
+.flora .ui-dialog .ui-resizable-e,
+.flora.ui-dialog .ui-resizable-e { cursor: e-resize; width: 7px; right: 0px; top: 0px; height: 100%; background: transparent url(i/dialog-e.gif) repeat scroll right center; }
+
+.flora .ui-dialog .ui-resizable-w,
+.flora.ui-dialog .ui-resizable-w { cursor: w-resize; width: 7px; left: 0px; top: 0px; height: 100%; background: transparent url(i/dialog-w.gif) repeat scroll right center; }
+
+.flora .ui-dialog .ui-resizable-se,
+.flora.ui-dialog .ui-resizable-se { cursor: se-resize; width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/dialog-se.gif); }
+
+.flora .ui-dialog .ui-resizable-sw,
+.flora.ui-dialog .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/dialog-sw.gif); }
+
+.flora .ui-dialog .ui-resizable-nw,
+.flora.ui-dialog .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 29px; left: 0px; top: 0px; background: transparent url(i/dialog-nw.gif); }
+
+.flora .ui-dialog .ui-resizable-ne,
+.flora.ui-dialog .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 29px; right: 0px; top: 0px; background: transparent url(i/dialog-ne.gif); }
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.menu.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.menu.css
new file mode 100644
index 0000000..6d2dd21
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.menu.css
@@ -0,0 +1,8 @@
+.ui-menu-toolbar {z-index:500; list-style:none;}
+.ui-menu-toolbar-button {float:left; padding:4px 20px; cursor:pointer;}
+.ui-menu-toolbar-button:hover {}
+.ui-menu-toolbar-button a {text-decoration:none;}
+.ui-menu-items {display:none; padding:0; z-index:500; list-style:none; padding:1px 4px; min-width:80px; *width:80px;}
+.ui-menu-item a { text-decoration:none;}
+.ui-menu-item-parent { background: url('i/menu-submenu.gif') no-repeat center right; }
+.ui-menu-item-disabled {}
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.resizable.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.resizable.css
new file mode 100644
index 0000000..5e30c0c
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.resizable.css
@@ -0,0 +1,20 @@
+/* This file skins resizables */
+
+.ui-resizable { position: relative; }
+
+/* Global handle styles */
+.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; }
+.ui-resizable .ui-resizable-handle { display: block; }
+body .ui-resizable-disabled .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
+body .ui-resizable-autohide .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
+
+.ui-resizable-n { cursor: n-resize; height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/resizable-n.gif) repeat scroll center top; }
+.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/resizable-s.gif) repeat scroll center top; }
+
+.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%; background: transparent url(i/resizable-e.gif) repeat scroll right center; }
+.ui-resizable-w { cursor: w-resize; width: 6px; left: 0px; top: 0px; height: 100%; background: transparent url(i/resizable-w.gif) repeat scroll right center; }
+
+.ui-resizable-se { cursor: se-resize; width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/resizable-se.gif); }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/resizable-sw.gif); }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: 0px; top: 0px; background: transparent url(i/resizable-nw.gif); }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: 0px; top: 0px; background: transparent url(i/resizable-ne.gif); }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.slider.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.slider.css
new file mode 100644
index 0000000..94827b3
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.slider.css
@@ -0,0 +1,11 @@
+/* This file skins sliders */
+
+.ui-slider { width: 200px; height: 23px; position: relative; background-repeat: no-repeat; background-position: center center; }
+.ui-slider-handle { position: absolute; z-index: 1; height: 23px; width: 12px; top: 0px; left: 0px; background-image: url(i/slider-handle.gif); }
+.ui-slider-handle-active { border: 1px dotted black; }
+.ui-slider-disabled .ui-slider-handle { opacity: 0.5; filter: alpha(opacity=50); }
+.ui-slider-range { position: absolute; background: #50A029; opacity: 0.3; filter: alpha(opacity=30); width: 100%; height: 100%; }
+
+/* Default slider backgrounds */
+.ui-slider, .ui-slider-1 { background-image: url(i/slider-bg-1.png); }
+.ui-slider-2 { background-image: url(i/slider-bg-2.png); }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tablesorter.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tablesorter.css
new file mode 100644
index 0000000..7d805a7
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tablesorter.css
@@ -0,0 +1,40 @@
+/* This file skins tableSorter */
+
+table.tablesorter {
+ font-family:arial;
+ background-color: #CDCDCD;
+ margin:10px 0pt 15px;
+ font-size: 8pt;
+ width: 100%;
+ text-align: left;
+}
+table.tablesorter thead tr th, table.tablesorter tfoot tr th {
+ background-color: #B1DB87;
+ border: 1px solid #FFF;
+ font-size: 8pt;
+ padding: 4px;
+}
+table.tablesorter thead tr .header {
+ background-image: url(i/bg.gif);
+ background-repeat: no-repeat;
+ background-position: center right;
+ cursor: pointer;
+}
+table.tablesorter tbody td {
+ color: #3D3D3D;
+ padding: 4px;
+ background-color: #FFF;
+ vertical-align: top;
+}
+table.tablesorter tbody tr.odd td {
+ background-color:#E0F4D7;
+}
+table.tablesorter thead tr .headerSortUp {
+ background-image: url(i/asc.gif);
+}
+table.tablesorter thead tr .headerSortDown {
+ background-image: url(i/desc.gif);
+}
+table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
+background-color: #83C948;
+}
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tabs.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tabs.css
new file mode 100644
index 0000000..c79a17e
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.tabs.css
@@ -0,0 +1,105 @@
+@import "flora.css";
+
+/* Caution! Ensure accessibility in print and other media types... */
+@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
+ .ui-tabs-hide {
+ display: none;
+ }
+}
+
+/* Hide useless elements in print layouts... */
+@media print {
+ .ui-tabs-nav {
+ display: none;
+ }
+}
+
+/* Skin */
+.ui-tabs-nav, .ui-tabs-panel {
+ font-family: "Trebuchet MS", Trebuchet, Verdana, Helvetica, Arial, sans-serif;
+ font-size: 12px;
+}
+.ui-tabs-nav {
+ list-style: none;
+ margin: 0;
+ padding: 0 0 0 3px;
+}
+.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
+ display: block;
+ clear: both;
+ content: " ";
+}
+.ui-tabs-nav li {
+ float: left;
+ margin: 0 0 0 2px;
+ font-weight: bold;
+}
+.ui-tabs-nav a, .ui-tabs-nav a span {
+ float: left; /* fixes dir=ltr problem and other quirks IE */
+ padding: 0 12px;
+ background: url(i/tabs.png) no-repeat;
+}
+.ui-tabs-nav a {
+ margin: 5px 0 0; /* position: relative makes opacity fail for disabled tab in IE */
+ padding-left: 0;
+ background-position: 100% 0;
+ text-decoration: none;
+ white-space: nowrap; /* @ IE 6 */
+ outline: 0; /* @ Firefox, prevent dotted border after click */
+}
+.ui-tabs-nav a:link, .ui-tabs-nav a:visited {
+ color: #fff;
+}
+.ui-tabs-nav .ui-tabs-selected a {
+ position: relative;
+ top: 1px;
+ z-index: 2;
+ margin-top: 0;
+ background-position: 100% -23px;
+}
+.ui-tabs-nav a span {
+ padding-top: 1px;
+ padding-right: 0;
+ height: 20px;
+ background-position: 0 0;
+ line-height: 20px;
+}
+.ui-tabs-nav .ui-tabs-selected a span {
+ padding-top: 0;
+ height: 27px;
+ background-position: 0 -23px;
+ line-height: 27px;
+}
+.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited,
+.ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
+ cursor: text;
+}
+.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active,
+.ui-tabs-nav .ui-tabs-unselect a:hover, .ui-tabs-nav .ui-tabs-unselect a:focus, .ui-tabs-nav .ui-tabs-unselect a:active { /* @ Opera, we need to be explicit again here now... */
+ cursor: pointer;
+}
+.ui-tabs-disabled {
+ opacity: .4;
+ filter: alpha(opacity=40);
+}
+.ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited {
+ color: #000;
+}
+.ui-tabs-panel {
+ border: 1px solid #519e2d;
+ padding: 10px;
+ background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
+}
+/*.ui-tabs-loading em {
+ padding: 0 0 0 20px;
+ background: url(loading.gif) no-repeat 0 50%;
+}*/
+
+/* Additional IE specific bug fixes... */
+* html .ui-tabs-nav { /* auto clear @ IE 6 & IE 7 Quirks Mode */
+ display: inline-block;
+}
+*:first-child+html .ui-tabs-nav { /* auto clear @ IE 7 Standards Mode - do not group selectors, otherwise IE 6 will ignore complete rule (because of the unknown + combinator)... */
+ display: inline-block;
+}
+
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toasterLite.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toasterLite.css
new file mode 100644
index 0000000..6f2b55f
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toasterLite.css
@@ -0,0 +1,106 @@
+/* This file skins toasterLite */
+
+.flora .ui-toasterLite,
+.flora.ui-toasterLite {
+ background-color: #e6f7d4;
+ width: 100px;
+ display: block;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-titlebar,
+.flora.ui-toasterLite .ui-toasterLite-titlebar {
+ border-bottom: 1px solid #d8d2aa;
+ background: #ff9900 url(i/dialog-title.gif) repeat-x;
+ padding: 0px;
+ height: 28px;
+ z-index: 5;
+ position: relative;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-title,
+.flora.ui-toasterLite .ui-toasterLite-title {
+ margin-left: 5px;
+ color: white;
+ font-weight: bold;
+ position: relative;
+ top: 7px;
+ left: 4px;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-content,
+.flora.ui-toasterLite .ui-toasterLite-content {
+ margin: 1.2em;
+ padding-bottom: 12px;
+}
+
+/* Toaster handle styles */
+.flora .ui-toasterLite .ui-toasterLite-n,
+.flora.ui-toasterLite .ui-toasterLite-n { height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/toaster-n.gif) repeat scroll center top; z-index: 6; }
+
+.flora .ui-toasterLite .ui-toasterLite-s,
+.flora.ui-toasterLite .ui-toasterLite-s { height: 8px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/toaster-s.gif) repeat scroll center top; z-index: 1; }
+
+.flora .ui-toasterLite .ui-toasterLite-e,
+.flora.ui-toasterLite .ui-toasterLite-e { width: 7px; right: 0px; top: 0px; height: 100%; background: transparent url(i/toaster-e.gif) repeat scroll right center; }
+
+.flora .ui-toasterLite .ui-toasterLite-w,
+.flora.ui-toasterLite .ui-toasterLite-w { width: 7px; left: 0px; top: 0px; height: 100%; background: url(i/toaster-w.gif) repeat scroll right center; }
+
+.flora .ui-toasterLite .ui-toasterLite-se,
+.flora.ui-toasterLite .ui-toasterLite-se { width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/toaster-se.gif); z-index: 2; }
+
+.flora .ui-toasterLite .ui-toasterLite-sw,
+.flora.ui-toasterLite .ui-toasterLite-sw { width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/toaster-sw.gif); z-index: 2; }
+
+.flora .ui-toasterLite .ui-toasterLite-nw,
+.flora.ui-toasterLite .ui-toasterLite-nw { width: 9px; height: 29px; left: 0px; top: 0px; background: transparent url(i/toaster-nw.gif); z-index: 6; }
+
+.flora .ui-toasterLite .ui-toasterLite-ne,
+.flora.ui-toasterLite .ui-toasterLite-ne { width: 9px; height: 29px; right: 0px; top: 0px; background: transparent url(i/toaster-ne.gif); z-index: 6; }
+
+/* Global handle styles */
+.ui-toasterLite-corner { position: absolute; font-size: 0.1px; }
+
+.flora .ui-toasterLite-holder,
+.flora.ui-toasterLite-holder {
+ position: absolute;
+}
+.flora .ui-toasterLite-holder-pos-tr,
+.flora.ui-toasterLite-holder-pos-tr {
+ top: 10px;
+ right: 10px;
+}
+
+.flora .ui-toasterLite-holder-pos-tl,
+.flora.ui-toasterLite-holder-pos-tl {
+ top: 10px;
+ left: 10px;
+}
+
+.flora .ui-toasterLite-holder-pos-br,
+.flora.ui-toasterLite-holder-pos-br {
+ bottom: 10px;
+ right: 10px;
+}
+
+.flora .ui-toasterLite-holder-pos-bl,
+.flora.ui-toasterLite-holder-pos-bl {
+ bottom: 10px;
+ left: 10px;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-titlebar-close,
+.flora.ui-toasterLite .ui-toasterLite-titlebar-close {
+ width: 16px;
+ height: 16px;
+ background: url(i/dialog-titlebar-close.png) no-repeat;
+ position:absolute;
+ top: 6px;
+ right: 7px;
+ cursor: default;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-titlebar-close-hover,
+.flora.ui-toasterLite .ui-toasterLite-titlebar-close-hover {
+ background: url(i/dialog-titlebar-close-hover.png) no-repeat;
+}
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toolbar.css b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toolbar.css
new file mode 100644
index 0000000..8ad0588
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/flora.toolbar.css
@@ -0,0 +1,241 @@
+/* light.toolbar.css
+ *
+ * Written: 05/09/07 4:38:01 PM
+ * Revision: 1.0.0
+ *
+ *
+ * Credits:
+ * Miksago: Full Coding.
+ */
+
+.flora .ui-toolbar {
+ position:relative;
+ padding:0px;
+ margin:0px;
+}
+.flora .ui-toolbar ul {
+ background:#E6F7D4;
+ padding:0px;
+ margin:0px;
+}
+ .flora .ui-toolbar ul li {
+ list-style-type: none;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz {
+ border-top:1px solid #5AB500;
+ background:#E6F7D4 url("i/toolbars-bot-bg.gif") repeat-x bottom left;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz li {
+ display:inline;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert {
+ padding: 0.025em 0em;
+ border-left: 1px solid #111;
+ border-right: 1px solid #444;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li {
+ display:block;
+ }
+ /* This hides the text on buttons in a icon only toolbar */
+ .flora .ui-toolbar ul.ui-toolbar-icons li .ui-toolbar-btn-desc {
+ display:none;
+ }
+ /* This hides the icon on buttons in a text only toolbar */
+ .flora .ui-toolbar ul.ui-toolbar-text li .ui-toolbar-btn-icon {
+ display:none;
+ }
+ /* This is just for icon sizes, not really needed, but it's there so if icon sizes are defined.. */
+ .flora .ui-toolbar ul li.ui-toolbar-btn-icon-sixteen .ui-toolbar-btn-icon {
+ width:16px; height:16px;
+ overflow:hidden;
+ padding:2px;
+ padding-left:16px;
+ background:no-repeat;
+ background-position:50% 50%;
+ }
+
+/************************************************
+ * Factory Elements:
+ * - These are different kinds of items that
+ * can be in a toolbar.
+ *
+ * Includes:
+ * @ ui-toolbar-btn
+ * toolbar buttons.
+ * @ ui-toolbar-sep
+ * toolbar separators.
+ *
+*/
+
+
+
+/************************************************
+ * UI-TOOLBAR-BTN
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-btn">
+ * <span class="ui-toolbar-btn-left"><i> </i></span>
+ * <span class="ui-toolbar-btn-center">
+ * <button><span>{{text}}</span></button>
+ * </span>
+ * <span class="ui-toolbar-btn-right"><i> </i></span>
+ * </li>
+ *
+ ************************************************/
+
+
+ .flora .ui-toolbar ul li.ui-toolbar-btn {
+ cursor:pointer;
+ white-space: nowrap;
+ position:relative;
+ }
+ .flora .ui-toolbar ul li .ui-toolbar-btn-left {
+ width:3px;
+ padding:5px 0px 1px 0;
+ position:absolute;
+ top:-3px;
+ bottom:0px;
+ left:-3px;
+ height:100%;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left i,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left i{
+ width:3px; height:5px;
+ padding:0px 0px 0px 0px;
+ position:absolute;
+ bottom:0px;
+ left:0px;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-center,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-center{
+ background:url("i/accordion-middle-over.png") repeat-x left top;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left {
+ background:url("i/accordion-left-over.png") no-repeat left top;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left i,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left i{
+ background:url("i/accordion-left-over.png") no-repeat left bottom;
+ }
+ .flora .ui-toolbar ul li .ui-toolbar-btn-center {
+ padding: 0.2em 0em;
+ line-height:2.2em;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-btn {
+ vertical-align: middle;
+ margin:0.3em 0.2em;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-btn {
+ margin:0.2em;
+ line-height:1.6em;
+ vertical-align: middle;
+ }
+ .flora .ui-toolbar ul li button {
+ vertical-align: middle;
+ background:transparent;
+ color:#000;
+ border:0px none;
+ cursor:pointer;
+ overflow:visible;
+ -moz-outline:0 none;
+ outline:0 none;
+ padding: 0.1em 0.1em;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn button span {
+ vertical-align: middle;
+ }
+ /* This hides the text on buttons in a icon only toolbar */
+ .flora .ui-toolbar ul.ui-toobar-iconOnly li.ui-toolbar-btn button span {
+ display:none;
+ }
+
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-center button,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-center button {
+ background: url("i/accordion-middle-over.png") repeat-x left bottom;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active {
+
+ }
+
+ .flora .ui-toolbar ul li.ui-toolbar-btn-disabled {
+ opacity:0.2;
+ }
+
+/************************************************
+ * UI-TOOLBAR-BTN
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-sep">
+ * <span>
+ *
+ * </span>
+ * </li>
+ *
+ ************************************************/
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-sep {
+ border-left:1px solid #444;
+ border-right:1px solid #111;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-sep {
+ border-top:1px solid #111;
+ border-bottom:1px solid #444;
+ }
+
+/************************************************
+ * UI-TOOLBAR-SLIDER
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-slider">
+ * <div class="ui-toolbar-slider-track ui-slider-track">
+ * <div class="ui-slider-handle"></div>
+ * </div>
+ * </li>
+ *
+ ************************************************/
+
+.flora .ui-toolbar ul li.ui-toolbar-slider .ui-toolbar-slider-track {
+ height: 20px!important;
+}
+
+/************************************************
+ * UI-TOOLBAR-RADIOGRP
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-radioGrp">
+ * <ul class="DIRECTION">
+ * <li class="ui-toolbar-btn">
+ * <span class="ui-toolbar-btn-left"><i> </i></span>
+ * <span class="ui-toolbar-btn-center">
+ * <button><span>{{text}}</span></button>
+ * </span>
+ * <span class="ui-toolbar-btn-right"><i> </i></span>
+ * </li>
+ * </ul>
+ * </li>
+ *
+ *
+ ************************************************/
+
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp,
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul,
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul li{
+ display:inline;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul {
+ margin:0px;
+ padding:0px;
+ }
+
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp,
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul,
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul li{
+ display:block;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul {
+ margin:0px;
+ padding:0px;
+ }
+
+
+/* END OF FILE */
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-act.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-act.png
new file mode 100644
index 0000000..bf6ee99
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-act.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-over.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-over.png
new file mode 100644
index 0000000..66378e0
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left-over.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left.png
new file mode 100644
index 0000000..13344fc
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-left.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-act.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-act.png
new file mode 100644
index 0000000..cecf4f1
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-act.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-over.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-over.png
new file mode 100644
index 0000000..251ad11
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle-over.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle.png
new file mode 100644
index 0000000..5238fd4
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-middle.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-act.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-act.png
new file mode 100644
index 0000000..1fa4792
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-act.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-over.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-over.png
new file mode 100644
index 0000000..d676dad
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right-over.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right.png
new file mode 100644
index 0000000..543991a
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/accordion-right.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/asc.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/asc.gif
new file mode 100644
index 0000000..7415786
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/asc.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/bg.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/bg.gif
new file mode 100644
index 0000000..fac668f
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/bg.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/desc.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/desc.gif
new file mode 100644
index 0000000..3b30b3c
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/desc.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-e.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-e.gif
new file mode 100644
index 0000000..3b8b521
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-e.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-n.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-n.gif
new file mode 100644
index 0000000..70887b8
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-n.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-ne.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-ne.gif
new file mode 100644
index 0000000..ab9c38e
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-ne.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-nw.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-nw.gif
new file mode 100644
index 0000000..e934073
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-nw.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-s.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-s.gif
new file mode 100644
index 0000000..d5f6b99
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-s.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-se.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-se.gif
new file mode 100644
index 0000000..186a864
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-se.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-sw.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-sw.gif
new file mode 100644
index 0000000..025dfda
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-sw.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-title.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-title.gif
new file mode 100644
index 0000000..156c59b
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-title.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png
new file mode 100644
index 0000000..67c1303
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png
new file mode 100644
index 0000000..cec974c
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-w.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-w.gif
new file mode 100644
index 0000000..931ff4a
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/dialog-w.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/menu-submenu.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/menu-submenu.gif
new file mode 100644
index 0000000..77647d8
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/menu-submenu.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-e.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-e.gif
new file mode 100644
index 0000000..7acf248
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-e.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-n.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-n.gif
new file mode 100644
index 0000000..59110f6
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-n.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-ne.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-ne.gif
new file mode 100644
index 0000000..515a3f8
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-ne.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-nw.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-nw.gif
new file mode 100644
index 0000000..665f318
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-nw.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-s.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-s.gif
new file mode 100644
index 0000000..da2fb35
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-s.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-se.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-se.gif
new file mode 100644
index 0000000..6c258ef
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-se.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-sw.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-sw.gif
new file mode 100644
index 0000000..2fd8de4
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-sw.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-w.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-w.gif
new file mode 100644
index 0000000..34b875b
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/resizable-w.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/shadow.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/shadow.png
new file mode 100644
index 0000000..4c58c7f
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/shadow.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-1.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-1.png
new file mode 100644
index 0000000..b7d806e
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-1.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-2.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-2.png
new file mode 100644
index 0000000..8b24cf0
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-bg-2.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-handle.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-handle.gif
new file mode 100644
index 0000000..9b89f26
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/slider-handle.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/tabs.png b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/tabs.png
new file mode 100644
index 0000000..8018e41
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/tabs.png differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-e.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-e.gif
new file mode 100644
index 0000000..55dcb2c
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-e.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-n.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-n.gif
new file mode 100644
index 0000000..b0fbeb9
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-n.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-ne.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-ne.gif
new file mode 100644
index 0000000..ab9c38e
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-ne.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-nw.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-nw.gif
new file mode 100644
index 0000000..e934073
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-nw.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-s.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-s.gif
new file mode 100644
index 0000000..15640e8
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-s.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-se.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-se.gif
new file mode 100644
index 0000000..fb7a7df
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-se.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-sw.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-sw.gif
new file mode 100644
index 0000000..ad1ae1c
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-sw.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-w.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-w.gif
new file mode 100644
index 0000000..8489de8
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toaster-w.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif
new file mode 100644
index 0000000..15640e8
Binary files /dev/null and b/moksha/widgetbrowser/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif differ
diff --git a/moksha/widgetbrowser/widgetbrowser/static/ui.base.js b/moksha/widgetbrowser/widgetbrowser/static/ui.base.js
new file mode 100644
index 0000000..17115f0
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/ui.base.js
@@ -0,0 +1,204 @@
+/*
+ * jQuery UI @VERSION
+ *
+ * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ *
+ * $Date: 2008-04-01 09:23:47 -0400 (Tue, 01 Apr 2008) $
+ * $Rev: 5174 $
+ */
+;(function($) {
+
+ //If the UI scope is not available, add it
+ $.ui = $.ui || {};
+
+ //Add methods that are vital for all mouse interaction stuff (plugin registering)
+ $.extend($.ui, {
+ plugin: {
+ add: function(module, option, set) {
+ var proto = $.ui[module].prototype;
+ for(var i in set) {
+ proto.plugins[i] = proto.plugins[i] || [];
+ proto.plugins[i].push([option, set[i]]);
+ }
+ },
+ call: function(instance, name, arguments) {
+ var set = instance.plugins[name]; if(!set) return;
+ for (var i = 0; i < set.length; i++) {
+ if (instance.options[set[i][0]]) set[i][1].apply(instance.element, arguments);
+ }
+ }
+ },
+ cssCache: {},
+ css: function(name) {
+ if ($.ui.cssCache[name]) return $.ui.cssCache[name];
+ var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
+
+ //if (!$.browser.safari)
+ //tmp.appendTo('body');
+
+ //Opera and Safari set width and height to 0px instead of auto
+ //Safari returns rgba(0,0,0,0) when bgcolor is not set
+ $.ui.cssCache[name] = !!(
+ (!/auto|default/.test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) ||
+ !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
+ );
+ try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){}
+ return $.ui.cssCache[name];
+ },
+ disableSelection: function(e) {
+ e.unselectable = "on";
+ e.onselectstart = function() { return false; };
+ if (e.style) e.style.MozUserSelect = "none";
+ },
+ enableSelection: function(e) {
+ e.unselectable = "off";
+ e.onselectstart = function() { return true; };
+ if (e.style) e.style.MozUserSelect = "";
+ },
+ hasScroll: function(e, a) {
+ var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
+ if (e[scroll] > 0) return true; e[scroll] = 1;
+ has = e[scroll] > 0 ? true : false; e[scroll] = 0;
+ return has;
+ }
+ });
+
+ /******* fn scope modifications ********/
+
+ $.each( ['Left', 'Top'], function(i, name) {
+ if(!$.fn['scroll'+name]) $.fn['scroll'+name] = function(v) {
+ return v != undefined ?
+ this.each(function() { this == window || this == document ? window.scrollTo(name == 'Left' ? v : $(window)['scrollLeft'](), name == 'Top' ? v : $(window)['scrollTop']()) : this['scroll'+name] = v; }) :
+ this[0] == window || this[0] == document ? self[(name == 'Left' ? 'pageXOffset' : 'pageYOffset')] || $.boxModel && document.documentElement['scroll'+name] || document.body['scroll'+name] : this[0][ 'scroll' + name ];
+ };
+ });
+
+ var _remove = $.fn.remove;
+ $.fn.extend({
+ position: function() {
+ var offset = this.offset();
+ var offsetParent = this.offsetParent();
+ var parentOffset = offsetParent.offset();
+
+ return {
+ top: offset.top - num(this[0], 'marginTop') - parentOffset.top - num(offsetParent, 'borderTopWidth'),
+ left: offset.left - num(this[0], 'marginLeft') - parentOffset.left - num(offsetParent, 'borderLeftWidth')
+ };
+ },
+ offsetParent: function() {
+ var offsetParent = this[0].offsetParent;
+ while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
+ offsetParent = offsetParent.offsetParent;
+ return $(offsetParent);
+ },
+ mouseInteraction: function(o) {
+ return this.each(function() {
+ new $.ui.mouseInteraction(this, o);
+ });
+ },
+ removeMouseInteraction: function(o) {
+ return this.each(function() {
+ if($.data(this, "ui-mouse"))
+ $.data(this, "ui-mouse").destroy();
+ });
+ },
+ remove: function() {
+ jQuery("*", this).add(this).trigger("remove");
+ return _remove.apply(this, arguments );
+ }
+ });
+
+ function num(el, prop) {
+ return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
+ };
+
+
+ /********** Mouse Interaction Plugin *********/
+
+ $.ui.mouseInteraction = function(element, options) {
+
+ var self = this;
+ this.element = element;
+
+ $.data(this.element, "ui-mouse", this);
+ this.options = $.extend({}, options);
+
+ $(element).bind('mousedown.draggable', function() { return self.click.apply(self, arguments); });
+ if($.browser.msie) $(element).attr('unselectable', 'on'); //Prevent text selection in IE
+
+ // prevent draggable-options-delay bug #2553
+ $(element).mouseup(function() {
+ if(self.timer) clearInterval(self.timer);
+ });
+ };
+
+ $.extend($.ui.mouseInteraction.prototype, {
+
+ destroy: function() { $(this.element).unbind('mousedown.draggable'); },
+ trigger: function() { return this.click.apply(this, arguments); },
+ click: function(e) {
+
+ if(
+ e.which != 1 //only left click starts dragging
+ || $.inArray(e.target.nodeName.toLowerCase(), this.options.dragPrevention || []) != -1 // Prevent execution on defined elements
+ || (this.options.condition && !this.options.condition.apply(this.options.executor || this, [e, this.element])) //Prevent execution on condition
+ ) return true;
+
+ var self = this;
+ var initialize = function() {
+ self._MP = { left: e.pageX, top: e.pageY }; // Store the click mouse position
+ $(document).bind('mouseup.draggable', function() { return self.stop.apply(self, arguments); });
+ $(document).bind('mousemove.draggable', function() { return self.drag.apply(self, arguments); });
+
+ if(!self.initalized && Math.abs(self._MP.left-e.pageX) >= self.options.distance || Math.abs(self._MP.top-e.pageY) >= self.options.distance) {
+ if(self.options.start) self.options.start.call(self.options.executor || self, e, self.element);
+ if(self.options.drag) self.options.drag.call(self.options.executor || self, e, this.element); //This is actually not correct, but expected
+ self.initialized = true;
+ }
+ };
+
+ if(this.options.delay) {
+ if(this.timer) clearInterval(this.timer);
+ this.timer = setTimeout(initialize, this.options.delay);
+ } else {
+ initialize();
+ }
+
+ return false;
+
+ },
+ stop: function(e) {
+
+ var o = this.options;
+ if(!this.initialized) return $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
+
+ if(this.options.stop) this.options.stop.call(this.options.executor || this, e, this.element);
+ $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
+ this.initialized = false;
+ return false;
+
+ },
+ drag: function(e) {
+
+ var o = this.options;
+ if ($.browser.msie && !e.button) return this.stop.apply(this, [e]); // IE mouseup check
+
+ if(!this.initialized && (Math.abs(this._MP.left-e.pageX) >= o.distance || Math.abs(this._MP.top-e.pageY) >= o.distance)) {
+ if(this.options.start) this.options.start.call(this.options.executor || this, e, this.element);
+ this.initialized = true;
+ } else {
+ if(!this.initialized) return false;
+ }
+
+ if(o.drag) o.drag.call(this.options.executor || this, e, this.element);
+ return false;
+
+ }
+ });
+
+})(jQuery);
+
\ No newline at end of file
diff --git a/moksha/widgetbrowser/widgetbrowser/static/ui.dialog.js b/moksha/widgetbrowser/widgetbrowser/static/ui.dialog.js
new file mode 100644
index 0000000..7a907bd
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/ui.dialog.js
@@ -0,0 +1,459 @@
+/*
+ * jQuery UI Dialog
+ *
+ * Copyright (c) 2008 Richard D. Worth (rdworth.org)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ * ui.base.js
+ * ui.draggable.js
+ * ui.resizable.js
+ *
+ * Revision: $Id: ui.dialog.js 5185 2008-04-03 15:39:51Z scott.gonzalez $
+ */
+;(function($) {
+
+ $.fn.extend({
+ dialog: function(options) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ if (typeof options == "string") {
+ var elem = $(this).is('.ui-dialog')
+ ? this
+ : $(this).parents(".ui-dialog:first").find(".ui-dialog-content")[0];
+ var dialog = elem ? $.data(elem, "dialog") : {};
+ if (dialog[options])
+ dialog[options].apply(dialog, args);
+ // INIT with optional options
+ } else if (!$(this).is(".ui-dialog-content"))
+ new $.ui.dialog(this, options);
+ });
+ }
+ });
+
+ $.ui.dialog = function(el, options) {
+
+ this.options = options = $.extend({}, $.ui.dialog.defaults, options);
+ this.element = el;
+ var self = this; //Do bindings
+
+ $.data(this.element, "dialog", this);
+
+ $(el).bind("remove", function() {
+ self.destroy();
+ });
+
+ $(el).bind("setData.dialog", function(event, key, value){
+ switch (key) {
+ case "draggable":
+ uiDialog.draggable(value ? 'enable' : 'disable');
+ break;
+ case "dragStart":
+ uiDialog.data('start.draggable', value);
+ break;
+ case "drag":
+ uiDialog.data('drag.draggable', value);
+ break;
+ case "dragStop":
+ uiDialog.data('stop.draggable', value);
+ break;
+ case "height":
+ uiDialog.height(value);
+ break;
+ case "maxHeight":
+ case "minHeight":
+ case "maxWidth":
+ case "minWidth":
+ uiDialog.data(key + ".resizable", value);
+ break;
+ case "position":
+ self.position(value);
+ break;
+ case "resizable":
+ uiDialog.resizable(value ? 'enable' : 'disable');
+ break;
+ case "resizeStart":
+ uiDialog.data('start.resizable', value);
+ break;
+ case "resize":
+ uiDialog.data('resize.resizable', value);
+ break;
+ case "resizeStop":
+ uiDialog.data('stop.resizable', value);
+ break;
+ case "title":
+ $(".ui-dialog-title", uiDialogTitlebar).text(value);
+ break;
+ case "width":
+ break;
+ }
+ options[key] = value;
+ }).bind("getData.dialog", function(event, key){
+ return options[key];
+ });
+
+ var uiDialogContent = $(el).addClass('ui-dialog-content');
+
+ if (!uiDialogContent.parent().length) {
+ uiDialogContent.appendTo('body');
+ }
+ uiDialogContent
+ .wrap(document.createElement('div'))
+ .wrap(document.createElement('div'));
+ var uiDialogContainer = uiDialogContent.parent().addClass('ui-dialog-container').css({position: 'relative'});
+ var uiDialog = this.uiDialog = uiDialogContainer.parent().hide()
+ .addClass('ui-dialog')
+ .css({position: 'absolute', width: options.width, height: options.height, overflow: 'hidden'});
+
+ var classNames = uiDialogContent.attr('className').split(' ');
+
+ // Add content classes to dialog, to inherit theme at top level of element
+ $.each(classNames, function(i, className) {
+ if (className != 'ui-dialog-content')
+ uiDialog.addClass(className);
+ });
+
+ if ($.fn.resizable) {
+ uiDialog.append('<div class="ui-resizable-n ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-s ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-e ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-w ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-ne ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-se ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-sw ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-nw ui-resizable-handle"></div>');
+ uiDialog.resizable({
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: options.minHeight,
+ start: options.resizeStart,
+ resize: options.resize,
+ stop: function(e, ui) {
+ options.resizeStop && options.resizeStop.apply(this, arguments);
+ $.ui.dialog.overlay.resize();
+ }
+ });
+ if (!options.resizable)
+ uiDialog.resizable('disable');
+ }
+
+ uiDialogContainer.prepend('<div class="ui-dialog-titlebar"></div>');
+ var uiDialogTitlebar = $('.ui-dialog-titlebar', uiDialogContainer);
+ var title = (options.title) ? options.title : (uiDialogContent.attr('title')) ? uiDialogContent.attr('title') : '';
+ uiDialogTitlebar.append('<span class="ui-dialog-title">' + title + '</span>');
+ uiDialogTitlebar.append('<a href="#" class="ui-dialog-titlebar-close"><span>X</span></a>');
+ this.uiDialogTitlebarClose = $('.ui-dialog-titlebar-close', uiDialogTitlebar)
+ .hover(function() { $(this).addClass('ui-dialog-titlebar-close-hover'); },
+ function() { $(this).removeClass('ui-dialog-titlebar-close-hover'); })
+ .mousedown(function(ev) {
+ ev.stopPropagation();
+ })
+ .click(function() {
+ self.close();
+ return false;
+ })
+ .keydown(function(ev) {
+ var ESC = 27;
+ ev.keyCode && ev.keyCode == ESC && self.close();
+ });
+
+ var l = 0;
+ $.each(options.buttons, function() { l = 1; return false; });
+ if (l == 1) {
+ uiDialog.append('<div class="ui-dialog-buttonpane"></div>');
+ var uiDialogButtonPane = $('.ui-dialog-buttonpane', uiDialog);
+ $.each(options.buttons, function(name, value) {
+ var btn = $(document.createElement('button')).text(name).click(value);
+ uiDialogButtonPane.append(btn);
+ });
+ }
+
+ if ($.fn.draggable) {
+ uiDialog.draggable({
+ handle: '.ui-dialog-titlebar',
+ start: function(e, ui) {
+ self.activate();
+ options.dragStart && options.dragStart.apply(this, arguments);
+ },
+ drag: options.drag,
+ stop: function(e, ui) {
+ options.dragStop && options.dragStop.apply(this, arguments);
+ $.ui.dialog.overlay.resize();
+ }
+ });
+ if (!options.draggable)
+ uiDialog.draggable('disable')
+ }
+
+ uiDialog.mousedown(function() {
+ self.activate();
+ });
+ uiDialogTitlebar.click(function() {
+ self.activate();
+ });
+
+ options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe();
+
+ this.position = function(pos) {
+ var wnd = $(window), doc = $(document), top = doc.scrollTop(), left = doc.scrollLeft();
+ if (pos.constructor == Array) {
+ // [x, y]
+ top += pos[1];
+ left += pos[0];
+ } else {
+ switch (pos) {
+ case 'center':
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ break;
+ case 'top':
+ top += 0;
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ break;
+ case 'right':
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += (wnd.width()) - (uiDialog.width());
+ break;
+ case 'bottom':
+ top += (wnd.height()) - (uiDialog.height());
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ break;
+ case 'left':
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += 0;
+ break;
+ default:
+ //center
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ }
+ }
+ top = top < doc.scrollTop() ? doc.scrollTop() : top;
+ uiDialog.css({top: top, left: left});
+ }
+
+ this.open = function() {
+ this.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
+ uiDialog.appendTo('body');
+ this.position(options.position);
+ uiDialog.show();
+ self.moveToTop();
+ self.activate();
+
+ // CALLBACK: open
+ var openEV = null;
+ var openUI = {
+ options: options
+ };
+ this.uiDialogTitlebarClose.focus();
+ $(this.element).triggerHandler("dialogopen", [openEV, openUI], options.open);
+ };
+
+ this.activate = function() {
+ // Move modeless dialogs to the top when they're activated. Even
+ // if there is a modal dialog in the window, the modeless dialog
+ // should be on top because it must have been opened after the modal
+ // dialog. Modal dialogs don't get moved to the top because that
+ // would make any modeless dialogs that it spawned unusable until
+ // the modal dialog is closed.
+ !options.modal && this.moveToTop();
+ };
+
+ this.moveToTop = function() {
+ var maxZ = options.zIndex;
+ $('.ui-dialog:visible').each(function() {
+ maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10) || options.zIndex);
+ });
+ this.overlay && this.overlay.$el.css('z-index', ++maxZ);
+ uiDialog.css('z-index', ++maxZ);
+ };
+
+ this.close = function() {
+ this.overlay && this.overlay.destroy();
+ uiDialog.hide();
+
+ // CALLBACK: close
+ var closeEV = null;
+ var closeUI = {
+ options: options
+ };
+ $(this.element).triggerHandler("dialogclose", [closeEV, closeUI], options.close);
+ $.ui.dialog.overlay.resize();
+ };
+
+ this.destroy = function() {
+ this.overlay && this.overlay.destroy();
+ uiDialog.hide();
+ $(el).unbind('.dialog').removeClass('ui-dialog-content').hide().appendTo('body');
+ uiDialog.remove();
+ $.removeData(this.element, "dialog");
+ };
+
+ if (options.autoOpen) {
+ this.open();
+ };
+ };
+
+ $.extend($.ui.dialog, {
+ defaults: {
+ autoOpen: true,
+ bgiframe: false,
+ buttons: [],
+ draggable: true,
+ height: 200,
+ minHeight: 100,
+ minWidth: 150,
+ modal: false,
+ overlay: {},
+ position: 'center',
+ resizable: true,
+ width: 300,
+ zIndex: 1000
+ },
+
+ overlay: function(dialog) {
+ this.$el = $.ui.dialog.overlay.create(dialog);
+ }
+ });
+
+ $.extend($.ui.dialog.overlay, {
+ instances: [],
+ events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
+ function(e) { return e + '.dialog-overlay'; }).join(' '),
+ create: function(dialog) {
+ if (this.instances.length === 0) {
+ // prevent use of anchors and inputs
+ $('a, :input').bind(this.events, function() {
+ // allow use of the element if inside a dialog and
+ // - there are no modal dialogs
+ // - there are modal dialogs, but we are in front of the
+ // topmost modal dialog
+ var allow = false;
+ var $dialog = $(this).parents('.ui-dialog');
+ if ($dialog.length) {
+ var $overlays = $('.ui-dialog-overlay');
+ if ($overlays.length) {
+ var maxZ = parseInt($overlays.css('z-index'), 10);
+ $overlays.each(function() {
+ maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10));
+ });
+ allow = parseInt($dialog.css('z-index'), 10) > maxZ;
+ } else {
+ allow = true;
+ }
+ }
+ return allow;
+ });
+
+ // allow closing by pressing the escape key
+ $(document).bind('keydown.dialog-overlay', function(e) {
+ var ESC = 27;
+ e.keyCode && e.keyCode == ESC && dialog.close();
+ });
+
+ // handle window resize
+ $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
+ }
+
+ var $el = $('<div/>').appendTo(document.body)
+ .addClass('ui-dialog-overlay').css($.extend({
+ borderWidth: 0, margin: 0, padding: 0,
+ position: 'absolute', top: 0, left: 0,
+ width: this.width(),
+ height: this.height()
+ }, dialog.options.overlay));
+
+ dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe();
+
+ this.instances.push($el);
+ return $el;
+ },
+
+ destroy: function($el) {
+ this.instances.splice($.inArray(this.instances, $el), 1);
+
+ if (this.instances.length === 0) {
+ $('a, :input').add([document, window]).unbind('.dialog-overlay');
+ }
+
+ $el.remove();
+ },
+
+ height: function() {
+ if ($.browser.msie && $.browser.version < 7) {
+ var scrollHeight = Math.max(
+ document.documentElement.scrollHeight,
+ document.body.scrollHeight
+ );
+ var offsetHeight = Math.max(
+ document.documentElement.offsetHeight,
+ document.body.offsetHeight
+ );
+
+ if (scrollHeight < offsetHeight) {
+ return $(window).height() + 'px';
+ } else {
+ return scrollHeight + 'px';
+ }
+ } else {
+ return $(document).height() + 'px';
+ }
+ },
+
+ width: function() {
+ if ($.browser.msie && $.browser.version < 7) {
+ var scrollWidth = Math.max(
+ document.documentElement.scrollWidth,
+ document.body.scrollWidth
+ );
+ var offsetWidth = Math.max(
+ document.documentElement.offsetWidth,
+ document.body.offsetWidth
+ );
+
+ if (scrollWidth < offsetWidth) {
+ return $(window).width() + 'px';
+ } else {
+ return scrollWidth + 'px';
+ }
+ } else {
+ return $(document).width() + 'px';
+ }
+ },
+
+ resize: function() {
+ /* If the dialog is draggable and the user drags it past the
+ * right edge of the window, the document becomes wider so we
+ * need to stretch the overlay. If the user then drags the
+ * dialog back to the left, the document will become narrower,
+ * so we need to shrink the overlay to the appropriate size.
+ * This is handled by shrinking the overlay before setting it
+ * to the full document size.
+ */
+ var $overlays = $([]);
+ $.each($.ui.dialog.overlay.instances, function() {
+ $overlays = $overlays.add(this);
+ });
+
+ $overlays.css({
+ width: 0,
+ height: 0
+ }).css({
+ width: $.ui.dialog.overlay.width(),
+ height: $.ui.dialog.overlay.height()
+ });
+ }
+ });
+
+ $.extend($.ui.dialog.overlay.prototype, {
+ destroy: function() {
+ $.ui.dialog.overlay.destroy(this.$el);
+ }
+ });
+
+})(jQuery);
diff --git a/moksha/widgetbrowser/widgetbrowser/static/ui.draggable.js b/moksha/widgetbrowser/widgetbrowser/static/ui.draggable.js
new file mode 100644
index 0000000..ce209db
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/ui.draggable.js
@@ -0,0 +1,572 @@
+/*
+ * jQuery UI Draggable
+ *
+ * Copyright (c) 2008 Paul Bakaus
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * ui.base.js
+ *
+ * Revision: $Id: ui.draggable.js 5194 2008-04-04 12:30:10Z paul.bakaus $
+ */
+;(function($) {
+
+ $.fn.extend({
+ draggable: function(options) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ if (typeof options == "string") {
+ var drag = $.data(this, "draggable");
+ if(drag) drag[options].apply(drag, args);
+
+ } else if(!$.data(this, "draggable"))
+ new $.ui.draggable(this, options);
+ });
+ }
+ });
+
+ $.ui.draggable = function(element, options) {
+ //Initialize needed constants
+ var self = this;
+
+ this.element = $(element);
+
+ $.data(element, "draggable", this);
+ this.element.addClass("ui-draggable");
+
+ //Prepare the passed options
+ this.options = $.extend({}, options);
+ var o = this.options;
+ $.extend(o, {
+ helper: o.ghosting == true ? 'clone' : (o.helper || 'original'),
+ handle : o.handle ? ($(o.handle, element)[0] ? $(o.handle, element) : this.element) : this.element,
+ appendTo: o.appendTo || 'parent'
+ });
+
+ $(element).bind("setData.draggable", function(event, key, value){
+ self.options[key] = value;
+ }).bind("getData.draggable", function(event, key){
+ return self.options[key];
+ });
+
+ //Initialize mouse events for interaction
+ $(o.handle).mouseInteraction({
+ executor: this,
+ delay: o.delay,
+ distance: o.distance || 1,
+ dragPrevention: o.cancel || o.cancel === '' ? o.cancel.toLowerCase().split(',') : ['input','textarea','button','select','option'],
+ start: this.start,
+ stop: this.stop,
+ drag: this.drag,
+ condition: function(e) { return !(e.target.className.indexOf("ui-resizable-handle") != -1 || this.options.disabled); }
+ });
+
+ //Position the node
+ if(o.helper == 'original' && (this.element.css('position') == 'static' || this.element.css('position') == ''))
+ this.element.css('position', 'relative');
+
+ //Prepare cursorAt
+ if(o.cursorAt && o.cursorAt.constructor == Array)
+ o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] };
+
+ };
+
+ $.extend($.ui.draggable.prototype, {
+ plugins: {},
+ ui: function(e) {
+ return {
+ helper: this.helper,
+ position: this.position,
+ absolutePosition: this.positionAbs,
+ instance: this,
+ options: this.options,
+ element: this.element
+ };
+ },
+ propagate: function(n,e) {
+ $.ui.plugin.call(this, n, [e, this.ui()]);
+ return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [e, this.ui()], this.options[n]);
+ },
+ destroy: function() {
+ if(!$.data(this.element[0], 'draggable')) return;
+ this.options.handle.removeMouseInteraction();
+ this.element
+ .removeClass("ui-draggable ui-draggable-disabled")
+ .removeData("draggable")
+ .unbind(".draggable");
+ },
+ enable: function() {
+ this.element.removeClass("ui-draggable-disabled");
+ this.options.disabled = false;
+ },
+ disable: function() {
+ this.element.addClass("ui-draggable-disabled");
+ this.options.disabled = true;
+ },
+ setContrains: function(minLeft,maxLeft,minTop,maxTop) {
+ this.minLeft = minLeft; this.maxLeft = maxLeft;
+ this.minTop = minTop; this.maxTop = maxTop;
+ this.constrainsSet = true;
+ },
+ checkConstrains: function() {
+ if(!this.constrainsSet) return;
+ if(this.position.left < this.minLeft) this.position.left = this.minLeft;
+ if(this.position.left > this.maxLeft - this.helperProportions.width) this.position.left = this.maxLeft - this.helperProportions.width;
+ if(this.position.top < this.minTop) this.position.top = this.minTop;
+ if(this.position.top > this.maxTop - this.helperProportions.height) this.position.top = this.maxTop - this.helperProportions.height;
+ },
+ recallOffset: function(e) {
+
+ var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top };
+ var r = this.helper.css('position') == 'relative';
+
+ //Generate the original position
+ this.originalPosition = {
+ left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)),
+ top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop))
+ };
+
+ //Generate a flexible offset that will later be subtracted from e.pageX/Y
+ this.offset = {left: this._pageX - this.originalPosition.left, top: this._pageY - this.originalPosition.top };
+
+ },
+ start: function(e) {
+ var o = this.options;
+ if($.ui.ddmanager) $.ui.ddmanager.current = this;
+
+ //Create and append the visible helper
+ this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone().appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)) : this.element);
+ if(this.helper[0] != this.element[0]) this.helper.css('position', 'absolute');
+ if(!this.helper.parents('body').length) this.helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
+
+
+ //Find out the next positioned parent
+ this.offsetParent = (function(cp) {
+ while(cp) {
+ if(cp.style && (/(absolute|relative|fixed)/).test($.css(cp,'position'))) return $(cp);
+ cp = cp.parentNode ? cp.parentNode : null;
+ }; return $("body");
+ })(this.helper[0].parentNode);
+
+ //Prepare variables for position generation
+ this.elementOffset = this.element.offset();
+ this.offsetParentOffset = this.offsetParent.offset();
+ var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top };
+ this._pageX = e.pageX; this._pageY = e.pageY;
+ this.clickOffset = { left: e.pageX - this.elementOffset.left, top: e.pageY - this.elementOffset.top };
+ var r = this.helper.css('position') == 'relative';
+
+ //Generate the original position
+ this.originalPosition = {
+ left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)),
+ top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop))
+ };
+
+ //If we have a fixed element, we must subtract the scroll offset again
+ if(this.element.css('position') == 'fixed') {
+ this.originalPosition.top -= this.offsetParent[0] == document.body ? $(document).scrollTop() : this.offsetParent[0].scrollTop;
+ this.originalPosition.left -= this.offsetParent[0] == document.body ? $(document).scrollLeft() : this.offsetParent[0].scrollLeft;
+ }
+
+ //Generate a flexible offset that will later be subtracted from e.pageX/Y
+ this.offset = {left: e.pageX - this.originalPosition.left, top: e.pageY - this.originalPosition.top };
+
+ //Substract margins
+ if(this.element[0] != this.helper[0]) {
+ this.offset.left += parseInt(this.element.css('marginLeft'),10) || 0;
+ this.offset.top += parseInt(this.element.css('marginTop'),10) || 0;
+ }
+
+ //Call plugins and callbacks
+ this.propagate("start", e);
+
+ this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };
+ if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e);
+
+ //If we have something in cursorAt, we'll use it
+ if(o.cursorAt) {
+ if(o.cursorAt.top != undefined || o.cursorAt.bottom != undefined) {
+ this.offset.top -= this.clickOffset.top - (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom));
+ this.clickOffset.top = (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom));
+ }
+ if(o.cursorAt.left != undefined || o.cursorAt.right != undefined) {
+ this.offset.left -= this.clickOffset.left - (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right));
+ this.clickOffset.left = (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right));
+ }
+ }
+
+ return false;
+
+ },
+ clear: function() {
+ if($.ui.ddmanager) $.ui.ddmanager.current = null;
+ this.helper = null;
+ },
+ stop: function(e) {
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
+ $.ui.ddmanager.drop(this, e);
+
+ //Call plugins and trigger callbacks
+ this.propagate("stop", e);
+
+ if(this.cancelHelperRemoval) return false;
+ if(this.options.helper != 'original') this.helper.remove();
+ this.clear();
+
+ return false;
+ },
+ drag: function(e) {
+
+ //Compute the helpers position
+ this.position = { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left };
+ this.positionAbs = { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top };
+
+ //Call plugins and callbacks
+ this.checkConstrains();
+ this.position = this.propagate("drag", e) || this.position;
+ this.checkConstrains();
+
+ $(this.helper).css({ left: this.position.left+'px', top: this.position.top+'px' }); // Stick the helper to the cursor
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, e);
+ return false;
+
+ }
+ });
+
+/*
+ * Draggable Extensions
+ */
+
+ $.ui.plugin.add("draggable", "cursor", {
+ start: function(e, ui) {
+ var t = $('body');
+ if (t.css("cursor")) ui.options._cursor = t.css("cursor");
+ t.css("cursor", ui.options.cursor);
+ },
+ stop: function(e, ui) {
+ if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
+ }
+ });
+
+ $.ui.plugin.add("draggable", "zIndex", {
+ start: function(e, ui) {
+ var t = $(ui.helper);
+ if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
+ t.css('zIndex', ui.options.zIndex);
+ },
+ stop: function(e, ui) {
+ if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
+ }
+ });
+
+ $.ui.plugin.add("draggable", "opacity", {
+ start: function(e, ui) {
+ var t = $(ui.helper);
+ if(t.css("opacity")) ui.options._opacity = t.css("opacity");
+ t.css('opacity', ui.options.opacity);
+ },
+ stop: function(e, ui) {
+ if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
+ }
+ });
+
+
+ $.ui.plugin.add("draggable", "revert", {
+ stop: function(e, ui) {
+ var self = ui.instance, helper = $(self.helper);
+ self.cancelHelperRemoval = true;
+
+ $(ui.helper).animate({ left: self.originalPosition.left, top: self.originalPosition.top }, parseInt(ui.options.revert, 10) || 500, function() {
+ if(ui.options.helper != 'original') helper.remove();
+ if (!helper) self.clear();
+ });
+ }
+ });
+
+ $.ui.plugin.add("draggable", "iframeFix", {
+ start: function(e, ui) {
+
+ var o = ui.options;
+ if(ui.instance.slowMode) return; // Make clones on top of iframes (only if we are not in slowMode)
+
+ if(o.iframeFix.constructor == Array) {
+ for(var i=0;i<o.iframeFix.length;i++) {
+ var co = $(o.iframeFix[i]).offset({ border: false });
+ $('<div class="DragDropIframeFix"" style="background: #fff;"></div>').css("width", $(o.iframeFix[i])[0].offsetWidth+"px").css("height", $(o.iframeFix[i])[0].offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body");
+ }
+ } else {
+ $("iframe").each(function() {
+ var co = $(this).offset({ border: false });
+ $('<div class="DragDropIframeFix" style="background: #fff;"></div>').css("width", this.offsetWidth+"px").css("height", this.offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body");
+ });
+ }
+
+ },
+ stop: function(e, ui) {
+ if(ui.options.iframeFix) $("div.DragDropIframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
+ }
+ });
+
+ $.ui.plugin.add("draggable", "containment", {
+ start: function(e, ui) {
+
+ var o = ui.options;
+ var self = ui.instance;
+ if((o.containment.left != undefined || o.containment.constructor == Array) && !o._containment) return;
+ if(!o._containment) o._containment = o.containment;
+
+ if(o._containment == 'parent') o._containment = this[0].parentNode;
+ if(o._containment == 'document') {
+ o.containment = [
+ 0,
+ 0,
+ $(document).width(),
+ ($(document).height() || document.body.parentNode.scrollHeight)
+ ];
+ } else { //I'm a node, so compute top/left/right/bottom
+
+ var ce = $(o._containment)[0];
+ var co = $(o._containment).offset();
+
+ o.containment = [
+ co.left,
+ co.top,
+ co.left+(ce.offsetWidth || ce.scrollWidth),
+ co.top+(ce.offsetHeight || ce.scrollHeight)
+ ];
+ }
+
+ var c = o.containment;
+ ui.instance.setContrains(
+ c[0] - (self.offset.left - self.clickOffset.left), //min left
+ c[2] - (self.offset.left - self.clickOffset.left), //max left
+ c[1] - (self.offset.top - self.clickOffset.top), //min top
+ c[3] - (self.offset.top - self.clickOffset.top) //max top
+ );
+
+ }
+ });
+
+ $.ui.plugin.add("draggable", "grid", {
+ drag: function(e, ui) {
+ var o = ui.options;
+ var newLeft = ui.instance.originalPosition.left + Math.round((e.pageX - ui.instance._pageX) / o.grid[0]) * o.grid[0];
+ var newTop = ui.instance.originalPosition.top + Math.round((e.pageY - ui.instance._pageY) / o.grid[1]) * o.grid[1];
+
+ ui.instance.position.left = newLeft;
+ ui.instance.position.top = newTop;
+
+ }
+ });
+
+ $.ui.plugin.add("draggable", "axis", {
+ drag: function(e, ui) {
+ var o = ui.options;
+ if(o.constraint) o.axis = o.constraint; //Legacy check
+ switch (o.axis) {
+ case 'x' : ui.instance.position.top = ui.instance.originalPosition.top; break;
+ case 'y' : ui.instance.position.left = ui.instance.originalPosition.left; break;
+ }
+ }
+ });
+
+ $.ui.plugin.add("draggable", "scroll", {
+ start: function(e, ui) {
+ var o = ui.options;
+ o.scrollSensitivity = o.scrollSensitivity || 20;
+ o.scrollSpeed = o.scrollSpeed || 20;
+
+ ui.instance.overflowY = function(el) {
+ do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode);
+ return $(document);
+ }(this);
+ ui.instance.overflowX = function(el) {
+ do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode);
+ return $(document);
+ }(this);
+ },
+ drag: function(e, ui) {
+
+ var o = ui.options;
+ var i = ui.instance;
+
+ if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') {
+ if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)
+ i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed;
+ if((ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)
+ i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed;
+ } else {
+ //$(document.body).append('<p>'+(e.pageY - $(document).scrollTop())+'</p>');
+ if(e.pageY - $(document).scrollTop() < o.scrollSensitivity)
+ $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+ $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') {
+ if(i.overflowX[0].offsetWidth - (ui.position.left - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity)
+ i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed;
+ if((ui.position.top - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity)
+ i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed;
+ } else {
+ if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+ $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+ $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ ui.instance.recallOffset(e);
+
+ }
+ });
+
+ $.ui.plugin.add("draggable", "snap", {
+ start: function(e, ui) {
+
+ ui.instance.snapElements = [];
+ $(ui.options.snap === true ? '.ui-draggable' : ui.options.snap).each(function() {
+ var $t = $(this); var $o = $t.offset();
+ if(this != ui.instance.element[0]) ui.instance.snapElements.push({
+ item: this,
+ width: $t.outerWidth(),
+ height: $t.outerHeight(),
+ top: $o.top,
+ left: $o.left
+ });
+ });
+
+ },
+ drag: function(e, ui) {
+
+ var d = ui.options.snapTolerance || 20;
+ var x1 = ui.absolutePosition.left, x2 = x1 + ui.instance.helperProportions.width,
+ y1 = ui.absolutePosition.top, y2 = y1 + ui.instance.helperProportions.height;
+
+ for (var i = ui.instance.snapElements.length - 1; i >= 0; i--){
+
+ var l = ui.instance.snapElements[i].left, r = l + ui.instance.snapElements[i].width,
+ t = ui.instance.snapElements[i].top, b = t + ui.instance.snapElements[i].height;
+
+ //Yes, I know, this is insane ;)
+ if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) continue;
+
+ if(ui.options.snapMode != 'inner') {
+ var ts = Math.abs(t - y2) <= 20;
+ var bs = Math.abs(b - y1) <= 20;
+ var ls = Math.abs(l - x2) <= 20;
+ var rs = Math.abs(r - x1) <= 20;
+ if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height;
+ if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top;
+ if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width;
+ if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left;
+ }
+
+ if(ui.options.snapMode != 'outer') {
+ var ts = Math.abs(t - y1) <= 20;
+ var bs = Math.abs(b - y2) <= 20;
+ var ls = Math.abs(l - x1) <= 20;
+ var rs = Math.abs(r - x2) <= 20;
+ if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top;
+ if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height;
+ if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left;
+ if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width;
+ }
+
+ };
+ }
+ });
+
+ $.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(e,ui) {
+ ui.instance.sortable = $.data($(ui.options.connectToSortable)[0], 'sortable');
+ ui.instance.sortableOffset = ui.instance.sortable.element.offset();
+ ui.instance.sortableOuterWidth = ui.instance.sortable.element.outerWidth();
+ ui.instance.sortableOuterHeight = ui.instance.sortable.element.outerHeight();
+ if(ui.instance.sortable.options.revert) ui.instance.sortable.shouldRevert = true;
+ },
+ stop: function(e,ui) {
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = ui.instance.sortable;
+ if(inst.isOver) {
+ inst.isOver = 0;
+ ui.instance.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ inst.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+ if(inst.shouldRevert) inst.options.revert = true; //revert here
+ inst.stop(e);
+ inst.options.helper = "original";
+ }
+ },
+ drag: function(e,ui) {
+ //This is handy: We reuse the intersectsWith method for checking if the current draggable helper
+ //intersects with the sortable container
+ var inst = ui.instance.sortable;
+ ui.instance.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix
+
+ if(inst.intersectsWith.call(ui.instance, {
+ left: ui.instance.sortableOffset.left, top: ui.instance.sortableOffset.top,
+ width: ui.instance.sortableOuterWidth, height: ui.instance.sortableOuterHeight
+ })) {
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!inst.isOver) {
+ inst.isOver = 1;
+
+ //Cache the width/height of the new helper
+ var height = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerHeight() : $(inst.options.items, inst.element).innerHeight();
+ var width = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerWidth() : $(inst.options.items, inst.element).innerWidth();
+
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ inst.currentItem = $(this).clone().appendTo(inst.element);
+ inst.options.helper = function() { return ui.helper[0]; };
+ inst.start(e);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ inst.clickOffset.top = ui.instance.clickOffset.top;
+ inst.clickOffset.left = ui.instance.clickOffset.left;
+ inst.offset.left -= ui.absolutePosition.left - inst.position.absolute.left;
+ inst.offset.top -= ui.absolutePosition.top - inst.position.absolute.top;
+
+ //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now)
+ inst.helperProportions = { width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there
+ ui.helper.animate({ height: height, width: width}, 500);
+ ui.instance.propagate("toSortable", e);
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(inst.currentItem) inst.drag(e);
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(inst.isOver) {
+ inst.isOver = 0;
+ inst.cancelHelperRemoval = true;
+ inst.options.revert = false; //No revert here
+ inst.stop(e);
+ inst.options.helper = "original";
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ inst.currentItem.remove();
+ inst.placeholder.remove();
+
+ ui.helper.animate({ height: this.innerHeight(), width: this.innerWidth() }, 500);
+ ui.instance.propagate("fromSortable", e);
+ }
+
+ };
+ }
+ })
+
+ //TODO: wrapHelper
+
+})(jQuery);
+
diff --git a/moksha/widgetbrowser/widgetbrowser/static/ui.resizable.js b/moksha/widgetbrowser/widgetbrowser/static/ui.resizable.js
new file mode 100644
index 0000000..409195e
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/ui.resizable.js
@@ -0,0 +1,710 @@
+/*
+ * jQuery UI Resizable
+ *
+ * Copyright (c) 2008 Paul Bakaus
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ * ui.base.js
+ *
+ * Revision: $Id: ui.resizable.js 5205 2008-04-06 16:12:50Z braeker $
+ */
+;(function($) {
+
+ $.fn.extend({
+ resizable: function(options, data) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ if (typeof options == "string") {
+ var resize = $.data(this, "resizable");
+ if (resize) resize[options].apply(resize, args);
+
+ } else if(!$(this).is(".ui-resizable"))
+ new $.ui.resizable(this, options);
+ });
+ }
+ });
+
+ $.ui.resizable = function(element, options) {
+ //Initialize needed constants
+ var self = this;
+
+ this.element = $(element);
+
+ $.data(element, "resizable", this);
+
+ // simulate .ui-resizable { position: relative; }
+ var elpos = this.element.css('position');
+ this.element.addClass("ui-resizable").css({ position: /static/.test(elpos) ? 'relative' : elpos });
+
+ //Prepare the passed options
+ this.options = $.extend({
+ preventDefault: true,
+ transparent: false,
+ minWidth: 10,
+ minHeight: 10,
+ aspectRatio: false,
+ disableSelection: true,
+ preserveCursor: true,
+ autohide: false,
+ knobHandles: false
+ }, options);
+
+ this.options._aspectRatio = !!(this.options.aspectRatio);
+
+ // force proxy if helper is enabled
+ this.options.proxy = this.options.proxy || this.options.ghost ? 'proxy' : null;
+
+ // force proxy if animation is enabled
+ this.options.proxy = this.options.proxy || this.options.animate ? 'proxy' : null;
+
+ // if knobHandles equals true set to ui-resizable-knob-handle
+ this.options.knobHandles = this.options.knobHandles === true ? 'ui-resizable-knob-handle' : this.options.knobHandles;
+
+ $(element).bind("setData.resizable", function(event, key, value){
+ self.options[key] = value;
+ }).bind("getData.resizable", function(event, key){
+ return self.options[key];
+ });
+
+ var o = this.options;
+
+ //Default Theme
+ var aBorder = '1px solid #DEDEDE';
+
+ o.defaultTheme = {
+ 'ui-resizable': { display: 'block' },
+ 'ui-resizable-handle': { position: 'absolute', background: '#F2F2F2', fontSize: '0.1px' },
+ 'ui-resizable-n': { cursor: 'n-resize', height: '4px', left: '0px', right: '0px', borderTop: aBorder },
+ 'ui-resizable-s': { cursor: 's-resize', height: '4px', left: '0px', right: '0px', borderBottom: aBorder },
+ 'ui-resizable-e': { cursor: 'e-resize', width: '4px', top: '0px', bottom: '0px', borderRight: aBorder },
+ 'ui-resizable-w': { cursor: 'w-resize', width: '4px', top: '0px', bottom: '0px', borderLeft: aBorder },
+ 'ui-resizable-se': { cursor: 'se-resize', width: '4px', height: '4px', borderRight: aBorder, borderBottom: aBorder },
+ 'ui-resizable-sw': { cursor: 'sw-resize', width: '4px', height: '4px', borderBottom: aBorder, borderLeft: aBorder },
+ 'ui-resizable-ne': { cursor: 'ne-resize', width: '4px', height: '4px', borderRight: aBorder, borderTop: aBorder },
+ 'ui-resizable-nw': { cursor: 'nw-resize', width: '4px', height: '4px', borderLeft: aBorder, borderTop: aBorder }
+ };
+
+ o.knobTheme = {
+ 'ui-resizable-handle': { background: '#F2F2F2', border: '1px solid #808080', height: '8px', width: '8px' },
+ 'ui-resizable-n': { cursor: 'n-resize', top: '-4px', left: '45%' },
+ 'ui-resizable-s': { cursor: 's-resize', bottom: '-4px', left: '45%' },
+ 'ui-resizable-e': { cursor: 'e-resize', right: '-4px', top: '45%' },
+ 'ui-resizable-w': { cursor: 'w-resize', left: '-4px', top: '45%' },
+ 'ui-resizable-se': { cursor: 'se-resize', right: '-4px', bottom: '-4px' },
+ 'ui-resizable-sw': { cursor: 'sw-resize', left: '-4px', bottom: '-4px' },
+ 'ui-resizable-nw': { cursor: 'nw-resize', left: '-4px', top: '-4px' },
+ 'ui-resizable-ne': { cursor: 'ne-resize', right: '-4px', top: '-4px' }
+ };
+
+ //Position the node
+ if(!o.proxy && (this.element.css('position') == 'static' || this.element.css('position') === ''))
+ this.element.css('position', 'relative');
+
+ o._nodeName = element.nodeName;
+
+ //Wrap the element if it cannot hold child nodes
+ if(o._nodeName.match(/textarea|input|select|button|img/i)) {
+ var el = this.element;
+
+ //Opera fixing relative position
+ if (/relative/.test(el.css('position')) && $.browser.opera)
+ el.css({ position: 'relative', top: 'auto', left: 'auto' });
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ el.wrap(
+ $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css( {
+ position: el.css('position'),
+ width: el.outerWidth(),
+ height: el.outerHeight(),
+ top: el.css('top'),
+ left: el.css('left')
+ })
+ );
+
+ var oel = this.element; element = element.parentNode; this.element = $(element);
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: oel.css("marginLeft"), marginTop: oel.css("marginTop"),
+ marginRight: oel.css("marginRight"), marginBottom: oel.css("marginBottom")
+ });
+
+ oel.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ if ($.browser.safari && o.preventDefault) oel.css('resize', 'none');
+
+ o.proportionallyResize = oel.css({ position: 'static', zoom: 1, display: 'block' });
+
+ // avoid IE jump
+ this.element.css({ margin: oel.css('margin') });
+
+ // fix handlers offset
+ this._proportionallyResize();
+ }
+
+ if(!o.handles) o.handles = !$('.ui-resizable-handle', element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' };
+ if(o.handles.constructor == String) {
+
+ if(o.handles == 'all') o.handles = 'n,e,s,w,se,sw,ne,nw';
+
+ var n = o.handles.split(","); o.handles = {};
+
+ o.zIndex = o.zIndex || 1000;
+
+ // insertions are applied when don't have theme loaded
+ var insertionsDefault = {
+ handle: 'position: absolute; display: none; overflow:hidden;',
+ n: 'top: 0pt; width:100%;',
+ e: 'right: 0pt; height:100%;',
+ s: 'bottom: 0pt; width:100%;',
+ w: 'left: 0pt; height:100%;',
+ se: 'bottom: 0pt; right: 0px;',
+ sw: 'bottom: 0pt; left: 0px;',
+ ne: 'top: 0pt; right: 0px;',
+ nw: 'top: 0pt; left: 0px;'
+ };
+
+ for(var i = 0; i < n.length; i++) {
+ var handle = jQuery.trim(n[i]), dt = o.defaultTheme, hname = 'ui-resizable-'+handle, loadDefault = !$.ui.css(hname) && !o.knobHandles, userKnobClass = $.ui.css('ui-resizable-knob-handle'),
+ allDefTheme = $.extend(dt[hname], dt['ui-resizable-handle']), allKnobTheme = $.extend(o.knobTheme[hname], !userKnobClass ? o.knobTheme['ui-resizable-handle'] : {});
+
+ // increase zIndex of sw, se, ne, nw axis
+ var applyZIndex = /sw|se|ne|nw/.test(handle) ? { zIndex: ++o.zIndex } : {};
+
+ var defCss = (loadDefault ? insertionsDefault[handle] : ''),
+ axis = $(['<div class="ui-resizable-handle ', hname, '" style="', defCss, insertionsDefault.handle, '"></div>'].join('')).css( applyZIndex );
+ o.handles[handle] = '.ui-resizable-'+handle;
+
+ this.element.append(
+ //Theme detection, if not loaded, load o.defaultTheme
+ axis.css( loadDefault ? allDefTheme : {} )
+ // Load the knobHandle css, fix width, height, top, left...
+ .css( o.knobHandles ? allKnobTheme : {} ).addClass(o.knobHandles ? 'ui-resizable-knob-handle' : '').addClass(o.knobHandles)
+ );
+ }
+
+ if (o.knobHandles) this.element.addClass('ui-resizable-knob').css( !$.ui.css('ui-resizable-knob') ? { /*border: '1px #fff dashed'*/ } : {} );
+ }
+
+ this._renderAxis = function(target) {
+ target = target || this.element;
+
+ for(var i in o.handles) {
+ if(o.handles[i].constructor == String)
+ o.handles[i] = $(o.handles[i], element).show();
+
+ if (o.transparent)
+ o.handles[i].css({opacity:0});
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.element.is('.ui-wrapper') &&
+ o._nodeName.match(/textarea|input|select|button/i)) {
+
+ var axis = $(o.handles[i], element), padWrapper = 0;
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ var padPos = [ 'padding',
+ /ne|nw|n/.test(i) ? 'Top' :
+ /se|sw|s/.test(i) ? 'Bottom' :
+ /^e$/.test(i) ? 'Right' : 'Left' ].join("");
+
+ if (!o.transparent)
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+ }
+ if(!$(o.handles[i]).length) continue;
+ }
+ };
+
+ this._renderAxis(this.element);
+ o._handles = $('.ui-resizable-handle', self.element);
+
+ if (o.disableSelection)
+ o._handles.each(function(i, e) { $.ui.disableSelection(e); });
+
+ //Matching axis name
+ o._handles.mouseover(function() {
+ if (!o.resizing) {
+ if (this.className)
+ var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ //Axis, default = se
+ self.axis = o.axis = axis && axis[1] ? axis[1] : 'se';
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autohide) {
+ o._handles.hide();
+ $(self.element).addClass("ui-resizable-autohide").hover(function() {
+ $(this).removeClass("ui-resizable-autohide");
+ o._handles.show();
+ },
+ function(){
+ if (!o.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ o._handles.hide();
+ }
+ });
+ }
+
+ //Initialize mouse events for interaction
+ this.element.mouseInteraction({
+ executor: this,
+ delay: 0,
+ distance: 0,
+ dragPrevention: ['input','textarea','button','select','option'],
+ start: this.start,
+ stop: this.stop,
+ drag: this.drag,
+ condition: function(e) {
+ if(this.disabled) return false;
+ for(var i in this.options.handles) {
+ if($(this.options.handles[i])[0] == e.target) return true;
+ }
+ return false;
+ }
+ });
+ };
+
+ $.extend($.ui.resizable.prototype, {
+ plugins: {},
+ ui: function() {
+ return {
+ instance: this,
+ axis: this.options.axis,
+ options: this.options
+ };
+ },
+ _renderProxy: function() {
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(o.proxy) {
+ this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
+
+ // fix ie6 offset
+ var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
+ pxyoffset = ( ie6 ? 2 : -1 );
+
+ this.helper.addClass(o.proxy).css({
+ width: el.outerWidth() + pxyoffset,
+ height: el.outerHeight() + pxyoffset,
+ position: 'absolute',
+ left: this.elementOffset.left - ie6offset +'px',
+ top: this.elementOffset.top - ie6offset +'px',
+ zIndex: ++o.zIndex
+ });
+
+ this.helper.appendTo("body");
+
+ if (o.disableSelection)
+ $.ui.disableSelection(this.helper.get(0));
+
+ } else {
+ this.helper = el;
+ }
+ },
+ propagate: function(n,e) {
+ $.ui.plugin.call(this, n, [e, this.ui()]);
+ this.element.triggerHandler(n == "resize" ? n : ["resize", n].join(""), [e, this.ui()], this.options[n]);
+ },
+ destroy: function() {
+ var el = this.element, wrapped = el.children(".ui-resizable").get(0),
+
+ _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled")
+ .removeMouseInteraction().removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
+ };
+
+ _destroy(el);
+
+ if (el.is('.ui-wrapper') && wrapped) {
+ el.parent().append(
+ $(wrapped).css({
+ position: el.css('position'),
+ width: el.outerWidth(),
+ height: el.outerHeight(),
+ top: el.css('top'),
+ left: el.css('left')
+ })
+ ).end().remove();
+
+ _destroy(wrapped);
+ }
+ },
+ enable: function() {
+ this.element.removeClass("ui-resizable-disabled");
+ this.disabled = false;
+ },
+ disable: function() {
+ this.element.addClass("ui-resizable-disabled");
+ this.disabled = true;
+ },
+ start: function(e) {
+ var o = this.options, iniPos = this.element.position(), el = this.element,
+ num = function(v) { return parseInt(v, 10) || 0; }, ie6 = $.browser.msie && $.browser.version < 7;
+ o.resizing = true;
+ o.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
+
+ // bugfix #1749
+ if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
+
+ // sOffset decides if document scrollOffset will be added to the top/left of the resizable element
+ var sOffset = $.browser.msie && !o.containment && (/absolute/).test(el.css('position')) && !(/relative/).test(el.parent().css('position'));
+ var dscrollt = sOffset ? o.documentScroll.top : 0, dscrolll = sOffset ? o.documentScroll.left : 0;
+
+ el.css({ position: 'absolute', top: (iniPos.top + dscrollt), left: (iniPos.left + dscrolll) });
+ }
+
+ //Opera fixing relative position
+ if (/relative/.test(el.css('position')) && $.browser.opera)
+ el.css({ position: 'relative', top: 'auto', left: 'auto' });
+
+ this._renderProxy();
+
+ var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = o.proxy || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalSize = o.proxy || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: e.pageX, top: e.pageY };
+
+ //Aspect Ratio
+ o.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.height / this.originalSize.width)||1);
+
+ if (o.preserveCursor)
+ $('body').css('cursor', this.axis + '-resize');
+
+ this.propagate("start", e);
+ return false;
+ },
+ stop: function(e) {
+ this.options.resizing = false;
+ var o = this.options, num = function(v) { return parseInt(v, 10) || 0; }, self = this;
+
+ if(o.proxy) {
+ var pr = o.proportionallyResize, ista = pr && /textarea/i.test(pr.get(0).nodeName),
+ soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
+ left = parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left),
+ top = parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top);
+
+ if (!o.animate)
+ this.element.css($.extend(style, { top: top, left: left }));
+
+ if (o.proxy && !o.animate) this._proportionallyResize();
+ this.helper.remove();
+ }
+
+ if (o.preserveCursor)
+ $('body').css('cursor', 'auto');
+
+ this.propagate("stop", e);
+ return false;
+ },
+ drag: function(e) {
+ //Increase performance, avoid regex
+ var el = this.helper, o = this.options, props = {},
+ self = this, smp = this.originalMousePosition, a = this.axis;
+
+ var dx = (e.pageX-smp.left)||0, dy = (e.pageY-smp.top)||0;
+ var trigger = this.change[a];
+ if (!trigger) return false;
+
+ // Calculate the attrs that will be change
+ var data = trigger.apply(this, [e, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
+
+ if (o._aspectRatio || e.shiftKey)
+ data = this._updateRatio(data, e);
+
+ data = this._respectSize(data, e);
+
+ this.propagate("resize", e);
+
+ el.css({
+ top: this.position.top + "px", left: this.position.left + "px",
+ width: this.size.width + "px", height: this.size.height + "px"
+ });
+
+ if (!o.proxy && o.proportionallyResize)
+ this._proportionallyResize();
+
+ this._updateCache(data);
+
+ return false;
+ },
+
+ _updateCache: function(data) {
+ var o = this.options;
+ this.offset = this.helper.offset();
+ if (data.left) this.position.left = data.left;
+ if (data.top) this.position.top = data.top;
+ if (data.height) this.size.height = data.height;
+ if (data.width) this.size.width = data.width;
+ },
+
+ _updateRatio: function(data, e) {
+ var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
+
+ if (data.height) data.width = Math.round(csize.height / o.aspectRatio);
+ else if (data.width) data.height = Math.round(csize.width * o.aspectRatio);
+
+ if (a == 'sw') {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a == 'nw') {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function(data, e) {
+
+ var el = this.helper, o = this.options, pRatio = o._aspectRatio || e.shiftKey, a = this.axis,
+ ismaxw = data.width && o.maxWidth && o.maxWidth < data.width, ismaxh = data.height && o.maxHeight && o.maxHeight < data.height,
+ isminw = data.width && o.minWidth && o.minWidth > data.width, isminh = data.height && o.minHeight && o.minHeight > data.height;
+
+ if (isminw) data.width = o.minWidth;
+ if (isminh) data.height = o.minHeight;
+ if (ismaxw) data.width = o.maxWidth;
+ if (ismaxh) data.height = o.maxHeight;
+
+ var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
+ var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+
+ if (isminw && cw) data.left = dw - o.minWidth;
+ if (ismaxw && cw) data.left = dw - o.maxWidth;
+ if (isminh && ch) data.top = dh - o.minHeight;
+ if (ismaxh && ch) data.top = dh - o.maxHeight;
+
+ // fixing jump error on top/left - bug #2330
+ var isNotwh = !data.width && !data.height;
+ if (isNotwh && !data.left && data.top) data.top = null;
+ else if (isNotwh && !data.top && data.left) data.left = null;
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+ var o = this.options;
+ if (!o.proportionallyResize) return;
+ var prel = o.proportionallyResize, el = this.helper || this.element;
+
+ if (!o.borderDif) {
+ var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
+ p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
+
+ o.borderDif = $.map(b, function(v, i) {
+ var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
+ return border + padding;
+ });
+ }
+ prel.css({
+ height: (el.height() - o.borderDif[0] - o.borderDif[2]) + "px",
+ width: (el.width() - o.borderDif[1] - o.borderDif[3]) + "px"
+ });
+ },
+
+ change: {
+ e: function(e, dx, dy) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(e, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(e, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(e, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(e, dx, dy) {
+ return $.extend(this.change.s.apply(this, arguments), this.change.e.apply(this, [e, dx, dy]));
+ },
+ sw: function(e, dx, dy) {
+ return $.extend(this.change.s.apply(this, arguments), this.change.w.apply(this, [e, dx, dy]));
+ },
+ ne: function(e, dx, dy) {
+ return $.extend(this.change.n.apply(this, arguments), this.change.e.apply(this, [e, dx, dy]));
+ },
+ nw: function(e, dx, dy) {
+ return $.extend(this.change.n.apply(this, arguments), this.change.w.apply(this, [e, dx, dy]));
+ }
+ }
+ });
+
+/*
+ * Resizable Extensions
+ */
+
+ $.ui.plugin.add("resizable", "containment", {
+
+ start: function(e, ui) {
+ var o = ui.options, self = ui.instance, el = self.element;
+ var oc = o.containment, ce = (oc instanceof jQuery) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+ if (!ce) return;
+
+ if (/document/.test(oc) || oc == document) {
+ self.containerOffset = { left: 0, top: 0 };
+
+ self.parentData = {
+ element: $(document), left: 0, top: 0, width: $(document).width(),
+ height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else{
+ self.containerOffset = $(ce).offset(), self.containerSize = { height: $(ce).innerHeight(), width: $(ce).innerWidth() };
+
+ var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ self.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function(e, ui) {
+ var o = ui.options, self = ui.instance, ps = self.containerSize,
+ co = self.containerOffset, cs = self.size, cp = self.position,
+ pRatio = o._aspectRatio || e.shiftKey;
+
+ if (cp.left < (o.proxy ? co.left : 0)) {
+ self.size.width = self.size.width + (o.proxy ? (self.position.left - co.left) : self.position.left);
+ if (pRatio) self.size.height = self.size.width * o.aspectRatio;
+ self.position.left = o.proxy ? co.left : 0;
+ }
+
+ if (cp.top < (o.proxy ? co.top : 0)) {
+ self.size.height = self.size.height + (o.proxy ? (self.position.top - co.top) : self.position.top);
+ if (pRatio) self.size.width = self.size.height / o.aspectRatio;
+ self.position.top = o.proxy ? co.top : 0;
+ }
+
+ var woset = (o.proxy ? self.offset.left - co.left : self.position.left) + self.sizeDiff.width,
+ hoset = (o.proxy ? self.offset.top - co.top : self.position.top) + self.sizeDiff.height;
+
+ if (woset + self.size.width >= self.parentData.width) {
+ self.size.width = self.parentData.width - woset;
+ if (pRatio) self.size.height = self.size.width * o.aspectRatio;
+ }
+
+ if (hoset + self.size.height >= self.parentData.height) {
+ self.size.height = self.parentData.height - hoset;
+ if (pRatio) self.size.width = self.size.height / o.aspectRatio;
+ }
+ }
+ });
+
+ $.ui.plugin.add("resizable", "grid", {
+
+ resize: function(e, ui) {
+ var o = ui.options, self = ui.instance, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || e.shiftKey;
+ o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
+ var ox = Math.round((cs.width - os.width) / o.grid[0]) * o.grid[0], oy = Math.round((cs.height - os.height) / o.grid[1]) * o.grid[1];
+
+ if (/^(se|s|e)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ }
+ else if (/^(ne)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ }
+ else if (/^(sw)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.left = op.left - ox;
+ }
+ else {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ self.position.left = op.left - ox;
+ }
+ }
+
+ });
+
+ $.ui.plugin.add("resizable", "animate", {
+
+ stop: function(e, ui) {
+ var o = ui.options, self = ui.instance;
+
+ var pr = o.proportionallyResize, ista = pr && /textarea/i.test(pr.get(0).nodeName),
+ soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
+ left = parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left),
+ top = parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top);
+
+ self.element.animate(
+ $.extend(style, { top: top, left: left }),
+ {
+ duration: o.animateDuration || "slow",
+ easing: o.animateEasing || "swing",
+ step: function() {
+ if (pr) pr.css({ width: self.element.css('width'), height: self.element.css('height') });
+ }
+ }
+ );
+ }
+
+ });
+
+ $.ui.plugin.add("resizable", "ghost", {
+
+ start: function(e, ui) {
+ var o = ui.options, self = ui.instance, pr = o.proportionallyResize, cs = self.size;
+
+ if (!pr) self.ghost = self.element.clone();
+ else self.ghost = pr.clone();
+
+ self.ghost.css(
+ { opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }
+ )
+ .addClass('ui-resizable-ghost').addClass(typeof o.ghost == 'string' ? o.ghost : '');
+
+ self.ghost.appendTo(self.helper);
+
+ },
+
+ resize: function(e, ui){
+ var o = ui.options, self = ui.instance, pr = o.proportionallyResize;
+
+ if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
+
+ },
+
+ stop: function(e, ui){
+ var o = ui.options, self = ui.instance, pr = o.proportionallyResize;
+ if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
+ }
+
+ });
+
+})(jQuery);
diff --git a/moksha/widgetbrowser/widgetbrowser/static/ui.tabs.css b/moksha/widgetbrowser/widgetbrowser/static/ui.tabs.css
new file mode 100644
index 0000000..0eabf94
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/ui.tabs.css
@@ -0,0 +1,114 @@
+/* Caution! Ensure accessibility in print and other media types... */
+@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
+ .ui-tabs-hide {
+ display: none;
+ }
+}
+
+/* Hide useless elements in print layouts... */
+@media print {
+ .ui-tabs-nav {
+ display: none;
+ }
+}
+
+/* Skin */
+.ui-tabs-nav {
+ list-style: none;
+ margin: 0 !important;
+ padding: 0 0 0 4px;
+}
+.ui-tabs-nav li {
+ list-style-image: none !important;
+ margin: 0 !important;
+ padding: 0 0 0 4px;
+}
+
+.ui-tabs-panel {
+ border-top: #94ADA7 solid 1px;
+ padding-top: 5px;
+ clear: left;
+}
+
+/* IE6 hack */
+* html .ui-tabs-panel {
+ margin-top: -1.2em;
+}
+
+.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
+ display: block;
+ clear: both;
+ content: " ";
+}
+.ui-tabs-nav li {
+ float: left;
+ margin: 0 0 0 1px;
+ min-width: 84px; /* be nice to Opera */
+}
+.ui-tabs-nav a, .ui-tabs-nav a span {
+ display: block;
+ padding: 0 10px;
+ background: url(tab.png) no-repeat;
+}
+.ui-tabs-nav a {
+ position: relative;
+ top: 1px;
+ z-index: 2;
+ padding-left: 0;
+ color: #27537a;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 1.2;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap; /* required in IE 6 */
+}
+.ui-tabs-nav .ui-tabs-selected a {
+ color: #000;
+}
+.ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active {
+ background-position: 100% -150px;
+ outline: 0; /* prevent dotted border in Firefox */
+}
+.ui-tabs-nav a, .ui-tabs-nav .ui-tabs-disabled a:hover, .ui-tabs-nav .ui-tabs-disabled a:focus, .ui-tabs-nav .ui-tabs-disabled a:active {
+ background-position: 100% -100px;
+}
+.ui-tabs-nav a span {
+ width: 64px; /* IE 6 treats width as min-width */
+ min-width: 64px;
+ height: 18px; /* IE 6 treats height as min-height */
+ min-height: 18px;
+ padding-top: 6px;
+ padding-right: 0;
+}
+*>.ui-tabs-nav a span { /* hide from IE 6 */
+ width: auto;
+ height: auto;
+}
+.ui-tabs-nav .ui-tabs-selected a span {
+ padding-top: 7px;
+}
+.ui-tabs-nav .ui-tabs-selected a span, .ui-tabs-nav a:hover span, .ui-tabs-nav a:focus span, .ui-tabs-nav a:active span {
+ background-position: 0 -50px;
+}
+.ui-tabs-nav a span, .ui-tabs-nav .ui-tabs-disabled a:hover span, .ui-tabs-nav .ui-tabs-disabled a:focus span, .ui-tabs-nav .ui-tabs-disabled a:active span {
+ background-position: 0 0;
+}
+.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited, .ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
+ cursor: text;
+}
+.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active { /* @ Opera, we need to be explicit again here now... */
+ cursor: pointer;
+}
+.ui-tabs-nav .ui-tabs-disabled {
+ opacity: .4;
+}
+.ui-tabs-container {
+ border-top: 1px solid #97a5b0;
+ padding: 1em 8px;
+ background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
+}
+.ui-tabs-loading em {
+ padding: 0 0 0 20px;
+ background: url(loading.gif) no-repeat 0 50%;
+}
diff --git a/moksha/widgetbrowser/widgetbrowser/static/ui.tabs.js b/moksha/widgetbrowser/widgetbrowser/static/ui.tabs.js
new file mode 100644
index 0000000..f595c10
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/ui.tabs.js
@@ -0,0 +1,616 @@
+/*
+ * jQuery UI Tabs
+ *
+ * Copyright (c) 2007 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ * ui.base.js
+ *
+ * Revision: $Id: ui.tabs.js 5149 2008-03-31 10:51:18Z rdworth $
+ */
+;(function($) {
+
+ // tabs API methods
+ $.fn.tabs = function() {
+ var method = typeof arguments[0] == 'string' && arguments[0];
+ var args = method && Array.prototype.slice.call(arguments, 1) || arguments;
+
+ return method == 'length' ?
+ $.data(this[0], 'tabs').$tabs.length :
+ this.each(function() {
+ if (method) {
+ var tabs = $.data(this, 'tabs');
+ if (tabs) tabs[method].apply(tabs, args);
+ } else
+ new $.ui.tabs(this, args[0] || {});
+ });
+ };
+
+ // tabs class
+ $.ui.tabs = function(el, options) {
+ var self = this;
+
+ this.options = $.extend({}, $.ui.tabs.defaults, options);
+ this.element = el;
+
+ // doesn't extend with null
+ if (options.selected === null)
+ this.options.selected = null;
+
+ this.options.event += '.tabs'; // namespace event
+
+ $(el).bind('setData.tabs', function(event, key, value) {
+ if ((/^selected/).test(key))
+ self.select(value);
+ else {
+ self.options[key] = value;
+ self.tabify();
+ }
+ }).bind('getData.tabs', function(event, key) {
+ return self.options[key];
+ });
+
+ // save instance for later
+ $.data(el, 'tabs', this);
+
+ // create tabs
+ this.tabify(true);
+ };
+
+ $.ui.tabs.defaults = {
+ // basic setup
+ selected: 0,
+ unselect: false,
+ event: 'click',
+ disabled: [],
+ cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
+ // TODO history: false,
+
+ // Ajax
+ spinner: 'Loading…',
+ cache: false,
+ idPrefix: 'ui-tabs-',
+ ajaxOptions: {},
+
+ // animations
+ fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
+
+ // templates
+ tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
+ panelTemplate: '<div></div>',
+
+ // CSS classes
+ navClass: 'ui-tabs-nav',
+ selectedClass: 'ui-tabs-selected',
+ unselectClass: 'ui-tabs-unselect',
+ disabledClass: 'ui-tabs-disabled',
+ panelClass: 'ui-tabs-panel',
+ hideClass: 'ui-tabs-hide',
+ loadingClass: 'ui-tabs-loading'
+ };
+
+ // instance methods
+ $.extend($.ui.tabs.prototype, {
+ tabId: function(a) {
+ return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
+ || this.options.idPrefix + $.data(a);
+ },
+ ui: function(tab, panel) {
+ return {
+ instance: this,
+ options: this.options,
+ tab: tab,
+ panel: panel
+ };
+ },
+ tabify: function(init) {
+
+ this.$lis = $('li:has(a[href])', this.element);
+ this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
+ this.$panels = $([]);
+
+ var self = this, o = this.options;
+
+ this.$tabs.each(function(i, a) {
+ // inline tab
+ if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
+ self.$panels = self.$panels.add(a.hash);
+ // remote tab
+ else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
+ $.data(a, 'href.tabs', a.href); // required for restore on destroy
+
+ var _cls = a.getAttribute('class');
+ var use_iframe = _cls && (_cls.indexOf('use_iframe') > -1)? true: false;
+ if (!use_iframe) {
+ $.data(a, 'load.tabs', a.href); // mutable
+ } else {
+ $.data(a, 'load.iframe_src', a.href); // mutable
+ }
+
+
+ var id = self.tabId(a);
+ a.href = '#' + id;
+ var $panel = $('#' + id);
+ var panelTemplate = use_iframe? '<div><iframe></iframe></div>': o.panelTemplate;
+ if (!$panel.length) {
+ $panel = $(panelTemplate).attr('id', id).addClass(o.panelClass)
+ .insertAfter( self.$panels[i - 1] || self.element );
+ $panel.data('destroy.tabs', true);
+ }
+ self.$panels = self.$panels.add( $panel );
+ }
+ // invalid tab href
+ else
+ o.disabled.push(i + 1);
+ });
+
+ if (init) {
+
+ // attach necessary classes for styling if not present
+ $(this.element).hasClass(o.navClass) || $(this.element).addClass(o.navClass);
+ this.$panels.each(function() {
+ var $this = $(this);
+ $this.hasClass(o.panelClass) || $this.addClass(o.panelClass);
+ });
+
+ // Try to retrieve selected tab:
+ // 1. from fragment identifier in url if present
+ // 2. from cookie
+ // 3. from selected class attribute on <li>
+ // 4. otherwise use given "selected" option
+ // 5. check if tab is disabled
+ this.$tabs.each(function(i, a) {
+ if (location.hash) {
+ if (a.hash == location.hash) {
+ o.selected = i;
+ // prevent page scroll to fragment
+ //if (($.browser.msie || $.browser.opera) && !o.remote) {
+ if ($.browser.msie || $.browser.opera) {
+ var $toShow = $(location.hash), toShowId = $toShow.attr('id');
+ $toShow.attr('id', '');
+ setTimeout(function() {
+ $toShow.attr('id', toShowId); // restore id
+ }, 500);
+ }
+ scrollTo(0, 0);
+ return false; // break
+ }
+ } else if (o.cookie) {
+ var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10);
+ if (index && self.$tabs[index]) {
+ o.selected = index;
+ return false; // break
+ }
+ } else if ( self.$lis.eq(i).hasClass(o.selectedClass) ) {
+ o.selected = i;
+ return false; // break
+ }
+ });
+
+ // highlight selected tab
+ this.$panels.addClass(o.hideClass);
+ this.$lis.removeClass(o.selectedClass);
+ if (o.selected !== null) {
+ this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
+ this.$lis.eq(o.selected).addClass(o.selectedClass);
+ }
+
+ // load if remote tab
+ var href = o.selected !== null && $.data(this.$tabs[o.selected], 'load.tabs');
+ if (href)
+ this.load(o.selected);
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly...
+ o.disabled = $.unique(o.disabled.concat(
+ $.map(this.$lis.filter('.' + o.disabledClass),
+ function(n, i) { return self.$lis.index(n); } )
+ )).sort();
+
+ // clean up to avoid memory leaks in certain versions of IE 6
+ $(window).bind('unload', function() {
+ self.$tabs.unbind('.tabs');
+ self.$lis = self.$tabs = self.$panels = null;
+ });
+
+ }
+
+ // disable tabs
+ for (var i = 0, li; li = this.$lis[i]; i++)
+ $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
+
+ // reset cache if switching from cached to not cached
+ if (o.cache === false)
+ this.$tabs.removeData('cache.tabs');
+
+ // set up animations
+ var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
+ if (o.fx && o.fx.constructor == Array)
+ hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
+ else
+ hideFx = showFx = o.fx || baseFx;
+
+ // reset some styles to maintain print style sheets etc.
+ var resetCSS = { display: '', overflow: '', height: '' };
+ if (!$.browser.msie) // not in IE to prevent ClearType font issue
+ resetCSS.opacity = '';
+
+ // Hide a tab, animation prevents browser scrolling to fragment,
+ // $show is optional.
+ function hideTab(clicked, $hide, $show) {
+ $hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
+ $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
+ if ($.browser.msie && hideFx.opacity)
+ $hide[0].style.filter = '';
+ if ($show)
+ showTab(clicked, $show, $hide);
+ });
+ }
+
+ // Show a tab, animation prevents browser scrolling to fragment,
+ // $hide is optional.
+ function showTab(clicked, $show, $hide) {
+ if (showFx === baseFx)
+ $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
+ $show.animate(showFx, showFx.duration || baseDuration, function() {
+ $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
+ if ($.browser.msie && showFx.opacity)
+ $show[0].style.filter = '';
+
+ // callback
+ $(self.element).triggerHandler('tabsshow', [self.ui(clicked, $show[0])], o.show);
+
+ });
+ }
+
+ // switch a tab
+ function switchTab(clicked, $li, $hide, $show) {
+ /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
+ $.ajaxHistory.update(clicked.hash);
+ }*/
+ $li.addClass(o.selectedClass)
+ .siblings().removeClass(o.selectedClass);
+ hideTab(clicked, $hide, $show);
+ }
+
+ // attach tab event handler, unbind to avoid duplicates from former tabifying...
+ this.$tabs.unbind('.tabs').bind(o.event, function() {
+
+ //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
+ var $li = $(this).parents('li:eq(0)'),
+ $hide = self.$panels.filter(':visible'),
+ $show = $(this.hash);
+
+ // If tab is already selected and not unselectable or tab disabled or
+ // or is already loading or click callback returns false stop here.
+ // Check if click handler returns false last so that it is not executed
+ // for a disabled or loading tab!
+ if (($li.hasClass(o.selectedClass) && !o.unselect)
+ || $li.hasClass(o.disabledClass)
+ || $(this).hasClass(o.loadingClass)
+ || $(self.element).triggerHandler('tabsselect', [self.ui(this, $show[0])], o.select) === false
+ ) {
+ this.blur();
+ return false;
+ }
+
+ self.options.selected = self.$tabs.index(this);
+
+ // if tab may be closed
+ if (o.unselect) {
+ if ($li.hasClass(o.selectedClass)) {
+ self.options.selected = null;
+ $li.removeClass(o.selectedClass);
+ self.$panels.stop();
+ hideTab(this, $hide);
+ this.blur();
+ return false;
+ } else if (!$hide.length) {
+ self.$panels.stop();
+ var a = this;
+ self.load(self.$tabs.index(this), function() {
+ $li.addClass(o.selectedClass).addClass(o.unselectClass);
+ showTab(a, $show);
+ });
+ this.blur();
+ return false;
+ }
+ }
+
+ if (o.cookie)
+ $.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie);
+
+ // stop possibly running animations
+ self.$panels.stop();
+
+ // show new tab
+ if ($show.length) {
+
+ // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
+ /*if ($.browser.msie && o.bookmarkable) {
+ var showId = this.hash.replace('#', '');
+ $show.attr('id', '');
+ setTimeout(function() {
+ $show.attr('id', showId); // restore id
+ }, 0);
+ }*/
+
+ var a = this;
+ self.load(self.$tabs.index(this), $hide.length ?
+ function() {
+ switchTab(a, $li, $hide, $show);
+ } :
+ function() {
+ $li.addClass(o.selectedClass);
+ showTab(a, $show);
+ }
+ );
+
+ // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
+ /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
+ var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
+ setTimeout(function() {
+ scrollTo(scrollX, scrollY);
+ }, 0);*/
+
+ } else
+ throw 'jQuery UI Tabs: Mismatching fragment identifier.';
+
+ // Prevent IE from keeping other link focussed when using the back button
+ // and remove dotted border from clicked link. This is controlled in modern
+ // browsers via CSS, also blur removes focus from address bar in Firefox
+ // which can become a usability and annoying problem with tabsRotate.
+ if ($.browser.msie)
+ this.blur();
+
+ //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
+ return false;
+
+ });
+
+ // disable click if event is configured to something else
+ if (!(/^click/).test(o.event))
+ this.$tabs.bind('click.tabs', function() { return false; });
+
+ },
+ add: function(url, label, index) {
+ if (index == undefined)
+ index = this.$tabs.length; // append by default
+
+ var o = this.options;
+ var $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{label\}/, label));
+ $li.data('destroy.tabs', true);
+
+ var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );
+
+ // try to find an existing element before creating a new one
+ var $panel = $('#' + id);
+ if (!$panel.length) {
+ $panel = $(o.panelTemplate).attr('id', id)
+ .addClass(o.panelClass).addClass(o.hideClass);
+ $panel.data('destroy.tabs', true);
+ }
+ if (index >= this.$lis.length) {
+ $li.appendTo(this.element);
+ $panel.appendTo(this.element.parentNode);
+ } else {
+ $li.insertBefore(this.$lis[index]);
+ $panel.insertBefore(this.$panels[index]);
+ }
+
+ o.disabled = $.map(o.disabled,
+ function(n, i) { return n >= index ? ++n : n });
+
+ this.tabify();
+
+ if (this.$tabs.length == 1) {
+ $li.addClass(o.selectedClass);
+ $panel.removeClass(o.hideClass);
+ var href = $.data(this.$tabs[0], 'load.tabs');
+ if (href)
+ this.load(index, href);
+ }
+
+ // callback
+ $(this.element).triggerHandler('tabsadd',
+ [this.ui(this.$tabs[index], this.$panels[index])], o.add
+ );
+ },
+ remove: function(index) {
+ var o = this.options, $li = this.$lis.eq(index).remove(),
+ $panel = this.$panels.eq(index).remove();
+
+ // If selected tab was removed focus tab to the right or
+ // in case the last tab was removed the tab to the left.
+ if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
+ this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
+
+ o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
+ function(n, i) { return n >= index ? --n : n });
+
+ this.tabify();
+
+ // callback
+ $(this.element).triggerHandler('tabsremove',
+ [this.ui($li.find('a')[0], $panel[0])], o.remove
+ );
+ },
+ enable: function(index) {
+ var o = this.options;
+ if ($.inArray(index, o.disabled) == -1)
+ return;
+
+ var $li = this.$lis.eq(index).removeClass(o.disabledClass);
+ if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
+ $li.css('display', 'inline-block');
+ setTimeout(function() {
+ $li.css('display', 'block');
+ }, 0);
+ }
+
+ o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
+
+ // callback
+ $(this.element).triggerHandler('tabsenable',
+ [this.ui(this.$tabs[index], this.$panels[index])], o.enable
+ );
+
+ },
+ disable: function(index) {
+ var self = this, o = this.options;
+ if (index != o.selected) { // cannot disable already selected tab
+ this.$lis.eq(index).addClass(o.disabledClass);
+
+ o.disabled.push(index);
+ o.disabled.sort();
+
+ // callback
+ $(this.element).triggerHandler('tabsdisable',
+ [this.ui(this.$tabs[index], this.$panels[index])], o.disable
+ );
+ }
+ },
+ select: function(index) {
+ if (typeof index == 'string')
+ index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
+ this.$tabs.eq(index).trigger(this.options.event);
+ },
+ load: function(index, callback) { // callback is for internal usage only
+
+ var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
+ bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
+
+ callback = callback || function() {};
+
+ // no remote or from cache - just finish with callback
+ if (!url || ($.data(a, 'cache.tabs') && !bypassCache)) {
+ callback();
+ return;
+ }
+
+ // load remote from here on
+ if (o.spinner) {
+ var $span = $('span', a);
+ $span.data('label.tabs', $span.html()).html('<em>' + o.spinner + '</em>');
+ }
+ var finish = function() {
+ self.$tabs.filter('.' + o.loadingClass).each(function() {
+ $(this).removeClass(o.loadingClass);
+ if (o.spinner) {
+ var $span = $('span', this);
+ $span.html($span.data('label.tabs')).removeData('label.tabs');
+ }
+ });
+ self.xhr = null;
+ };
+ var ajaxOptions = $.extend({}, o.ajaxOptions, {
+ url: url,
+ success: function(r, s) {
+ $(a.hash).html(r);
+ finish();
+
+ // This callback is required because the switch has to take
+ // place after loading has completed.
+ callback();
+
+ if (o.cache)
+ $.data(a, 'cache.tabs', true); // if loaded once do not load them again
+
+ // callback
+ $(self.element).triggerHandler('tabsload',
+ [self.ui(self.$tabs[index], self.$panels[index])], o.load
+ );
+
+ o.ajaxOptions.success && o.ajaxOptions.success(r, s);
+ }
+ });
+ if (this.xhr) {
+ // terminate pending requests from other tabs and restore tab label
+ this.xhr.abort();
+ finish();
+ }
+ $a.addClass(o.loadingClass);
+ setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
+ self.xhr = $.ajax(ajaxOptions);
+ }, 0);
+
+ },
+ url: function(index, url) {
+ this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
+ },
+ destroy: function() {
+ var o = this.options;
+ $(this.element).unbind('.tabs')
+ .removeClass(o.navClass).removeData('tabs');
+ this.$tabs.each(function() {
+ var href = $.data(this, 'href.tabs');
+ if (href)
+ this.href = href;
+ var $this = $(this).unbind('.tabs');
+ $.each(['href', 'load', 'cache'], function(i, prefix) {
+ $this.removeData(prefix + '.tabs');
+ });
+ });
+ this.$lis.add(this.$panels).each(function() {
+ if ($.data(this, 'destroy.tabs'))
+ $(this).remove();
+ else
+ $(this).removeClass([o.selectedClass, o.unselectClass,
+ o.disabledClass, o.panelClass, o.hideClass].join(' '));
+ });
+ }
+ });
+
+/*
+ * Tabs Extensions
+ */
+
+ /*
+ * Rotate
+ */
+ $.extend($.ui.tabs.prototype, {
+ rotation: null,
+ rotate: function(ms, continuing) {
+
+ continuing = continuing || false;
+
+ var self = this, t = this.options.selected;
+
+ function start() {
+ self.rotation = setInterval(function() {
+ t = ++t < self.$tabs.length ? t : 0;
+ self.select(t);
+ }, ms);
+ }
+
+ function stop(e) {
+ if (!e || e.clientX) { // only in case of a true click
+ clearInterval(self.rotation);
+ }
+ }
+
+ // start interval
+ if (ms) {
+ start();
+ if (!continuing)
+ this.$tabs.bind(this.options.event, stop);
+ else
+ this.$tabs.bind(this.options.event, function() {
+ stop();
+ t = self.options.selected;
+ start();
+ });
+ }
+ // stop interval
+ else {
+ stop();
+ this.$tabs.unbind(this.options.event, stop);
+ }
+ }
+ });
+
+})(jQuery);
diff --git a/moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.css b/moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.css
new file mode 100644
index 0000000..21a046d
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.css
@@ -0,0 +1,9 @@
+.widgetbrowser iframe {
+ width: 100%;
+ border: 0;
+}
+div.small iframe { height: 50px; }
+div.medium iframe { height: 150px; }
+div.large iframe { height: 300px; }
+div.x-large iframe { height: 500px; }
+
diff --git a/moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.js b/moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.js
new file mode 100644
index 0000000..c0b78e6
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/static/widgetbrowser.js
@@ -0,0 +1,13 @@
+jQuery(function() {
+ jQuery('.widgetbrowser > ul').tabs({
+ selected: null,
+ unselect: true,
+ select: function (ui) {
+ var url = jQuery.data(ui.tab, 'load.iframe_src');
+ var iframe = jQuery('iframe', ui.panel);
+ if (url && !iframe.attr('src')) {
+ iframe.attr('src', url);
+ }
+ }
+ })
+});
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/__init__.py b/moksha/widgetbrowser/widgetbrowser/templates/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/home.html b/moksha/widgetbrowser/widgetbrowser/templates/home.html
new file mode 100644
index 0000000..012ce08
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/home.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<?python
+from widgetbrowser import widgets
+?>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <style>
+ .ui-tabs-panel {
+ border-bottom: solid 1px #94ada7;
+ padding-left: 1.5em;
+ }
+ .ui-tabs-panel iframe {
+ width: 100%;
+ border: 0;
+ min-height: 500px;
+ }
+ #home {
+ min-height: 450px;
+ }
+ </style>
+ </head>
+ <body class="flora">
+ <div id="main">
+ <ul>
+ <li><a href="#home"><span>Home</span></a></li>
+ <li><a href="#terminal" class="use_iframe"><span>Terminal</span></a></li>
+ <li><a href="${url('/widgets/')}" class="use_iframe"><span>Widgets</span></a></li>
+ </ul>
+ <div id="home">
+ <h1>Welcome to Toscawidgets' Browser</h1>
+ <p>
+ </p>
+ </div>
+ <div id="terminal">
+ ${widgets.repl(prefix=url('_repl/'))}
+ </div>
+ </div>
+ <div id="footer">
+ <p>© 2008. Alberto Valverde González</p>
+ </div>
+ <script type="text/javascript">
+ //<![CDATA[
+ jQuery(function () {
+ jQuery('#main > ul').tabs({
+ select: function (ui) {
+ var url = jQuery.data(ui.tab, 'load.iframe_src');
+ var iframe = jQuery('iframe', ui.panel);
+ if (url && !iframe.attr('src')) {
+ iframe.attr('src', url);
+ }
+ }
+ });
+ });
+ //]]>
+ </script>
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/list_widgets.html b/moksha/widgetbrowser/widgetbrowser/templates/list_widgets.html
new file mode 100644
index 0000000..2ef5dfe
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/list_widgets.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: Installed widgets</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widgets">
+ <ul>
+ <li py:for="path, url in widgets">
+ <a href="$url">$path</a>
+ </li>
+ </ul>
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/show_widget.html b/moksha/widgetbrowser/widgetbrowser/templates/show_widget.html
new file mode 100644
index 0000000..b75e063
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/show_widget.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: ${widget_name}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widget_browser">
+ <form py:if="interactive" method="GET">
+ <label for="display_args">Display arguments:</label>
+ <input id="display_args" name="_disp" type="text" size="50" value="${_disp}" />
+ <input type="submit" value="Display" />
+ </form>
+ <div py:replace="widget_output" />
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/validation_result.html b/moksha/widgetbrowser/widgetbrowser/templates/validation_result.html
new file mode 100644
index 0000000..e43da7b
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/validation_result.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: ${widget_name}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widget_browser">
+ <h1 class="title">Validated data:</h1>
+ ${Markup(value)}
+ <a href="">Back</a>
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/widget_browser_tabs.html b/moksha/widgetbrowser/widgetbrowser/templates/widget_browser_tabs.html
new file mode 100644
index 0000000..7edb374
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/widget_browser_tabs.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<div xmlns:py="http://genshi.edgewall.org/"
+ class="widgetbrowser ${size}">
+ <ul>
+ <li py:for="text, url in tabs">
+ <a href="${url}" class="${text == 'Demo' and 'use_iframe' or None}">
+ <span>${text}</span>
+ </a>
+ </li>
+ </ul>
+</div>
+
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/widget_index.html b/moksha/widgetbrowser/widgetbrowser/templates/widget_index.html
new file mode 100644
index 0000000..4759c25
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/widget_index.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <?python
+ from widgetbrowser.widgets import WidgetBrowserTabs
+ from widgetbrowser.util import widget_path
+ browser = WidgetBrowserTabs(size='x-large')
+ ?>
+ <head>
+ <title>WidgetBrowser: ${widget_path(widget)}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body>
+ <h1>${widget_path(widget)}</h1>
+ <p><a href="javascript:history.back()">Back</a></p>
+ ${browser(widget)}
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/widgetbrowser/templates/widget_parameters.html b/moksha/widgetbrowser/widgetbrowser/templates/widget_parameters.html
new file mode 100644
index 0000000..c95c195
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/templates/widget_parameters.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<div xmlns:py="http://genshi.edgewall.org/" class="widget_params">
+ <div py:if="parameters.local" class="widget_params local_params">
+ <h3>This widget's</h3>
+ <dl>
+ <py:for each="k in sorted(parameters.local)">
+ <dt>${k} <span class="default_param">(default = ${parameters.get_default(k)})</span></dt>
+ <dd py:content="parameters.get_doc(k, 'Undocumented')" />
+ </py:for>
+ </dl>
+ </div>
+ <div py:if="parameters.inherited" class="widget_param inherited_params">
+ <h3>Inherited</h3>
+ <dl>
+ <py:for each="k in sorted(parameters.inherited)">
+ <dt>${k} <span class="default_param">(default = ${parameters.get_default(k)})</span></dt>
+ <dd py:content="parameters.get_doc(k, 'Undocumented')" />
+ </py:for>
+ </dl>
+ </div>
+</div>
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/__init__.py b/moksha/widgetbrowser/widgetbrowser/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.html b/moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.html
new file mode 100644
index 0000000..7c9c42c
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.html
@@ -0,0 +1 @@
+Dummy template $value
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.mak b/moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.mak
new file mode 100644
index 0000000..1774ce6
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/dummy_m_template.mak
@@ -0,0 +1 @@
+Dummy template $value mako version
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/dummy_template.html b/moksha/widgetbrowser/widgetbrowser/tests/dummy_template.html
new file mode 100644
index 0000000..7c9c42c
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/dummy_template.html
@@ -0,0 +1 @@
+Dummy template $value
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/test_app.txt b/moksha/widgetbrowser/widgetbrowser/tests/test_app.txt
new file mode 100644
index 0000000..bacbc39
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/test_app.txt
@@ -0,0 +1,50 @@
+>>> from widgetbrowser import WidgetBrowser
+>>> from webtest import TestApp
+
+>>> app = TestApp(WidgetBrowser())
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo')
+>>> assert 'default' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/')
+>>> assert 'Demo' in r
+
+>>> r = app.get('/os.open/demo', status=404)
+
+Test that code isn't executed if not allowed
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo?_disp="foo"')
+>>> assert 'default' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/template')
+>>> assert '$value' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/source')
+>>> assert 'class' in r
+>>> assert 'TestWidget' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/parameters')
+>>> assert 'Inherited' in r
+
+Test posting:
+
+>>> r = app.post('/widgetbrowser.tests.widgets.TestWidget/demo', {'some_key':'foo'})
+>>> assert 'some_key' in r
+
+# the following is just to test the failed validation code-path
+>>> r = app.post('/widgetbrowser.tests.widgets.TestWidget/demo', {'break':'y'})
+>>> assert 'some_key' not in r
+
+Test unimplemented methods:
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/foobarize', status=501)
+
+Test custom controller
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/test')
+>>> assert 'Testing TestWidget' in r
+
+Now with code execution
+
+>>> app = TestApp(WidgetBrowser(interactive=True))
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo?_disp="foo"')
+>>> assert 'foo' in r
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/test_sphinx_ext.py b/moksha/widgetbrowser/widgetbrowser/tests/test_sphinx_ext.py
new file mode 100644
index 0000000..fc2d10a
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/test_sphinx_ext.py
@@ -0,0 +1,26 @@
+import os
+import shutil
+from unittest import TestCase
+from pkg_resources import resource_filename
+import sphinx
+
+doc_dir = resource_filename('widgetbrowser.tests', 'testdocs')
+
+class TestSphinxExt(TestCase):
+ def setUp(self):
+ self.dest_dir = os.tempnam()
+ if not os.path.isdir(self.dest_dir):
+ os.makedirs(self.dest_dir)
+
+ def tearDown(self):
+ try:
+ shutil.rmtree(self.dest_dir)
+ except OSError:
+ pass
+
+ def test_generate(self):
+ out = sphinx.main(['sphinx-build', doc_dir, self.dest_dir])
+ self.failUnless(not out, out)
+ html = open(os.path.join(self.dest_dir, 'index.html')).read()
+ self.failUnless('widgetbrowser' in html)
+ self.failUnless('x-large' in html)
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/testdocs/conf.py b/moksha/widgetbrowser/widgetbrowser/tests/testdocs/conf.py
new file mode 100644
index 0000000..4bd428a
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/testdocs/conf.py
@@ -0,0 +1,149 @@
+# -*- coding: utf-8 -*-
+#
+# TestDocs documentation build configuration file, created by
+# sphinx-quickstart on Fri May 9 09:56:10 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['widgetbrowser.sphinx_ext']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = []
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = 'TestDocs'
+copyright = '2008, Alberto'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# The name of an image file (within the static path) to place at the top of
+# the sidebar.
+#html_logo = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.
+#html_use_opensearch = False
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'TestDocsdoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'TestDocs.tex', 'TestDocs Documentation', 'Alberto', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/testdocs/index.rst b/moksha/widgetbrowser/widgetbrowser/tests/testdocs/index.rst
new file mode 100644
index 0000000..6f70ced
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/testdocs/index.rst
@@ -0,0 +1,12 @@
+.. TestDocs documentation master file, created by sphinx-quickstart on Fri May 9 09:56:10 2008.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Testing the `widgetbroser` directive
+====================================
+
+Test an existing widget
+-----------------------
+.. widgetbrowser:: widgetbrowser.tests.widgets.TestWidget
+ :tabs: source, demo, parameters, template
+ :size: x-large
diff --git a/moksha/widgetbrowser/widgetbrowser/tests/widgets.py b/moksha/widgetbrowser/widgetbrowser/tests/widgets.py
new file mode 100644
index 0000000..149139d
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/tests/widgets.py
@@ -0,0 +1,25 @@
+from tw.api import Widget
+from widgetbrowser import WidgetBrowser
+from formencode.api import Invalid
+
+class TestWidget(Widget):
+ template = "$value"
+ default = "default"
+
+ def validate(self, value, *args, **kw):
+ if 'break' in value.keys():
+ raise Invalid("Validation failed", value, None)
+ return value
+
+(a)WidgetBrowser.register_controller(TestWidget, 'test')
+def test_controller(request, response):
+ response.headers['Content-Type'] = 'text/plain'
+ return "Testing " + request.widget.__class__.__name__
+
+class TestWidgetExternalTemplate(Widget):
+ template = "toscawidgets:widgetbrowser.tests.dummy_template"
+ default = "default"
+
+class TestWidgetMultipleExternalTemplate(Widget):
+ template = "toscawidgets:widgetbrowser.tests.dummy_m_template"
+ default = "default"
diff --git a/moksha/widgetbrowser/widgetbrowser/util.py b/moksha/widgetbrowser/widgetbrowser/util.py
new file mode 100644
index 0000000..648cd8c
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/util.py
@@ -0,0 +1,242 @@
+import logging
+import os
+import errno
+import sys
+import pprint
+
+from pkg_resources import EntryPoint, iter_entry_points, resource_string
+
+import tw
+from tw.api import Widget, WidgetType
+from tw.core import view
+
+log = logging.getLogger(__name__)
+
+def import_widget(path):
+ """Import a widget given a dotted or entry point notation path.
+
+ Can import both widget instances or classes.
+
+ >>> import_widget('tw.core.base.Widget')
+ <class 'tw.core.base.Widget'>
+ >>> import_widget('tw.core.base:Widget')
+ <class 'tw.core.base.Widget'>
+ >>> import_widget('os.popen')
+
+ """
+ if ':' not in path:
+ parts = path.split('.')
+ path = '.'.join(parts[:-1]) + ':' + parts[-1]
+ widget = EntryPoint.parse("x="+path).load(False)
+ if not isinstance(widget, (WidgetType, Widget)):
+ widget = None
+ return widget
+
+
+def widget_path(widget):
+ """Returns the path of a widget instance or subclass
+
+ >>> from tw.api import Widget
+ >>> widget_path(Widget)
+ 'tw.core.base.Widget'
+ >>> widget_path(Widget())
+ 'tw.core.base.Widget'
+ """
+ if not isinstance(widget, (WidgetType, Widget)):
+ raise TypeError("Only widgets are allowed")
+ if isinstance(widget, Widget):
+ widget = widget.__class__
+ return '.'.join([widget.__module__, widget.__name__])
+
+def format_code(code, format='python'):
+ """Formats a chunk of code as html. If pygments is installed it will
+ pygmentize it.
+
+ >>> code = "from __future__ import teletransportation"
+ >>> '<pre' in format_code(code)
+ True
+ """
+ try:
+ from pygments import highlight, formatters, lexers
+ except ImportError:
+ log.info("Pygments is not available to colorize")
+ return '<pre>' + code + '</pre>'
+ lexer = lexers.get_lexer_by_name(format)
+ formatter = formatters.get_formatter_by_name('html')
+ return highlight(code, lexer, formatter)
+
+#TODO: Memoize this function
+def widget_template(widget, extension='.html'):
+ """Returns the template of a widget as a string.
+
+ Loads external templates if needed.
+
+ >>> from widgetbrowser.tests.widgets import *
+ >>> widget_template(TestWidgetExternalTemplate())
+ 'Dummy template $value\\n'
+
+ If more than one is available, it will use the extension to disambiguate.
+
+ >>> from widgetbrowser.tests.widgets import TestWidgetExternalTemplate
+ >>> widget_template(TestWidgetMultipleExternalTemplate(), '.html')
+ 'Dummy template $value\\n'
+ >>> widget_template(TestWidgetMultipleExternalTemplate(), '.mak')
+ 'Dummy template $value mako version\\n'
+ """
+ template = widget.template
+ if template and not view._is_inline_template(template):
+ # Template seems to refer to a file, look it up
+ parts = template.split('.')
+ possible_extensions = set(".html .mak .mako".split())
+ possible_extensions.remove(extension)
+ possible_extensions = [extension] + list(possible_extensions)
+ for ext in possible_extensions:
+ try:
+ return resource_string('.'.join(parts[:-1]), parts[-1]+ext)
+ except IOError, e:
+ if e.errno not in (0, errno.ENOENT):
+ raise
+ return None
+ return template
+
+def pretty_print(obj):
+ """Pretty prints an object returning pygmentized code if possible."""
+ return format_code(pprint.pformat(obj), 'python')
+
+def display_widget(widget, argstr='', ctx=None):
+ """Displays a widget with optional arguments as a string.
+
+
+ .. warning:: IT IS VERY UNSAFE TO EXECUTE UNTRUSTED CODE
+
+ Example::
+
+ >>> from tw.api import Widget
+ >>> class TestWidget(Widget):
+ ... params = ['param']
+ ... template = "$value-$param"
+ >>> display_widget(TestWidget())
+ u'None-None'
+ >>> display_widget(TestWidget(), '"hello", param=2')
+ u'hello-2'
+ """
+ ctx = ctx or {}
+ ctx['_w'] = widget
+ code = "_o = _w(%s)" % argstr
+ exec code in ctx
+ return ctx['_o']
+
+def widget_url(widget, action='', prefix=None):
+ """Returns the URL of the controller to perform `action` on `widget`.
+
+ If no `prefix` is passed the it will be tried to be fetched from
+ `tw.framework.request_local` where the :class:`WidgetBrowser` leaves it
+ on every request.
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> widget_url(Widget)
+ '/tw.core.base.Widget/'
+ >>> widget_url(Widget())
+ '/tw.core.base.Widget/'
+
+ You can also pass the `path` of the widget::
+
+ >>> widget_url('tw.api.Widget')
+ '/tw.api.Widget/'
+ >>> widget_url('tw.api.Widget', 'show')
+ '/tw.api.Widget/show'
+ >>> widget_url('tw.api.Widget', 'show', prefix='/widget')
+ '/widget/tw.api.Widget/show'
+
+ .. note::
+
+ You can pass any path the widget can be imported from when passing a
+ string but if you pass a widget instance or subclass then the real
+ module where it is defined will be generated.
+ """
+ if isinstance(widget, (Widget, WidgetType)):
+ widgeturi = widget_path(widget)
+ else:
+ widgeturi = widget
+ if import_widget(widgeturi) is None:
+ return
+ if prefix is None:
+ prefix = getattr(tw.framework.request_local, 'browser_prefix', '')
+ return '/'.join([prefix.rstrip('/'), widgeturi, action])
+
+def all_widgets():
+ """Iterates over all the Widget subclasses in the modules
+ that are declared as `toscawidgets.widgets` entrypoints
+
+ >>> len(list(all_widgets())) > 0
+ True
+ """
+ seen = set()
+ for ep in iter_entry_points('toscawidgets.widgets'):
+ try:
+ mod = ep.load(False)
+ except ImportError, e:
+ log.error("Could not load %r: %s", ep, e)
+ continue
+ for name in dir(mod):
+ obj = getattr(mod, name)
+ if isinstance(obj, WidgetType) and obj not in seen:
+ seen.add(obj)
+ yield obj
+
+class WidgetParameters(object):
+ """Wraps a widget and provides information on it's parameters.
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> params = WidgetParameters(Widget)
+ >>> len(params.all) > 0
+ True
+ >>> params.all - params.local == params.inherited
+ True
+ """
+ def __init__(self, widget):
+ if isinstance(widget, Widget):
+ widget = widget.__class__
+ self.widget = widget
+ self.all = widget.params
+ self.inherited = set()
+ for b in self.widget.__mro__:
+ if b is self.widget:
+ continue
+ self.inherited.update(getattr(b, 'params', set()))
+ self.local = self.all - self.inherited
+
+ def get_default(self, name, default=None):
+ """Returns a string representation of a parameter default value.
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> params = WidgetParameters(Widget)
+ >>> type(params.get_default('id'))
+ <type 'str'>
+ """
+ return repr(getattr(self.widget, name, default))
+
+ def get_doc(self, name, default='Undocumented'):
+ """Returns parameters's doc. If it is not documented it will return
+ ``default``
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> params = WidgetParameters(Widget)
+ >>> type(params.get_doc('id'))
+ <type 'str'>
+ """
+ return getattr(self.widget, name + '__doc', default)
+
+def build_docs(src, dst):
+ import sphinx
+ if not os.path.exists(dst):
+ os.mkdir(dst)
+ return sphinx.main(['sphinx-build', src, dst])
diff --git a/moksha/widgetbrowser/widgetbrowser/widgets.py b/moksha/widgetbrowser/widgetbrowser/widgets.py
new file mode 100644
index 0000000..b40fdea
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/widgets.py
@@ -0,0 +1,71 @@
+from tw.api import Widget, JSLink, CSSLink, js_function
+from widgetbrowser import util
+import string
+
+__all__ = ['WidgetBrowserTabs']
+
+mod = 'widgetbrowser'
+flora_all_css = CSSLink(modname=mod, filename="static/themes/flora/flora.all.css")
+tabs_css = CSSLink(modname=mod, filename="static/ui.tabs.css")
+wb_css = CSSLink(modname=mod, filename="static/widgetbrowser.css")
+pygments_css = CSSLink(modname=mod, filename="static/pygments.css")
+httprepl_css = CSSLink(modname=mod, filename="static/httprepl.css")
+jquery_js = JSLink(modname=mod, filename="static/jquery.js")
+# Do not pull jquery as an automatic dependency since Sphinx already includes
+# it
+ui_base_js = JSLink(modname=mod, filename="static/ui.base.js",
+ location="bodybottom")
+ui_tabs_js = JSLink(modname=mod, filename="static/ui.tabs.js",
+ location="bodybottom",
+ javascript=[ui_base_js])
+ui_dragabble_js = JSLink(modname=mod, filename="static/ui.draggable.js",
+ location="bodybottom")
+ui_resizable_js = JSLink(modname=mod, filename="static/ui.resizable.js",
+ location="bodybottom")
+ui_dialog_js = JSLink(modname=mod, filename="static/ui.dialog.js",
+ location="bodybottom",
+ javascript=[ui_base_js, ui_dragabble_js, ui_resizable_js])
+widgetbrowser_js = JSLink(modname=mod, filename="static/widgetbrowser.js",
+ javascript=[ui_tabs_js],
+ css=[tabs_css, wb_css, pygments_css],
+ location="bodybottom")
+
+httprepl_js = JSLink(modname=mod, filename='static/httprepl.js',
+ javascript=[ui_dialog_js],
+ css=[httprepl_css],
+ location="bodybottom")
+
+class WidgetBrowserTabs(Widget):
+ template = "genshi:widgetbrowser.templates.widget_browser_tabs"
+ params = ["tabs", "prefix", "size", "in_sphinx"]
+ in_sphinx = False
+ javascript = [widgetbrowser_js]
+ size = "small"
+ tabs = ['demo', 'demo_source', 'source', 'template', 'parameters']
+ prefix = None
+
+ def update_params(self, d):
+ super(WidgetBrowserTabs, self).update_params(d)
+ d.tabs = [(string.capwords(t.replace('_', ' ')), util.widget_url(d.value, t, prefix=d.prefix))
+ for t in d.tabs]
+ if not d.in_sphinx:
+ # Not displayed inside Sphinx, include jquery and pygments
+ jquery_js.inject()
+ pygments_css.inject()
+
+
+class WidgetRepl(Widget):
+ template = '<div id="$id" class="$css_class"></div>'
+ params = ["prefix"]
+ prefix = '/_repl/' # show nicely in the browser tabs
+ include_dynamic_js_calls = True
+ javascript = [jquery_js, httprepl_js]
+ css = [flora_all_css]
+ def update_params(self, d):
+ super(WidgetRepl, self).update_params(d)
+ assert d.id, "This widget needs an id"
+ config = dict(prefix=d.prefix)
+ call = js_function('HTTPRepl.render')('#'+d.id, config)
+ self.add_call("jQuery(function () {%s});" % call)
+
+repl = WidgetRepl("widgetrepl")
diff --git a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
new file mode 100644
index 0000000..a89a137
--- /dev/null
+++ b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
@@ -0,0 +1,238 @@
+import sys
+import weakref
+import os
+import inspect
+import logging
+from pkg_resources import resource_filename
+from genshi.core import Markup
+from genshi.template import TemplateLoader, Context
+from webob import Request, Response, exc
+import tw
+from tw.api import Widget, WidgetType, make_middleware
+from widgetbrowser import util, widgets, repl
+
+from moksha.api.widgets.global_resources import global_resources as moksha_global_resources
+
+try:
+ from formencode import Invalid
+ have_formencode = True
+except ImportError:
+ have_formencode = False
+
+__all__ = ['WidgetBrowser']
+
+log = logging.getLogger(__name__)
+
+def asbool(v):
+ if isinstance(v, basestring):
+ return v.lower().startswith('t') or v == '1' or v == 'on'
+ elif isinstance(v, bool):
+ return v
+ return False
+
+class WidgetBrowser(object):
+ """A widget browser WSGI app.
+
+ Parameters:
+
+ * `template_dirs`: A list of directories that shall be searched for
+ temlates used by the widget browser.
+ * `interactive`: Enable code execution. This is needed to for the REPL and
+ to override display arguments via the web interface. This is a BIG
+ SECURITY HOLE, enable only in a controlled environment.
+ * `docs_dir`: A directory where sphinx sources live.
+ """
+ def __init__(self, global_conf={}, template_dirs=None, interactive=False,
+ docs_dir=None, full_stack=True):
+ if isinstance(template_dirs, basestring):
+ template_dirs = template_dirs.split()
+ template_dirs = template_dirs or []
+ template_dirs.append(resource_filename('widgetbrowser', 'templates'))
+ self.loader = TemplateLoader(template_dirs)
+ self.interactive = asbool(interactive)
+ if self.interactive:
+ self.http_repl = repl.WidgetReplApp(globals(), weakref.proxy(self))
+ self.context = self.http_repl.repl.locals
+ else:
+ self.context = None
+ self.http_repl = exc.HTTPForbidden("Interactive mode is disabled")
+ if docs_dir:
+ from paste.cascade import Cascade
+ dest_dir = os.path.abspath(os.path.join(docs_dir, '.build'))
+ log.info('Building docs...')
+ util.build_docs(docs_dir, dest_dir)
+ self.built_docs = dest_dir
+ self.app = Cascade([self.docs_app, self.app])
+ if asbool(full_stack):
+ self.app = make_middleware(self.app, {
+ 'toscawidgets.framework.default_view': 'genshi',
+ }, stack_registry = True)
+ self._default_controllers = dict(demo=self.show_demo,
+ index=self.show_index,
+ template=self.show_template,
+ parameters=self.show_parameters,
+ source=self.show_source,
+ demo_source=self.show_demo_source)
+
+
+ def docs_app(self, environ, start_response):
+ """Registers widgetbrowser_js as resources before serving static html
+ files so it is injected into the page"""
+ from paste.urlparser import StaticURLParser
+ app = StaticURLParser(self.built_docs)
+ resources = widgets.widgetbrowser_js.retrieve_resources()
+ tw.framework.register_resources(resources)
+ moksha_global_resources.register_resources()
+ return app(environ, start_response)
+
+ _widget_controllers = {}
+ @classmethod
+ def register_controller(cls, widget, action):
+ """Registers function to act as a demo controller for a widget"""
+ def _register(controller):
+ cls._widget_controllers[(widget,action)] = controller
+ return controller
+ return _register
+
+ def lookup_controller(self, widget_cls, action):
+ try:
+ return self._widget_controllers[(widget_cls, action)]
+ except KeyError:
+ return self._default_controllers[action]
+
+ def lookup_widget_action(self, path_info):
+ try:
+ widget_path, action = path_info.strip('/').split('/')
+ except ValueError:
+ widget_path, action = path_info, 'index'
+ if widget_path:
+ try:
+ widget = util.import_widget(widget_path.strip('/'))
+ except (ImportError, ValueError):
+ widget = None
+ if widget:
+ return widget, action
+ raise LookupError(path_info)
+
+ def render(self, template, ns):
+ ns.pop('self',None)
+ stream = self.loader.load(template).generate(Context(**ns))
+ return stream.render(method='xhtml', doctype='xhtml')
+
+ def __call__(self, environ, start_response):
+ return self.app(environ, start_response)
+
+ def app(self, environ, start_response):
+ req = Request(environ)
+ resp = Response(request=req, content_type='text/html; charset=utf-8')
+ # Leave the interactive flag in tw.framework so demo controllers can know
+ # if it is safe to enable advanced/unsecure features.
+ tw.framework.request_local.interactive = self.interactive
+ tw.framework.request_local.browser_prefix = req.script_name
+
+ # Lookup widget XXX: Yuck!
+ if req.path_info == '/':
+ controller = self.home
+ elif req.path_info.startswith('/_repl') and self.http_repl:
+ req.path_info_pop()
+ return self.http_repl(environ, start_response)
+ elif req.path_info.startswith('/widgets'):
+ controller = self.widgets
+ else:
+ try:
+ widget, action = self.lookup_widget_action(req.path_info)
+ except LookupError:
+ resp = exc.HTTPNotFound('No widget at %s' % req.path_info)
+ return resp(environ, start_response)
+
+
+ # Lookup controller
+ try:
+ controller = self.lookup_controller(widget, action)
+ except LookupError:
+ resp = exc.HTTPNotImplemented()
+ return resp(environ, start_response)
+
+ # If it's a widget class instantiate it with no arguments
+ if isinstance(widget, WidgetType):
+ widget = widget('test_widget')
+ req.widget = widget
+
+ # Call controller and handle output
+ output = controller(req, resp)
+ if isinstance(output, str):
+ resp.body = output
+ elif isinstance(output, unicode):
+ resp.body = output.encode('utf-8')
+ elif output:
+ resp = output
+
+ return resp(environ, start_response)
+
+
+ def show_template(self, req, resp):
+ widget = req.widget
+ if getattr(widget, 'demo_for', None):
+ widget = req.widget.demo_for()
+ template = util.widget_template(widget)
+ if template:
+ return util.format_code(template, 'html')
+ else:
+ resp.content_type = "text/plain"
+ return widget.__class__.__name__ + ' has no template.'
+
+ def show_source(self, req, resp):
+ cls = getattr(req.widget, 'demo_for', req.widget.__class__)
+ source = inspect.getsource(cls)
+ return util.format_code(source, 'python')
+
+ def show_demo_source(self, req, resp):
+ widget = req.widget
+ source = inspect.getsource(widget.__class__)
+ return util.format_code(source, 'python')
+
+ def show_parameters(self, req, resp):
+ cls = getattr(req.widget, 'demo_for', req.widget.__class__)
+ parameters = util.WidgetParameters(cls)
+ return self.render('widget_parameters.html', locals())
+
+
+ def show_index(self, req, resp):
+ widget = req.widget
+ return self.render('widget_index.html', locals())
+
+ def show_demo(self, req, resp):
+ widget = req.widget
+ widget_name = widget.__class__.__name__
+ interactive = self.interactive
+ if have_formencode and req.method.upper() == "POST":
+ # A widget submission, try to validate.
+ try:
+ value = widget.validate(req.POST)
+ value = util.pretty_print(value)
+ return self.render('validation_result.html', locals())
+ except Invalid, error:
+ pass
+
+ if self.interactive:
+ _disp = req.GET.get('_disp', '')
+ else:
+ _disp = ''
+ widget_output = util.display_widget(widget, _disp, self.context)
+ if not callable(widget_output):
+ widget_output = Markup(widget_output)
+ return self.render('show_widget.html', locals())
+
+ def widgets(self, req, resp):
+ widgets = [(util.widget_path(w), util.widget_url(w))
+ for w in util.all_widgets()]
+ widgets.sort()
+ return self.render('list_widgets.html', locals())
+
+ def home(self, req, resp):
+ widgets.jquery_js.inject()
+ widgets.tabs_css.inject()
+ widgets.ui_tabs_js.inject()
+ def url(s):
+ return req.script_name + s
+ return self.render('home.html', locals())
diff --git a/moksha/widgetbrowser/widgets.py b/moksha/widgetbrowser/widgets.py
deleted file mode 100644
index b40fdea..0000000
--- a/moksha/widgetbrowser/widgets.py
+++ /dev/null
@@ -1,71 +0,0 @@
-from tw.api import Widget, JSLink, CSSLink, js_function
-from widgetbrowser import util
-import string
-
-__all__ = ['WidgetBrowserTabs']
-
-mod = 'widgetbrowser'
-flora_all_css = CSSLink(modname=mod, filename="static/themes/flora/flora.all.css")
-tabs_css = CSSLink(modname=mod, filename="static/ui.tabs.css")
-wb_css = CSSLink(modname=mod, filename="static/widgetbrowser.css")
-pygments_css = CSSLink(modname=mod, filename="static/pygments.css")
-httprepl_css = CSSLink(modname=mod, filename="static/httprepl.css")
-jquery_js = JSLink(modname=mod, filename="static/jquery.js")
-# Do not pull jquery as an automatic dependency since Sphinx already includes
-# it
-ui_base_js = JSLink(modname=mod, filename="static/ui.base.js",
- location="bodybottom")
-ui_tabs_js = JSLink(modname=mod, filename="static/ui.tabs.js",
- location="bodybottom",
- javascript=[ui_base_js])
-ui_dragabble_js = JSLink(modname=mod, filename="static/ui.draggable.js",
- location="bodybottom")
-ui_resizable_js = JSLink(modname=mod, filename="static/ui.resizable.js",
- location="bodybottom")
-ui_dialog_js = JSLink(modname=mod, filename="static/ui.dialog.js",
- location="bodybottom",
- javascript=[ui_base_js, ui_dragabble_js, ui_resizable_js])
-widgetbrowser_js = JSLink(modname=mod, filename="static/widgetbrowser.js",
- javascript=[ui_tabs_js],
- css=[tabs_css, wb_css, pygments_css],
- location="bodybottom")
-
-httprepl_js = JSLink(modname=mod, filename='static/httprepl.js',
- javascript=[ui_dialog_js],
- css=[httprepl_css],
- location="bodybottom")
-
-class WidgetBrowserTabs(Widget):
- template = "genshi:widgetbrowser.templates.widget_browser_tabs"
- params = ["tabs", "prefix", "size", "in_sphinx"]
- in_sphinx = False
- javascript = [widgetbrowser_js]
- size = "small"
- tabs = ['demo', 'demo_source', 'source', 'template', 'parameters']
- prefix = None
-
- def update_params(self, d):
- super(WidgetBrowserTabs, self).update_params(d)
- d.tabs = [(string.capwords(t.replace('_', ' ')), util.widget_url(d.value, t, prefix=d.prefix))
- for t in d.tabs]
- if not d.in_sphinx:
- # Not displayed inside Sphinx, include jquery and pygments
- jquery_js.inject()
- pygments_css.inject()
-
-
-class WidgetRepl(Widget):
- template = '<div id="$id" class="$css_class"></div>'
- params = ["prefix"]
- prefix = '/_repl/' # show nicely in the browser tabs
- include_dynamic_js_calls = True
- javascript = [jquery_js, httprepl_js]
- css = [flora_all_css]
- def update_params(self, d):
- super(WidgetRepl, self).update_params(d)
- assert d.id, "This widget needs an id"
- config = dict(prefix=d.prefix)
- call = js_function('HTTPRepl.render')('#'+d.id, config)
- self.add_call("jQuery(function () {%s});" % call)
-
-repl = WidgetRepl("widgetrepl")
diff --git a/moksha/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/wsgiapp.py
deleted file mode 100644
index abdae33..0000000
--- a/moksha/widgetbrowser/wsgiapp.py
+++ /dev/null
@@ -1,236 +0,0 @@
-import sys
-import weakref
-import os
-import inspect
-import logging
-from pkg_resources import resource_filename
-from genshi.core import Markup
-from genshi.template import TemplateLoader, Context
-from webob import Request, Response, exc
-import tw
-from tw.api import Widget, WidgetType, make_middleware
-from widgetbrowser import util, widgets, repl
-
-
-try:
- from formencode import Invalid
- have_formencode = True
-except ImportError:
- have_formencode = False
-
-__all__ = ['WidgetBrowser']
-
-log = logging.getLogger(__name__)
-
-def asbool(v):
- if isinstance(v, basestring):
- return v.lower().startswith('t') or v == '1' or v == 'on'
- elif isinstance(v, bool):
- return v
- return False
-
-class WidgetBrowser(object):
- """A widget browser WSGI app.
-
- Parameters:
-
- * `template_dirs`: A list of directories that shall be searched for
- temlates used by the widget browser.
- * `interactive`: Enable code execution. This is needed to for the REPL and
- to override display arguments via the web interface. This is a BIG
- SECURITY HOLE, enable only in a controlled environment.
- * `docs_dir`: A directory where sphinx sources live.
- """
- def __init__(self, global_conf={}, template_dirs=None, interactive=False,
- docs_dir=None, full_stack=True):
- if isinstance(template_dirs, basestring):
- template_dirs = template_dirs.split()
- template_dirs = template_dirs or []
- template_dirs.append(resource_filename('widgetbrowser', 'templates'))
- self.loader = TemplateLoader(template_dirs)
- self.interactive = asbool(interactive)
- if self.interactive:
- self.http_repl = repl.WidgetReplApp(globals(), weakref.proxy(self))
- self.context = self.http_repl.repl.locals
- else:
- self.context = None
- self.http_repl = exc.HTTPForbidden("Interactive mode is disabled")
- if docs_dir:
- from paste.cascade import Cascade
- dest_dir = os.path.abspath(os.path.join(docs_dir, '.build'))
- log.info('Building docs...')
- util.build_docs(docs_dir, dest_dir)
- self.built_docs = dest_dir
- self.app = Cascade([self.docs_app, self.app])
- if asbool(full_stack):
- self.app = make_middleware(self.app, {
- 'toscawidgets.framework.default_view': 'genshi',
- }, stack_registry = True)
- self._default_controllers = dict(demo=self.show_demo,
- index=self.show_index,
- template=self.show_template,
- parameters=self.show_parameters,
- source=self.show_source,
- demo_source=self.show_demo_source)
-
-
- def docs_app(self, environ, start_response):
- """Registers widgetbrowser_js as resources before serving static html
- files so it is injected into the page"""
- from paste.urlparser import StaticURLParser
- app = StaticURLParser(self.built_docs)
- resources = widgets.widgetbrowser_js.retrieve_resources()
- tw.framework.register_resources(resources)
- return app(environ, start_response)
-
- _widget_controllers = {}
- @classmethod
- def register_controller(cls, widget, action):
- """Registers function to act as a demo controller for a widget"""
- def _register(controller):
- cls._widget_controllers[(widget,action)] = controller
- return controller
- return _register
-
- def lookup_controller(self, widget_cls, action):
- try:
- return self._widget_controllers[(widget_cls, action)]
- except KeyError:
- return self._default_controllers[action]
-
- def lookup_widget_action(self, path_info):
- try:
- widget_path, action = path_info.strip('/').split('/')
- except ValueError:
- widget_path, action = path_info, 'index'
- if widget_path:
- try:
- widget = util.import_widget(widget_path.strip('/'))
- except (ImportError, ValueError):
- widget = None
- if widget:
- return widget, action
- raise LookupError(path_info)
-
- def render(self, template, ns):
- ns.pop('self',None)
- stream = self.loader.load(template).generate(Context(**ns))
- return stream.render(method='xhtml', doctype='xhtml')
-
- def __call__(self, environ, start_response):
- return self.app(environ, start_response)
-
- def app(self, environ, start_response):
- req = Request(environ)
- resp = Response(request=req, content_type='text/html; charset=utf-8')
- # Leave the interactive flag in tw.framework so demo controllers can know
- # if it is safe to enable advanced/unsecure features.
- tw.framework.request_local.interactive = self.interactive
- tw.framework.request_local.browser_prefix = req.script_name
-
- # Lookup widget XXX: Yuck!
- if req.path_info == '/':
- controller = self.home
- elif req.path_info.startswith('/_repl') and self.http_repl:
- req.path_info_pop()
- return self.http_repl(environ, start_response)
- elif req.path_info.startswith('/widgets'):
- controller = self.widgets
- else:
- try:
- widget, action = self.lookup_widget_action(req.path_info)
- except LookupError:
- resp = exc.HTTPNotFound('No widget at %s' % req.path_info)
- return resp(environ, start_response)
-
-
- # Lookup controller
- try:
- controller = self.lookup_controller(widget, action)
- except LookupError:
- resp = exc.HTTPNotImplemented()
- return resp(environ, start_response)
-
- # If it's a widget class instantiate it with no arguments
- if isinstance(widget, WidgetType):
- widget = widget('test_widget')
- req.widget = widget
-
- # Call controller and handle output
- output = controller(req, resp)
- if isinstance(output, str):
- resp.body = output
- elif isinstance(output, unicode):
- resp.body = output.encode('utf-8')
- elif output:
- resp = output
-
- return resp(environ, start_response)
-
-
- def show_template(self, req, resp):
- widget = req.widget
- if getattr(widget, 'demo_for', None):
- widget = req.widget.demo_for()
- template = util.widget_template(widget)
- if template:
- return util.format_code(template, 'html')
- else:
- resp.content_type = "text/plain"
- return widget.__class__.__name__ + ' has no template.'
-
- def show_source(self, req, resp):
- cls = getattr(req.widget, 'demo_for', req.widget.__class__)
- source = inspect.getsource(cls)
- return util.format_code(source, 'python')
-
- def show_demo_source(self, req, resp):
- widget = req.widget
- source = inspect.getsource(widget.__class__)
- return util.format_code(source, 'python')
-
- def show_parameters(self, req, resp):
- cls = getattr(req.widget, 'demo_for', req.widget.__class__)
- parameters = util.WidgetParameters(cls)
- return self.render('widget_parameters.html', locals())
-
-
- def show_index(self, req, resp):
- widget = req.widget
- return self.render('widget_index.html', locals())
-
- def show_demo(self, req, resp):
- widget = req.widget
- widget_name = widget.__class__.__name__
- interactive = self.interactive
- if have_formencode and req.method.upper() == "POST":
- # A widget submission, try to validate.
- try:
- value = widget.validate(req.POST)
- value = util.pretty_print(value)
- return self.render('validation_result.html', locals())
- except Invalid, error:
- pass
-
- if self.interactive:
- _disp = req.GET.get('_disp', '')
- else:
- _disp = ''
- widget_output = util.display_widget(widget, _disp, self.context)
- if not callable(widget_output):
- widget_output = Markup(widget_output)
- return self.render('show_widget.html', locals())
-
- def widgets(self, req, resp):
- widgets = [(util.widget_path(w), util.widget_url(w))
- for w in util.all_widgets()]
- widgets.sort()
- return self.render('list_widgets.html', locals())
-
- def home(self, req, resp):
- widgets.jquery_js.inject()
- widgets.tabs_css.inject()
- widgets.ui_tabs_js.inject()
- def url(s):
- return req.script_name + s
- return self.render('home.html', locals())
commit efec110a9dbb9ed55919b421e99286c5ef7595d0
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:17:31 2009 -0500
Mount the WidgetBrowser WSGI app in our RootController.
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index 37fb643..1e50870 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -21,6 +21,8 @@ import moksha
from tg import expose, flash, require, tmpl_context, redirect, validate
from tg.controllers import WSGIAppController
from repoze.what import predicates
+from pkg_resources import resource_filename
+from widgetbrowser import WidgetBrowser
from moksha import _
from moksha.model import DBSession
@@ -36,6 +38,13 @@ class RootController(BaseController):
admin = AdminController()
error = ErrorController()
+ # ToscaWidgets WidgetBrowser integration
+ widget = WSGIAppController(
+ WidgetBrowser(
+ template_dirs=[resource_filename('moksha','templates/widget_browser')],
+ full_stack=False,
+ docs_dir='docs'))
+
@expose('mako:moksha.templates.index')
def index(self):
tmpl_context.menu_widget = moksha.menus['default_menu']
commit f090a85b4d5da72a4314859e19c1fc97c7cd8bc2
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:14:10 2009 -0500
Clean up our LiveFeedWidget.
- Document the parameters
- Utilize a single Feed object, instead of instantiating one each update_params
- Remove the unnecessary update_params
- Remove the jQuery show() animation, as it adds 'display:block' to our <li>'s,
which remove the list bullets...
diff --git a/moksha/api/widgets/feed/live.py b/moksha/api/widgets/feed/live.py
index 3f3c0c1..4ceda47 100644
--- a/moksha/api/widgets/feed/live.py
+++ b/moksha/api/widgets/feed/live.py
@@ -21,20 +21,20 @@ from moksha.api.widgets import LiveWidget
class LiveFeedWidget(LiveWidget):
""" A live streaming feed widget """
- topic = 'feed_demo'
- template = '${feed()}'
+ params = {
+ 'url': 'The feed URL',
+ 'topic': 'A topic or list of topics to subscribe to',
+ 'feed': 'A moksha Feed object',
+ }
+ template = '${feed(id=id, url=url)}'
onmessage = """
$.each(json, function() {
$("#${id} ul li:last").remove();
- $("<li/>").hide().html(
+ $("<li/>").html(
$("<a/>")
.attr("href", this.link)
.text(this.title))
- .prependTo($("#${id} ul"))
- .show();
+ .prependTo($("#${id} ul"));
});
"""
-
- def update_params(self, d):
- super(LiveFeedWidget, self).update_params(d)
- d['feed'] = Feed(d['id'], url=d.get('url', 'http://doggdot.us/rss'))
+ feed = Feed()
commit 8c50a6a63b2bf526659bbb442ea435d07ef1f3a3
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:13:48 2009 -0500
Add a demo live feed widget to the LiveWidgets documentation
diff --git a/docs/main/LiveWidget.rst b/docs/main/LiveWidget.rst
index 5db9b73..d0d9ba8 100644
--- a/docs/main/LiveWidget.rst
+++ b/docs/main/LiveWidget.rst
@@ -26,6 +26,16 @@ the 'stuff' message topic, and will perform an `alert` upon new messages.
The Live Feed Widget
--------------------
+.. code-block:: python
+
+ from moksha.api.widgets.feed.live import LiveFeedWidget
+
+.. widgetbrowser:: moksha.widgets.demos.LiveFeedDemo
+ :tabs: demo, source, template, parameters
+ :size: large
+
+--------------------------------------------------------------------------------
+
Moksha provides an example :class:`LiveFeedWidget` that displays messages from the `feed_example` topic, using jQuery.
.. code-block:: python
commit e03054cd56720202aa6e4f5b23cea48aaa3594f7
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:13:36 2009 -0500
Add a demo feed widget to our sphinx documentation.
diff --git a/docs/main/Feeds.rst b/docs/main/Feeds.rst
index e53cabc..7c580a1 100644
--- a/docs/main/Feeds.rst
+++ b/docs/main/Feeds.rst
@@ -10,10 +10,22 @@ When used within the Moksha Platform, the Feed object will utilize the central
global `moksha.feed_cache`. When used outside of the platform, it will
automatically use a local sqlite database cache.
+The Moksha Feed Widget
+----------------------
+
+.. code-block:: python
+
+ from moksha.api.widgets.feed import Feed
+
+.. widgetbrowser:: moksha.widgets.demos.FeedDemo
+ :tabs: demo, source, template
+ :size: large
+
+
API usage
---------
-The Feed API provides a flexible Feed object that can be utilize in many ways.
+The Feed object can be utilize in many ways.
Rendering a url with the Feed object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
commit 31a472671ce031cd98572f34741edbb55ee3b1d2
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:13:14 2009 -0500
Add a `moksha.widgets.demos` module for demo widgets.
diff --git a/moksha/widgets/demos.py b/moksha/widgets/demos.py
new file mode 100644
index 0000000..3de705e
--- /dev/null
+++ b/moksha/widgets/demos.py
@@ -0,0 +1,10 @@
+from moksha.api.widgets.feed import Feed
+
+class FeedDemo(Feed):
+ url = 'http://feeds.arstechnica.com/arstechnica/index'
+
+from moksha.api.widgets.feed.live import LiveFeedWidget
+
+class LiveFeedDemo(LiveFeedWidget):
+ url = 'http://feeds.arstechnica.com/arstechnica/index'
+ topic = 'feed_demo'
commit a017b3c2c9f51cd7f36d352d25ac2edd482030b9
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:10:05 2009 -0500
If the widget output is not callable (eg: genshi.core.Stream), then wrap it in
Genshi Markup. This is to allow Mako widgets to be rendered in the
WidgetBrowser's Genshi templates.
diff --git a/moksha/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/wsgiapp.py
index 036d4b2..abdae33 100644
--- a/moksha/widgetbrowser/wsgiapp.py
+++ b/moksha/widgetbrowser/wsgiapp.py
@@ -4,6 +4,7 @@ import os
import inspect
import logging
from pkg_resources import resource_filename
+from genshi.core import Markup
from genshi.template import TemplateLoader, Context
from webob import Request, Response, exc
import tw
@@ -216,6 +217,8 @@ class WidgetBrowser(object):
else:
_disp = ''
widget_output = util.display_widget(widget, _disp, self.context)
+ if not callable(widget_output):
+ widget_output = Markup(widget_output)
return self.render('show_widget.html', locals())
def widgets(self, req, resp):
commit c04a33c8f33657f867a6bac568feb6eecb97eafa
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:09:18 2009 -0500
Remove a non-existent doc
diff --git a/docs/index.rst b/docs/index.rst
index aa3c96f..6fb323c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -92,7 +92,6 @@ Development
:maxdepth: 2
main/Development
- main/CallToAction
Deployment
----------
commit 0be868ccb3a9f82368c1aa42edc7ae169b40e18b
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:09:00 2009 -0500
Import the moksha.widgetbrowser Sphinx extension
diff --git a/docs/conf.py b/docs/conf.py
index c774831..f2ea061 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -155,7 +155,5 @@ code_path = test_path = os.path.dirname(os.path.abspath(__file__)) + os.path.sep
#
# Enable the ToscaWidgets WidgetBrowser
#
-#try:
-# extensions.append("widgetbrowser.sphinx_ext")
-#except ImportError:
-# print "Unable to import the WidgetBrowser; skipping."
+import moksha.widgetbrowser
+extensions.append("moksha.widgetbrowser.sphinx_ext")
commit 936f96fed9f912146b153844af5f26dc4998b02d
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:08:16 2009 -0500
Add the ToscaWidgets WidgetBrowser as `moksha.widgetbrowser`.
This project does not yet exist in PyPi, so we cannot easy_install it.
diff --git a/moksha/widgetbrowser/__init__.py b/moksha/widgetbrowser/__init__.py
new file mode 100644
index 0000000..c037ed3
--- /dev/null
+++ b/moksha/widgetbrowser/__init__.py
@@ -0,0 +1,2 @@
+from wsgiapp import WidgetBrowser
+from util import widget_url
diff --git a/moksha/widgetbrowser/command.py b/moksha/widgetbrowser/command.py
new file mode 100644
index 0000000..4b15fbe
--- /dev/null
+++ b/moksha/widgetbrowser/command.py
@@ -0,0 +1,54 @@
+from wsgiref.simple_server import make_server
+from optparse import OptionParser
+
+from widgetbrowser.wsgiapp import WidgetBrowser
+
+
+_parser = OptionParser(usage = "%prog [OPTIONS] [widget_url]")
+_parser.add_option("-i", "--interactive",
+ dest="interactive",
+ action="store_true",
+ default=False)
+_parser.add_option("-b", "--browser",
+ dest="browser",
+ action="store_true",
+ default=False)
+_parser.add_option("-d", "--docs",
+ dest="docs",
+ default=None)
+_parser.add_option("-p", "--port",
+ dest="port",
+ default=8000)
+
+def browser_command(argv=None):
+ """Command line interface to launch the widgetbrowser"""
+ opts, args = _parser.parse_args(argv)
+
+ # Only allow passing display arguments in debug mode
+ if args:
+ widget_url = args[0] + '/'
+ else:
+ widget_url = ''
+ app = WidgetBrowser(interactive=opts.interactive, docs_dir=opts.docs)
+ if opts.interactive:
+ try:
+ from weberror.evalexception import EvalException
+ app = EvalException(app)
+ except ImportError:
+ raise ImportError("You need to install WebError for interactive "
+ "debugging")
+ url = "http://127.0.0.1:%s/" % opts.port
+ if opts.browser:
+ import webbrowser
+ webbrowser.open(url + widget_url)
+ server = make_server('127.0.0.1', int(opts.port), app)
+ print "Server started at " + url
+ try:
+ server.serve_forever()
+ except (KeyboardInterrupt, SystemExit):
+ pass
+
+if __name__ == '__main__':
+ import sys
+ sys.exit(browser_command(sys.argv))
+
diff --git a/moksha/widgetbrowser/repl.py b/moksha/widgetbrowser/repl.py
new file mode 100644
index 0000000..5855068
--- /dev/null
+++ b/moksha/widgetbrowser/repl.py
@@ -0,0 +1,305 @@
+"""
+Robert Brewer was the original author of the module this module has heavily
+inspired from. http://www.aminus.net/wiki/HTTPREPL
+"""
+import warnings
+from itertools import count
+import codeop
+import inspect
+import os
+import re
+
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
+import sys
+import traceback
+
+from webob import Request, Response, exc
+
+try:
+ from formencode import Invalid
+ have_formencode = True
+except ImportError:
+ have_formencode = False
+
+from genshi.util import LRUCache
+import tw
+from tw.api import make_middleware, Widget
+
+from widgetbrowser import util, widgets
+
+class HTTPREPL:
+
+ def __init__(self, locals=None):
+ self.locals = {}
+ if locals:
+ self.locals.update(locals)
+ self.buffer = []
+
+ def push(self, line):
+ """Push 'line' and return exec results (None if more input needed)."""
+ if line == "help":
+ return "Type help(object) for help about object."
+ if line == "help()":
+ return "You cannot call help() without an argument."
+
+ self.buffer.append(line)
+ source = "\n".join(self.buffer)
+
+ try:
+ code = codeop.compile_command(source, "<HTTP input>", 'single')
+ except (OverflowError, SyntaxError, ValueError):
+ self.buffer = []
+ return traceback.format_exc()
+
+ if code is None:
+ # More lines needed.
+ return None
+
+ self.buffer = []
+ return self.execute(code)
+
+ def execute(self, code):
+ """Execute the given code in self.locals and return any stdout/sterr."""
+ out = StringIO()
+ oldout = sys.stdout
+ olderr = sys.stderr
+ sys.stdout = sys.stderr = out
+ try:
+ try:
+ exec code in self.locals
+ except:
+ result = traceback.format_exc()
+ else:
+ result = out.getvalue()
+ finally:
+ # FormEncode will break if _ is left in __builtins__ and it tries
+ # to use it as a translator
+ __builtins__.pop('_', None)
+ sys.stdout = oldout
+ sys.stderr = olderr
+ out.close()
+ return result
+
+ def dir(self, line):
+ """Examine a partial line and provide attr list of final expr."""
+ line = re.split(r"\s", line)[-1].strip()
+ # Support lines like "thing.attr" as "thing.", because the browser
+ # may not finish calculating the partial line until after the user
+ # has clicked on a few more keys.
+ line = ".".join(line.split(".")[:-1])
+ try:
+ result = eval("dir(%s)" % line, {}, self.locals)
+ except:
+ return []
+ return result
+
+ def doc(self, line):
+ """Examine a partial line and provide sig+doc of final expr."""
+ line = re.split(r"\s", line)[-1].strip()
+ # Support lines like "func(text" as "func(", because the browser
+ # may not finish calculating the partial line until after the user
+ # has clicked on a few more keys.
+ line = "(".join(line.split("(")[:-1])
+ try:
+ result = eval(line, {}, self.locals)
+ try:
+ if isinstance(result, type):
+ func = result.__init__
+ else:
+ func = result
+ args, varargs, varkw, defaults = inspect.getargspec(func)
+ except TypeError:
+ if callable(result):
+ doc = getattr(result, "__doc__", "") or ""
+ return "%s\n\n%s" % (line, doc)
+ return None
+ except:
+ return None
+
+ if args and args[0] == 'self':
+ args.pop(0)
+ missing = object()
+ defaults = defaults or []
+ defaults = ([missing] * (len(args) - len(defaults))) + list(defaults)
+ arglist = []
+ for a, d in zip(args, defaults):
+ if d is missing:
+ arglist.append(a)
+ else:
+ arglist.append("%s=%s" % (a, d))
+ if varargs:
+ arglist.append("*%s" % varargs)
+ if varkw:
+ arglist.append("**%s" % varkw)
+ doc = getattr(result, "__doc__", "") or ""
+ return "%s(%s)\n%s" % (line, ", ".join(arglist), doc)
+
+
+class DeferredDisplay(object):
+ """Wraps a widget and the args passed to display/render so we can defer
+ its display to another request.
+
+ .. note::
+ The JS code is dependent on the output of __repr__ since it parses it
+ to know a widget is being displayed so it can open an overlay.
+ """
+ _counter = count(0)
+ def __init__(self, widget, value, **kw):
+ self.id = self._counter.next()
+ self.value = value
+ self.widget = widget
+ self.kw = kw
+
+ def display(self):
+ """
+ Displays the widget as it was intended to be displayed when it was
+ wrapped.
+ """
+ return self.widget.display(self.value, **self.kw)
+
+ __call__ = display
+
+ def __repr__(self):
+ data = (self.id, self.widget.__class__)
+ return self.__class__.__name__ + repr(data)
+
+
+class WidgetReplApp(object):
+ def __init__(self, locals=None, widget_browser=None, max_dialogs=10):
+ self.repl = HTTPREPL(locals)
+ warnings.warn("\n"*2 + "*"*79 + "\n"
+ "DISCLAIMER:\n"
+ "Running this app poses a significant security threat "
+ "if accessible to an \nattacker. Make sure the server is "
+ "bound to the loopback interface or behind\na firewall "
+ "and that there are no local untrusted users.\n" + "*"*79)
+ if widget_browser:
+ self.widget_browser = widget_browser
+ self.displayed_widgets = LRUCache(max_dialogs)
+ self.setup_tw()
+
+ def setup_tw(repl_app):
+ # Stack TW's middleware configured with dummy default_view to signal
+ # that a widget is being displayed so we can wrap and register its
+ # output.
+ conf = {'toscawidgets.framework.default_view' : 'tw_repl',
+ 'toscawidgets.middleware.inject_resources' : True}
+ repl_app.app = make_middleware(repl_app.app, conf)
+ # monkey-patch display and render to hijack output
+ def wrap(f):
+ if f.func_name == 'wrapper':
+ return f
+ def wrapper(self, value=None, **kw):
+ if self.displays_on == 'tw_repl':
+ o = DeferredDisplay(self, value, **kw)
+ repl_app.displayed_widgets[o.id] = o
+ else:
+ o = f(self, value, **kw)
+ return o
+ return wrapper
+ Widget.display = wrap(Widget.display)
+ Widget.render = wrap(Widget.render)
+
+ def __call__(self, environ, start_response):
+ assert not environ['wsgi.multiprocess'], "Cannot run in a multiprocess"\
+ " environment"
+ return self.app(environ, start_response)
+
+ def app(self, environ, start_response):
+ """Main dispatcher. pops PATH_INFO and delegates to exposed methods."""
+ req = Request(environ.copy())
+ resp = Response(request=req, content_type='text/html; charset=UTF8')
+ first_part = req.path_info_pop() or 'index'
+ method = getattr(self, first_part, None)
+ if getattr(method, 'exposed', False):
+ output = method(req, resp)
+ if isinstance(output, unicode):
+ resp.body = output.encode('utf-8')
+ elif isinstance(output, str):
+ resp.body = output
+ elif output:
+ resp = output
+ else:
+ resp = exc.HTTPNotImplemented()
+ return resp(environ, start_response)
+
+ def index(self, req, resp):
+ """Return an HTTP-based Read-Eval-Print-Loop terminal."""
+ # Override default_view so resources display properly
+ tw.framework.default_view = 'toscawidgets'
+ tpl = '<html><head><title>"%(title)s</title></head>' \
+ '<body class="flora">%(repl)s</body></html>'
+ prefix = req.script_name + '/'
+ return tpl % {'title': 'WidgetBrowser Terminal',
+ 'repl': widgets.repl(prefix=req.script_name + '/')}
+ index.exposed = True
+
+ def push(self, req, resp):
+ """Push 'line' and return exec results as a bare response."""
+ line = req.params['line']
+ result = self.repl.push(line)
+ if result is None:
+ # More input lines needed.
+ resp.status_int = 204
+ return result
+ push.exposed = True
+
+ def dir(self, req, resp):
+ """Push 'line' and return result of eval on the final expr."""
+ line = req.params['line']
+ result = self.repl.dir(line)
+ if not result:
+ resp.status_int = 204
+ return
+ return repr(result)
+ dir.exposed = True
+
+ def doc(self, req, resp):
+ """Push 'line' and return result of getargspec on the final expr."""
+ line = req.params['line']
+ result = self.repl.doc(line)
+ if not result:
+ resp.status_int = 204
+ return result
+ doc.exposed = True
+
+ def enrich_namespace(self, ns, request):
+
+ _disp = request.GET.get('_disp', '')
+
+ if not "_disp" in ns:
+ ns["_disp"]=_disp
+ if not "interactive" in ns:
+ ns["interactive"]=True
+ return ns
+
+ def widget_output(self, req, resp):
+ try:
+ key = int(req.path_info.strip('/'))
+ dd = self.displayed_widgets[key]
+ except KeyError:
+ resp.status_int = 404
+ return "There's now widget output at this URL. Maybe it has "\
+ "expired? Try increasing the 'max_dialogs' parameter"
+
+ widget = dd.widget
+ widget_name = widget.__class__.__name__
+ render = self.widget_browser.render
+ if have_formencode and req.method.upper() == "POST":
+ # A widget submission, try to validate.
+ try:
+ value = widget.validate(req.POST)
+ value = util.pretty_print(value)
+ return render('validation_result.html', locals())
+ except Invalid, error:
+ pass
+ # Override default_view because WidgetBrowser renders on Genshi, not
+ # 'tw_repl', this is needed so widget and resources display properly
+ tw.framework.default_view = 'genshi'
+ widget_output = dd.display()
+ return render('show_widget.html', self.enrich_namespace(locals(),request=req))
+ widget_output.exposed = True
diff --git a/moksha/widgetbrowser/sphinx_ext.py b/moksha/widgetbrowser/sphinx_ext.py
new file mode 100644
index 0000000..f0c9bea
--- /dev/null
+++ b/moksha/widgetbrowser/sphinx_ext.py
@@ -0,0 +1,43 @@
+import os
+from docutils import nodes, utils
+from docutils.parsers.rst import directives
+
+from widgetbrowser import util, widgets
+
+widget_tabs = widgets.WidgetBrowserTabs(in_sphinx=True)
+
+def widgetbrowser_directive(dirname, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Processes the `widgetbrowser` reStructuredText directive.
+
+ When generating the URL for the widget it peeks into os.environ for the
+ 'TW_BROWSER_PREFIX' environment variable.
+ """
+ widget_path = arguments[0]
+ widget = util.import_widget(widget_path)
+ if not widget:
+ reporter = state.document.reporter
+ msg = reporter.warning(
+ 'No widget found at %r' % widget_path, line=lineno)
+ prb = nodes.problematic(block_text, block_text, msg)
+ return [msg, prb]
+ tabs = options.get('tabs') or widget_tabs.tabs
+ prefix = os.environ.get('TW_BROWSER_PREFIX')
+ size = options.get('size')
+ html = widget_tabs(widget, tabs=tabs, prefix=prefix, size=size)
+ node = nodes.raw('', html, format='html')
+ return [node]
+
+
+def _get_tabs(arg):
+ if arg is None:
+ return []
+ return [s.strip() for s in arg.split(',')]
+
+def _get_size(arg):
+ return arg or "small"
+
+def setup(app):
+ browser_options = {'tabs': _get_tabs, 'size':_get_size}
+ app.add_directive('widgetbrowser', widgetbrowser_directive, 1, (1, 0, 1),
+ **browser_options)
diff --git a/moksha/widgetbrowser/static/httprepl.css b/moksha/widgetbrowser/static/httprepl.css
new file mode 100644
index 0000000..6eda851
--- /dev/null
+++ b/moksha/widgetbrowser/static/httprepl.css
@@ -0,0 +1,78 @@
+.httprepl .output pre {
+ font: 10pt monospace;
+ margin: 0;
+ padding: 1px;
+ border: 1px solid #E0E0FF;
+ background-color: #F8F8FF;
+
+ white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
+ white-space: -pre-wrap; /* Opera 4 - 6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
+ http://www.w3.org/TR/css3-text/#white-space */
+ word-wrap: break-word; /* IE 5.5+ */
+}
+
+.httprepl .output pre.stdin {
+ border: none;
+ background-color: transparent;
+}
+
+form {
+ font: 10pt monospace;
+ margin: 0;
+}
+
+.httprepl .input {
+ font: 10pt monospace;
+ width: 95%;
+ border-top: none;
+ border-right: 1px dotted #E0E0FF;
+ border-bottom: none;
+ border-left: 1px dotted #E0E0FF;
+}
+
+.httprepl .tipbar {
+ position: fixed;
+ top: 10px;
+
+ /* See http://annevankesteren.nl/test/examples/ie/position-fixed.html */
+ _position:absolute;
+ _top:expression(eval(document.body.scrollTop) + 10);
+
+ right: 10px;
+
+ max-width: 50%;
+ max-height: 80%;
+ /* See http://www.svendtofte.com/code/max_width_in_ie/ */
+ width: expression(document.body.clientWidth / 2);
+ height: expression(document.body.clientHeight * 0.8);
+
+ border: 2px outset #DDCCBB;
+ background-color: #FFEEDD;
+ font: 9pt monospace;
+
+ margin: 0;
+ padding: 4px;
+
+ white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
+ white-space: -pre-wrap; /* Opera 4 - 6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
+ http://www.w3.org/TR/css3-text/#white-space */
+ word-wrap: break-word; /* IE 5.5+ */
+
+ display: none;
+ overflow: auto;
+}
+
+.httprepl .tipbar a {
+ padding: 4px;
+ text-decoration: none;
+ color: #666666;
+}
+
+.widget-dialog {
+ background: #fff;
+ z-index: 9999;
+}
diff --git a/moksha/widgetbrowser/static/httprepl.js b/moksha/widgetbrowser/static/httprepl.js
new file mode 100644
index 0000000..a85f1ef
--- /dev/null
+++ b/moksha/widgetbrowser/static/httprepl.js
@@ -0,0 +1,432 @@
+var HTTPRepl = (function ($) {
+ function http() {
+ var h;
+ if (typeof(XMLHttpRequest) != "undefined") {
+ h = new XMLHttpRequest();
+ } else {
+ try { h = new ActiveXObject("Msxml2.XMLHTTP"); }
+ catch (e) {
+ try { h = new ActiveXObject("Microsoft.XMLHTTP"); }
+ catch (E) { alert("Your browser is not supported."); }
+ }
+ }
+ return h
+ }
+
+
+ // HISTORY NAVIGATION //
+
+ function use_history(elem) {
+ var content = get_text(elem);
+ // Strip the leading prompt
+ if (elem.className == 'stdin') content = content.substr(4);
+ input.value = content;
+ input.focus();
+ }
+
+ function history_hook() {
+ use_history(this);
+ }
+
+ var current_history = undefined;
+
+ function prev_history() {
+ if (current_history == undefined) {
+ var prev = output.lastChild;
+ } else {
+ var prev = current_history.previousSibling;
+ }
+ while (prev != null && prev.className != 'stdin') {
+ prev = prev.previousSibling;
+ }
+ if (prev != null) {
+ current_history = prev;
+ use_history(prev);
+ }
+ }
+
+ function next_history() {
+ if (current_history == undefined) return;
+
+ var next = current_history.nextSibling;
+ while (next != null && next.className != 'stdin') {
+ next = next.nextSibling;
+ }
+ if (next != null) {
+ current_history = next;
+ use_history(next);
+ }
+ }
+
+
+ // CODE COMPLETION //
+
+ current_range = undefined;
+
+ function partial_line() {
+ if (document.selection) {
+ // Internet Explorer
+ current_range = document.selection.createRange();
+ var end = current_range.getBookmark().charCodeAt(2) - 2;
+ } else {
+ var end = input.selectionEnd;
+ }
+ return input.value.substring(0, end);
+ }
+
+ function insert_text(newtext) {
+ if (document.selection) {
+ // Internet Explorer
+ current_range.text = newtext;
+ current_range.select();
+ } else {
+ var start = input.selectionStart;
+ input.value = input.value.substring(0, start) + newtext + input.value.substr(input.selectionEnd);
+ var end = start + newtext.length;
+ input.setSelectionRange(end, end);
+ }
+ }
+
+ function clear_tips() {
+ tipbar.style.display = '';
+ while (tipbar.hasChildNodes()) {
+ tipbar.removeChild(tipbar.lastChild);
+ }
+ }
+
+ function show_tips() {
+ tipbar.style.display = 'block';
+ }
+
+ var intip = false;
+
+ function use_tip() {
+ insert_text(get_text(this));
+ clear_tips();
+ intip = true;
+ input.focus();
+ }
+
+ function dir() {
+ var data = partial_line();
+
+ clear_tips();
+
+ var h = http();
+ h.onreadystatechange = function() {
+ if (h.readyState == 4) {
+ try {
+ var status = h.status;
+ } catch(e) {
+ var status = "NO HTTP RESPONSE";
+ }
+ switch (status) {
+ case 200:
+ var tips = eval(h.responseText);
+ for (var i=0; i < tips.length; i++) {
+ var tiplink = document.createElement("a");
+ tiplink.onclick = use_tip;
+ tiplink.href = "javascript:void(0)";
+ set_text(tiplink, tips[i]);
+ tipbar.appendChild(tiplink);
+ tipbar.appendChild(document.createElement("br"));
+ }
+ show_tips()
+ input.focus();
+ break;
+ // Internet Explorer might return 1223 for 204
+ case 1223:
+ case 204:
+ // No tips available
+ break;
+ case 12029:
+ // Internet Explorer client could not connect to server
+ status = "NO HTTP RESPONSE";
+ case 403:
+ stdout_write("Interactive mode is disabled", false);
+ break;
+ default:
+ stdout_write(status + "\n" + h.responseText, false);
+ }
+ }
+ }
+ h.open("GET", prefix + "dir?line=" + escape(data), true);
+ h.send(null);
+ }
+
+ function doc() {
+ var data = partial_line();
+
+ clear_tips();
+
+ var h = http();
+ h.onreadystatechange = function() {
+ if (h.readyState == 4) {
+ try {
+ var status = h.status;
+ } catch(e) {
+ var status = "NO HTTP RESPONSE";
+ }
+ switch (status) {
+ case 200:
+ tipbar.appendChild(document.createTextNode(h.responseText));
+ show_tips();
+ input.focus();
+ break;
+ // Internet Explorer might return 1223 for 204
+ case 1223:
+ case 403:
+ stdout_write("Interactive mode is disabled", false);
+ break;
+ case 204:
+ // No tips available
+ break;
+ case 12029:
+ // Internet Explorer client could not connect to server
+ status = "NO HTTP RESPONSE";
+ default:
+ stdout_write(status + "\n" + h.responseText, false);
+ }
+ }
+ }
+ h.open("GET", prefix + "doc?line=" + escape(data), true);
+ h.send(null);
+ }
+
+ // COMMAND EXECUTION //
+
+ function get_text(elem) {
+ if (elem.innerText != undefined) {
+ // Internet Explorer
+ return elem.innerText;
+ } else {
+ // Mozilla
+ return elem.textContent;
+ }
+ }
+
+ function set_text(elem, newvalue) {
+ if (elem.innerText != undefined) {
+ // Internet Explorer
+ elem.innerText = newvalue;
+ } else {
+ // Mozilla
+ elem.textContent = newvalue;
+ }
+ }
+
+ function get_prompt() {
+ return get_text(prompt_);
+ }
+
+ function set_prompt(newvalue) {
+ set_text(prompt_, newvalue);
+ }
+
+ function stdout_write(content, stdin) {
+ current_history = undefined;
+ if (content == "") return;
+
+ var block = document.createElement("pre");
+ block.ondblclick = history_hook;
+ if (stdin) {
+ content = get_prompt() + content;
+ block.className = 'stdin';
+ }
+ if (block.innerText != undefined) {
+ // Internet Explorer quirkiness
+ block.innerText = content;
+ } else {
+ block.appendChild(document.createTextNode(content));
+ }
+ output.appendChild(block);
+ }
+
+ whitespace = /^\s+$/;
+
+ function push() {
+ var data = input.value;
+ // Uncomment to treat a line with only whitespace like a blank line
+ // if (whitespace.test(data)) data = "";
+
+ input.value = "";
+
+ var h = http();
+ h.onreadystatechange = function() {
+ if (h.readyState == 4) {
+ stdout_write(data, true);
+ try {
+ var status = h.status;
+ } catch(e) {
+ var status = "NO HTTP RESPONSE";
+ }
+ switch (status) {
+ case 200:
+ set_prompt(">>> ");
+ var response = h.responseText;
+ if (!handle_widget_output(response)) {
+ stdout_write(response, false);
+ }
+ break;
+ // Internet Explorer might return 1223 for 204
+ case 1223:
+ case 204:
+ set_prompt("... ");
+ // input.value *should* be blank, but just in case...
+ input.value = " " + input.value;
+ break;
+ case 403:
+ stdout_write("Interactive mode is disabled", false);
+ break;
+ case 12029:
+ // Internet Explorer client could not connect to server
+ status = "NO HTTP RESPONSE";
+ default:
+ stdout_write(status + "\n" + h.responseText, false);
+ }
+ input.focus();
+ }
+ }
+ h.open("POST", prefix + "push", true);
+ h.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ h.send("line=" + escape(data));
+ }
+
+
+ function escape(data) {
+ data = data.replace(/%/gi, "%25");
+ data = data.replace(/&/gi, "%26");
+ data = data.replace(/[+]/gi, "%2B");
+ data = data.replace(/;/gi, "%3B");
+ return data;
+ }
+
+
+ // SETUP //
+
+ function mapKeys(key_code) {
+ if (intip) {
+ intip = false;
+ // Trap the bubbling keyup event from a tiplink. This means that,
+ // if you actually click a tiplink instead of tab and hit 'enter',
+ // you have to hit 'enter' twice to push the line. :(
+ if (key_code == 13) return;
+ }
+ switch(key_code) {
+ case 8: // backspace
+ clear_tips();
+ break;
+ case 13: // enter
+ clear_tips();
+ push();
+ break;
+ case 38: // up arrow
+ prev_history();
+ break;
+ case 40: // down arrow
+ next_history();
+ break;
+ case 48: // close paren "("
+ clear_tips();
+ break;
+ case 57: // open paren "("
+ doc();
+ break;
+ case 190: // period "."
+ dir();
+ break;
+ }
+ }
+
+ function trapKeys(e) {
+ if (!e) var e = window.event;
+ mapKeys(e.keyCode);
+ }
+
+ // WIDGET DIALOGS //
+
+ var new_id = (function make_counter(value) {
+ var state = {value: value || 0};
+ function next() {
+ state.value ++;
+ return 'widget-dialog-' + state.value;
+ }
+ return next;
+ })();
+
+ function open_dialog(config) {
+ var c = $.extend({}, {height:450, width:600}, config);
+ var iframe = $('<iframe><iframe>');
+ iframe.attr({id: new_id(), 'class': 'widget-dialog'});
+ function setSize(size) {
+ var attr = {
+ height: Math.max(0, Math.round(size.height-60)),
+ width: Math.max(0, Math.round(size.width-40))
+ }
+ iframe.attr(attr);
+ }
+ function onResizeStart(event, data) {
+ // Hide the iframe so it doesn't captute mouse events while dragging
+ // the resize handlers
+ iframe.hide();
+ }
+ function onResizeStop(event, data) {
+ setSize(data.instance.size);
+ iframe.show();
+ }
+ function onClose() {
+ iframe.remove();
+ input.focus();
+ }
+ iframe.appendTo(httprepl).dialog(config)
+ .bind('dialogclose', onClose)
+ .trigger('setData.dialog', ['resizeStart', onResizeStart])
+ .trigger('setData.dialog', ['resizeStop', onResizeStop])
+ .attr('src', config.url)
+ .dialog('open');
+ setSize(c);
+ }
+
+ var displayed_widget = /DeferredDisplay\((\d+)[^']*'([^']+)'/;
+
+ function handle_widget_output(response) {
+ var match = displayed_widget(response);
+ if (match) {
+ var config = {
+ url: prefix + 'widget_output/' + match[1],
+ height: 500,
+ width: 750,
+ title: match[2]
+ }
+ open_dialog(config);
+ return true;
+ }
+ return false;
+ }
+ var httprepl = $(''
+ +'<div class="httprepl">'
+ + '<div class="output"></div>'
+ + '<form action="" class="terminal">'
+ + '<div class="tipbar"></div>'
+ + '<nobr>'
+ + '<span class="prompt">>>> </span>'
+ + '<input type="text" class="input" size=60" />'
+ + '</nobr>'
+ + '</form>'
+ +'</div>'
+ );
+ var prefix = '';
+ var input = $('.input', httprepl)[0];
+ input.onkeyup = trapKeys;
+ var output = $('.output', httprepl)[0];
+ var tipbar = $('.tipbar', httprepl)[0];
+ var prompt_ = $('.prompt', httprepl)[0];
+ $('form', httprepl).submit(function() { return false });
+
+ return {
+ render: function(el, config) {
+ prefix = config.prefix || '';
+ httprepl.appendTo($(el));
+ }
+ }
+})(jQuery);
diff --git a/moksha/widgetbrowser/static/jquery.js b/moksha/widgetbrowser/static/jquery.js
new file mode 100644
index 0000000..ea64073
--- /dev/null
+++ b/moksha/widgetbrowser/static/jquery.js
@@ -0,0 +1,3436 @@
+(function(){
+/*
+ * jQuery 1.2.4a - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-04-08 13:40:03 -0300 (ter, 08 abr 2008) $
+ * $Rev: 5214 $
+ */
+
+// Map over jQuery in case of overwrite
+if ( window.jQuery )
+ var _jQuery = window.jQuery;
+
+var jQuery = window.jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.prototype.init( selector, context );
+};
+
+// Map over the $ in case of overwrite
+if ( window.$ )
+ var _$ = window.$;
+
+// Map the jQuery namespace to the '$' one
+window.$ = jQuery;
+
+// A simple way to check for HTML strings or ID strings
+// (both of which we optimize for)
+var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
+
+// Is it a simple selector
+var isSimple = /^.[^:#\[\.]*$/;
+
+jQuery.fn = jQuery.prototype = {
+ init: function( selector, context ) {
+ // Make sure that a selection was provided
+ selector = selector || document;
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // Handle HTML strings
+ } else if ( typeof selector == "string" ) {
+ // Are we dealing with HTML string or an ID?
+ var match = quickExpr.exec( selector );
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] )
+ selector = jQuery.clean( [ match[1] ], context );
+
+ // HANDLE: $("#id")
+ else {
+ var elem = document.getElementById( match[3] );
+
+ // Make sure an element was located
+ if ( elem )
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id != match[3] )
+ return jQuery().find( selector );
+
+ // Otherwise, we inject the element directly into the jQuery object
+ else {
+ this[0] = elem;
+ this.length = 1;
+ return this;
+ }
+
+ else
+ selector = [];
+ }
+
+ // HANDLE: $(expr, [context])
+ // (which is just equivalent to: $(content).find(expr)
+ } else
+ return new jQuery( context ).find( selector );
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) )
+ return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
+
+ return this.setArray(
+ // HANDLE: $(array)
+ selector.constructor == Array && selector ||
+
+ // HANDLE: $(arraylike)
+ // Watch for when an array-like object, contains DOM nodes, is passed in as the selector
+ (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) ||
+
+ // HANDLE: $(*)
+ [ selector ] );
+ },
+
+ // The current version of jQuery being used
+ jquery: "1.2.4a",
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ // The number of elements contained in the matched element set
+ length: 0,
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == undefined ?
+
+ // Return a 'clean' array
+ jQuery.makeArray( this ) :
+
+ // Return just the object
+ this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+ // Build a new jQuery matched element set
+ var ret = jQuery( elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Force the current matched set of elements to become
+ // the specified array of elements (destroying the stack in the process)
+ // You should use pushStack() in order to do this, but maintain the stack
+ setArray: function( elems ) {
+ // Resetting the length to 0, then using the native Array push
+ // is a super-fast way to populate an object with array-like properties
+ this.length = 0;
+ Array.prototype.push.apply( this, elems );
+
+ return this;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ var ret = -1;
+
+ // Locate the position of the desired element
+ this.each(function(i){
+ if ( this == elem )
+ ret = i;
+ });
+
+ return ret;
+ },
+
+ attr: function( name, value, type ) {
+ var options = name;
+
+ // Look for the case where we're accessing a style value
+ if ( name.constructor == String )
+ if ( value == undefined )
+ return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined;
+
+ else {
+ options = {};
+ options[ name ] = value;
+ }
+
+ // Check to see if we're setting style values
+ return this.each(function(i){
+ // Set all the styles
+ for ( name in options )
+ jQuery.attr(
+ type ?
+ this.style :
+ this,
+ name, jQuery.prop( this, options[ name ], type, i, name )
+ );
+ });
+ },
+
+ css: function( key, value ) {
+ // ignore negative width and height values
+ if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
+ value = undefined;
+ return this.attr( key, value, "curCSS" );
+ },
+
+ text: function( text ) {
+ if ( typeof text != "object" && text != null )
+ return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+
+ var ret = "";
+
+ jQuery.each( text || this, function(){
+ jQuery.each( this.childNodes, function(){
+ if ( this.nodeType != 8 )
+ ret += this.nodeType != 1 ?
+ this.nodeValue :
+ jQuery.fn.text( [ this ] );
+ });
+ });
+
+ return ret;
+ },
+
+ wrapAll: function( html ) {
+ if ( this[0] )
+ // The elements to wrap the target around
+ jQuery( html, this[0].ownerDocument )
+ .clone()
+ .insertBefore( this[0] )
+ .map(function(){
+ var elem = this;
+
+ while ( elem.firstChild )
+ elem = elem.firstChild;
+
+ return elem;
+ })
+ .append(this);
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ return this.each(function(){
+ jQuery( this ).contents().wrapAll( html );
+ });
+ },
+
+ wrap: function( html ) {
+ return this.each(function(){
+ jQuery( this ).wrapAll( html );
+ });
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, false, function(elem){
+ if (this.nodeType == 1)
+ this.appendChild( elem );
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, true, function(elem){
+ if (this.nodeType == 1)
+ this.insertBefore( elem, this.firstChild );
+ });
+ },
+
+ before: function() {
+ return this.domManip(arguments, false, false, function(elem){
+ this.parentNode.insertBefore( elem, this );
+ });
+ },
+
+ after: function() {
+ return this.domManip(arguments, false, true, function(elem){
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ },
+
+ end: function() {
+ return this.prevObject || jQuery( [] );
+ },
+
+ find: function( selector ) {
+ var elems = jQuery.map(this, function(elem){
+ return jQuery.find( selector, elem );
+ });
+
+ return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
+ jQuery.unique( elems ) :
+ elems );
+ },
+
+ clone: function( events ) {
+ // Do the clone
+ var ret = this.map(function(){
+ if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
+ // IE copies events bound via attachEvent when
+ // using cloneNode. Calling detachEvent on the
+ // clone will also remove the events from the orignal
+ // In order to get around this, we use innerHTML.
+ // Unfortunately, this means some modifications to
+ // attributes in IE that are actually only stored
+ // as properties will not be copied (such as the
+ // the name attribute on an input).
+ var clone = this.cloneNode(true),
+ container = document.createElement("div");
+ container.appendChild(clone);
+ return jQuery.clean([container.innerHTML])[0];
+ } else
+ return this.cloneNode(true);
+ });
+
+ // Need to set the expando to null on the cloned set if it exists
+ // removeData doesn't work here, IE removes it from the original as well
+ // this is primarily for IE but the data expando shouldn't be copied over in any browser
+ var clone = ret.find("*").andSelf().each(function(){
+ if ( this[ expando ] != undefined )
+ this[ expando ] = null;
+ });
+
+ // Copy the events from the original to the clone
+ if ( events === true )
+ this.find("*").andSelf().each(function(i){
+ if (this.nodeType == 3)
+ return;
+ var events = jQuery.data( this, "events" );
+
+ for ( var type in events )
+ for ( var handler in events[ type ] )
+ jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
+ });
+
+ // Return the cloned set
+ return ret;
+ },
+
+ filter: function( selector ) {
+ return this.pushStack(
+ jQuery.isFunction( selector ) &&
+ jQuery.grep(this, function(elem, i){
+ return selector.call( elem, i );
+ }) ||
+
+ jQuery.multiFilter( selector, this ) );
+ },
+
+ not: function( selector ) {
+ if ( selector.constructor == String )
+ // test special case where just one selector is passed in
+ if ( isSimple.test( selector ) )
+ return this.pushStack( jQuery.multiFilter( selector, this, true ) );
+ else
+ selector = jQuery.multiFilter( selector, this );
+
+ var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
+ return this.filter(function() {
+ return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
+ });
+ },
+
+ add: function( selector ) {
+ return !selector ? this : this.pushStack( jQuery.merge(
+ this.get(),
+ selector.constructor == String ?
+ jQuery( selector ).get() :
+ selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ?
+ selector : [selector] ) );
+ },
+
+ is: function( selector ) {
+ return selector ?
+ jQuery.multiFilter( selector, this ).length > 0 :
+ false;
+ },
+
+ hasClass: function( selector ) {
+ return this.is( "." + selector );
+ },
+
+ val: function( value ) {
+ if ( value == undefined ) {
+
+ if ( this.length ) {
+ var elem = this[0];
+
+ // We need to handle select boxes special
+ if ( jQuery.nodeName( elem, "select" ) ) {
+ var index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type == "select-one";
+
+ // Nothing was selected
+ if ( index < 0 )
+ return null;
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ if ( option.selected ) {
+ // Get the specifc value for the option
+ value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
+
+ // We don't need an array for one selects
+ if ( one )
+ return value;
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+
+ // Everything else, we just grab the value
+ } else
+ return (this[0].value || "").replace(/\r/g, "");
+
+ }
+
+ return undefined;
+ }
+
+ return this.each(function(){
+ if ( this.nodeType != 1 )
+ return;
+
+ if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
+ this.checked = (jQuery.inArray(this.value, value) >= 0 ||
+ jQuery.inArray(this.name, value) >= 0);
+
+ else if ( jQuery.nodeName( this, "select" ) ) {
+ var values = value.constructor == Array ?
+ value :
+ [ value ];
+
+ jQuery( "option", this ).each(function(){
+ this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
+ jQuery.inArray( this.text, values ) >= 0);
+ });
+
+ if ( !values.length )
+ this.selectedIndex = -1;
+
+ } else
+ this.value = value;
+ });
+ },
+
+ html: function( value ) {
+ return value == undefined ?
+ (this.length ?
+ this[0].innerHTML :
+ null) :
+ this.empty().append( value );
+ },
+
+ replaceWith: function( value ) {
+ return this.after( value ).remove();
+ },
+
+ eq: function( i ) {
+ return this.slice( i, i + 1 );
+ },
+
+ slice: function() {
+ return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function(elem, i){
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ },
+
+ data: function( key, value ){
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value == null ) {
+ var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ if ( data == undefined && this.length )
+ data = jQuery.data( this[0], key );
+
+ return data == null && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ } else
+ return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
+ jQuery.data( this, key, value );
+ });
+ },
+
+ removeData: function( key ){
+ return this.each(function(){
+ jQuery.removeData( this, key );
+ });
+ },
+
+ domManip: function( args, table, reverse, callback ) {
+ var clone = this.length > 1, elems;
+
+ return this.each(function(){
+ if ( !elems ) {
+ elems = jQuery.clean( args, this.ownerDocument );
+
+ if ( reverse )
+ elems.reverse();
+ }
+
+ var obj = this;
+
+ if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
+ obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
+
+ var scripts = jQuery( [] );
+
+ jQuery.each(elems, function(){
+ var elem = clone ?
+ jQuery( this ).clone( true )[0] :
+ this;
+
+ // execute all scripts after the elements have been injected
+ if ( jQuery.nodeName( elem, "script" ) ) {
+ scripts = scripts.add( elem );
+ } else {
+ // Remove any inner scripts for later evaluation
+ if ( elem.nodeType == 1 )
+ scripts = scripts.add( jQuery( "script", elem ).remove() );
+
+ // Inject the elements into the document
+ callback.call( obj, elem );
+ }
+ });
+
+ scripts.each( evalScript );
+ });
+ }
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.prototype.init.prototype = jQuery.prototype;
+
+function evalScript( i, elem ) {
+ if ( elem.src )
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+
+ else
+ jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+
+ if ( elem.parentNode )
+ elem.parentNode.removeChild( elem );
+}
+
+jQuery.extend = jQuery.fn.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+ // Handle a deep copy situation
+ if ( target.constructor == Boolean ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target != "object" && typeof target != "function" )
+ target = {};
+
+ // extend jQuery itself if only one argument is passed
+ if ( length == 1 ) {
+ target = this;
+ i = 0;
+ }
+
+ for ( ; i < length; i++ )
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null )
+ // Extend the base object
+ for ( var name in options ) {
+ // Prevent never-ending loop
+ if ( target === options[ name ] )
+ continue;
+
+ // Recurse if we're merging object values
+ if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType )
+ target[ name ] = jQuery.extend( deep, target[ name ], options[ name ] );
+
+ // Don't bring in undefined values
+ else if ( options[ name ] != undefined )
+ target[ name ] = options[ name ];
+
+ }
+
+ // Return the modified object
+ return target;
+};
+
+var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {};
+
+// exclude the following css properties to add px
+var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ window.$ = _$;
+
+ if ( deep )
+ window.jQuery = _jQuery;
+
+ return jQuery;
+ },
+
+ // See test/unit/core.js for details concerning this function.
+ isFunction: function( fn ) {
+ return !!fn && typeof fn != "string" && !fn.nodeName &&
+ fn.constructor != Array && /function/i.test( fn + "" );
+ },
+
+ // check if an element is in a (or is an) XML document
+ isXMLDoc: function( elem ) {
+ return elem.documentElement && !elem.body ||
+ elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+ },
+
+ // Evalulates a script in a global context
+ globalEval: function( data ) {
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Inspired by code by Andrea Giammarchi
+ // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom...
+ var head = document.getElementsByTagName("head")[0] || document.documentElement,
+ script = document.createElement("script");
+
+ script.type = "text/javascript";
+ if ( jQuery.browser.msie )
+ script.text = data;
+ else
+ script.appendChild( document.createTextNode( data ) );
+
+ head.appendChild( script );
+ head.removeChild( script );
+ }
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
+ },
+
+ cache: {},
+
+ data: function( elem, name, data ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // Compute a unique ID for the element
+ if ( !id )
+ id = elem[ expando ] = ++uuid;
+
+ // Only generate the data cache if we're
+ // trying to access or manipulate it
+ if ( name && !jQuery.cache[ id ] )
+ jQuery.cache[ id ] = {};
+
+ // Prevent overriding the named cache with undefined values
+ if ( data != undefined )
+ jQuery.cache[ id ][ name ] = data;
+
+ // Return the named cache data, or the ID for the element
+ return name ?
+ jQuery.cache[ id ][ name ] :
+ id;
+ },
+
+ removeData: function( elem, name ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // If we want to remove a specific section of the element's data
+ if ( name ) {
+ if ( jQuery.cache[ id ] ) {
+ // Remove the section of cache data
+ delete jQuery.cache[ id ][ name ];
+
+ // If we've removed all the data, remove the element's cache
+ name = "";
+
+ for ( name in jQuery.cache[ id ] )
+ break;
+
+ if ( !name )
+ jQuery.removeData( elem );
+ }
+
+ // Otherwise, we want to remove all of the element's data
+ } else {
+ // Clean up the element expando
+ try {
+ delete elem[ expando ];
+ } catch(e){
+ // IE has trouble directly removing the expando
+ // but it's ok with using removeAttribute
+ if ( elem.removeAttribute )
+ elem.removeAttribute( expando );
+ }
+
+ // Completely remove the data cache
+ delete jQuery.cache[ id ];
+ }
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ if ( args ) {
+ if ( object.length == undefined ) {
+ for ( var name in object )
+ if ( callback.apply( object[ name ], args ) === false )
+ break;
+ } else
+ for ( var i = 0, length = object.length; i < length; i++ )
+ if ( callback.apply( object[ i ], args ) === false )
+ break;
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( object.length == undefined ) {
+ for ( var name in object )
+ if ( callback.call( object[ name ], name, object[ name ] ) === false )
+ break;
+ } else
+ for ( var i = 0, length = object.length, value = object[0];
+ i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
+ }
+
+ return object;
+ },
+
+ prop: function( elem, value, type, i, name ) {
+ // Handle executable functions
+ if ( jQuery.isFunction( value ) )
+ value = value.call( elem, i );
+
+ // Handle passing in a number to a CSS property
+ return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
+ value + "px" :
+ value;
+ },
+
+ className: {
+ // internal only, use addClass("class")
+ add: function( elem, classNames ) {
+ jQuery.each((classNames || "").split(/\s+/), function(i, className){
+ if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+ elem.className += (elem.className ? " " : "") + className;
+ });
+ },
+
+ // internal only, use removeClass("class")
+ remove: function( elem, classNames ) {
+ if (elem.nodeType == 1)
+ elem.className = classNames != undefined ?
+ jQuery.grep(elem.className.split(/\s+/), function(className){
+ return !jQuery.className.has( classNames, className );
+ }).join(" ") :
+ "";
+ },
+
+ // internal only, use is(".class")
+ has: function( elem, className ) {
+ return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ callback.call( elem );
+
+ // Revert the old values
+ for ( var name in options )
+ elem.style[ name ] = old[ name ];
+ },
+
+ css: function( elem, name, force ) {
+ if ( name == "width" || name == "height" ) {
+ var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
+
+ function getWH() {
+ val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
+ var padding = 0, border = 0;
+ jQuery.each( which, function() {
+ padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+ border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+ });
+ val -= Math.round(padding + border);
+ }
+
+ if ( jQuery(elem).is(":visible") )
+ getWH();
+ else
+ jQuery.swap( elem, props, getWH );
+
+ return Math.max(0, val);
+ }
+
+ return jQuery.curCSS( elem, name, force );
+ },
+
+ curCSS: function( elem, name, force ) {
+ var ret;
+
+ // A helper method for determining if an element's values are broken
+ function color( elem ) {
+ if ( !jQuery.browser.safari )
+ return false;
+
+ var ret = document.defaultView.getComputedStyle( elem, null );
+ return !ret || ret.getPropertyValue("color") == "";
+ }
+
+ // We need to handle opacity special in IE
+ if ( name == "opacity" && jQuery.browser.msie ) {
+ ret = jQuery.attr( elem.style, "opacity" );
+
+ return ret == "" ?
+ "1" :
+ ret;
+ }
+ // Opera sometimes will give the wrong display answer, this fixes it, see #2037
+ if ( jQuery.browser.opera && name == "display" ) {
+ var save = elem.style.outline;
+ elem.style.outline = "0 solid black";
+ elem.style.outline = save;
+ }
+
+ // Make sure we're using the right name for getting the float value
+ if ( name.match( /float/i ) )
+ name = styleFloat;
+
+ if ( !force && elem.style && elem.style[ name ] )
+ ret = elem.style[ name ];
+
+ else if ( document.defaultView && document.defaultView.getComputedStyle ) {
+
+ // Only "float" is needed here
+ if ( name.match( /float/i ) )
+ name = "float";
+
+ name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+
+ var getComputedStyle = document.defaultView.getComputedStyle( elem, null );
+
+ if ( getComputedStyle && !color( elem ) )
+ ret = getComputedStyle.getPropertyValue( name );
+
+ // If the element isn't reporting its values properly in Safari
+ // then some display: none elements are involved
+ else {
+ var swap = [], stack = [];
+
+ // Locate all of the parent display: none elements
+ for ( var a = elem; a && color(a); a = a.parentNode )
+ stack.unshift(a);
+
+ // Go through and make them visible, but in reverse
+ // (It would be better if we knew the exact display type that they had)
+ for ( var i = 0; i < stack.length; i++ )
+ if ( color( stack[ i ] ) ) {
+ swap[ i ] = stack[ i ].style.display;
+ stack[ i ].style.display = "block";
+ }
+
+ // Since we flip the display style, we have to handle that
+ // one special, otherwise get the value
+ ret = name == "display" && swap[ stack.length - 1 ] != null ?
+ "none" :
+ ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || "";
+
+ // Finally, revert the display styles back
+ for ( var i = 0; i < swap.length; i++ )
+ if ( swap[ i ] != null )
+ stack[ i ].style.display = swap[ i ];
+ }
+
+ // We should always get a number back from opacity
+ if ( name == "opacity" && ret == "" )
+ ret = "1";
+
+ } else if ( elem.currentStyle ) {
+ var camelCase = name.replace(/\-(\w)/g, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+ // Remember the original values
+ var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ elem.style.left = ret || 0;
+ ret = elem.style.pixelLeft + "px";
+
+ // Revert the changed values
+ elem.style.left = style;
+ elem.runtimeStyle.left = runtimeStyle;
+ }
+ }
+
+ return ret;
+ },
+
+ clean: function( elems, context ) {
+ var ret = [];
+ context = context || document;
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if (typeof context.createElement == 'undefined')
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+
+ jQuery.each(elems, function(i, elem){
+ if ( !elem )
+ return;
+
+ if ( elem.constructor == Number )
+ elem = elem.toString();
+
+ // Convert html string into DOM nodes
+ if ( typeof elem == "string" ) {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
+ return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
+ all :
+ front + "></" + tag + ">";
+ });
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
+
+ var wrap =
+ // option or optgroup
+ !tags.indexOf("<opt") &&
+ [ 1, "<select multiple='multiple'>", "</select>" ] ||
+
+ !tags.indexOf("<leg") &&
+ [ 1, "<fieldset>", "</fieldset>" ] ||
+
+ tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
+ [ 1, "<table>", "</table>" ] ||
+
+ !tags.indexOf("<tr") &&
+ [ 2, "<table><tbody>", "</tbody></table>" ] ||
+
+ // <thead> matched above
+ (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
+ [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
+
+ !tags.indexOf("<col") &&
+ [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
+
+ // IE can't serialize <link> and <script> tags normally
+ jQuery.browser.msie &&
+ [ 1, "div<div>", "</div>" ] ||
+
+ [ 0, "", "" ];
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( wrap[0]-- )
+ div = div.lastChild;
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( jQuery.browser.msie ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
+ div.childNodes :
+ [];
+
+ for ( var j = tbody.length - 1; j >= 0 ; --j )
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( /^\s/.test( elem ) )
+ div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+
+ }
+
+ elem = jQuery.makeArray( div.childNodes );
+ }
+
+ if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
+ return;
+
+ if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
+ ret.push( elem );
+
+ else
+ ret = jQuery.merge( ret, elem );
+
+ });
+
+ return ret;
+ },
+
+ attr: function( elem, name, value ) {
+ // don't set attributes on text and comment nodes
+ if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
+ return undefined;
+
+ var fix = jQuery.isXMLDoc( elem ) ?
+ {} :
+ jQuery.props;
+
+ // Safari mis-reports the default selected property of a hidden option
+ // Accessing the parent's selectedIndex property fixes it
+ if ( name == "selected" && jQuery.browser.safari )
+ elem.parentNode.selectedIndex;
+
+ // Certain attributes only work when accessed via the old DOM 0 way
+ if ( fix[ name ] ) {
+ if ( value != undefined )
+ elem[ fix[ name ] ] = value;
+
+ return elem[ fix[ name ] ];
+
+ } else if ( jQuery.browser.msie && name == "style" )
+ return jQuery.attr( elem.style, "cssText", value );
+
+ else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName( elem, "form" ) && (name == "action" || name == "method") )
+ return elem.getAttributeNode( name ).nodeValue;
+
+ // IE elem.getAttribute passes even for style
+ else if ( elem.tagName ) {
+
+ if ( value != undefined ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
+ throw "type property can't be changed";
+
+ // convert the value to a string (all browsers do this but IE) see #1070
+ elem.setAttribute( name, "" + value );
+ }
+
+ if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) )
+ return elem.getAttribute( name, 2 );
+
+ return elem.getAttribute( name );
+
+ // elem is actually elem.style ... set the style
+ } else {
+ // IE actually uses filters for opacity
+ if ( name == "opacity" && jQuery.browser.msie ) {
+ if ( value != undefined ) {
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ elem.zoom = 1;
+
+ // Set the alpha filter to set the opacity
+ elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
+ (parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+ }
+
+ return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+ (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() :
+ "";
+ }
+
+ name = name.replace(/-([a-z])/ig, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ if ( value != undefined )
+ elem[ name ] = value;
+
+ return elem[ name ];
+ }
+ },
+
+ trim: function( text ) {
+ return (text || "").replace( /^\s+|\s+$/g, "" );
+ },
+
+ makeArray: function( array ) {
+ var ret = [];
+
+ // Need to use typeof to fight Safari childNodes crashes
+ if ( array.constructor != Array )
+ for ( var i = 0, length = array.length; i < length; i++ )
+ ret.push( array[ i ] );
+ else
+ ret = array.slice( 0 );
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+ for ( var i = 0, length = array.length; i < length; i++ )
+ if ( array[ i ] == elem )
+ return i;
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ // We have to loop this way because IE & Opera overwrite the length
+ // expando of getElementsByTagName
+
+ // Also, we need to make sure that the correct elements are being returned
+ // (IE returns comment nodes in a '*' query)
+ if ( jQuery.browser.msie ) {
+ for ( var i = 0; second[ i ]; i++ )
+ if ( second[ i ].nodeType != 8 )
+ first.push( second[ i ] );
+
+ } else
+ for ( var i = 0; second[ i ]; i++ )
+ first.push( second[ i ] );
+
+ return first;
+ },
+
+ unique: function( array ) {
+ var ret = [], done = {};
+
+ try {
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ var id = jQuery.data( array[ i ] );
+
+ if ( !done[ id ] ) {
+ done[ id ] = true;
+ ret.push( array[ i ] );
+ }
+ }
+
+ } catch( e ) {
+ ret = array;
+ }
+
+ return ret;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [];
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ )
+ if ( !inv && callback( elems[ i ], i ) || inv && !callback( elems[ i ], i ) )
+ ret.push( elems[ i ] );
+
+ return ret;
+ },
+
+ map: function( elems, callback ) {
+ var ret = [];
+
+ // Go through the array, translating each of the items to their
+ // new value (or values).
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ var value = callback( elems[ i ], i );
+
+ if ( value !== null && value != undefined ) {
+ if ( value.constructor != Array )
+ value = [ value ];
+
+ ret = ret.concat( value );
+ }
+ }
+
+ return ret;
+ }
+});
+
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+ version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
+ safari: /webkit/.test( userAgent ),
+ opera: /opera/.test( userAgent ),
+ msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+ mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+
+var styleFloat = jQuery.browser.msie ?
+ "styleFloat" :
+ "cssFloat";
+
+jQuery.extend({
+ // Check to see if the W3C box model is being used
+ boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
+
+ props: {
+ "for": "htmlFor",
+ "class": "className",
+ "float": styleFloat,
+ cssFloat: styleFloat,
+ styleFloat: styleFloat,
+ innerHTML: "innerHTML",
+ className: "className",
+ value: "value",
+ disabled: "disabled",
+ checked: "checked",
+ readonly: "readOnly",
+ selected: "selected",
+ maxlength: "maxLength",
+ selectedIndex: "selectedIndex",
+ defaultValue: "defaultValue",
+ tagName: "tagName",
+ nodeName: "nodeName"
+ }
+});
+
+jQuery.each({
+ parent: function(elem){return elem.parentNode;},
+ parents: function(elem){return jQuery.dir(elem,"parentNode");},
+ next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
+ prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
+ nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
+ prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
+ siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
+ children: function(elem){return jQuery.sibling(elem.firstChild);},
+ contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
+}, function(name, fn){
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = jQuery.map( this, fn );
+
+ if ( selector && typeof selector == "string" )
+ ret = jQuery.multiFilter( selector, ret );
+
+ return this.pushStack( jQuery.unique( ret ) );
+ };
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function(name, original){
+ jQuery.fn[ name ] = function() {
+ var args = arguments;
+
+ return this.each(function(){
+ for ( var i = 0, length = args.length; i < length; i++ )
+ jQuery( args[ i ] )[ original ]( this );
+ });
+ };
+});
+
+jQuery.each({
+ removeAttr: function( name ) {
+ jQuery.attr( this, name, "" );
+ if (this.nodeType == 1)
+ this.removeAttribute( name );
+ },
+
+ addClass: function( classNames ) {
+ jQuery.className.add( this, classNames );
+ },
+
+ removeClass: function( classNames ) {
+ jQuery.className.remove( this, classNames );
+ },
+
+ toggleClass: function( classNames ) {
+ jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
+ },
+
+ remove: function( selector ) {
+ if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
+ // Prevent memory leaks
+ jQuery( "*", this ).add(this).each(function(){
+ jQuery.event.remove(this);
+ jQuery.removeData(this);
+ });
+ if (this.parentNode)
+ this.parentNode.removeChild( this );
+ }
+ },
+
+ empty: function() {
+ // Remove element nodes and prevent memory leaks
+ jQuery( ">*", this ).remove();
+
+ // Remove any remaining nodes
+ while ( this.firstChild )
+ this.removeChild( this.firstChild );
+ }
+}, function(name, fn){
+ jQuery.fn[ name ] = function(){
+ return this.each( fn, arguments );
+ };
+});
+
+jQuery.each([ "Height", "Width" ], function(i, name){
+ var type = name.toLowerCase();
+
+ jQuery.fn[ type ] = function( size ) {
+ // Get window width or height
+ return this[0] == window ?
+ // Opera reports document.body.client[Width/Height] properly in both quirks and standards
+ jQuery.browser.opera && document.body[ "client" + name ] ||
+
+ // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
+ jQuery.browser.safari && window[ "inner" + name ] ||
+
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
+
+ // Get document width or height
+ this[0] == document ?
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ Math.max(
+ Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
+ Math.max(document.body["offset" + name], document.documentElement["offset" + name])
+ ) :
+
+ // Get or set width or height on the element
+ size == undefined ?
+ // Get width or height on the element
+ (this.length ? jQuery.css( this[0], type ) : null) :
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ this.css( type, size.constructor == String ? size : size + "px" );
+ };
+});
+
+var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
+ "(?:[\\w*_-]|\\\\.)" :
+ "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
+ quickChild = new RegExp("^>\\s*(" + chars + "+)"),
+ quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
+ quickClass = new RegExp("^([#.]?)(" + chars + "*)");
+
+jQuery.extend({
+ expr: {
+ "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
+ "#": function(a,i,m){return a.getAttribute("id")==m[2];},
+ ":": {
+ // Position Checks
+ lt: function(a,i,m){return i<m[3]-0;},
+ gt: function(a,i,m){return i>m[3]-0;},
+ nth: function(a,i,m){return m[3]-0==i;},
+ eq: function(a,i,m){return m[3]-0==i;},
+ first: function(a,i){return i==0;},
+ last: function(a,i,m,r){return i==r.length-1;},
+ even: function(a,i){return i%2==0;},
+ odd: function(a,i){return i%2;},
+
+ // Child Checks
+ "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
+ "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
+ "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
+
+ // Parent Checks
+ parent: function(a){return a.firstChild;},
+ empty: function(a){return !a.firstChild;},
+
+ // Text Check
+ contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
+
+ // Visibility
+ visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
+ hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
+
+ // Form attributes
+ enabled: function(a){return !a.disabled;},
+ disabled: function(a){return a.disabled;},
+ checked: function(a){return a.checked;},
+ selected: function(a){return a.selected||jQuery.attr(a,"selected");},
+
+ // Form elements
+ text: function(a){return "text"==a.type;},
+ radio: function(a){return "radio"==a.type;},
+ checkbox: function(a){return "checkbox"==a.type;},
+ file: function(a){return "file"==a.type;},
+ password: function(a){return "password"==a.type;},
+ submit: function(a){return "submit"==a.type;},
+ image: function(a){return "image"==a.type;},
+ reset: function(a){return "reset"==a.type;},
+ button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
+ input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
+
+ // :has()
+ has: function(a,i,m){return jQuery.find(m[3],a).length;},
+
+ // :header
+ header: function(a){return /h\d/i.test(a.nodeName);},
+
+ // :animated
+ animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
+ }
+ },
+
+ // The regular expressions that power the parsing engine
+ parse: [
+ // Match: [@value='test'], [@foo]
+ /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
+
+ // Match: :contains('foo')
+ /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
+
+ // Match: :even, :last-chlid, #id, .class
+ new RegExp("^([:.#]*)(" + chars + "+)")
+ ],
+
+ multiFilter: function( expr, elems, not ) {
+ var old, cur = [];
+
+ while ( expr && expr != old ) {
+ old = expr;
+ var f = jQuery.filter( expr, elems, not );
+ expr = f.t.replace(/^\s*,\s*/, "" );
+ cur = not ? elems = f.r : jQuery.merge( cur, f.r );
+ }
+
+ return cur;
+ },
+
+ find: function( t, context ) {
+ // Quickly handle non-string expressions
+ if ( typeof t != "string" )
+ return [ t ];
+
+ // check to make sure context is a DOM element or a document
+ if ( context && context.nodeType != 1 && context.nodeType != 9)
+ return [ ];
+
+ // Set the correct context (if none is provided)
+ context = context || document;
+
+ // Initialize the search
+ var ret = [context], done = [], last, nodeName;
+
+ // Continue while a selector expression exists, and while
+ // we're no longer looping upon ourselves
+ while ( t && last != t ) {
+ var r = [];
+ last = t;
+
+ t = jQuery.trim(t);
+
+ var foundToken = false;
+
+ // An attempt at speeding up child selectors that
+ // point to a specific element tag
+ var re = quickChild;
+ var m = re.exec(t);
+
+ if ( m ) {
+ nodeName = m[1].toUpperCase();
+
+ // Perform our own iteration and filter
+ for ( var i = 0; ret[i]; i++ )
+ for ( var c = ret[i].firstChild; c; c = c.nextSibling )
+ if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
+ r.push( c );
+
+ ret = r;
+ t = t.replace( re, "" );
+ if ( t.indexOf(" ") == 0 ) continue;
+ foundToken = true;
+ } else {
+ re = /^([>+~])\s*(\w*)/i;
+
+ if ( (m = re.exec(t)) != null ) {
+ r = [];
+
+ var merge = {};
+ nodeName = m[2].toUpperCase();
+ m = m[1];
+
+ for ( var j = 0, rl = ret.length; j < rl; j++ ) {
+ var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
+ for ( ; n; n = n.nextSibling )
+ if ( n.nodeType == 1 ) {
+ var id = jQuery.data(n);
+
+ if ( m == "~" && merge[id] ) break;
+
+ if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
+ if ( m == "~" ) merge[id] = true;
+ r.push( n );
+ }
+
+ if ( m == "+" ) break;
+ }
+ }
+
+ ret = r;
+
+ // And remove the token
+ t = jQuery.trim( t.replace( re, "" ) );
+ foundToken = true;
+ }
+ }
+
+ // See if there's still an expression, and that we haven't already
+ // matched a token
+ if ( t && !foundToken ) {
+ // Handle multiple expressions
+ if ( !t.indexOf(",") ) {
+ // Clean the result set
+ if ( context == ret[0] ) ret.shift();
+
+ // Merge the result sets
+ done = jQuery.merge( done, ret );
+
+ // Reset the context
+ r = ret = [context];
+
+ // Touch up the selector string
+ t = " " + t.substr(1,t.length);
+
+ } else {
+ // Optimize for the case nodeName#idName
+ var re2 = quickID;
+ var m = re2.exec(t);
+
+ // Re-organize the results, so that they're consistent
+ if ( m ) {
+ m = [ 0, m[2], m[3], m[1] ];
+
+ } else {
+ // Otherwise, do a traditional filter check for
+ // ID, class, and element selectors
+ re2 = quickClass;
+ m = re2.exec(t);
+ }
+
+ m[2] = m[2].replace(/\\/g, "");
+
+ var elem = ret[ret.length-1];
+
+ // Try to do a global search by ID, where we can
+ if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
+ // Optimization for HTML document case
+ var oid = elem.getElementById(m[2]);
+
+ // Do a quick check for the existence of the actual ID attribute
+ // to avoid selecting by the name attribute in IE
+ // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
+ if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
+ oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
+
+ // Do a quick check for node name (where applicable) so
+ // that div#foo searches will be really fast
+ ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
+ } else {
+ // We need to find all descendant elements
+ for ( var i = 0; ret[i]; i++ ) {
+ // Grab the tag name being searched for
+ var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
+
+ // Handle IE7 being really dumb about <object>s
+ if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
+ tag = "param";
+
+ r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
+ }
+
+ // It's faster to filter by class and be done with it
+ if ( m[1] == "." )
+ r = jQuery.classFilter( r, m[2] );
+
+ // Same with ID filtering
+ if ( m[1] == "#" ) {
+ var tmp = [];
+
+ // Try to find the element with the ID
+ for ( var i = 0; r[i]; i++ )
+ if ( r[i].getAttribute("id") == m[2] ) {
+ tmp = [ r[i] ];
+ break;
+ }
+
+ r = tmp;
+ }
+
+ ret = r;
+ }
+
+ t = t.replace( re2, "" );
+ }
+
+ }
+
+ // If a selector string still exists
+ if ( t ) {
+ // Attempt to filter it
+ var val = jQuery.filter(t,r);
+ ret = r = val.r;
+ t = jQuery.trim(val.t);
+ }
+ }
+
+ // An error occurred with the selector;
+ // just return an empty set instead
+ if ( t )
+ ret = [];
+
+ // Remove the root context
+ if ( ret && context == ret[0] )
+ ret.shift();
+
+ // And combine the results
+ done = jQuery.merge( done, ret );
+
+ return done;
+ },
+
+ classFilter: function(r,m,not){
+ m = " " + m + " ";
+ var tmp = [];
+ for ( var i = 0; r[i]; i++ ) {
+ var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
+ if ( !not && pass || not && !pass )
+ tmp.push( r[i] );
+ }
+ return tmp;
+ },
+
+ filter: function(t,r,not) {
+ var last;
+
+ // Look for common filter expressions
+ while ( t && t != last ) {
+ last = t;
+
+ var p = jQuery.parse, m;
+
+ for ( var i = 0; p[i]; i++ ) {
+ m = p[i].exec( t );
+
+ if ( m ) {
+ // Remove what we just matched
+ t = t.substring( m[0].length );
+
+ m[2] = m[2].replace(/\\/g, "");
+ break;
+ }
+ }
+
+ if ( !m )
+ break;
+
+ // :not() is a special case that can be optimized by
+ // keeping it out of the expression list
+ if ( m[1] == ":" && m[2] == "not" )
+ // optimize if only one selector found (most common case)
+ r = isSimple.test( m[3] ) ?
+ jQuery.filter(m[3], r, true).r :
+ jQuery( r ).not( m[3] );
+
+ // We can get a big speed boost by filtering by class here
+ else if ( m[1] == "." )
+ r = jQuery.classFilter(r, m[2], not);
+
+ else if ( m[1] == "[" ) {
+ var tmp = [], type = m[3];
+
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
+
+ if ( z == null || /href|src|selected/.test(m[2]) )
+ z = jQuery.attr(a,m[2]) || '';
+
+ if ( (type == "" && !!z ||
+ type == "=" && z == m[5] ||
+ type == "!=" && z != m[5] ||
+ type == "^=" && z && !z.indexOf(m[5]) ||
+ type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
+ (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
+ tmp.push( a );
+ }
+
+ r = tmp;
+
+ // We can get a speed boost by handling nth-child here
+ } else if ( m[1] == ":" && m[2] == "nth-child" ) {
+ var merge = {}, tmp = [],
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
+ !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
+ // calculate the numbers (first)n+(last) including if they are negative
+ first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
+
+ // loop through all the elements left in the jQuery object
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
+
+ if ( !merge[id] ) {
+ var c = 1;
+
+ for ( var n = parentNode.firstChild; n; n = n.nextSibling )
+ if ( n.nodeType == 1 )
+ n.nodeIndex = c++;
+
+ merge[id] = true;
+ }
+
+ var add = false;
+
+ if ( first == 0 ) {
+ if ( node.nodeIndex == last )
+ add = true;
+ } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
+ add = true;
+
+ if ( add ^ not )
+ tmp.push( node );
+ }
+
+ r = tmp;
+
+ // Otherwise, find the expression to execute
+ } else {
+ var fn = jQuery.expr[ m[1] ];
+ if ( typeof fn == "object" )
+ fn = fn[ m[2] ];
+
+ if ( typeof fn == "string" )
+ fn = eval("false||function(a,i){return " + fn + ";}");
+
+ // Execute it against the current filter
+ r = jQuery.grep( r, function(elem, i){
+ return fn(elem, i, m, r);
+ }, not );
+ }
+ }
+
+ // Return an array of filtered elements (r)
+ // and the modified expression string (t)
+ return { r: r, t: t };
+ },
+
+ dir: function( elem, dir ){
+ var matched = [];
+ var cur = elem[dir];
+ while ( cur && cur != document ) {
+ if ( cur.nodeType == 1 )
+ matched.push( cur );
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function(cur,result,dir,elem){
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] )
+ if ( cur.nodeType == 1 && ++num == result )
+ break;
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType == 1 && (!elem || n != elem) )
+ r.push( n );
+ }
+
+ return r;
+ }
+});
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code orignated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function(elem, types, handler, data) {
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ // For whatever reason, IE has trouble passing the window object
+ // around, causing it to be cloned in the process
+ if ( jQuery.browser.msie && elem.setInterval != undefined )
+ elem = window;
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid )
+ handler.guid = this.guid++;
+
+ // if data is passed, bind to handler
+ if( data != undefined ) {
+ // Create temporary function pointer to original handler
+ var fn = handler;
+
+ // Create unique handler function, wrapped around original handler
+ handler = function() {
+ // Pass arguments and context to original handler
+ return fn.apply(this, arguments);
+ };
+
+ // Store data in unique handler
+ handler.data = data;
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ handler.guid = fn.guid;
+ }
+
+ // Init the element's event structure
+ var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+ handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+ // returned undefined or false
+ var val;
+
+ // Handle the second event of a trigger and when
+ // an event is called after a page has unloaded
+ if ( typeof jQuery == "undefined" || jQuery.event.triggered )
+ return val;
+
+ val = jQuery.event.handle.apply(arguments.callee.elem, arguments);
+
+ return val;
+ });
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native
+ // event in IE.
+ handle.elem = elem;
+
+ // Handle multiple events seperated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type) {
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+ handler.type = parts[1];
+
+ // Get the current list of functions bound to this event
+ var handlers = events[type];
+
+ // Init the event handler queue
+ if (!handlers) {
+ handlers = events[type] = {};
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
+ // Bind the global event handler to the element
+ if (elem.addEventListener)
+ elem.addEventListener(type, handle, false);
+ else if (elem.attachEvent)
+ elem.attachEvent("on" + type, handle);
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers[handler.guid] = handler;
+
+ // Keep track of which events have been used, for global triggering
+ jQuery.event.global[type] = true;
+ });
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ guid: 1,
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function(elem, types, handler) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ var events = jQuery.data(elem, "events"), ret, index;
+
+ if ( events ) {
+ // Unbind all events for the element
+ if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
+ for ( var type in events )
+ this.remove( elem, type + (types || "") );
+ else {
+ // types is actually an event object here
+ if ( types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Handle multiple events seperated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type){
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+
+ if ( events[type] ) {
+ // remove the given handler for the given type
+ if ( handler )
+ delete events[type][handler.guid];
+
+ // remove all handlers for the given type
+ else
+ for ( handler in events[type] )
+ // Handle the removal of namespaced events
+ if ( !parts[1] || events[type][handler].type == parts[1] )
+ delete events[type][handler];
+
+ // remove generic event handler if no more handlers exist
+ for ( ret in events[type] ) break;
+ if ( !ret ) {
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
+ if (elem.removeEventListener)
+ elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+ else if (elem.detachEvent)
+ elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+ }
+ ret = null;
+ delete events[type];
+ }
+ }
+ });
+ }
+
+ // Remove the expando if it's no longer used
+ for ( ret in events ) break;
+ if ( !ret ) {
+ var handle = jQuery.data( elem, "handle" );
+ if ( handle ) handle.elem = null;
+ jQuery.removeData( elem, "events" );
+ jQuery.removeData( elem, "handle" );
+ }
+ }
+ },
+
+ trigger: function(type, data, elem, donative, extra) {
+ // Clone the incoming data, if any
+ data = jQuery.makeArray(data || []);
+
+ if ( type.indexOf("!") >= 0 ) {
+ type = type.slice(0, -1);
+ var exclusive = true;
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // Only trigger if we've ever bound an event for it
+ if ( this.global[type] )
+ jQuery("*").add([window, document]).trigger(type, data);
+
+ // Handle triggering a single element
+ } else {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return undefined;
+
+ var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
+ // Check to see if we need to provide a fake event, or not
+ event = !data[0] || !data[0].preventDefault;
+
+ // Pass along a fake event
+ if ( event )
+ data.unshift( this.fix({ type: type, target: elem }) );
+
+ // Enforce the right trigger type
+ data[0].type = type;
+ if ( exclusive )
+ data[0].exclusive = true;
+
+ // Trigger the event
+ if ( jQuery.isFunction( jQuery.data(elem, "handle") ) )
+ val = jQuery.data(elem, "handle").apply( elem, data );
+
+ // Handle triggering native .onfoo handlers
+ if ( !fn && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+ val = false;
+
+ // Extra functions don't get the custom event object
+ if ( event )
+ data.shift();
+
+ // Handle triggering of extra function
+ if ( extra && jQuery.isFunction( extra ) ) {
+ // call the extra function and tack the current return value on the end for possible inspection
+ ret = extra.apply( elem, val == null ? data : data.concat( val ) );
+ // if anything is returned, give it precedence and have it overwrite the previous value
+ if (ret !== undefined)
+ val = ret;
+ }
+
+ // Trigger the native events (except for clicks on links)
+ if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
+ this.triggered = true;
+ try {
+ elem[ type ]();
+ // prevent IE from throwing an error for some hidden elements
+ } catch (e) {}
+ }
+
+ this.triggered = false;
+ }
+
+ return val;
+ },
+
+ handle: function(event) {
+ // returned undefined or false
+ var val;
+
+ // Empty object is for triggered events with no data
+ event = jQuery.event.fix( event || window.event || {} );
+
+ // Namespaced event handlers
+ var parts = event.type.split(".");
+ event.type = parts[0];
+
+ var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
+ args.unshift( event );
+
+ for ( var j in handlers ) {
+ var handler = handlers[j];
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ args[0].handler = handler;
+ args[0].data = handler.data;
+
+ // Filter the functions by class
+ if ( !parts[1] && !event.exclusive || handler.type == parts[1] ) {
+ var ret = handler.apply( this, args );
+
+ if ( val !== false )
+ val = ret;
+
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+
+ // Clean up added properties in IE to prevent memory leak
+ if (jQuery.browser.msie)
+ event.target = event.preventDefault = event.stopPropagation =
+ event.handler = event.data = null;
+
+ return val;
+ },
+
+ fix: function(event) {
+ // store a copy of the original event object
+ // and clone to set read-only properties
+ var originalEvent = event;
+ event = jQuery.extend({}, originalEvent);
+
+ // add preventDefault and stopPropagation since
+ // they will not work on the clone
+ event.preventDefault = function() {
+ // if preventDefault exists run it on the original event
+ if (originalEvent.preventDefault)
+ originalEvent.preventDefault();
+ // otherwise set the returnValue property of the original event to false (IE)
+ originalEvent.returnValue = false;
+ };
+ event.stopPropagation = function() {
+ // if stopPropagation exists run it on the original event
+ if (originalEvent.stopPropagation)
+ originalEvent.stopPropagation();
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ originalEvent.cancelBubble = true;
+ };
+
+ // Fix target property, if necessary
+ if ( !event.target )
+ event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType == 3 )
+ event.target = originalEvent.target.parentNode;
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement )
+ event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var doc = document.documentElement, body = document.body;
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
+ event.which = event.charCode || event.keyCode;
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey )
+ event.metaKey = event.ctrlKey;
+
+ // Add which for click: 1 == left; 2 == middle; 3 == right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button )
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
+ return event;
+ },
+
+ special: {
+ ready: {
+ setup: function() {
+ // Make sure the ready event is setup
+ bindReady();
+ return;
+ },
+
+ teardown: function() { return; }
+ },
+
+ mouseenter: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseenter
+ arguments[0].type = "mouseenter";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ },
+
+ mouseleave: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseleave
+ arguments[0].type = "mouseleave";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ }
+ }
+};
+
+jQuery.fn.extend({
+ bind: function( type, data, fn ) {
+ return type == "unload" ? this.one(type, data, fn) : this.each(function(){
+ jQuery.event.add( this, type, fn || data, fn && data );
+ });
+ },
+
+ one: function( type, data, fn ) {
+ return this.each(function(){
+ jQuery.event.add( this, type, function(event) {
+ jQuery(this).unbind(event);
+ return (fn || data).apply( this, arguments);
+ }, fn && data);
+ });
+ },
+
+ unbind: function( type, fn ) {
+ return this.each(function(){
+ jQuery.event.remove( this, type, fn );
+ });
+ },
+
+ trigger: function( type, data, fn ) {
+ return this.each(function(){
+ jQuery.event.trigger( type, data, this, true, fn );
+ });
+ },
+
+ triggerHandler: function( type, data, fn ) {
+ if ( this[0] )
+ return jQuery.event.trigger( type, data, this[0], false, fn );
+ return undefined;
+ },
+
+ toggle: function() {
+ // Save reference to arguments for access in closure
+ var args = arguments;
+
+ return this.click(function(event) {
+ // Figure out which function to execute
+ this.lastToggle = 0 == this.lastToggle ? 1 : 0;
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[this.lastToggle].apply( this, arguments ) || false;
+ });
+ },
+
+ hover: function(fnOver, fnOut) {
+ return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
+ },
+
+ ready: function(fn) {
+ // Attach the listeners
+ bindReady();
+
+ // If the DOM is already ready
+ if ( jQuery.isReady )
+ // Execute the function immediately
+ fn.call( document, jQuery );
+
+ // Otherwise, remember the function for later
+ else
+ // Add the function to the wait list
+ jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
+
+ return this;
+ }
+});
+
+jQuery.extend({
+ isReady: false,
+ readyList: [],
+ // Handle when the DOM is ready
+ ready: function() {
+ // Make sure that the DOM is not already loaded
+ if ( !jQuery.isReady ) {
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If there are functions bound, to execute
+ if ( jQuery.readyList ) {
+ // Execute all of them
+ jQuery.each( jQuery.readyList, function(){
+ this.apply( document );
+ });
+
+ // Reset the list of functions
+ jQuery.readyList = null;
+ }
+
+ // Trigger any bound ready events
+ jQuery(document).triggerHandler("ready");
+ }
+ }
+});
+
+var readyBound = false;
+
+function bindReady(){
+ if ( readyBound ) return;
+ readyBound = true;
+
+ // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
+ if ( document.addEventListener && !jQuery.browser.opera)
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
+
+ // If IE is used and is not in a frame
+ // Continually check to see if the document is ready
+ if ( jQuery.browser.msie && window == top ) (function(){
+ if (jQuery.isReady) return;
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch( error ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+
+ if ( jQuery.browser.opera )
+ document.addEventListener( "DOMContentLoaded", function () {
+ if (jQuery.isReady) return;
+ for (var i = 0; i < document.styleSheets.length; i++)
+ if (document.styleSheets[i].disabled) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ }, false);
+
+ if ( jQuery.browser.safari ) {
+ var numStyles;
+ (function(){
+ if (jQuery.isReady) return;
+ if ( document.readyState != "loaded" && document.readyState != "complete" ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ if ( numStyles === undefined )
+ numStyles = jQuery("style, link[rel=stylesheet]").length;
+ if ( document.styleSheets.length != numStyles ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+ }
+
+ // A fallback to window.onload, that will always work
+ jQuery.event.add( window, "load", jQuery.ready );
+}
+
+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
+ "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
+ "submit,keydown,keypress,keyup,error").split(","), function(i, name){
+
+ // Handle event binding
+ jQuery.fn[name] = function(fn){
+ return fn ? this.bind(name, fn) : this.trigger(name);
+ };
+});
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event, elem) {
+ // Check if mouse(over|out) are still within the same parent element
+ var parent = event.relatedTarget;
+ // Traverse up the tree
+ while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
+ // Return true if we actually just moused on to a sub-element
+ return parent == elem;
+};
+
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery(window).bind("unload", function() {
+ jQuery("*").add(document).unbind();
+});
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( jQuery.isFunction( url ) )
+ return this.bind("load", url);
+
+ var off = url.indexOf(" ");
+ if ( off >= 0 ) {
+ var selector = url.slice(off, url.length);
+ url = url.slice(0, off);
+ }
+
+ callback = callback || function(){};
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params )
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = null;
+
+ // Otherwise, build a param string
+ } else {
+ params = jQuery.param( params );
+ type = "POST";
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ complete: function(res, status){
+ // If successful, inject the HTML into all the matched elements
+ if ( status == "success" || status == "notmodified" )
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div/>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ res.responseText );
+
+ self.each( callback, [res.responseText, status, res] );
+ }
+ });
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param(this.serializeArray());
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ return jQuery.nodeName(this, "form") ?
+ jQuery.makeArray(this.elements) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ (this.checked || /select|textarea/i.test(this.nodeName) ||
+ /text|hidden|password/i.test(this.type));
+ })
+ .map(function(i, elem){
+ var val = jQuery(this).val();
+ return val == null ? null :
+ val.constructor == Array ?
+ jQuery.map( val, function(val, i){
+ return {name: elem.name, value: val};
+ }) :
+ {name: elem.name, value: val};
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
+ jQuery.fn[o] = function(f){
+ return this.bind(o, f);
+ };
+});
+
+var jsc = (new Date).getTime();
+
+jQuery.extend({
+ get: function( url, data, callback, type ) {
+ // shift arguments if data argument was ommited
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = null;
+ }
+
+ return jQuery.ajax({
+ type: "GET",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get(url, null, callback, "script");
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get(url, data, callback, "json");
+ },
+
+ post: function( url, data, callback, type ) {
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = {};
+ }
+
+ return jQuery.ajax({
+ type: "POST",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ ajaxSetup: function( settings ) {
+ jQuery.extend( jQuery.ajaxSettings, settings );
+ },
+
+ ajaxSettings: {
+ global: true,
+ type: "GET",
+ timeout: 0,
+ contentType: "application/x-www-form-urlencoded",
+ processData: true,
+ async: true,
+ data: null,
+ username: null,
+ password: null,
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ script: "text/javascript, application/javascript",
+ json: "application/json, text/javascript",
+ text: "text/plain",
+ _default: "*/*"
+ }
+ },
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+
+ ajax: function( s ) {
+ var jsonp, jsre = /=\?(&|$)/g, status, data;
+
+ // Extend the settings, but re-extend 's' so that it can be
+ // checked again later (in the test suite, specifically)
+ s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+
+ // convert data if not already a string
+ if ( s.data && s.processData && typeof s.data != "string" )
+ s.data = jQuery.param(s.data);
+
+ // Handle JSONP Parameter Callbacks
+ if ( s.dataType == "jsonp" ) {
+ if ( s.type.toLowerCase() == "get" ) {
+ if ( !s.url.match(jsre) )
+ s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+ } else if ( !s.data || !s.data.match(jsre) )
+ s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+ s.dataType = "json";
+ }
+
+ // Build temporary JSONP function
+ if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
+ jsonp = "jsonp" + jsc++;
+
+ // Replace the =? sequence both in the query string and the data
+ if ( s.data )
+ s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+ s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+ s.dataType = "script";
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = function(tmp){
+ data = tmp;
+ success();
+ complete();
+ // Garbage collect
+ window[ jsonp ] = undefined;
+ try{ delete window[ jsonp ]; } catch(e){}
+ if ( head )
+ head.removeChild( script );
+ };
+ }
+
+ if ( s.dataType == "script" && s.cache == null )
+ s.cache = false;
+
+ if ( s.cache === false && s.type.toLowerCase() == "get" ) {
+ var ts = (new Date()).getTime();
+ // try replacing _= if it is there
+ var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
+ }
+
+ // If data is available, append data to url for get requests
+ if ( s.data && s.type.toLowerCase() == "get" ) {
+ s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
+
+ // IE likes to send both get and post data, prevent this
+ s.data = null;
+ }
+
+ // Watch for a new set of requests
+ if ( s.global && ! jQuery.active++ )
+ jQuery.event.trigger( "ajaxStart" );
+
+ // If we're requesting a remote document
+ // and trying to load JSON or Script with a GET
+ if ( (!s.url.indexOf("http") || !s.url.indexOf("//")) && s.dataType == "script" && s.type.toLowerCase() == "get" ) {
+ var head = document.getElementsByTagName("head")[0];
+ var script = document.createElement("script");
+ script.src = s.url;
+ if (s.scriptCharset)
+ script.charset = s.scriptCharset;
+
+ // Handle Script loading
+ if ( !jsonp ) {
+ var done = false;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function(){
+ if ( !done && (!this.readyState ||
+ this.readyState == "loaded" || this.readyState == "complete") ) {
+ done = true;
+ success();
+ complete();
+ head.removeChild( script );
+ }
+ };
+ }
+
+ head.appendChild(script);
+
+ // We handle everything using the script element injection
+ return undefined;
+ }
+
+ var requestDone = false;
+
+ // Create the request object; Microsoft failed to properly
+ // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+ var xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+
+ // Open the socket
+ xml.open(s.type, s.url, s.async, s.username, s.password);
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ // Set the correct header, if data is being sent
+ if ( s.data )
+ xml.setRequestHeader("Content-Type", s.contentType);
+
+ // Set the If-Modified-Since header, if ifModified mode.
+ if ( s.ifModified )
+ xml.setRequestHeader("If-Modified-Since",
+ jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+
+ // Set header so the called script knows that it's an XMLHttpRequest
+ xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+ // Set the Accepts header for the server, depending on the dataType
+ xml.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+ s.accepts[ s.dataType ] + ", */*" :
+ s.accepts._default );
+ } catch(e){}
+
+ // Allow custom headers/mimetypes
+ if ( s.beforeSend )
+ s.beforeSend(xml);
+
+ if ( s.global )
+ jQuery.event.trigger("ajaxSend", [xml, s]);
+
+ // Wait for a response to come back
+ var onreadystatechange = function(isTimeout){
+ // The transfer is complete and the data is available, or the request timed out
+ if ( !requestDone && xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
+ requestDone = true;
+
+ // clear poll interval
+ if (ival) {
+ clearInterval(ival);
+ ival = null;
+ }
+
+ status = isTimeout == "timeout" && "timeout" ||
+ !jQuery.httpSuccess( xml ) && "error" ||
+ s.ifModified && jQuery.httpNotModified( xml, s.url ) && "notmodified" ||
+ "success";
+
+ if ( status == "success" ) {
+ // Watch for, and catch, XML document parse errors
+ try {
+ // process the data (runs the xml through httpData regardless of callback)
+ data = jQuery.httpData( xml, s.dataType );
+ } catch(e) {
+ status = "parsererror";
+ }
+ }
+
+ // Make sure that the request was successful or notmodified
+ if ( status == "success" ) {
+ // Cache Last-Modified header, if ifModified mode.
+ var modRes;
+ try {
+ modRes = xml.getResponseHeader("Last-Modified");
+ } catch(e) {} // swallow exception thrown by FF if header is not available
+
+ if ( s.ifModified && modRes )
+ jQuery.lastModified[s.url] = modRes;
+
+ // JSONP handles its own success callback
+ if ( !jsonp )
+ success();
+ } else
+ jQuery.handleError(s, xml, status);
+
+ // Fire the complete handlers
+ complete();
+
+ // Stop memory leaks
+ if ( s.async )
+ xml = null;
+ }
+ };
+
+ if ( s.async ) {
+ // don't attach the handler to the request, just poll it instead
+ var ival = setInterval(onreadystatechange, 13);
+
+ // Timeout checker
+ if ( s.timeout > 0 )
+ setTimeout(function(){
+ // Check to see if the request is still happening
+ if ( xml ) {
+ // Cancel the request
+ xml.abort();
+
+ if( !requestDone )
+ onreadystatechange( "timeout" );
+ }
+ }, s.timeout);
+ }
+
+ // Send the data
+ try {
+ xml.send(s.data);
+ } catch(e) {
+ jQuery.handleError(s, xml, null, e);
+ }
+
+ // firefox 1.5 doesn't fire statechange for sync requests
+ if ( !s.async )
+ onreadystatechange();
+
+ function success(){
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success )
+ s.success( data, status );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxSuccess", [xml, s] );
+ }
+
+ function complete(){
+ // Process result
+ if ( s.complete )
+ s.complete(xml, status);
+
+ // The request was completed
+ if ( s.global )
+ jQuery.event.trigger( "ajaxComplete", [xml, s] );
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active )
+ jQuery.event.trigger( "ajaxStop" );
+ }
+
+ // return XMLHttpRequest to allow aborting the request etc.
+ return xml;
+ },
+
+ handleError: function( s, xml, status, e ) {
+ // If a local callback was specified, fire it
+ if ( s.error ) s.error( xml, status, e );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxError", [xml, s, e] );
+ },
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Determines if an XMLHttpRequest was successful or not
+ httpSuccess: function( r ) {
+ try {
+ // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+ return !r.status && location.protocol == "file:" ||
+ ( r.status >= 200 && r.status < 300 ) || r.status == 304 || r.status == 1223 ||
+ jQuery.browser.safari && r.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ // Determines if an XMLHttpRequest returns NotModified
+ httpNotModified: function( xml, url ) {
+ try {
+ var xmlRes = xml.getResponseHeader("Last-Modified");
+
+ // Firefox always returns 200. check Last-Modified date
+ return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
+ jQuery.browser.safari && xml.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ httpData: function( r, type ) {
+ var ct = r.getResponseHeader("content-type");
+ var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0;
+ var data = xml ? r.responseXML : r.responseText;
+
+ if ( xml && data.documentElement.tagName == "parsererror" )
+ throw "parsererror";
+
+ // If the type is "script", eval it in global context
+ if ( type == "script" )
+ jQuery.globalEval( data );
+
+ // Get the JavaScript object, if JSON is used.
+ if ( type == "json" )
+ data = eval("(" + data + ")");
+
+ return data;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a ) {
+ var s = [];
+
+ // If an array was passed in, assume that it is an array
+ // of form elements
+ if ( a.constructor == Array || a.jquery )
+ // Serialize the form elements
+ jQuery.each( a, function(){
+ s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
+ });
+
+ // Otherwise, assume that it's an object of key/value pairs
+ else
+ // Serialize the key/values
+ for ( var j in a )
+ // If the value is an array then the key names need to be repeated
+ if ( a[j] && a[j].constructor == Array )
+ jQuery.each( a[j], function(){
+ s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
+ });
+ else
+ s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );
+
+ // Return the resulting serialization
+ return s.join("&").replace(/%20/g, "+");
+ }
+
+});
+jQuery.fn.extend({
+ show: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "show", width: "show", opacity: "show"
+ }, speed, callback) :
+
+ this.filter(":hidden").each(function(){
+ this.style.display = this.oldblock || "";
+ if ( jQuery.css(this,"display") == "none" ) {
+ var elem = jQuery("<" + this.tagName + " />").appendTo("body");
+ this.style.display = elem.css("display");
+ // handle an edge condition where css is - div { display:none; } or similar
+ if (this.style.display == "none")
+ this.style.display = "block";
+ elem.remove();
+ }
+ }).end();
+ },
+
+ hide: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "hide", width: "hide", opacity: "hide"
+ }, speed, callback) :
+
+ this.filter(":visible").each(function(){
+ this.oldblock = this.oldblock || jQuery.css(this,"display");
+ this.style.display = "none";
+ }).end();
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2 ){
+ return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+ this._toggle( fn, fn2 ) :
+ fn ?
+ this.animate({
+ height: "toggle", width: "toggle", opacity: "toggle"
+ }, fn, fn2) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ });
+ },
+
+ slideDown: function(speed,callback){
+ return this.animate({height: "show"}, speed, callback);
+ },
+
+ slideUp: function(speed,callback){
+ return this.animate({height: "hide"}, speed, callback);
+ },
+
+ slideToggle: function(speed, callback){
+ return this.animate({height: "toggle"}, speed, callback);
+ },
+
+ fadeIn: function(speed, callback){
+ return this.animate({opacity: "show"}, speed, callback);
+ },
+
+ fadeOut: function(speed, callback){
+ return this.animate({opacity: "hide"}, speed, callback);
+ },
+
+ fadeTo: function(speed,to,callback){
+ return this.animate({opacity: to}, speed, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed(speed, easing, callback);
+
+ return this[ optall.queue === false ? "each" : "queue" ](function(){
+ if ( this.nodeType != 1)
+ return false;
+
+ var opt = jQuery.extend({}, optall);
+ var hidden = jQuery(this).is(":hidden"), self = this;
+
+ for ( var p in prop ) {
+ if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+ return jQuery.isFunction(opt.complete) && opt.complete.apply(this);
+
+ if ( p == "height" || p == "width" ) {
+ // Store display property
+ opt.display = jQuery.css(this, "display");
+
+ // Make sure that nothing sneaks out
+ opt.overflow = this.style.overflow;
+ }
+ }
+
+ if ( opt.overflow != null )
+ this.style.overflow = "hidden";
+
+ opt.curAnim = jQuery.extend({}, prop);
+
+ jQuery.each( prop, function(name, val){
+ var e = new jQuery.fx( self, opt, name );
+
+ if ( /toggle|show|hide/.test(val) )
+ e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+ else {
+ var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
+ start = e.cur(true) || 0;
+
+ if ( parts ) {
+ var end = parseFloat(parts[2]),
+ unit = parts[3] || "px";
+
+ // We need to compute starting value
+ if ( unit != "px" ) {
+ self.style[ name ] = (end || 1) + unit;
+ start = ((end || 1) / e.cur(true)) * start;
+ self.style[ name ] = start + unit;
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] )
+ end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
+
+ e.custom( start, end, unit );
+ } else
+ e.custom( start, val, "" );
+ }
+ });
+
+ // For JS strict compliance
+ return true;
+ });
+ },
+
+ queue: function(type, fn){
+ if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
+ fn = type;
+ type = "fx";
+ }
+
+ if ( !type || (typeof type == "string" && !fn) )
+ return queue( this[0], type );
+
+ return this.each(function(){
+ if ( fn.constructor == Array )
+ queue(this, type, fn);
+ else {
+ queue(this, type).push( fn );
+
+ if ( queue(this, type).length == 1 )
+ fn.apply(this);
+ }
+ });
+ },
+
+ stop: function(clearQueue, gotoEnd){
+ var timers = jQuery.timers;
+
+ if (clearQueue)
+ this.queue([]);
+
+ this.each(function(){
+ // go in reverse order so anything added to the queue during the loop is ignored
+ for ( var i = timers.length - 1; i >= 0; i-- )
+ if ( timers[i].elem == this ) {
+ if (gotoEnd)
+ // force the next step to be the last
+ timers[i](true);
+ timers.splice(i, 1);
+ }
+ });
+
+ // start the next in the queue if the last step wasn't forced
+ if (!gotoEnd)
+ this.dequeue();
+
+ return this;
+ }
+
+});
+
+var queue = function( elem, type, array ) {
+ if ( !elem )
+ return undefined;
+
+ type = type || "fx";
+
+ var q = jQuery.data( elem, type + "queue" );
+
+ if ( !q || array )
+ q = jQuery.data( elem, type + "queue",
+ array ? jQuery.makeArray(array) : [] );
+
+ return q;
+};
+
+jQuery.fn.dequeue = function(type){
+ type = type || "fx";
+
+ return this.each(function(){
+ var q = queue(this, type);
+
+ q.shift();
+
+ if ( q.length )
+ q[0].apply( this );
+ });
+};
+
+jQuery.extend({
+
+ speed: function(speed, easing, fn) {
+ var opt = speed && speed.constructor == Object ? speed : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && easing.constructor != Function && easing
+ };
+
+ opt.duration = (opt.duration && opt.duration.constructor == Number ?
+ opt.duration :
+ { slow: 600, fast: 200 }[opt.duration]) || 400;
+
+ // Queueing
+ opt.old = opt.complete;
+ opt.complete = function(){
+ if ( opt.queue !== false )
+ jQuery(this).dequeue();
+ if ( jQuery.isFunction( opt.old ) )
+ opt.old.apply( this );
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p, n, firstNum, diff ) {
+ return firstNum + diff * p;
+ },
+ swing: function( p, n, firstNum, diff ) {
+ return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ }
+ },
+
+ timers: [],
+ timerId: null,
+
+ fx: function( elem, options, prop ){
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ if ( !options.orig )
+ options.orig = {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+
+ // Simple function for setting a style value
+ update: function(){
+ if ( this.options.step )
+ this.options.step.apply( this.elem, [ this.now, this ] );
+
+ (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+ // Set display property to block for height/width animations
+ if ( this.prop == "height" || this.prop == "width" )
+ this.elem.style.display = "block";
+ },
+
+ // Get the current size
+ cur: function(force){
+ if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
+ return this.elem[ this.prop ];
+
+ var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+ return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+ },
+
+ // Start an animation from one number to another
+ custom: function(from, to, unit){
+ this.startTime = (new Date()).getTime();
+ this.start = from;
+ this.end = to;
+ this.unit = unit || this.unit || "px";
+ this.now = this.start;
+ this.pos = this.state = 0;
+ this.update();
+
+ var self = this;
+ function t(gotoEnd){
+ return self.step(gotoEnd);
+ }
+
+ t.elem = this.elem;
+
+ jQuery.timers.push(t);
+
+ if ( jQuery.timerId == null ) {
+ jQuery.timerId = setInterval(function(){
+ var timers = jQuery.timers;
+
+ for ( var i = 0; i < timers.length; i++ )
+ if ( !timers[i]() )
+ timers.splice(i--, 1);
+
+ if ( !timers.length ) {
+ clearInterval( jQuery.timerId );
+ jQuery.timerId = null;
+ }
+ }, 13);
+ }
+ },
+
+ // Simple 'show' function
+ show: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ this.custom(0, this.cur());
+
+ // Make sure that we start at a small width/height to avoid any
+ // flash of content
+ if ( this.prop == "width" || this.prop == "height" )
+ this.elem.style[this.prop] = "1px";
+
+ // Start by showing the element
+ jQuery(this.elem).show();
+ },
+
+ // Simple 'hide' function
+ hide: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom(this.cur(), 0);
+ },
+
+ // Each step of an animation
+ step: function(gotoEnd){
+ var t = (new Date()).getTime();
+
+ if ( gotoEnd || t > this.options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ this.options.curAnim[ this.prop ] = true;
+
+ var done = true;
+ for ( var i in this.options.curAnim )
+ if ( this.options.curAnim[i] !== true )
+ done = false;
+
+ if ( done ) {
+ if ( this.options.display != null ) {
+ // Reset the overflow
+ this.elem.style.overflow = this.options.overflow;
+
+ // Reset the display
+ this.elem.style.display = this.options.display;
+ if ( jQuery.css(this.elem, "display") == "none" )
+ this.elem.style.display = "block";
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( this.options.hide )
+ this.elem.style.display = "none";
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( this.options.hide || this.options.show )
+ for ( var p in this.options.curAnim )
+ jQuery.attr(this.elem.style, p, this.options.orig[p]);
+ }
+
+ // If a callback was provided, execute it
+ if ( done && jQuery.isFunction( this.options.complete ) )
+ // Execute the complete function
+ this.options.complete.apply( this.elem );
+
+ return false;
+ } else {
+ var n = t - this.startTime;
+ this.state = n / this.options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
+ this.now = this.start + ((this.end - this.start) * this.pos);
+
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+
+};
+
+jQuery.fx.step = {
+ scrollLeft: function(fx){
+ fx.elem.scrollLeft = fx.now;
+ },
+
+ scrollTop: function(fx){
+ fx.elem.scrollTop = fx.now;
+ },
+
+ opacity: function(fx){
+ jQuery.attr(fx.elem.style, "opacity", fx.now);
+ },
+
+ _default: function(fx){
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ }
+};
+// The Offset Method
+// Originally By Brandon Aaron, part of the Dimension Plugin
+// http://jquery.com/plugins/project/dimensions
+jQuery.fn.offset = function() {
+ var left = 0, top = 0, elem = this[0], results;
+
+ if ( elem ) with ( jQuery.browser ) {
+ var parent = elem.parentNode,
+ offsetChild = elem,
+ offsetParent = elem.offsetParent,
+ doc = elem.ownerDocument,
+ safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
+ fixed = jQuery.css(elem, "position") == "fixed";
+
+ // Use getBoundingClientRect if available
+ if ( elem.getBoundingClientRect ) {
+ var box = elem.getBoundingClientRect();
+
+ // Add the document scroll offsets
+ add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+
+ // IE adds the HTML element's border, by default it is medium which is 2px
+ // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
+ // IE 7 standards mode, the border is always 2px
+ // This border/offset is typically represented by the clientLeft and clientTop properties
+ // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
+ // Therefore this method will be off by 2px in IE while in quirksmode
+ add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
+
+ // Otherwise loop through the offsetParents and parentNodes
+ } else {
+
+ // Initial element offsets
+ add( elem.offsetLeft, elem.offsetTop );
+
+ // Get parent offsets
+ while ( offsetParent ) {
+ // Add offsetParent offsets
+ add( offsetParent.offsetLeft, offsetParent.offsetTop );
+
+ // Mozilla and Safari > 2 does not include the border on offset parents
+ // However Mozilla adds the border for table or table cells
+ if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
+ border( offsetParent );
+
+ // Add the document scroll offsets if position is fixed on any offsetParent
+ if ( !fixed && jQuery.css(offsetParent, "position") == "fixed" )
+ fixed = true;
+
+ // Set offsetChild to previous offsetParent unless it is the body element
+ offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
+ // Get next offsetParent
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ // Get parent scroll offsets
+ while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
+ // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
+ if ( !/^inline|table.*$/i.test(jQuery.css(parent, "display")) )
+ // Subtract parent scroll offsets
+ add( -parent.scrollLeft, -parent.scrollTop );
+
+ // Mozilla does not add the border for a parent that has overflow != visible
+ if ( mozilla && jQuery.css(parent, "overflow") != "visible" )
+ border( parent );
+
+ // Get next parent
+ parent = parent.parentNode;
+ }
+
+ // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
+ // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
+ if ( (safari2 && (fixed || jQuery.css(offsetChild, "position") == "absolute")) ||
+ (mozilla && jQuery.css(offsetChild, "position") != "absolute") )
+ add( -doc.body.offsetLeft, -doc.body.offsetTop );
+
+ // Add the document scroll offsets if position is fixed
+ if ( fixed )
+ add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+ }
+
+ // Return an object with top and left properties
+ results = { top: top, left: left };
+ }
+
+ function border(elem) {
+ add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
+ }
+
+ function add(l, t) {
+ left += parseInt(l) || 0;
+ top += parseInt(t) || 0;
+ }
+
+ return results;
+};
+
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each(["Height", "Width"], function(i, name){
+
+ var tl = name == "Height" ? "Top" : "Left", // top or left
+ br = name == "Height" ? "Bottom" : "Right"; // bottom or right
+
+ // innerHeight and innerWidth
+ jQuery.fn["inner" + name] = function(){
+ return this[ name.toLowerCase() ]() +
+ num(this, "padding" + tl) +
+ num(this, "padding" + br);
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn["outer" + name] = function(margin) {
+ return this["inner" + name]() +
+ num(this, "border" + tl + "Width") +
+ num(this, "border" + br + "Width") +
+ (!!margin ?
+ num(this, "margin" + tl) + num(this, "margin" + br) : 0);
+ };
+
+});
+
+function num(elem, prop) {
+ elem = elem.jquery ? elem[0] : elem;
+ return elem && parseInt( jQuery.curCSS(elem, prop, true) ) || 0;
+}})();
diff --git a/moksha/widgetbrowser/static/loading.gif b/moksha/widgetbrowser/static/loading.gif
new file mode 100644
index 0000000..85b99d4
Binary files /dev/null and b/moksha/widgetbrowser/static/loading.gif differ
diff --git a/moksha/widgetbrowser/static/pygments.css b/moksha/widgetbrowser/static/pygments.css
new file mode 100644
index 0000000..a55a324
--- /dev/null
+++ b/moksha/widgetbrowser/static/pygments.css
@@ -0,0 +1,59 @@
+.c { color: #408090; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #007020; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.cp { color: #007020 } /* Comment.Preproc */
+.c1 { color: #408090; font-style: italic } /* Comment.Single */
+.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #303030 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.kp { color: #007020 } /* Keyword.Pseudo */
+.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #902000 } /* Keyword.Type */
+.m { color: #208050 } /* Literal.Number */
+.s { color: #4070a0 } /* Literal.String */
+.na { color: #4070a0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.no { color: #60add5 } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.ne { color: #007020 } /* Name.Exception */
+.nf { color: #06287e } /* Name.Function */
+.nl { color: #002070; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #062873; font-weight: bold } /* Name.Tag */
+.nv { color: #bb60d5 } /* Name.Variable */
+.ow { color: #007020; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #208050 } /* Literal.Number.Float */
+.mh { color: #208050 } /* Literal.Number.Hex */
+.mi { color: #208050 } /* Literal.Number.Integer */
+.mo { color: #208050 } /* Literal.Number.Oct */
+.sb { color: #4070a0 } /* Literal.String.Backtick */
+.sc { color: #4070a0 } /* Literal.String.Char */
+.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4070a0 } /* Literal.String.Double */
+.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #4070a0 } /* Literal.String.Heredoc */
+.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.sx { color: #c65d09 } /* Literal.String.Other */
+.sr { color: #235388 } /* Literal.String.Regex */
+.s1 { color: #4070a0 } /* Literal.String.Single */
+.ss { color: #517918 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #bb60d5 } /* Name.Variable.Class */
+.vg { color: #bb60d5 } /* Name.Variable.Global */
+.vi { color: #bb60d5 } /* Name.Variable.Instance */
+.il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/tab.png b/moksha/widgetbrowser/static/tab.png
new file mode 100644
index 0000000..413c755
Binary files /dev/null and b/moksha/widgetbrowser/static/tab.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.accordion.css b/moksha/widgetbrowser/static/themes/flora/flora.accordion.css
new file mode 100644
index 0000000..f45ed75
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.accordion.css
@@ -0,0 +1,12 @@
+ul.ui-accordion { margin: 0; padding: 0; list-style-type: none; }
+ul.ui-accordion li { margin: 0; margin-bottom: 2px; padding: 0; background-image: url(i/accordion-left.png); background-repeat: no-repeat; }
+ul.ui-accordion li a.ui-accordion-header { display: block; padding-left: 5px; margin-right: 3px; height: 28px; background-image: url(i/accordion-middle.png); color: #000; text-decoration: none; line-height: 28px; }
+ul.ui-accordion li .ui-accordion-right { display: block; background-image: url(i/accordion-right.png); position: absolute; top: 0px; right: 0px; height: 28px; width: 3px; }
+
+ul.ui-accordion li:hover { background-image: url(i/accordion-left-over.png); }
+ul.ui-accordion li:hover a.ui-accordion-header { background-image: url(i/accordion-middle-over.png); }
+ul.ui-accordion li:hover .ui-accordion-right { background-image: url(i/accordion-right-over.png); }
+
+ul.ui-accordion li.active { background-image: url(i/accordion-left-act.png); }
+ul.ui-accordion li.active a.ui-accordion-header { background-image: url(i/accordion-middle-act.png); }
+ul.ui-accordion li.active .ui-accordion-right { background-image: url(i/accordion-right-act.png); }
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.all.css b/moksha/widgetbrowser/static/themes/flora/flora.all.css
new file mode 100644
index 0000000..3de5386
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.all.css
@@ -0,0 +1,9 @@
+@import "flora.css";
+@import "flora.shadow.css";
+@import "flora.resizable.css";
+@import "flora.slider.css";
+@import "flora.accordion.css";
+@import "flora.tabs.css";
+@import "flora.dialog.css";
+@import "flora.tablesorter.css";
+@import "flora.datepicker.css";
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.calendar.css b/moksha/widgetbrowser/static/themes/flora/flora.calendar.css
new file mode 100644
index 0000000..dedcf0c
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.calendar.css
@@ -0,0 +1,167 @@
+/* Main Style Sheet for jQuery Calendar */
+#calendar_div, .calendar_inline {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 14px;
+ padding: 0;
+ margin: 0;
+ background: #ddd;
+}
+#calendar_div {
+ display: none;
+ border: 1px solid #FF9900;
+ z-index: 10; /*must have*/
+}
+#calendar_div, .calendar_control, .calendar_links, .calendar_header, .calendar {
+ width: 185px;
+}
+.calendar_inline {
+ float: left;
+ display: block;
+ border: 0;
+}
+.calendar_dialog {
+ padding: 5px !important;
+ border: 4px ridge #ddd !important;
+}
+button.calendar_trigger {
+ width: 25px;
+}
+img.calendar_trigger {
+ margin: 2px;
+ vertical-align: middle;
+}
+.calendar_prompt {
+ float: left;
+ width: 181px;
+ padding: 2px;
+ background: #ddd;
+ color: #000;
+}
+* html .calendar_prompt {
+ width: 185px;
+}
+.calendar_control, .calendar_links, .calendar_header, .calendar {
+ clear: both;
+ float: left;
+ color: #fff;
+}
+.calendar_control {
+ background: #FF9900;
+}
+.calendar_links {
+ background: #E0F4D7;
+}
+.calendar_control, .calendar_links {
+ font-weight: bold;
+ font-size: 80%;
+ letter-spacing: 1px;
+}
+.calendar_links label { /* disabled links */
+ padding: 2px 5px;
+ color: #888;
+}
+.calendar_clear, .calendar_prev {
+ float: left;
+}
+.calendar_current {
+ float: left;
+ width: 35%;
+ text-align: center;
+}
+.calendar_close, .calendar_next {
+ float: right;
+}
+.calendar_header {
+ background: #83C948;
+ text-align: center;
+ font-weight: bold;
+}
+.calendar_header select {
+ background: #83C948;
+ color: #000;
+ border: 0px;
+ font-weight: bold;
+}
+.calendar {
+ background: #ccc;
+ text-align: center;
+ font-size: 100%;
+}
+.calendar a {
+ display: block;
+ width: 100%;
+}
+.calendar .calendar_titleRow {
+ background: #B1DB87;
+ color: #000 !important;
+}
+.calendar .calendar_daysRow {
+ background: #FFF;
+ color: #666;
+}
+.calendar .calendar_daysCell {
+ color: #000;
+ border: 1px solid #ddd;
+}
+#calendar .calendar_daysCell a{
+ display: block;
+}
+.calendar .calendar_weekEndCell {
+ background: #E0F4D7;
+}
+.calendar .calendar_daysCellOver {
+ background: #fff;
+ border: 1px solid #777;
+}
+.calendar .calendar_unselectable {
+ color: #888;
+}
+.calendar_today {
+ background: #ccc !important;
+}
+.calendar_currentDay {
+ background: #999 !important;
+}
+
+/* ________ CALENDAR LINKS _______
+
+** Reset link properties and then override them with !important */
+#calendar_div a, .calendar_inline a {
+ cursor: pointer;
+ margin: 0;
+ padding: 0;
+ background: none;
+ color: #000;
+}
+.calendar_inline .calendar_links a {
+ padding: 0 5px !important;
+}
+.calendar_control a, .calendar_links a {
+ padding: 2px 5px !important;
+ color: #000 !important;
+}
+.calendar_titleRow a {
+ color: #000 !important;
+}
+.calendar_control a:hover {
+ /*background: #fdd !important;*/
+ color: #333 !important;
+}
+.calendar_links a:hover, .calendar_titleRow a:hover {
+ background: #FFF !important;
+ color: #333 !important;
+}
+
+/* ___________ IE6 IFRAME FIX ________ */
+
+.calendar_cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 193px; /*must have to match width and borders*/
+ height: 200px; /*must have to match maximum height*/
+}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.css b/moksha/widgetbrowser/static/themes/flora/flora.css
new file mode 100644
index 0000000..761217d
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.css
@@ -0,0 +1,2 @@
+.ui-wrapper { border: 1px solid #50A029; }
+.ui-wrapper input, .ui-wrapper textarea { border: 0; }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.datepicker.css b/moksha/widgetbrowser/static/themes/flora/flora.datepicker.css
new file mode 100644
index 0000000..34ea650
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.datepicker.css
@@ -0,0 +1,179 @@
+/* Main Flora Style Sheet for jQuery UI Datepicker */
+#datepicker_div, .datepicker_inline {
+ font-family: Arial,Helvetica,sans-serif;
+ font-size: 14px;
+ padding: 0;
+ margin: 0;
+ background: #DDD;
+ width: 185px;
+}
+#datepicker_div {
+ display: none;
+ border: 1px solid #FF9900;
+ z-index: 10;
+}
+.datepicker_inline {
+ float: left;
+ display: block;
+ border: 0;
+}
+.datepicker_dialog {
+ padding: 5px !important;
+ border: 4px ridge #DDD !important;
+}
+button.datepicker_trigger {
+ width: 25px;
+}
+img.datepicker_trigger {
+ margin: 2px;
+ vertical-align: middle;
+}
+.datepicker_prompt {
+ float: left;
+ padding: 2px;
+ background: #DDD;
+ color: #000;
+}
+*html .datepicker_prompt {
+ width: 185px;
+}
+.datepicker_control, .datepicker_links, .datepicker_header, .datepicker {
+ clear: both;
+ float: left;
+ width: 100%;
+ color: #FFF;
+}
+.datepicker_control {
+ background: #FF9900;
+ padding: 2px 0px;
+}
+.datepicker_links {
+ background: #E0F4D7;
+ padding: 2px 0px;
+}
+.datepicker_control, .datepicker_links {
+ font-weight: bold;
+ font-size: 80%;
+ letter-spacing: 1px;
+}
+.datepicker_links label {
+ padding: 2px 5px;
+ color: #888;
+}
+.datepicker_clear, .datepicker_prev {
+ float: left;
+ width: 34%;
+}
+.datepicker_current {
+ float: left;
+ width: 30%;
+ text-align: center;
+}
+.datepicker_close, .datepicker_next {
+ float: right;
+ width: 34%;
+ text-align: right;
+}
+.datepicker_header {
+ padding: 1px 0 3px;
+ background: #83C948;
+ text-align: center;
+ font-weight: bold;
+ height: 1.3em;
+}
+.datepicker_header select {
+ background: #83C948;
+ color: #000;
+ border: 0px;
+ font-weight: bold;
+}
+.datepicker {
+ background: #CCC;
+ text-align: center;
+ font-size: 100%;
+}
+.datepicker a {
+ display: block;
+ width: 100%;
+}
+.datepicker .datepicker_titleRow {
+ background: #B1DB87;
+ color: #000;
+}
+.datepicker .datepicker_daysRow {
+ background: #FFF;
+ color: #666;
+}
+.datepicker_weekCol {
+ background: #B1DB87;
+ color: #000;
+}
+.datepicker .datepicker_daysCell {
+ color: #000;
+ border: 1px solid #DDD;
+}
+#datepicker .datepicker_daysCell a {
+ display: block;
+}
+.datepicker .datepicker_weekEndCell {
+ background: #E0F4D7;
+}
+.datepicker .datepicker_daysCellOver {
+ background: #FFF;
+ border: 1px solid #777;
+}
+.datepicker .datepicker_unselectable {
+ color: #888;
+}
+.datepicker_today {
+ background: #B1DB87 !important;
+}
+.datepicker_currentDay {
+ background: #83C948 !important;
+}
+#datepicker_div a, .datepicker_inline a {
+ cursor: pointer;
+ margin: 0;
+ padding: 0;
+ background: none;
+ color: #000;
+}
+.datepicker_inline .datepicker_links a {
+ padding: 0 5px !important;
+}
+.datepicker_control a, .datepicker_links a {
+ padding: 2px 5px !important;
+ color: #000 !important;
+}
+.datepicker_titleRow a {
+ color: #000 !important;
+}
+.datepicker_control a:hover {
+ background: #FDD !important;
+ color: #333 !important;
+}
+.datepicker_links a:hover, .datepicker_titleRow a:hover {
+ background: #FFF !important;
+ color: #333 !important;
+}
+.datepicker_multi .datepicker {
+ border: 1px solid #83C948;
+}
+.datepicker_oneMonth {
+ float: left;
+ width: 185px;
+}
+.datepicker_newRow {
+ clear: left;
+}
+.datepicker_cover {
+ display: none;
+ display/**/: block;
+ position: absolute;
+ z-index: -1;
+ filter: mask();
+ top: -4px;
+ left: -4px;
+ width: 193px;
+ height: 200px;
+}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.dialog.css b/moksha/widgetbrowser/static/themes/flora/flora.dialog.css
new file mode 100644
index 0000000..efef1c4
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.dialog.css
@@ -0,0 +1,95 @@
+/* This file skins dialog */
+
+.flora .ui-dialog,
+.flora.ui-dialog {
+ background-color: #e6f7d4;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar,
+.flora.ui-dialog .ui-dialog-titlebar {
+ border-bottom: 1px solid #d8d2aa;
+ background: #ff9900 url(i/dialog-title.gif) repeat-x;
+ padding: 0px;
+ height: 28px;
+ _height: 29px;
+}
+
+.flora .ui-dialog.ui-draggable .ui-dialog-titlebar,
+.flora.ui-dialog.ui-draggable .ui-dialog-titlebar {
+ cursor: move;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar-close,
+.flora.ui-dialog .ui-dialog-titlebar-close {
+ width: 16px;
+ height: 16px;
+ background: url(i/dialog-titlebar-close.png) no-repeat;
+ position:absolute;
+ top: 6px;
+ right: 7px;
+ cursor: default;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar-close span,
+.flora.ui-dialog .ui-dialog-titlebar-close span {
+ display: none;
+}
+
+.flora .ui-dialog .ui-dialog-titlebar-close-hover,
+.flora.ui-dialog .ui-dialog-titlebar-close-hover {
+ background: url(i/dialog-titlebar-close-hover.png) no-repeat;
+}
+
+.flora .ui-dialog .ui-dialog-title,
+.flora.ui-dialog .ui-dialog-title {
+ margin-left: 5px;
+ color: white;
+ font-weight: bold;
+ position: relative;
+ top: 7px;
+ left: 4px;
+}
+
+.flora .ui-dialog .ui-dialog-content,
+.flora.ui-dialog .ui-dialog-content {
+ margin: 1.2em;
+}
+
+.flora .ui-dialog .ui-dialog-buttonpane,
+.flora.ui-dialog .ui-dialog-buttonpane {
+ position: absolute;
+ bottom: 8px;
+ right: 12px;
+ width: 100%;
+ text-align: right;
+}
+
+.flora .ui-dialog .ui-dialog-buttonpane button,
+.flora.ui-dialog .ui-dialog-buttonpane button {
+ margin: 6px;
+}
+
+/* Dialog handle styles */
+.flora .ui-dialog .ui-resizable-n,
+.flora.ui-dialog .ui-resizable-n { cursor: n-resize; height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/dialog-n.gif) repeat scroll center top; }
+
+.flora .ui-dialog .ui-resizable-s,
+.flora.ui-dialog .ui-resizable-s { cursor: s-resize; height: 8px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/dialog-s.gif) repeat scroll center top; }
+
+.flora .ui-dialog .ui-resizable-e,
+.flora.ui-dialog .ui-resizable-e { cursor: e-resize; width: 7px; right: 0px; top: 0px; height: 100%; background: transparent url(i/dialog-e.gif) repeat scroll right center; }
+
+.flora .ui-dialog .ui-resizable-w,
+.flora.ui-dialog .ui-resizable-w { cursor: w-resize; width: 7px; left: 0px; top: 0px; height: 100%; background: transparent url(i/dialog-w.gif) repeat scroll right center; }
+
+.flora .ui-dialog .ui-resizable-se,
+.flora.ui-dialog .ui-resizable-se { cursor: se-resize; width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/dialog-se.gif); }
+
+.flora .ui-dialog .ui-resizable-sw,
+.flora.ui-dialog .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/dialog-sw.gif); }
+
+.flora .ui-dialog .ui-resizable-nw,
+.flora.ui-dialog .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 29px; left: 0px; top: 0px; background: transparent url(i/dialog-nw.gif); }
+
+.flora .ui-dialog .ui-resizable-ne,
+.flora.ui-dialog .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 29px; right: 0px; top: 0px; background: transparent url(i/dialog-ne.gif); }
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.menu.css b/moksha/widgetbrowser/static/themes/flora/flora.menu.css
new file mode 100644
index 0000000..6d2dd21
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.menu.css
@@ -0,0 +1,8 @@
+.ui-menu-toolbar {z-index:500; list-style:none;}
+.ui-menu-toolbar-button {float:left; padding:4px 20px; cursor:pointer;}
+.ui-menu-toolbar-button:hover {}
+.ui-menu-toolbar-button a {text-decoration:none;}
+.ui-menu-items {display:none; padding:0; z-index:500; list-style:none; padding:1px 4px; min-width:80px; *width:80px;}
+.ui-menu-item a { text-decoration:none;}
+.ui-menu-item-parent { background: url('i/menu-submenu.gif') no-repeat center right; }
+.ui-menu-item-disabled {}
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.resizable.css b/moksha/widgetbrowser/static/themes/flora/flora.resizable.css
new file mode 100644
index 0000000..5e30c0c
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.resizable.css
@@ -0,0 +1,20 @@
+/* This file skins resizables */
+
+.ui-resizable { position: relative; }
+
+/* Global handle styles */
+.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; }
+.ui-resizable .ui-resizable-handle { display: block; }
+body .ui-resizable-disabled .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
+body .ui-resizable-autohide .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
+
+.ui-resizable-n { cursor: n-resize; height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/resizable-n.gif) repeat scroll center top; }
+.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/resizable-s.gif) repeat scroll center top; }
+
+.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%; background: transparent url(i/resizable-e.gif) repeat scroll right center; }
+.ui-resizable-w { cursor: w-resize; width: 6px; left: 0px; top: 0px; height: 100%; background: transparent url(i/resizable-w.gif) repeat scroll right center; }
+
+.ui-resizable-se { cursor: se-resize; width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/resizable-se.gif); }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/resizable-sw.gif); }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: 0px; top: 0px; background: transparent url(i/resizable-nw.gif); }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: 0px; top: 0px; background: transparent url(i/resizable-ne.gif); }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.slider.css b/moksha/widgetbrowser/static/themes/flora/flora.slider.css
new file mode 100644
index 0000000..94827b3
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.slider.css
@@ -0,0 +1,11 @@
+/* This file skins sliders */
+
+.ui-slider { width: 200px; height: 23px; position: relative; background-repeat: no-repeat; background-position: center center; }
+.ui-slider-handle { position: absolute; z-index: 1; height: 23px; width: 12px; top: 0px; left: 0px; background-image: url(i/slider-handle.gif); }
+.ui-slider-handle-active { border: 1px dotted black; }
+.ui-slider-disabled .ui-slider-handle { opacity: 0.5; filter: alpha(opacity=50); }
+.ui-slider-range { position: absolute; background: #50A029; opacity: 0.3; filter: alpha(opacity=30); width: 100%; height: 100%; }
+
+/* Default slider backgrounds */
+.ui-slider, .ui-slider-1 { background-image: url(i/slider-bg-1.png); }
+.ui-slider-2 { background-image: url(i/slider-bg-2.png); }
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.tablesorter.css b/moksha/widgetbrowser/static/themes/flora/flora.tablesorter.css
new file mode 100644
index 0000000..7d805a7
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.tablesorter.css
@@ -0,0 +1,40 @@
+/* This file skins tableSorter */
+
+table.tablesorter {
+ font-family:arial;
+ background-color: #CDCDCD;
+ margin:10px 0pt 15px;
+ font-size: 8pt;
+ width: 100%;
+ text-align: left;
+}
+table.tablesorter thead tr th, table.tablesorter tfoot tr th {
+ background-color: #B1DB87;
+ border: 1px solid #FFF;
+ font-size: 8pt;
+ padding: 4px;
+}
+table.tablesorter thead tr .header {
+ background-image: url(i/bg.gif);
+ background-repeat: no-repeat;
+ background-position: center right;
+ cursor: pointer;
+}
+table.tablesorter tbody td {
+ color: #3D3D3D;
+ padding: 4px;
+ background-color: #FFF;
+ vertical-align: top;
+}
+table.tablesorter tbody tr.odd td {
+ background-color:#E0F4D7;
+}
+table.tablesorter thead tr .headerSortUp {
+ background-image: url(i/asc.gif);
+}
+table.tablesorter thead tr .headerSortDown {
+ background-image: url(i/desc.gif);
+}
+table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
+background-color: #83C948;
+}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.tabs.css b/moksha/widgetbrowser/static/themes/flora/flora.tabs.css
new file mode 100644
index 0000000..c79a17e
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.tabs.css
@@ -0,0 +1,105 @@
+@import "flora.css";
+
+/* Caution! Ensure accessibility in print and other media types... */
+@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
+ .ui-tabs-hide {
+ display: none;
+ }
+}
+
+/* Hide useless elements in print layouts... */
+@media print {
+ .ui-tabs-nav {
+ display: none;
+ }
+}
+
+/* Skin */
+.ui-tabs-nav, .ui-tabs-panel {
+ font-family: "Trebuchet MS", Trebuchet, Verdana, Helvetica, Arial, sans-serif;
+ font-size: 12px;
+}
+.ui-tabs-nav {
+ list-style: none;
+ margin: 0;
+ padding: 0 0 0 3px;
+}
+.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
+ display: block;
+ clear: both;
+ content: " ";
+}
+.ui-tabs-nav li {
+ float: left;
+ margin: 0 0 0 2px;
+ font-weight: bold;
+}
+.ui-tabs-nav a, .ui-tabs-nav a span {
+ float: left; /* fixes dir=ltr problem and other quirks IE */
+ padding: 0 12px;
+ background: url(i/tabs.png) no-repeat;
+}
+.ui-tabs-nav a {
+ margin: 5px 0 0; /* position: relative makes opacity fail for disabled tab in IE */
+ padding-left: 0;
+ background-position: 100% 0;
+ text-decoration: none;
+ white-space: nowrap; /* @ IE 6 */
+ outline: 0; /* @ Firefox, prevent dotted border after click */
+}
+.ui-tabs-nav a:link, .ui-tabs-nav a:visited {
+ color: #fff;
+}
+.ui-tabs-nav .ui-tabs-selected a {
+ position: relative;
+ top: 1px;
+ z-index: 2;
+ margin-top: 0;
+ background-position: 100% -23px;
+}
+.ui-tabs-nav a span {
+ padding-top: 1px;
+ padding-right: 0;
+ height: 20px;
+ background-position: 0 0;
+ line-height: 20px;
+}
+.ui-tabs-nav .ui-tabs-selected a span {
+ padding-top: 0;
+ height: 27px;
+ background-position: 0 -23px;
+ line-height: 27px;
+}
+.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited,
+.ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
+ cursor: text;
+}
+.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active,
+.ui-tabs-nav .ui-tabs-unselect a:hover, .ui-tabs-nav .ui-tabs-unselect a:focus, .ui-tabs-nav .ui-tabs-unselect a:active { /* @ Opera, we need to be explicit again here now... */
+ cursor: pointer;
+}
+.ui-tabs-disabled {
+ opacity: .4;
+ filter: alpha(opacity=40);
+}
+.ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited {
+ color: #000;
+}
+.ui-tabs-panel {
+ border: 1px solid #519e2d;
+ padding: 10px;
+ background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
+}
+/*.ui-tabs-loading em {
+ padding: 0 0 0 20px;
+ background: url(loading.gif) no-repeat 0 50%;
+}*/
+
+/* Additional IE specific bug fixes... */
+* html .ui-tabs-nav { /* auto clear @ IE 6 & IE 7 Quirks Mode */
+ display: inline-block;
+}
+*:first-child+html .ui-tabs-nav { /* auto clear @ IE 7 Standards Mode - do not group selectors, otherwise IE 6 will ignore complete rule (because of the unknown + combinator)... */
+ display: inline-block;
+}
+
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.toasterLite.css b/moksha/widgetbrowser/static/themes/flora/flora.toasterLite.css
new file mode 100644
index 0000000..6f2b55f
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.toasterLite.css
@@ -0,0 +1,106 @@
+/* This file skins toasterLite */
+
+.flora .ui-toasterLite,
+.flora.ui-toasterLite {
+ background-color: #e6f7d4;
+ width: 100px;
+ display: block;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-titlebar,
+.flora.ui-toasterLite .ui-toasterLite-titlebar {
+ border-bottom: 1px solid #d8d2aa;
+ background: #ff9900 url(i/dialog-title.gif) repeat-x;
+ padding: 0px;
+ height: 28px;
+ z-index: 5;
+ position: relative;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-title,
+.flora.ui-toasterLite .ui-toasterLite-title {
+ margin-left: 5px;
+ color: white;
+ font-weight: bold;
+ position: relative;
+ top: 7px;
+ left: 4px;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-content,
+.flora.ui-toasterLite .ui-toasterLite-content {
+ margin: 1.2em;
+ padding-bottom: 12px;
+}
+
+/* Toaster handle styles */
+.flora .ui-toasterLite .ui-toasterLite-n,
+.flora.ui-toasterLite .ui-toasterLite-n { height: 6px; width: 100%; top: 0px; left: 0px; background: transparent url(i/toaster-n.gif) repeat scroll center top; z-index: 6; }
+
+.flora .ui-toasterLite .ui-toasterLite-s,
+.flora.ui-toasterLite .ui-toasterLite-s { height: 8px; width: 100%; bottom: 0px; left: 0px; background: transparent url(i/toaster-s.gif) repeat scroll center top; z-index: 1; }
+
+.flora .ui-toasterLite .ui-toasterLite-e,
+.flora.ui-toasterLite .ui-toasterLite-e { width: 7px; right: 0px; top: 0px; height: 100%; background: transparent url(i/toaster-e.gif) repeat scroll right center; }
+
+.flora .ui-toasterLite .ui-toasterLite-w,
+.flora.ui-toasterLite .ui-toasterLite-w { width: 7px; left: 0px; top: 0px; height: 100%; background: url(i/toaster-w.gif) repeat scroll right center; }
+
+.flora .ui-toasterLite .ui-toasterLite-se,
+.flora.ui-toasterLite .ui-toasterLite-se { width: 9px; height: 9px; right: 0px; bottom: 0px; background: transparent url(i/toaster-se.gif); z-index: 2; }
+
+.flora .ui-toasterLite .ui-toasterLite-sw,
+.flora.ui-toasterLite .ui-toasterLite-sw { width: 9px; height: 9px; left: 0px; bottom: 0px; background: transparent url(i/toaster-sw.gif); z-index: 2; }
+
+.flora .ui-toasterLite .ui-toasterLite-nw,
+.flora.ui-toasterLite .ui-toasterLite-nw { width: 9px; height: 29px; left: 0px; top: 0px; background: transparent url(i/toaster-nw.gif); z-index: 6; }
+
+.flora .ui-toasterLite .ui-toasterLite-ne,
+.flora.ui-toasterLite .ui-toasterLite-ne { width: 9px; height: 29px; right: 0px; top: 0px; background: transparent url(i/toaster-ne.gif); z-index: 6; }
+
+/* Global handle styles */
+.ui-toasterLite-corner { position: absolute; font-size: 0.1px; }
+
+.flora .ui-toasterLite-holder,
+.flora.ui-toasterLite-holder {
+ position: absolute;
+}
+.flora .ui-toasterLite-holder-pos-tr,
+.flora.ui-toasterLite-holder-pos-tr {
+ top: 10px;
+ right: 10px;
+}
+
+.flora .ui-toasterLite-holder-pos-tl,
+.flora.ui-toasterLite-holder-pos-tl {
+ top: 10px;
+ left: 10px;
+}
+
+.flora .ui-toasterLite-holder-pos-br,
+.flora.ui-toasterLite-holder-pos-br {
+ bottom: 10px;
+ right: 10px;
+}
+
+.flora .ui-toasterLite-holder-pos-bl,
+.flora.ui-toasterLite-holder-pos-bl {
+ bottom: 10px;
+ left: 10px;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-titlebar-close,
+.flora.ui-toasterLite .ui-toasterLite-titlebar-close {
+ width: 16px;
+ height: 16px;
+ background: url(i/dialog-titlebar-close.png) no-repeat;
+ position:absolute;
+ top: 6px;
+ right: 7px;
+ cursor: default;
+}
+
+.flora .ui-toasterLite .ui-toasterLite-titlebar-close-hover,
+.flora.ui-toasterLite .ui-toasterLite-titlebar-close-hover {
+ background: url(i/dialog-titlebar-close-hover.png) no-repeat;
+}
diff --git a/moksha/widgetbrowser/static/themes/flora/flora.toolbar.css b/moksha/widgetbrowser/static/themes/flora/flora.toolbar.css
new file mode 100644
index 0000000..8ad0588
--- /dev/null
+++ b/moksha/widgetbrowser/static/themes/flora/flora.toolbar.css
@@ -0,0 +1,241 @@
+/* light.toolbar.css
+ *
+ * Written: 05/09/07 4:38:01 PM
+ * Revision: 1.0.0
+ *
+ *
+ * Credits:
+ * Miksago: Full Coding.
+ */
+
+.flora .ui-toolbar {
+ position:relative;
+ padding:0px;
+ margin:0px;
+}
+.flora .ui-toolbar ul {
+ background:#E6F7D4;
+ padding:0px;
+ margin:0px;
+}
+ .flora .ui-toolbar ul li {
+ list-style-type: none;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz {
+ border-top:1px solid #5AB500;
+ background:#E6F7D4 url("i/toolbars-bot-bg.gif") repeat-x bottom left;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz li {
+ display:inline;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert {
+ padding: 0.025em 0em;
+ border-left: 1px solid #111;
+ border-right: 1px solid #444;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li {
+ display:block;
+ }
+ /* This hides the text on buttons in a icon only toolbar */
+ .flora .ui-toolbar ul.ui-toolbar-icons li .ui-toolbar-btn-desc {
+ display:none;
+ }
+ /* This hides the icon on buttons in a text only toolbar */
+ .flora .ui-toolbar ul.ui-toolbar-text li .ui-toolbar-btn-icon {
+ display:none;
+ }
+ /* This is just for icon sizes, not really needed, but it's there so if icon sizes are defined.. */
+ .flora .ui-toolbar ul li.ui-toolbar-btn-icon-sixteen .ui-toolbar-btn-icon {
+ width:16px; height:16px;
+ overflow:hidden;
+ padding:2px;
+ padding-left:16px;
+ background:no-repeat;
+ background-position:50% 50%;
+ }
+
+/************************************************
+ * Factory Elements:
+ * - These are different kinds of items that
+ * can be in a toolbar.
+ *
+ * Includes:
+ * @ ui-toolbar-btn
+ * toolbar buttons.
+ * @ ui-toolbar-sep
+ * toolbar separators.
+ *
+*/
+
+
+
+/************************************************
+ * UI-TOOLBAR-BTN
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-btn">
+ * <span class="ui-toolbar-btn-left"><i> </i></span>
+ * <span class="ui-toolbar-btn-center">
+ * <button><span>{{text}}</span></button>
+ * </span>
+ * <span class="ui-toolbar-btn-right"><i> </i></span>
+ * </li>
+ *
+ ************************************************/
+
+
+ .flora .ui-toolbar ul li.ui-toolbar-btn {
+ cursor:pointer;
+ white-space: nowrap;
+ position:relative;
+ }
+ .flora .ui-toolbar ul li .ui-toolbar-btn-left {
+ width:3px;
+ padding:5px 0px 1px 0;
+ position:absolute;
+ top:-3px;
+ bottom:0px;
+ left:-3px;
+ height:100%;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left i,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left i{
+ width:3px; height:5px;
+ padding:0px 0px 0px 0px;
+ position:absolute;
+ bottom:0px;
+ left:0px;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-center,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-center{
+ background:url("i/accordion-middle-over.png") repeat-x left top;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left {
+ background:url("i/accordion-left-over.png") no-repeat left top;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-left i,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-left i{
+ background:url("i/accordion-left-over.png") no-repeat left bottom;
+ }
+ .flora .ui-toolbar ul li .ui-toolbar-btn-center {
+ padding: 0.2em 0em;
+ line-height:2.2em;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-btn {
+ vertical-align: middle;
+ margin:0.3em 0.2em;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-btn {
+ margin:0.2em;
+ line-height:1.6em;
+ vertical-align: middle;
+ }
+ .flora .ui-toolbar ul li button {
+ vertical-align: middle;
+ background:transparent;
+ color:#000;
+ border:0px none;
+ cursor:pointer;
+ overflow:visible;
+ -moz-outline:0 none;
+ outline:0 none;
+ padding: 0.1em 0.1em;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn button span {
+ vertical-align: middle;
+ }
+ /* This hides the text on buttons in a icon only toolbar */
+ .flora .ui-toolbar ul.ui-toobar-iconOnly li.ui-toolbar-btn button span {
+ display:none;
+ }
+
+ .flora .ui-toolbar ul li.ui-toolbar-btn-over .ui-toolbar-btn-center button,
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active .ui-toolbar-btn-center button {
+ background: url("i/accordion-middle-over.png") repeat-x left bottom;
+ }
+ .flora .ui-toolbar ul li.ui-toolbar-btn-active {
+
+ }
+
+ .flora .ui-toolbar ul li.ui-toolbar-btn-disabled {
+ opacity:0.2;
+ }
+
+/************************************************
+ * UI-TOOLBAR-BTN
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-sep">
+ * <span>
+ *
+ * </span>
+ * </li>
+ *
+ ************************************************/
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-sep {
+ border-left:1px solid #444;
+ border-right:1px solid #111;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-sep {
+ border-top:1px solid #111;
+ border-bottom:1px solid #444;
+ }
+
+/************************************************
+ * UI-TOOLBAR-SLIDER
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-slider">
+ * <div class="ui-toolbar-slider-track ui-slider-track">
+ * <div class="ui-slider-handle"></div>
+ * </div>
+ * </li>
+ *
+ ************************************************/
+
+.flora .ui-toolbar ul li.ui-toolbar-slider .ui-toolbar-slider-track {
+ height: 20px!important;
+}
+
+/************************************************
+ * UI-TOOLBAR-RADIOGRP
+ *
+ * STRUCTURE:
+ * <li class="ui-toolbar-radioGrp">
+ * <ul class="DIRECTION">
+ * <li class="ui-toolbar-btn">
+ * <span class="ui-toolbar-btn-left"><i> </i></span>
+ * <span class="ui-toolbar-btn-center">
+ * <button><span>{{text}}</span></button>
+ * </span>
+ * <span class="ui-toolbar-btn-right"><i> </i></span>
+ * </li>
+ * </ul>
+ * </li>
+ *
+ *
+ ************************************************/
+
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp,
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul,
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul li{
+ display:inline;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-horiz li.ui-toolbar-radioGrp ul {
+ margin:0px;
+ padding:0px;
+ }
+
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp,
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul,
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul li{
+ display:block;
+ }
+ .flora .ui-toolbar ul.ui-toolbar-vert li.ui-toolbar-radioGrp ul {
+ margin:0px;
+ padding:0px;
+ }
+
+
+/* END OF FILE */
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-left-act.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-left-act.png
new file mode 100644
index 0000000..bf6ee99
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-left-act.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-left-over.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-left-over.png
new file mode 100644
index 0000000..66378e0
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-left-over.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-left.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-left.png
new file mode 100644
index 0000000..13344fc
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-left.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-act.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-act.png
new file mode 100644
index 0000000..cecf4f1
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-act.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-over.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-over.png
new file mode 100644
index 0000000..251ad11
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle-over.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-middle.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle.png
new file mode 100644
index 0000000..5238fd4
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-middle.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-right-act.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-right-act.png
new file mode 100644
index 0000000..1fa4792
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-right-act.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-right-over.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-right-over.png
new file mode 100644
index 0000000..d676dad
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-right-over.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/accordion-right.png b/moksha/widgetbrowser/static/themes/flora/i/accordion-right.png
new file mode 100644
index 0000000..543991a
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/accordion-right.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/asc.gif b/moksha/widgetbrowser/static/themes/flora/i/asc.gif
new file mode 100644
index 0000000..7415786
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/asc.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/bg.gif b/moksha/widgetbrowser/static/themes/flora/i/bg.gif
new file mode 100644
index 0000000..fac668f
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/bg.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/desc.gif b/moksha/widgetbrowser/static/themes/flora/i/desc.gif
new file mode 100644
index 0000000..3b30b3c
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/desc.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-e.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-e.gif
new file mode 100644
index 0000000..3b8b521
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-e.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-n.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-n.gif
new file mode 100644
index 0000000..70887b8
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-n.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-ne.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-ne.gif
new file mode 100644
index 0000000..ab9c38e
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-ne.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-nw.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-nw.gif
new file mode 100644
index 0000000..e934073
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-nw.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-s.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-s.gif
new file mode 100644
index 0000000..d5f6b99
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-s.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-se.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-se.gif
new file mode 100644
index 0000000..186a864
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-se.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-sw.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-sw.gif
new file mode 100644
index 0000000..025dfda
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-sw.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-title.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-title.gif
new file mode 100644
index 0000000..156c59b
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-title.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png b/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png
new file mode 100644
index 0000000..67c1303
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close-hover.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png b/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png
new file mode 100644
index 0000000..cec974c
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-titlebar-close.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/dialog-w.gif b/moksha/widgetbrowser/static/themes/flora/i/dialog-w.gif
new file mode 100644
index 0000000..931ff4a
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/dialog-w.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/menu-submenu.gif b/moksha/widgetbrowser/static/themes/flora/i/menu-submenu.gif
new file mode 100644
index 0000000..77647d8
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/menu-submenu.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-e.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-e.gif
new file mode 100644
index 0000000..7acf248
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-e.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-n.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-n.gif
new file mode 100644
index 0000000..59110f6
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-n.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-ne.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-ne.gif
new file mode 100644
index 0000000..515a3f8
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-ne.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-nw.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-nw.gif
new file mode 100644
index 0000000..665f318
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-nw.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-s.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-s.gif
new file mode 100644
index 0000000..da2fb35
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-s.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-se.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-se.gif
new file mode 100644
index 0000000..6c258ef
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-se.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-sw.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-sw.gif
new file mode 100644
index 0000000..2fd8de4
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-sw.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/resizable-w.gif b/moksha/widgetbrowser/static/themes/flora/i/resizable-w.gif
new file mode 100644
index 0000000..34b875b
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/resizable-w.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/shadow.png b/moksha/widgetbrowser/static/themes/flora/i/shadow.png
new file mode 100644
index 0000000..4c58c7f
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/shadow.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/slider-bg-1.png b/moksha/widgetbrowser/static/themes/flora/i/slider-bg-1.png
new file mode 100644
index 0000000..b7d806e
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/slider-bg-1.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/slider-bg-2.png b/moksha/widgetbrowser/static/themes/flora/i/slider-bg-2.png
new file mode 100644
index 0000000..8b24cf0
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/slider-bg-2.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/slider-handle.gif b/moksha/widgetbrowser/static/themes/flora/i/slider-handle.gif
new file mode 100644
index 0000000..9b89f26
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/slider-handle.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/tabs.png b/moksha/widgetbrowser/static/themes/flora/i/tabs.png
new file mode 100644
index 0000000..8018e41
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/tabs.png differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-e.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-e.gif
new file mode 100644
index 0000000..55dcb2c
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-e.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-n.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-n.gif
new file mode 100644
index 0000000..b0fbeb9
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-n.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-ne.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-ne.gif
new file mode 100644
index 0000000..ab9c38e
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-ne.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-nw.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-nw.gif
new file mode 100644
index 0000000..e934073
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-nw.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-s.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-s.gif
new file mode 100644
index 0000000..15640e8
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-s.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-se.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-se.gif
new file mode 100644
index 0000000..fb7a7df
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-se.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-sw.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-sw.gif
new file mode 100644
index 0000000..ad1ae1c
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-sw.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toaster-w.gif b/moksha/widgetbrowser/static/themes/flora/i/toaster-w.gif
new file mode 100644
index 0000000..8489de8
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toaster-w.gif differ
diff --git a/moksha/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif b/moksha/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif
new file mode 100644
index 0000000..15640e8
Binary files /dev/null and b/moksha/widgetbrowser/static/themes/flora/i/toolbars-bot-bg.gif differ
diff --git a/moksha/widgetbrowser/static/ui.base.js b/moksha/widgetbrowser/static/ui.base.js
new file mode 100644
index 0000000..17115f0
--- /dev/null
+++ b/moksha/widgetbrowser/static/ui.base.js
@@ -0,0 +1,204 @@
+/*
+ * jQuery UI @VERSION
+ *
+ * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ *
+ * $Date: 2008-04-01 09:23:47 -0400 (Tue, 01 Apr 2008) $
+ * $Rev: 5174 $
+ */
+;(function($) {
+
+ //If the UI scope is not available, add it
+ $.ui = $.ui || {};
+
+ //Add methods that are vital for all mouse interaction stuff (plugin registering)
+ $.extend($.ui, {
+ plugin: {
+ add: function(module, option, set) {
+ var proto = $.ui[module].prototype;
+ for(var i in set) {
+ proto.plugins[i] = proto.plugins[i] || [];
+ proto.plugins[i].push([option, set[i]]);
+ }
+ },
+ call: function(instance, name, arguments) {
+ var set = instance.plugins[name]; if(!set) return;
+ for (var i = 0; i < set.length; i++) {
+ if (instance.options[set[i][0]]) set[i][1].apply(instance.element, arguments);
+ }
+ }
+ },
+ cssCache: {},
+ css: function(name) {
+ if ($.ui.cssCache[name]) return $.ui.cssCache[name];
+ var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
+
+ //if (!$.browser.safari)
+ //tmp.appendTo('body');
+
+ //Opera and Safari set width and height to 0px instead of auto
+ //Safari returns rgba(0,0,0,0) when bgcolor is not set
+ $.ui.cssCache[name] = !!(
+ (!/auto|default/.test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) ||
+ !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
+ );
+ try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){}
+ return $.ui.cssCache[name];
+ },
+ disableSelection: function(e) {
+ e.unselectable = "on";
+ e.onselectstart = function() { return false; };
+ if (e.style) e.style.MozUserSelect = "none";
+ },
+ enableSelection: function(e) {
+ e.unselectable = "off";
+ e.onselectstart = function() { return true; };
+ if (e.style) e.style.MozUserSelect = "";
+ },
+ hasScroll: function(e, a) {
+ var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
+ if (e[scroll] > 0) return true; e[scroll] = 1;
+ has = e[scroll] > 0 ? true : false; e[scroll] = 0;
+ return has;
+ }
+ });
+
+ /******* fn scope modifications ********/
+
+ $.each( ['Left', 'Top'], function(i, name) {
+ if(!$.fn['scroll'+name]) $.fn['scroll'+name] = function(v) {
+ return v != undefined ?
+ this.each(function() { this == window || this == document ? window.scrollTo(name == 'Left' ? v : $(window)['scrollLeft'](), name == 'Top' ? v : $(window)['scrollTop']()) : this['scroll'+name] = v; }) :
+ this[0] == window || this[0] == document ? self[(name == 'Left' ? 'pageXOffset' : 'pageYOffset')] || $.boxModel && document.documentElement['scroll'+name] || document.body['scroll'+name] : this[0][ 'scroll' + name ];
+ };
+ });
+
+ var _remove = $.fn.remove;
+ $.fn.extend({
+ position: function() {
+ var offset = this.offset();
+ var offsetParent = this.offsetParent();
+ var parentOffset = offsetParent.offset();
+
+ return {
+ top: offset.top - num(this[0], 'marginTop') - parentOffset.top - num(offsetParent, 'borderTopWidth'),
+ left: offset.left - num(this[0], 'marginLeft') - parentOffset.left - num(offsetParent, 'borderLeftWidth')
+ };
+ },
+ offsetParent: function() {
+ var offsetParent = this[0].offsetParent;
+ while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
+ offsetParent = offsetParent.offsetParent;
+ return $(offsetParent);
+ },
+ mouseInteraction: function(o) {
+ return this.each(function() {
+ new $.ui.mouseInteraction(this, o);
+ });
+ },
+ removeMouseInteraction: function(o) {
+ return this.each(function() {
+ if($.data(this, "ui-mouse"))
+ $.data(this, "ui-mouse").destroy();
+ });
+ },
+ remove: function() {
+ jQuery("*", this).add(this).trigger("remove");
+ return _remove.apply(this, arguments );
+ }
+ });
+
+ function num(el, prop) {
+ return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
+ };
+
+
+ /********** Mouse Interaction Plugin *********/
+
+ $.ui.mouseInteraction = function(element, options) {
+
+ var self = this;
+ this.element = element;
+
+ $.data(this.element, "ui-mouse", this);
+ this.options = $.extend({}, options);
+
+ $(element).bind('mousedown.draggable', function() { return self.click.apply(self, arguments); });
+ if($.browser.msie) $(element).attr('unselectable', 'on'); //Prevent text selection in IE
+
+ // prevent draggable-options-delay bug #2553
+ $(element).mouseup(function() {
+ if(self.timer) clearInterval(self.timer);
+ });
+ };
+
+ $.extend($.ui.mouseInteraction.prototype, {
+
+ destroy: function() { $(this.element).unbind('mousedown.draggable'); },
+ trigger: function() { return this.click.apply(this, arguments); },
+ click: function(e) {
+
+ if(
+ e.which != 1 //only left click starts dragging
+ || $.inArray(e.target.nodeName.toLowerCase(), this.options.dragPrevention || []) != -1 // Prevent execution on defined elements
+ || (this.options.condition && !this.options.condition.apply(this.options.executor || this, [e, this.element])) //Prevent execution on condition
+ ) return true;
+
+ var self = this;
+ var initialize = function() {
+ self._MP = { left: e.pageX, top: e.pageY }; // Store the click mouse position
+ $(document).bind('mouseup.draggable', function() { return self.stop.apply(self, arguments); });
+ $(document).bind('mousemove.draggable', function() { return self.drag.apply(self, arguments); });
+
+ if(!self.initalized && Math.abs(self._MP.left-e.pageX) >= self.options.distance || Math.abs(self._MP.top-e.pageY) >= self.options.distance) {
+ if(self.options.start) self.options.start.call(self.options.executor || self, e, self.element);
+ if(self.options.drag) self.options.drag.call(self.options.executor || self, e, this.element); //This is actually not correct, but expected
+ self.initialized = true;
+ }
+ };
+
+ if(this.options.delay) {
+ if(this.timer) clearInterval(this.timer);
+ this.timer = setTimeout(initialize, this.options.delay);
+ } else {
+ initialize();
+ }
+
+ return false;
+
+ },
+ stop: function(e) {
+
+ var o = this.options;
+ if(!this.initialized) return $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
+
+ if(this.options.stop) this.options.stop.call(this.options.executor || this, e, this.element);
+ $(document).unbind('mouseup.draggable').unbind('mousemove.draggable');
+ this.initialized = false;
+ return false;
+
+ },
+ drag: function(e) {
+
+ var o = this.options;
+ if ($.browser.msie && !e.button) return this.stop.apply(this, [e]); // IE mouseup check
+
+ if(!this.initialized && (Math.abs(this._MP.left-e.pageX) >= o.distance || Math.abs(this._MP.top-e.pageY) >= o.distance)) {
+ if(this.options.start) this.options.start.call(this.options.executor || this, e, this.element);
+ this.initialized = true;
+ } else {
+ if(!this.initialized) return false;
+ }
+
+ if(o.drag) o.drag.call(this.options.executor || this, e, this.element);
+ return false;
+
+ }
+ });
+
+})(jQuery);
+
\ No newline at end of file
diff --git a/moksha/widgetbrowser/static/ui.dialog.js b/moksha/widgetbrowser/static/ui.dialog.js
new file mode 100644
index 0000000..7a907bd
--- /dev/null
+++ b/moksha/widgetbrowser/static/ui.dialog.js
@@ -0,0 +1,459 @@
+/*
+ * jQuery UI Dialog
+ *
+ * Copyright (c) 2008 Richard D. Worth (rdworth.org)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ * ui.base.js
+ * ui.draggable.js
+ * ui.resizable.js
+ *
+ * Revision: $Id: ui.dialog.js 5185 2008-04-03 15:39:51Z scott.gonzalez $
+ */
+;(function($) {
+
+ $.fn.extend({
+ dialog: function(options) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ if (typeof options == "string") {
+ var elem = $(this).is('.ui-dialog')
+ ? this
+ : $(this).parents(".ui-dialog:first").find(".ui-dialog-content")[0];
+ var dialog = elem ? $.data(elem, "dialog") : {};
+ if (dialog[options])
+ dialog[options].apply(dialog, args);
+ // INIT with optional options
+ } else if (!$(this).is(".ui-dialog-content"))
+ new $.ui.dialog(this, options);
+ });
+ }
+ });
+
+ $.ui.dialog = function(el, options) {
+
+ this.options = options = $.extend({}, $.ui.dialog.defaults, options);
+ this.element = el;
+ var self = this; //Do bindings
+
+ $.data(this.element, "dialog", this);
+
+ $(el).bind("remove", function() {
+ self.destroy();
+ });
+
+ $(el).bind("setData.dialog", function(event, key, value){
+ switch (key) {
+ case "draggable":
+ uiDialog.draggable(value ? 'enable' : 'disable');
+ break;
+ case "dragStart":
+ uiDialog.data('start.draggable', value);
+ break;
+ case "drag":
+ uiDialog.data('drag.draggable', value);
+ break;
+ case "dragStop":
+ uiDialog.data('stop.draggable', value);
+ break;
+ case "height":
+ uiDialog.height(value);
+ break;
+ case "maxHeight":
+ case "minHeight":
+ case "maxWidth":
+ case "minWidth":
+ uiDialog.data(key + ".resizable", value);
+ break;
+ case "position":
+ self.position(value);
+ break;
+ case "resizable":
+ uiDialog.resizable(value ? 'enable' : 'disable');
+ break;
+ case "resizeStart":
+ uiDialog.data('start.resizable', value);
+ break;
+ case "resize":
+ uiDialog.data('resize.resizable', value);
+ break;
+ case "resizeStop":
+ uiDialog.data('stop.resizable', value);
+ break;
+ case "title":
+ $(".ui-dialog-title", uiDialogTitlebar).text(value);
+ break;
+ case "width":
+ break;
+ }
+ options[key] = value;
+ }).bind("getData.dialog", function(event, key){
+ return options[key];
+ });
+
+ var uiDialogContent = $(el).addClass('ui-dialog-content');
+
+ if (!uiDialogContent.parent().length) {
+ uiDialogContent.appendTo('body');
+ }
+ uiDialogContent
+ .wrap(document.createElement('div'))
+ .wrap(document.createElement('div'));
+ var uiDialogContainer = uiDialogContent.parent().addClass('ui-dialog-container').css({position: 'relative'});
+ var uiDialog = this.uiDialog = uiDialogContainer.parent().hide()
+ .addClass('ui-dialog')
+ .css({position: 'absolute', width: options.width, height: options.height, overflow: 'hidden'});
+
+ var classNames = uiDialogContent.attr('className').split(' ');
+
+ // Add content classes to dialog, to inherit theme at top level of element
+ $.each(classNames, function(i, className) {
+ if (className != 'ui-dialog-content')
+ uiDialog.addClass(className);
+ });
+
+ if ($.fn.resizable) {
+ uiDialog.append('<div class="ui-resizable-n ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-s ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-e ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-w ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-ne ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-se ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-sw ui-resizable-handle"></div>')
+ .append('<div class="ui-resizable-nw ui-resizable-handle"></div>');
+ uiDialog.resizable({
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: options.minHeight,
+ start: options.resizeStart,
+ resize: options.resize,
+ stop: function(e, ui) {
+ options.resizeStop && options.resizeStop.apply(this, arguments);
+ $.ui.dialog.overlay.resize();
+ }
+ });
+ if (!options.resizable)
+ uiDialog.resizable('disable');
+ }
+
+ uiDialogContainer.prepend('<div class="ui-dialog-titlebar"></div>');
+ var uiDialogTitlebar = $('.ui-dialog-titlebar', uiDialogContainer);
+ var title = (options.title) ? options.title : (uiDialogContent.attr('title')) ? uiDialogContent.attr('title') : '';
+ uiDialogTitlebar.append('<span class="ui-dialog-title">' + title + '</span>');
+ uiDialogTitlebar.append('<a href="#" class="ui-dialog-titlebar-close"><span>X</span></a>');
+ this.uiDialogTitlebarClose = $('.ui-dialog-titlebar-close', uiDialogTitlebar)
+ .hover(function() { $(this).addClass('ui-dialog-titlebar-close-hover'); },
+ function() { $(this).removeClass('ui-dialog-titlebar-close-hover'); })
+ .mousedown(function(ev) {
+ ev.stopPropagation();
+ })
+ .click(function() {
+ self.close();
+ return false;
+ })
+ .keydown(function(ev) {
+ var ESC = 27;
+ ev.keyCode && ev.keyCode == ESC && self.close();
+ });
+
+ var l = 0;
+ $.each(options.buttons, function() { l = 1; return false; });
+ if (l == 1) {
+ uiDialog.append('<div class="ui-dialog-buttonpane"></div>');
+ var uiDialogButtonPane = $('.ui-dialog-buttonpane', uiDialog);
+ $.each(options.buttons, function(name, value) {
+ var btn = $(document.createElement('button')).text(name).click(value);
+ uiDialogButtonPane.append(btn);
+ });
+ }
+
+ if ($.fn.draggable) {
+ uiDialog.draggable({
+ handle: '.ui-dialog-titlebar',
+ start: function(e, ui) {
+ self.activate();
+ options.dragStart && options.dragStart.apply(this, arguments);
+ },
+ drag: options.drag,
+ stop: function(e, ui) {
+ options.dragStop && options.dragStop.apply(this, arguments);
+ $.ui.dialog.overlay.resize();
+ }
+ });
+ if (!options.draggable)
+ uiDialog.draggable('disable')
+ }
+
+ uiDialog.mousedown(function() {
+ self.activate();
+ });
+ uiDialogTitlebar.click(function() {
+ self.activate();
+ });
+
+ options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe();
+
+ this.position = function(pos) {
+ var wnd = $(window), doc = $(document), top = doc.scrollTop(), left = doc.scrollLeft();
+ if (pos.constructor == Array) {
+ // [x, y]
+ top += pos[1];
+ left += pos[0];
+ } else {
+ switch (pos) {
+ case 'center':
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ break;
+ case 'top':
+ top += 0;
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ break;
+ case 'right':
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += (wnd.width()) - (uiDialog.width());
+ break;
+ case 'bottom':
+ top += (wnd.height()) - (uiDialog.height());
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ break;
+ case 'left':
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += 0;
+ break;
+ default:
+ //center
+ top += (wnd.height() / 2) - (uiDialog.height() / 2);
+ left += (wnd.width() / 2) - (uiDialog.width() / 2);
+ }
+ }
+ top = top < doc.scrollTop() ? doc.scrollTop() : top;
+ uiDialog.css({top: top, left: left});
+ }
+
+ this.open = function() {
+ this.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
+ uiDialog.appendTo('body');
+ this.position(options.position);
+ uiDialog.show();
+ self.moveToTop();
+ self.activate();
+
+ // CALLBACK: open
+ var openEV = null;
+ var openUI = {
+ options: options
+ };
+ this.uiDialogTitlebarClose.focus();
+ $(this.element).triggerHandler("dialogopen", [openEV, openUI], options.open);
+ };
+
+ this.activate = function() {
+ // Move modeless dialogs to the top when they're activated. Even
+ // if there is a modal dialog in the window, the modeless dialog
+ // should be on top because it must have been opened after the modal
+ // dialog. Modal dialogs don't get moved to the top because that
+ // would make any modeless dialogs that it spawned unusable until
+ // the modal dialog is closed.
+ !options.modal && this.moveToTop();
+ };
+
+ this.moveToTop = function() {
+ var maxZ = options.zIndex;
+ $('.ui-dialog:visible').each(function() {
+ maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10) || options.zIndex);
+ });
+ this.overlay && this.overlay.$el.css('z-index', ++maxZ);
+ uiDialog.css('z-index', ++maxZ);
+ };
+
+ this.close = function() {
+ this.overlay && this.overlay.destroy();
+ uiDialog.hide();
+
+ // CALLBACK: close
+ var closeEV = null;
+ var closeUI = {
+ options: options
+ };
+ $(this.element).triggerHandler("dialogclose", [closeEV, closeUI], options.close);
+ $.ui.dialog.overlay.resize();
+ };
+
+ this.destroy = function() {
+ this.overlay && this.overlay.destroy();
+ uiDialog.hide();
+ $(el).unbind('.dialog').removeClass('ui-dialog-content').hide().appendTo('body');
+ uiDialog.remove();
+ $.removeData(this.element, "dialog");
+ };
+
+ if (options.autoOpen) {
+ this.open();
+ };
+ };
+
+ $.extend($.ui.dialog, {
+ defaults: {
+ autoOpen: true,
+ bgiframe: false,
+ buttons: [],
+ draggable: true,
+ height: 200,
+ minHeight: 100,
+ minWidth: 150,
+ modal: false,
+ overlay: {},
+ position: 'center',
+ resizable: true,
+ width: 300,
+ zIndex: 1000
+ },
+
+ overlay: function(dialog) {
+ this.$el = $.ui.dialog.overlay.create(dialog);
+ }
+ });
+
+ $.extend($.ui.dialog.overlay, {
+ instances: [],
+ events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
+ function(e) { return e + '.dialog-overlay'; }).join(' '),
+ create: function(dialog) {
+ if (this.instances.length === 0) {
+ // prevent use of anchors and inputs
+ $('a, :input').bind(this.events, function() {
+ // allow use of the element if inside a dialog and
+ // - there are no modal dialogs
+ // - there are modal dialogs, but we are in front of the
+ // topmost modal dialog
+ var allow = false;
+ var $dialog = $(this).parents('.ui-dialog');
+ if ($dialog.length) {
+ var $overlays = $('.ui-dialog-overlay');
+ if ($overlays.length) {
+ var maxZ = parseInt($overlays.css('z-index'), 10);
+ $overlays.each(function() {
+ maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10));
+ });
+ allow = parseInt($dialog.css('z-index'), 10) > maxZ;
+ } else {
+ allow = true;
+ }
+ }
+ return allow;
+ });
+
+ // allow closing by pressing the escape key
+ $(document).bind('keydown.dialog-overlay', function(e) {
+ var ESC = 27;
+ e.keyCode && e.keyCode == ESC && dialog.close();
+ });
+
+ // handle window resize
+ $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
+ }
+
+ var $el = $('<div/>').appendTo(document.body)
+ .addClass('ui-dialog-overlay').css($.extend({
+ borderWidth: 0, margin: 0, padding: 0,
+ position: 'absolute', top: 0, left: 0,
+ width: this.width(),
+ height: this.height()
+ }, dialog.options.overlay));
+
+ dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe();
+
+ this.instances.push($el);
+ return $el;
+ },
+
+ destroy: function($el) {
+ this.instances.splice($.inArray(this.instances, $el), 1);
+
+ if (this.instances.length === 0) {
+ $('a, :input').add([document, window]).unbind('.dialog-overlay');
+ }
+
+ $el.remove();
+ },
+
+ height: function() {
+ if ($.browser.msie && $.browser.version < 7) {
+ var scrollHeight = Math.max(
+ document.documentElement.scrollHeight,
+ document.body.scrollHeight
+ );
+ var offsetHeight = Math.max(
+ document.documentElement.offsetHeight,
+ document.body.offsetHeight
+ );
+
+ if (scrollHeight < offsetHeight) {
+ return $(window).height() + 'px';
+ } else {
+ return scrollHeight + 'px';
+ }
+ } else {
+ return $(document).height() + 'px';
+ }
+ },
+
+ width: function() {
+ if ($.browser.msie && $.browser.version < 7) {
+ var scrollWidth = Math.max(
+ document.documentElement.scrollWidth,
+ document.body.scrollWidth
+ );
+ var offsetWidth = Math.max(
+ document.documentElement.offsetWidth,
+ document.body.offsetWidth
+ );
+
+ if (scrollWidth < offsetWidth) {
+ return $(window).width() + 'px';
+ } else {
+ return scrollWidth + 'px';
+ }
+ } else {
+ return $(document).width() + 'px';
+ }
+ },
+
+ resize: function() {
+ /* If the dialog is draggable and the user drags it past the
+ * right edge of the window, the document becomes wider so we
+ * need to stretch the overlay. If the user then drags the
+ * dialog back to the left, the document will become narrower,
+ * so we need to shrink the overlay to the appropriate size.
+ * This is handled by shrinking the overlay before setting it
+ * to the full document size.
+ */
+ var $overlays = $([]);
+ $.each($.ui.dialog.overlay.instances, function() {
+ $overlays = $overlays.add(this);
+ });
+
+ $overlays.css({
+ width: 0,
+ height: 0
+ }).css({
+ width: $.ui.dialog.overlay.width(),
+ height: $.ui.dialog.overlay.height()
+ });
+ }
+ });
+
+ $.extend($.ui.dialog.overlay.prototype, {
+ destroy: function() {
+ $.ui.dialog.overlay.destroy(this.$el);
+ }
+ });
+
+})(jQuery);
diff --git a/moksha/widgetbrowser/static/ui.draggable.js b/moksha/widgetbrowser/static/ui.draggable.js
new file mode 100644
index 0000000..ce209db
--- /dev/null
+++ b/moksha/widgetbrowser/static/ui.draggable.js
@@ -0,0 +1,572 @@
+/*
+ * jQuery UI Draggable
+ *
+ * Copyright (c) 2008 Paul Bakaus
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * ui.base.js
+ *
+ * Revision: $Id: ui.draggable.js 5194 2008-04-04 12:30:10Z paul.bakaus $
+ */
+;(function($) {
+
+ $.fn.extend({
+ draggable: function(options) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ if (typeof options == "string") {
+ var drag = $.data(this, "draggable");
+ if(drag) drag[options].apply(drag, args);
+
+ } else if(!$.data(this, "draggable"))
+ new $.ui.draggable(this, options);
+ });
+ }
+ });
+
+ $.ui.draggable = function(element, options) {
+ //Initialize needed constants
+ var self = this;
+
+ this.element = $(element);
+
+ $.data(element, "draggable", this);
+ this.element.addClass("ui-draggable");
+
+ //Prepare the passed options
+ this.options = $.extend({}, options);
+ var o = this.options;
+ $.extend(o, {
+ helper: o.ghosting == true ? 'clone' : (o.helper || 'original'),
+ handle : o.handle ? ($(o.handle, element)[0] ? $(o.handle, element) : this.element) : this.element,
+ appendTo: o.appendTo || 'parent'
+ });
+
+ $(element).bind("setData.draggable", function(event, key, value){
+ self.options[key] = value;
+ }).bind("getData.draggable", function(event, key){
+ return self.options[key];
+ });
+
+ //Initialize mouse events for interaction
+ $(o.handle).mouseInteraction({
+ executor: this,
+ delay: o.delay,
+ distance: o.distance || 1,
+ dragPrevention: o.cancel || o.cancel === '' ? o.cancel.toLowerCase().split(',') : ['input','textarea','button','select','option'],
+ start: this.start,
+ stop: this.stop,
+ drag: this.drag,
+ condition: function(e) { return !(e.target.className.indexOf("ui-resizable-handle") != -1 || this.options.disabled); }
+ });
+
+ //Position the node
+ if(o.helper == 'original' && (this.element.css('position') == 'static' || this.element.css('position') == ''))
+ this.element.css('position', 'relative');
+
+ //Prepare cursorAt
+ if(o.cursorAt && o.cursorAt.constructor == Array)
+ o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] };
+
+ };
+
+ $.extend($.ui.draggable.prototype, {
+ plugins: {},
+ ui: function(e) {
+ return {
+ helper: this.helper,
+ position: this.position,
+ absolutePosition: this.positionAbs,
+ instance: this,
+ options: this.options,
+ element: this.element
+ };
+ },
+ propagate: function(n,e) {
+ $.ui.plugin.call(this, n, [e, this.ui()]);
+ return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [e, this.ui()], this.options[n]);
+ },
+ destroy: function() {
+ if(!$.data(this.element[0], 'draggable')) return;
+ this.options.handle.removeMouseInteraction();
+ this.element
+ .removeClass("ui-draggable ui-draggable-disabled")
+ .removeData("draggable")
+ .unbind(".draggable");
+ },
+ enable: function() {
+ this.element.removeClass("ui-draggable-disabled");
+ this.options.disabled = false;
+ },
+ disable: function() {
+ this.element.addClass("ui-draggable-disabled");
+ this.options.disabled = true;
+ },
+ setContrains: function(minLeft,maxLeft,minTop,maxTop) {
+ this.minLeft = minLeft; this.maxLeft = maxLeft;
+ this.minTop = minTop; this.maxTop = maxTop;
+ this.constrainsSet = true;
+ },
+ checkConstrains: function() {
+ if(!this.constrainsSet) return;
+ if(this.position.left < this.minLeft) this.position.left = this.minLeft;
+ if(this.position.left > this.maxLeft - this.helperProportions.width) this.position.left = this.maxLeft - this.helperProportions.width;
+ if(this.position.top < this.minTop) this.position.top = this.minTop;
+ if(this.position.top > this.maxTop - this.helperProportions.height) this.position.top = this.maxTop - this.helperProportions.height;
+ },
+ recallOffset: function(e) {
+
+ var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top };
+ var r = this.helper.css('position') == 'relative';
+
+ //Generate the original position
+ this.originalPosition = {
+ left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)),
+ top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop))
+ };
+
+ //Generate a flexible offset that will later be subtracted from e.pageX/Y
+ this.offset = {left: this._pageX - this.originalPosition.left, top: this._pageY - this.originalPosition.top };
+
+ },
+ start: function(e) {
+ var o = this.options;
+ if($.ui.ddmanager) $.ui.ddmanager.current = this;
+
+ //Create and append the visible helper
+ this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone().appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)) : this.element);
+ if(this.helper[0] != this.element[0]) this.helper.css('position', 'absolute');
+ if(!this.helper.parents('body').length) this.helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
+
+
+ //Find out the next positioned parent
+ this.offsetParent = (function(cp) {
+ while(cp) {
+ if(cp.style && (/(absolute|relative|fixed)/).test($.css(cp,'position'))) return $(cp);
+ cp = cp.parentNode ? cp.parentNode : null;
+ }; return $("body");
+ })(this.helper[0].parentNode);
+
+ //Prepare variables for position generation
+ this.elementOffset = this.element.offset();
+ this.offsetParentOffset = this.offsetParent.offset();
+ var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top };
+ this._pageX = e.pageX; this._pageY = e.pageY;
+ this.clickOffset = { left: e.pageX - this.elementOffset.left, top: e.pageY - this.elementOffset.top };
+ var r = this.helper.css('position') == 'relative';
+
+ //Generate the original position
+ this.originalPosition = {
+ left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)),
+ top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop))
+ };
+
+ //If we have a fixed element, we must subtract the scroll offset again
+ if(this.element.css('position') == 'fixed') {
+ this.originalPosition.top -= this.offsetParent[0] == document.body ? $(document).scrollTop() : this.offsetParent[0].scrollTop;
+ this.originalPosition.left -= this.offsetParent[0] == document.body ? $(document).scrollLeft() : this.offsetParent[0].scrollLeft;
+ }
+
+ //Generate a flexible offset that will later be subtracted from e.pageX/Y
+ this.offset = {left: e.pageX - this.originalPosition.left, top: e.pageY - this.originalPosition.top };
+
+ //Substract margins
+ if(this.element[0] != this.helper[0]) {
+ this.offset.left += parseInt(this.element.css('marginLeft'),10) || 0;
+ this.offset.top += parseInt(this.element.css('marginTop'),10) || 0;
+ }
+
+ //Call plugins and callbacks
+ this.propagate("start", e);
+
+ this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };
+ if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e);
+
+ //If we have something in cursorAt, we'll use it
+ if(o.cursorAt) {
+ if(o.cursorAt.top != undefined || o.cursorAt.bottom != undefined) {
+ this.offset.top -= this.clickOffset.top - (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom));
+ this.clickOffset.top = (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom));
+ }
+ if(o.cursorAt.left != undefined || o.cursorAt.right != undefined) {
+ this.offset.left -= this.clickOffset.left - (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right));
+ this.clickOffset.left = (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right));
+ }
+ }
+
+ return false;
+
+ },
+ clear: function() {
+ if($.ui.ddmanager) $.ui.ddmanager.current = null;
+ this.helper = null;
+ },
+ stop: function(e) {
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
+ $.ui.ddmanager.drop(this, e);
+
+ //Call plugins and trigger callbacks
+ this.propagate("stop", e);
+
+ if(this.cancelHelperRemoval) return false;
+ if(this.options.helper != 'original') this.helper.remove();
+ this.clear();
+
+ return false;
+ },
+ drag: function(e) {
+
+ //Compute the helpers position
+ this.position = { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left };
+ this.positionAbs = { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top };
+
+ //Call plugins and callbacks
+ this.checkConstrains();
+ this.position = this.propagate("drag", e) || this.position;
+ this.checkConstrains();
+
+ $(this.helper).css({ left: this.position.left+'px', top: this.position.top+'px' }); // Stick the helper to the cursor
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, e);
+ return false;
+
+ }
+ });
+
+/*
+ * Draggable Extensions
+ */
+
+ $.ui.plugin.add("draggable", "cursor", {
+ start: function(e, ui) {
+ var t = $('body');
+ if (t.css("cursor")) ui.options._cursor = t.css("cursor");
+ t.css("cursor", ui.options.cursor);
+ },
+ stop: function(e, ui) {
+ if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
+ }
+ });
+
+ $.ui.plugin.add("draggable", "zIndex", {
+ start: function(e, ui) {
+ var t = $(ui.helper);
+ if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
+ t.css('zIndex', ui.options.zIndex);
+ },
+ stop: function(e, ui) {
+ if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
+ }
+ });
+
+ $.ui.plugin.add("draggable", "opacity", {
+ start: function(e, ui) {
+ var t = $(ui.helper);
+ if(t.css("opacity")) ui.options._opacity = t.css("opacity");
+ t.css('opacity', ui.options.opacity);
+ },
+ stop: function(e, ui) {
+ if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
+ }
+ });
+
+
+ $.ui.plugin.add("draggable", "revert", {
+ stop: function(e, ui) {
+ var self = ui.instance, helper = $(self.helper);
+ self.cancelHelperRemoval = true;
+
+ $(ui.helper).animate({ left: self.originalPosition.left, top: self.originalPosition.top }, parseInt(ui.options.revert, 10) || 500, function() {
+ if(ui.options.helper != 'original') helper.remove();
+ if (!helper) self.clear();
+ });
+ }
+ });
+
+ $.ui.plugin.add("draggable", "iframeFix", {
+ start: function(e, ui) {
+
+ var o = ui.options;
+ if(ui.instance.slowMode) return; // Make clones on top of iframes (only if we are not in slowMode)
+
+ if(o.iframeFix.constructor == Array) {
+ for(var i=0;i<o.iframeFix.length;i++) {
+ var co = $(o.iframeFix[i]).offset({ border: false });
+ $('<div class="DragDropIframeFix"" style="background: #fff;"></div>').css("width", $(o.iframeFix[i])[0].offsetWidth+"px").css("height", $(o.iframeFix[i])[0].offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body");
+ }
+ } else {
+ $("iframe").each(function() {
+ var co = $(this).offset({ border: false });
+ $('<div class="DragDropIframeFix" style="background: #fff;"></div>').css("width", this.offsetWidth+"px").css("height", this.offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body");
+ });
+ }
+
+ },
+ stop: function(e, ui) {
+ if(ui.options.iframeFix) $("div.DragDropIframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
+ }
+ });
+
+ $.ui.plugin.add("draggable", "containment", {
+ start: function(e, ui) {
+
+ var o = ui.options;
+ var self = ui.instance;
+ if((o.containment.left != undefined || o.containment.constructor == Array) && !o._containment) return;
+ if(!o._containment) o._containment = o.containment;
+
+ if(o._containment == 'parent') o._containment = this[0].parentNode;
+ if(o._containment == 'document') {
+ o.containment = [
+ 0,
+ 0,
+ $(document).width(),
+ ($(document).height() || document.body.parentNode.scrollHeight)
+ ];
+ } else { //I'm a node, so compute top/left/right/bottom
+
+ var ce = $(o._containment)[0];
+ var co = $(o._containment).offset();
+
+ o.containment = [
+ co.left,
+ co.top,
+ co.left+(ce.offsetWidth || ce.scrollWidth),
+ co.top+(ce.offsetHeight || ce.scrollHeight)
+ ];
+ }
+
+ var c = o.containment;
+ ui.instance.setContrains(
+ c[0] - (self.offset.left - self.clickOffset.left), //min left
+ c[2] - (self.offset.left - self.clickOffset.left), //max left
+ c[1] - (self.offset.top - self.clickOffset.top), //min top
+ c[3] - (self.offset.top - self.clickOffset.top) //max top
+ );
+
+ }
+ });
+
+ $.ui.plugin.add("draggable", "grid", {
+ drag: function(e, ui) {
+ var o = ui.options;
+ var newLeft = ui.instance.originalPosition.left + Math.round((e.pageX - ui.instance._pageX) / o.grid[0]) * o.grid[0];
+ var newTop = ui.instance.originalPosition.top + Math.round((e.pageY - ui.instance._pageY) / o.grid[1]) * o.grid[1];
+
+ ui.instance.position.left = newLeft;
+ ui.instance.position.top = newTop;
+
+ }
+ });
+
+ $.ui.plugin.add("draggable", "axis", {
+ drag: function(e, ui) {
+ var o = ui.options;
+ if(o.constraint) o.axis = o.constraint; //Legacy check
+ switch (o.axis) {
+ case 'x' : ui.instance.position.top = ui.instance.originalPosition.top; break;
+ case 'y' : ui.instance.position.left = ui.instance.originalPosition.left; break;
+ }
+ }
+ });
+
+ $.ui.plugin.add("draggable", "scroll", {
+ start: function(e, ui) {
+ var o = ui.options;
+ o.scrollSensitivity = o.scrollSensitivity || 20;
+ o.scrollSpeed = o.scrollSpeed || 20;
+
+ ui.instance.overflowY = function(el) {
+ do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode);
+ return $(document);
+ }(this);
+ ui.instance.overflowX = function(el) {
+ do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode);
+ return $(document);
+ }(this);
+ },
+ drag: function(e, ui) {
+
+ var o = ui.options;
+ var i = ui.instance;
+
+ if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') {
+ if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)
+ i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed;
+ if((ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)
+ i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed;
+ } else {
+ //$(document.body).append('<p>'+(e.pageY - $(document).scrollTop())+'</p>');
+ if(e.pageY - $(document).scrollTop() < o.scrollSensitivity)
+ $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+ $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') {
+ if(i.overflowX[0].offsetWidth - (ui.position.left - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity)
+ i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed;
+ if((ui.position.top - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity)
+ i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed;
+ } else {
+ if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+ $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+ $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ ui.instance.recallOffset(e);
+
+ }
+ });
+
+ $.ui.plugin.add("draggable", "snap", {
+ start: function(e, ui) {
+
+ ui.instance.snapElements = [];
+ $(ui.options.snap === true ? '.ui-draggable' : ui.options.snap).each(function() {
+ var $t = $(this); var $o = $t.offset();
+ if(this != ui.instance.element[0]) ui.instance.snapElements.push({
+ item: this,
+ width: $t.outerWidth(),
+ height: $t.outerHeight(),
+ top: $o.top,
+ left: $o.left
+ });
+ });
+
+ },
+ drag: function(e, ui) {
+
+ var d = ui.options.snapTolerance || 20;
+ var x1 = ui.absolutePosition.left, x2 = x1 + ui.instance.helperProportions.width,
+ y1 = ui.absolutePosition.top, y2 = y1 + ui.instance.helperProportions.height;
+
+ for (var i = ui.instance.snapElements.length - 1; i >= 0; i--){
+
+ var l = ui.instance.snapElements[i].left, r = l + ui.instance.snapElements[i].width,
+ t = ui.instance.snapElements[i].top, b = t + ui.instance.snapElements[i].height;
+
+ //Yes, I know, this is insane ;)
+ if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) continue;
+
+ if(ui.options.snapMode != 'inner') {
+ var ts = Math.abs(t - y2) <= 20;
+ var bs = Math.abs(b - y1) <= 20;
+ var ls = Math.abs(l - x2) <= 20;
+ var rs = Math.abs(r - x1) <= 20;
+ if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height;
+ if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top;
+ if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width;
+ if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left;
+ }
+
+ if(ui.options.snapMode != 'outer') {
+ var ts = Math.abs(t - y1) <= 20;
+ var bs = Math.abs(b - y2) <= 20;
+ var ls = Math.abs(l - x1) <= 20;
+ var rs = Math.abs(r - x2) <= 20;
+ if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top;
+ if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height;
+ if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left;
+ if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width;
+ }
+
+ };
+ }
+ });
+
+ $.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(e,ui) {
+ ui.instance.sortable = $.data($(ui.options.connectToSortable)[0], 'sortable');
+ ui.instance.sortableOffset = ui.instance.sortable.element.offset();
+ ui.instance.sortableOuterWidth = ui.instance.sortable.element.outerWidth();
+ ui.instance.sortableOuterHeight = ui.instance.sortable.element.outerHeight();
+ if(ui.instance.sortable.options.revert) ui.instance.sortable.shouldRevert = true;
+ },
+ stop: function(e,ui) {
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = ui.instance.sortable;
+ if(inst.isOver) {
+ inst.isOver = 0;
+ ui.instance.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ inst.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+ if(inst.shouldRevert) inst.options.revert = true; //revert here
+ inst.stop(e);
+ inst.options.helper = "original";
+ }
+ },
+ drag: function(e,ui) {
+ //This is handy: We reuse the intersectsWith method for checking if the current draggable helper
+ //intersects with the sortable container
+ var inst = ui.instance.sortable;
+ ui.instance.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix
+
+ if(inst.intersectsWith.call(ui.instance, {
+ left: ui.instance.sortableOffset.left, top: ui.instance.sortableOffset.top,
+ width: ui.instance.sortableOuterWidth, height: ui.instance.sortableOuterHeight
+ })) {
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!inst.isOver) {
+ inst.isOver = 1;
+
+ //Cache the width/height of the new helper
+ var height = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerHeight() : $(inst.options.items, inst.element).innerHeight();
+ var width = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerWidth() : $(inst.options.items, inst.element).innerWidth();
+
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ inst.currentItem = $(this).clone().appendTo(inst.element);
+ inst.options.helper = function() { return ui.helper[0]; };
+ inst.start(e);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ inst.clickOffset.top = ui.instance.clickOffset.top;
+ inst.clickOffset.left = ui.instance.clickOffset.left;
+ inst.offset.left -= ui.absolutePosition.left - inst.position.absolute.left;
+ inst.offset.top -= ui.absolutePosition.top - inst.position.absolute.top;
+
+ //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now)
+ inst.helperProportions = { width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there
+ ui.helper.animate({ height: height, width: width}, 500);
+ ui.instance.propagate("toSortable", e);
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(inst.currentItem) inst.drag(e);
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(inst.isOver) {
+ inst.isOver = 0;
+ inst.cancelHelperRemoval = true;
+ inst.options.revert = false; //No revert here
+ inst.stop(e);
+ inst.options.helper = "original";
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ inst.currentItem.remove();
+ inst.placeholder.remove();
+
+ ui.helper.animate({ height: this.innerHeight(), width: this.innerWidth() }, 500);
+ ui.instance.propagate("fromSortable", e);
+ }
+
+ };
+ }
+ })
+
+ //TODO: wrapHelper
+
+})(jQuery);
+
diff --git a/moksha/widgetbrowser/static/ui.resizable.js b/moksha/widgetbrowser/static/ui.resizable.js
new file mode 100644
index 0000000..409195e
--- /dev/null
+++ b/moksha/widgetbrowser/static/ui.resizable.js
@@ -0,0 +1,710 @@
+/*
+ * jQuery UI Resizable
+ *
+ * Copyright (c) 2008 Paul Bakaus
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ * ui.base.js
+ *
+ * Revision: $Id: ui.resizable.js 5205 2008-04-06 16:12:50Z braeker $
+ */
+;(function($) {
+
+ $.fn.extend({
+ resizable: function(options, data) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ if (typeof options == "string") {
+ var resize = $.data(this, "resizable");
+ if (resize) resize[options].apply(resize, args);
+
+ } else if(!$(this).is(".ui-resizable"))
+ new $.ui.resizable(this, options);
+ });
+ }
+ });
+
+ $.ui.resizable = function(element, options) {
+ //Initialize needed constants
+ var self = this;
+
+ this.element = $(element);
+
+ $.data(element, "resizable", this);
+
+ // simulate .ui-resizable { position: relative; }
+ var elpos = this.element.css('position');
+ this.element.addClass("ui-resizable").css({ position: /static/.test(elpos) ? 'relative' : elpos });
+
+ //Prepare the passed options
+ this.options = $.extend({
+ preventDefault: true,
+ transparent: false,
+ minWidth: 10,
+ minHeight: 10,
+ aspectRatio: false,
+ disableSelection: true,
+ preserveCursor: true,
+ autohide: false,
+ knobHandles: false
+ }, options);
+
+ this.options._aspectRatio = !!(this.options.aspectRatio);
+
+ // force proxy if helper is enabled
+ this.options.proxy = this.options.proxy || this.options.ghost ? 'proxy' : null;
+
+ // force proxy if animation is enabled
+ this.options.proxy = this.options.proxy || this.options.animate ? 'proxy' : null;
+
+ // if knobHandles equals true set to ui-resizable-knob-handle
+ this.options.knobHandles = this.options.knobHandles === true ? 'ui-resizable-knob-handle' : this.options.knobHandles;
+
+ $(element).bind("setData.resizable", function(event, key, value){
+ self.options[key] = value;
+ }).bind("getData.resizable", function(event, key){
+ return self.options[key];
+ });
+
+ var o = this.options;
+
+ //Default Theme
+ var aBorder = '1px solid #DEDEDE';
+
+ o.defaultTheme = {
+ 'ui-resizable': { display: 'block' },
+ 'ui-resizable-handle': { position: 'absolute', background: '#F2F2F2', fontSize: '0.1px' },
+ 'ui-resizable-n': { cursor: 'n-resize', height: '4px', left: '0px', right: '0px', borderTop: aBorder },
+ 'ui-resizable-s': { cursor: 's-resize', height: '4px', left: '0px', right: '0px', borderBottom: aBorder },
+ 'ui-resizable-e': { cursor: 'e-resize', width: '4px', top: '0px', bottom: '0px', borderRight: aBorder },
+ 'ui-resizable-w': { cursor: 'w-resize', width: '4px', top: '0px', bottom: '0px', borderLeft: aBorder },
+ 'ui-resizable-se': { cursor: 'se-resize', width: '4px', height: '4px', borderRight: aBorder, borderBottom: aBorder },
+ 'ui-resizable-sw': { cursor: 'sw-resize', width: '4px', height: '4px', borderBottom: aBorder, borderLeft: aBorder },
+ 'ui-resizable-ne': { cursor: 'ne-resize', width: '4px', height: '4px', borderRight: aBorder, borderTop: aBorder },
+ 'ui-resizable-nw': { cursor: 'nw-resize', width: '4px', height: '4px', borderLeft: aBorder, borderTop: aBorder }
+ };
+
+ o.knobTheme = {
+ 'ui-resizable-handle': { background: '#F2F2F2', border: '1px solid #808080', height: '8px', width: '8px' },
+ 'ui-resizable-n': { cursor: 'n-resize', top: '-4px', left: '45%' },
+ 'ui-resizable-s': { cursor: 's-resize', bottom: '-4px', left: '45%' },
+ 'ui-resizable-e': { cursor: 'e-resize', right: '-4px', top: '45%' },
+ 'ui-resizable-w': { cursor: 'w-resize', left: '-4px', top: '45%' },
+ 'ui-resizable-se': { cursor: 'se-resize', right: '-4px', bottom: '-4px' },
+ 'ui-resizable-sw': { cursor: 'sw-resize', left: '-4px', bottom: '-4px' },
+ 'ui-resizable-nw': { cursor: 'nw-resize', left: '-4px', top: '-4px' },
+ 'ui-resizable-ne': { cursor: 'ne-resize', right: '-4px', top: '-4px' }
+ };
+
+ //Position the node
+ if(!o.proxy && (this.element.css('position') == 'static' || this.element.css('position') === ''))
+ this.element.css('position', 'relative');
+
+ o._nodeName = element.nodeName;
+
+ //Wrap the element if it cannot hold child nodes
+ if(o._nodeName.match(/textarea|input|select|button|img/i)) {
+ var el = this.element;
+
+ //Opera fixing relative position
+ if (/relative/.test(el.css('position')) && $.browser.opera)
+ el.css({ position: 'relative', top: 'auto', left: 'auto' });
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ el.wrap(
+ $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css( {
+ position: el.css('position'),
+ width: el.outerWidth(),
+ height: el.outerHeight(),
+ top: el.css('top'),
+ left: el.css('left')
+ })
+ );
+
+ var oel = this.element; element = element.parentNode; this.element = $(element);
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: oel.css("marginLeft"), marginTop: oel.css("marginTop"),
+ marginRight: oel.css("marginRight"), marginBottom: oel.css("marginBottom")
+ });
+
+ oel.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ if ($.browser.safari && o.preventDefault) oel.css('resize', 'none');
+
+ o.proportionallyResize = oel.css({ position: 'static', zoom: 1, display: 'block' });
+
+ // avoid IE jump
+ this.element.css({ margin: oel.css('margin') });
+
+ // fix handlers offset
+ this._proportionallyResize();
+ }
+
+ if(!o.handles) o.handles = !$('.ui-resizable-handle', element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' };
+ if(o.handles.constructor == String) {
+
+ if(o.handles == 'all') o.handles = 'n,e,s,w,se,sw,ne,nw';
+
+ var n = o.handles.split(","); o.handles = {};
+
+ o.zIndex = o.zIndex || 1000;
+
+ // insertions are applied when don't have theme loaded
+ var insertionsDefault = {
+ handle: 'position: absolute; display: none; overflow:hidden;',
+ n: 'top: 0pt; width:100%;',
+ e: 'right: 0pt; height:100%;',
+ s: 'bottom: 0pt; width:100%;',
+ w: 'left: 0pt; height:100%;',
+ se: 'bottom: 0pt; right: 0px;',
+ sw: 'bottom: 0pt; left: 0px;',
+ ne: 'top: 0pt; right: 0px;',
+ nw: 'top: 0pt; left: 0px;'
+ };
+
+ for(var i = 0; i < n.length; i++) {
+ var handle = jQuery.trim(n[i]), dt = o.defaultTheme, hname = 'ui-resizable-'+handle, loadDefault = !$.ui.css(hname) && !o.knobHandles, userKnobClass = $.ui.css('ui-resizable-knob-handle'),
+ allDefTheme = $.extend(dt[hname], dt['ui-resizable-handle']), allKnobTheme = $.extend(o.knobTheme[hname], !userKnobClass ? o.knobTheme['ui-resizable-handle'] : {});
+
+ // increase zIndex of sw, se, ne, nw axis
+ var applyZIndex = /sw|se|ne|nw/.test(handle) ? { zIndex: ++o.zIndex } : {};
+
+ var defCss = (loadDefault ? insertionsDefault[handle] : ''),
+ axis = $(['<div class="ui-resizable-handle ', hname, '" style="', defCss, insertionsDefault.handle, '"></div>'].join('')).css( applyZIndex );
+ o.handles[handle] = '.ui-resizable-'+handle;
+
+ this.element.append(
+ //Theme detection, if not loaded, load o.defaultTheme
+ axis.css( loadDefault ? allDefTheme : {} )
+ // Load the knobHandle css, fix width, height, top, left...
+ .css( o.knobHandles ? allKnobTheme : {} ).addClass(o.knobHandles ? 'ui-resizable-knob-handle' : '').addClass(o.knobHandles)
+ );
+ }
+
+ if (o.knobHandles) this.element.addClass('ui-resizable-knob').css( !$.ui.css('ui-resizable-knob') ? { /*border: '1px #fff dashed'*/ } : {} );
+ }
+
+ this._renderAxis = function(target) {
+ target = target || this.element;
+
+ for(var i in o.handles) {
+ if(o.handles[i].constructor == String)
+ o.handles[i] = $(o.handles[i], element).show();
+
+ if (o.transparent)
+ o.handles[i].css({opacity:0});
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.element.is('.ui-wrapper') &&
+ o._nodeName.match(/textarea|input|select|button/i)) {
+
+ var axis = $(o.handles[i], element), padWrapper = 0;
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ var padPos = [ 'padding',
+ /ne|nw|n/.test(i) ? 'Top' :
+ /se|sw|s/.test(i) ? 'Bottom' :
+ /^e$/.test(i) ? 'Right' : 'Left' ].join("");
+
+ if (!o.transparent)
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+ }
+ if(!$(o.handles[i]).length) continue;
+ }
+ };
+
+ this._renderAxis(this.element);
+ o._handles = $('.ui-resizable-handle', self.element);
+
+ if (o.disableSelection)
+ o._handles.each(function(i, e) { $.ui.disableSelection(e); });
+
+ //Matching axis name
+ o._handles.mouseover(function() {
+ if (!o.resizing) {
+ if (this.className)
+ var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ //Axis, default = se
+ self.axis = o.axis = axis && axis[1] ? axis[1] : 'se';
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autohide) {
+ o._handles.hide();
+ $(self.element).addClass("ui-resizable-autohide").hover(function() {
+ $(this).removeClass("ui-resizable-autohide");
+ o._handles.show();
+ },
+ function(){
+ if (!o.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ o._handles.hide();
+ }
+ });
+ }
+
+ //Initialize mouse events for interaction
+ this.element.mouseInteraction({
+ executor: this,
+ delay: 0,
+ distance: 0,
+ dragPrevention: ['input','textarea','button','select','option'],
+ start: this.start,
+ stop: this.stop,
+ drag: this.drag,
+ condition: function(e) {
+ if(this.disabled) return false;
+ for(var i in this.options.handles) {
+ if($(this.options.handles[i])[0] == e.target) return true;
+ }
+ return false;
+ }
+ });
+ };
+
+ $.extend($.ui.resizable.prototype, {
+ plugins: {},
+ ui: function() {
+ return {
+ instance: this,
+ axis: this.options.axis,
+ options: this.options
+ };
+ },
+ _renderProxy: function() {
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(o.proxy) {
+ this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
+
+ // fix ie6 offset
+ var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
+ pxyoffset = ( ie6 ? 2 : -1 );
+
+ this.helper.addClass(o.proxy).css({
+ width: el.outerWidth() + pxyoffset,
+ height: el.outerHeight() + pxyoffset,
+ position: 'absolute',
+ left: this.elementOffset.left - ie6offset +'px',
+ top: this.elementOffset.top - ie6offset +'px',
+ zIndex: ++o.zIndex
+ });
+
+ this.helper.appendTo("body");
+
+ if (o.disableSelection)
+ $.ui.disableSelection(this.helper.get(0));
+
+ } else {
+ this.helper = el;
+ }
+ },
+ propagate: function(n,e) {
+ $.ui.plugin.call(this, n, [e, this.ui()]);
+ this.element.triggerHandler(n == "resize" ? n : ["resize", n].join(""), [e, this.ui()], this.options[n]);
+ },
+ destroy: function() {
+ var el = this.element, wrapped = el.children(".ui-resizable").get(0),
+
+ _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled")
+ .removeMouseInteraction().removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
+ };
+
+ _destroy(el);
+
+ if (el.is('.ui-wrapper') && wrapped) {
+ el.parent().append(
+ $(wrapped).css({
+ position: el.css('position'),
+ width: el.outerWidth(),
+ height: el.outerHeight(),
+ top: el.css('top'),
+ left: el.css('left')
+ })
+ ).end().remove();
+
+ _destroy(wrapped);
+ }
+ },
+ enable: function() {
+ this.element.removeClass("ui-resizable-disabled");
+ this.disabled = false;
+ },
+ disable: function() {
+ this.element.addClass("ui-resizable-disabled");
+ this.disabled = true;
+ },
+ start: function(e) {
+ var o = this.options, iniPos = this.element.position(), el = this.element,
+ num = function(v) { return parseInt(v, 10) || 0; }, ie6 = $.browser.msie && $.browser.version < 7;
+ o.resizing = true;
+ o.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
+
+ // bugfix #1749
+ if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
+
+ // sOffset decides if document scrollOffset will be added to the top/left of the resizable element
+ var sOffset = $.browser.msie && !o.containment && (/absolute/).test(el.css('position')) && !(/relative/).test(el.parent().css('position'));
+ var dscrollt = sOffset ? o.documentScroll.top : 0, dscrolll = sOffset ? o.documentScroll.left : 0;
+
+ el.css({ position: 'absolute', top: (iniPos.top + dscrollt), left: (iniPos.left + dscrolll) });
+ }
+
+ //Opera fixing relative position
+ if (/relative/.test(el.css('position')) && $.browser.opera)
+ el.css({ position: 'relative', top: 'auto', left: 'auto' });
+
+ this._renderProxy();
+
+ var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = o.proxy || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalSize = o.proxy || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: e.pageX, top: e.pageY };
+
+ //Aspect Ratio
+ o.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.height / this.originalSize.width)||1);
+
+ if (o.preserveCursor)
+ $('body').css('cursor', this.axis + '-resize');
+
+ this.propagate("start", e);
+ return false;
+ },
+ stop: function(e) {
+ this.options.resizing = false;
+ var o = this.options, num = function(v) { return parseInt(v, 10) || 0; }, self = this;
+
+ if(o.proxy) {
+ var pr = o.proportionallyResize, ista = pr && /textarea/i.test(pr.get(0).nodeName),
+ soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
+ left = parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left),
+ top = parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top);
+
+ if (!o.animate)
+ this.element.css($.extend(style, { top: top, left: left }));
+
+ if (o.proxy && !o.animate) this._proportionallyResize();
+ this.helper.remove();
+ }
+
+ if (o.preserveCursor)
+ $('body').css('cursor', 'auto');
+
+ this.propagate("stop", e);
+ return false;
+ },
+ drag: function(e) {
+ //Increase performance, avoid regex
+ var el = this.helper, o = this.options, props = {},
+ self = this, smp = this.originalMousePosition, a = this.axis;
+
+ var dx = (e.pageX-smp.left)||0, dy = (e.pageY-smp.top)||0;
+ var trigger = this.change[a];
+ if (!trigger) return false;
+
+ // Calculate the attrs that will be change
+ var data = trigger.apply(this, [e, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
+
+ if (o._aspectRatio || e.shiftKey)
+ data = this._updateRatio(data, e);
+
+ data = this._respectSize(data, e);
+
+ this.propagate("resize", e);
+
+ el.css({
+ top: this.position.top + "px", left: this.position.left + "px",
+ width: this.size.width + "px", height: this.size.height + "px"
+ });
+
+ if (!o.proxy && o.proportionallyResize)
+ this._proportionallyResize();
+
+ this._updateCache(data);
+
+ return false;
+ },
+
+ _updateCache: function(data) {
+ var o = this.options;
+ this.offset = this.helper.offset();
+ if (data.left) this.position.left = data.left;
+ if (data.top) this.position.top = data.top;
+ if (data.height) this.size.height = data.height;
+ if (data.width) this.size.width = data.width;
+ },
+
+ _updateRatio: function(data, e) {
+ var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
+
+ if (data.height) data.width = Math.round(csize.height / o.aspectRatio);
+ else if (data.width) data.height = Math.round(csize.width * o.aspectRatio);
+
+ if (a == 'sw') {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a == 'nw') {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function(data, e) {
+
+ var el = this.helper, o = this.options, pRatio = o._aspectRatio || e.shiftKey, a = this.axis,
+ ismaxw = data.width && o.maxWidth && o.maxWidth < data.width, ismaxh = data.height && o.maxHeight && o.maxHeight < data.height,
+ isminw = data.width && o.minWidth && o.minWidth > data.width, isminh = data.height && o.minHeight && o.minHeight > data.height;
+
+ if (isminw) data.width = o.minWidth;
+ if (isminh) data.height = o.minHeight;
+ if (ismaxw) data.width = o.maxWidth;
+ if (ismaxh) data.height = o.maxHeight;
+
+ var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
+ var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+
+ if (isminw && cw) data.left = dw - o.minWidth;
+ if (ismaxw && cw) data.left = dw - o.maxWidth;
+ if (isminh && ch) data.top = dh - o.minHeight;
+ if (ismaxh && ch) data.top = dh - o.maxHeight;
+
+ // fixing jump error on top/left - bug #2330
+ var isNotwh = !data.width && !data.height;
+ if (isNotwh && !data.left && data.top) data.top = null;
+ else if (isNotwh && !data.top && data.left) data.left = null;
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+ var o = this.options;
+ if (!o.proportionallyResize) return;
+ var prel = o.proportionallyResize, el = this.helper || this.element;
+
+ if (!o.borderDif) {
+ var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
+ p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
+
+ o.borderDif = $.map(b, function(v, i) {
+ var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
+ return border + padding;
+ });
+ }
+ prel.css({
+ height: (el.height() - o.borderDif[0] - o.borderDif[2]) + "px",
+ width: (el.width() - o.borderDif[1] - o.borderDif[3]) + "px"
+ });
+ },
+
+ change: {
+ e: function(e, dx, dy) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(e, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(e, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(e, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(e, dx, dy) {
+ return $.extend(this.change.s.apply(this, arguments), this.change.e.apply(this, [e, dx, dy]));
+ },
+ sw: function(e, dx, dy) {
+ return $.extend(this.change.s.apply(this, arguments), this.change.w.apply(this, [e, dx, dy]));
+ },
+ ne: function(e, dx, dy) {
+ return $.extend(this.change.n.apply(this, arguments), this.change.e.apply(this, [e, dx, dy]));
+ },
+ nw: function(e, dx, dy) {
+ return $.extend(this.change.n.apply(this, arguments), this.change.w.apply(this, [e, dx, dy]));
+ }
+ }
+ });
+
+/*
+ * Resizable Extensions
+ */
+
+ $.ui.plugin.add("resizable", "containment", {
+
+ start: function(e, ui) {
+ var o = ui.options, self = ui.instance, el = self.element;
+ var oc = o.containment, ce = (oc instanceof jQuery) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+ if (!ce) return;
+
+ if (/document/.test(oc) || oc == document) {
+ self.containerOffset = { left: 0, top: 0 };
+
+ self.parentData = {
+ element: $(document), left: 0, top: 0, width: $(document).width(),
+ height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else{
+ self.containerOffset = $(ce).offset(), self.containerSize = { height: $(ce).innerHeight(), width: $(ce).innerWidth() };
+
+ var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ self.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function(e, ui) {
+ var o = ui.options, self = ui.instance, ps = self.containerSize,
+ co = self.containerOffset, cs = self.size, cp = self.position,
+ pRatio = o._aspectRatio || e.shiftKey;
+
+ if (cp.left < (o.proxy ? co.left : 0)) {
+ self.size.width = self.size.width + (o.proxy ? (self.position.left - co.left) : self.position.left);
+ if (pRatio) self.size.height = self.size.width * o.aspectRatio;
+ self.position.left = o.proxy ? co.left : 0;
+ }
+
+ if (cp.top < (o.proxy ? co.top : 0)) {
+ self.size.height = self.size.height + (o.proxy ? (self.position.top - co.top) : self.position.top);
+ if (pRatio) self.size.width = self.size.height / o.aspectRatio;
+ self.position.top = o.proxy ? co.top : 0;
+ }
+
+ var woset = (o.proxy ? self.offset.left - co.left : self.position.left) + self.sizeDiff.width,
+ hoset = (o.proxy ? self.offset.top - co.top : self.position.top) + self.sizeDiff.height;
+
+ if (woset + self.size.width >= self.parentData.width) {
+ self.size.width = self.parentData.width - woset;
+ if (pRatio) self.size.height = self.size.width * o.aspectRatio;
+ }
+
+ if (hoset + self.size.height >= self.parentData.height) {
+ self.size.height = self.parentData.height - hoset;
+ if (pRatio) self.size.width = self.size.height / o.aspectRatio;
+ }
+ }
+ });
+
+ $.ui.plugin.add("resizable", "grid", {
+
+ resize: function(e, ui) {
+ var o = ui.options, self = ui.instance, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || e.shiftKey;
+ o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
+ var ox = Math.round((cs.width - os.width) / o.grid[0]) * o.grid[0], oy = Math.round((cs.height - os.height) / o.grid[1]) * o.grid[1];
+
+ if (/^(se|s|e)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ }
+ else if (/^(ne)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ }
+ else if (/^(sw)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.left = op.left - ox;
+ }
+ else {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ self.position.left = op.left - ox;
+ }
+ }
+
+ });
+
+ $.ui.plugin.add("resizable", "animate", {
+
+ stop: function(e, ui) {
+ var o = ui.options, self = ui.instance;
+
+ var pr = o.proportionallyResize, ista = pr && /textarea/i.test(pr.get(0).nodeName),
+ soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
+ left = parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left),
+ top = parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top);
+
+ self.element.animate(
+ $.extend(style, { top: top, left: left }),
+ {
+ duration: o.animateDuration || "slow",
+ easing: o.animateEasing || "swing",
+ step: function() {
+ if (pr) pr.css({ width: self.element.css('width'), height: self.element.css('height') });
+ }
+ }
+ );
+ }
+
+ });
+
+ $.ui.plugin.add("resizable", "ghost", {
+
+ start: function(e, ui) {
+ var o = ui.options, self = ui.instance, pr = o.proportionallyResize, cs = self.size;
+
+ if (!pr) self.ghost = self.element.clone();
+ else self.ghost = pr.clone();
+
+ self.ghost.css(
+ { opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }
+ )
+ .addClass('ui-resizable-ghost').addClass(typeof o.ghost == 'string' ? o.ghost : '');
+
+ self.ghost.appendTo(self.helper);
+
+ },
+
+ resize: function(e, ui){
+ var o = ui.options, self = ui.instance, pr = o.proportionallyResize;
+
+ if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
+
+ },
+
+ stop: function(e, ui){
+ var o = ui.options, self = ui.instance, pr = o.proportionallyResize;
+ if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
+ }
+
+ });
+
+})(jQuery);
diff --git a/moksha/widgetbrowser/static/ui.tabs.css b/moksha/widgetbrowser/static/ui.tabs.css
new file mode 100644
index 0000000..0eabf94
--- /dev/null
+++ b/moksha/widgetbrowser/static/ui.tabs.css
@@ -0,0 +1,114 @@
+/* Caution! Ensure accessibility in print and other media types... */
+@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
+ .ui-tabs-hide {
+ display: none;
+ }
+}
+
+/* Hide useless elements in print layouts... */
+@media print {
+ .ui-tabs-nav {
+ display: none;
+ }
+}
+
+/* Skin */
+.ui-tabs-nav {
+ list-style: none;
+ margin: 0 !important;
+ padding: 0 0 0 4px;
+}
+.ui-tabs-nav li {
+ list-style-image: none !important;
+ margin: 0 !important;
+ padding: 0 0 0 4px;
+}
+
+.ui-tabs-panel {
+ border-top: #94ADA7 solid 1px;
+ padding-top: 5px;
+ clear: left;
+}
+
+/* IE6 hack */
+* html .ui-tabs-panel {
+ margin-top: -1.2em;
+}
+
+.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
+ display: block;
+ clear: both;
+ content: " ";
+}
+.ui-tabs-nav li {
+ float: left;
+ margin: 0 0 0 1px;
+ min-width: 84px; /* be nice to Opera */
+}
+.ui-tabs-nav a, .ui-tabs-nav a span {
+ display: block;
+ padding: 0 10px;
+ background: url(tab.png) no-repeat;
+}
+.ui-tabs-nav a {
+ position: relative;
+ top: 1px;
+ z-index: 2;
+ padding-left: 0;
+ color: #27537a;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 1.2;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap; /* required in IE 6 */
+}
+.ui-tabs-nav .ui-tabs-selected a {
+ color: #000;
+}
+.ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active {
+ background-position: 100% -150px;
+ outline: 0; /* prevent dotted border in Firefox */
+}
+.ui-tabs-nav a, .ui-tabs-nav .ui-tabs-disabled a:hover, .ui-tabs-nav .ui-tabs-disabled a:focus, .ui-tabs-nav .ui-tabs-disabled a:active {
+ background-position: 100% -100px;
+}
+.ui-tabs-nav a span {
+ width: 64px; /* IE 6 treats width as min-width */
+ min-width: 64px;
+ height: 18px; /* IE 6 treats height as min-height */
+ min-height: 18px;
+ padding-top: 6px;
+ padding-right: 0;
+}
+*>.ui-tabs-nav a span { /* hide from IE 6 */
+ width: auto;
+ height: auto;
+}
+.ui-tabs-nav .ui-tabs-selected a span {
+ padding-top: 7px;
+}
+.ui-tabs-nav .ui-tabs-selected a span, .ui-tabs-nav a:hover span, .ui-tabs-nav a:focus span, .ui-tabs-nav a:active span {
+ background-position: 0 -50px;
+}
+.ui-tabs-nav a span, .ui-tabs-nav .ui-tabs-disabled a:hover span, .ui-tabs-nav .ui-tabs-disabled a:focus span, .ui-tabs-nav .ui-tabs-disabled a:active span {
+ background-position: 0 0;
+}
+.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited, .ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
+ cursor: text;
+}
+.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active { /* @ Opera, we need to be explicit again here now... */
+ cursor: pointer;
+}
+.ui-tabs-nav .ui-tabs-disabled {
+ opacity: .4;
+}
+.ui-tabs-container {
+ border-top: 1px solid #97a5b0;
+ padding: 1em 8px;
+ background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
+}
+.ui-tabs-loading em {
+ padding: 0 0 0 20px;
+ background: url(loading.gif) no-repeat 0 50%;
+}
diff --git a/moksha/widgetbrowser/static/ui.tabs.js b/moksha/widgetbrowser/static/ui.tabs.js
new file mode 100644
index 0000000..f595c10
--- /dev/null
+++ b/moksha/widgetbrowser/static/ui.tabs.js
@@ -0,0 +1,616 @@
+/*
+ * jQuery UI Tabs
+ *
+ * Copyright (c) 2007 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ * ui.base.js
+ *
+ * Revision: $Id: ui.tabs.js 5149 2008-03-31 10:51:18Z rdworth $
+ */
+;(function($) {
+
+ // tabs API methods
+ $.fn.tabs = function() {
+ var method = typeof arguments[0] == 'string' && arguments[0];
+ var args = method && Array.prototype.slice.call(arguments, 1) || arguments;
+
+ return method == 'length' ?
+ $.data(this[0], 'tabs').$tabs.length :
+ this.each(function() {
+ if (method) {
+ var tabs = $.data(this, 'tabs');
+ if (tabs) tabs[method].apply(tabs, args);
+ } else
+ new $.ui.tabs(this, args[0] || {});
+ });
+ };
+
+ // tabs class
+ $.ui.tabs = function(el, options) {
+ var self = this;
+
+ this.options = $.extend({}, $.ui.tabs.defaults, options);
+ this.element = el;
+
+ // doesn't extend with null
+ if (options.selected === null)
+ this.options.selected = null;
+
+ this.options.event += '.tabs'; // namespace event
+
+ $(el).bind('setData.tabs', function(event, key, value) {
+ if ((/^selected/).test(key))
+ self.select(value);
+ else {
+ self.options[key] = value;
+ self.tabify();
+ }
+ }).bind('getData.tabs', function(event, key) {
+ return self.options[key];
+ });
+
+ // save instance for later
+ $.data(el, 'tabs', this);
+
+ // create tabs
+ this.tabify(true);
+ };
+
+ $.ui.tabs.defaults = {
+ // basic setup
+ selected: 0,
+ unselect: false,
+ event: 'click',
+ disabled: [],
+ cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
+ // TODO history: false,
+
+ // Ajax
+ spinner: 'Loading…',
+ cache: false,
+ idPrefix: 'ui-tabs-',
+ ajaxOptions: {},
+
+ // animations
+ fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
+
+ // templates
+ tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
+ panelTemplate: '<div></div>',
+
+ // CSS classes
+ navClass: 'ui-tabs-nav',
+ selectedClass: 'ui-tabs-selected',
+ unselectClass: 'ui-tabs-unselect',
+ disabledClass: 'ui-tabs-disabled',
+ panelClass: 'ui-tabs-panel',
+ hideClass: 'ui-tabs-hide',
+ loadingClass: 'ui-tabs-loading'
+ };
+
+ // instance methods
+ $.extend($.ui.tabs.prototype, {
+ tabId: function(a) {
+ return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
+ || this.options.idPrefix + $.data(a);
+ },
+ ui: function(tab, panel) {
+ return {
+ instance: this,
+ options: this.options,
+ tab: tab,
+ panel: panel
+ };
+ },
+ tabify: function(init) {
+
+ this.$lis = $('li:has(a[href])', this.element);
+ this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
+ this.$panels = $([]);
+
+ var self = this, o = this.options;
+
+ this.$tabs.each(function(i, a) {
+ // inline tab
+ if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
+ self.$panels = self.$panels.add(a.hash);
+ // remote tab
+ else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
+ $.data(a, 'href.tabs', a.href); // required for restore on destroy
+
+ var _cls = a.getAttribute('class');
+ var use_iframe = _cls && (_cls.indexOf('use_iframe') > -1)? true: false;
+ if (!use_iframe) {
+ $.data(a, 'load.tabs', a.href); // mutable
+ } else {
+ $.data(a, 'load.iframe_src', a.href); // mutable
+ }
+
+
+ var id = self.tabId(a);
+ a.href = '#' + id;
+ var $panel = $('#' + id);
+ var panelTemplate = use_iframe? '<div><iframe></iframe></div>': o.panelTemplate;
+ if (!$panel.length) {
+ $panel = $(panelTemplate).attr('id', id).addClass(o.panelClass)
+ .insertAfter( self.$panels[i - 1] || self.element );
+ $panel.data('destroy.tabs', true);
+ }
+ self.$panels = self.$panels.add( $panel );
+ }
+ // invalid tab href
+ else
+ o.disabled.push(i + 1);
+ });
+
+ if (init) {
+
+ // attach necessary classes for styling if not present
+ $(this.element).hasClass(o.navClass) || $(this.element).addClass(o.navClass);
+ this.$panels.each(function() {
+ var $this = $(this);
+ $this.hasClass(o.panelClass) || $this.addClass(o.panelClass);
+ });
+
+ // Try to retrieve selected tab:
+ // 1. from fragment identifier in url if present
+ // 2. from cookie
+ // 3. from selected class attribute on <li>
+ // 4. otherwise use given "selected" option
+ // 5. check if tab is disabled
+ this.$tabs.each(function(i, a) {
+ if (location.hash) {
+ if (a.hash == location.hash) {
+ o.selected = i;
+ // prevent page scroll to fragment
+ //if (($.browser.msie || $.browser.opera) && !o.remote) {
+ if ($.browser.msie || $.browser.opera) {
+ var $toShow = $(location.hash), toShowId = $toShow.attr('id');
+ $toShow.attr('id', '');
+ setTimeout(function() {
+ $toShow.attr('id', toShowId); // restore id
+ }, 500);
+ }
+ scrollTo(0, 0);
+ return false; // break
+ }
+ } else if (o.cookie) {
+ var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10);
+ if (index && self.$tabs[index]) {
+ o.selected = index;
+ return false; // break
+ }
+ } else if ( self.$lis.eq(i).hasClass(o.selectedClass) ) {
+ o.selected = i;
+ return false; // break
+ }
+ });
+
+ // highlight selected tab
+ this.$panels.addClass(o.hideClass);
+ this.$lis.removeClass(o.selectedClass);
+ if (o.selected !== null) {
+ this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
+ this.$lis.eq(o.selected).addClass(o.selectedClass);
+ }
+
+ // load if remote tab
+ var href = o.selected !== null && $.data(this.$tabs[o.selected], 'load.tabs');
+ if (href)
+ this.load(o.selected);
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly...
+ o.disabled = $.unique(o.disabled.concat(
+ $.map(this.$lis.filter('.' + o.disabledClass),
+ function(n, i) { return self.$lis.index(n); } )
+ )).sort();
+
+ // clean up to avoid memory leaks in certain versions of IE 6
+ $(window).bind('unload', function() {
+ self.$tabs.unbind('.tabs');
+ self.$lis = self.$tabs = self.$panels = null;
+ });
+
+ }
+
+ // disable tabs
+ for (var i = 0, li; li = this.$lis[i]; i++)
+ $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
+
+ // reset cache if switching from cached to not cached
+ if (o.cache === false)
+ this.$tabs.removeData('cache.tabs');
+
+ // set up animations
+ var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
+ if (o.fx && o.fx.constructor == Array)
+ hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
+ else
+ hideFx = showFx = o.fx || baseFx;
+
+ // reset some styles to maintain print style sheets etc.
+ var resetCSS = { display: '', overflow: '', height: '' };
+ if (!$.browser.msie) // not in IE to prevent ClearType font issue
+ resetCSS.opacity = '';
+
+ // Hide a tab, animation prevents browser scrolling to fragment,
+ // $show is optional.
+ function hideTab(clicked, $hide, $show) {
+ $hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
+ $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
+ if ($.browser.msie && hideFx.opacity)
+ $hide[0].style.filter = '';
+ if ($show)
+ showTab(clicked, $show, $hide);
+ });
+ }
+
+ // Show a tab, animation prevents browser scrolling to fragment,
+ // $hide is optional.
+ function showTab(clicked, $show, $hide) {
+ if (showFx === baseFx)
+ $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
+ $show.animate(showFx, showFx.duration || baseDuration, function() {
+ $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
+ if ($.browser.msie && showFx.opacity)
+ $show[0].style.filter = '';
+
+ // callback
+ $(self.element).triggerHandler('tabsshow', [self.ui(clicked, $show[0])], o.show);
+
+ });
+ }
+
+ // switch a tab
+ function switchTab(clicked, $li, $hide, $show) {
+ /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
+ $.ajaxHistory.update(clicked.hash);
+ }*/
+ $li.addClass(o.selectedClass)
+ .siblings().removeClass(o.selectedClass);
+ hideTab(clicked, $hide, $show);
+ }
+
+ // attach tab event handler, unbind to avoid duplicates from former tabifying...
+ this.$tabs.unbind('.tabs').bind(o.event, function() {
+
+ //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
+ var $li = $(this).parents('li:eq(0)'),
+ $hide = self.$panels.filter(':visible'),
+ $show = $(this.hash);
+
+ // If tab is already selected and not unselectable or tab disabled or
+ // or is already loading or click callback returns false stop here.
+ // Check if click handler returns false last so that it is not executed
+ // for a disabled or loading tab!
+ if (($li.hasClass(o.selectedClass) && !o.unselect)
+ || $li.hasClass(o.disabledClass)
+ || $(this).hasClass(o.loadingClass)
+ || $(self.element).triggerHandler('tabsselect', [self.ui(this, $show[0])], o.select) === false
+ ) {
+ this.blur();
+ return false;
+ }
+
+ self.options.selected = self.$tabs.index(this);
+
+ // if tab may be closed
+ if (o.unselect) {
+ if ($li.hasClass(o.selectedClass)) {
+ self.options.selected = null;
+ $li.removeClass(o.selectedClass);
+ self.$panels.stop();
+ hideTab(this, $hide);
+ this.blur();
+ return false;
+ } else if (!$hide.length) {
+ self.$panels.stop();
+ var a = this;
+ self.load(self.$tabs.index(this), function() {
+ $li.addClass(o.selectedClass).addClass(o.unselectClass);
+ showTab(a, $show);
+ });
+ this.blur();
+ return false;
+ }
+ }
+
+ if (o.cookie)
+ $.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie);
+
+ // stop possibly running animations
+ self.$panels.stop();
+
+ // show new tab
+ if ($show.length) {
+
+ // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
+ /*if ($.browser.msie && o.bookmarkable) {
+ var showId = this.hash.replace('#', '');
+ $show.attr('id', '');
+ setTimeout(function() {
+ $show.attr('id', showId); // restore id
+ }, 0);
+ }*/
+
+ var a = this;
+ self.load(self.$tabs.index(this), $hide.length ?
+ function() {
+ switchTab(a, $li, $hide, $show);
+ } :
+ function() {
+ $li.addClass(o.selectedClass);
+ showTab(a, $show);
+ }
+ );
+
+ // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
+ /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
+ var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
+ setTimeout(function() {
+ scrollTo(scrollX, scrollY);
+ }, 0);*/
+
+ } else
+ throw 'jQuery UI Tabs: Mismatching fragment identifier.';
+
+ // Prevent IE from keeping other link focussed when using the back button
+ // and remove dotted border from clicked link. This is controlled in modern
+ // browsers via CSS, also blur removes focus from address bar in Firefox
+ // which can become a usability and annoying problem with tabsRotate.
+ if ($.browser.msie)
+ this.blur();
+
+ //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
+ return false;
+
+ });
+
+ // disable click if event is configured to something else
+ if (!(/^click/).test(o.event))
+ this.$tabs.bind('click.tabs', function() { return false; });
+
+ },
+ add: function(url, label, index) {
+ if (index == undefined)
+ index = this.$tabs.length; // append by default
+
+ var o = this.options;
+ var $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{label\}/, label));
+ $li.data('destroy.tabs', true);
+
+ var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );
+
+ // try to find an existing element before creating a new one
+ var $panel = $('#' + id);
+ if (!$panel.length) {
+ $panel = $(o.panelTemplate).attr('id', id)
+ .addClass(o.panelClass).addClass(o.hideClass);
+ $panel.data('destroy.tabs', true);
+ }
+ if (index >= this.$lis.length) {
+ $li.appendTo(this.element);
+ $panel.appendTo(this.element.parentNode);
+ } else {
+ $li.insertBefore(this.$lis[index]);
+ $panel.insertBefore(this.$panels[index]);
+ }
+
+ o.disabled = $.map(o.disabled,
+ function(n, i) { return n >= index ? ++n : n });
+
+ this.tabify();
+
+ if (this.$tabs.length == 1) {
+ $li.addClass(o.selectedClass);
+ $panel.removeClass(o.hideClass);
+ var href = $.data(this.$tabs[0], 'load.tabs');
+ if (href)
+ this.load(index, href);
+ }
+
+ // callback
+ $(this.element).triggerHandler('tabsadd',
+ [this.ui(this.$tabs[index], this.$panels[index])], o.add
+ );
+ },
+ remove: function(index) {
+ var o = this.options, $li = this.$lis.eq(index).remove(),
+ $panel = this.$panels.eq(index).remove();
+
+ // If selected tab was removed focus tab to the right or
+ // in case the last tab was removed the tab to the left.
+ if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
+ this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
+
+ o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
+ function(n, i) { return n >= index ? --n : n });
+
+ this.tabify();
+
+ // callback
+ $(this.element).triggerHandler('tabsremove',
+ [this.ui($li.find('a')[0], $panel[0])], o.remove
+ );
+ },
+ enable: function(index) {
+ var o = this.options;
+ if ($.inArray(index, o.disabled) == -1)
+ return;
+
+ var $li = this.$lis.eq(index).removeClass(o.disabledClass);
+ if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
+ $li.css('display', 'inline-block');
+ setTimeout(function() {
+ $li.css('display', 'block');
+ }, 0);
+ }
+
+ o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
+
+ // callback
+ $(this.element).triggerHandler('tabsenable',
+ [this.ui(this.$tabs[index], this.$panels[index])], o.enable
+ );
+
+ },
+ disable: function(index) {
+ var self = this, o = this.options;
+ if (index != o.selected) { // cannot disable already selected tab
+ this.$lis.eq(index).addClass(o.disabledClass);
+
+ o.disabled.push(index);
+ o.disabled.sort();
+
+ // callback
+ $(this.element).triggerHandler('tabsdisable',
+ [this.ui(this.$tabs[index], this.$panels[index])], o.disable
+ );
+ }
+ },
+ select: function(index) {
+ if (typeof index == 'string')
+ index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
+ this.$tabs.eq(index).trigger(this.options.event);
+ },
+ load: function(index, callback) { // callback is for internal usage only
+
+ var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
+ bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
+
+ callback = callback || function() {};
+
+ // no remote or from cache - just finish with callback
+ if (!url || ($.data(a, 'cache.tabs') && !bypassCache)) {
+ callback();
+ return;
+ }
+
+ // load remote from here on
+ if (o.spinner) {
+ var $span = $('span', a);
+ $span.data('label.tabs', $span.html()).html('<em>' + o.spinner + '</em>');
+ }
+ var finish = function() {
+ self.$tabs.filter('.' + o.loadingClass).each(function() {
+ $(this).removeClass(o.loadingClass);
+ if (o.spinner) {
+ var $span = $('span', this);
+ $span.html($span.data('label.tabs')).removeData('label.tabs');
+ }
+ });
+ self.xhr = null;
+ };
+ var ajaxOptions = $.extend({}, o.ajaxOptions, {
+ url: url,
+ success: function(r, s) {
+ $(a.hash).html(r);
+ finish();
+
+ // This callback is required because the switch has to take
+ // place after loading has completed.
+ callback();
+
+ if (o.cache)
+ $.data(a, 'cache.tabs', true); // if loaded once do not load them again
+
+ // callback
+ $(self.element).triggerHandler('tabsload',
+ [self.ui(self.$tabs[index], self.$panels[index])], o.load
+ );
+
+ o.ajaxOptions.success && o.ajaxOptions.success(r, s);
+ }
+ });
+ if (this.xhr) {
+ // terminate pending requests from other tabs and restore tab label
+ this.xhr.abort();
+ finish();
+ }
+ $a.addClass(o.loadingClass);
+ setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
+ self.xhr = $.ajax(ajaxOptions);
+ }, 0);
+
+ },
+ url: function(index, url) {
+ this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
+ },
+ destroy: function() {
+ var o = this.options;
+ $(this.element).unbind('.tabs')
+ .removeClass(o.navClass).removeData('tabs');
+ this.$tabs.each(function() {
+ var href = $.data(this, 'href.tabs');
+ if (href)
+ this.href = href;
+ var $this = $(this).unbind('.tabs');
+ $.each(['href', 'load', 'cache'], function(i, prefix) {
+ $this.removeData(prefix + '.tabs');
+ });
+ });
+ this.$lis.add(this.$panels).each(function() {
+ if ($.data(this, 'destroy.tabs'))
+ $(this).remove();
+ else
+ $(this).removeClass([o.selectedClass, o.unselectClass,
+ o.disabledClass, o.panelClass, o.hideClass].join(' '));
+ });
+ }
+ });
+
+/*
+ * Tabs Extensions
+ */
+
+ /*
+ * Rotate
+ */
+ $.extend($.ui.tabs.prototype, {
+ rotation: null,
+ rotate: function(ms, continuing) {
+
+ continuing = continuing || false;
+
+ var self = this, t = this.options.selected;
+
+ function start() {
+ self.rotation = setInterval(function() {
+ t = ++t < self.$tabs.length ? t : 0;
+ self.select(t);
+ }, ms);
+ }
+
+ function stop(e) {
+ if (!e || e.clientX) { // only in case of a true click
+ clearInterval(self.rotation);
+ }
+ }
+
+ // start interval
+ if (ms) {
+ start();
+ if (!continuing)
+ this.$tabs.bind(this.options.event, stop);
+ else
+ this.$tabs.bind(this.options.event, function() {
+ stop();
+ t = self.options.selected;
+ start();
+ });
+ }
+ // stop interval
+ else {
+ stop();
+ this.$tabs.unbind(this.options.event, stop);
+ }
+ }
+ });
+
+})(jQuery);
diff --git a/moksha/widgetbrowser/static/widgetbrowser.css b/moksha/widgetbrowser/static/widgetbrowser.css
new file mode 100644
index 0000000..21a046d
--- /dev/null
+++ b/moksha/widgetbrowser/static/widgetbrowser.css
@@ -0,0 +1,9 @@
+.widgetbrowser iframe {
+ width: 100%;
+ border: 0;
+}
+div.small iframe { height: 50px; }
+div.medium iframe { height: 150px; }
+div.large iframe { height: 300px; }
+div.x-large iframe { height: 500px; }
+
diff --git a/moksha/widgetbrowser/static/widgetbrowser.js b/moksha/widgetbrowser/static/widgetbrowser.js
new file mode 100644
index 0000000..c0b78e6
--- /dev/null
+++ b/moksha/widgetbrowser/static/widgetbrowser.js
@@ -0,0 +1,13 @@
+jQuery(function() {
+ jQuery('.widgetbrowser > ul').tabs({
+ selected: null,
+ unselect: true,
+ select: function (ui) {
+ var url = jQuery.data(ui.tab, 'load.iframe_src');
+ var iframe = jQuery('iframe', ui.panel);
+ if (url && !iframe.attr('src')) {
+ iframe.attr('src', url);
+ }
+ }
+ })
+});
diff --git a/moksha/widgetbrowser/templates/__init__.py b/moksha/widgetbrowser/templates/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/moksha/widgetbrowser/templates/home.html b/moksha/widgetbrowser/templates/home.html
new file mode 100644
index 0000000..012ce08
--- /dev/null
+++ b/moksha/widgetbrowser/templates/home.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<?python
+from widgetbrowser import widgets
+?>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <style>
+ .ui-tabs-panel {
+ border-bottom: solid 1px #94ada7;
+ padding-left: 1.5em;
+ }
+ .ui-tabs-panel iframe {
+ width: 100%;
+ border: 0;
+ min-height: 500px;
+ }
+ #home {
+ min-height: 450px;
+ }
+ </style>
+ </head>
+ <body class="flora">
+ <div id="main">
+ <ul>
+ <li><a href="#home"><span>Home</span></a></li>
+ <li><a href="#terminal" class="use_iframe"><span>Terminal</span></a></li>
+ <li><a href="${url('/widgets/')}" class="use_iframe"><span>Widgets</span></a></li>
+ </ul>
+ <div id="home">
+ <h1>Welcome to Toscawidgets' Browser</h1>
+ <p>
+ </p>
+ </div>
+ <div id="terminal">
+ ${widgets.repl(prefix=url('_repl/'))}
+ </div>
+ </div>
+ <div id="footer">
+ <p>© 2008. Alberto Valverde González</p>
+ </div>
+ <script type="text/javascript">
+ //<![CDATA[
+ jQuery(function () {
+ jQuery('#main > ul').tabs({
+ select: function (ui) {
+ var url = jQuery.data(ui.tab, 'load.iframe_src');
+ var iframe = jQuery('iframe', ui.panel);
+ if (url && !iframe.attr('src')) {
+ iframe.attr('src', url);
+ }
+ }
+ });
+ });
+ //]]>
+ </script>
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/templates/list_widgets.html b/moksha/widgetbrowser/templates/list_widgets.html
new file mode 100644
index 0000000..2ef5dfe
--- /dev/null
+++ b/moksha/widgetbrowser/templates/list_widgets.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: Installed widgets</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widgets">
+ <ul>
+ <li py:for="path, url in widgets">
+ <a href="$url">$path</a>
+ </li>
+ </ul>
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/templates/show_widget.html b/moksha/widgetbrowser/templates/show_widget.html
new file mode 100644
index 0000000..b75e063
--- /dev/null
+++ b/moksha/widgetbrowser/templates/show_widget.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: ${widget_name}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widget_browser">
+ <form py:if="interactive" method="GET">
+ <label for="display_args">Display arguments:</label>
+ <input id="display_args" name="_disp" type="text" size="50" value="${_disp}" />
+ <input type="submit" value="Display" />
+ </form>
+ <div py:replace="widget_output" />
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/templates/validation_result.html b/moksha/widgetbrowser/templates/validation_result.html
new file mode 100644
index 0000000..e43da7b
--- /dev/null
+++ b/moksha/widgetbrowser/templates/validation_result.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <head>
+ <title>WidgetBrowser: ${widget_name}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body id="widget_browser">
+ <h1 class="title">Validated data:</h1>
+ ${Markup(value)}
+ <a href="">Back</a>
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/templates/widget_browser_tabs.html b/moksha/widgetbrowser/templates/widget_browser_tabs.html
new file mode 100644
index 0000000..7edb374
--- /dev/null
+++ b/moksha/widgetbrowser/templates/widget_browser_tabs.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<div xmlns:py="http://genshi.edgewall.org/"
+ class="widgetbrowser ${size}">
+ <ul>
+ <li py:for="text, url in tabs">
+ <a href="${url}" class="${text == 'Demo' and 'use_iframe' or None}">
+ <span>${text}</span>
+ </a>
+ </li>
+ </ul>
+</div>
+
diff --git a/moksha/widgetbrowser/templates/widget_index.html b/moksha/widgetbrowser/templates/widget_index.html
new file mode 100644
index 0000000..4759c25
--- /dev/null
+++ b/moksha/widgetbrowser/templates/widget_index.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
+ xmlns:py="http://genshi.edgewall.org/">
+ <?python
+ from widgetbrowser.widgets import WidgetBrowserTabs
+ from widgetbrowser.util import widget_path
+ browser = WidgetBrowserTabs(size='x-large')
+ ?>
+ <head>
+ <title>WidgetBrowser: ${widget_path(widget)}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ </head>
+ <body>
+ <h1>${widget_path(widget)}</h1>
+ <p><a href="javascript:history.back()">Back</a></p>
+ ${browser(widget)}
+ </body>
+</html>
diff --git a/moksha/widgetbrowser/templates/widget_parameters.html b/moksha/widgetbrowser/templates/widget_parameters.html
new file mode 100644
index 0000000..c95c195
--- /dev/null
+++ b/moksha/widgetbrowser/templates/widget_parameters.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<div xmlns:py="http://genshi.edgewall.org/" class="widget_params">
+ <div py:if="parameters.local" class="widget_params local_params">
+ <h3>This widget's</h3>
+ <dl>
+ <py:for each="k in sorted(parameters.local)">
+ <dt>${k} <span class="default_param">(default = ${parameters.get_default(k)})</span></dt>
+ <dd py:content="parameters.get_doc(k, 'Undocumented')" />
+ </py:for>
+ </dl>
+ </div>
+ <div py:if="parameters.inherited" class="widget_param inherited_params">
+ <h3>Inherited</h3>
+ <dl>
+ <py:for each="k in sorted(parameters.inherited)">
+ <dt>${k} <span class="default_param">(default = ${parameters.get_default(k)})</span></dt>
+ <dd py:content="parameters.get_doc(k, 'Undocumented')" />
+ </py:for>
+ </dl>
+ </div>
+</div>
diff --git a/moksha/widgetbrowser/tests/__init__.py b/moksha/widgetbrowser/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/moksha/widgetbrowser/tests/dummy_m_template.html b/moksha/widgetbrowser/tests/dummy_m_template.html
new file mode 100644
index 0000000..7c9c42c
--- /dev/null
+++ b/moksha/widgetbrowser/tests/dummy_m_template.html
@@ -0,0 +1 @@
+Dummy template $value
diff --git a/moksha/widgetbrowser/tests/dummy_m_template.mak b/moksha/widgetbrowser/tests/dummy_m_template.mak
new file mode 100644
index 0000000..1774ce6
--- /dev/null
+++ b/moksha/widgetbrowser/tests/dummy_m_template.mak
@@ -0,0 +1 @@
+Dummy template $value mako version
diff --git a/moksha/widgetbrowser/tests/dummy_template.html b/moksha/widgetbrowser/tests/dummy_template.html
new file mode 100644
index 0000000..7c9c42c
--- /dev/null
+++ b/moksha/widgetbrowser/tests/dummy_template.html
@@ -0,0 +1 @@
+Dummy template $value
diff --git a/moksha/widgetbrowser/tests/test_app.txt b/moksha/widgetbrowser/tests/test_app.txt
new file mode 100644
index 0000000..bacbc39
--- /dev/null
+++ b/moksha/widgetbrowser/tests/test_app.txt
@@ -0,0 +1,50 @@
+>>> from widgetbrowser import WidgetBrowser
+>>> from webtest import TestApp
+
+>>> app = TestApp(WidgetBrowser())
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo')
+>>> assert 'default' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/')
+>>> assert 'Demo' in r
+
+>>> r = app.get('/os.open/demo', status=404)
+
+Test that code isn't executed if not allowed
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo?_disp="foo"')
+>>> assert 'default' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/template')
+>>> assert '$value' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/source')
+>>> assert 'class' in r
+>>> assert 'TestWidget' in r
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/parameters')
+>>> assert 'Inherited' in r
+
+Test posting:
+
+>>> r = app.post('/widgetbrowser.tests.widgets.TestWidget/demo', {'some_key':'foo'})
+>>> assert 'some_key' in r
+
+# the following is just to test the failed validation code-path
+>>> r = app.post('/widgetbrowser.tests.widgets.TestWidget/demo', {'break':'y'})
+>>> assert 'some_key' not in r
+
+Test unimplemented methods:
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/foobarize', status=501)
+
+Test custom controller
+
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/test')
+>>> assert 'Testing TestWidget' in r
+
+Now with code execution
+
+>>> app = TestApp(WidgetBrowser(interactive=True))
+>>> r = app.get('/widgetbrowser.tests.widgets.TestWidget/demo?_disp="foo"')
+>>> assert 'foo' in r
diff --git a/moksha/widgetbrowser/tests/test_sphinx_ext.py b/moksha/widgetbrowser/tests/test_sphinx_ext.py
new file mode 100644
index 0000000..fc2d10a
--- /dev/null
+++ b/moksha/widgetbrowser/tests/test_sphinx_ext.py
@@ -0,0 +1,26 @@
+import os
+import shutil
+from unittest import TestCase
+from pkg_resources import resource_filename
+import sphinx
+
+doc_dir = resource_filename('widgetbrowser.tests', 'testdocs')
+
+class TestSphinxExt(TestCase):
+ def setUp(self):
+ self.dest_dir = os.tempnam()
+ if not os.path.isdir(self.dest_dir):
+ os.makedirs(self.dest_dir)
+
+ def tearDown(self):
+ try:
+ shutil.rmtree(self.dest_dir)
+ except OSError:
+ pass
+
+ def test_generate(self):
+ out = sphinx.main(['sphinx-build', doc_dir, self.dest_dir])
+ self.failUnless(not out, out)
+ html = open(os.path.join(self.dest_dir, 'index.html')).read()
+ self.failUnless('widgetbrowser' in html)
+ self.failUnless('x-large' in html)
diff --git a/moksha/widgetbrowser/tests/testdocs/conf.py b/moksha/widgetbrowser/tests/testdocs/conf.py
new file mode 100644
index 0000000..4bd428a
--- /dev/null
+++ b/moksha/widgetbrowser/tests/testdocs/conf.py
@@ -0,0 +1,149 @@
+# -*- coding: utf-8 -*-
+#
+# TestDocs documentation build configuration file, created by
+# sphinx-quickstart on Fri May 9 09:56:10 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['widgetbrowser.sphinx_ext']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = []
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = 'TestDocs'
+copyright = '2008, Alberto'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# The name of an image file (within the static path) to place at the top of
+# the sidebar.
+#html_logo = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.
+#html_use_opensearch = False
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'TestDocsdoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'TestDocs.tex', 'TestDocs Documentation', 'Alberto', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/moksha/widgetbrowser/tests/testdocs/index.rst b/moksha/widgetbrowser/tests/testdocs/index.rst
new file mode 100644
index 0000000..6f70ced
--- /dev/null
+++ b/moksha/widgetbrowser/tests/testdocs/index.rst
@@ -0,0 +1,12 @@
+.. TestDocs documentation master file, created by sphinx-quickstart on Fri May 9 09:56:10 2008.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Testing the `widgetbroser` directive
+====================================
+
+Test an existing widget
+-----------------------
+.. widgetbrowser:: widgetbrowser.tests.widgets.TestWidget
+ :tabs: source, demo, parameters, template
+ :size: x-large
diff --git a/moksha/widgetbrowser/tests/widgets.py b/moksha/widgetbrowser/tests/widgets.py
new file mode 100644
index 0000000..149139d
--- /dev/null
+++ b/moksha/widgetbrowser/tests/widgets.py
@@ -0,0 +1,25 @@
+from tw.api import Widget
+from widgetbrowser import WidgetBrowser
+from formencode.api import Invalid
+
+class TestWidget(Widget):
+ template = "$value"
+ default = "default"
+
+ def validate(self, value, *args, **kw):
+ if 'break' in value.keys():
+ raise Invalid("Validation failed", value, None)
+ return value
+
+(a)WidgetBrowser.register_controller(TestWidget, 'test')
+def test_controller(request, response):
+ response.headers['Content-Type'] = 'text/plain'
+ return "Testing " + request.widget.__class__.__name__
+
+class TestWidgetExternalTemplate(Widget):
+ template = "toscawidgets:widgetbrowser.tests.dummy_template"
+ default = "default"
+
+class TestWidgetMultipleExternalTemplate(Widget):
+ template = "toscawidgets:widgetbrowser.tests.dummy_m_template"
+ default = "default"
diff --git a/moksha/widgetbrowser/util.py b/moksha/widgetbrowser/util.py
new file mode 100644
index 0000000..648cd8c
--- /dev/null
+++ b/moksha/widgetbrowser/util.py
@@ -0,0 +1,242 @@
+import logging
+import os
+import errno
+import sys
+import pprint
+
+from pkg_resources import EntryPoint, iter_entry_points, resource_string
+
+import tw
+from tw.api import Widget, WidgetType
+from tw.core import view
+
+log = logging.getLogger(__name__)
+
+def import_widget(path):
+ """Import a widget given a dotted or entry point notation path.
+
+ Can import both widget instances or classes.
+
+ >>> import_widget('tw.core.base.Widget')
+ <class 'tw.core.base.Widget'>
+ >>> import_widget('tw.core.base:Widget')
+ <class 'tw.core.base.Widget'>
+ >>> import_widget('os.popen')
+
+ """
+ if ':' not in path:
+ parts = path.split('.')
+ path = '.'.join(parts[:-1]) + ':' + parts[-1]
+ widget = EntryPoint.parse("x="+path).load(False)
+ if not isinstance(widget, (WidgetType, Widget)):
+ widget = None
+ return widget
+
+
+def widget_path(widget):
+ """Returns the path of a widget instance or subclass
+
+ >>> from tw.api import Widget
+ >>> widget_path(Widget)
+ 'tw.core.base.Widget'
+ >>> widget_path(Widget())
+ 'tw.core.base.Widget'
+ """
+ if not isinstance(widget, (WidgetType, Widget)):
+ raise TypeError("Only widgets are allowed")
+ if isinstance(widget, Widget):
+ widget = widget.__class__
+ return '.'.join([widget.__module__, widget.__name__])
+
+def format_code(code, format='python'):
+ """Formats a chunk of code as html. If pygments is installed it will
+ pygmentize it.
+
+ >>> code = "from __future__ import teletransportation"
+ >>> '<pre' in format_code(code)
+ True
+ """
+ try:
+ from pygments import highlight, formatters, lexers
+ except ImportError:
+ log.info("Pygments is not available to colorize")
+ return '<pre>' + code + '</pre>'
+ lexer = lexers.get_lexer_by_name(format)
+ formatter = formatters.get_formatter_by_name('html')
+ return highlight(code, lexer, formatter)
+
+#TODO: Memoize this function
+def widget_template(widget, extension='.html'):
+ """Returns the template of a widget as a string.
+
+ Loads external templates if needed.
+
+ >>> from widgetbrowser.tests.widgets import *
+ >>> widget_template(TestWidgetExternalTemplate())
+ 'Dummy template $value\\n'
+
+ If more than one is available, it will use the extension to disambiguate.
+
+ >>> from widgetbrowser.tests.widgets import TestWidgetExternalTemplate
+ >>> widget_template(TestWidgetMultipleExternalTemplate(), '.html')
+ 'Dummy template $value\\n'
+ >>> widget_template(TestWidgetMultipleExternalTemplate(), '.mak')
+ 'Dummy template $value mako version\\n'
+ """
+ template = widget.template
+ if template and not view._is_inline_template(template):
+ # Template seems to refer to a file, look it up
+ parts = template.split('.')
+ possible_extensions = set(".html .mak .mako".split())
+ possible_extensions.remove(extension)
+ possible_extensions = [extension] + list(possible_extensions)
+ for ext in possible_extensions:
+ try:
+ return resource_string('.'.join(parts[:-1]), parts[-1]+ext)
+ except IOError, e:
+ if e.errno not in (0, errno.ENOENT):
+ raise
+ return None
+ return template
+
+def pretty_print(obj):
+ """Pretty prints an object returning pygmentized code if possible."""
+ return format_code(pprint.pformat(obj), 'python')
+
+def display_widget(widget, argstr='', ctx=None):
+ """Displays a widget with optional arguments as a string.
+
+
+ .. warning:: IT IS VERY UNSAFE TO EXECUTE UNTRUSTED CODE
+
+ Example::
+
+ >>> from tw.api import Widget
+ >>> class TestWidget(Widget):
+ ... params = ['param']
+ ... template = "$value-$param"
+ >>> display_widget(TestWidget())
+ u'None-None'
+ >>> display_widget(TestWidget(), '"hello", param=2')
+ u'hello-2'
+ """
+ ctx = ctx or {}
+ ctx['_w'] = widget
+ code = "_o = _w(%s)" % argstr
+ exec code in ctx
+ return ctx['_o']
+
+def widget_url(widget, action='', prefix=None):
+ """Returns the URL of the controller to perform `action` on `widget`.
+
+ If no `prefix` is passed the it will be tried to be fetched from
+ `tw.framework.request_local` where the :class:`WidgetBrowser` leaves it
+ on every request.
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> widget_url(Widget)
+ '/tw.core.base.Widget/'
+ >>> widget_url(Widget())
+ '/tw.core.base.Widget/'
+
+ You can also pass the `path` of the widget::
+
+ >>> widget_url('tw.api.Widget')
+ '/tw.api.Widget/'
+ >>> widget_url('tw.api.Widget', 'show')
+ '/tw.api.Widget/show'
+ >>> widget_url('tw.api.Widget', 'show', prefix='/widget')
+ '/widget/tw.api.Widget/show'
+
+ .. note::
+
+ You can pass any path the widget can be imported from when passing a
+ string but if you pass a widget instance or subclass then the real
+ module where it is defined will be generated.
+ """
+ if isinstance(widget, (Widget, WidgetType)):
+ widgeturi = widget_path(widget)
+ else:
+ widgeturi = widget
+ if import_widget(widgeturi) is None:
+ return
+ if prefix is None:
+ prefix = getattr(tw.framework.request_local, 'browser_prefix', '')
+ return '/'.join([prefix.rstrip('/'), widgeturi, action])
+
+def all_widgets():
+ """Iterates over all the Widget subclasses in the modules
+ that are declared as `toscawidgets.widgets` entrypoints
+
+ >>> len(list(all_widgets())) > 0
+ True
+ """
+ seen = set()
+ for ep in iter_entry_points('toscawidgets.widgets'):
+ try:
+ mod = ep.load(False)
+ except ImportError, e:
+ log.error("Could not load %r: %s", ep, e)
+ continue
+ for name in dir(mod):
+ obj = getattr(mod, name)
+ if isinstance(obj, WidgetType) and obj not in seen:
+ seen.add(obj)
+ yield obj
+
+class WidgetParameters(object):
+ """Wraps a widget and provides information on it's parameters.
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> params = WidgetParameters(Widget)
+ >>> len(params.all) > 0
+ True
+ >>> params.all - params.local == params.inherited
+ True
+ """
+ def __init__(self, widget):
+ if isinstance(widget, Widget):
+ widget = widget.__class__
+ self.widget = widget
+ self.all = widget.params
+ self.inherited = set()
+ for b in self.widget.__mro__:
+ if b is self.widget:
+ continue
+ self.inherited.update(getattr(b, 'params', set()))
+ self.local = self.all - self.inherited
+
+ def get_default(self, name, default=None):
+ """Returns a string representation of a parameter default value.
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> params = WidgetParameters(Widget)
+ >>> type(params.get_default('id'))
+ <type 'str'>
+ """
+ return repr(getattr(self.widget, name, default))
+
+ def get_doc(self, name, default='Undocumented'):
+ """Returns parameters's doc. If it is not documented it will return
+ ``default``
+
+ Example::
+
+ >>> from tw.core.base import Widget
+ >>> params = WidgetParameters(Widget)
+ >>> type(params.get_doc('id'))
+ <type 'str'>
+ """
+ return getattr(self.widget, name + '__doc', default)
+
+def build_docs(src, dst):
+ import sphinx
+ if not os.path.exists(dst):
+ os.mkdir(dst)
+ return sphinx.main(['sphinx-build', src, dst])
diff --git a/moksha/widgetbrowser/widgets.py b/moksha/widgetbrowser/widgets.py
new file mode 100644
index 0000000..b40fdea
--- /dev/null
+++ b/moksha/widgetbrowser/widgets.py
@@ -0,0 +1,71 @@
+from tw.api import Widget, JSLink, CSSLink, js_function
+from widgetbrowser import util
+import string
+
+__all__ = ['WidgetBrowserTabs']
+
+mod = 'widgetbrowser'
+flora_all_css = CSSLink(modname=mod, filename="static/themes/flora/flora.all.css")
+tabs_css = CSSLink(modname=mod, filename="static/ui.tabs.css")
+wb_css = CSSLink(modname=mod, filename="static/widgetbrowser.css")
+pygments_css = CSSLink(modname=mod, filename="static/pygments.css")
+httprepl_css = CSSLink(modname=mod, filename="static/httprepl.css")
+jquery_js = JSLink(modname=mod, filename="static/jquery.js")
+# Do not pull jquery as an automatic dependency since Sphinx already includes
+# it
+ui_base_js = JSLink(modname=mod, filename="static/ui.base.js",
+ location="bodybottom")
+ui_tabs_js = JSLink(modname=mod, filename="static/ui.tabs.js",
+ location="bodybottom",
+ javascript=[ui_base_js])
+ui_dragabble_js = JSLink(modname=mod, filename="static/ui.draggable.js",
+ location="bodybottom")
+ui_resizable_js = JSLink(modname=mod, filename="static/ui.resizable.js",
+ location="bodybottom")
+ui_dialog_js = JSLink(modname=mod, filename="static/ui.dialog.js",
+ location="bodybottom",
+ javascript=[ui_base_js, ui_dragabble_js, ui_resizable_js])
+widgetbrowser_js = JSLink(modname=mod, filename="static/widgetbrowser.js",
+ javascript=[ui_tabs_js],
+ css=[tabs_css, wb_css, pygments_css],
+ location="bodybottom")
+
+httprepl_js = JSLink(modname=mod, filename='static/httprepl.js',
+ javascript=[ui_dialog_js],
+ css=[httprepl_css],
+ location="bodybottom")
+
+class WidgetBrowserTabs(Widget):
+ template = "genshi:widgetbrowser.templates.widget_browser_tabs"
+ params = ["tabs", "prefix", "size", "in_sphinx"]
+ in_sphinx = False
+ javascript = [widgetbrowser_js]
+ size = "small"
+ tabs = ['demo', 'demo_source', 'source', 'template', 'parameters']
+ prefix = None
+
+ def update_params(self, d):
+ super(WidgetBrowserTabs, self).update_params(d)
+ d.tabs = [(string.capwords(t.replace('_', ' ')), util.widget_url(d.value, t, prefix=d.prefix))
+ for t in d.tabs]
+ if not d.in_sphinx:
+ # Not displayed inside Sphinx, include jquery and pygments
+ jquery_js.inject()
+ pygments_css.inject()
+
+
+class WidgetRepl(Widget):
+ template = '<div id="$id" class="$css_class"></div>'
+ params = ["prefix"]
+ prefix = '/_repl/' # show nicely in the browser tabs
+ include_dynamic_js_calls = True
+ javascript = [jquery_js, httprepl_js]
+ css = [flora_all_css]
+ def update_params(self, d):
+ super(WidgetRepl, self).update_params(d)
+ assert d.id, "This widget needs an id"
+ config = dict(prefix=d.prefix)
+ call = js_function('HTTPRepl.render')('#'+d.id, config)
+ self.add_call("jQuery(function () {%s});" % call)
+
+repl = WidgetRepl("widgetrepl")
diff --git a/moksha/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/wsgiapp.py
new file mode 100644
index 0000000..036d4b2
--- /dev/null
+++ b/moksha/widgetbrowser/wsgiapp.py
@@ -0,0 +1,233 @@
+import sys
+import weakref
+import os
+import inspect
+import logging
+from pkg_resources import resource_filename
+from genshi.template import TemplateLoader, Context
+from webob import Request, Response, exc
+import tw
+from tw.api import Widget, WidgetType, make_middleware
+from widgetbrowser import util, widgets, repl
+
+
+try:
+ from formencode import Invalid
+ have_formencode = True
+except ImportError:
+ have_formencode = False
+
+__all__ = ['WidgetBrowser']
+
+log = logging.getLogger(__name__)
+
+def asbool(v):
+ if isinstance(v, basestring):
+ return v.lower().startswith('t') or v == '1' or v == 'on'
+ elif isinstance(v, bool):
+ return v
+ return False
+
+class WidgetBrowser(object):
+ """A widget browser WSGI app.
+
+ Parameters:
+
+ * `template_dirs`: A list of directories that shall be searched for
+ temlates used by the widget browser.
+ * `interactive`: Enable code execution. This is needed to for the REPL and
+ to override display arguments via the web interface. This is a BIG
+ SECURITY HOLE, enable only in a controlled environment.
+ * `docs_dir`: A directory where sphinx sources live.
+ """
+ def __init__(self, global_conf={}, template_dirs=None, interactive=False,
+ docs_dir=None, full_stack=True):
+ if isinstance(template_dirs, basestring):
+ template_dirs = template_dirs.split()
+ template_dirs = template_dirs or []
+ template_dirs.append(resource_filename('widgetbrowser', 'templates'))
+ self.loader = TemplateLoader(template_dirs)
+ self.interactive = asbool(interactive)
+ if self.interactive:
+ self.http_repl = repl.WidgetReplApp(globals(), weakref.proxy(self))
+ self.context = self.http_repl.repl.locals
+ else:
+ self.context = None
+ self.http_repl = exc.HTTPForbidden("Interactive mode is disabled")
+ if docs_dir:
+ from paste.cascade import Cascade
+ dest_dir = os.path.abspath(os.path.join(docs_dir, '.build'))
+ log.info('Building docs...')
+ util.build_docs(docs_dir, dest_dir)
+ self.built_docs = dest_dir
+ self.app = Cascade([self.docs_app, self.app])
+ if asbool(full_stack):
+ self.app = make_middleware(self.app, {
+ 'toscawidgets.framework.default_view': 'genshi',
+ }, stack_registry = True)
+ self._default_controllers = dict(demo=self.show_demo,
+ index=self.show_index,
+ template=self.show_template,
+ parameters=self.show_parameters,
+ source=self.show_source,
+ demo_source=self.show_demo_source)
+
+
+ def docs_app(self, environ, start_response):
+ """Registers widgetbrowser_js as resources before serving static html
+ files so it is injected into the page"""
+ from paste.urlparser import StaticURLParser
+ app = StaticURLParser(self.built_docs)
+ resources = widgets.widgetbrowser_js.retrieve_resources()
+ tw.framework.register_resources(resources)
+ return app(environ, start_response)
+
+ _widget_controllers = {}
+ @classmethod
+ def register_controller(cls, widget, action):
+ """Registers function to act as a demo controller for a widget"""
+ def _register(controller):
+ cls._widget_controllers[(widget,action)] = controller
+ return controller
+ return _register
+
+ def lookup_controller(self, widget_cls, action):
+ try:
+ return self._widget_controllers[(widget_cls, action)]
+ except KeyError:
+ return self._default_controllers[action]
+
+ def lookup_widget_action(self, path_info):
+ try:
+ widget_path, action = path_info.strip('/').split('/')
+ except ValueError:
+ widget_path, action = path_info, 'index'
+ if widget_path:
+ try:
+ widget = util.import_widget(widget_path.strip('/'))
+ except (ImportError, ValueError):
+ widget = None
+ if widget:
+ return widget, action
+ raise LookupError(path_info)
+
+ def render(self, template, ns):
+ ns.pop('self',None)
+ stream = self.loader.load(template).generate(Context(**ns))
+ return stream.render(method='xhtml', doctype='xhtml')
+
+ def __call__(self, environ, start_response):
+ return self.app(environ, start_response)
+
+ def app(self, environ, start_response):
+ req = Request(environ)
+ resp = Response(request=req, content_type='text/html; charset=utf-8')
+ # Leave the interactive flag in tw.framework so demo controllers can know
+ # if it is safe to enable advanced/unsecure features.
+ tw.framework.request_local.interactive = self.interactive
+ tw.framework.request_local.browser_prefix = req.script_name
+
+ # Lookup widget XXX: Yuck!
+ if req.path_info == '/':
+ controller = self.home
+ elif req.path_info.startswith('/_repl') and self.http_repl:
+ req.path_info_pop()
+ return self.http_repl(environ, start_response)
+ elif req.path_info.startswith('/widgets'):
+ controller = self.widgets
+ else:
+ try:
+ widget, action = self.lookup_widget_action(req.path_info)
+ except LookupError:
+ resp = exc.HTTPNotFound('No widget at %s' % req.path_info)
+ return resp(environ, start_response)
+
+
+ # Lookup controller
+ try:
+ controller = self.lookup_controller(widget, action)
+ except LookupError:
+ resp = exc.HTTPNotImplemented()
+ return resp(environ, start_response)
+
+ # If it's a widget class instantiate it with no arguments
+ if isinstance(widget, WidgetType):
+ widget = widget('test_widget')
+ req.widget = widget
+
+ # Call controller and handle output
+ output = controller(req, resp)
+ if isinstance(output, str):
+ resp.body = output
+ elif isinstance(output, unicode):
+ resp.body = output.encode('utf-8')
+ elif output:
+ resp = output
+
+ return resp(environ, start_response)
+
+
+ def show_template(self, req, resp):
+ widget = req.widget
+ if getattr(widget, 'demo_for', None):
+ widget = req.widget.demo_for()
+ template = util.widget_template(widget)
+ if template:
+ return util.format_code(template, 'html')
+ else:
+ resp.content_type = "text/plain"
+ return widget.__class__.__name__ + ' has no template.'
+
+ def show_source(self, req, resp):
+ cls = getattr(req.widget, 'demo_for', req.widget.__class__)
+ source = inspect.getsource(cls)
+ return util.format_code(source, 'python')
+
+ def show_demo_source(self, req, resp):
+ widget = req.widget
+ source = inspect.getsource(widget.__class__)
+ return util.format_code(source, 'python')
+
+ def show_parameters(self, req, resp):
+ cls = getattr(req.widget, 'demo_for', req.widget.__class__)
+ parameters = util.WidgetParameters(cls)
+ return self.render('widget_parameters.html', locals())
+
+
+ def show_index(self, req, resp):
+ widget = req.widget
+ return self.render('widget_index.html', locals())
+
+ def show_demo(self, req, resp):
+ widget = req.widget
+ widget_name = widget.__class__.__name__
+ interactive = self.interactive
+ if have_formencode and req.method.upper() == "POST":
+ # A widget submission, try to validate.
+ try:
+ value = widget.validate(req.POST)
+ value = util.pretty_print(value)
+ return self.render('validation_result.html', locals())
+ except Invalid, error:
+ pass
+
+ if self.interactive:
+ _disp = req.GET.get('_disp', '')
+ else:
+ _disp = ''
+ widget_output = util.display_widget(widget, _disp, self.context)
+ return self.render('show_widget.html', locals())
+
+ def widgets(self, req, resp):
+ widgets = [(util.widget_path(w), util.widget_url(w))
+ for w in util.all_widgets()]
+ widgets.sort()
+ return self.render('list_widgets.html', locals())
+
+ def home(self, req, resp):
+ widgets.jquery_js.inject()
+ widgets.tabs_css.inject()
+ widgets.ui_tabs_js.inject()
+ def url(s):
+ return req.script_name + s
+ return self.render('home.html', locals())
commit b427c525e8965001ed27bd0e7db1a52289390fe9
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 05:03:14 2009 -0500
Quiet a lot of our loggers
diff --git a/development.ini b/development.ini
index 78962c9..ca81db0 100644
--- a/development.ini
+++ b/development.ini
@@ -105,7 +105,7 @@ sqlalchemy.pool_recycle = 3600
# http://docs.python.org/lib/logging-config-fileformat.html
[loggers]
-keys = root, moksha, sqlalchemy, tg
+keys = root, moksha, sqlalchemy, tg, auth, pylons
[handlers]
keys = console
@@ -124,17 +124,24 @@ handlers =
qualname = moksha
[logger_tg]
-level = DEBUG
+level = INFO
handlers =
qualname = tg
+# repoze.who is noisy by default
+[logger_auth]
+level = WARNING
+handlers =
+qualname = auth
+
+
[logger_pylons]
-level = DEBUG
+level = INFO
handlers =
qualname = pylons
[logger_sqlalchemy]
-level = DEBUG
+level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
commit f0dd18a906ceac9f8e749ea2f75be9f79c0c222d
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 04:08:56 2009 -0500
Fix a bug in the extension point middleware
diff --git a/moksha/middleware/extensionpoint.py b/moksha/middleware/extensionpoint.py
index 50d687a..14a426e 100644
--- a/moksha/middleware/extensionpoint.py
+++ b/moksha/middleware/extensionpoint.py
@@ -76,6 +76,7 @@ class MokshaExtensionPointMiddleware(object):
"""
def __init__(self, application, module='moksha', dir='plugins/extensions'):
log.info('Creating MokshaExtensionPointMiddleware')
+ self.application = application
# if debug is False condense javascript to optimize
self.__debug = config.get('moksha.extension_points.debug')
commit 12a751cdbc9cd321bd5c1239e1531c74d09c79e4
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 4 01:32:10 2009 -0500
Add some instructions for profiling Moksha's WSGI stack
diff --git a/docs/main/Development.rst b/docs/main/Development.rst
index 8075726..f17f0d6 100644
--- a/docs/main/Development.rst
+++ b/docs/main/Development.rst
@@ -37,3 +37,8 @@ Running the test suite
.. code-block:: bash
$ nosetests
+
+Profiling the WSGI stack
+------------------------
+
+Open the :file:`moksha/config/app_cfg.py` file and set the `base_config.profile` variable to `True`. After surfing around your application, you can then go to `http://localhost:8080/__profile__ <http://localhost:8080/__profile__>`_ to view your profiling statistics.
15 years, 4 months
moksha/config moksha/middleware
by John (J5) Palmieri
moksha/config/middleware.py | 4
moksha/middleware/__init__.py | 4
moksha/middleware/extensionpoint.py | 204 ++++++++++++++++++++++++++++++++++++
3 files changed, 210 insertions(+), 2 deletions(-)
New commits:
commit 38fea7a510c1b294e8d9ad75b5f9da66dac276e4
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 3 22:55:00 2009 -0500
port extension points from myfedora
diff --git a/moksha/config/middleware.py b/moksha/config/middleware.py
index bfddacf..e9854b8 100644
--- a/moksha/config/middleware.py
+++ b/moksha/config/middleware.py
@@ -2,7 +2,8 @@
from moksha.config.app_cfg import base_config
from moksha.config.environment import load_environment
-from moksha.middleware import MokshaMiddleware, MokshaConnectorMiddleware
+from moksha.middleware import (MokshaMiddleware, MokshaConnectorMiddleware,
+ MokshaExtensionPointMiddleware)
# Use base_config to setup the necessary WSGI App factory.
# make_base_app will wrap the TG2 app with all the middleware it needs.
@@ -14,6 +15,7 @@ def make_app(global_conf, full_stack=True, **app_conf):
**app_conf)
app = MokshaConnectorMiddleware(app)
+ app = MokshaExtensionPointMiddleware(app)
if base_config.squeeze:
from repoze.squeeze.processor import ResourceSqueezingMiddleware
diff --git a/moksha/middleware/__init__.py b/moksha/middleware/__init__.py
index 40ce721..80a3816 100644
--- a/moksha/middleware/__init__.py
+++ b/moksha/middleware/__init__.py
@@ -1,4 +1,6 @@
from middleware import MokshaMiddleware
from connector import MokshaConnectorMiddleware
+from extensionpoint import MokshaExtensionPointMiddleware
-__all__ = ('MokshaMiddleware', 'MokshaConnectorMiddleware')
+__all__ = ('MokshaMiddleware', 'MokshaConnectorMiddleware',
+ 'MokshaExtensionPointMiddleware')
diff --git a/moksha/middleware/extensionpoint.py b/moksha/middleware/extensionpoint.py
new file mode 100644
index 0000000..50d687a
--- /dev/null
+++ b/moksha/middleware/extensionpoint.py
@@ -0,0 +1,204 @@
+# This file is part of Moksha.
+#
+# Moksha is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Moksha is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Moksha. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2008, Red Hat, Inc.
+# Authors: John (J5) Palmieri <johnp(a)redhat.com>
+
+import logging
+import pkg_resources
+
+from webob import Request, Response
+from pylons import config
+from pylons.i18n import ugettext
+
+from moksha.exc import ApplicationNotFound, MokshaException
+
+log = logging.getLogger(__name__)
+
+import shlex
+import os
+
+class Chunk(object):
+ def __init__(self):
+ self.consumes = []
+ self.info = ""
+ self.code = ""
+
+ def parse_consumes_field(self):
+ start = self.info.find('consumes') + 8
+ start = self.info.find('[',start)
+ end = self.info.find(']', start)
+
+ consumes = self.info[start + 1 : end]
+
+ self.consumes = shlex.split(consumes)
+
+class MokshaExtensionPointMiddleware(object):
+ """
+ A layer of WSGI middleware that is responsible for serving
+ javascript extensions.
+
+ If a request for an extension comes in (/moksha_extension/$extension_point),
+ it will serve up any extensions that consume the extension point.
+
+ This works by searching for all extensions of a given type and creating a
+ javascript array pointing to their run functions.
+
+ All extensions should contain at least a run function which will be passed
+ the data fields specified by the extension point. They should also return
+ the HTML they wish to be embedded at the extension point. e.g.:
+
+ function run(data) {
+ // data will always contain a uid field and the HTML you return
+ // will be wrapped in a div with that id
+ return "<div>Hello</div>";
+ };
+
+ Extensions also need a header which describes the extension as such:
+
+ info : {'consumes':['build_message'],
+ 'author': 'John (J5) Palmieri <johnp(a)redhat.com>',
+ 'version': '0.1',
+ 'name': 'Hello World Message'
+
+ """
+ def __init__(self, application, module='moksha', dir='plugins/extensions'):
+ log.info('Creating MokshaExtensionPointMiddleware')
+
+ # if debug is False condense javascript to optimize
+ self.__debug = config.get('moksha.extension_points.debug')
+ self.__extension_cache = {}
+
+ # FIXME: figure out a way to load extensions like we load entry points
+ self.load_extensions(module, dir)
+
+ def chunk_code(self, js, filename):
+ start = js.find('{')
+ end = 0
+ chunks = []
+ length = len(js)
+
+ while (start != -1):
+ count = 1
+ i = start + 1
+ pull_info = False
+ pull_info_start = 0
+ pull_info_end = 0
+
+ while(count != 0 and i < length):
+ if js[i] == '{':
+ count += 1
+ elif js[i] == '}':
+ count -= 1
+ elif count==1 and js[i]=='i' and js.find('info',i) == i:
+ if pull_info_start != 0:
+ print "ERROR: Unexpected Info Field : extension file %s has more than on info field per extension (ignoring file)" % filename
+ return None
+
+ # put us on info duty
+ pull_info = True
+
+ if pull_info:
+ if pull_info_start == 0:
+ if count > 1:
+ pull_info_start = i
+ else:
+ if count == 1:
+ pull_info_end = i
+ pull_info = False
+
+ i += 1
+
+ end = i
+
+ c = Chunk()
+ c.code = js[start:end]
+ c.info = js[pull_info_start:pull_info_end + 1]
+
+ c.parse_consumes_field()
+ chunks.append(c)
+
+ if i >= length:
+ print "ERROR: Unexpected EOF: extension file %s has mismatched braces (ignoring file)" % filename
+ return None
+
+ start = js.find('{', end)
+
+ return chunks
+
+ def load_extension(self, file):
+ log.info("Loading JavaScript extension %s" % file)
+ f = open(file,'r')
+ js = f.read()
+
+ chunks = self.chunk_code(js, file)
+ if not chunks:
+ if chunks != None:
+ log.warning("No Content : extension file %s doesn't have any valid extensions (ignoring file)" % filename)
+
+ return
+
+ for c in chunks:
+ for exttype in c.consumes:
+ code = self.__extension_cache.get(exttype, [])
+ #TODO: run through optimizer which strips whitespace
+ code.append(c.code)
+ self.__extension_cache[exttype] = code
+
+ def load_extensions(self, module, dir):
+ real_dir = pkg_resources.resource_filename(module, dir)
+ for root, dirs, files in os.walk(real_dir):
+ for name in files:
+ if name.endswith('js'):
+ path = os.path.join(root, name)
+ self.load_extension(path)
+
+ # compile lists in the cache down to a string so we don't have to
+ # process it on each request
+ for key, value in self.__extension_cache.iteritems():
+ s = '[' + ','.join(value) + ']'
+ self.__extension_cache[key] = s
+
+ def __call__(self, environ, start_response):
+
+ request = Request(environ)
+
+ if request.path.startswith('/moksha_extension_point'):
+ exttype = request.params.get('exttype')
+ if not exttype:
+ response = Response('')
+ else:
+ extensions_data = self.__extension_cache.get(exttype, "")
+ extensions_str = ','.join(extensions_data)
+
+ script = 'var mf_loaded_extensions ='
+ script += extensions_data
+ script += ';'
+ # now run the deferred extensions queued up while the scripts
+ # were being downloaded
+
+ script += 'myfedora.extensions._extension_cache["' + exttype +'"] = mf_loaded_extensions;'
+ script += 'var deferred=myfedora.extensions._extension_deferred["' + exttype +'"];'
+ script += 'var d=deferred.shift();'
+ script += 'while(d){'
+ script += 'myfedora.extensions.run_extensions(mf_loaded_extensions, d);'
+ script += 'd = deferred.shift();'
+ script += '}'
+
+ response = Response(script)
+ else:
+ response = request.get_response(self.application)
+
+ return response(environ, start_response)
15 years, 4 months
moksha/lib
by John (J5) Palmieri
moksha/lib/helpers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 5327a7427116300c8bb78b468f2e48aa2e967836
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 3 21:29:34 2009 -0500
fix typo
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py
index 1171aec..7d9982b 100644
--- a/moksha/lib/helpers.py
+++ b/moksha/lib/helpers.py
@@ -108,7 +108,7 @@ class Category(ConfigWrapper):
id = uuid.uuid4()
apps = self.process_wrappers(self.apps)
- return {'label': self.label, 'apps': apps, 'id': id, 'css_class': css_class}
+ return {'label': self.label, 'apps': apps, 'id': id, 'css_class': self.css_class}
class App(ConfigWrapper):
"""A configuration wrapper class that displays an application pointed to
15 years, 4 months
2 commits - moksha/config moksha/middleware
by John (J5) Palmieri
moksha/config/middleware.py | 9 ++-
moksha/middleware/__init__.py | 3 -
moksha/middleware/connector.py | 118 ++++++++++++++++++++++++++++++++++++++++
moksha/middleware/middleware.py | 81 ++-------------------------
4 files changed, 134 insertions(+), 77 deletions(-)
New commits:
commit ac33b1149121f5d23427e0b4a309d065e273da46
Merge: 1928722... a816836...
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 3 21:27:46 2009 -0500
Merge branch 'master' of git+ssh://johnp@git.fedorahosted.org/git/moksha
commit 192872214440e99545c7dc38566b10f2aa10bdb7
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 3 21:26:44 2009 -0500
split the connector into its own middleware
diff --git a/moksha/config/middleware.py b/moksha/config/middleware.py
index b22c418..bfddacf 100644
--- a/moksha/config/middleware.py
+++ b/moksha/config/middleware.py
@@ -2,7 +2,7 @@
from moksha.config.app_cfg import base_config
from moksha.config.environment import load_environment
-from moksha.middleware import MokshaMiddleware
+from moksha.middleware import MokshaMiddleware, MokshaConnectorMiddleware
# Use base_config to setup the necessary WSGI App factory.
# make_base_app will wrap the TG2 app with all the middleware it needs.
@@ -10,7 +10,10 @@ make_base_app = base_config.setup_tg_wsgi_app(load_environment)
def make_app(global_conf, full_stack=True, **app_conf):
app = make_base_app(global_conf, wrap_app=MokshaMiddleware,
- full_stack=True, **app_conf)
+ full_stack=True,
+ **app_conf)
+
+ app = MokshaConnectorMiddleware(app)
if base_config.squeeze:
from repoze.squeeze.processor import ResourceSqueezingMiddleware
@@ -30,4 +33,4 @@ def make_app(global_conf, full_stack=True, **app_conf):
path='/__profile__'
)
- return app
+ return app
\ No newline at end of file
diff --git a/moksha/middleware/__init__.py b/moksha/middleware/__init__.py
index 891fe41..40ce721 100644
--- a/moksha/middleware/__init__.py
+++ b/moksha/middleware/__init__.py
@@ -1,3 +1,4 @@
from middleware import MokshaMiddleware
+from connector import MokshaConnectorMiddleware
-__all__ = ('MokshaMiddleware')
+__all__ = ('MokshaMiddleware', 'MokshaConnectorMiddleware')
diff --git a/moksha/middleware/connector.py b/moksha/middleware/connector.py
new file mode 100644
index 0000000..f1f0291
--- /dev/null
+++ b/moksha/middleware/connector.py
@@ -0,0 +1,118 @@
+# This file is part of Moksha.
+#
+# Moksha is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Moksha is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Moksha. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2008, Red Hat, Inc.
+# Authors: John (J5) Palmieri <johnp(a)redhat.com>
+
+import logging
+import pkg_resources
+import simplejson as json
+import urllib
+
+from webob import Request, Response
+from pylons import config
+from pylons.i18n import ugettext
+
+from moksha.exc import ApplicationNotFound, MokshaException
+
+log = logging.getLogger(__name__)
+
+class MokshaConnectorMiddleware(object):
+ """
+ A layer of WSGI middleware that is responsible for handling every
+ moksha_connector requests.
+
+ If a request for a connector comes in (/moksha_connector/$name), it will
+ run that connector as defined in it's egg-info.
+
+ """
+ def __init__(self, application):
+ log.info('Creating MokshaConnectorMiddleware')
+ self.application = application
+ self.connectors = {} # {'connector name': moksha.IConnector class}
+
+ self.load_connectors()
+
+ def __call__(self, environ, start_response):
+
+ request = Request(environ)
+
+ if request.path.startswith('/moksha_connector'):
+ s = request.path.split('/')[2:]
+
+ # since keys are not unique we need to condense them
+ # into an actual dictionary with multiple entries becoming lists
+ p = request.params
+ params = {}
+ for k in p.iterkeys():
+ if k == '_cookies':
+ # reserved parameter
+ # FIXME: provide a proper error response
+ return Response(status='404 Not Found')
+
+ if k not in params:
+ params[k] = p.getall(k)
+
+ response = self._run_connector(s[0], s[1], *s[2:], **params)
+ else:
+ response = request.get_response(self.application)
+
+ return response(environ, start_response)
+
+ def _run_connector(self, conn, op, *path, **remote_params):
+ response = None
+ # check last part of path to see if it is json data
+ dispatch_params = {};
+
+ p = urllib.unquote_plus(path[-1].lstrip())
+ if p.startswith('{'):
+ dispatch_params = json.loads(p)
+ f = dispatch_params.get('filters')
+ if isinstance(f, basestring):
+ dispatch_params['filters'] = json.loads(f)
+ path = path[:-1]
+
+ # prevent trailing slash
+ if not p:
+ path = path[:-1]
+
+ path = '/'.join(path)
+ conn = self.connectors.get(conn)
+
+ if conn:
+ conn_obj = conn['connector_class']()
+ r = conn_obj._dispatch(op, path, remote_params, **dispatch_params)
+ if not isinstance(r, str):
+ r = json.dumps(r, separators=(',',':'))
+ response = Response(r)
+ else:
+ response = Response(status='404 Not Found')
+
+ return response
+
+ def load_connectors(self):
+ log.info('Loading moksha connectors')
+ for conn_entry in pkg_resources.iter_entry_points('moksha.connector'):
+ log.info('Loading %s connector' % conn_entry.name)
+ conn_class = conn_entry.load()
+ # call the register class method
+ # FIXME: Should we pass some resource in?
+ conn_class.register()
+ conn_path = conn_entry.dist.location
+ self.connectors[conn_entry.name] = {
+ 'name': conn_entry.name,
+ 'connector_class': conn_class,
+ 'path': conn_path,
+ }
diff --git a/moksha/middleware/middleware.py b/moksha/middleware/middleware.py
index 609b806..701f7d5 100644
--- a/moksha/middleware/middleware.py
+++ b/moksha/middleware/middleware.py
@@ -1,15 +1,15 @@
# This file is part of Moksha.
-#
+#
# Moksha is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-#
+#
# Moksha is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with Moksha. If not, see <http://www.gnu.org/licenses/>.
#
@@ -57,12 +57,10 @@ class MokshaMiddleware(object):
self.menus = {} # {'menu name': MokshaMenu}
self.widgets = {} # {'widget name': tw.api.Widget}
self.engines = {} # {'app name': sqlalchemy.engine.base.Engine}
- self.connectors = {} # {'connector name': moksha.IConnector class}
self.load_paths()
self.load_renderers()
self.load_configs()
- self.load_connectors()
self.load_widgets()
self.load_applications()
self.load_models()
@@ -73,7 +71,7 @@ class MokshaMiddleware(object):
def __call__(self, environ, start_response):
environ['paste.registry'].register(moksha.apps, self.apps)
-
+
# environ['paste.registry'].register(moksha._widgets, self.widgets)
environ['paste.registry'].register(moksha.feed_cache, self.feed_cache)
environ['paste.registry'].register(moksha.menus, self.menus)
@@ -87,25 +85,6 @@ class MokshaMiddleware(object):
response = request.get_response(self.mokshaapp)
except ApplicationNotFound:
response = Response(status='404 Not Found')
- elif request.path.startswith('/moksha_connector'):
- # FIXME: this should be separate middleware so other
- # frameworks can use connectors
- s = request.path.split('/')[2:]
-
- # since keys are not unique we need to condense them
- # into an actual dictionary with multiple entries becoming lists
- p = request.params
- params = {}
- for k in p.iterkeys():
- if k == '_cookies':
- # reserved parameter
- # FIXME: provide a proper error response
- return Response(status='404 Not Found')
-
- if k not in params:
- params[k] = p.getall(k)
-
- response = self._run_connector(s[0], s[1], *s[2:], **params)
else:
response = request.get_response(self.application)
@@ -121,36 +100,7 @@ class MokshaMiddleware(object):
'onmessageframe': defaultdict(list) # {topic: [js_callback,]}
})
- def _run_connector(self, conn, op, *path, **remote_params):
- response = None
- # check last part of path to see if it is json data
- dispatch_params = {};
-
- p = urllib.unquote_plus(path[-1].lstrip())
- if p.startswith('{'):
- dispatch_params = json.loads(p)
- f = dispatch_params.get('filters')
- if isinstance(f, basestring):
- dispatch_params['filters'] = json.loads(f)
- path = path[:-1]
-
- # prevent trailing slash
- if not p:
- path = path[:-1]
-
- path = '/'.join(path)
- conn = self.connectors.get(conn)
-
- if conn:
- conn_obj = conn['connector_class']()
- r = conn_obj._dispatch(op, path, remote_params, **dispatch_params)
- if not isinstance(r, str):
- r = json.dumps(r, separators=(',',':'))
- response = Response(r)
- else:
- response = Response(status='404 Not Found')
- return response
def load_paths(self):
""" Load the names and paths of all moksha applications and widgets.
@@ -161,7 +111,7 @@ class MokshaMiddleware(object):
"""
for app_entry in pkg_resources.iter_entry_points('moksha.application'):
if app_entry.name in self.apps:
- raise MokshaException('Duplicate application name: %s' %
+ raise MokshaException('Duplicate application name: %s' %
app_entry.name)
app_path = app_entry.dist.location
self.apps[app_entry.name] = {
@@ -170,7 +120,7 @@ class MokshaMiddleware(object):
}
for widget_entry in pkg_resources.iter_entry_points('moksha.widget'):
if widget_entry.name in self.widgets:
- raise MokshaException('Duplicate widget name: %s' %
+ raise MokshaException('Duplicate widget name: %s' %
widget_entry.name)
widget_path = widget_entry.dist.location
self.widgets[widget_entry.name] = {
@@ -178,21 +128,6 @@ class MokshaMiddleware(object):
'path': widget_path,
}
- def load_connectors(self):
- log.info('Loading moksha connectors')
- for conn_entry in pkg_resources.iter_entry_points('moksha.connector'):
- log.info('Loading %s connector' % conn_entry.name)
- conn_class = conn_entry.load()
- # call the register class method
- # FIXME: Should we pass some resource in?
- conn_class.register()
- conn_path = conn_entry.dist.location
- self.connectors[conn_entry.name] = {
- 'name': conn_entry.name,
- 'connector_class': conn_class,
- 'path': conn_path,
- }
-
def load_applications(self):
log.info('Loading moksha applications')
for app_entry in pkg_resources.iter_entry_points('moksha.application'):
@@ -207,7 +142,7 @@ class MokshaMiddleware(object):
}
try:
model = __import__('%s.model' % app_entry.name,
- globals(), locals(),
+ globals(), locals(),
[app_entry.name])
self.apps[app_entry.name]['model'] = model
except ImportError:
@@ -229,7 +164,7 @@ class MokshaMiddleware(object):
'widget': widget,
'path': widget_path,
}
-
+
moksha._widgets = self.widgets
def load_menus(self):
15 years, 4 months
setup.py
by Luke Macken
setup.py | 2 ++
1 file changed, 2 insertions(+)
New commits:
commit a8168361c0ed00d9281a1928f71803baf80a20d2
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 20:09:21 2009 -0500
Add Sphinx and Paver to our package requirements
diff --git a/setup.py b/setup.py
index aeabf48..2eb5756 100644
--- a/setup.py
+++ b/setup.py
@@ -20,6 +20,8 @@ setup(
"orbited",
"twisted",
"stomper",
+ "Sphinx",
+ "Paver",
#"WidgetBrowser", # not in PyPi yet
],
packages=find_packages(exclude=['ez_setup']),
15 years, 4 months
docs/main
by Luke Macken
docs/main/MokshaContainerWidgets.rst | 5 +++++
1 file changed, 5 insertions(+)
New commits:
commit a850a028367ce771e79d23e3fb209d9e66ece809
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:43:25 2009 -0500
Fix the code-block's in the container widget docs
diff --git a/docs/main/MokshaContainerWidgets.rst b/docs/main/MokshaContainerWidgets.rst
index 65176d3..5abd9a3 100644
--- a/docs/main/MokshaContainerWidgets.rst
+++ b/docs/main/MokshaContainerWidgets.rst
@@ -84,6 +84,7 @@ Here is an example on how to subclass a TabbedContainer:
mainnav.py
.. code-block:: python
+
from moksha.api.widgets.containers import TabbedContainer
class MainNav(TabbedContainer):
@@ -93,6 +94,7 @@ mainnav.py
mainnav.mak
.. code-block:: html
+
<div>
<ul id="${id}">
% for t in tabs:
@@ -121,6 +123,7 @@ mainnav.mak
development.ini
.. code-block:: python
+
[DEFAULT]
myapp.mainnav.apps = (MokshaApp('Home', 'myapp.home'),
MokshaApp('2nd Tab', 'myapp.tab2'),
@@ -149,6 +152,7 @@ Here is an example on how to subclass a DashboardContainer:
homepage.py
.. code-block:: python
+
from moksha.api.widgets.containers import DashboardContainer
class HomePageContainer(DashboardContainer):
@@ -172,6 +176,7 @@ homepage.py
homepagecontainer.mak
.. code-block:: html
+
<div id="${id}">
<div>
<div id="right-content-column">
15 years, 4 months
11 commits - moksha/api moksha/controllers moksha/exc.py moksha/public moksha/templates moksha/widgets setup.py
by Luke Macken
moksha/api/menus/default.py | 7
moksha/controllers/root.py | 27
moksha/exc.py | 3
moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif |binary
moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif |binary
moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif |binary
moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif |binary
moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif |binary
moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif |binary
moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif |binary
moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif |binary
moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif |binary
moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif |binary
moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif |binary
moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif |binary
moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif |binary
moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif |binary
moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif |binary
moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif |binary
moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png |binary
moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png |binary
moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png |binary
moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png |binary
moksha/public/css/jquery-ui/ui.theme.css | 607 ++++++++++
moksha/templates/footer.mak | 2
moksha/templates/index.mak | 3
moksha/widgets/container/container.py | 19
moksha/widgets/jquery_ui_theme.py | 5
moksha/widgets/misc/ptd/LICENSE | 28
moksha/widgets/misc/ptd/__init__.py | 1
moksha/widgets/misc/ptd/game/creep_waves.js | 90 +
moksha/widgets/misc/ptd/game/creeps.js | 353 +++++
moksha/widgets/misc/ptd/game/ptd.js | 460 +++++++
moksha/widgets/misc/ptd/game/terrain.js | 79 +
moksha/widgets/misc/ptd/game/ui_modes.js | 346 +++++
moksha/widgets/misc/ptd/game/util.js | 264 ++++
moksha/widgets/misc/ptd/game/weapons.js | 398 ++++++
moksha/widgets/misc/ptd/ptd.py | 31
moksha/widgets/misc/ptd/static/jsfprocessing.js | 101 +
moksha/widgets/misc/ptd/static/konami.js | 10
moksha/widgets/misc/ptd/static/style.css | 171 ++
moksha/widgets/misc/ptd/templates/ptd.mak | 319 +++++
setup.py | 12
64 files changed, 3300 insertions(+), 36 deletions(-)
New commits:
commit aeef1fe9fe2e4acdde843a45c8e5e742906ea529
Merge: 8701e4b... 0b58dcf...
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:25:53 2009 -0500
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit 8701e4b1ea456396f4fdadead1dde92043fcba4d
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:24:35 2009 -0500
Add a custom jQuery UI theme, and a widget for it, for future use.
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif
new file mode 100644
index 0000000..b26780a
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif
new file mode 100644
index 0000000..69eb077
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif
new file mode 100644
index 0000000..70d0c82
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif
new file mode 100644
index 0000000..26db434
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif
new file mode 100644
index 0000000..4efed68
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif
new file mode 100644
index 0000000..0032ff6
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif
new file mode 100644
index 0000000..6851f39
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif
new file mode 100644
index 0000000..74ac5cb
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif
new file mode 100644
index 0000000..251dc16
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif
new file mode 100644
index 0000000..29c6c70
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif
new file mode 100644
index 0000000..9f95efa
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif
new file mode 100644
index 0000000..bc02050
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif differ
diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif
new file mode 100644
index 0000000..28169eb
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif
new file mode 100644
index 0000000..136e626
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif
new file mode 100644
index 0000000..4f00635
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif
new file mode 100644
index 0000000..390a759
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif
new file mode 100644
index 0000000..e91c733
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif
new file mode 100644
index 0000000..85f0e0b
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif
new file mode 100644
index 0000000..f6414c7
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif
new file mode 100644
index 0000000..25b3e17
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif
new file mode 100644
index 0000000..41d9534
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif
new file mode 100644
index 0000000..92fdfe0
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif
new file mode 100644
index 0000000..cf01ff3
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif
new file mode 100644
index 0000000..3190e7a
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif differ
diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif
new file mode 100644
index 0000000..7ae34bf
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif
new file mode 100644
index 0000000..19f9d6b
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif
new file mode 100644
index 0000000..c10451f
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif
new file mode 100644
index 0000000..326d015
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif
new file mode 100644
index 0000000..7d1b5cb
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif
new file mode 100644
index 0000000..71bff05
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif
new file mode 100644
index 0000000..33a20b8
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif
new file mode 100644
index 0000000..777c328
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif
new file mode 100644
index 0000000..43531ff
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif
new file mode 100644
index 0000000..c91731d
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif
new file mode 100644
index 0000000..d6c523b
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif
new file mode 100644
index 0000000..d65b2ed
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif differ
diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif
new file mode 100644
index 0000000..165666a
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif differ
diff --git a/moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png b/moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png
new file mode 100644
index 0000000..60ba001
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png differ
diff --git a/moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png b/moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png
new file mode 100644
index 0000000..d1f8955
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png differ
diff --git a/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png
new file mode 100644
index 0000000..ac8b229
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png differ
diff --git a/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png
new file mode 100644
index 0000000..2c16183
Binary files /dev/null and b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png differ
diff --git a/moksha/public/css/jquery-ui/ui.theme.css b/moksha/public/css/jquery-ui/ui.theme.css
new file mode 100644
index 0000000..d32d49c
--- /dev/null
+++ b/moksha/public/css/jquery-ui/ui.theme.css
@@ -0,0 +1,607 @@
+/*
+ * jQuery UI screen structure and presentation
+ * This CSS file was generated by ThemeRoller, a Filament Group Project for jQuery UI
+ * Author: Scott Jehl, scott(a)filamentgroup.com, http://www.filamentgroup.com
+ * Visit ThemeRoller.com
+*/
+
+/*
+ * Note: If your ThemeRoller settings have a font size set in ems, your components will scale according to their parent element's font size.
+ * As a rule of thumb, set your body's font size to 62.5% to make 1em = 10px.
+ * body {font-size: 62.5%;}
+*/
+
+
+
+/*UI accordion*/
+.ui-accordion {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 1.1em;
+ border-bottom: 1px solid #d3d3d3;
+}
+.ui-accordion-group {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ border: 1px solid #d3d3d3;
+ border-bottom: none;
+}
+.ui-accordion-header {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ cursor: pointer;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+}
+.ui-accordion-header a {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ display: block;
+ font-size: 1em;
+ font-weight: normal;
+ text-decoration: none;
+ padding: .5em .5em .5em 1.7em;
+ color: #555555;
+ background: url(images/888888_7x7_arrow_right.gif) .5em 50% no-repeat;
+}
+.ui-accordion-header a:hover {
+ background: url(images/454545_7x7_arrow_right.gif) .5em 50% no-repeat;
+ color: #212121;
+}
+.ui-accordion-header:hover {
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ color: #212121;
+}
+.selected .ui-accordion-header, .selected .ui-accordion-header:hover {
+ background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x;
+}
+.selected .ui-accordion-header a, .selected .ui-accordion-header a:hover {
+ color: #222222;
+ background: url(images/222222_7x7_arrow_down.gif) .5em 50% no-repeat;
+}
+.ui-accordion-content {
+ background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x;
+ color: #222222;
+ font-size: 1em;
+}
+.ui-accordion-content p {
+ padding: 1em 1.7em 0.6em;
+}
+
+
+
+
+
+
+/*UI tabs*/
+.ui-tabs-nav {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 1.1em;
+ float: left;
+ position: relative;
+ z-index: 1;
+ border-right: 1px solid #d3d3d3;
+ bottom: -1px;
+}
+.ui-tabs-nav li {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ float: left;
+ border: 1px solid #d3d3d3;
+ border-right: none;
+}
+.ui-tabs-nav li a {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ float: left;
+ font-size: 1em;
+ font-weight: normal;
+ text-decoration: none;
+ padding: .5em 1.7em;
+ color: #555555;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+}
+.ui-tabs-nav li a:hover {
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ color: #212121;
+}
+.ui-tabs-nav li.ui-tabs-selected {
+ border-bottom-color: #ffffff;
+}
+.ui-tabs-nav li.ui-tabs-selected a, .ui-tabs-nav li.ui-tabs-selected a:hover {
+ background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x;
+ color: #222222;
+}
+.ui-tabs-panel {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ clear:left;
+ border: 1px solid #d3d3d3;
+ background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x;
+ color: #222222;
+ padding: 1.5em 1.7em;
+ font-size: 1.1em;
+}
+.ui-tabs-hide {
+ display: none;/* for accessible hiding: position: absolute; left: -99999999px*/;
+}
+
+
+
+
+
+/*slider*/
+.ui-slider {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 1.1em;
+ background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x;
+ border: 1px solid #dddddd;
+ height: .8em;
+ position: relative;
+}
+.ui-slider-handle {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ position: absolute;
+ z-index: 2;
+ top: -3px;
+ width: 1.2em;
+ height: 1.2em;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ border: 1px solid #d3d3d3;
+}
+.ui-slider-handle:hover {
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ border: 1px solid #999999;
+}
+.ui-slider-handle-active, .ui-slider-handle-active:hover {
+ background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x;
+ border: 1px solid #dddddd;
+}
+.ui-slider-range {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ height: .8em;
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ position: absolute;
+ border: 1px solid #d3d3d3;
+ border-left: 0;
+ border-right: 0;
+ top: -1px;
+ z-index: 1;
+ opacity:.7;
+ filter:Alpha(Opacity=70);
+}
+
+
+
+
+
+
+/*dialog*/
+.ui-dialog {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 1.1em;
+ background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x;
+ color: #222222;
+ border: 4px solid #dddddd;
+ position: relative;
+}
+.ui-resizable-handle {
+ position: absolute;
+ font-size: 0.1px;
+ z-index: 99999;
+}
+.ui-resizable .ui-resizable-handle {
+ display: block;
+}
+body .ui-resizable-disabled .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
+body .ui-resizable-autohide .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */
+.ui-resizable-n {
+ cursor: n-resize;
+ height: 7px;
+ width: 100%;
+ top: -5px;
+ left: 0px;
+}
+.ui-resizable-s {
+ cursor: s-resize;
+ height: 7px;
+ width: 100%;
+ bottom: -5px;
+ left: 0px;
+}
+.ui-resizable-e {
+ cursor: e-resize;
+ width: 7px;
+ right: -5px;
+ top: 0px;
+ height: 100%;
+}
+.ui-resizable-w {
+ cursor: w-resize;
+ width: 7px;
+ left: -5px;
+ top: 0px;
+ height: 100%;
+}
+.ui-resizable-se {
+ cursor: se-resize;
+ width: 13px;
+ height: 13px;
+ right: 0px;
+ bottom: 0px;
+ background: url(images/222222_11x11_icon_resize_se.gif) no-repeat 0 0;
+}
+.ui-resizable-sw {
+ cursor: sw-resize;
+ width: 9px;
+ height: 9px;
+ left: 0px;
+ bottom: 0px;
+}
+.ui-resizable-nw {
+ cursor: nw-resize;
+ width: 9px;
+ height: 9px;
+ left: 0px;
+ top: 0px;
+}
+.ui-resizable-ne {
+ cursor: ne-resize;
+ width: 9px;
+ height: 9px;
+ right: 0px;
+ top: 0px;
+}
+.ui-dialog-titlebar {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ padding: .5em 1.5em .5em 1em;
+ color: #555555;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ border-bottom: 1px solid #d3d3d3;
+ font-size: 1em;
+ font-weight: normal;
+ position: relative;
+}
+.ui-dialog-title {}
+.ui-dialog-titlebar-close {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ background: url(images/888888_11x11_icon_close.gif) 0 0 no-repeat;
+ position: absolute;
+ right: 8px;
+ top: .7em;
+ width: 11px;
+ height: 11px;
+ z-index: 100;
+}
+.ui-dialog-titlebar-close-hover, .ui-dialog-titlebar-close:hover {
+ background: url(images/454545_11x11_icon_close.gif) 0 0 no-repeat;
+}
+.ui-dialog-titlebar-close:active {
+ background: url(images/222222_11x11_icon_close.gif) 0 0 no-repeat;
+}
+.ui-dialog-titlebar-close span {
+ display: none;
+}
+.ui-dialog-content {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ color: #222222;
+ padding: 1.5em 1.7em;
+}
+.ui-dialog-buttonpane {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ text-align: left;
+ border-top: 1px solid #dddddd;
+ background: #ffffff;
+}
+.ui-dialog-buttonpane button {
+ margin: .5em 0 .5em 8px;
+ color: #555555;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ font-size: 1em;
+ border: 1px solid #d3d3d3;
+ cursor: pointer;
+ padding: .2em .6em .3em .6em;
+ line-height: 1.4em;
+}
+.ui-dialog-buttonpane button:hover {
+ color: #212121;
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ border: 1px solid #999999;
+}
+.ui-dialog-buttonpane button:active {
+ color: #222222;
+ background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x;
+ border: 1px solid #dddddd;
+}
+/* This file skins dialog */
+.ui-dialog.ui-draggable .ui-dialog-titlebar,
+.ui-dialog.ui-draggable .ui-dialog-titlebar {
+ cursor: move;
+}
+
+
+
+
+
+
+
+/*datepicker*/
+/* Main Style Sheet for jQuery UI date picker */
+.ui-datepicker-div, .ui-datepicker-inline, #ui-datepicker-div {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x;
+ font-size: 1.1em;
+ border: 4px solid #dddddd;
+ width: 15.5em;
+ padding: 2.5em .5em .5em .5em;
+ position: relative;
+}
+.ui-datepicker-div, #ui-datepicker-div {
+ z-index: 9999; /*must have*/
+ display: none;
+}
+.ui-datepicker-inline {
+ float: left;
+ display: block;
+}
+.ui-datepicker-control {
+ display: none;
+}
+.ui-datepicker-current {
+ display: none;
+}
+.ui-datepicker-next, .ui-datepicker-prev {
+ position: absolute;
+ left: .5em;
+ top: .5em;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+}
+.ui-datepicker-next {
+ left: 14.6em;
+}
+.ui-datepicker-next:hover, .ui-datepicker-prev:hover {
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+}
+.ui-datepicker-next a, .ui-datepicker-prev a {
+ text-indent: -999999px;
+ width: 1.3em;
+ height: 1.4em;
+ display: block;
+ font-size: 1em;
+ background: url(images/888888_7x7_arrow_left.gif) 50% 50% no-repeat;
+ border: 1px solid #d3d3d3;
+ cursor: pointer;
+}
+.ui-datepicker-next a {
+ background: url(images/888888_7x7_arrow_right.gif) 50% 50% no-repeat;
+}
+.ui-datepicker-prev a:hover {
+ background: url(images/454545_7x7_arrow_left.gif) 50% 50% no-repeat;
+}
+.ui-datepicker-next a:hover {
+ background: url(images/454545_7x7_arrow_right.gif) 50% 50% no-repeat;
+}
+.ui-datepicker-prev a:active {
+ background: url(images/222222_7x7_arrow_left.gif) 50% 50% no-repeat;
+}
+.ui-datepicker-next a:active {
+ background: url(images/222222_7x7_arrow_right.gif) 50% 50% no-repeat;
+}
+.ui-datepicker-header select {
+ border: 1px solid #d3d3d3;
+ color: #555555;
+ background: #e6e6e6;
+ font-size: 1em;
+ line-height: 1.4em;
+ position: absolute;
+ top: .5em;
+ margin: 0 !important;
+}
+.ui-datepicker-header option:focus, .ui-datepicker-header option:hover {
+ background: #dadada;
+}
+.ui-datepicker-header select.ui-datepicker-new-month {
+ width: 7em;
+ left: 2.2em;
+}
+.ui-datepicker-header select.ui-datepicker-new-year {
+ width: 5em;
+ left: 9.4em;
+}
+table.ui-datepicker {
+ width: 15.5em;
+ text-align: right;
+}
+table.ui-datepicker td a {
+ padding: .1em .3em .1em 0;
+ display: block;
+ color: #555555;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ cursor: pointer;
+ border: 1px solid #ffffff;
+}
+table.ui-datepicker td a:hover {
+ border: 1px solid #999999;
+ color: #212121;
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+}
+table.ui-datepicker td a:active {
+ border: 1px solid #dddddd;
+ color: #222222;
+ background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x;
+}
+table.ui-datepicker .ui-datepicker-title-row td {
+ padding: .3em 0;
+ text-align: center;
+ font-size: .9em;
+ color: #222222;
+ text-transform: uppercase;
+}
+table.ui-datepicker .ui-datepicker-title-row td a {
+ color: #222222;
+}
+.ui-datepicker-cover {
+ display: none;
+ display/**/: block;
+ position: absolute;
+ z-index: -1;
+ filter: mask();
+ top: -4px;
+ left: -4px;
+ width: 193px;
+ height: 200px;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+Generic ThemeRoller Classes
+>> Make your jQuery Components ThemeRoller-Compatible!
+*/
+
+/*component global class*/
+.ui-component {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 1.1em;
+}
+/*component content styles*/
+.ui-component-content {
+ border: 1px solid #dddddd;
+ background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x;
+ color: #222222;
+}
+.ui-component-content a {
+ color: #222222;
+ text-decoration: underline;
+}
+/*component states*/
+.ui-default-state {
+ border: 1px solid #d3d3d3;
+ background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ font-weight: normal;
+ color: #555555 !important;
+}
+.ui-default-state a {
+ color: #555555;
+}
+.ui-default-state:hover, .ui-hover-state {
+ border: 1px solid #999999;
+ background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x;
+ font-weight: normal;
+ color: #212121 !important;
+}
+.ui-hover-state a {
+ color: #212121;
+}
+.ui-default-state:active, .ui-active-state {
+ border: 1px solid #dddddd;
+ background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x;
+ font-weight: normal;
+ color: #222222 !important;
+ outline: none;
+}
+.ui-active-state a {
+ color: #222222;
+ outline: none;
+}
+/*icons*/
+.ui-arrow-right-default {background: url(images/888888_7x7_arrow_right.gif) no-repeat 50% 50%;}
+.ui-arrow-right-default:hover, .ui-arrow-right-hover {background: url(images/454545_7x7_arrow_right.gif) no-repeat 50% 50%;}
+.ui-arrow-right-default:active, .ui-arrow-right-active {background: url(images/222222_7x7_arrow_right.gif) no-repeat 50% 50%;}
+.ui-arrow-right-content {background: url(images/222222_7x7_arrow_right.gif) no-repeat 50% 50%;}
+
+.ui-arrow-left-default {background: url(images/888888_7x7_arrow_left.gif) no-repeat 50% 50%;}
+.ui-arrow-left-default:hover, .ui-arrow-left-hover {background: url(images/454545_7x7_arrow_left.gif) no-repeat 50% 50%;}
+.ui-arrow-left-default:active, .ui-arrow-left-active {background: url(images/222222_7x7_arrow_left.gif) no-repeat 50% 50%;}
+.ui-arrow-left-content {background: url(images/222222_7x7_arrow_left.gif) no-repeat 50% 50%;}
+
+.ui-arrow-down-default {background: url(images/888888_7x7_arrow_down.gif) no-repeat 50% 50%;}
+.ui-arrow-down-default:hover, .ui-arrow-down-hover {background: url(images/454545_7x7_arrow_down.gif) no-repeat 50% 50%;}
+.ui-arrow-down-default:active, .ui-arrow-down-active {background: url(images/222222_7x7_arrow_down.gif) no-repeat 50% 50%;}
+.ui-arrow-down-content {background: url(images/222222_7x7_arrow_down.gif) no-repeat 50% 50%;}
+
+.ui-arrow-up-default {background: url(images/888888_7x7_arrow_up.gif) no-repeat 50% 50%;}
+.ui-arrow-up-default:hover, .ui-arrow-up-hover {background: url(images/454545_7x7_arrow_up.gif) no-repeat 50% 50%;}
+.ui-arrow-up-default:active, .ui-arrow-up-active {background: url(images/222222_7x7_arrow_up.gif) no-repeat 50% 50%;}
+.ui-arrow-up-content {background: url(images/222222_7x7_arrow_up.gif) no-repeat 50% 50%;}
+
+.ui-close-default {background: url(images/888888_11x11_icon_close.gif) no-repeat 50% 50%;}
+.ui-close-default:hover, .ui-close-hover {background: url(images/454545_11x11_icon_close.gif) no-repeat 50% 50%;}
+.ui-close-default:active, .ui-close-active {background: url(images/222222_11x11_icon_close.gif) no-repeat 50% 50%;}
+.ui-close-content {background: url(images/222222_11x11_icon_close.gif) no-repeat 50% 50%;}
+
+.ui-folder-closed-default {background: url(images/888888_11x11_icon_folder_closed.gif) no-repeat 50% 50%;}
+.ui-folder-closed-default:hover, .ui-folder-closed-hover {background: url(images/454545_11x11_icon_folder_closed.gif) no-repeat 50% 50%;}
+.ui-folder-closed-default:active, .ui-folder-closed-active {background: url(images/222222_11x11_icon_folder_closed.gif) no-repeat 50% 50%;}
+.ui-folder-closed-content {background: url(images/888888_11x11_icon_folder_closed.gif) no-repeat 50% 50%;}
+
+.ui-folder-open-default {background: url(images/888888_11x11_icon_folder_open.gif) no-repeat 50% 50%;}
+.ui-folder-open-default:hover, .ui-folder-open-hover {background: url(images/454545_11x11_icon_folder_open.gif) no-repeat 50% 50%;}
+.ui-folder-open-default:active, .ui-folder-open-active {background: url(images/222222_11x11_icon_folder_open.gif) no-repeat 50% 50%;}
+.ui-folder-open-content {background: url(images/222222_11x11_icon_folder_open.gif) no-repeat 50% 50%;}
+
+.ui-doc-default {background: url(images/888888_11x11_icon_doc.gif) no-repeat 50% 50%;}
+.ui-doc-default:hover, .ui-doc-hover {background: url(images/454545_11x11_icon_doc.gif) no-repeat 50% 50%;}
+.ui-doc-default:active, .ui-doc-active {background: url(images/222222_11x11_icon_doc.gif) no-repeat 50% 50%;}
+.ui-doc-content {background: url(images/222222_11x11_icon_doc.gif) no-repeat 50% 50%;}
+
+.ui-arrows-leftright-default {background: url(images/888888_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;}
+.ui-arrows-leftright-default:hover, .ui-arrows-leftright-hover {background: url(images/454545_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;}
+.ui-arrows-leftright-default:active, .ui-arrows-leftright-active {background: url(images/222222_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;}
+.ui-arrows-leftright-content {background: url(images/222222_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;}
+
+.ui-arrows-updown-default {background: url(images/888888_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;}
+.ui-arrows-updown-default:hover, .ui-arrows-updown-hover {background: url(images/454545_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;}
+.ui-arrows-updown-default:active, .ui-arrows-updown-active {background: url(images/222222_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;}
+.ui-arrows-updown-content {background: url(images/222222_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;}
+
+.ui-minus-default {background: url(images/888888_11x11_icon_minus.gif) no-repeat 50% 50%;}
+.ui-minus-default:hover, .ui-minus-hover {background: url(images/454545_11x11_icon_minus.gif) no-repeat 50% 50%;}
+.ui-minus-default:active, .ui-minus-active {background: url(images/222222_11x11_icon_minus.gif) no-repeat 50% 50%;}
+.ui-minus-content {background: url(images/222222_11x11_icon_minus.gif) no-repeat 50% 50%;}
+
+.ui-plus-default {background: url(images/888888_11x11_icon_plus.gif) no-repeat 50% 50%;}
+.ui-plus-default:hover, .ui-plus-hover {background: url(images/454545_11x11_icon_plus.gif) no-repeat 50% 50%;}
+.ui-plus-default:active, .ui-plus-active {background: url(images/222222_11x11_icon_plus.gif) no-repeat 50% 50%;}
+.ui-plus-content {background: url(images/222222_11x11_icon_plus.gif) no-repeat 50% 50%;}
+
+/*hidden elements*/
+.ui-hidden {
+ display: none;/* for accessible hiding: position: absolute; left: -99999999px*/;
+}
+.ui-accessible-hidden {
+ position: absolute; left: -99999999px;
+}
+/*reset styles*/
+.ui-reset {
+ /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none;
+}
+/*clearfix class*/
+.ui-clearfix:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+.ui-clearfix {display: inline-block;}
+/* Hides from IE-mac \*/
+* html .ui-clearfix {height: 1%;}
+.ui-clearfix {display: block;}
+/* End hide from IE-mac */
+
+/* Note: for resizable styles, use the styles listed above in the dialog section */
+
+
diff --git a/moksha/widgets/jquery_ui_theme.py b/moksha/widgets/jquery_ui_theme.py
new file mode 100644
index 0000000..8afe29a
--- /dev/null
+++ b/moksha/widgets/jquery_ui_theme.py
@@ -0,0 +1,5 @@
+from tw.api import Widget, CSSLink
+
+class JQueryUITheme(Widget):
+ css = [CSSLink(link='/css/jquery-ui/ui.theme.css', modname=__name__)]
+ template = ''
diff --git a/moksha/widgets/misc/__init__.py b/moksha/widgets/misc/__init__.py
new file mode 100644
index 0000000..e69de29
commit 8d1427ccd3964b612a4cd4e7a856580b2d82567d
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:24:00 2009 -0500
Some setup.py changes to point to the newly create tw.jquery.ui modules
diff --git a/setup.py b/setup.py
index 5892dcd..aeabf48 100644
--- a/setup.py
+++ b/setup.py
@@ -61,6 +61,7 @@ setup(
chat = moksha.api.widgets.chat:LiveChatWidget
#livegraph = moksha.examples.livegraph:LiveGraphWidget
#grid = moksha.api.widgets:Grid
+ ptd = moksha.widgets.misc.ptd:ProcessedTowerDefense
[moksha.global]
# The pipeline for our live widgets
@@ -68,13 +69,16 @@ setup(
orbited = moksha.api.widgets.orbited:orbited_js
jquery = tw.jquery:jquery_js
- jquery_ui_core = moksha.widgets.container:ui_core_js
- jquery_ui_draggable = moksha.widgets.container:ui_draggable_js
- jquery_ui_resizable = moksha.widgets.container:ui_resizable_js
+ jquery_ui_core = tw.jquery.ui:ui_core_js
+ jquery_ui_draggable = tw.jquery.ui:ui_draggable_min_js
+ jquery_ui_resizable = tw.jquery.ui:ui_resizable_min_js
+ #jquery_ui_dialog = tw.jquery.ui:ui_dialog_min_js
#jquery_ui_tabs = tw.jquery.ui_tabs:jquery_ui_tabs_js
#jquery_json_js = fedoracommunity.widgets:jquery_json_js
#jquery_template_js = fedoracommunity.widgets:jquery_template_js
+ #jquery_ui_css = moksha.widgets.jquery_ui_theme:JQueryUITheme
+
# Enable support for the Blueprint CSS framework
blueprint_ie_css = moksha.widgets.blueprint:blueprint_ie_css
blueprint_screen_css = moksha.widgets.blueprint:blueprint_screen_css
@@ -83,6 +87,8 @@ setup(
# Blueprint plugins
blueprint_fancytype_css = moksha.widgets.blueprint:blueprint_plugin_fancytype_css
+ konami_js = moksha.widgets.misc.ptd:konami
+
[moksha.menu]
default_menu = moksha.api.menus:MokshaDefaultMenu
contextual_menu = moksha.api.menus:MokshaContextMenu
commit 560220e7dbad507bf44b0bcd863fbf98390ade81
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:23:36 2009 -0500
Minor formatting / comment
diff --git a/moksha/templates/index.mak b/moksha/templates/index.mak
index c71eac8..3aa1ecc 100644
--- a/moksha/templates/index.mak
+++ b/moksha/templates/index.mak
@@ -18,7 +18,6 @@
## Left sidebar
</div>
<div class="span-16">
-
## Main content
<div id="content"></div>
</div>
@@ -26,7 +25,6 @@
## Right sidebar
</div>
<hr class="space">
- <hr class="space">
${footer()}
</div>
</a>
@@ -34,6 +32,7 @@
## Inject our global resources
${tmpl_context.moksha_global_resources()}
+ ## Setup our right-click contextual menu
${tmpl_context.contextual_menu_widget()}
</body>
commit 67b1635a701d5aa17f356705a5dfa29a02866175
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:23:14 2009 -0500
Give our footer an id
diff --git a/moksha/templates/footer.mak b/moksha/templates/footer.mak
index 81f2f39..b7f7fdf 100644
--- a/moksha/templates/footer.mak
+++ b/moksha/templates/footer.mak
@@ -1,6 +1,8 @@
<%def name="footer()">
+<div id="footer">
<br/> <br/> <br/> <br/>
<br/> <br/> <br/> <br/>
<br/> <br/> <br/> <br/>
<center><img src="/images/moksha-logo.png"/></center>
+</div>
</%def>
commit 1ac0a1dd8836804532703c1474c03261f0f7073f
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:22:43 2009 -0500
Improve our RootController.widgets method, making it much more simple.
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index 8a5a8b3..37fb643 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -18,8 +18,7 @@
import moksha
-from tg import (expose, flash, require, tmpl_context, redirect, validate,
- override_template)
+from tg import expose, flash, require, tmpl_context, redirect, validate
from tg.controllers import WSGIAppController
from repoze.what import predicates
@@ -43,17 +42,21 @@ class RootController(BaseController):
tmpl_context.contextual_menu_widget = moksha.menus['contextual_menu']
return dict(title='Moksha')
- @expose('mako:moksha.templates.widgetcontainer')
- def widgets(self, widget, chrome=True, **kw):
- tmpl_context.widget = moksha.get_widget(widget)
- if not chrome or not getattr(tmpl_context.widget, 'visible', True):
- override_template(self.widgets, 'mako:moksha.templates.widget')
- return dict(options={})
+ @expose('mako:moksha.templates.widget')
+ def widgets(self, widget, chrome=None, **kw):
+ options = {}
+ w = moksha._widgets.get(widget)
+ if not w:
+ raise WidgetNotFound(widget)
+ if chrome and getattr(w['widget'], 'visible', True):
+ tmpl_context.widget = container
+ options['content'] = w['widget']
+ options['title'] = w['name']
+ options['id'] = widget + '_container'
else:
- override_template(self.widgets, 'mako:moksha.templates.widgetcontainer')
- tmpl_context.container = container
- kw['id'] = widget + '_container'
- return dict(title=moksha._widgets[widget]['name'], container_options=kw)
+ tmpl_context.widget = w['widget']
+ options.update(kw)
+ return dict(options=options)
@expose('moksha.templates.login')
def login(self, **kw):
diff --git a/moksha/exc.py b/moksha/exc.py
index 1a5da11..152d9d2 100644
--- a/moksha/exc.py
+++ b/moksha/exc.py
@@ -22,3 +22,6 @@ class MokshaException(Exception):
class ApplicationNotFound(MokshaException):
pass
+
+class WidgetNotFound(MokshaException):
+ pass
commit f92194b3e49057e3bc61385881ced4ff246da963
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:20:40 2009 -0500
Update our default menu to append all widgets to the footer, to avoid the logo flicker
diff --git a/moksha/api/menus/default.py b/moksha/api/menus/default.py
index a420036..7d68bcf 100644
--- a/moksha/api/menus/default.py
+++ b/moksha/api/menus/default.py
@@ -54,9 +54,10 @@ class MokshaDefaultMenu(MokshaMenu):
</a>
"""
for id, widget in moksha._widgets.iteritems():
- menu += """
- <a href="#" onclick="$('<div/>').appendTo('#content').load('/widgets/%s'); return false;">%s</a>
- """ % (id, widget['name'])
+ if not getattr(widget['widget'], 'hidden', False):
+ menu += """
+ <a href="#" onclick="$('<div/>').appendTo('#footer').load('/widgets/%s?chrome=True'); return false;">%s</a>
+ """ % (id, widget['name'])
return menu
def moksha(self, *args, **kw):
commit 7678245d3c6bed35ba2e4558bf1ac4f887170f70
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 17:16:45 2009 -0500
Add an example processing.js towerdefense widget.
diff --git a/moksha/widgets/misc/ptd/LICENSE b/moksha/widgets/misc/ptd/LICENSE
new file mode 100644
index 0000000..772302f
--- /dev/null
+++ b/moksha/widgets/misc/ptd/LICENSE
@@ -0,0 +1,28 @@
+jQuery, jQuery.hotkeys, and processing.js have been released under the MIT License
+by their copyright holders.
+
+The code and markup of PTD itself are likewise released under the MIT License by
+their copyright holders.
+
+Files in the assets directory however are subject to other licenses. See
+assets/LICENSE
+
+The MIT License
+
+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,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/moksha/widgets/misc/ptd/__init__.py b/moksha/widgets/misc/ptd/__init__.py
new file mode 100644
index 0000000..27f4875
--- /dev/null
+++ b/moksha/widgets/misc/ptd/__init__.py
@@ -0,0 +1 @@
+from ptd import *
diff --git a/moksha/widgets/misc/ptd/game/creep_waves.js b/moksha/widgets/misc/ptd/game/creep_waves.js
new file mode 100644
index 0000000..aea8a01
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/creep_waves.js
@@ -0,0 +1,90 @@
+var CreepWaveController = function() {
+ var cwc = new Object();
+ Object.extend(cwc, InertDrawable);
+ cwc.delay = 25000;
+ cwc.last = millis()-20000;
+ cwc.wave = 1;
+ cwc.spawn_wave = function(bonus) {
+ WIDGETS.wave.innerHTML = this.wave;
+ var settings = {wave:this.wave, bonus:bonus};
+ var mixins = [];
+
+ var n = Math.random();
+ if (n < 0.1)
+ mixins.push(WaterAdverseMixin);
+ else if (n < 0.2)
+ mixins.push(WaterLovingMixin);
+ else if (n < 0.3)
+ mixins.push(MountainAdverseMixin);
+ else if (n < 0.4)
+ mixins.push(MountainLovingMixin);
+ else if (n < 0.5)
+ mixins.push(ImmuneMixin);
+ else if (n < 0.6)
+ mixins.push(FlyingMixin);
+
+ if (this.wave % 15 == 0) {
+ mixins.push(BossMixin);
+ settings.remaining = 1;
+ }
+ else if (this.wave % 5 == 0) mixins.push(StrongMixin);
+ else if (this.wave % 3 == 0) mixins.push(QuickMixin);
+
+ create_creep_wave_with_mixins(settings, mixins);
+
+ this.wave++;
+ cwc.last = SET.now;
+ };
+ cwc.update = function() {
+ if (SET.now - cwc.last > cwc.delay) {
+ this.spawn_wave();
+ }
+ }
+ assign_to_depth(cwc, SET.system_render_level);
+ return cwc;
+};
+
+var CreepWave = function(settings) {
+ var cw = new Object();
+ Object.extend(cw, InertDrawable);
+ cw.remaining = 20;
+ cw.wave = 1;
+ cw.last = 0;
+ cw.interval = 1000;
+ Object.extend(cw, settings);
+ cw.spawn_creep = function() { Creep(this.wave); };
+ cw.spawn = function() {
+ this.remaining--;
+ this.spawn_creep();
+ this.last = SET.now;
+ if (this.remaining < 1) {
+ this.is_dead = function() { return true; };
+ if (this.bonus)
+ SET.score += this.bonus;
+ }
+ }
+
+ cw.update = function() {
+ if (SET.now - this.last > this.interval) {
+ this.spawn();
+ }
+ }
+ assign_to_depth(cw, SET.system_render_level);
+ SET.creep_variety = "Normal Creeps";
+ return cw;
+};
+
+var create_creep_wave_with_mixins = function(settings, mixins) {
+ if (!mixins) mixins = [];
+ var cw = CreepWave(settings);
+ cw.knows_creep_variety = false;
+ cw.spawn_creep = function() {
+ var c = Creep(cw.wave);
+ mixins.forEach(function(mixin) { mixin(c); });
+ if (cw.knows_creep_variety == false) {
+ SET.creep_variety = c.creep_type + "s";
+ cw.knows_creep_variety = true;
+ }
+ }
+ return cw;
+}
diff --git a/moksha/widgets/misc/ptd/game/creeps.js b/moksha/widgets/misc/ptd/game/creeps.js
new file mode 100644
index 0000000..ecf3e86
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/creeps.js
@@ -0,0 +1,353 @@
+
+
+/*
+ Used in by the Creep method "display stats" to
+ support constantly updated hp for the specific
+ selected creep. Conceivably one might move into
+ another state immediately without transitioning
+ into normal state before that. Preferably some
+ kind of state cleanup function will be added to
+ the state API, but at the moment it will function
+ correctly anyway, because the creep div will either
+ be invisible, or the most recent creephpupdater
+ will be the last one called, meaning that the
+ correct hp will be displayed even if there are
+ multiple existing creephpupdaters in the
+ system rendering level.
+ */
+var CreepHpUpdater = function(creep) {
+ var chp = new Object();
+ Object.extend(chp, InertDrawable);
+ chp.update = function() {
+ WIDGETS.creep_hp.innerHTML = creep.hp;
+ }
+ chp.should_die = false;
+ chp.is_dead = function() {
+ if (chp.should_die || !creep || !SET.state || SET.state.name() != "CreepSelectMode" || creep.is_dead()) {
+ unselect();
+ if (chp.kz)
+ chp.kz.is_dead = function() { return true; };
+ return true;
+ }
+ else return false;
+ }
+ chp.draw = function() {
+ if (chp.kz) chp.kz.is_dead = function() { return true; };
+ chp.kz = KillZone(creep.x,creep.y,15);
+ }
+
+ assign_to_depth(chp, SET.system_render_level);
+ return chp;
+}
+
+
+/*
+ ### Types of creeps
+
+ Creeps interact with terrain in a variety of ways.
+ Some types of creeps will be much faster on certain
+ squares, and much slower on others. Some types will
+ be ignore towers and fly over them.
+
+ #### Terrain baseline (how a non-modified creep reacts
+ to certain types of terrain):
+
+ 1. Mountains: 3/4 speed.
+ 2. Water: 1/2 speed.
+ 3. Neutral: 1/1 speed.
+ 4. Power Plant: 2/1 speed.
+
+ #### Creep mixins
+
+ 1. FlyingMixin: ignore standard pathfinding, and go in a straight line to exit.
+ 2. WaterAdverseMixin: very slow walking through water.
+ 3. WaterLovingMixin: very quick walking in water.
+ 4. MoutainAdverseMixin: very slow crossing mountains.
+ 5. MountainLovingMixin: very quick crossing mountains.
+ 6. ImmuneMixin: ignores terrain effects completely.
+
+
+ ### Implementation
+
+ Each creep has an object named terrain, the keys of which
+ are the varying types of terrain. The value stored for each
+ key is a decimal which is used as a multiplier against the
+ creep's base speed in that type of terrain.
+
+ */
+
+/* Creep Mixins */
+
+var FlyingMixin = function(creep) {
+ creep.creep_type = "Flying " + creep.creep_type;
+ creep.terrain['water'] = 1.0;
+ creep.terrain['mountain'] = 1.0;
+ creep.ignores_towers = true;
+ return creep;
+}
+
+var WaterAdverseMixin = function(creep) {
+ creep.terrain['water'] = 0.25;
+ creep.creep_type = "Water-Hating " + creep.creep_type;
+ return creep;
+}
+
+var WaterLovingMixin = function(creep) {
+ creep.terrain['water'] = 2.0;
+creep.creep_type = "Water-Loving " + creep.creep_type;
+ return creep;
+}
+
+var MountainAdverseMixin = function(creep) {
+ creep.terrain['mountain'] = 0.25;
+creep.creep_type = "Mountain-Hating " + creep.creep_type;
+ return creep;
+}
+
+var MountainLovingMixin = function(creep) {
+ creep.terrain['mountain'] = 1.25;
+creep.creep_type = "Mountain-Loving " + creep.creep_type;
+ return creep;
+}
+
+var ImmuneMixin = function(creep) {
+ creep.terrain['mountain'] = 1.0;
+ creep.terrain['neutral'] = 1.0;
+ creep.terrain['water'] = 1.0;
+ creep.terrain['mountain'] = 1.0;
+ creep.terrain['power plant'] = 1.0;
+ creep.creep_type = "Immune " + creep.creep_type;
+ return creep;
+}
+
+var StrongMixin = function(creep) {
+ creep.color = color(0,255,255);
+ creep.size = creep.size * 1.3;
+ creep.hp = Math.floor(creep.hp * 2);
+ creep.value = Math.floor(creep.value * 1.5);
+ creep.creep_type = "Strong " + creep.creep_type;
+ return creep;
+}
+
+var QuickMixin = function(creep) {
+ creep.creep_type = "Quick " + creep.creep_type;
+ creep.color = color(200,150,50);
+ creep.speed = creep.speed * 1.5;
+ creep.hp = Math.floor(creep.hp * .75);
+ creep.size = creep.size * 0.9;
+ creep.value = Math.floor(creep.value * 1.25);
+ return creep;
+}
+
+var BossMixin = function(creep) {
+ creep.creep_type = "Boss " + creep.creep_type;
+ creep.color = color(255,100,150);
+ creep.size = creep.size * 1.5;
+ creep.hp = Math.floor(creep.hp * 10);
+ creep.value = Math.floor(creep.value * 20);
+ return creep;
+}
+
+var Creep = function(wave) {
+ var cp = SET.creeps_spawned;
+ var c = new Object();
+ c.terrain = {"entrance":1.0,"exit":1.0,"mountain":0.75,"water":0.5,"neutral":1.0,"power plant":2.0};
+
+ c.x = SET.entrance.x_mid;
+ c.y = SET.entrance.y_mid;
+ c.color = SET.creep_color;
+ c.size = SET.creep_size;
+ c.hp = Math.floor(SET.creep_hp * Math.pow(1.4,wave));
+ c.value = SET.creep_value + wave;
+ c.speed = SET.creep_speed;
+ c.last = millis();
+ c.is_dead = function() {
+ if (this.hp <= 0) {
+ SET.gold += this.value;
+ SET.score += this.value;
+ return true;
+ }
+ return false;
+ }
+ c.terrain_modified_speed = function() {
+ var terrain = get_terrain_at(this.gx,this.gy);
+ if (terrain) {
+ var terrain_type = terrain.type;
+ var terrain_modifier = c.terrain[terrain_type];
+ }
+ else {
+ var terrain_modifier = 1.0;
+ }
+ return c.speed * terrain_modifier;
+ }
+
+ c.ignores_towers = false;
+
+ c.update = function() {
+ var gpos = pixel_to_grid(this);
+ this.gx = gpos.gx;
+ this.gy = gpos.gy;
+ // if it reaches the exit, kill it, but reduce the players
+ // lives and reduce its value to 0 (it will be collected
+ // and destroyed in the is_dead phase.
+ if (this.gx == SET.exit.gx && this.gy == SET.exit.gy) {
+ this.hp = -1;
+ this.value = 0;
+ SET.lives--;
+ if (SET.lives < 1) game_lost();
+ }
+ else if(!this.ignores_towers) {
+ var elapsed = SET.now - this.last;
+ var terrain_modified_speed = this.terrain_modified_speed();
+ var speed = (elapsed/1000) * terrain_modified_speed;
+ this.last = SET.now;
+
+ var next_block = pathfind(gpos);
+ if (next_block == undefined){
+ game_lost();
+ error("Pathfinding failed. Erroring hard so that we catch these bugs.");
+ log("creep",this);
+ return;
+ }
+
+ var coords = center_of_square(next_block.gx, next_block.gy)
+ move_towards(this,this.x,this.y,coords.x,coords.y,speed);
+ }
+ else if (this.ignores_towers) {
+ var elapsed = SET.now - this.last;
+ var terrain_modified_speed = this.terrain_modified_speed();
+ var speed = (elapsed/1000) * terrain_modified_speed;
+ move_towards(this, this.x,this.y,SET.exit.x_mid,SET.exit.y_mid,speed)
+ this.last = SET.now;
+ }
+ }
+ c.draw = function() {
+ noStroke();
+ fill(this.color);
+ ellipse(this.x,this.y,this.size,this.size);
+ }
+ c.creep_type = "Normal Creep";
+ c.display_stats = function() {
+ WIDGETS.creep_type.innerHTML = this.creep_type;
+ WIDGETS.creep_hp.innerHTML = this.hp;
+ WIDGETS.creep_value.innerHTML = this.value + " gold";
+ WIDGETS.creep.style.display = "block";
+ }
+ SET.creeps_spawned++;
+ assign_to_depth(c, SET.creep_render_level);
+ return c;
+};
+
+
+
+
+/* pathfinding */
+
+var known_best_paths = undefined;
+var reset_pathfinding = function(new_value) {
+ if (new_value == undefined){
+ var coords = [SET.exit.gx, SET.exit.gy];
+ new_value = {};
+ SET.grid_cache_reset_all_values_for_key("valid_tower_location");
+ new_value[coords] = {}; //The actual value doesn't really matter
+ }
+ var previous = known_best_paths;
+ known_best_paths = new_value;
+ return previous;
+}
+
+//Could a creep occupy this square?
+var valid_path_location = function(gx, gy) {
+ //out of bounds
+ if (gx < 0 || gy < 0) return false;
+ if (gx >= SET.gwidth || gy >= SET.gheight) return false;
+ //a tower is present
+ if (get_tower_at(gx,gy) != false)
+ return false;
+ //a hypothetical tower is present (when selecting a space for a new tower)
+ if (SET.considering_location && SET.considering_location.gx == gx && SET.considering_location.gy == gy)
+ return false;
+ return true;
+}
+
+var pathfind = function(start_block) {
+// log("pathfinding [from, to]", [start_block, SET.exit]);
+ if ([start_block.gx, start_block.gy] in known_best_paths) {
+// log("path found from cache", start_block);
+ return known_best_paths[[start_block.gx, start_block.gy]].next_block.gpos;
+ }
+
+
+ var successors = function(block) {
+ var candidates = [];
+ var normal_dist = 10;
+ [[0,1],[1,0],[-1,0],[0,-1]].forEach(function(pair) {
+ var gpos = {gx:block.gpos.gx + pair[0], gy: block.gpos.gy + pair[1], dist:normal_dist};
+ if (valid_path_location(gpos.gx, gpos.gy))
+ candidates.push(gpos);
+ });
+
+ var diag_dist = 14; //sqrt(2) * 10
+ [[1,1],[-1,-1],[1,-1],[-1,1]].forEach(function(pair){
+ var gpos = {gx:block.gpos.gx + pair[0], gy: block.gpos.gy + pair[1], dist:diag_dist};
+ if (valid_path_location(gpos.gx, gpos.gy) && valid_path_location(block.gpos.gx, gpos.gy) && valid_path_location(gpos.gx, block.gpos.gy))
+ candidates.push(gpos);
+ })
+ return candidates;
+ }
+
+
+ //Heuristic assumes that we move at a 45˚ angle until we've got a
+ //horizontal or vertical path to the goal, then we move straight
+ //to the goal. This is the actual behavior when there are no obstructions.
+ var heuristic = function(gpos) {
+ var dx = Math.abs(gpos.gx - SET.exit.gx);
+ var dy = Math.abs(gpos.gy - SET.exit.gy);
+ var dist = Math.min(dx,dy) * 14;
+ dist += (Math.max(dx,dy) - Math.min(dx,dy)) * 10
+ return dist
+ }
+
+
+ var closed = {};
+ var pqueue = [{gpos:start_block, f:heuristic(start_block), g:0}];
+ while (pqueue.length > 0) {
+ var block = pqueue[0];
+ pqueue = pqueue.slice(1);
+// log("looking at", block)
+ if (closed[[block.gpos.gx, block.gpos.gy]] == true){
+// log("in closed, skipping", closed)
+ continue;
+ }
+ if ([block.gpos.gx, block.gpos.gy] in known_best_paths){
+ //logging:
+// rpath = [];
+
+ while ("ancestor" in block) {
+ block.ancestor.next_block = block;
+ known_best_paths[[block.ancestor.gpos.gx, block.ancestor.gpos.gy]] = block.ancestor
+// rpath.push({gx:block.gx, gy:block.gy});
+ block = block.ancestor;
+ }
+// rpath.push({gx:block.gx, gy:block.gy});
+// rpath.reverse();
+// log("known_best_paths", known_best_paths);
+ var result = known_best_paths[[start_block.gx, start_block.gy]].next_block.gpos;
+// log("path found!", rpath);
+ return result;
+ }
+ closed[[block.gpos.gx, block.gpos.gy]] = true;
+// log("closed", closed);
+ successors(block).forEach(function(s) {
+ var suc = {gpos:s, g:s.dist + block.g, ancestor:block};
+ suc.f = suc.g + heuristic(suc.gpos);
+
+ pqueue = insert_sorted(pqueue, suc, function(bl) {
+ return bl.f
+ });
+ })
+
+// log("pqueue", pqueue);
+ }
+// log("---------pathfinding failed!----------");
+}
diff --git a/moksha/widgets/misc/ptd/game/ptd.js b/moksha/widgets/misc/ptd/game/ptd.js
new file mode 100644
index 0000000..e3a7180
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/ptd.js
@@ -0,0 +1,460 @@
+/*
+Processed Tower Defense by Will Larson lethain(a)gmail.com
+
+### Processed Tower Defense
+
+PTD is a simple game I decided to make to get used to
+the Processing.js library, and also to consider the
+feasibility of writing Processing-like code, but
+using Javascript instead of Java 1.3 style syntax for
+all control code.
+
+I began prototyping the game, the first game I had
+tried developing, and I got fairly far but realized
+that my lack of knowledge about games had led me to
+make some organizational mistakes that were making
+the code increasingly incoherent and piecemeally.
+So, I decided to rewrite the code to be clearer,
+with the hope that it might serve as an useful
+example for others.
+*/
+
+/*
+ Object life cycle.
+ */
+
+// assign @obj to render at @depth until it dies.
+// 0 is the topmost layer, and thus something at
+// layer 1 will render before something at layer 0.
+// Something at layer 10 will render before something
+// at layer 4, and so on. This means that something
+// rendered at layer 0 will draw itself ontop of anything
+// rendered before layer 0.
+var assign_to_depth = function(obj,depth) {
+ var rendering_group = SET.rendering_groups[depth];
+ if (rendering_group == undefined) SET.rendering_groups[depth] = [obj];
+ else rendering_group.push(obj);
+}
+
+// updates any groups
+var update_groups = function(groups) {
+ var obj_update = function(x) {
+ if (x != undefined) x.update();
+ };
+ var obj_is_alive = function(x) {
+ if ( x == undefined || x.is_dead()) return false;
+ return true;
+ };
+ var obj_draw = function(x) { x.draw(); };
+ for (var i=groups.length-1;i>=0;i--) {
+ var group = groups[i];
+ if (group != undefined) {
+ group.forEach(obj_update);
+ var alive = group.filter(obj_is_alive);
+ alive.forEach(obj_draw);
+ groups[i] = alive;
+ }
+ }
+}
+
+/*
+ Configuration & settings.
+ */
+
+var default_set = function() {
+ var set = {};
+
+ // constants
+ set.pixels_per_square = 25;
+ set.half_pixels_per_square = (1.0 * set.pixels_per_square) / 2;
+ set.height = 450;
+ set.width = 600;
+ set.framerate = 60;
+ set.gheight = Math.floor(set.height / set.pixels_per_square);
+ set.gwidth = Math.floor(set.width / set.pixels_per_square);
+
+ /*
+ ### Grid Cache
+
+ This is a place to store any data that should be associated
+ with a specific grid square. For example, each grid square
+ will have the Terrain occupying it stored there, and a grid
+ square's tower could be retrieved this way as well.
+
+ ### Using the Grid Cache
+
+ The Grid Cache is, as it is named, intended to be
+ used as a cache. This means it shouldn't be relied upon as the
+ definitive answer to a question, but should be used to store
+ answers to frequently answered questions.
+
+ For example, the find_tower_at(gx,gy) method is used to find
+ any towers existing at (gx,gy). That method should first check
+ the cache for a key of 'tower', and use it if it exists, but
+ should be able to find the tower without the cache as well
+ (by scanning through all towers looking for the correct
+ one).
+
+ ### Invalidating Entries in Grid Cache
+
+ Entries in the Grid Cache will be cleared out each time the
+ game is reset, and beyond that invalidating of key/value pairs
+ must be done manually.
+
+ For example, upon selling a tower the value of the tower stored
+ in the cache should be extinguished.
+ */
+ set.grid_cache = {};
+
+
+ set.grid_cache_at = function(gx,gy) {
+ var gx_cache = set.grid_cache[gx];
+ if (!gx_cache) {
+ gx_cache = {};
+ set.grid_cache[gx] = gx_cache;
+ }
+ var gy_cache = gx_cache[gy];
+ if (!gy_cache) {
+ gy_cache = {};
+ gx_cache[gy] = gy_cache;
+ }
+ return gy_cache;
+ }
+
+ set.grid_cache_reset_all_values_for_key = function(key) {
+ for(gx in set.grid_cache) {
+ for (gy in set.grid_cache[gx]) {
+ delete set.grid_cache[gx][gy][key];
+ }
+ }
+ }
+
+ // colors
+ set.bg_colors = {neutral:color(90,80,70),
+ positive:color(60,80,250),
+ negative:color(250,80,60)};
+ set.bg_color = set.bg_colors.neutral;
+ set.grid_color = color(255,255,255);
+ set.entrance_color = color(100,255,100);
+ set.exit_color = color(255,100,50);
+ set.killzone_color = color(200,50,50,0.5);
+ set.creep_color = color(255,255,0);
+
+ // rendering groups
+ set.rendering_groups = [];
+ for (var i=0; i <= 7; i++) set.rendering_groups.push([]);
+ set.system_render_level = 7;
+ set.square_render_level = 6;
+ set.killzone_render_level = 5;
+ set.grid_render_level = 4;
+ set.tower_render_level = 3;
+ set.build_zone_render_level = 2;
+ set.creep_render_level = 1;
+ set.bullet_render_level = 0;
+
+ // game state
+ set.state = undefined;
+
+ // game values
+ set.creep_variety = "Normal Creeps";
+ set.creep_size = 10;
+ set.creep_hp = 10;
+ set.creep_value = 1;
+ set.creep_speed = 50;
+ set.missile_blast_radius = 5;
+ set.missile_damage = 100;
+ set.gold = 200;
+ set.creeps_spawned = 0;
+ set.max_creeps = 1;
+ set.score = 0;
+ set.lives = 20;
+ set.nukes = 3;
+ set.bomb_cost = 50;
+
+ return set
+};
+var SET;
+
+var fetch_ui_widgets = function() {
+ var w = {};
+ // status bar widgets
+ w.score = document.getElementById("score");
+ w.gold = document.getElementById("gold");
+ w.lives = document.getElementById("lives");
+ w.nukes_left = document.getElementById("nukes_left");
+ w.creep_variety = document.getElementById("creep_variety");
+ w.wave = document.getElementById("wave");
+ w.till_next_wave = document.getElementById("till_next_wave");
+ w.bomb_cost = document.getElementById("bomb_cost");
+
+ // tower widgets
+ w.tower = document.getElementById("tower");
+ w.tower_type = document.getElementById("tower_type");
+ w.tower_range = document.getElementById("tower_range");
+ w.tower_damage = document.getElementById("tower_damage");
+ w.tower_rate = document.getElementById("tower_rate");
+ w.tower_upgrade_button = document.getElementById("tower_upgrade_button");
+ w.tower_sell_button = document.getElementById("tower_sell_button");
+
+ // creep widgets
+ w.creep = document.getElementById("creep");
+ w.creep_type = document.getElementById("creep_type");
+ w.creep_hp = document.getElementById("creep_hp");
+ w.creep_value = document.getElementById("creep_value");
+
+ return w;
+};
+var WIDGETS;
+
+/*
+ Drawable objects (grid, towers, creeps, everything).
+ */
+
+// prototype for grid lines and colored squares
+var InertDrawable = new Object();
+Object.extend(InertDrawable, {
+ update:function() {},
+ is_dead:function() { return false; },
+ draw:function() {}
+ });
+
+
+// responsible for updating settings in SET
+// at the very beginning of a rendering cycle
+var SettingUpdater = function() {
+ var su = new Object();
+ Object.extend(su, InertDrawable);
+ su.update = function() { SET.now = millis(); }
+ assign_to_depth(su, SET.system_render_level);
+ return su;
+};
+
+var UIUpdater = function() {
+ var uiu = new Object();
+ Object.extend(uiu, InertDrawable);
+
+ uiu.update = function() {
+ WIDGETS.creep_variety.innerHTML = SET.creep_variety;
+ WIDGETS.score.innerHTML = SET.score;
+ WIDGETS.gold.innerHTML = SET.gold;
+ WIDGETS.lives.innerHTML = SET.lives;
+ WIDGETS.nukes_left.innerHTML = SET.nukes + " left";
+ WIDGETS.till_next_wave.innerHTML = Math.floor(((SET.creep_wave_controller.last + SET.creep_wave_controller.delay) - SET.now) / 1000)
+ };
+ assign_to_depth(uiu, SET.system_render_level);
+ return uiu;
+}
+
+
+var Grid = function() {
+ var grid = new Object();
+ Object.extend(grid, InertDrawable);
+ grid.draw = function() {
+ stroke(SET.grid_color);
+ var p = SET.pixels_per_square;
+ var w = SET.width;
+ var h = SET.height;
+ for (i = 0; i<w; i+=p) {
+ line(i, 0, i, h);
+ }
+ for (i = 0; i<h; i+=p) {
+ line(0,i,w,i);
+ }
+ };
+ assign_to_depth(grid, SET.grid_render_level);
+ return grid;
+};
+
+
+var GridSquare = function(gx,gy,color) {
+ var square = new Object();
+ Object.extend(square, InertDrawable);
+ square.gx = gx;
+ square.gy = gy;
+ square.x = grid_to_pixel(gx);
+ square.y = grid_to_pixel(gy);
+ var mid = center_of_square(gx,gy);
+ square.x_mid = mid.x;
+ square.y_mid = mid.y;
+ return square;
+}
+
+var Square = function(gx,gy,color) {
+ var square = GridSquare(gx,gy,color);
+ square.color = color;
+ square.draw = function() {
+ noStroke();
+ fill(this.color);
+ draw_square_in_grid(this.gx,this.gy);
+ }
+ assign_to_depth(square, SET.square_render_level);
+ return square;
+};
+var ExitSquare = function(gx,gy) {
+ var square = Square(gx,gy,SET.exit_color);
+ square.type = "exit";
+ square.draw = function() {
+ noStroke();
+ fill(SET.exit_color);
+ draw_square_in_grid(this.gx,this.gy);
+ noFill();
+ stroke("black");
+ draw_circle_in_grid(this.gx,this.gy);
+ }
+ return square;
+}
+
+
+var spawn_wave = function() {
+ if (!SET.state ||
+ (SET.state.name() != "GameOverMode" &&
+ SET.state.name() != "PauseMode")) {
+ //a bonus for bravery, to be paid when the creep wave thus spawned is done
+ var bonus = Math.floor(((SET.creep_wave_controller.last + SET.creep_wave_controller.delay) - SET.now) / 100);
+ SET.creep_wave_controller.spawn_wave(bonus);
+ }
+}
+
+var nuke_creeps = function() {
+ if (SET.nukes > 0) {
+ var creeps = SET.rendering_groups[SET.creep_render_level];
+ creeps.forEach(function(x) {
+ x.hp = -1;
+ x.value = 0; // no gold for nuked creeps
+ });
+ play_sound("nuke");
+ SET.nukes--;
+ }
+ else {error("You're all out of nukes!")}
+};
+
+
+var pause_resume = function() {
+ if (SET.state) {
+ var state_name = SET.state.name();
+ if (state_name == "GameOverMode")
+ ;
+ else if (state_name == "PauseMode") {
+ unselect();
+ }
+ else {
+ unselect();
+ SET.state = new PauseMode();
+ SET.state.set_up();
+ }
+ }
+ else {
+ SET.state = new PauseMode();
+ SET.state.set_up();
+ }
+};
+
+var game_lost = function() {
+ unselect();
+ attempt_to_enter_ui_mode(new GameOverMode());
+}
+
+/*
+ Game level functions. Starting, resetting, etc.
+ */
+
+var generate_map = function() {
+ SET.entrance = Square(0, random(SET.gheight-1), SET.entrance_color);
+ SET.entrance.type = "entrance";
+ SET.exit = ExitSquare(SET.gwidth-1, random(SET.gheight-1));
+ populate_terrains();
+}
+
+var reset_game = function() {
+ SET = default_set();
+ WIDGETS = fetch_ui_widgets();
+ WIDGETS.bomb_cost.innerHTML = SET.bomb_cost;
+ SettingUpdater();
+ UIUpdater();
+ //Grid();
+ generate_map();
+ SET.creep_wave_controller = CreepWaveController();
+ reset_pathfinding();
+ $('').trigger("game_over",false);
+};
+
+/*
+ Mouse functions.
+ */
+
+var on_mouse_moved = function() {
+ if (SET.state && SET.state.draw) {
+ var pos = mouse_pos();
+ SET.state.draw(pos.x,pos.y);
+ }
+};
+
+// user-interface modes that can be entered by clicking within
+// the game canvas (i.e. this does not include states reached
+// by clicking an html button)
+var UI_MODES_FROM_CLICK = [TowerSelectMode, CreepSelectMode];
+
+var on_mouse_press = function() {
+ var pos = mouse_pos();
+ if (SET.state) {
+ if (SET.state.is_legal(pos.x,pos.y)) {
+ SET.state.action(pos.x,pos.y);
+ }
+ if (SET.state.can_leave_mode(pos.x,pos.y)) {
+ unselect();
+ }
+ }
+ if (!SET.state) {
+ var len = UI_MODES_FROM_CLICK.length;
+ for (var i=0;i<len;i++) {
+ var modeFunc = UI_MODES_FROM_CLICK[i];
+ var mode = new modeFunc();
+ if (mode.can_enter_mode(pos.x,pos.y)) {
+ SET.state = mode;
+ SET.state.set_up(pos.x,pos.y);
+ break;
+ }
+ }
+ }
+}
+
+
+var message = function(msg) {
+ $('').trigger("message", msg);
+}
+
+var unselect = function() {
+ if (SET.state) SET.state.tear_down();
+ SET.state = undefined;
+ $('').trigger("no_mode");
+}
+
+var error = function(msg) {
+ $('').trigger("error", msg);
+}
+
+/*
+ Main game loop.
+ */
+
+var start_tower_defense = function() {
+ setup = function() {
+ $('#pause_button').html("Pause");
+ set_canvas("tower_defense");
+ reset_game();
+ size(SET.width, SET.height);
+ frameRate(SET.framerate);
+ mouseMoved(on_mouse_moved);
+ mousePressed(on_mouse_press);
+ initProcessing();
+ }
+ draw = function() {
+ if (SET.state) {
+ var state_name = SET.state.name();
+ if (state_name == "GameOverMode" || state_name == "PauseMode") return
+ }
+ background(SET.bg_color);
+ update_groups(SET.rendering_groups);
+ }
+ setup();
+}
diff --git a/moksha/widgets/misc/ptd/game/terrain.js b/moksha/widgets/misc/ptd/game/terrain.js
new file mode 100644
index 0000000..70327cf
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/terrain.js
@@ -0,0 +1,79 @@
+
+/* File to contain Terrain implementation. */
+
+var NeutralTerrain = function(gx,gy) {
+ var terrain_color = color(200,200,200);
+ var t = Square(gx,gy,terrain_color);
+ t.type = "neutral";
+ t.tower_range_modifier = 1.0;
+ t.tower_damage_modifier = 1.0;
+ t.tower_frequency_modifier = 1.0;
+ return t;
+}
+
+var WaterTerrain = function(gx,gy) {
+ var t = NeutralTerrain(gx,gy);
+ t.color = color(78,150,236);
+ t.type = "water";
+ return t;
+}
+
+var MountainTerrain = function(gx,gy) {
+ var t = NeutralTerrain(gx,gy);
+ t.color = color(228,51,51);
+ t.type = "mountain";
+ t.tower_range_modifier = 1.25;
+ return t;
+}
+
+var PowerPlantTerrain = function(gx,gy) {
+ var t = NeutralTerrain(gx,gy);
+ t.color = color(189,194,78);
+ t.type = "power plant";
+ t.tower_damage_modifier = 2.0;
+ return t;
+}
+
+var populate_terrains = function() {
+ var p_mountains = SET.terrain_percent_mountains || 0.05;
+ var p_water = SET.terrain_percent_water || 0.1;
+ var p_power_plant = SET.terrain_percent_power_plant || 0.01;
+ // remainder is neutral terrain
+
+ var range_mountain = p_mountains;
+ var range_water = p_mountains + p_water;
+ var range_power_plant = p_power_plant + range_water;
+ // remainder is neutral terrain
+
+ var entrance = SET.entrance;
+ var exit = SET.exit;
+ var gwidth = SET.gwidth;
+ var gheight = SET.gheight;
+
+ // column with entrance & exit squares
+ // are all neutral terrain
+ for (var gy=0; gy<gheight; gy++) {
+ if ( gy != entrance.gy ) {
+ NeutralTerrain(0,gy);
+ }
+ if ( gy != exit.gy ) {
+ NeutralTerrain(gwidth-1,gy);
+ }
+ }
+
+ for (var gx=1; gx<gwidth-1; gx++) {
+ for (var gy=0; gy<gheight; gy++) {
+ var n = Math.random();
+ if (n <= range_mountain)
+ MountainTerrain(gx,gy);
+ else if (n <= range_water)
+ WaterTerrain(gx,gy);
+ else if (n <= range_power_plant)
+ PowerPlantTerrain(gx,gy);
+ else
+ NeutralTerrain(gx,gy);
+ }
+ }
+
+
+}
diff --git a/moksha/widgets/misc/ptd/game/ui_modes.js b/moksha/widgets/misc/ptd/game/ui_modes.js
new file mode 100644
index 0000000..f187598
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/ui_modes.js
@@ -0,0 +1,346 @@
+/*
+ User-interface functions.
+ */
+
+var UserInterfaceMode = function() {
+ this.action = function(x,y) {
+ // called when the mouse is clicked, if is_legal
+ };
+ this.is_legal = function(x,y) {
+ // returns true,false or undefined.
+ // if true, then the UI mode's action can be undertaken
+ // at @x, @y. If false, then it cannot be undertaken.
+ // Otherwise, the UI has no concept of legality.
+ // The distinction between undefined and true lies in
+ // visual cues presented to the user.
+ return undefined;
+ };
+ this.draw = function(x,y) {
+ // draw any relevant graphics at the mouse's location
+ };
+ this.set_up = function() {
+ // do any setup before entering the UI mode
+ };
+ this.tear_down = function() {
+ // perform any clean up before exiting the UI mode.
+ };
+ this.can_leave_mode = function(x,y) {
+ // used to check if the the UI mode can be left
+ return true;
+ };
+ this.can_enter_mode = function(x,y) {
+ // used for checking if a UI can be invoked
+ return true;
+ };
+ this.name = function() {
+ return "UserInterfaceMode";
+ };
+};
+
+var attempt_to_enter_ui_mode = function(mode, error_msg) {
+ /*
+ This is only necessary for button based UI modes. This
+ logic is already handled for UI modes invoked by mouse
+ clicks in the game canvas.
+ */
+ if (!SET.state || SET.state.can_leave_mode()) {
+ unselect();
+ if (mode.can_enter_mode()) {
+ SET.state = mode;
+ var pos = mouse_pos();
+ SET.state.set_up(pos.x,pos.y);
+ }
+ else if (!error_msg)
+ {error("Not enough gold, you need at least " + mode.cost)};
+ }
+};
+
+var BuildTowerMode = function() {
+ var is_blocking_paths = function(gpos) {
+ //if the proposed tower isn't along any known path, it's not in
+ //the way
+ pathfind({gx:SET.entrance.gx, gy:SET.entrance.gy});
+ if (!([gpos.gx,gpos.gy] in known_best_paths)) {
+ var safe = true;
+// log("looking at diagonals of",gpos);
+ [[1,1],[-1,-1],[1,-1],[-1,1]].forEach(function(pair) {
+// log("diagonal",{gx:gpos.gx + pair[0], gy:gpos.gy + pair[1]});
+ if (!valid_path_location(gpos.gx + pair[0], gpos.gy + pair[1])){
+// log("diagonal disqualified from free is_blocking call",gpos);
+ safe = false;
+ }
+ });
+ if (safe)
+ return true;
+ }
+
+// log("pathfinding on behaf of", gpos);
+
+ //check that we can pathfind from the entrance
+ //to the exit, and from each creep to the exit
+ SET.considering_location = gpos;
+ var previous_pathfinding = reset_pathfinding();
+ var valid = pathfind({gx:SET.entrance.gx, gy:SET.entrance.gy});
+ var creeps = SET.rendering_groups[SET.creep_render_level];
+ creeps.forEach(function(creep){
+ valid = valid && pathfind(pixel_to_grid(creep));
+ });
+ SET.considering_location = undefined;
+ reset_pathfinding(previous_pathfinding);
+ if (!valid)
+ return false;
+ return true;
+ }
+
+ this.is_legal = function(x,y) {
+ var gpos = pixel_to_grid(x,y);
+ if (can_build_here(gpos.gx,gpos.gy) == false) return false;
+
+ var cache = SET.grid_cache_at(gpos.gx, gpos.gy);
+ if (cache["valid_tower_location"] == undefined){
+// log("grid grid miss");
+ cache["valid_tower_location"] = is_blocking_paths(gpos);
+// log("placing tower ok?", cache["valid_tower_location"]);
+ }
+// else log("in grid cache");
+
+ return cache["valid_tower_location"];
+ };
+ this.draw = function(x,y) {
+ var gpos = pixel_to_grid(x,y);
+ var mid = center_of_square(gpos);
+ var radius = SET.half_pixels_per_square;
+ if (this.br)
+ this.br.is_dead = function() { return true; }
+ this.br = BuildRadius(mid.x,mid.y,radius);
+ if (this.is_legal(x,y))
+ this.br.color = SET.bg_colors.positive;
+ else
+ this.br.color = SET.bg_colors.negative;
+
+ };
+ this.set_up = function(x,y) {
+ this.draw(x,y);
+ $('').trigger(this.name());
+ };
+ this.tear_down = function() {
+ if (this.br) {
+ this.br.is_dead = function() { return true; };
+ }
+ };
+ this.action = function(x,y) {
+ var gpos = pixel_to_grid(x,y);
+ this.tower(gpos.gx,gpos.gy);
+ SET.gold -= this.cost;
+ reset_pathfinding();
+ };
+ this.can_enter_mode = function(x,y) {
+ if (SET.gold >= this.cost) return true;
+ else return false;
+ };
+ this.can_leave_mode = function() {
+ //if we don't have enough money, we can't keep building
+ if (SET.gold < this.cost) return true;
+ //remain in build mode if shift is held down
+ return !shift_down;
+ };
+ this.name = function() {
+ return "BuildTowerMode";
+ };
+};
+BuildTowerMode.prototype = new UserInterfaceMode();
+
+var BuildMissileTowerMode = function() {
+ this.cost = 100;
+ this.tower = MissileTower;
+ this.name = function() {
+ return "BuildMissileTowerMode";
+ };
+};
+BuildMissileTowerMode.prototype = new BuildTowerMode();
+
+
+var build_missile_tower = function() {
+ attempt_to_enter_ui_mode(new BuildMissileTowerMode());
+};
+
+var BuildCannonTowerMode = function() {
+ this.cost = 75;
+ this.tower = CannonTower;
+ this.name = function() {
+ return "BuildCannonTowerMode";
+ };
+};
+BuildCannonTowerMode.prototype = new BuildTowerMode();
+
+
+var build_cannon_tower = function() {
+ attempt_to_enter_ui_mode(new BuildCannonTowerMode());
+};
+
+var BuildLaserTowerMode = function() {
+ this.cost = 25;
+ this.tower = LaserTower;
+ this.name = function() {
+ return "BuildLaserTowerMode";
+ };
+};
+BuildLaserTowerMode.prototype = new BuildTowerMode();
+
+var build_laser_tower = function() {
+ attempt_to_enter_ui_mode(new BuildLaserTowerMode());
+};
+
+var BuildGatlingTowerMode = function() {
+ this.cost = 50;
+ this.tower = GatlingTower;
+ this.name = function() {
+ return "BuildGatlingTowerMode";
+ }
+};
+BuildGatlingTowerMode.prototype = new BuildTowerMode();
+
+var build_gatling_tower = function() {
+ attempt_to_enter_ui_mode(new BuildGatlingTowerMode());
+}
+
+
+/* TowerSelectMode */
+
+var TowerSelectMode = function() {
+ this.set_up = function(x,y) {
+ var gpos = pixel_to_grid(x,y);
+ this.tower = get_tower_at(gpos.gx,gpos.gy);
+ if (this.tower) {
+ this.tower.display_stats();
+ this.killzone = KillZone(this.tower.x_mid,
+ this.tower.y_mid,
+ this.tower.range*SET.pixels_per_square);
+ WIDGETS.tower.style.display = "block";
+ }
+ };
+ this.tear_down = function() {
+ WIDGETS.tower.style.display = "none";
+ if (this.killzone)
+ this.killzone.is_dead = function() { return true; };
+ };
+ this.can_enter_mode = function(x,y) {
+ var gpos = pixel_to_grid(x,y);
+ var tower = get_tower_at(gpos.gx,gpos.gy);
+ return (tower == false) ? false : true;
+ }
+
+};
+TowerSelectMode.prototype = new UserInterfaceMode();
+
+var select_tower = function() {
+ SET.state = new TowerSelectMode();
+};
+
+/* CreepSelectMode */
+
+var CreepSelectMode = function() {
+ this.set_up = function(x,y) {
+ this.creep = get_creep_nearest(x,y);
+ if (this.creep) {
+ this.creep.display_stats();
+ WIDGETS.creep.style.display = "block";
+ this.hp_updater = CreepHpUpdater(this.creep);
+ }
+ };
+ this.tear_down = function() {
+ WIDGETS.creep.style.display = "none";
+ if (this.hp_updater) {
+ this.hp_updater.should_die = true;
+ }
+ };
+ this.name = function() {
+ return "CreepSelectMode";
+ };
+};
+CreepSelectMode.prototype = new UserInterfaceMode();
+
+var select_creep = function() {
+ SET.state = CreepSelectMode();
+};
+
+/* AimBombMode */
+
+var AimBombMode = function() {
+ this.cost = SET.bomb_cost;
+ this.radius = SET.missile_blast_radius * SET.pixels_per_square * 1.0;
+ this.draw = function(x,y) {
+ if (this.mr) this.mr.is_dead = function() { return true; };
+ this.mr = MissileRadius(x,y,this.radius);
+ }
+ this.set_up = function(x,y) {
+ this.draw(x,y);
+ $('').trigger("AimBombMode");
+ }
+ this.tear_down = function() {
+ if (this.mr) this.mr.is_dead = function() { return true; };
+ }
+ this.can_enter_mode = function(x,y) {
+ if (SET.gold >= this.cost) return true;
+ else return false;
+ };
+ this.name = function() {
+ return "AimBombMode";
+ };
+ this.is_legal = function() { return true; };
+ this.action = function(x,y) {
+ var creeps = SET.rendering_groups[SET.creep_render_level];
+ var l = creeps.length;
+ var range = Math.floor(this.radius);
+ for (var i=0;i<l;i++) {
+ var creep = creeps[i];
+ var d = Math.floor(dist(x,y,creep.x,creep.y));
+ if (d <= range)
+ creep.hp = Math.floor(creep.hp / 2);
+ }
+ play_sound("bomb");
+ SET.gold -= this.cost;
+ var cost_increase = SET.bomb_cost * 0.25;
+ if (cost_increase < 25) cost_increase = 25;
+ SET.bomb_cost = Math.floor(SET.bomb_cost + cost_increase);
+ WIDGETS.bomb_cost.innerHTML = SET.bomb_cost;
+ }
+}
+AimBombMode.prototype = new UserInterfaceMode();
+
+var aim_bomb = function(x,y) {
+ attempt_to_enter_ui_mode(new AimBombMode());
+};
+
+var PauseMode = function() {
+ this.name = function() { return "PauseMode" };
+ this.can_leave_mode = function(x,y) {
+ return false;
+ };
+ this.set_up = function() {
+ this.began_at = millis();
+ $('').trigger("PauseMode");
+ }
+ this.tear_down = function() {
+ var elapsed = millis() - this.began_at;
+ SET.rendering_groups.forEach(function(group) {
+ group.forEach(function(member) {
+ if (member.last)
+ member.last += elapsed;
+ });
+ });
+ }
+ this.name = function() { return "PauseMode"; };
+};
+PauseMode.prototype = new UserInterfaceMode();
+
+var GameOverMode = function() {
+ this.set_up = function(x,y) {
+ SET.score += SET.gold;
+ SET.gold = 0;
+ $('').trigger("game_over",true);
+ }
+ this.name = function() { return "GameOverMode"; };
+ this.can_leave_mode = function(x,y) { return false; };
+};
+GameOverMode.prototype = new UserInterfaceMode();
diff --git a/moksha/widgets/misc/ptd/game/util.js b/moksha/widgets/misc/ptd/game/util.js
new file mode 100644
index 0000000..26a68a6
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/util.js
@@ -0,0 +1,264 @@
+/* Coordinate System
+
+There are two coordinate systems in effect that need
+to be taken into consideration. The first is the pixel
+coordinate system, and the second is a coordinate system
+formed by a grid of veritical and horizontal lines.
+The grid's size is determined by three settings.
+
+1. *pixels_per_square* determines the number of pixels per grid square.
+2. *height* determines the overall height of the board.
+3. *width* determines the overall width of the board.
+
+Thus the board will create as many squares as possible within
+the constraints of the height and width that it is given.
+
+Within the code, positions within the grid coordinate
+system are always referred to as (gx,gy) and positions
+in the pixel coordinate system are always referred to
+as (x,y). This is a very important distinction, and
+mixing the two together can cause ample confusion.
+
+*/
+
+/*
+ General utility functions.
+ */
+// return a random number (0 <= n <= max)
+var random = function(max) {
+ return Math.floor(Math.random()*(max+1));
+};
+
+//given a start point, and end point, and a speed at which to travel,
+//return the point that the entity should go to in the next draw
+var calc_path = function(x1,y1,x2,y2,speed) {
+ var ac = y2 - y1;
+ var bc = x2 - x1;
+ var ab = Math.sqrt(Math.pow(ac,2) + Math.pow(bc,2));
+ var de = (1.0 * speed * ac) / ab;
+ var be = (1.0 * speed * bc) / ab;
+ return {y:de,x:be};
+};
+
+var dist = function(x1,y1,x2,y2) {
+ var ac = y2 - y1;
+ var bc = x2 - x1;
+ return Math.sqrt(Math.pow(ac,2) + Math.pow(bc,2));
+}
+
+/*
+ Coordinate systems utilities.
+ */
+
+// return pixel coordinates of top left corner
+// of square at grid coordinates (gx,gy)
+var grid_to_pixel = function(gx,gy) {
+ if (gy == undefined) {
+ gy = gx.gy;
+ gx = gx.gx;
+ }
+ return {x:gx*SET.pixels_per_square, y:gy*SET.pixels_per_square};
+};
+
+// return grid coordinates of square containing pixel
+// coordinate (x,y)
+var pixel_to_grid = function(x,y) {
+ if (y == undefined) {
+ y = x.y;
+ x = x.x;
+ }
+ var grid_x = Math.floor(x / SET.pixels_per_square);
+ var grid_y = Math.floor(y / SET.pixels_per_square);
+ return {gx:grid_x, gy:grid_y};
+};
+
+// return pixel coordinates for the center of
+// square at grid coordinates (gx,gy)
+var center_of_square = function(gx,gy) {
+ if (gy == undefined) {
+ gy = gx.gy;
+ gx = gx.gx;
+ }
+ var coords = grid_to_pixel(gx,gy);
+ return {x:coords.x + SET.half_pixels_per_square,
+ y:coords.y + SET.half_pixels_per_square};
+};
+
+/*
+ Drawing functions.
+ */
+
+// draw a square filling square (gx,gy)
+var draw_square_in_grid = function(gx,gy) {
+ var pos = grid_to_pixel(gx,gy);
+ rect(pos.x,pos.y,SET.pixels_per_square,SET.pixels_per_square);
+}
+
+// draw a circle filling (gx,gy)
+var draw_circle_in_grid = function(gx,gy) {
+ var pos = grid_to_pixel(gx,gy);
+ var h = SET.half_pixels_per_square;
+ var l = SET.pixels_per_square;
+ ellipse(pos.x+h,pos.y+h,l-1,l-1);
+};
+
+/*
+ Various game utility functions.
+ */
+
+var can_build_here = function(gx,gy) {
+ if ( get_tower_at(gx,gy) != false) return false;
+ if ((gx == SET.entrance.gx) && (gy == SET.entrance.gy)) return false;
+ if ((gx == SET.exit.gx) && (gy == SET.exit.gy)) return false;
+
+ return true;
+};
+
+var get_tower_at = function(gx,gy) {
+ var cached = SET.grid_cache_at(gx,gy);
+ if (cached.tower) return cached.tower;
+
+ var towers = SET.rendering_groups[SET.tower_render_level];
+ for (var i=0;i<towers.length;i++) {
+ var tower = towers[i];
+ if (tower.gx == gx && tower.gy == gy) {
+ cached.tower = tower;
+ return tower;
+ }
+ }
+ return false;
+};
+
+var get_terrain_at = function(gx,gy) {
+ var cached = SET.grid_cache_at(gx,gy);
+ if (cached.terrain) return cached.terrain;
+
+ var squares = SET.rendering_groups[SET.square_render_level];
+ for (var i=0;i<squares.length;i++) {
+ var square = squares[i];
+ if (square.gx == gx && square.gy == gy) {
+ cached.terrain = square;
+ return square;
+ }
+ }
+ return;
+}
+
+var get_creep_nearest = function(x,y,sensitivity) {
+ if (!sensitivity) sensitivity = 10;
+ var creeps = SET.rendering_groups[SET.creep_render_level];
+ var len = creeps.length;
+ var nearest_creep;
+ var distance = sensitivity;
+ for (var i=0;i<len;i++) {
+ var creep = creeps[i];
+ var d = dist(x,y,creep.x,creep.y);
+ if (d < distance) {
+ distance = d;
+ nearest_creep = creep;
+ }
+ }
+ return (distance < sensitivity) ? nearest_creep : undefined;
+}
+
+// Object.extend borrowed from Prototype javascript library.
+Object.extend = function(destination, source) {
+ for (var property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+};
+
+// Pretty-printing of objects
+var pp = function(obj, depth) {
+ if (depth == undefined) depth = 4;
+ depth -= 1;
+ if (depth <= 0)
+ return '' + obj;
+ if (obj instanceof Array) {
+ var str = "[";
+ obj.forEach(function(i){
+ str += pp(i,depth) + ", ";
+ });
+ return str + "]";
+ }
+ if (obj instanceof String)
+ return '"'+str+'"';
+ if (obj instanceof Object){
+ var str="{"; //variable which will hold property values
+ for(prop in obj){
+ if (prop == "ancestor")
+ depth = 0;
+ str+= pp(prop,depth) + ":" + pp(obj[prop],depth) +", ";
+ }
+ return str + "}";
+ }
+
+
+ return '' + obj;
+
+
+}
+
+var log = function(label, thing) {
+ if (thing == undefined)
+ $('#log').append(label + "<br/>");
+ else
+ $('#log').append(label + ": " + pp(thing) + "<br/>");
+}
+
+
+Array.prototype.equals = function(testArr) {
+ if (this.length != testArr.length) return false;
+ for (var i = 0; i < testArr.length; i++) {
+ if (this[i].equals) {
+ if (!this[i].equals(testArr[i])) return false;
+ }
+ if (this[i] != testArr[i]) return false;
+ }
+ return true;
+}
+
+var insert_sorted = function(array, value, sortKey) {
+ var vkey = sortKey(value);
+ var min=0;
+ var max=array.length;
+ var mid=-1;
+ while(true){
+ if (max<=min) {
+ break;
+ }
+ mid = Math.floor((max+min)/2);
+ if (mid >= array.length || mid < 0) {
+ log("outofbounds in insert sorted");
+ break;
+ }
+ if (vkey <= sortKey(array[mid]))
+ max = mid-1;
+ else
+ min = mid+1;
+ }
+ mid = Math.floor((max+min)/2);
+ if (array[mid])
+ if (vkey > sortKey(array[mid]))
+ mid += 1;
+ mid = Math.max(0,mid);
+
+ var result = array.slice(0,mid).concat([value]).concat(array.slice(mid))
+// log("inserting", [mid,vkey,array.map(sortKey), result.map(sortKey)]);
+// var rm = result.map(sortKey);
+// if (!rm.equals(rm.slice().sort(function(a,b){return a-b})))
+// log("insert_sorted failed inserting",[vkey,rm]);
+ return result;
+}
+
+//moves the given object towards the target at speed
+//also ensures that the given object doesn't go outside of the bounds
+//of the map
+var move_towards = function(obj, x,y,tx,ty,speed) {
+ var path = calc_path(x,y,tx,ty,speed);
+ obj.x += path.x;
+ obj.y += path.y;
+ obj.x = Math.max(0, Math.min(SET.width , obj.x));
+ obj.y = Math.max(0, Math.min(SET.height, obj.y));
+}
\ No newline at end of file
diff --git a/moksha/widgets/misc/ptd/game/weapons.js b/moksha/widgets/misc/ptd/game/weapons.js
new file mode 100644
index 0000000..a591abf
--- /dev/null
+++ b/moksha/widgets/misc/ptd/game/weapons.js
@@ -0,0 +1,398 @@
+var CircleZone = function(x,y,r) {
+ var cz = new Object();
+ Object.extend(cz, InertDrawable);
+ var d = 2*r;
+ cz.color = SET.killzone_color;
+ cz.draw = function() {
+ fill(this.color);
+ stroke(255);
+ ellipse(x,y,d,d);
+ };
+ return cz
+}
+
+var KillZone = function(x,y,r) {
+ var kz = new CircleZone(x,y,r);
+ assign_to_depth(kz, SET.killzone_render_level);
+ return kz;
+};
+
+var BuildRadius = function(x,y,r) {
+ var br = KillZone(x,y,r);
+ assign_to_depth(br, SET.build_zone_render_level);
+ return br;
+};
+
+var MissileRadius = function(x,y,r) {
+ var mr = KillZone(x,y,r);
+ mr.color = color(0, 40,40,0.5);
+ return mr;
+}
+
+var Tower = function(settings) {
+ var tower = GridSquare(settings.gx,settings.gy,settings.color);
+ Object.extend(tower, settings);
+ // note, range is in terms of grid squares
+ // and is calculated from center of tower
+ tower.set_range = function(range) {
+ tower.range = range;
+ tower.prange = range * SET.pixels_per_square;
+ };
+ tower.account_for_terrain = function() {
+ var terrain = get_terrain_at(this.gx,this.gy);
+ this.damage = this.damage * terrain.tower_damage_modifier;
+ this.set_range(this.range * terrain.tower_range_modifier);
+ this.reload_rate = this.reload_rate * terrain.tower_frequency_modifier;
+ };
+ tower.set_range(3.5);
+ tower.damage = 5.0;
+ tower.attack = function(creep) {};
+ var mid = center_of_square(tower.gx,tower.gy);
+ tower.x_mid = mid.x;
+ tower.y_mid = mid.y;
+ tower.fired_at = 0;
+ tower.reload_rate = 1000;
+ tower.weapon_ready = function() {
+ if (SET.now - tower.fired_at > tower.reload_rate) {
+ tower.fired_at = SET.now;
+ return true;
+ }
+ return false;
+ };
+ tower.update = function() {
+ var creeps = SET.rendering_groups[SET.creep_render_level];
+ if (creeps.length == 0) return;
+ var closest_creep;
+ var closest_distance;
+ creeps.forEach(function(creep) {
+ var distance = dist(tower.x_mid,tower.y_mid,creep.x,creep.y);
+ if (distance < tower.prange) {
+ if (!closest_creep) {
+ closest_creep = creep;
+ closest_distance = distance;
+ }
+ else {
+ if (distance < closest_distance) {
+ closest_creep = creep;
+ closest_distance = distance;
+ }
+ }
+ }
+ });
+ if (closest_creep && tower.weapon_ready() == true)
+ tower.attack(closest_creep);
+ }
+ tower.sale_value = 50;
+ tower.sell = function() {
+ SET.gold += Math.floor(this.sale_value * 0.75);
+ this.is_dead = function() { return true; };
+ SET.grid_cache_at(this.gx,this.gy).tower = undefined;
+
+ unselect();
+ }
+ tower.display_stats = function() {
+ WIDGETS.tower_type.innerHTML = this.type;
+ WIDGETS.tower_range.innerHTML = this.range;
+ WIDGETS.tower_damage.innerHTML = this.damage;
+ WIDGETS.tower_rate.innerHTML = this.reload_rate;
+ WIDGETS.tower_sell_button.innerHTML = "Sell tower for " + Math.floor(this.sale_value * 0.75) + " gold!";
+ WIDGETS.tower_upgrade_button.innerHTML = "<u>U</u>pgrade for " + Math.floor(this.upgrade_cost) + " gold!";
+
+ WIDGETS.tower_upgrade_button.onclick = function() {
+ tower.upgrade();
+ }
+ WIDGETS.tower_sell_button.onclick = function() {
+ tower.sell();
+ reset_pathfinding();
+ }
+ WIDGETS.tower.style.display = "block";
+ };
+ tower.draw = function() {
+ noStroke();
+ fill(this.color);
+ draw_circle_in_grid(this.gx,this.gy);
+ }
+ assign_to_depth(tower, SET.tower_render_level);
+ return tower;
+};
+
+var MissileTower = function(gx,gy) {
+ var mt = Tower({gx:gx,gy:gy,color:color(250,150,50)});
+ mt.type = "Missile Tower";
+ mt.damage = 5000;
+ mt.upgrade_cost = 100;
+ mt.sale_value = 100;
+ mt.set_range(5.5);
+ mt.reload_rate = 2000;
+ mt.attack = function(creep) {
+ assign_to_depth(Missile(this,creep),SET.bullet_render_level);
+ }
+ mt.upgrade = function() {
+ if (SET.gold >= this.upgrade_cost) {
+ SET.gold -= this.upgrade_cost;
+ this.sale_value = Math.floor(this.sale_value + this.upgrade_cost);
+ this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5);
+ this.damage = Math.floor(this.damage * 2.5);
+ this.set_range(this.range + 0.5);
+
+ unselect();
+ SET.state = new TowerSelectMode();
+ SET.state.set_up(this.x_mid,this.y_mid);
+ }
+ else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more.");
+ }
+ mt.account_for_terrain();
+ return mt;
+}
+
+var LaserTower = function(gx,gy) {
+ var lt = Tower({gx:gx,gy:gy,color:color(90,150,50)});
+ lt.type = "Laser Tower";
+ lt.attack = function(creep) {
+ assign_to_depth(Laser(this,creep),SET.bullet_render_level);
+ };
+ lt.upgrade_cost = 25;
+ lt.sale_value = 13;
+ lt.upgrade = function() {
+ if (SET.gold >= this.upgrade_cost) {
+ SET.gold -= this.upgrade_cost;
+ this.sale_value = Math.floor(this.sale_value + this.upgrade_cost);
+ this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5);
+ this.damage = Math.floor(this.damage * 2.0);
+ this.set_range(this.range + 0.25);
+ this.reload_rate = this.reload_rate - 10;
+
+ unselect();
+ SET.state = new TowerSelectMode();
+ SET.state.set_up(this.x_mid,this.y_mid);
+ }
+ else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more.");
+ }
+ lt.damage = 10;
+ lt.set_range(4);
+ lt.reload_rate = 250;
+ lt.account_for_terrain();
+ return lt;
+};
+
+var CannonTower = function(gx,gy) {
+ var lt = Tower({gx:gx,gy:gy,color:color(100,120,140)});
+ lt.type = "Cannon Tower";
+ lt.attack = function(creep) {
+ assign_to_depth(CannonBall(this,{x:creep.x, y:creep.y, hp:1}),SET.bullet_render_level);
+ };
+ lt.upgrade_cost = 75;
+ lt.sale_value = 50;
+ lt.upgrade = function() {
+ if (SET.gold >= this.upgrade_cost) {
+ SET.gold -= this.upgrade_cost;
+ this.sale_value = Math.floor(this.sale_value + this.upgrade_cost);
+ this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5);
+ this.damage = Math.floor(this.damage * 2.0);
+ this.set_range(this.range + 0.25);
+ this.reload_rate = this.reload_rate - 10;
+
+ unselect();
+ SET.state = new TowerSelectMode();
+ SET.state.set_up(this.x_mid,this.y_mid);
+ }
+ else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more.");
+ }
+ lt.damage = 100;
+ lt.set_range(4);
+ lt.reload_rate = 1000;
+ lt.account_for_terrain();
+ return lt;
+};
+
+var GatlingTower = function(gx,gy) {
+ var gt = Tower({gx:gx,gy:gy,color:color(250,250,50)});
+ gt.type = "Gatling Tower";
+ gt.damage = 50;
+ gt.upgrade_cost = 25;
+ gt.sale_value = 50;
+ gt.set_range(3.5);
+
+ gt.reload_rate = 100;
+ gt.shots_per_volley = 12;
+ gt.shots_left_in_volley = gt.shots_per_volley;
+ gt.pause_after_volley = 2000;
+ gt.finish_reload_at = 0;
+ gt.reloading = false;
+ gt.fire_next_at = 0;
+
+ gt.weapon_ready = function() {
+ if (gt.reloading && gt.finish_reload_at < SET.now) {
+ gt.shots_left_in_volley = gt.shots_per_volley;
+ gt.reloading = false;
+ }
+ if (!gt.reloading && gt.fire_next_at < SET.now) {
+ return true;
+ }
+ return false;
+ };
+
+ gt.attack = function(creep) {
+ assign_to_depth(Bullet(this,creep),SET.bullet_render_level);
+ gt.shots_left_in_volley--;
+ gt.fire_next_at = SET.now + gt.reload_rate;
+ if (gt.shots_left_in_volley < 1) {
+ gt.reloading = true;
+ gt.finish_reload_at = SET.now + gt.pause_after_volley;
+ }
+ }
+
+ gt.upgrade = function() {
+ if (SET.gold >= this.upgrade_cost) {
+ SET.gold -= this.upgrade_cost;
+ this.sale_value = Math.floor(this.sale_value + this.upgrade_cost);
+ this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5);
+ this.damage = Math.floor(this.damage * 2.5);
+ this.set_range(this.range + 0.5);
+ this.reload_rate = Math.floor(this.reload_rate * 0.95);
+ unselect();
+ SET.state = new TowerSelectMode();
+ SET.state.set_up(this.x_mid,this.y_mid);
+ }
+ else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more.");
+ }
+ gt.account_for_terrain();
+ return gt;
+}
+
+var Weapon = function(tower,target) {
+ var w = new Object();
+ w.x = tower.x_mid;
+ w.y = tower.y_mid;
+ w.target = target;
+ w.tower = tower;
+ w.proximity = 7;
+ w.damage = tower.damage;
+ w.last = millis();
+ w.impact = function(target) {
+ this.is_dead = function() { return true; };
+ target.hp -= this.damage;
+ }
+ w.update = function() {
+ var distance = dist(this.x,this.y,this.target.x,this.target.y);
+ if (distance < this.proximity) {
+ this.impact(this.target);
+ }
+ else {
+ var elapsed = 1.0 * (SET.now - this.last);
+ var speed = this.speed * (elapsed/1000);
+ this.last = SET.now;
+ move_towards(this, this.x,this.y,target.x,target.y,this.speed);
+ }
+ }
+ w.is_dead = function() {
+ if (!target || target.hp <= 0) return true;
+ return false;
+ };
+ return w;
+};
+
+var Bullet = function(tower, target) {
+ var b = new Object();
+ Object.extend(b, Weapon(tower,target));
+ b.size = 5;
+ b.color = color(255,255,255);
+ b.fill_color = color(100,255,0);
+ b.speed = 8;
+ b.damage = tower.damage;
+ b.proximity = 10;
+ b.draw = function() {
+ stroke(b.color);
+ fill(b.fill_color);
+ ellipse(this.x,this.y,this.size,this.size);
+ }
+ return b;
+}
+
+var CannonBall = function(tower, target) {
+ var c = new Object();
+ Object.extend(c, Weapon(tower,target));
+ c.midpoint = {x:Math.floor((c.x + target.x)/2.0), y:Math.floor((c.y + target.y) / 2.0)};
+ c.middist = dist(c.x, c.y, c.midpoint.x, c.midpoint.y);
+ c.min_size = 8
+ c.size_variance = 4;
+ c.color = color(0,0,0);
+ c.fill_color = color(50,50,50);
+ c.speed = 8;
+ c.damage = tower.damage;
+ c.proximity = 25;
+ c.splash_range = 50.0;
+ c.draw = function() {
+ var percent_to_apex = ((this.middist - dist(this.x, this.y, this.midpoint.x, this.midpoint.y)) / this.middist);
+ size = ((1 - Math.pow(1 - percent_to_apex, 2)) * this.size_variance) + this.min_size;
+ log("drawing cannonball", size);
+ stroke(this.color);
+ fill(this.fill_color);
+ ellipse(this.x,this.y,size,size);
+ };
+ c.impact = function(target) {
+ this.is_dead = function() { return true; };
+ var creeps = SET.rendering_groups[SET.creep_render_level];
+ var l = creeps.length;
+ var range = Math.floor(this.splash_range);
+ for (var i=0;i<l;i++) {
+ var creep = creeps[i];
+ var d = Math.floor(dist(this.x,this.y,creep.x,creep.y));
+ if (d <= range) {
+ creep.hp -= this.damage;
+ }
+ }
+ };
+
+ return c;
+};
+
+var Missile = function(tower,target) {
+ var m = new Object();
+ Object.extend(m, Weapon(tower,target));
+ m.size = 10;
+ m.color = color(255,0,0);
+ m.fill_color = color(250,50,50);
+ m.speed = 8;
+ m.damage = tower.damage;
+ m.proximity = 20;
+ m.is_dead = function() {
+ if (!this.target || this.target.hp <= 0) {
+ this.target = get_creep_nearest(this.x,this.y,100);
+ //log("new target: " + pp(this.target));
+ }
+ if (!this.target) return true;
+ return false;
+ }
+
+ m.draw = function() {
+ stroke(m.color);
+ fill(m.fill_color);
+ var mx = this.x;
+ var my = this.y;
+ var size = this.size;
+ var tx = this.target.x;
+ var ty = this.target.y;
+ var tth = Math.atan((ty-my)/(tx-mx));
+ var angle = 2.35619449; // 135 degrees in radians
+ triangle(mx,my,
+ mx+size * Math.cos(tth - 2.35619449), my+size * Math.sin(tth + 2.35619449),
+ mx+size * Math.cos(tth + 2.35619449), my+size * Math.sin(tth - 2.35619449));
+ }
+ return m;
+};
+
+var Laser = function(tower,target) {
+ var l = new Object();
+ Object.extend(l, Weapon(tower,target));
+ l.tail = 20; // length of laser's graphic
+ l.color = color(0,0,255);
+ l.speed = 10;
+ l.proximity = 10;
+ l.draw = function() {
+ var path = calc_path(l.x,l.y,tower.x_mid,tower.y_mid,l.tail);
+ stroke(l.color);
+ line(l.x,l.y,l.x+path.x,l.y+path.y);
+ }
+ return l;
+};
diff --git a/moksha/widgets/misc/ptd/ptd.py b/moksha/widgets/misc/ptd/ptd.py
new file mode 100644
index 0000000..baebcef
--- /dev/null
+++ b/moksha/widgets/misc/ptd/ptd.py
@@ -0,0 +1,31 @@
+# Processed Tower Defense Widget
+
+from tw.api import Widget, CSSLink, JSLink
+from tw.jquery.ui import effects_core_js, effects_highlight_min_js
+from tw.jquery.processing import processing_js
+
+modname = __name__
+
+jsfprocessing_js = JSLink(filename='static/jsfprocessing.js',
+ javascript=[processing_js],
+ modname=modname)
+
+# lulz
+konami = JSLink(filename='static/konami.js', modname=modname)
+
+class ProcessedTowerDefense(Widget):
+ name = 'Processed Tower Defense'
+ hidden = True
+ template = 'mako:moksha.widgets.misc.ptd.templates.ptd'
+ css = [CSSLink(filename='static/style.css', modname=modname),]
+ javascript = [
+ processing_js, jsfprocessing_js,
+ effects_core_js, effects_highlight_min_js,
+ JSLink(filename='game/creep_waves.js', modname=modname),
+ JSLink(filename='game/terrain.js', modname=modname),
+ JSLink(filename='game/util.js', modname=modname),
+ JSLink(filename='game/creeps.js', modname=modname),
+ JSLink(filename='game/ui_modes.js', modname=modname),
+ JSLink(filename='game/weapons.js', modname=modname),
+ JSLink(filename='game/ptd.js', modname=modname),
+ ]
diff --git a/moksha/widgets/misc/ptd/static/jsfprocessing.js b/moksha/widgets/misc/ptd/static/jsfprocessing.js
new file mode 100644
index 0000000..f663e8d
--- /dev/null
+++ b/moksha/widgets/misc/ptd/static/jsfprocessing.js
@@ -0,0 +1,101 @@
+var GLOBAL_PROCESSING;
+function set_canvas(id) {
+ var canvas = document.getElementById(id);
+ GLOBAL_PROCESSING = Processing(canvas);
+}
+
+function size(height, width) {
+ GLOBAL_PROCESSING.size(height, width);
+}
+function stroke(color) {
+ GLOBAL_PROCESSING.stroke(color);
+}
+function background(color) {
+ GLOBAL_PROCESSING.background(color);
+}
+
+function line(x1, y1, x2, y2) {
+ GLOBAL_PROCESSING.line(x1, y1, x2, y2);
+}
+
+var draw = function() {}; // stub to replace
+
+function frameRate(rate) {
+ var interval = 1000.00 / rate;
+ setInterval(draw, interval);
+}
+
+function height() {
+ return GLOBAL_PROCESSING.height;
+}
+
+function width() {
+ return GLOBAL_PROCESSING.width;
+}
+
+function rect(x,y,width,height) {
+ return GLOBAL_PROCESSING.rect(x,y,width,height);
+}
+
+function ellipse(x,y,width,height) {
+ return GLOBAL_PROCESSING.ellipse(x,y,width,height);
+}
+
+function triangle(x1,y1,x2,y2,x3,y3) {
+ return GLOBAL_PROCESSING.triangle(x1,y1,x2,y2,x3,y3);
+}
+
+function fill(color) {
+ return GLOBAL_PROCESSING.fill(color);
+}
+
+var color = function(r,g,b,a) {
+ if (!a)
+ return "rgb(" + r + "," + g + "," + b + ")";
+ else
+ return "rgba(" + r + "," + g + "," + b + "," + a +")";
+};
+
+function translate(width, height) {
+ return GLOBAL_PROCESSING.translate(width, height);
+}
+
+function noFill() {
+ return GLOBAL_PROCESSING.noFill();
+}
+
+function noStroke() {
+ return GLOBAL_PROCESSING.noStroke();
+}
+
+function mouse_pos() {
+ return {x:GLOBAL_PROCESSING.mouseX, y:GLOBAL_PROCESSING.mouseY};
+}
+
+function previous_mouse_pos() {
+ return {x:GLOBAL_PROCESSING.pmouseX, y:GLOBAL_PROCESSING.pmouseY};
+}
+
+function mousePressed(func) {
+ GLOBAL_PROCESSING.mousePressed = func;
+}
+
+function mouseReleased(func) {
+ GLOBAL_PROCESSING.mouseReleased = func;
+}
+
+function mouseMoved(func) {
+ GLOBAL_PROCESSING.mouseMoved = func;
+}
+
+function mouseReleased(func) {
+ GLOBAL_PROCESSING.mouseDragged = func;
+}
+
+function millis() {
+ return GLOBAL_PROCESSING.millis();
+}
+
+function initProcessing() {
+ GLOBAL_PROCESSING.init();
+}
diff --git a/moksha/widgets/misc/ptd/static/konami.js b/moksha/widgets/misc/ptd/static/konami.js
new file mode 100644
index 0000000..7484c9a
--- /dev/null
+++ b/moksha/widgets/misc/ptd/static/konami.js
@@ -0,0 +1,10 @@
+if ( window.addEventListener ) {
+ var kkeys = [], konami = "38,38,40,40,37,39,37,39,66,65";
+ window.addEventListener("keydown", function(e){
+ kkeys.push( e.keyCode );
+ if ( kkeys.toString().indexOf( konami ) >= 0 ) {
+ window.location = '/widgets/ptd';
+ kkeys = [];
+ }
+ }, true);
+}
diff --git a/moksha/widgets/misc/ptd/static/style.css b/moksha/widgets/misc/ptd/static/style.css
new file mode 100644
index 0000000..88ff585
--- /dev/null
+++ b/moksha/widgets/misc/ptd/static/style.css
@@ -0,0 +1,171 @@
+#tower_defense {
+ float:left;
+}
+
+/*
+ From the always helpful article on styling buttons.
+ http://particletree.com/features/rediscovering-the-button-element/
+ */
+
+button{
+ margin:0 7px 0 0;
+ background-color:#f5f5f5;
+ border:1px solid #dedede;
+ border-top:1px solid #eee;
+ border-left:1px solid #eee;
+ font-size:100%;
+ line-height:110%;
+ text-decoration:none;
+ font-weight:bold;
+ color:#565656;
+ cursor:pointer;
+ padding:5px 10px 6px 7px; /* Links */
+}
+button:hover {
+ background-color:#dff4ff;
+ border:1px solid #c2e1ef;
+ color:#336699;
+}
+button:active{
+ background-color:#6299c5;
+ border:1px solid #6299c5;
+ color:#fff;
+}
+
+button.active_mode {
+ background-color:#6299c5;
+ border:1px solid #6299c5;
+ color:#fff;
+}
+
+div#game {
+ background-color: #888;
+ padding-left: 10px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ overflow: auto;
+}
+
+#game div {
+ overflow:auto
+}
+
+#menu {
+ float: left;
+}
+
+#top_controls .item {
+ padding-right: 10px;
+}
+
+#middle {
+ overflow: auto;
+}
+
+#bottom_controls {
+ padding-bottom:10px;
+ padding-top:5px;
+ width: 100%;
+}
+
+#game_over {
+ font-size: 150%;
+ background-color: #000;
+ color: #f73;
+}
+
+.error {
+ background-color: #000;
+ color: #f73;
+}
+
+div#side {
+ float: left;
+}
+
+#tower {
+ display: none;
+}
+
+#creep {
+ display: none;
+}
+
+#side table {
+ margin-left: 10px;
+ margin-top: 10px;
+ border: solid 1px black;
+}
+#side .message_area {
+ margin-left: 10px;
+ margin-top: 10px;
+ border: solid 1px black;
+}
+#logging_button {
+ display: none;
+}
+
+.hotkey {
+ text-decoration: underline;
+}
+
+#help {
+ background: white;
+ margin-top: 25px;
+ margin-left: 20px;
+ padding-left: 30px;
+ padding-right: 30px;
+ width: 500px;
+ height: 400px;
+ position: absolute;
+ z-index: 1000;
+ display: none;
+ border: 3px solid black;
+}
+
+
+#help-sections div {
+ display: none;
+}
+
+#help-sections div.visible {
+ display: block;
+}
+
+#help-headers {
+ padding: 10px;
+ border-bottom: 2px solid black;
+}
+
+a.section {
+ margin-left: 5px;
+ margin-right: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ text-decoration: none;
+ color: black;
+}
+
+a.section:hover {
+ color: #AAA;
+}
+a.section.active { color: #2259a5; font-weight: bold;}
+a.section.active:hover { color: #2259a5;}
+
+#help .missile-tower { color: rgb(250,150,50); }
+#help .laser-tower { color: rgb(90,150,50); }
+#help .cannon-tower { color: rgb(100,120,140); }
+#help .gatling-tower { color: rgb(250,250,50); }
+
+#help .normal-creep { color: rgb(255,255,0);}
+#help .quick-creep {color: rgb(200,150,50);}
+#help .strong-creep {color: rgb(0,255,255);}
+#help .boss-creep {color: rgb(255,100,150);}
+
+#help .neutral-terrain {color: rgb(200,200,200);}
+#help .mountain-terrain {color: rgb(228,51,51);}
+#help .water-terrain {color: rgb(78,150,236);}
+#help .power-plant-terrain {color: rgb(189,194,78);}
+
+#help .bomb {color: rgb(100,120,140);}
+#help .nuke {color: rgb(255,70,30);}
diff --git a/moksha/widgets/misc/ptd/templates/__init__.py b/moksha/widgets/misc/ptd/templates/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/moksha/widgets/misc/ptd/templates/ptd.mak b/moksha/widgets/misc/ptd/templates/ptd.mak
new file mode 100644
index 0000000..bfc9f48
--- /dev/null
+++ b/moksha/widgets/misc/ptd/templates/ptd.mak
@@ -0,0 +1,319 @@
+# -*- coding: utf-8 -*-
+<div class="container">
+
+<div id="game_over"></div>
+
+<div id="game">
+ <div id="top_controls">
+ <span class='item'> Lives: <span id="lives">20</span></span>
+ <span class='item'> Score: <span id="score">0</span></span>
+ <span class='item'> Gold: <span id="gold">0</span></span>
+ <span class='item'> Wave: <span id="wave">1</span></span>
+ <span class='item'> Creep Variety: <span id="creep_variety"></span></span>
+ <span class='item'> Next Wave in <span id="till_next_wave"></span> seconds</span>
+ </div>
+ <div id="help">
+
+
+ <div id="help-headers">
+ <span><a class="section active" href="#help-gameplay">Gameplay</a></span>
+ <span><a class="section" href="#help-towers">Towers</a></span>
+ <span><a class="section" href="#help-creeps">Creeps</a></span>
+ <span><a class="section" href="#help-terrain">Terrain</a></span>
+ <span><a class="section" href="#help-bomb">Bombs & Nukes</a></span>
+ </div>
+ <div id="help-sections">
+ <div class="visible" id="help-gameplay">
+ <p> Processed Tower Defense is a strategy game where you try to defeat waves of dangerous monsters before they reach your tower. Of course, its less of a tower and more of a blueish square on the right side of the screen, but the idea stands. </p>
+ <p> Monsters appear on the only colorful square on the far left edge of the map, sprint towards the only colorful square on the far right edge of the map. Each time a monster reaches your tower, you lose one life. Lose all of your lives and the game ends. </p>
+ <p> You start out with a small treasury of gold, and each time you defeat a creep you receive a bit more gold to aid in your valiant defense of the lame blue squa... I mean... your tower. You also receive a few more points to your score when you defeat a creep. While gold can be redeemed for more powerful towers, score can only be redeemed as social capital among fellow PTD players, and thus could be fairly described as both invaluable and worthless. </p>
+ </div>
+ <div id="help-towers">
+ <p> Towers are your first and last line of defense against creeps. Except for the bomb and the nuke, but thats not the point right now. We're talking about towers, okay? Keep on task, won't ya? </p>
+ <ul>
+ <li><strong class='missile-tower'>Missile Towers</strong> – slow-firing towers with long range and the gentle caress of a freight truck.</li>
+ <li><strong class='cannon-tower'>Cannon Towers</strong> – potent beasts whose arcing balls of destruction cause splash damage</li>
+ <li><strong class='gatling-tower'>Gatling Towers</strong> – unleash a relentless fury of bullets... until they pause to reload</li>
+ <li><strong class='laser-tower'>Laser Towers</strong> – the circular reincarnation of bland reliability: they shoot blue lines at a high rate, and nothing else</li>
+ </ul>
+ <p> Towers all have another helpful characteristic: they block the paths of creeps. This lets you build complex mazes in the hope that the creeps will become dizzy and stop for a few moments to recover over a nice cup of tea. At the bare minimum you'll get to shoot at them for longer. </p>
+ </div>
+ <div id="help-creeps">
+ <p> Creeps are the evil scourge which long to plaster the sickening <strong>Game Over</strong> message at the top of your screen. Resisting them is your calling, your purpose, your afternoon you were supposed to spend doing laundry.</p>
+ <ul>
+ <li><strong class='normal-creep'>Normal</strong> creeps: You will know these creeps well, and will prosper by ending their drab, boring existences</li>
+ <li><strong class='quick-creep'>Quick</strong> creeps arrive every third wave. These creeps move quickly, but their smaller bodies can take less damage</li>
+ <li><strong class='strong-creep'>Strong</strong> creeps plow through your territory every five waves. They're slow, but extremely hearty.</li>
+ <li><strong class='boss-creep'>Boss</strong> creep: once in a blue moon, one of these warlords appears and lays waste to your defenses with its absurd hitpoints and size.</li>
+ </ul>
+ <p> Each of those categories of creeps can also have one additional behavior. Some creeps are very slow crossing water, some climb mountains at shocking speeds, and some even fly over your towers while mocking the effectiveness of your intricate designs.</p>
+ </div>
+ <div id="help-terrain">
+ <p> Each square on the board is a certain type of terrain. Terrain is randomly assigned each time the game is played, and bestows certain effects upon towers and creeps inside of them. </p>
+ <ul>
+ <li> <strong class='neutral-terrain'>Neutral</strong> terrain is the most common terrain, and doesn't do anything. </li>
+ <li> <strong class='water-terrain'>Water</strong> terrain slows most creeps down.</li>
+ <li> <strong class='mountain-terrain'>Mountain</strong> terrain slows creeps down, and gives towers a range bonus. </li>
+ <li> <strong class='power-plant-terrain'> Power plant </strong> terrain makes creep zip along at double speed, but will also double the damage of any tower built there. </li>
+ </ul>
+ </div>
+ <div id="help-bomb">
+ <p> The <strong class='bomb'>Bomb</strong> is the first of two last resort weapons at your disposal. You have an unlimited supply, but they get a bit more expensive with each passing level. Will severely damage all creeps in its radius (dealing 75% of their max hitpoints), but won't come cheap. </p>
+ <p> The <strong class='nuke'>Nuke</strong> is the last resort weapon of last resort weapons. It will destroy all creeps on the screen, but has two drawbacks. First, you won't recieve any loot from creeps destroyed this way. Second, you only have a limited supply and have no way to replenish that supply once they are exhausted. </p>
+ </div>
+ </div>
+
+ </div>
+
+ <div id="middle">
+ <canvas id='tower_defense' width="600" height="400"></canvas>
+
+ <div id="side">
+ <div id="controls">
+ <table>
+ <tr>
+ <td> <button id='laser_button' class='mode_button' onclick="build_laser_tower();" accesskey="L">Build <span class='hotkey'>L</span>aser Tower - 25 Gold</button> </td>
+ </tr>
+ <tr>
+ <td> <button id='gatling_button' class='mode_button' onclick="build_gatling_tower();"> Build <span class='hotkey'>G</span>attling Tower - 50 Gold</button></td>
+ </tr>
+ <tr>
+ <td> <button id='cannon_button' class='mode_button' onclick="build_cannon_tower();" accesskey="M">Build <span class='hotkey'>C</span>annon Tower - 75 Gold</button> </td>
+ </tr>
+ <tr>
+ <td> <button id='missile_button' class='mode_button' onclick="build_missile_tower();" accesskey="M">Build <span class='hotkey'>M</span>issile Tower - 100 Gold</button> </td>
+ </tr>
+ <tr>
+ <td> <button id='bomb_button' class='mode_button' onclick="aim_bomb();" accesskey="S">Drop <span class='hotkey'>B</span>omb - <span id="bomb_cost">50</span> Gold</button></td>
+ </tr>
+ <tr>
+ <td> <button onclick="nuke_creeps();" accesskey="N"> Launch <span class='hotkey'>N</span>uke - <span id="nukes_left"> 3 left </span></button></td>
+ </tr>
+ </table>
+ </div>
+
+ <div id="tower">
+ <table>
+ <tr><td></td><td> <em>Tower Details</em> </td></tr>
+ <tr><td> Type: </td><td id="tower_type"></td></tr>
+ <tr><td> Range: </td><td id="tower_range"></td></tr>
+ <tr><td> Damage: </td><td id="tower_damage"></td></tr>
+ <tr><td> Firing Rate: </td><td id="tower_rate"></td></tr>
+ <tr><td><button id="tower_sell_button"></button></td></tr>
+ <tr><td><button id="tower_upgrade_button"><span class='hotkey'>U</span>pgrade!</button></td></tr>
+ </table>
+ </div>
+ <div id="creep">
+ <table>
+ <tr><td></td><td> <em> Creep Details </em></td></tr>
+ <tr><td> Type: </td><td id="creep_type"></td></tr>
+ <tr><td> Hp: </td><td id="creep_hp"></td></tr>
+ <tr><td> Value: </td><td id="creep_value"></td></tr>
+ </table>
+ </div>
+ <div class='error message_area'></div>
+ <div class='message message_area'></div>
+ </div>
+ </div>
+
+ <div id="bottom_controls">
+ <button id='pause_button' class='mode_button' onclick="pause();">Pause</button>
+ <button id='reset_button' onclick="reset_game();">Reset Game</button>
+ <button onclick="spawn_wave();">Spawn Next <span class='hotkey'>W</span>ave</button>
+<!-- <button id='mute_button' onclick="mute();">Mute</button> -->
+ <button id='help_button' onclick="toggle_help();"><span class='hotkey'>H</span>elp</button>
+ <button id='logging_button' onclick='toggle_logging();' class='active_mode'>Stop <span class='hotkey'>D</span>ebugging</button>
+ </div>
+</div>
+
+<h4>Hotkeys:</h4>
+<ul>
+ <li>[space] – Pause/Resume</li>
+ <li>[esc] – Cancel Tower/Missile</li>
+ <li>H – Help!</li>
+ <li>L – Build laser tower</li>
+ <li>M – Build missile tower</li>
+ <li>G – Build gatling tower</li>
+ <li>C – Build cannon tower</li>
+ <li>B – Drop Bomb</li>
+ <li>N – Launch Nuke</li>
+ <li>W – Spawn Next Wave</li>
+ <li>U – Upgrade Selected Tower</li>
+</ul>
+
+<script type="text/javascript" charset="utf-8">
+ /* initialization */
+ $(document).ready(function() {
+ start_tower_defense();
+ })
+
+
+ /* Hotkeys! */
+ special_keys = {
+ 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll', 20: 'capslock',
+ 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',35:'end', 33: 'pageup', 16: 'shift',
+ 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down', 112:'f1',113:'f2', 114:'f3',
+ 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8', 120:'f9', 121:'f10', 122:'f11', 123:'f12'};
+
+ /* Modifier keys */
+ var modifierkeys = {};
+ var shift_down = false;
+
+ //extract hotkeys from the DOM
+ var hotkeys = {};
+ $('button .hotkey').each(function(){
+ //this is bass ackwards, but I got type errors passing around the native click method
+ var button = this.parentNode;
+ hotkeys[$(this).html().toUpperCase()] = function() {button.click()};
+ });
+
+ //hotkeys that aren't in the dom
+ hotkeys["space"] = pause;
+ hotkeys["esc"] = unselect;
+ hotkeys['Z'] = function() {$('#log').empty()};
+ hotkeys['R'] = function() {if (SET.state.name() == "GameOverMode") reset_game();}
+
+ //modifiers to be called on keydown and keyup
+ modifierkeys["shift"] = function() { shift_down = !shift_down; };
+
+ $(document).bind("keydown", function(e) {
+ // if the user is holding down ctrl or cmd, let the browser handle it
+ if (e.metaKey) return true;
+ var key = special_keys[e.keyCode] || String.fromCharCode(e.keyCode);
+ if (key in hotkeys){
+ hotkeys[key]();
+ return false;
+ }
+ if (key in modifierkeys){
+ modifierkeys[key]();
+ return false;
+ }
+ return true;
+ });
+
+ $(document).bind("keyup", function(e) {
+ if (e.metaKey) return true;
+ var key = special_keys[e.keyCode] || String.fromCharCode(e.keyCode);
+ if (key in modifierkeys){
+ modifierkeys[key]();
+ return false;
+ }
+ return true;
+ });
+
+
+ /* Toggle buttons along the bottom */
+
+ // all of this is really a prime candidate for some cleanup
+ // so much dupiclation and so many global variables for such
+ // simple behavior
+
+ var paused = false;
+ function pause() {
+ paused = !paused;
+ pause_resume();
+ $('#pause_button').html(paused ? "Resume" : "Pause");
+ }
+ function mute() {
+ mute_unmute();
+ $('#mute_button').html(muted ? "Unmute" : "Mute");
+ }
+ var logging = true;
+ var prim_log = log;
+ function toggle_logging() {
+ logging = !logging;
+
+ if (logging)
+ log = prim_log;
+ else
+ log = function(){};
+ $("#logging_button").toggleClass("active_mode").html(logging? "Stop <span class='hotkey'>D</span>ebugging" : 'Start <span class="hotkey">D</span>ebugging');
+ }
+
+ if (document.location.hash == "#debug")
+ $('#logging_button').show();
+ else{
+ toggle_logging()
+ $('#logging_button')[0].onclick = function(){};
+ }
+
+ var getIdFromURL = function(url) {
+ return url.slice(url.indexOf("#"));
+ }
+ $("#help-headers .section").click(function() {
+ $("#help-sections div").hide();
+ $(getIdFromURL(this.href)).show();
+ $("#help-headers .section").removeClass("active");
+ $(this).addClass("active");
+ return false;
+ })
+
+ var help_displayed = false;
+ var toggle_help = function() {
+ help_displayed = !help_displayed;
+ if (help_displayed){
+ $("#help").show();
+ $("#help_button").addClass("active_mode");
+ if (!paused) pause();
+ }
+ else {
+ $('#help').hide();
+ $('#help_button').removeClass('active_mode');
+ if (paused) pause();
+ }
+ };
+
+
+
+ /* illustrating to the user what mode they're in*/
+ mode_signifiers = {'BuildLaserTowerMode':'laser_button', 'BuildGatlingTowerMode':'gatling_button',
+ 'BuildCannonTowerMode':'cannon_button', 'BuildMissileTowerMode':'missile_button',
+ 'AimBombMode':'bomb_button', 'PauseMode':'pause_button'};
+ for (event in mode_signifiers) {
+ $('').bind(event, function(e) {
+ $('#'+mode_signifiers[e.type]).addClass('active_mode');
+ });
+ }
+ $('').bind('no_mode', function() {
+ $('.mode_button').removeClass('active_mode');
+ })
+
+
+ /* Messages for the player */
+
+ //Temporary messages are a bit of a pain
+ var timeToHide = null;
+ ["error","message"].forEach(function(s){
+ $('.'+s).hide();
+ $('').bind(s,function(e,message){
+ timeToHide = new Date().getTime() + 2500;
+ var el = $('.'+s);
+ el.html(message).fadeIn();
+ window.setTimeout(function() {
+ if (new Date().getTime() >= timeToHide)
+ el.fadeOut();
+ }, 3000);
+ });
+ });
+ $('#game_over').hide();
+ $('').bind('game_over', function(e,over){
+ if (over == true){
+ log("game over");
+ $('#game_over').html("Game Over! Final score: " + $("#score").html()).fadeIn();
+ //tempt tempt tempt
+ for (var i=0; i < 3; i++)
+ $("#reset_button").effect("highlight",{color:"#f60"},3000);
+ }
+ else{
+ log("game (re?)started");
+ $('#game_over').html("Just once more...").fadeOut();
+ }
+ });
+
+ /* stub until we pull in sound for reals */
+ var play_sound = function(){};
+</script>
+<div id="log"></div>
+<div id="sfx_dump"></div>
+
+</div>
commit 308769f819e8322385486bb154c2a6f42de13f1d
Merge: a3d9d2f... 60ed1f4...
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 16:18:44 2009 -0500
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit a3d9d2f48f0355ccd9040c9447d3fe72aae0ebe8
Merge: da163c0... 8ca724e...
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 3 15:56:17 2009 -0500
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit da163c0687237e006eb792c049d77c7bb8df8e15
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 2 23:56:01 2009 -0500
I added the jQuery UI JSLinks to the tw.query.ui module
diff --git a/moksha/widgets/container/container.py b/moksha/widgets/container/container.py
index 3abb547..6fcfd4d 100644
--- a/moksha/widgets/container/container.py
+++ b/moksha/widgets/container/container.py
@@ -19,24 +19,12 @@
from tw.api import Widget, JSLink, CSSLink
from tw.jquery import jquery_js, jQuery
-# @@ put this stuff in the tw.jquery modules
-
-ui_core_js = JSLink(filename='static/js/ui/ui.core.js',
- modname=__name__, javascript=[jquery_js])
-ui_draggable_js = JSLink(filename='static/js/ui/ui.draggable.js',
- modname=__name__, javascript=[ui_core_js])
-ui_resizable_js = JSLink(filename='static/js/ui/ui.resizable.js',
- modname=__name__, javascript=[ui_core_js])
-
-container_js = JSLink(filename='static/js/mbContainer.js',
- modname=__name__)
-container_css = CSSLink(filename='static/css/mbContainer.css',
- modname=__name__)
-
+container_js = JSLink(filename='static/js/mbContainer.js', modname=__name__)
+container_css = CSSLink(filename='static/css/mbContainer.css', modname=__name__)
class MokshaContainer(Widget):
template = 'mako:moksha.widgets.container.templates.container'
- javascript = [container_js] # , ui_draggable_js, ui_resizable_js]
+ javascript = [container_js]
css = [container_css]
options = ['draggable', 'droppable', 'resizable', 'stikynote']
button_options = ['iconize', 'minimize', 'close']
@@ -48,7 +36,6 @@ class MokshaContainer(Widget):
content = '' # either text, or a Widget
title = 'Moksha Container'
skin = 'skin3' # skin[1-7]
- #id = 'moksha_container'
# Pixel tweaking
width = 400
15 years, 4 months
docs/main
by John (J5) Palmieri
docs/main/MokshaContainerWidgets.rst | 55 +++++++++++++++++++----------------
1 file changed, 30 insertions(+), 25 deletions(-)
New commits:
commit 0b58dcf11a8affba6f357f1662e11195240364e1
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 3 16:31:39 2009 -0500
fix up some formatting
diff --git a/docs/main/MokshaContainerWidgets.rst b/docs/main/MokshaContainerWidgets.rst
index 839d07c..65176d3 100644
--- a/docs/main/MokshaContainerWidgets.rst
+++ b/docs/main/MokshaContainerWidgets.rst
@@ -46,26 +46,26 @@ CSS to position those categories in your layout.
Lets look at each individual component.
* Category 'Test Applications' - This tells the container that you want to group
-a number of applications under the 'Test Application' title which in essence
-creates a div with class 'test_applications'. You may also want to specify
-css_class instead of relying on the label.
+ a number of applications under the 'Test Application' title which in essence
+ creates a div with class 'test_applications'. You may also want to specify
+ css_class instead of relying on the label.
* MokshaApp 'Hello World 1': here we dynamically load the moksha application
-installed on the ``moksha.application`` entry point as ``moksha.helloworld``.
-We then send it a dictionary of keys - in this case the key 'name'.
+ installed on the ``moksha.application`` entry point as ``moksha.helloworld``.
+ We then send it a dictionary of keys - in this case the key 'name'.
* App 'Hello World 2': This is the same as the above but instead of giving
-the application name we give it the url the application is mounted on. We
-also send in different configuration data. The App object allows for non
-moksha web apps and static content to be placed in a container.
+ the application name we give it the url the application is mounted on. We
+ also send in different configuration data. The App object allows for non
+ moksha web apps and static content to be placed in a container.
* MokshaWidget 'Hello World 3': Again this is the same as above but we pass in
-a widget installed on the ``moksha.widget`` entry point as
-``moksha.helloworldwidget``. We also pass in a auth predicate. If the
-authorization evaluates to True, in this case if the user is anonymous, the
-widget will be embedded in the page. If not then it is removed. Predicates
-are defined by the :module:`repoze.what.authorize` module and can be added to
-any ConfigWrapper.
+ a widget installed on the ``moksha.widget`` entry point as
+ ``moksha.helloworldwidget``. We also pass in a auth predicate. If the
+ authorization evaluates to True, in this case if the user is anonymous, the
+ widget will be embedded in the page. If not then it is removed. Predicates
+ are defined by the :module:`repoze.what.authorize` module and can be added to
+ any ConfigWrapper.
Tabbed Container
----------------
@@ -82,6 +82,7 @@ subclassed in order to point it to the correct resources.
Here is an example on how to subclass a TabbedContainer:
mainnav.py
+
.. code-block:: python
from moksha.api.widgets.containers import TabbedContainer
@@ -90,6 +91,7 @@ mainnav.py
config_key = 'myapp.mainnav.apps'
mainnav.mak
+
.. code-block:: html
<div>
<ul id="${id}">
@@ -117,6 +119,7 @@ mainnav.mak
</div>
development.ini
+
.. code-block:: python
[DEFAULT]
myapp.mainnav.apps = (MokshaApp('Home', 'myapp.home'),
@@ -143,7 +146,8 @@ subclassed in order to point it to the correct resources.
Here is an example on how to subclass a DashboardContainer:
-mainnav.py
+homepage.py
+
.. code-block:: python
from moksha.api.widgets.containers import DashboardContainer
@@ -166,6 +170,7 @@ mainnav.py
]
homepagecontainer.mak
+
.. code-block:: html
<div id="${id}">
<div>
@@ -189,15 +194,15 @@ dynamically loading content in the browser means that there are some issues
to consider.
* Id's may clash. It is suggested that when using jQuery
-or any other javascript dom tool to generate a uuid and do all of your
-selections relative to that id. It is also suggested you namespace your id's
-and only use classes to style.
+ or any other javascript dom tool to generate a uuid and do all of your
+ selections relative to that id. It is also suggested you namespace your id's
+ and only use classes to style.
* Javascript may load more than once. If all you uses is widgets you are fine
-as ToscaWidgets will take care of duplicate resource requests. However a
-powerful concept in moksha is the ability to load applications asynchronously
-so that the user does not have to wait for the server to finish processing a
-page before any data is streamed to them. It is suggested you make heavy use
-of global resources in order to aleviate the issue. At some point we may
-introduce a way for the browser to filter out already loaded javascript and
-other resources.
\ No newline at end of file
+ as ToscaWidgets will take care of duplicate resource requests. However a
+ powerful concept in moksha is the ability to load applications asynchronously
+ so that the user does not have to wait for the server to finish processing a
+ page before any data is streamed to them. It is suggested you make heavy use
+ of global resources in order to aleviate the issue. At some point we may
+ introduce a way for the browser to filter out already loaded javascript and
+ other resources.
15 years, 4 months
docs/index.rst
by John (J5) Palmieri
docs/index.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 60ed1f483037f70877567356dc870f64c1a030db
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 3 16:02:10 2009 -0500
add Moksha Container Widgets doc to index
diff --git a/docs/index.rst b/docs/index.rst
index a18d764..aa3c96f 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -68,7 +68,7 @@ Widgets
main/Feeds
main/LiveWidget
-
+ main/MokshaContainerWidgets
..
Model
-----
15 years, 4 months