[Jifty-commit] r1102 - in jifty/trunk: . lib/Jifty lib/Jifty/Web
plugins/EditInPlace share/web/static/css
share/web/static/images/silk share/web/static/js
share/web/static/js/cssquery share/web/static/js/ie7
share/web/static/js/jsan share/web/static/js/jsan/DOM
share/web/static/js/jsan/Upgrade
share/web/static/js/jsan/Upgrade/Array
share/web/static/js/jsan/Upgrade/Function
share/web/templates/_elements
jifty-commit at lists.jifty.org
jifty-commit at lists.jifty.org
Tue May 23 11:02:09 EDT 2006
Author: jesse
Date: Tue May 23 11:02:05 2006
New Revision: 1102
Added:
jifty/trunk/share/web/static/css/context-menus.css
jifty/trunk/share/web/static/images/silk/bullet_arrow_down.png (contents, props changed)
jifty/trunk/share/web/static/images/silk/bullet_arrow_up.png (contents, props changed)
jifty/trunk/share/web/static/js/context_menu.js
jifty/trunk/share/web/static/js/cssquery/
jifty/trunk/share/web/static/js/cssquery/cssQuery-level2.js
jifty/trunk/share/web/static/js/cssquery/cssQuery-level3.js
jifty/trunk/share/web/static/js/cssquery/cssQuery-standard.js
jifty/trunk/share/web/static/js/cssquery/cssQuery.js
jifty/trunk/share/web/static/js/jifty_utils.js
jifty/trunk/share/web/static/js/jsan/
jifty/trunk/share/web/static/js/jsan/DOM/
jifty/trunk/share/web/static/js/jsan/DOM/Events.js
jifty/trunk/share/web/static/js/jsan/JSAN.js
jifty/trunk/share/web/static/js/jsan/Upgrade/
jifty/trunk/share/web/static/js/jsan/Upgrade.js
jifty/trunk/share/web/static/js/jsan/Upgrade/Array/
jifty/trunk/share/web/static/js/jsan/Upgrade/Array/push.js
jifty/trunk/share/web/static/js/jsan/Upgrade/Function/
jifty/trunk/share/web/static/js/jsan/Upgrade/Function/apply.js
jifty/trunk/share/web/templates/_elements/keybindings
Removed:
jifty/trunk/share/web/static/js/ie7/
Modified:
jifty/trunk/ (props changed)
jifty/trunk/Changelog
jifty/trunk/lib/Jifty/Action.pm
jifty/trunk/lib/Jifty/Web.pm
jifty/trunk/lib/Jifty/Web/Form.pm
jifty/trunk/lib/Jifty/Web/Form/Element.pm
jifty/trunk/lib/Jifty/Web/Form/Field.pm
jifty/trunk/lib/Jifty/Web/Form/Link.pm
jifty/trunk/lib/Jifty/Web/Menu.pm
jifty/trunk/plugins/EditInPlace/META.yml
jifty/trunk/share/web/static/css/main.css
jifty/trunk/share/web/static/js/behaviour.js
jifty/trunk/share/web/static/js/jifty.js
jifty/trunk/share/web/static/js/key_bindings.js
jifty/trunk/share/web/static/js/rico.js
jifty/trunk/share/web/templates/_elements/javascript
jifty/trunk/share/web/templates/_elements/menu
jifty/trunk/share/web/templates/_elements/wrapper
Log:
r11778 at hualien (orig r892): trs | 2006-04-22 17:25:16 -0400
New branch for JSAN integration instead of prototype, etc.
r11801 at hualien (orig r898): trs | 2006-04-23 12:15:31 -0400
r9946 at zot: tom | 2006-04-23 00:38:34 -0400
Remove IE7 source from Jifty
r11802 at hualien (orig r899): trs | 2006-04-23 12:15:37 -0400
r9947 at zot: tom | 2006-04-23 00:39:58 -0400
Reworked Behaviour library to use JSAN and cssQuery
r11803 at hualien (orig r900): trs | 2006-04-23 12:15:41 -0400
r11858 at hualien (orig r915): trs | 2006-04-24 15:36:29 -0400
r9980 at zot: tom | 2006-04-24 11:49:12 -0400
We use cssQuery now
r11859 at hualien (orig r916): trs | 2006-04-24 15:36:37 -0400
r9981 at zot: tom | 2006-04-24 12:06:29 -0400
Turn the key bindings into a Jifty library and fix propagation problems in Firefox
r11873 at hualien (orig r920): trs | 2006-04-24 17:11:45 -0400
r10015 at zot: tom | 2006-04-24 17:10:18 -0400
Make writing keybinding legend use Behaviour and the DOM
r11877 at hualien (orig r924): trs | 2006-04-24 22:48:58 -0400
r10027 at zot: tom | 2006-04-24 22:48:38 -0400
IE doesn't like binding to the window, but document works (should have just kept it in the first place, I guess)
r11879 at hualien (orig r926): trs | 2006-04-24 23:18:35 -0400
r10035 at zot: tom | 2006-04-24 23:18:18 -0400
Support key bindings for Opera
r11962 at hualien (orig r938): trs | 2006-04-26 21:01:54 -0400
r10127 at zot: tom | 2006-04-26 21:01:10 -0400
Only append the keybindings if there are any
r13101 at hualien (orig r963): trs | 2006-04-29 17:49:43 -0400
r10199 at zot: tom | 2006-04-29 17:48:30 -0400
Fix Rico's corner implementation to deal with padding better
r13145 at hualien (orig r967): trs | 2006-04-29 23:15:18 -0400
r10202 at zot: tom | 2006-04-29 23:14:57 -0400
Add a note about the modified Rico and make it a new version
r13405 at hualien (orig r1037): trs | 2006-05-11 22:42:20 -0400
r10438 at zot: tom | 2006-05-11 22:41:10 -0400
Hardcoding the dependencies instead of letting JSAN handle it was a bad idea (users would have to fiddle then instead of simply "use"ing the libs)
r13567 at hualien (orig r1046): trs | 2006-05-13 16:43:30 -0400
r12260 at zot: tom | 2006-05-13 13:01:09 -0400
s/'/"/g -- not all browsers like single quotes
r13568 at hualien (orig r1047): trs | 2006-05-13 16:43:34 -0400
r12269 at zot: tom | 2006-05-13 16:40:32 -0400
Put JSAN.js first and take care of its config _before_ loading anything that uses it. Plus, be a little smarter about the includePath and errorLevel.
r13569 at hualien (orig r1048): trs | 2006-05-13 16:43:41 -0400
r13570 at hualien (orig r1049): trs | 2006-05-13 16:43:47 -0400
r12275 at zot: tom | 2006-05-13 16:43:21 -0400
Fix merge bug
r13572 at hualien (orig r1051): trs | 2006-05-13 17:46:54 -0400
r12281 at zot: tom | 2006-05-13 17:30:28 -0400
Compat with Konq
r13891 at hualien (orig r1079): trs | 2006-05-18 18:49:52 -0400
r12387 at zot: tom | 2006-05-18 18:49:43 -0400
Not really as desirable or as useful as I first thought.
r13965 at hualien (orig r1086): alexmv | 2006-05-22 16:43:57 -0400
r13204 at zoq-fot-pik: chmrr | 2006-05-22 16:43:48 -0400
* Register actions of buttons in the buttons, not in the form
r13966 at hualien (orig r1087): alexmv | 2006-05-22 19:13:23 -0400
r13212 at zoq-fot-pik: chmrr | 2006-05-22 19:12:06 -0400
* "" is false in javascript
r13967 at hualien (orig r1088): jesse | 2006-05-22 21:43:15 -0400
* Added support for context menus (at the code level. next up, at the CSS level)
r13977 at hualien (orig r1093): jesse | 2006-05-22 22:01:58 -0400
* Added back missing loc
r13978 at hualien (orig r1094): trs | 2006-05-22 22:23:34 -0400
r12461 at zot: tom | 2006-05-22 22:23:22 -0400
Oops, we don't want these
r13981 at hualien (orig r1096): jesse | 2006-05-22 22:39:32 -0400
* Pull in backcompat breakage notes from trs
r13986 at hualien (orig r1097): trs | 2006-05-22 23:32:14 -0400
r12463 at zot: tom | 2006-05-22 23:24:39 -0400
Contextual menu support
r13987 at hualien (orig r1098): trs | 2006-05-22 23:32:19 -0400
r13989 at hualien (orig r1099): trs | 2006-05-22 23:57:37 -0400
r12469 at zot: tom | 2006-05-22 23:57:21 -0400
* Use JS to place the context menu above everything else
* Better styling
Modified: jifty/trunk/Changelog
==============================================================================
--- jifty/trunk/Changelog (original)
+++ jifty/trunk/Changelog Tue May 23 11:02:05 2006
@@ -1,6 +1,24 @@
* Removed the ActionBasePath and CurrentUserClass configuration
variables. This breaks backwards compatibility.
+ * If you've overridden /_elements/javascript in your app, you'll want to
+ take a look at the new stock version to see what has changed.
+
+ * The JS method document.getElementsBySelector() no longer exists. Use
+ cssQuery() instead.
+
+* The keybinding JS code is now a more proper library
+ (Jifty.KeyBindings) and less intrusive. If you've overridden the
+ default /_elements/wrapper in your app, you'll want to make sure you get
+ rid of the keybinding javascript (see the stock wrapper). Just include
+ <& /_elements/keybindings &> wherever you want the keybindings for a
+ page to appear.
+
+* This shouldn't be the cause of breakage, but the included rico.js is
+ no longer a stock Rico build. See the comments at the top of the file
+ if you're interested.
+
+
0.60507 (7 May 2006)
* Pod fixes from Eric Wilhelm
Modified: jifty/trunk/lib/Jifty/Action.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Action.pm (original)
+++ jifty/trunk/lib/Jifty/Action.pm Tue May 23 11:02:05 2006
@@ -423,8 +423,14 @@
submit => $self,
@_);
- Jifty->web->form->register_action( $self );
- Jifty->web->form->print_action_registration($self->moniker);
+ # Unless we've printed a moniker for the action, we embed the
+ # action registration into the button
+ unless ( Jifty->web->form->printed_actions->{ $self->moniker } ) {
+ $args{parameters}{ $self->register_name } = ref $self;
+ $args{parameters}{ $self->double_fallback_form_field_name($_) }
+ = $self->argument_value($_) || $self->arguments->{$_}->{'default_value'}
+ for grep { $self->arguments->{$_}{constructor} } keys %{ $self->arguments };
+ }
$args{parameters}{$self->form_field_name($_)} = $args{arguments}{$_}
for keys %{$args{arguments}};
Modified: jifty/trunk/lib/Jifty/Web.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web.pm (original)
+++ jifty/trunk/lib/Jifty/Web.pm Tue May 23 11:02:05 2006
@@ -707,7 +707,7 @@
sub link {
my $self = shift;
- return Jifty::Web::Form::Clickable->new(@_)->generate->render;
+ return Jifty::Web::Form::Clickable->new(@_)->generate;
}
=head3 return PARAMHASH
Modified: jifty/trunk/lib/Jifty/Web/Form.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form.pm (original)
+++ jifty/trunk/lib/Jifty/Web/Form.pm Tue May 23 11:02:05 2006
@@ -230,7 +230,7 @@
my $action = $self->has_action($moniker);
return unless ($action);
return if exists $self->printed_actions->{$moniker};
- $self->printed_actions->{$moniker} = 1;
+ $self->printed_actions->{$moniker} = 1;
$action->register();
Modified: jifty/trunk/lib/Jifty/Web/Form/Element.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form/Element.pm (original)
+++ jifty/trunk/lib/Jifty/Web/Form/Element.pm Tue May 23 11:02:05 2006
@@ -258,7 +258,7 @@
my $self = shift;
my $key = $self->key_binding;
if ($key) {
- Jifty->web->out( "<script><!--\naddKeyBinding(" . "'"
+ Jifty->web->out( "<script><!--\nJifty.KeyBindings.add(" . "'"
. uc($key) . "', "
. "'click', " . "'"
. $self->id . "'," . "'"
Modified: jifty/trunk/lib/Jifty/Web/Form/Field.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form/Field.pm (original)
+++ jifty/trunk/lib/Jifty/Web/Form/Field.pm Tue May 23 11:02:05 2006
@@ -45,7 +45,7 @@
use Scalar::Util;
use HTML::Entities;
-use overload '""' => sub {shift->render};
+use overload '""' => sub { shift->render};
=head2 new
Modified: jifty/trunk/lib/Jifty/Web/Form/Link.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Form/Link.pm (original)
+++ jifty/trunk/lib/Jifty/Web/Form/Link.pm Tue May 23 11:02:05 2006
@@ -17,6 +17,9 @@
use base qw/Jifty::Web::Form::Element Class::Accessor::Fast/;
+# Since we don't inherit from Form::Field, we don't otherwise stringify
+use overload '""' => sub { shift->render};
+
=head2 accessors
Link adds C<url> and C<escape_label> to the list of possible accessors
Modified: jifty/trunk/lib/Jifty/Web/Menu.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Menu.pm (original)
+++ jifty/trunk/lib/Jifty/Web/Menu.pm Tue May 23 11:02:05 2006
@@ -3,7 +3,7 @@
use base qw/Class::Accessor::Fast/;
use URI;
-__PACKAGE__->mk_accessors(qw(label parent sort_order));
+__PACKAGE__->mk_accessors(qw(label parent sort_order link));
=head2 new PARAMHASH
@@ -14,6 +14,14 @@
=cut
+sub new {
+ my $package = shift;
+ # Class::Accessor only wants a hashref;
+ $package->SUPER::new( ref($_[0]) eq 'HASH' ? @_ : {@_} );
+
+}
+
+
=head2 label [STRING]
Sets or returns the string that the menu item will be displayed as.
@@ -28,6 +36,14 @@
Gets or sets the sort order of the item, as it will be displayed under
the parent. This defaults to adding onto the end.
+
+=head2 link
+
+Gets or set a Jifty::Web::Link object that represents this menu item. If
+you're looking to do complex ajaxy things with menus, this is likely
+the option you want.
+
+
=head2 url
Gets or sets the URL that the menu's link goes to. If the link
@@ -146,4 +162,42 @@
return wantarray ? @kids : \@kids;
}
+
+sub render_as_context_menu {
+ my $self = shift;
+ my @kids = $self->children;
+ my $id = Jifty->web->serial;
+ Jifty->web->out(
+ qq{<ul class="context_menu">} .qq{<li class="closed toplevel">}. qq{<span class="title">} . $self->label() . qq{</span>}
+ . (
+ @kids
+ ? qq{<span class="expand"><a href="#" onClick="Jifty.ContextMenu.hideshow('}.$id.qq{'); return false;">+</a></span>}
+ : ''
+ )
+ . qq{<ul id="}.$id. qq{">}
+ );
+ for (@kids) {
+ Jifty->web->out("<li>");
+
+ # We should be able to get this as a string.
+ $_->as_link;
+ Jifty->web->out("</li>");
+ }
+
+ Jifty->web->out(qq{</ul></li></ul>});
+ '';
+
+}
+
+=head2 as_link
+
+Return this menu item as a C<Jifty::Web::Link>, either the one we were initialized with or a new one made from the C</label> and c</url>
+
+=cut
+
+sub as_link {
+ my $self = shift;
+ ($self->link ? $self->link : Jifty->web->link(label => _($self->label), url => $self->url));
+}
+
1;
Modified: jifty/trunk/plugins/EditInPlace/META.yml
==============================================================================
--- jifty/trunk/plugins/EditInPlace/META.yml (original)
+++ jifty/trunk/plugins/EditInPlace/META.yml Tue May 23 11:02:05 2006
@@ -1,5 +1,7 @@
+build_requires:
+ ExtUtils::MakeMaker: 6.11
distribution_type: module
-generated_by: Module::Install version 0.610
+generated_by: Module::Install version 0.620
license: unknown
name: Jifty-Plugin-EditInPlace
no_index:
Added: jifty/trunk/share/web/static/css/context-menus.css
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/css/context-menus.css Tue May 23 11:02:05 2006
@@ -0,0 +1,101 @@
+ul.context_menu {
+ clear: none;
+ float: left;
+}
+
+ul.context_menu, ul.context_menu ul {
+ list-style: none;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+.context_menu li.toplevel {
+ float: left;
+ margin: 0 0.5em 0 0;
+ padding: 0.2em;
+
+ border: 1px solid #ccc;
+ border-top-color: white;
+ border-left-color: white;
+
+ color: #793300;
+}
+
+.context_menu li.toplevel ul li {
+ color: gray;
+}
+
+.context_menu li.toplevel .title {
+ font-weight: bold;
+}
+
+.context_menu li.toplevel ul {
+ font-size: 0.9em;
+ display: none;
+
+ padding: 0.1em 0.2em 0.5em 0.1em;
+ background: white;
+ border-top: 1px dotted lightgrey;
+ border-left: 1px solid lightgrey;
+ border-right: 1px solid grey;
+ border-bottom: 1px solid grey;
+}
+
+.context_menu li.toplevel ul a {
+ width: 100%;
+ display: block;
+}
+
+.context_menu .open span.expand a {
+ background-image: url(/static/images/silk/bullet_arrow_up.png);
+}
+
+.context_menu span.expand a {
+ background: url(/static/images/silk/bullet_arrow_down.png) no-repeat center center;
+ padding-left: 16px;
+ border: 1px solid transparent;
+ color: white;
+ margin-left: 0.3em;
+}
+
+.context_menu li.toplevel:hover .expand a {
+ border-top: 1px solid grey;
+ border-left: 1px solid grey;
+ border-right: 1px solid lightgrey;
+ border-bottom: 1px solid lightgrey;
+}
+
+.context_menu li.open a {
+ border-bottom-color: transparent;
+}
+
+.context_menu li.open, .context_menu li.closed:hover {
+ border-top: 1px solid lightgrey;
+ border-left: 1px solid lightgrey;
+ border-right: 1px solid grey;
+ border-bottom-color: transparent;
+}
+
+.context_menu li.closed:hover {
+ border-bottom-color: grey;
+}
+
+.context_menu li.toplevel span.expand a:active {
+ border-top: 1px solid white;
+ border-left: 1px solid white;
+ border-right: 1px solid grey;
+ border-bottom: 1px solid grey;
+
+ position: relative;
+ top: 1px;
+ left: 1px;
+}
+
+.context_menu li ul li {
+ padding: 0.2em;
+}
+
+.context_menu li.open ul li:hover {
+ background: #eee;
+}
+
Modified: jifty/trunk/share/web/static/css/main.css
==============================================================================
--- jifty/trunk/share/web/static/css/main.css (original)
+++ jifty/trunk/share/web/static/css/main.css Tue May 23 11:02:05 2006
@@ -1,6 +1,7 @@
@import "app-base.css";
@import "base.css";
@import "nav.css";
+ at import "context-menus.css";
@import "calendar.css";
@import "combobox.css";
@import "keybindings.css";
Added: jifty/trunk/share/web/static/images/silk/bullet_arrow_down.png
==============================================================================
Binary file. No diff available.
Added: jifty/trunk/share/web/static/images/silk/bullet_arrow_up.png
==============================================================================
Binary file. No diff available.
Modified: jifty/trunk/share/web/static/js/behaviour.js
==============================================================================
--- jifty/trunk/share/web/static/js/behaviour.js (original)
+++ jifty/trunk/share/web/static/js/behaviour.js Tue May 23 11:02:05 2006
@@ -1,257 +1,55 @@
/*
- Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
- of Simon Willison (see comments by Simon below).
-
- Description:
-
- Uses css selectors to apply javascript behaviours to enable
- unobtrusive javascript in html documents.
-
+ Modified to fix some bugs, use a different css query engine, and to
+ to use JSAN classes.
+
+ Based on Behaviour v1.1 by Ben Nolan, June 2005, which was based
+ largely on the work of Simon Willison.
+
Usage:
- var myrules = {
- 'b.someclass' : function(element){
- element.onclick = function(){
- alert(this.innerHTML);
- }
- },
- '#someid u' : function(element){
- element.onmouseover = function(){
- this.innerHTML = "BLAH!";
- }
- }
- };
-
- Behaviour.register(myrules);
-
- // Call Behaviour.apply() to re-apply the rules (if you
- // update the dom, etc).
+ var myrules = {
+ 'b.someclass' : function(element){
+ element.onclick = function(){
+ alert(this.innerHTML);
+ }
+ },
+ '#someid u' : function(element){
+ element.onmouseover = function(){
+ this.innerHTML = "BLAH!";
+ }
+ }
+ };
+
+ Behaviour.register(myrules);
+
+ // Call Behaviour.apply() to re-apply the rules (if you
+ // update the dom, etc).
- License:
-
- My stuff is BSD licensed. Not sure about Simon's.
-
- More information:
-
- http://ripcord.co.nz/behaviour/
-
*/
-var Behaviour = {
- list : new Array,
-
- register : function(sheet){
- Behaviour.list.push(sheet);
- },
-
- start : function(){
- Behaviour.addLoadEvent(function(){
- Behaviour.apply();
- });
- },
-
- apply : function(){
- for (h=0;sheet=Behaviour.list[h];h++){
- for (selector in sheet){
- list = document.getElementsBySelector(selector);
-
- if (!list){
- continue;
- }
-
- for (i=0;element=list[i];i++){
- sheet[selector](element);
- }
- }
- }
- },
-
- addLoadEvent : function(func){
- var oldonload = window.onload;
-
- if (typeof window.onload != 'function') {
- window.onload = func;
- } else {
- window.onload = function() {
- oldonload();
- func();
- }
- }
- }
-}
-
-Behaviour.start();
-
-/*
- The following code is Copyright (C) Simon Willison 2004.
-
- document.getElementsBySelector(selector)
- - returns an array of element objects from the current document
- matching the CSS selector. Selectors can contain element names,
- class names and ids and can be nested. For example:
-
- elements = document.getElementsBySelect('div#main p a.external')
-
- Will return an array of all 'a' elements with 'external' in their
- class attribute that are contained inside 'p' elements that are
- contained inside the 'div' element which has id="main"
-
- New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
- See http://www.w3.org/TR/css3-selectors/#attribute-selectors
-
- Version 0.4 - Simon Willison, March 25th 2003
- -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
- -- Opera 7 fails
-*/
+JSAN.use("DOM.Events");
+JSAN.use("Upgrade.Array.push");
-function getAllChildren(e) {
- // Returns all children of element. Workaround required for IE5/Windows. Ugh.
- return e.all ? e.all : e.getElementsByTagName('*');
-}
-
-document.getElementsBySelector = function(selector) {
- // Attempt to fail gracefully in lesser browsers
- if (!document.getElementsByTagName) {
- return new Array();
- }
- // Split selector in to tokens
- var tokens = selector.split(' ');
- var currentContext = new Array(document);
- for (var i = 0; i < tokens.length; i++) {
- token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
- if (token.indexOf('#') > -1) {
- // Token is an ID selector
- var bits = token.split('#');
- var tagName = bits[0];
- var id = bits[1];
- var element = document.getElementById(id);
- if (!element) {
- // id doesn't exist on the page; no use continuing
- return new Array();
- } else if (tagName && element.nodeName.toLowerCase() != tagName) {
- // tag with that ID not found, return false
- return new Array();
- }
- // Set currentContext to contain just this element
- currentContext = new Array(element);
- continue; // Skip to next token
- }
- if (token.indexOf('.') > -1) {
- // Token contains a class selector
- var bits = token.split('.');
- var tagName = bits[0];
- var className = bits[1];
- if (!tagName) {
- tagName = '*';
- }
- // Get elements matching tag, filter them for class selector
- var found = new Array;
- var foundCount = 0;
- for (var h = 0; h < currentContext.length; h++) {
- var elements;
- if (tagName == '*') {
- elements = getAllChildren(currentContext[h]);
- } else {
- elements = currentContext[h].getElementsByTagName(tagName);
- }
- for (var j = 0; j < elements.length; j++) {
- found[foundCount++] = elements[j];
- }
- }
- currentContext = new Array;
- var currentContextIndex = 0;
- for (var k = 0; k < found.length; k++) {
- if (found[k].className && found[k].className.match(new RegExp('(^|\\s)'+className+'(\\s|$)'))) {
- currentContext[currentContextIndex++] = found[k];
- }
- }
- continue; // Skip to next token
- }
- // Code to deal with attribute selectors
- if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
- var tagName = RegExp.$1;
- var attrName = RegExp.$2;
- var attrOperator = RegExp.$3;
- var attrValue = RegExp.$4;
- if (!tagName) {
- tagName = '*';
- }
- // Grab all of the tagName elements within current context
- var found = new Array;
- var foundCount = 0;
- for (var h = 0; h < currentContext.length; h++) {
- var elements;
- if (tagName == '*') {
- elements = getAllChildren(currentContext[h]);
- } else {
- elements = currentContext[h].getElementsByTagName(tagName);
- }
- for (var j = 0; j < elements.length; j++) {
- found[foundCount++] = elements[j];
- }
- }
- currentContext = new Array;
- var currentContextIndex = 0;
- var checkFunction; // This function will be used to filter the elements
- switch (attrOperator) {
- case '=': // Equality
- checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
- break;
- case '~': // Match one of space seperated words
- checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
- break;
- case '|': // Match start with value followed by optional hyphen
- checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
- break;
- case '^': // Match starts with value
- checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
- break;
- case '$': // Match ends with value - fails with "Warning" in Opera 7
- checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
- break;
- case '*': // Match ends with value
- checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
- break;
- default :
- // Just test for existence of attribute
- checkFunction = function(e) { return e.getAttribute(attrName); };
- }
- currentContext = new Array;
- var currentContextIndex = 0;
- for (var k = 0; k < found.length; k++) {
- if (checkFunction(found[k])) {
- currentContext[currentContextIndex++] = found[k];
- }
- }
- // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
- continue; // Skip to next token
- }
+var Behaviour = {
+ list: new Array(),
- if (!currentContext[0]){
- return;
- }
+ register: function(sheet) {
+ Behaviour.list.push(sheet);
+ },
- // If we get here, token is JUST an element (not a class or ID selector)
- tagName = token;
- var found = new Array;
- var foundCount = 0;
- for (var h = 0; h < currentContext.length; h++) {
- var elements = currentContext[h].getElementsByTagName(tagName);
- for (var j = 0; j < elements.length; j++) {
- found[foundCount++] = elements[j];
- }
+ apply: function() {
+ for (var h = 0; sheet = Behaviour.list[h]; h++) {
+ for (var selector in sheet) {
+ var elements = cssQuery(selector);
+
+ if ( !elements ) continue;
+
+ for (var i = 0; element = elements[i]; i++)
+ sheet[selector](element);
+ }
+ }
}
- currentContext = found;
- }
- return currentContext;
-}
+}
+
+DOM.Events.addListener( window, "load", Behaviour.apply );
-/* That revolting regular expression explained
-/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
- \---/ \---/\-------------/ \-------/
- | | | |
- | | | The value
- | | ~,|,^,$,* or =
- | Attribute
- Tag
-*/
Added: jifty/trunk/share/web/static/js/context_menu.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/context_menu.js Tue May 23 11:02:05 2006
@@ -0,0 +1,86 @@
+JSAN.use("DOM.Events");
+
+if (typeof Jifty == "undefined") Jifty = { };
+
+Jifty.ContextMenu = {
+ currently_open: "",
+ prevent_stutter: "",
+
+ getParentListItem: function(ul) {
+ /* XXX TODO: Put this in the onclick handler? */
+ return ul.parentNode;
+ },
+
+ hideshow: function(id) {
+ var ul = document.getElementById(id);
+
+ Jifty.ContextMenu.prevent_stutter = id;
+
+ if ( ul.style.display == "block" )
+ Jifty.ContextMenu.hide(id);
+ else
+ Jifty.ContextMenu.show(id);
+ },
+
+ hide: function(id) {
+ var ul = document.getElementById(id);
+
+ var li = Jifty.ContextMenu.getParentListItem(ul);
+ Element.removeClassName(li, "open");
+ Element.addClassName(li, "closed");
+
+ ul.style.display = "none";
+ Jifty.ContextMenu.currently_open = "";
+ },
+
+ show: function(id) {
+ var ul = document.getElementById(id);
+
+ if ( Jifty.ContextMenu.currently_open
+ && Jifty.ContextMenu.currently_open != ul.id )
+ {
+ Jifty.ContextMenu.hide(Jifty.ContextMenu.currently_open);
+ }
+
+ var li = Jifty.ContextMenu.getParentListItem(ul);
+
+ if ( ul.style.position == "" ) {
+ var x = Jifty.Utils.findPosX( li );
+ var y = Jifty.Utils.findPosY( li ) + li.offsetHeight;
+
+ ul.style.position = "absolute";
+ ul.style.left = x + "px";
+ ul.style.top = y + "px";
+ ul.style.width = li.offsetWidth * 2 + "px";
+ }
+
+ Element.removeClassName(li, "closed");
+ Element.addClassName(li, "open");
+
+ ul.style.display = "block";
+ Jifty.ContextMenu.currently_open = ul.id;
+ },
+
+ hideOpenMenu: function(event) {
+ /* This is a bloody hack to deal with the Document based listener
+ firing just before our listener on the link.
+ If both fire, the window closes and then opens again.
+ */
+ if ( Jifty.ContextMenu.prevent_stutter
+ && Jifty.ContextMenu.prevent_stutter == Jifty.ContextMenu.currently_open)
+ {
+ Jifty.ContextMenu.prevent_stutter = "";
+ return;
+ }
+ else {
+ Jifty.ContextMenu.prevent_stutter = "";
+ }
+
+ if (Jifty.ContextMenu.currently_open) {
+ Jifty.ContextMenu.hide(Jifty.ContextMenu.currently_open);
+ }
+ }
+};
+
+DOM.Events.addListener( window, "click", Jifty.ContextMenu.hideOpenMenu );
+
Added: jifty/trunk/share/web/static/js/cssquery/cssQuery-level2.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/cssquery/cssQuery-level2.js Tue May 23 11:02:05 2006
@@ -0,0 +1,142 @@
+/*
+ cssQuery, version 2.0.2 (2005-08-19)
+ Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+cssQuery.addModule("css-level2", function() {
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// child selector
+selectors[">"] = function($results, $from, $tagName, $namespace) {
+ var $element, i, j;
+ for (i = 0; i < $from.length; i++) {
+ var $subset = childElements($from[i]);
+ for (j = 0; ($element = $subset[j]); j++)
+ if (compareTagName($element, $tagName, $namespace))
+ $results.push($element);
+ }
+};
+
+// sibling selector
+selectors["+"] = function($results, $from, $tagName, $namespace) {
+ for (var i = 0; i < $from.length; i++) {
+ var $element = nextElementSibling($from[i]);
+ if ($element && compareTagName($element, $tagName, $namespace))
+ $results.push($element);
+ }
+};
+
+// attribute selector
+selectors["@"] = function($results, $from, $attributeSelectorID) {
+ var $test = attributeSelectors[$attributeSelectorID].test;
+ var $element, i;
+ for (i = 0; ($element = $from[i]); i++)
+ if ($test($element)) $results.push($element);
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+pseudoClasses["first-child"] = function($element) {
+ return !previousElementSibling($element);
+};
+
+pseudoClasses["lang"] = function($element, $code) {
+ $code = new RegExp("^" + $code, "i");
+ while ($element && !$element.getAttribute("lang")) $element = $element.parentNode;
+ return $element && $code.test($element.getAttribute("lang"));
+};
+
+// -----------------------------------------------------------------------
+// attribute selectors
+// -----------------------------------------------------------------------
+
+// constants
+AttributeSelector.NS_IE = /\\:/g;
+AttributeSelector.PREFIX = "@";
+// properties
+AttributeSelector.tests = {};
+// methods
+AttributeSelector.replace = function($match, $attribute, $namespace, $compare, $value) {
+ var $key = this.PREFIX + $match;
+ if (!attributeSelectors[$key]) {
+ $attribute = this.create($attribute, $compare || "", $value || "");
+ // store the selector
+ attributeSelectors[$key] = $attribute;
+ attributeSelectors.push($attribute);
+ }
+ return attributeSelectors[$key].id;
+};
+AttributeSelector.parse = function($selector) {
+ $selector = $selector.replace(this.NS_IE, "|");
+ var $match;
+ while ($match = $selector.match(this.match)) {
+ var $replace = this.replace($match[0], $match[1], $match[2], $match[3], $match[4]);
+ $selector = $selector.replace(this.match, $replace);
+ }
+ return $selector;
+};
+AttributeSelector.create = function($propertyName, $test, $value) {
+ var $attributeSelector = {};
+ $attributeSelector.id = this.PREFIX + attributeSelectors.length;
+ $attributeSelector.name = $propertyName;
+ $test = this.tests[$test];
+ $test = $test ? $test(this.getAttribute($propertyName), getText($value)) : false;
+ $attributeSelector.test = new Function("e", "return " + $test);
+ return $attributeSelector;
+};
+AttributeSelector.getAttribute = function($name) {
+ switch ($name.toLowerCase()) {
+ case "id":
+ return "e.id";
+ case "class":
+ return "e.className";
+ case "for":
+ return "e.htmlFor";
+ case "href":
+ if (isMSIE) {
+ // IE always returns the full path not the fragment in the href attribute
+ // so we RegExp it out of outerHTML. Opera does the same thing but there
+ // is no way to get the original attribute.
+ return "String((e.outerHTML.match(/href=\\x22?([^\\s\\x22]*)\\x22?/)||[])[1]||'')";
+ }
+ }
+ return "e.getAttribute('" + $name.replace($NAMESPACE, ":") + "')";
+};
+
+// -----------------------------------------------------------------------
+// attribute selector tests
+// -----------------------------------------------------------------------
+
+AttributeSelector.tests[""] = function($attribute) {
+ return $attribute;
+};
+
+AttributeSelector.tests["="] = function($attribute, $value) {
+ return $attribute + "==" + Quote.add($value);
+};
+
+AttributeSelector.tests["~="] = function($attribute, $value) {
+ return "/(^| )" + regEscape($value) + "( |$)/.test(" + $attribute + ")";
+};
+
+AttributeSelector.tests["|="] = function($attribute, $value) {
+ return "/^" + regEscape($value) + "(-|$)/.test(" + $attribute + ")";
+};
+
+// -----------------------------------------------------------------------
+// parsing
+// -----------------------------------------------------------------------
+
+// override parseSelector to parse out attribute selectors
+var _parseSelector = parseSelector;
+parseSelector = function($selector) {
+ return _parseSelector(AttributeSelector.parse($selector));
+};
+
+}); // addModule
Added: jifty/trunk/share/web/static/js/cssquery/cssQuery-level3.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/cssquery/cssQuery-level3.js Tue May 23 11:02:05 2006
@@ -0,0 +1,150 @@
+/*
+ cssQuery, version 2.0.2 (2005-08-19)
+ Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+/* Thanks to Bill Edney */
+
+cssQuery.addModule("css-level3", function() {
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// indirect sibling selector
+selectors["~"] = function($results, $from, $tagName, $namespace) {
+ var $element, i;
+ for (i = 0; ($element = $from[i]); i++) {
+ while ($element = nextElementSibling($element)) {
+ if (compareTagName($element, $tagName, $namespace))
+ $results.push($element);
+ }
+ }
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+// I'm hoping these pseudo-classes are pretty readable. Let me know if
+// any need explanation.
+
+pseudoClasses["contains"] = function($element, $text) {
+ $text = new RegExp(regEscape(getText($text)));
+ return $text.test(getTextContent($element));
+};
+
+pseudoClasses["root"] = function($element) {
+ return $element == getDocument($element).documentElement;
+};
+
+pseudoClasses["empty"] = function($element) {
+ var $node, i;
+ for (i = 0; ($node = $element.childNodes[i]); i++) {
+ if (thisElement($node) || $node.nodeType == 3) return false;
+ }
+ return true;
+};
+
+pseudoClasses["last-child"] = function($element) {
+ return !nextElementSibling($element);
+};
+
+pseudoClasses["only-child"] = function($element) {
+ $element = $element.parentNode;
+ return firstElementChild($element) == lastElementChild($element);
+};
+
+pseudoClasses["not"] = function($element, $selector) {
+ var $negated = cssQuery($selector, getDocument($element));
+ for (var i = 0; i < $negated.length; i++) {
+ if ($negated[i] == $element) return false;
+ }
+ return true;
+};
+
+pseudoClasses["nth-child"] = function($element, $arguments) {
+ return nthChild($element, $arguments, previousElementSibling);
+};
+
+pseudoClasses["nth-last-child"] = function($element, $arguments) {
+ return nthChild($element, $arguments, nextElementSibling);
+};
+
+pseudoClasses["target"] = function($element) {
+ return $element.id == location.hash.slice(1);
+};
+
+// UI element states
+
+pseudoClasses["checked"] = function($element) {
+ return $element.checked;
+};
+
+pseudoClasses["enabled"] = function($element) {
+ return $element.disabled === false;
+};
+
+pseudoClasses["disabled"] = function($element) {
+ return $element.disabled;
+};
+
+pseudoClasses["indeterminate"] = function($element) {
+ return $element.indeterminate;
+};
+
+// -----------------------------------------------------------------------
+// attribute selector tests
+// -----------------------------------------------------------------------
+
+AttributeSelector.tests["^="] = function($attribute, $value) {
+ return "/^" + regEscape($value) + "/.test(" + $attribute + ")";
+};
+
+AttributeSelector.tests["$="] = function($attribute, $value) {
+ return "/" + regEscape($value) + "$/.test(" + $attribute + ")";
+};
+
+AttributeSelector.tests["*="] = function($attribute, $value) {
+ return "/" + regEscape($value) + "/.test(" + $attribute + ")";
+};
+
+// -----------------------------------------------------------------------
+// nth child support (Bill Edney)
+// -----------------------------------------------------------------------
+
+function nthChild($element, $arguments, $traverse) {
+ switch ($arguments) {
+ case "n": return true;
+ case "even": $arguments = "2n"; break;
+ case "odd": $arguments = "2n+1";
+ }
+
+ var $$children = childElements($element.parentNode);
+ function _checkIndex($index) {
+ var $index = ($traverse == nextElementSibling) ? $$children.length - $index : $index - 1;
+ return $$children[$index] == $element;
+ };
+
+ // it was just a number (no "n")
+ if (!isNaN($arguments)) return _checkIndex($arguments);
+
+ $arguments = $arguments.split("n");
+ var $multiplier = parseInt($arguments[0]);
+ var $step = parseInt($arguments[1]);
+
+ if ((isNaN($multiplier) || $multiplier == 1) && $step == 0) return true;
+ if ($multiplier == 0 && !isNaN($step)) return _checkIndex($step);
+ if (isNaN($step)) $step = 0;
+
+ var $count = 1;
+ while ($element = $traverse($element)) $count++;
+
+ if (isNaN($multiplier) || $multiplier == 1)
+ return ($traverse == nextElementSibling) ? ($count <= $step) : ($step >= $count);
+
+ return ($count % $multiplier) == $step;
+};
+
+}); // addModule
Added: jifty/trunk/share/web/static/js/cssquery/cssQuery-standard.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/cssquery/cssQuery-standard.js Tue May 23 11:02:05 2006
@@ -0,0 +1,53 @@
+/*
+ cssQuery, version 2.0.2 (2005-08-19)
+ Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+cssQuery.addModule("css-standard", function() { // override IE optimisation
+
+// cssQuery was originally written as the CSS engine for IE7. It is
+// optimised (in terms of size not speed) for IE so this module is
+// provided separately to provide cross-browser support.
+
+// -----------------------------------------------------------------------
+// browser compatibility
+// -----------------------------------------------------------------------
+
+// sniff for Win32 Explorer
+isMSIE = eval("false;/*@cc_on at if(@\x5fwin32)isMSIE=true at end@*/");
+
+if (!isMSIE) {
+ getElementsByTagName = function($element, $tagName, $namespace) {
+ return $namespace ? $element.getElementsByTagNameNS("*", $tagName) :
+ $element.getElementsByTagName($tagName);
+ };
+
+ compareNamespace = function($element, $namespace) {
+ return !$namespace || ($namespace == "*") || ($element.prefix == $namespace);
+ };
+
+ isXML = document.contentType ? function($element) {
+ return /xml/i.test(getDocument($element).contentType);
+ } : function($element) {
+ return getDocument($element).documentElement.tagName != "HTML";
+ };
+
+ getTextContent = function($element) {
+ // mozilla || opera || other
+ return $element.textContent || $element.innerText || _getTextContent($element);
+ };
+
+ function _getTextContent($element) {
+ var $textContent = "", $node, i;
+ for (i = 0; ($node = $element.childNodes[i]); i++) {
+ switch ($node.nodeType) {
+ case 11: // document fragment
+ case 1: $textContent += _getTextContent($node); break;
+ case 3: $textContent += $node.nodeValue; break;
+ }
+ }
+ return $textContent;
+ };
+}
+}); // addModule
Added: jifty/trunk/share/web/static/js/cssquery/cssQuery.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/cssquery/cssQuery.js Tue May 23 11:02:05 2006
@@ -0,0 +1,356 @@
+/*
+ cssQuery, version 2.0.2 (2005-08-19)
+ Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+// the following functions allow querying of the DOM using CSS selectors
+var cssQuery = function() {
+var version = "2.0.2";
+
+// -----------------------------------------------------------------------
+// main query function
+// -----------------------------------------------------------------------
+
+var $COMMA = /\s*,\s*/;
+var cssQuery = function($selector, $$from) {
+try {
+ var $match = [];
+ var $useCache = arguments.callee.caching && !$$from;
+ var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];
+ // process comma separated selectors
+ var $$selectors = parseSelector($selector).split($COMMA), i;
+ for (i = 0; i < $$selectors.length; i++) {
+ // convert the selector to a stream
+ $selector = _toStream($$selectors[i]);
+ // faster chop if it starts with id (MSIE only)
+ if (isMSIE && $selector.slice(0, 3).join("") == " *#") {
+ $selector = $selector.slice(2);
+ $$from = _msie_selectById([], $base, $selector[1]);
+ } else $$from = $base;
+ // process the stream
+ var j = 0, $token, $filter, $arguments, $cacheSelector = "";
+ while (j < $selector.length) {
+ $token = $selector[j++];
+ $filter = $selector[j++];
+ $cacheSelector += $token + $filter;
+ // some pseudo-classes allow arguments to be passed
+ // e.g. nth-child(even)
+ $arguments = "";
+ if ($selector[j] == "(") {
+ while ($selector[j++] != ")" && j < $selector.length) {
+ $arguments += $selector[j];
+ }
+ $arguments = $arguments.slice(0, -1);
+ $cacheSelector += "(" + $arguments + ")";
+ }
+ // process a token/filter pair use cached results if possible
+ $$from = ($useCache && cache[$cacheSelector]) ?
+ cache[$cacheSelector] : select($$from, $token, $filter, $arguments);
+ if ($useCache) cache[$cacheSelector] = $$from;
+ }
+ $match = $match.concat($$from);
+ }
+ delete cssQuery.error;
+ return $match;
+} catch ($error) {
+ cssQuery.error = $error;
+ return [];
+}};
+
+// -----------------------------------------------------------------------
+// public interface
+// -----------------------------------------------------------------------
+
+cssQuery.toString = function() {
+ return "function cssQuery() {\n [version " + version + "]\n}";
+};
+
+// caching
+var cache = {};
+cssQuery.caching = false;
+cssQuery.clearCache = function($selector) {
+ if ($selector) {
+ $selector = _toStream($selector).join("");
+ delete cache[$selector];
+ } else cache = {};
+};
+
+// allow extensions
+var modules = {};
+var loaded = false;
+cssQuery.addModule = function($name, $script) {
+ if (loaded) eval("$script=" + String($script));
+ modules[$name] = new $script();;
+};
+
+// hackery
+cssQuery.valueOf = function($code) {
+ return $code ? eval($code) : this;
+};
+
+// -----------------------------------------------------------------------
+// declarations
+// -----------------------------------------------------------------------
+
+var selectors = {};
+var pseudoClasses = {};
+// a safari bug means that these have to be declared here
+var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};
+var attributeSelectors = [];
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// descendant selector
+selectors[" "] = function($results, $from, $tagName, $namespace) {
+ // loop through current selection
+ var $element, i, j;
+ for (i = 0; i < $from.length; i++) {
+ // get descendants
+ var $subset = getElementsByTagName($from[i], $tagName, $namespace);
+ // loop through descendants and add to results selection
+ for (j = 0; ($element = $subset[j]); j++) {
+ if (thisElement($element) && compareNamespace($element, $namespace))
+ $results.push($element);
+ }
+ }
+};
+
+// ID selector
+selectors["#"] = function($results, $from, $id) {
+ // loop through current selection and check ID
+ var $element, j;
+ for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);
+};
+
+// class selector
+selectors["."] = function($results, $from, $className) {
+ // create a RegExp version of the class
+ $className = new RegExp("(^|\\s)" + $className + "(\\s|$)");
+ // loop through current selection and check class
+ var $element, i;
+ for (i = 0; ($element = $from[i]); i++)
+ if ($className.test($element.className)) $results.push($element);
+};
+
+// pseudo-class selector
+selectors[":"] = function($results, $from, $pseudoClass, $arguments) {
+ // retrieve the cssQuery pseudo-class function
+ var $test = pseudoClasses[$pseudoClass], $element, i;
+ // loop through current selection and apply pseudo-class filter
+ if ($test) for (i = 0; ($element = $from[i]); i++)
+ // if the cssQuery pseudo-class function returns "true" add the element
+ if ($test($element, $arguments)) $results.push($element);
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+pseudoClasses["link"] = function($element) {
+ var $document = getDocument($element);
+ if ($document.links) for (var i = 0; i < $document.links.length; i++) {
+ if ($document.links[i] == $element) return true;
+ }
+};
+
+pseudoClasses["visited"] = function($element) {
+ // can't do this without jiggery-pokery
+};
+
+// -----------------------------------------------------------------------
+// DOM traversal
+// -----------------------------------------------------------------------
+
+// IE5/6 includes comments (LOL) in it's elements collections.
+// so we have to check for this. the test is tagName != "!". LOL (again).
+var thisElement = function($element) {
+ return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;
+};
+
+// return the previous element to the supplied element
+// previousSibling is not good enough as it might return a text or comment node
+var previousElementSibling = function($element) {
+ while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;
+ return $element;
+};
+
+// return the next element to the supplied element
+var nextElementSibling = function($element) {
+ while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;
+ return $element;
+};
+
+// return the first child ELEMENT of an element
+// NOT the first child node (though they may be the same thing)
+var firstElementChild = function($element) {
+ return thisElement($element.firstChild) || nextElementSibling($element.firstChild);
+};
+
+var lastElementChild = function($element) {
+ return thisElement($element.lastChild) || previousElementSibling($element.lastChild);
+};
+
+// return child elements of an element (not child nodes)
+var childElements = function($element) {
+ var $childElements = [];
+ $element = firstElementChild($element);
+ while ($element) {
+ $childElements.push($element);
+ $element = nextElementSibling($element);
+ }
+ return $childElements;
+};
+
+// -----------------------------------------------------------------------
+// browser compatibility
+// -----------------------------------------------------------------------
+
+// all of the functions in this section can be overwritten. the default
+// configuration is for IE. The functions below reflect this. standard
+// methods are included in a separate module. It would probably be better
+// the other way round of course but this makes it easier to keep IE7 trim.
+
+var isMSIE = true;
+
+var isXML = function($element) {
+ var $document = getDocument($element);
+ return (typeof $document.mimeType == "unknown") ?
+ /\.xml$/i.test($document.URL) :
+ Boolean($document.mimeType == "XML Document");
+};
+
+// return the element's containing document
+var getDocument = function($element) {
+ return $element.ownerDocument || $element.document;
+};
+
+var getElementsByTagName = function($element, $tagName) {
+ return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);
+};
+
+var compareTagName = function($element, $tagName, $namespace) {
+ if ($tagName == "*") return thisElement($element);
+ if (!compareNamespace($element, $namespace)) return false;
+ if (!isXML($element)) $tagName = $tagName.toUpperCase();
+ return $element.tagName == $tagName;
+};
+
+var compareNamespace = function($element, $namespace) {
+ return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);
+};
+
+var getTextContent = function($element) {
+ return $element.innerText;
+};
+
+function _msie_selectById($results, $from, id) {
+ var $match, i, j;
+ for (i = 0; i < $from.length; i++) {
+ if ($match = $from[i].all.item(id)) {
+ if ($match.id == id) $results.push($match);
+ else if ($match.length != null) {
+ for (j = 0; j < $match.length; j++) {
+ if ($match[j].id == id) $results.push($match[j]);
+ }
+ }
+ }
+ }
+ return $results;
+};
+
+// for IE5.0
+if (![].push) Array.prototype.push = function() {
+ for (var i = 0; i < arguments.length; i++) {
+ this[this.length] = arguments[i];
+ }
+ return this.length;
+};
+
+// -----------------------------------------------------------------------
+// query support
+// -----------------------------------------------------------------------
+
+// select a set of matching elements.
+// "from" is an array of elements.
+// "token" is a character representing the type of filter
+// e.g. ">" means child selector
+// "filter" represents the tag name, id or class name that is being selected
+// the function returns an array of matching elements
+var $NAMESPACE = /\|/;
+function select($$from, $token, $filter, $arguments) {
+ if ($NAMESPACE.test($filter)) {
+ $filter = $filter.split($NAMESPACE);
+ $arguments = $filter[0];
+ $filter = $filter[1];
+ }
+ var $results = [];
+ if (selectors[$token]) {
+ selectors[$token]($results, $$from, $filter, $arguments);
+ }
+ return $results;
+};
+
+// -----------------------------------------------------------------------
+// parsing
+// -----------------------------------------------------------------------
+
+// convert css selectors to a stream of tokens and filters
+// it's not a real stream. it's just an array of strings.
+var $STANDARD_SELECT = /^[^\s>+~]/;
+var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;
+function _toStream($selector) {
+ if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;
+ return $selector.match($$STREAM) || [];
+};
+
+var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;
+var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;
+var parseSelector = function($selector) {
+ return $selector
+ // trim whitespace
+ .replace($WHITESPACE, "$1")
+ // e.g. ".class1" --> "*.class1"
+ .replace($IMPLIED_ALL, "$1*$2");
+};
+
+var Quote = {
+ toString: function() {return "'"},
+ match: /^('[^']*')|("[^"]*")$/,
+ test: function($string) {
+ return this.match.test($string);
+ },
+ add: function($string) {
+ return this.test($string) ? $string : this + $string + this;
+ },
+ remove: function($string) {
+ return this.test($string) ? $string.slice(1, -1) : $string;
+ }
+};
+
+var getText = function($text) {
+ return Quote.remove($text);
+};
+
+var $ESCAPE = /([\/()[\]?{}|*+-])/g;
+function regEscape($string) {
+ return $string.replace($ESCAPE, "\\$1");
+};
+
+// -----------------------------------------------------------------------
+// modules
+// -----------------------------------------------------------------------
+
+// -------- >> insert modules here for packaging << -------- \\
+
+loaded = true;
+
+// -----------------------------------------------------------------------
+// return the query function
+// -----------------------------------------------------------------------
+
+return cssQuery;
+
+}(); // cssQuery
Modified: jifty/trunk/share/web/static/js/jifty.js
==============================================================================
--- jifty/trunk/share/web/static/js/jifty.js (original)
+++ jifty/trunk/share/web/static/js/jifty.js Tue May 23 11:02:05 2006
@@ -80,7 +80,7 @@
for (var i = 0; i < fields.length; i++) {
var f = fields[i];
- if ((Form.Element.getType(f) != "registration") && Form.Element.getValue(f)) {
+ if ((Form.Element.getType(f) != "registration") && (Form.Element.getValue(f) != null)) {
if (! a['fields'][Form.Element.getField(f)])
a['fields'][Form.Element.getField(f)] = {};
a['fields'][Form.Element.getField(f)][Form.Element.getType(f)] = Form.Element.getValue(f);
@@ -417,7 +417,7 @@
// Find where we are going to go
var element = $('region-' + f['region']);
if (f['element']) {
- var possible = document.getElementsBySelector(f['element']);
+ var possible = cssQuery(f['element']);
if (possible.length == 0)
element = null;
else
Added: jifty/trunk/share/web/static/js/jifty_utils.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/jifty_utils.js Tue May 23 11:02:05 2006
@@ -0,0 +1,36 @@
+
+if (typeof Jifty == "undefined") Jifty = { };
+
+Jifty.Utils = {
+ /* From http://www.quirksmode.org/js/findpos.html */
+ findPosX: function(obj) {
+ var curleft = 0;
+ if (obj.offsetParent)
+ {
+ while (obj.offsetParent)
+ {
+ curleft += obj.offsetLeft
+ obj = obj.offsetParent;
+ }
+ }
+ else if (obj.x)
+ curleft += obj.x;
+ return curleft;
+ },
+
+ findPosY: function(obj) {
+ var curtop = 0;
+ if (obj.offsetParent)
+ {
+ while (obj.offsetParent)
+ {
+ curtop += obj.offsetTop
+ obj = obj.offsetParent;
+ }
+ }
+ else if (obj.y)
+ curtop += obj.y;
+ return curtop;
+ }
+};
+
Added: jifty/trunk/share/web/static/js/jsan/DOM/Events.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/jsan/DOM/Events.js Tue May 23 11:02:05 2006
@@ -0,0 +1,262 @@
+/**
+
+=head1 NAME
+
+DOM.Events - Event registration abstraction layer
+
+=head1 SYNOPSIS
+
+ JSAN.use("DOM.Events");
+
+ function handleClick(e) {
+ e.currentTarget.style.backgroundColor = "#68b";
+ }
+
+ DOM.Events.addListener(window, "load", function () {
+ alert("The page is loaded.");
+ });
+
+ DOM.Events.addListener(window, "load", function () {
+ // this listener won't interfere with the first one
+ var divs = document.getElementsByTagName("div");
+ for(var i=0; i<divs.length; i++) {
+ DOM.Events.addListener(divs[i], "click", handleClick);
+ }
+ });
+
+=head1 DESCRIPTION
+
+This library lets you use a single interface to listen for and handle all DOM events
+to reduce browser-specific code branching. It also helps in dealing with Internet
+Explorer's memory leak problem by automatically unsetting all event listeners when
+the page is unloaded (for IE only).
+
+=cut
+
+*/
+
+(function () {
+ if(typeof DOM == "undefined") DOM = {};
+ DOM.Events = {};
+
+ DOM.Events.VERSION = "0.02";
+ DOM.Events.EXPORT = [];
+ DOM.Events.EXPORT_OK = ["addListener", "removeListener"];
+ DOM.Events.EXPORT_TAGS = {
+ ":common": DOM.Events.EXPORT,
+ ":all": [].concat(DOM.Events.EXPORT, DOM.Events.EXPORT_OK)
+ };
+
+ // list of event listeners set by addListener
+ // offset 0 is null to prevent 0 from being used as a listener identifier
+ var listenerList = [null];
+
+/**
+
+=head2 Functions
+
+All functions are kept inside the namespace C<DOM.Events> and aren't exported
+automatically.
+
+=head3 addListener( S<I<HTMLElement> element,> S<I<string> eventType,>
+S<I<Function> handler> S<[, I<boolean> makeCompatible = true] )>
+
+Registers an event listener/handler on an element. The C<eventType> string should
+I<not> be prefixed with "on" (e.g. "mouseover" not "onmouseover"). If C<makeCompatible>
+is C<true> (the default), the handler is put inside a wrapper that lets you handle the
+events using parts of the DOM Level 2 Events model, even in Internet Explorer (and
+behave-alikes). Specifically:
+
+=over
+
+=item *
+
+The event object is passed as the first argument to the event handler, so you don't
+have to access it through C<window.event>.
+
+=item *
+
+The event object has the properties C<target>, C<currentTarget>, and C<relatedTarget>
+and the methods C<preventDefault()> and C<stopPropagation()> that behave as described
+in the DOM Level 2 Events specification (for the most part).
+
+=item *
+
+If possible, the event object for mouse events will have the properties C<pageX> and
+C<pageY> that contain the mouse's position relative to the document at the time the
+event occurred.
+
+=item *
+
+If you attempt to set a duplicate event handler on an element, the duplicate will
+still be added (this is different from the DOM2 Events model, where duplicates are
+discarded).
+
+=back
+
+If C<makeCompatible> is C<false>, the arguments are simply passed to the browser's
+native event registering facilities, which means you'll have to deal with event
+incompatibilities yourself. However, if you don't need to access the event information,
+doing it this way can be slightly faster and it gives you the option of unsetting the
+handler with a different syntax (see below).
+
+The return value is a positive integer identifier for the listener that can be used to
+unregister it later on in your script.
+
+=cut
+
+*/
+
+ DOM.Events.addListener = function(elt, ev, func, makeCompatible) {
+ var usedFunc = func;
+ var id = listenerList.length;
+ if(makeCompatible == true || makeCompatible == undefined) {
+ usedFunc = makeCompatibilityWrapper(elt, ev, func);
+ }
+ if(elt.addEventListener) {
+ elt.addEventListener(ev, usedFunc, false);
+ listenerList[id] = [elt, ev, usedFunc];
+ return id;
+ }
+ else if(elt.attachEvent) {
+ elt.attachEvent("on" + ev, usedFunc);
+ listenerList[id] = [elt, ev, usedFunc];
+ return id;
+ }
+ else return false;
+ };
+
+/**
+
+=head3 removeListener( S<I<integer> identifier> )
+
+Unregisters the event listener associated with the given identifier so that it will
+no longer be called when the event fires.
+
+ var listener = DOM.Events.addListener(myElement, "mousedown", myHandler);
+ // later on ...
+ DOM.Events.removeListener(listener);
+
+=head3 removeListener( S<I<HTMLElement> element,> S<I<string> eventType,> S<I<Function> handler )>
+
+This alternative syntax can be also be used to unset an event listener, but it can only
+be used if C<makeCompatible> was C<false> when it was set.
+
+=cut
+
+*/
+
+ DOM.Events.removeListener = function() {
+ var elt, ev, func;
+ if(arguments.length == 1 && listenerList[arguments[0]]) {
+ elt = listenerList[arguments[0]][0];
+ ev = listenerList[arguments[0]][1];
+ func = listenerList[arguments[0]][2];
+ delete listenerList[arguments[0]];
+ }
+ else if(arguments.length == 3) {
+ elt = arguments[0];
+ ev = arguments[1];
+ func = arguments[2];
+ }
+ else return;
+
+ if(elt.removeEventListener) {
+ elt.removeEventListener(ev, func, false);
+ }
+ else if(elt.detachEvent) {
+ elt.detachEvent("on" + ev, func);
+ }
+ };
+
+ var rval;
+
+ function makeCompatibilityWrapper(elt, ev, func) {
+ return function (e) {
+ rval = true;
+ if(e == undefined && window.event != undefined)
+ e = window.event;
+ if(e.target == undefined && e.srcElement != undefined)
+ e.target = e.srcElement;
+ if(e.currentTarget == undefined)
+ e.currentTarget = elt;
+ if(e.relatedTarget == undefined) {
+ if(ev == "mouseover" && e.fromElement != undefined)
+ e.relatedTarget = e.fromElement;
+ else if(ev == "mouseout" && e.toElement != undefined)
+ e.relatedTarget = e.toElement;
+ }
+ if(e.pageX == undefined) {
+ if(document.body.scrollTop != undefined) {
+ e.pageX = e.clientX + document.body.scrollLeft;
+ e.pageY = e.clientY + document.body.scrollTop;
+ }
+ if(document.documentElement != undefined
+ && document.documentElement.scrollTop != undefined) {
+ if(document.documentElement.scrollTop > 0
+ || document.documentElement.scrollLeft > 0) {
+ e.pageX = e.clientX + document.documentElement.scrollLeft;
+ e.pageY = e.clientY + document.documentElement.scrollTop;
+ }
+ }
+ }
+ if(e.stopPropagation == undefined)
+ e.stopPropagation = IEStopPropagation;
+ if(e.preventDefault == undefined)
+ e.preventDefault = IEPreventDefault;
+ if(e.cancelable == undefined) e.cancelable = true;
+ func(e);
+ return rval;
+ };
+ }
+
+ function IEStopPropagation() {
+ if(window.event) window.event.cancelBubble = true;
+ }
+
+ function IEPreventDefault() {
+ rval = false;
+ }
+
+ function cleanUpIE () {
+ for(var i=0; i<listenerList.length; i++) {
+ var listener = listenerList[i];
+ if(listener) {
+ var elt = listener[0];
+ var ev = listener[1];
+ var func = listener[2];
+ elt.detachEvent("on" + ev, func);
+ }
+ }
+ listenerList = null;
+ }
+
+ if(!window.addEventListener && window.attachEvent) {
+ window.attachEvent("onunload", cleanUpIE);
+ }
+
+})();
+
+/**
+
+=head1 SEE ALSO
+
+DOM Level 2 Events Specification,
+L<http://www.w3.org/TR/DOM-Level-2-Events/>
+
+Understanding and Solving Internet Explorer Leak Patterns,
+L<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp>
+
+=head1 AUTHOR
+
+Justin Constantino, <F<goflyapig at gmail.com>>.
+
+=head1 COPYRIGHT
+
+ Copyright (c) 2005 Justin Constantino. All rights reserved.
+ This module is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public Licence.
+
+=cut
+
+*/
\ No newline at end of file
Added: jifty/trunk/share/web/static/js/jsan/JSAN.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/jsan/JSAN.js Tue May 23 11:02:05 2006
@@ -0,0 +1,303 @@
+/*
+ * This is not a stock JSAN.js. To increase browser compatibility,
+ * s/'/"/g has been applied to the file and the range of valid response
+ * codes for JSAN.Request has been expanded (lifted from Prototype, in
+ * fact).
+ */
+
+/*
+
+*/
+
+var JSAN = function () { JSAN.addRepository(arguments) };
+
+JSAN.VERSION = "0.10-jifty2";
+
+/*
+
+*/
+
+JSAN.globalScope = self;
+JSAN.includePath = [".", "lib"];
+JSAN.errorLevel = "none";
+JSAN.errorMessage = "";
+JSAN.loaded = {};
+
+/*
+
+*/
+
+JSAN.use = function () {
+ var classdef = JSAN.require(arguments[0]);
+ if (!classdef) return null;
+
+ var importList = JSAN._parseUseArgs.apply(JSAN, arguments).importList;
+ JSAN.exporter(classdef, importList);
+
+ return classdef;
+}
+
+/*
+
+*/
+
+JSAN.require = function (pkg) {
+ var path = JSAN._convertPackageToPath(pkg);
+ if (JSAN.loaded[path]) {
+ return JSAN.loaded[path];
+ }
+
+ try {
+ var classdef = eval(pkg);
+ if (typeof classdef != "undefined") return classdef;
+ } catch (e) { /* nice try, eh? */ }
+
+
+ for (var i = 0; i < JSAN.includePath.length; i++) {
+ var js;
+ try{
+ var url = JSAN._convertPathToUrl(path, JSAN.includePath[i]);
+ js = JSAN._loadJSFromUrl(url);
+ } catch (e) {
+ if (i == JSAN.includePath.length - 1) throw e;
+ }
+ if (js != null) {
+ var classdef = JSAN._createScript(js, pkg);
+ JSAN.loaded[path] = classdef;
+ return classdef;
+ }
+ }
+ return false;
+
+}
+
+/*
+
+*/
+
+JSAN.exporter = function () {
+ JSAN._exportItems.apply(JSAN, arguments);
+}
+
+/*
+
+*/
+
+JSAN.addRepository = function () {
+ var temp = JSAN._flatten( arguments );
+ // Need to go in reverse to do something as simple as unshift( @foo, @_ );
+ for ( var i = temp.length - 1; i >= 0; i-- )
+ JSAN.includePath.unshift(temp[i]);
+ return JSAN;
+}
+
+JSAN._flatten = function( list1 ) {
+ var list2 = new Array();
+ for ( var i = 0; i < list1.length; i++ ) {
+ if ( typeof list1[i] == "object" ) {
+ list2 = JSAN._flatten( list1[i], list2 );
+ }
+ else {
+ list2.push( list1[i] );
+ }
+ }
+ return list2;
+};
+
+JSAN._findMyPath = function () {
+ if (document) {
+ var scripts = document.getElementsByTagName("script");
+ for ( var i = 0; i < scripts.length; i++ ) {
+ var src = scripts[i].getAttribute("src");
+ if (src) {
+ var inc = src.match(/^(.*?)\/?JSAN.js/);
+ if (inc && inc[1]) {
+ var repo = inc[1];
+ for (var j = 0; j < JSAN.includePath.length; j++) {
+ if (JSAN.includePath[j] == repo) {
+ return;
+ }
+ }
+ JSAN.addRepository(repo);
+ }
+ }
+ }
+ }
+}
+JSAN._findMyPath();
+
+JSAN._convertPathToUrl = function (path, repository) {
+ return repository.concat("/" + path);
+};
+
+
+JSAN._convertPackageToPath = function (pkg) {
+ var path = pkg.replace(/\./g, "/");
+ path = path.concat(".js");
+ return path;
+}
+
+JSAN._parseUseArgs = function () {
+ var pkg = arguments[0];
+ var importList = [];
+
+ for (var i = 1; i < arguments.length; i++)
+ importList.push(arguments[i]);
+
+ return {
+ pkg: pkg,
+ importList: importList
+ }
+}
+
+JSAN._loadJSFromUrl = function (url) {
+ return new JSAN.Request().getText(url);
+}
+
+JSAN._findExportInList = function (list, request) {
+ if (list == null) return false;
+ for (var i = 0; i < list.length; i++)
+ if (list[i] == request)
+ return true;
+ return false;
+}
+
+JSAN._findExportInTag = function (tags, request) {
+ if (tags == null) return [];
+ for (var i in tags)
+ if (i == request)
+ return tags[i];
+ return [];
+}
+
+JSAN._exportItems = function (classdef, importList) {
+ var exportList = new Array();
+ var EXPORT = classdef.EXPORT;
+ var EXPORT_OK = classdef.EXPORT_OK;
+ var EXPORT_TAGS = classdef.EXPORT_TAGS;
+
+ if (importList.length > 0) {
+ importList = JSAN._flatten( importList );
+
+ for (var i = 0; i < importList.length; i++) {
+ var request = importList[i];
+ if ( JSAN._findExportInList(EXPORT, request)
+ || JSAN._findExportInList(EXPORT_OK, request)) {
+ exportList.push(request);
+ continue;
+ }
+ var list = JSAN._findExportInTag(EXPORT_TAGS, request);
+ for (var i = 0; i < list.length; i++) {
+ exportList.push(list[i]);
+ }
+ }
+ } else {
+ exportList = EXPORT;
+ }
+ JSAN._exportList(classdef, exportList);
+}
+
+JSAN._exportList = function (classdef, exportList) {
+ if (typeof(exportList) != "object") return null;
+ for (var i = 0; i < exportList.length; i++) {
+ var name = exportList[i];
+
+ if (JSAN.globalScope[name] == null)
+ JSAN.globalScope[name] = classdef[name];
+ }
+}
+
+JSAN._makeNamespace = function(js, pkg) {
+ var spaces = pkg.split(".");
+ var parent = JSAN.globalScope;
+ eval(js);
+ var classdef = eval(pkg);
+ for (var i = 0; i < spaces.length; i++) {
+ var name = spaces[i];
+ if (i == spaces.length - 1) {
+ if (typeof parent[name] == "undefined") {
+ parent[name] = classdef;
+ if ( typeof classdef["prototype"] != "undefined" ) {
+ parent[name].prototype = classdef.prototype;
+ }
+ }
+ } else {
+ if (parent[name] == undefined) {
+ parent[name] = {};
+ }
+ }
+
+ parent = parent[name];
+ }
+ return classdef;
+}
+
+JSAN._handleError = function (msg, level) {
+ if (!level) level = JSAN.errorLevel;
+ JSAN.errorMessage = msg;
+
+ switch (level) {
+ case "none":
+ break;
+ case "warn":
+ alert(msg);
+ break;
+ case "die":
+ default:
+ throw new Error(msg);
+ break;
+ }
+}
+
+JSAN._createScript = function (js, pkg) {
+ try {
+ return JSAN._makeNamespace(js, pkg);
+ } catch (e) {
+ JSAN._handleError("Could not create namespace[" + pkg + "]: " + e);
+ }
+ return null;
+}
+
+
+JSAN.prototype = {
+ use: function () { JSAN.use.apply(JSAN, arguments) }
+};
+
+
+// Low-Level HTTP Request
+JSAN.Request = function (jsan) {
+ if (JSAN.globalScope.XMLHttpRequest) {
+ this._req = new XMLHttpRequest();
+ } else {
+ this._req = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+}
+
+JSAN.Request.prototype = {
+ _req: null,
+
+ getText: function (url) {
+ this._req.open("GET", url, false);
+ try {
+ this._req.send(null);
+ if ( this.responseIsSuccess() )
+ return this._req.responseText;
+ } catch (e) {
+ JSAN._handleError("File not found: " + url);
+ return null;
+ };
+
+ JSAN._handleError("File not found: " + url);
+ return null;
+ },
+
+ responseIsSuccess: function() {
+ return this._req.status == undefined
+ || this._req.status == 0
+ || (this._req.status >= 200 && this._req.status < 300);
+ }
+};
+
+/*
+
+*/
Added: jifty/trunk/share/web/static/js/jsan/Upgrade.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/jsan/Upgrade.js Tue May 23 11:02:05 2006
@@ -0,0 +1,121 @@
+/*
+Keep package scanners happy
+Upgrade.VERSION = 0.04;
+*/
+
+/*
+
+=head1 NAME
+
+Upgrade - Upgrade older JavaScript implementations to support newer features
+
+=head1 SYNOPSIS
+
+ // Upgrade Array.push if the client does not have it
+ JSAN.use("Upgrade.Array.push");
+
+=head1 DESCRIPTION
+
+Many many different JavaScript toolkits start with something like the following:
+
+ // Provides Array.push for implementations that don't have it
+ if ( ! Array.prototype.push ) {
+ Array.prototype.push = function () {
+ var l = this.length;
+ for ( var i = 0; i < arguments.length; i++ ) {
+ this[l+i] = arguments[i];
+ }
+ return this.length;
+ }
+ }
+
+These provide implementations of expected or required functions/classes
+for older JavaScript implementations that do not provide them natively,
+in effect "upgrading" the client at run-time.
+
+In fact, due to its flexibility JavaScript is a language ideally suited
+to this sort of behaviour.
+
+C<Upgrade> is a JSAN package that provides standard implementations for
+many of these standard functions. If your code relies on a particular
+function that you later find to be not as common as you might have
+initially thought, you can simply add a dependency on that function within
+the C<Upgrade> namespace, and if an implementation exists the standard code
+to implement it will be added it the current environment (when it doesn't
+already have it).
+
+Rather than one huge file that provides a "compatibility layer" and upgrades
+verything all at once, C<Upgrade> is broken down into a large number of
+maller .js files, each implementing one function or class.
+
+Generally these functions are ones defined in the ECMA standard, and those
+that aren't, such as C<HTMLHttpRequest> are not provided by Upgrade (as much
+as we would like to) :)
+
+=head1 USING UPGRADE
+
+The C<Upgrade> namespace acts as a parallel root to the global namespace.
+For any function you want to upgrade, you can then simply prepend
+C<"Upgrade"> to it.
+
+For example, to do the very common upgrade for the C<Array.push> function,
+you simply add C<JSAN.use("Upgrade.Array.push") to your module (or manually
+load the C<Upgrade/Array/push.js> file).
+
+One advantage of using these standard implementations rather than your own
+is that when a number of modules with C<Upgrade> depedencies are merged
+together by C<JSAN::Concat> or another package merger it results in only
+a single copy of the upgrading code at the appropriate place in the code.
+
+=head1 UPGRADABLE FUNCTIONS
+
+While implementations are provided seperately, rather than document them
+this way we will instead defined all functions available in the C<Upgrade>
+package here.
+
+=head2 Upgrade.Array.push
+
+This provides the same standard implementation of the instance method
+C<Array.push> (located at Array.prototype.push) as used by all of the
+major frameworks.
+
+=head2 Upgrade.Function.apply
+
+This provides a version of the instance method C<Function.apply>
+(located at C<Function.prototype.apply>) adapted from an implementation
+found in the L<Prototype> framework, which was itself adapted from an
+implementation found on L<http://www.youngpup.net/>.
+
+=head1 METHODS
+
+The C<Upgrade> module itself does not at this time provide any
+functionality, and only acts as a source of documentation.
+
+Likewise, nothing is ever actually created at or beneath the C<Upgrade>
+namespace, but serves as an address mechanism for determining which
+.js files to load. Each of these files only inserts functions into the
+core tree and do not create any additional useless namespace variables.
+
+=head1 SUPPORT
+
+Until the JSAN RT gains package-specific queues, bugs or new functions
+to add to Upgrade should be reported to the jsan-authors mailing list.
+
+For B<non-support> issues or questions, contact the author.
+
+=head1 AUTHOR
+
+Adam Kennedy <jsan at ali.as>, L<http://ali.as/>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2005 Adam Kennedy. All rights reserved.
+This program is free software; you can redistribute it and/or modify
+it under the the terms of the Perl dual GPL/Artistic license.
+
+The full text of the license can be found in the
+LICENSE file included with this package
+
+=cut
+
+*/
Added: jifty/trunk/share/web/static/js/jsan/Upgrade/Array/push.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/jsan/Upgrade/Array/push.js Tue May 23 11:02:05 2006
@@ -0,0 +1,14 @@
+/*
+Upgrade.Array.push.VERSION = 0.04;
+*/
+
+// Provides Array.push for implementations that don't have it
+if ( ! Array.prototype.push ) {
+ Array.prototype.push = function () {
+ var l = this.length;
+ for ( var i = 0; i < arguments.length; i++ ) {
+ this[l+i] = arguments[i];
+ }
+ return this.length;
+ }
+}
Added: jifty/trunk/share/web/static/js/jsan/Upgrade/Function/apply.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/static/js/jsan/Upgrade/Function/apply.js Tue May 23 11:02:05 2006
@@ -0,0 +1,19 @@
+/*
+Upgrade.Function.Apply.VERSION = 0.04;
+*/
+// Adapted from a Prototype adaptation of code
+// originally from http://www.youngpup.net/
+if ( ! Function.prototype.apply ) {
+ Function.prototype.apply = function(o, p) {
+ var pstr = new Array();
+ if ( ! o ) o = window;
+ if ( ! p ) p = new Array();
+ for ( var i = 0; i < p.length; i++ ) {
+ pstr[i] = 'p[' + i + ']';
+ }
+ o.__apply__ = this;
+ var rv = eval('o.__apply__(' + pstr[i].join(', ') + ')' );
+ o.__apply__ = null;
+ return rv;
+ }
+}
Modified: jifty/trunk/share/web/static/js/key_bindings.js
==============================================================================
--- jifty/trunk/share/web/static/js/key_bindings.js (original)
+++ jifty/trunk/share/web/static/js/key_bindings.js Tue May 23 11:02:05 2006
@@ -1,69 +1,112 @@
-// Copyright 2004-2005, Best Practical Solutions, LLC
+// Copyright 2004-2006, Best Practical Solutions, LLC
// This Library is licensed to you under the same terms as Perl 5.x
-var bindings = Array;
-
-document.onkeydown = doClick;
-function doClick(e) {
- var targ;
- if (!e) var e = window.event;
- if (e.target) targ = e.target;
- else if (e.srcElement) targ = e.srcElement;
- if (targ.nodeType == 3) // defeat Safari bug
- targ = targ.parentNode;
-
- // safari or mozilla
- if ( ( ! e.metaKey && ! e.altKey && ! e.ctrlKey )
- && (
- (targ == document.body) ||
- (targ == document.getElementsByTagName('html')[0])
- ) ){
- var code = String.fromCharCode(e.keyCode);
- var binding = getKeyBinding(code);
- if (binding) {
- if (binding["action"] == "goto") {
- document.location = (binding["data"]);
- }
- else if (binding["action"] == "focus") {
- var elements = document.getElementsByName(binding["data"]);
- elements[0].focus();
- }
- else if (binding["action"] == "click") {
- var elements = document.getElementsByName(binding["data"]);
- elements[0].click();
- }
-
- }
-
-}
-}
-
-function addKeyBinding(key, action, data, label) {
- var binding = new Array;
- binding["action"] = action;
- binding["data"] = data;
- binding["label"] = label;
- bindings[key] = binding;
-}
+JSAN.use("DOM.Events");
+if ( typeof Jifty == "undefined" ) Jifty = {};
-function getKeyBinding(key) {
- return(bindings[key]);
+Jifty.KeyBindings = {
+ bindings: new Array(),
+ listener: null,
+
+ activate: function() {
+ if ( Jifty.KeyBindings.listener )
+ return;
+
+ Jifty.KeyBindings.listener = DOM.Events.addListener(
+ document,
+ "keydown",
+ Jifty.KeyBindings.doClick
+ );
+ },
+
+ deactivate: function() {
+ DOM.Events.removeListener(Jifty.KeyBindings.listener);
+ },
+
+ doClick: function(e) {
+ if (e.target.nodeType == 3) // defeat Safari bug
+ e.target = e.target.parentNode;
+
+ /* XXX TODO: Is there a better way to do this and still support
+ opera?
+ */
+ if ( !e.metaKey && !e.altKey && !e.ctrlKey
+ && !e.target.nodeName.match(/^(INPUT|TEXTAREA)$/) )
+ {
+ var code = String.fromCharCode(e.keyCode);
+ var binding = Jifty.KeyBindings.get(code);
+
+ if (binding) {
+ e.preventDefault();
+
+ if (binding["action"] == "goto") {
+ document.location = (binding["data"]);
+ }
+ else if (binding["action"] == "focus") {
+ var elements = document.getElementsByName(binding["data"]);
+ elements[0].focus();
+ }
+ else if (binding["action"] == "click") {
+ var elements = document.getElementsByName(binding["data"]);
+ elements[0].click();
+ }
+ }
+ }
+ },
+
+ add: function(key, action, data, label) {
+ var binding = new Array();
+ binding["action"] = action;
+ binding["data"] = data;
+ binding["label"] = label;
+ Jifty.KeyBindings.bindings[key] = binding;
+ },
+
+ get: function(key) {
+ return Jifty.KeyBindings.bindings[key];
+ },
+
+ writeLegend: function(e) {
+ if ( !document.createElement
+ || !document.createTextNode
+ || Element.hasClassName(e, 'keybindings-written') )
+ return;
+
+
+ /* definition list */
+ var dl = document.createElement("dl");
+ dl.setAttribute("class", "keybindings");
+
+
+ /* terms of the list */
+
+ for (var key in Jifty.KeyBindings.bindings) {
+ if ( Jifty.KeyBindings.get(key)["label"] ) {
+ var div = document.createElement("div");
+ div.setAttribute("class", "keybinding");
+
+ var dt = document.createElement("dt");
+ dt.appendChild( document.createTextNode( key ) );
+
+ var dd = document.createElement("dd");
+ dd.appendChild( document.createTextNode( Jifty.KeyBindings.get(key)["label"] ) );
+
+ div.appendChild( dt );
+ div.appendChild( dd );
+ dl.appendChild( div );
+ }
+ }
+
+ if ( dl.hasChildNodes() ) {
+ e.appendChild( dl );
+ Element.addClassName(e, 'keybindings-written');
+
+ /* since we wrote the legend, now obey it */
+ Jifty.KeyBindings.activate();
+ }
+ }
}
+Behaviour.register({ "div.keybindings": Jifty.KeyBindings.writeLegend });
-function writeKeyBindingLegend() {
- var content = '';
- for (var key in bindings) {
- if ( bindings[key]['label']) {
- content = content + '<div class="keybinding"><dt>'+key + '</dt>' +'<dd>'+bindings[key]['label'] +'</dd></div>';
- }
- }
- if (content) {
- document.write('<div class="keybindings">');
- document.write('<dl class="keybindings">');
- document.write(content);
- document.write('</dl>');
- document.write('</div>');
- }
-}
Modified: jifty/trunk/share/web/static/js/rico.js
==============================================================================
--- jifty/trunk/share/web/static/js/rico.js (original)
+++ jifty/trunk/share/web/static/js/rico.js Tue May 23 11:02:05 2006
@@ -1,3 +1,12 @@
+/*
+ * This is a slightly modified version of Rico which has improved
+ * corner rounding methods that try to take care of preserving padding.
+ *
+ * Replacing it with a stock Rico probably isn't a good idea unless you
+ * repatch it or don't plan on using any of the corner rounding.
+ *
+ */
+
/**
*
* Copyright 2005 Sabre Airline Solutions
@@ -16,7 +25,7 @@
//-------------------- rico.js
var Rico = {
- Version: '1.1.2',
+ Version: '1.1.2.jifty.r963',
prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
}
@@ -785,7 +794,7 @@
},
_roundTopCorners: function(el, color, bgColor) {
- var corner = this._createCorner(bgColor);
+ var corner = this._createCorner(el, bgColor);
for(var i=0 ; i < this.options.numSlices ; i++ )
corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
el.style.paddingTop = 0;
@@ -793,16 +802,22 @@
},
_roundBottomCorners: function(el, color, bgColor) {
- var corner = this._createCorner(bgColor);
+ var corner = this._createCorner(el, bgColor);
for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
el.style.paddingBottom = 0;
el.appendChild(corner);
},
- _createCorner: function(bgColor) {
+ _createCorner: function(el, bgColor) {
var corner = document.createElement("div");
corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+ var paddingLeft = "-" + RicoUtil.getElementsComputedStyle(el, "paddingLeft", "padding-left");
+ var paddingRight = "-" + RicoUtil.getElementsComputedStyle(el, "paddingRight", "padding-right");
+
+ corner.style.marginRight = paddingRight;
+ corner.style.marginLeft = paddingLeft;
+
return corner;
},
Modified: jifty/trunk/share/web/templates/_elements/javascript
==============================================================================
--- jifty/trunk/share/web/templates/_elements/javascript (original)
+++ jifty/trunk/share/web/templates/_elements/javascript Tue May 23 11:02:05 2006
@@ -4,19 +4,35 @@
my @libs = qw(
/static/js/json.js
/static/js/prototype.js
+ /static/js/cssquery/cssQuery.js
+ /static/js/cssquery/cssQuery-level2.js
+ /static/js/cssquery/cssQuery-level3.js
+ /static/js/cssquery/cssQuery-standard.js
/static/js/behaviour.js
- /static/js/scriptaculous/scriptaculous.js
+ /static/js/scriptaculous/builder.js
+ /static/js/scriptaculous/effects.js
+ /static/js/scriptaculous/controls.js
/static/js/jifty.js
/static/js/dom-drag.js
/static/js/halo.js
/static/js/combobox.js
+ /static/js/jifty_utils.js
/static/js/key_bindings.js
+ /static/js/context_menu.js
/static/js/bps_util.js
/static/js/rico.js
/static/js/app_behaviour.js
);
</%init>
+ <script type="text/javascript" src="/static/js/jsan/JSAN.js"></script>
+ <script type="text/javascript">
+ JSAN.includePath = [ "/static/js/jsan" ];
+ // You might want to change this to "warn" for development
+ JSAN.errorLevel = "none";
+ </script>
+
% for (@libs) {
<script type="text/javascript" src="<%$_%>"></script>
% }
+
Added: jifty/trunk/share/web/templates/_elements/keybindings
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/templates/_elements/keybindings Tue May 23 11:02:05 2006
@@ -0,0 +1 @@
+<div class="keybindings"></div>
Modified: jifty/trunk/share/web/templates/_elements/menu
==============================================================================
--- jifty/trunk/share/web/templates/_elements/menu (original)
+++ jifty/trunk/share/web/templates/_elements/menu Tue May 23 11:02:05 2006
@@ -20,11 +20,7 @@
<%init>
my @kids = $item->children;
</%init>
- <li <% $item->active ? 'class="active"' : '' |n %>><%
- Jifty->web->link(
- url => $item->url,
- label => _($item->label),
- ) %><% @kids ? '' : '</li>' |n %>
+ <li <% $item->active ? 'class="active"' : '' |n %>><% $item->as_link |n %><% @kids ? '' : '</li>' |n %>
% if (@kids) {
<ul class="submenu">
% $m->comp(".menu", item => $_) for @kids;
Modified: jifty/trunk/share/web/templates/_elements/wrapper
==============================================================================
--- jifty/trunk/share/web/templates/_elements/wrapper (original)
+++ jifty/trunk/share/web/templates/_elements/wrapper Tue May 23 11:02:05 2006
@@ -13,12 +13,8 @@
% }
<% Jifty->web->render_messages %>
<% $m->content |n%>
- <script type="text/javascript"><!--
- document.write('<div id="keybindings">');
- writeKeyBindingLegend();
- document.write('<\/div>');
- document.write('<div id="jifty-wait-message" style="display: none"><%_('Loading...')%><\/div>');
- --></script>
+ <& /_elements/keybindings &>
+ <div id="jifty-wait-message" style="display: none"><%_('Loading...')%></div>
% Jifty::Mason::Halo->render_component_tree() if (Jifty->config->framework('DevelMode') );
</body>
</html>
More information about the Jifty-commit
mailing list