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@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/%22%3E + <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@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@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@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@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@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@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.ht... - 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/%22%3E - <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/%22%3E - <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/%22%3E - <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/%22%3E - <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/%22%3E - <?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 - -@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.ht... + 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/%22%3E + <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/%22%3E + <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/%22%3E + <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/%22%3E + <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/%22%3E + <?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 + +@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@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@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@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@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@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@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@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@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@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.ht... + 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/%22%3E + <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/%22%3E + <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/%22%3E + <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/%22%3E + <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/%22%3E + <?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 + +@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@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@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@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.
moksha-commits@lists.fedorahosted.org