[dw-free] move the 6A libraries into a folder in the local repo (to keep them grouped with their LIC
[commit: http://hg.dwscoalition.org/dw-free/rev/4b328d722eab]
move the 6A libraries into a folder in the local repo (to keep them grouped
with their LICENSE file). Update various includes
Files modified:
move the 6A libraries into a folder in the local repo (to keep them grouped
with their LICENSE file). Update various includes
Files modified:
- cgi-bin/LJ/CProd.pm
- cgi-bin/LJ/S2.pm
- cgi-bin/LJ/Talk.pm
- cgi-bin/LJ/Web.pm
- cgi-bin/LJ/Widget/InboxFolder.pm
- cgi-bin/LJ/Widget/InboxFolderNav.pm
- cgi-bin/LJ/Widget/ThemeNav.pm
- cgi-bin/ljlib.pl
- cvs/multicvs.conf
- htdocs/editicons.bml
- htdocs/editjournal.bml
- htdocs/inbox/index.bml
- htdocs/js/6alib/LICENSE.txt
- htdocs/js/6alib/checkallbutton.js
- htdocs/js/6alib/core.js
- htdocs/js/6alib/datasource.js
- htdocs/js/6alib/devel.js
- htdocs/js/6alib/dom.js
- htdocs/js/6alib/hourglass.js
- htdocs/js/6alib/httpreq.js
- htdocs/js/6alib/image-region-select.js
- htdocs/js/6alib/inputcomplete.js
- htdocs/js/6alib/ippu.js
- htdocs/js/6alib/json.js
- htdocs/js/6alib/perlbal-uploadtrack.js
- htdocs/js/6alib/progressbar.js
- htdocs/js/6alib/selectable_table.js
- htdocs/js/6alib/template.js
- htdocs/js/6alib/timer.js
- htdocs/js/6alib/view.js
- htdocs/tools/userpicfactory.bml
- htdocs/update.bml
- views/dev/tests/commentmanage.js
- views/dev/tests/libfunctions.js
- views/dev/tests/login.js
- views/dev/tests/quickreply.js
--------------------------------------------------------------------------------
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/CProd.pm
--- a/cgi-bin/LJ/CProd.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/CProd.pm Tue May 01 17:55:19 2012 +0800
@@ -413,10 +413,10 @@
my ($class, $content, %opts) = @_;
# include js libraries
- LJ::need_res("js/core.js");
- LJ::need_res("js/dom.js");
- LJ::need_res("js/httpreq.js");
- LJ::need_res("js/hourglass.js");
+ LJ::need_res("js/6alib/core.js");
+ LJ::need_res("js/6alib/dom.js");
+ LJ::need_res("js/6alib/httpreq.js");
+ LJ::need_res("js/6alib/hourglass.js");
LJ::need_res("js/cprod.js");
LJ::need_res("stc/cprod.css");
my $e_class = LJ::ehtml($class);
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/S2.pm
--- a/cgi-bin/LJ/S2.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/S2.pm Tue May 01 17:55:19 2012 +0800
@@ -183,9 +183,9 @@
# used if we're using our old library
LJ::need_res(qw(
- js/core.js
- js/dom.js
- js/httpreq.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/httpreq.js
js/livejournal.js
js/md5.js
js/login.js
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/Talk.pm
--- a/cgi-bin/LJ/Talk.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/Talk.pm Tue May 01 17:55:19 2012 +0800
@@ -2173,24 +2173,24 @@
@additional,
) : (
# base libraries
- 'js/core.js',
- 'js/dom.js',
- 'js/json.js',
+ 'js/6alib/core.js',
+ 'js/6alib/dom.js',
+ 'js/6alib/json.js',
# for the formatting of the icon selector popup
- 'js/template.js',
- 'js/ippu.js',
+ 'js/6alib/template.js',
+ 'js/6alib/ippu.js',
'js/lj_ippu.js',
# logic for the icon selector
'js/userpicselect.js',
# fetching the userpic information
- 'js/httpreq.js',
- 'js/hourglass.js',
+ 'js/6alib/httpreq.js',
+ 'js/6alib/hourglass.js',
# autocomplete
- 'js/inputcomplete.js',
+ 'js/6alib/inputcomplete.js',
'stc/ups.css',
# selecting an icon by clicking on a row
- 'js/datasource.js',
- 'js/selectable_table.js',
+ 'js/6alib/datasource.js',
+ 'js/6alib/selectable_table.js',
# additional files from arguments
@additional,
);
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/Web.pm
--- a/cgi-bin/LJ/Web.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/Web.pm Tue May 01 17:55:19 2012 +0800
@@ -1473,9 +1473,9 @@
### Insert Object Toolbar:
LJ::need_res(qw(
- js/core.js
- js/dom.js
- js/ippu.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/ippu.js
js/lj_ippu.js
));
$out .= "<div id='htmltools' class='pkg'>\n";
@@ -3303,9 +3303,9 @@
croak "Invalid options passed to subscribe_interface" if (scalar keys %opts);
LJ::need_res('stc/esn.css');
- LJ::need_res('js/core.js');
- LJ::need_res('js/dom.js');
- LJ::need_res('js/checkallbutton.js');
+ LJ::need_res('js/6alib/core.js');
+ LJ::need_res('js/6alib/dom.js');
+ LJ::need_res('js/6alib/checkallbutton.js');
LJ::need_res('js/esn.js');
my @categories = $catref ? @$catref : ();
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/Widget/InboxFolder.pm
--- a/cgi-bin/LJ/Widget/InboxFolder.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/Widget/InboxFolder.pm Tue May 01 17:55:19 2012 +0800
@@ -25,14 +25,14 @@
sub need_res {
return qw(
- js/core.js
- js/dom.js
- js/view.js
- js/datasource.js
- js/checkallbutton.js
- js/selectable_table.js
- js/httpreq.js
- js/hourglass.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/view.js
+ js/6alib/datasource.js
+ js/6alib/checkallbutton.js
+ js/6alib/selectable_table.js
+ js/6alib/httpreq.js
+ js/6alib/hourglass.js
js/esn_inbox.js
stc/esn.css
stc/lj_base.css
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/Widget/InboxFolderNav.pm
--- a/cgi-bin/LJ/Widget/InboxFolderNav.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/Widget/InboxFolderNav.pm Tue May 01 17:55:19 2012 +0800
@@ -19,9 +19,9 @@
sub need_res {
return qw(
- js/core.js
- js/dom.js
- js/hourglass.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/hourglass.js
stc/esn.css
stc/lj_base.css
);
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/LJ/Widget/ThemeNav.pm
--- a/cgi-bin/LJ/Widget/ThemeNav.pm Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/LJ/Widget/ThemeNav.pm Tue May 01 17:55:19 2012 +0800
@@ -21,7 +21,7 @@
sub ajax { 1 }
sub can_fake_ajax_post { 1 }
sub authas { 1 }
-sub need_res { qw( stc/widgets/themenav.css js/inputcomplete.js ) }
+sub need_res { qw( stc/widgets/themenav.css js/6alib/inputcomplete.js ) }
sub render_body {
my $class = shift;
diff -r cb15f9c272f5 -r 4b328d722eab cgi-bin/ljlib.pl
--- a/cgi-bin/ljlib.pl Tue May 01 16:18:41 2012 +0800
+++ b/cgi-bin/ljlib.pl Tue May 01 17:55:19 2012 +0800
@@ -1072,9 +1072,9 @@
# standard site-wide JS and CSS
LJ::need_res( { priority => $LJ::LIB_RES_PRIORITY }, qw(
- js/core.js
- js/dom.js
- js/httpreq.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/httpreq.js
js/livejournal.js
stc/lj_base.css
));
@@ -1089,9 +1089,9 @@
# contextual popup JS
if ( $LJ::CTX_POPUP ) {
LJ::need_res( { priority => $LJ::LIB_RES_PRIORITY }, qw(
- js/ippu.js
+ js/6alib/ippu.js
js/lj_ippu.js
- js/hourglass.js
+ js/6alib/hourglass.js
js/contextualhover.js
stc/contextualhover.css
));
@@ -1113,7 +1113,7 @@
# development JS
LJ::need_res( { priority => $LJ::LIB_RES_PRIORITY }, qw(
- js/devel.js
+ js/6alib/devel.js
js/livejournal-devel.js
))
if $LJ::IS_DEV_SERVER;
diff -r cb15f9c272f5 -r 4b328d722eab cvs/multicvs.conf
--- a/cvs/multicvs.conf Tue May 01 16:18:41 2012 +0800
+++ b/cvs/multicvs.conf Tue May 01 17:55:19 2012 +0800
@@ -12,7 +12,6 @@
# DreamWidth repositories
HG(dw-free) = http://hg.dwscoalition.org/dw-free @stable
-HG(js) = http://hg.dwscoalition.org/js
# stock/unchanged repositories pulled from external sources
SVN(gearman) = http://code.livejournal.org/svn/gearman/trunk/
@@ -30,9 +29,6 @@
TheSchwartz-Worker-SendEmail/lib cgi-bin/
TheSchwartz/bin/schwartzmon bin/schwartzmon
-js/ htdocs/js
-js/ImageRegionSelect/image-region-select.js htdocs/js/image-region-select.js
-
memcached/server src/memcached
memcached/api/perl/lib/ cgi-bin
@@ -63,12 +59,12 @@
dw-free/htdocs/manage/circle/invite.bml ssldocs/manage/circle/invite.bml
dw-free/htdocs/shop/ ssldocs/shop/
-js/core.js ssldocs/js/core.js
-js/devel.js ssldocs/js/devel.js
-js/dom.js ssldocs/js/dom.js
-js/httpreq.js ssldocs/js/httpreq.js
-js/ippu.js ssldocs/js/ippu.js
-js/hourglass.js ssldocs/js/hourglass.js
+dw-free/htdocs/js/6alib/core.js ssldocs/js/6alib/core.js
+dw-free/htdocs/js/6alib/devel.js ssldocs/js/6alib/devel.js
+dw-free/htdocs/js/6alib/dom.js ssldocs/js/6alib/dom.js
+dw-free/htdocs/js/6alib/httpreq.js ssldocs/js/6alib/httpreq.js
+dw-free/htdocs/js/6alib/ippu.js ssldocs/js/6alib/ippu.js
+dw-free/htdocs/js/6alib/hourglass.js ssldocs/js/6alib/hourglass.js
dw-free/htdocs/_config.bml ssldocs/_config.bml
dw-free/htdocs/img/ ssldocs/img/
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/editicons.bml
--- a/htdocs/editicons.bml Tue May 01 16:18:41 2012 +0800
+++ b/htdocs/editicons.bml Tue May 01 17:55:19 2012 +0800
@@ -48,9 +48,9 @@
LJ::need_res(qw(
stc/editicons.css
- js/progressbar.js
+ js/6alib/progressbar.js
js/ljprogressbar.js
- js/perlbal-uploadtrack.js
+ js/6alib/perlbal-uploadtrack.js
js/editicons.js
));
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/editjournal.bml
--- a/htdocs/editjournal.bml Tue May 01 16:18:41 2012 +0800
+++ b/htdocs/editjournal.bml Tue May 01 17:55:19 2012 +0800
@@ -33,7 +33,7 @@
if ($GET{'itemid'} || $POST{'itemid'}) { $mode = "edit"; }
LJ::need_res( { priority => $LJ::OLD_RES_PRIORITY }, 'stc/entry.css' );
- LJ::need_res( 'js/inputcomplete.js' );
+ LJ::need_res( 'js/6alib/inputcomplete.js' );
# are they asking to be authed as someone else?
my $authas = $GET{'authas'} || $remote->{'user'};
@@ -639,9 +639,9 @@
my $ret;
LJ::need_res(qw(
- js/core.js
- js/dom.js
- js/httpreq.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/httpreq.js
js/livejournal.js
js/entry.js
js/poll.js
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/inbox/index.bml
--- a/htdocs/inbox/index.bml Tue May 01 16:18:41 2012 +0800
+++ b/htdocs/inbox/index.bml Tue May 01 17:55:19 2012 +0800
@@ -30,14 +30,14 @@
return $ML{'.error.not_ready'} unless $remote->can_use_esn;
LJ::need_res(qw(
- js/core.js
- js/dom.js
- js/view.js
- js/datasource.js
- js/checkallbutton.js
- js/selectable_table.js
- js/httpreq.js
- js/hourglass.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/view.js
+ js/6alib/datasource.js
+ js/6alib/checkallbutton.js
+ js/6alib/selectable_table.js
+ js/6alib/httpreq.js
+ js/6alib/hourglass.js
js/esn_inbox.js
stc/esn.css
stc/lj_base.css
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/LICENSE.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/LICENSE.txt Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,30 @@
+Copyright (c) 2005, 2006, 2007 Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/checkallbutton.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/checkallbutton.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,70 @@
+/*
+ This is a class which you can attach to a checkbox element.
+ When that element is clicked, it will toggle every checkbox
+ with a specified classname to be the same as the checkbox that was
+ clicked.
+
+ $Id: checkallbutton.js 69 2006-07-14 22:38:26Z mischa $
+*/
+
+CheckallButton = new Class(Object, {
+
+ // opts:
+ // class => what class all of the checkboxes have
+ // button => the "check all" button element
+ // parent => [optional] only check boxes that are children of this element
+ init: function (opts) {
+ if ( CheckallButton.superClass.init ) {
+ CheckallButton.superClass.init.apply(arguments);
+ }
+
+ this.button = opts["button"];
+ this.className = opts["class"];
+ this.parent = opts["parent"];
+ this.attachEvents();
+ },
+
+ attachEvents: function () {
+ if (!this.button || !this.className)
+ return;
+
+ DOM.addEventListener(this.button, "click", this.buttonClicked.bindEventListener(this));
+ },
+
+ buttonClicked: function (e) {
+ if (!this.button || !this.className)
+ return;
+
+ var parent = this.parent;
+ if (!parent)
+ parent = document;
+
+ var viewObjects = parent.getElementsByTagName("*");
+ var boxes = DOM.filterElementsByClassName(viewObjects, this.className) || [];
+
+ var checkallBox = this.button;
+
+ for (var i = 0; i < boxes.length; i++) {
+ var box = boxes[i];
+
+ if (!box)
+ continue;
+
+ if (box.checked == checkallBox.checked) continue;
+
+ // send a "clicked" event to the checkbox
+ try {
+ // w3c
+ var evt = document.createEvent("MouseEvents");
+ evt.initMouseEvent("click", true, false, window,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ box.dispatchEvent(evt);
+ } catch (e) {
+ try {
+ // ie
+ box.click();
+ } catch (e2) { }
+ }
+ }
+ }
+});
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/core.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/core.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,843 @@
+/*
+Core JavaScript Library
+$Id: core.js 232 2007-10-01 20:32:42Z whitaker $
+
+Copyright (c) 2005, Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/* stubs */
+
+log = function() {};
+log.error = log.warn = log.debug = log;
+
+
+/* utility functions */
+
+defined = function( x ) {
+ return x === undefined ? false : true;
+}
+
+
+/**
+ * Utility method.
+ * @param x <code>any</code> Any JavaScript value, including <code>undefined</code>.
+ * @return boolean <code>true</code> if the value is not <code>null</code> and is not <code>undefined</code>.
+ */
+exists = function( x ) {
+ return (x === undefined || x === null) ? false : true;
+}
+
+
+finite = function( x ) {
+ return isFinite( x ) ? x : 0;
+}
+
+
+finiteInt = function( x, base ) {
+ return finite( parseInt( x, base ) );
+}
+
+
+finiteFloat = function( x ) {
+ return finite( parseFloat( x ) );
+}
+
+
+max = function() {
+ var a = arguments;
+ var n = a[ 0 ];
+ for( var i = 1; i < a.length; i++ )
+ if( a[ i ] > n )
+ n = a[ i ];
+ return n;
+}
+
+
+min = function() {
+ var a = arguments;
+ var n = a[ 0 ];
+ for( var i = 1; i < a.length; i++ )
+ if( a[ i ] < n )
+ n = a[ i ];
+ return n;
+}
+
+
+/* try block */
+
+Try = {
+ these: function() {
+ for( var i = 0; i < arguments.length; i++ ) {
+ try {
+ return arguments[ i ]();
+ } catch( e ) {}
+ }
+ return undefined;
+ }
+}
+
+
+/* unique id generator */
+
+Unique = {
+ length: 0,
+
+ id: function() {
+ return ++this.length;
+ }
+}
+
+
+/* event methods */
+
+if( !defined( window.Event ) )
+ Event = {};
+
+
+Event.stop = function( event ) {
+ event = event || this;
+ if( event === Event )
+ event = window.event;
+
+ // w3c
+ if( event.preventDefault )
+ event.preventDefault();
+ if( event.stopPropagation )
+ event.stopPropagation();
+
+ // ie
+ try {
+ event.cancelBubble = true;
+ event.returnValue = false;
+ } catch( e ) {}
+
+ return false;
+}
+
+
+Event.prep = function( event ) {
+ event = event || window.event;
+ if( !defined( event.stop ) )
+ event.stop = this.stop;
+ if( !defined( event.target ) )
+ event.target = event.srcElement;
+ if( !defined( event.relatedTarget ) )
+ event.relatedTarget = event.toElement;
+ return event;
+}
+
+
+try { Event.prototype.stop = Event.stop; }
+catch( e ) {}
+
+
+/* object extensions */
+
+Function.stub = function() {};
+
+
+if( !Object.prototype.hasOwnProperty ) {
+ Object.prototype.hasOwnProperty = function( p ) {
+ if( !(p in this) )
+ return false;
+ try {
+ var pr = this.constructor.prototype;
+ while( pr ) {
+ if( pr[ p ] === this[ p ] )
+ return false;
+ if( pr === pr.constructor.prototype )
+ break;
+ pr = pr.constructor.prototype;
+ }
+ } catch( e ) {}
+ return true;
+ }
+}
+
+
+if ( ! defined ( window.OBJ ) )
+ OBJ = {};
+
+OBJ.extend = function(obj_this) {
+ var a = arguments;
+ for( var i = 0; i < a.length; i++ ) {
+ var o = a[ i ];
+ for( var p in o ) {
+ try {
+ if( !obj_this[ p ] &&
+ (!o.hasOwnProperty || o.hasOwnProperty( p )) )
+ obj_this[ p ] = o[ p ];
+ } catch( e ) {}
+ }
+ }
+ return obj_this;
+}
+
+
+OBJ.override = function(obj_this) {
+ var a = arguments;
+ for( var i = 0; i < a.length; i++ ) {
+ var o = a[ i ];
+ for( var p in o ) {
+ try {
+ if( !o.hasOwnProperty || o.hasOwnProperty( p ) )
+ obj_this[ p ] = o[ p ];
+ } catch( e ) {}
+ }
+ }
+ return obj_this;
+}
+
+
+/* function extensions */
+
+OBJ.extend( Function.prototype, {
+ bind: function( object ) {
+ var method = this;
+ return function() {
+ return method.apply( object, arguments );
+ };
+ },
+
+
+ bindEventListener: function( object ) {
+ var method = this; // Use double closure to work around IE 6 memory leak.
+ return function( event ) {
+ try {
+ event = Event.prep( event );
+ } catch( e ) {}
+ return method.call( object, event );
+ };
+ }
+} );
+
+
+/* class helpers */
+
+indirectObjects = [];
+
+
+Class = function( superClass ) {
+
+ // Set the constructor:
+ var constructor = function() {
+ if( arguments.length && this.init )
+ this.init.apply( this, arguments );
+ };
+ // -- Accomplish static-inheritance:
+ OBJ.override( constructor,Class ); // inherit static methods from Class
+ superClass = superClass || Object;
+ OBJ.override(constructor, superClass ); // inherit static methods from the superClass
+ constructor.superClass = superClass.prototype;
+
+ // Set the constructor's prototype (accomplish object-inheritance):
+ constructor.prototype = new superClass();
+ constructor.prototype.constructor = constructor; // rev. 0.7
+ // -- extend prototype with Class instance methods
+ OBJ.extend(constructor.prototype, Class.prototype );
+ // -- override prototype with interface methods
+ for( var i = 1; i < arguments.length; i++ )
+ OBJ.override(constructor.prototype, arguments[ i ] );
+
+ return constructor;
+}
+
+
+OBJ.extend( Class, {
+ initSingleton: function() {
+ if( this.singleton )
+ return this.singleton;
+ this.singleton = this.singletonConstructor
+ ? new this.singletonConstructor()
+ : new this();
+ if ( this.singleton.init )
+ this.singleton.init.apply( this.singleton, arguments );
+ return this.singleton;
+ }
+} );
+
+
+Class.prototype = {
+ destroy: function() {
+ try {
+ if( this.indirectIndex )
+ indirectObjects[ this.indirectIndex ] = undefined;
+ delete this.indirectIndex;
+ } catch( e ) {}
+
+ for( var property in this ) {
+ try {
+ if( this.hasOwnProperty( property ) )
+ delete this[ property ];
+ } catch( e ) {}
+ }
+ },
+
+
+ getBoundMethod: function( methodName ) {
+ return this[ name ].bind( this );
+ },
+
+
+ getEventListener: function( methodName ) {
+ return this[ methodName ].bindEventListener( this );
+ },
+
+
+ getIndirectIndex: function() {
+ if( !defined( this.indirectIndex ) ) {
+ this.indirectIndex = indirectObjects.length;
+ indirectObjects.push( this );
+ }
+ return this.indirectIndex;
+ },
+
+
+ getIndirectMethod: function( methodName ) {
+ if( !this.indirectMethods )
+ this.indirectMethods = {};
+ var method = this[ methodName ];
+ if( typeof method != "function" )
+ return undefined;
+ var indirectIndex = this.getIndirectIndex();
+ if( !this.indirectMethods[ methodName ] ) {
+ this.indirectMethods[ methodName ] = new Function(
+ "var o = indirectObjects[" + indirectIndex + "];" +
+ "return o." + methodName + ".apply( o, arguments );"
+ );
+ }
+ return this.indirectMethods[ methodName ];
+ },
+
+
+ getIndirectEventListener: function( methodName ) {
+ if( !this.indirectEventListeners )
+ this.indirectEventListeners = {};
+ var method = this[ methodName ];
+ if( typeof method != "function" )
+ return undefined;
+ var indirectIndex = this.getIndirectIndex();
+ if( !this.indirectEventListeners[ methodName ] ) {
+ this.indirectEventListeners[ methodName ] = new Function( "event",
+ "try { event = Event.prep( event ); } catch( e ) {}" +
+ "var o = indirectObjects[" + indirectIndex + "];" +
+ "return o." + methodName + ".call( o, event );"
+ );
+ }
+ return this.indirectEventListeners[ methodName ];
+ }
+}
+
+
+/* string extensions */
+
+OBJ.extend( String, {
+ escapeJSChar: function( c ) {
+ // try simple escaping
+ switch( c ) {
+ case "\\": return "\\\\";
+ case "\"": return "\\\"";
+ case "'": return "\\'";
+ case "\b": return "\\b";
+ case "\f": return "\\f";
+ case "\n": return "\\n";
+ case "\r": return "\\r";
+ case "\t": return "\\t";
+ }
+
+ // return raw bytes now ... should be UTF-8
+ if( c >= " " )
+ return c;
+
+ // try \uXXXX escaping, but shouldn't make it for case 1, 2
+ c = c.charCodeAt( 0 ).toString( 16 );
+ switch( c.length ) {
+ case 1: return "\\u000" + c;
+ case 2: return "\\u00" + c;
+ case 3: return "\\u0" + c;
+ case 4: return "\\u" + c;
+ }
+
+ // should never make it here
+ return "";
+ },
+
+
+ encodeEntity: function( c ) {
+ switch( c ) {
+ case "<": return "<";
+ case ">": return ">";
+ case "&": return "&";
+ case '"': return """;
+ case "'": return "'";
+ }
+ return c;
+ },
+
+
+ decodeEntity: function( c ) {
+ switch( c ) {
+ case "amp": return "&";
+ case "quot": return '"';
+ case "gt": return ">";
+ case "lt": return "<";
+ }
+ var m = c.match( /^#(\d+)$/ );
+ if( m && defined( m[ 1 ] ) )
+ return String.fromCharCode( m[ 1 ] );
+ m = c.match( /^#x([0-9a-f]+)$/i );
+ if( m && defined( m[ 1 ] ) )
+ return String.fromCharCode( parseInt( hex, m[ 1 ] ) );
+ return c;
+ }
+} );
+
+
+OBJ.extend( String.prototype, {
+ escapeJS: function() {
+ return this.replace( /([^ -!#-\[\]-~])/g, function( m, c ) { return String.escapeJSChar( c ); } )
+ },
+
+
+ escapeJS2: function() {
+ return this.replace( /([\u0000-\u0031'"\\])/g, function( m, c ) { return String.escapeJSChar( c ); } )
+ },
+
+
+ escapeJS3: function() {
+ return this.replace( /[\u0000-\u0031'"\\]/g, function( m ) { return String.escapeJSChar( m ); } )
+ },
+
+
+ escapeJS4: function() {
+ return this.replace( /./g, function( m ) { return String.escapeJSChar( m ); } )
+ },
+
+
+ encodeHTML: function() {
+ return this.replace( /([<>&"])/g, function( m, c ) { return String.encodeEntity( c ) } );
+ },
+
+
+ decodeHTML: function() {
+ return this.replace( /&(.*?);/g, function( m, c ) { return String.decodeEntity( c ) } );
+ },
+
+
+ cssToJS: function() {
+ return this.replace( /-([a-z])/g, function( m, c ) { return c.toUpperCase() } );
+ },
+
+
+ jsToCSS: function() {
+ return this.replace( /([A-Z])/g, function( m, c ) { return "-" + c.toLowerCase() } );
+ },
+
+
+ firstToLowerCase: function() {
+ return this.replace( /^(.)/, function( m, c ) { return c.toLowerCase() } );
+ },
+
+
+ rgbToHex: function() {
+ var c = this.match( /(\d+)\D+(\d+)\D+(\d+)/ );
+ if( !c )
+ return undefined;
+ return "#" +
+ finiteInt( c[ 1 ] ).toString( 16 ).pad( 2, "0" ) +
+ finiteInt( c[ 2 ] ).toString( 16 ).pad( 2, "0" ) +
+ finiteInt( c[ 3 ] ).toString( 16 ).pad( 2, "0" );
+ },
+
+
+ pad: function( length, padChar ) {
+ var padding = length - this.length;
+ if( padding <= 0 )
+ return this;
+ if( !defined( padChar ) )
+ padChar = " ";
+ var out = [];
+ for( var i = 0; i < padding; i++ )
+ out.push( padChar );
+ out.push( this );
+ return out.join( "" );
+ },
+
+
+ trim: function() {
+ return this.replace( /^\s+|\s+$/g, "" );
+ }
+
+} );
+
+
+/* extend array object */
+
+OBJ.extend( Array, {
+ fromPseudo: function ( args ) {
+ var out = [];
+ for ( var i = 0; i < args.length; i++ )
+ out.push( args[ i ] );
+ return out;
+ }
+});
+
+
+/* extend array object */
+
+OBJ.extend(Array.prototype, {
+ copy: function() {
+ var out = [];
+ for( var i = 0; i < this.length; i++ )
+ out[ i ] = this[ i ];
+ return out;
+ },
+
+
+ first: function( callback, object ) {
+ var length = this.length;
+ for( var i = 0; i < length; i++ ) {
+ var result = object
+ ? callback.call( object, this[ i ], i, this )
+ : callback( this[ i ], i, this );
+ if( result )
+ return this[ i ];
+ }
+ return null;
+ },
+
+
+ fitIndex: function( fromIndex, defaultIndex ) {
+ if( !defined( fromIndex ) || fromIndex == null )
+ fromIndex = defaultIndex;
+ else if( fromIndex < 0 ) {
+ fromIndex = this.length + fromIndex;
+ if( fromIndex < 0 )
+ fromIndex = 0;
+ } else if( fromIndex >= this.length )
+ fromIndex = this.length - 1;
+ return fromIndex;
+ },
+
+
+ scramble: function() {
+ for( var i = 0; i < this.length; i++ ) {
+ var j = Math.floor( Math.random() * this.length );
+ var temp = this[ i ];
+ this[ i ] = this[ j ];
+ this[ j ] = temp;
+ }
+ },
+
+
+ add: function() {
+ var a = arguments;
+ for( var i = 0; i < a.length; i++ ) {
+ var index = this.indexOf( a[ i ] );
+ if( index < 0 )
+ this.push( arguments[ i ] );
+ }
+ return this.length;
+ },
+
+
+ remove: function() {
+ var a = arguments;
+ for( var i = 0; i < a.length; i++ ) {
+ var j = this.indexOf( a[ i ] );
+ if( j >= 0 )
+ this.splice( j, 1 );
+ }
+ return this.length;
+ },
+
+
+ /* javascript 1.5 array methods */
+ /* http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array#Methods */
+
+ every: function( callback, object ) {
+ var length = this.length;
+ for( var i = 0; i < length; i++ ) {
+ var result = object
+ ? callback.call( object, this[ i ], i, this )
+ : callback( this[ i ], i, this );
+ if( !result )
+ return false;
+ }
+ return true;
+ },
+
+
+ filter: function( callback, object ) {
+ var out = [];
+ var length = this.length;
+ for( var i = 0; i < length; i++ ) {
+ var result = object
+ ? callback.call( object, this[ i ], i, this )
+ : callback( this[ i ], i, this );
+ if( result )
+ out.push( this[ i ] );
+ }
+ return out;
+ },
+
+
+ forEach: function( callback, object ) {
+ var length = this.length;
+ for( var i = 0; i < length; i++ ) {
+ object
+ ? callback.call( object, this[ i ], i, this )
+ : callback( this[ i ], i, this );
+ }
+ },
+
+
+ indexOf: function( value, fromIndex ) {
+ fromIndex = this.fitIndex( fromIndex, 0 );
+ for( var i = 0; i < this.length; i++ ) {
+ if( this[ i ] === value )
+ return i;
+ }
+ return -1;
+ },
+
+
+ lastIndexOf: function( value, fromIndex ) {
+ fromIndex = this.fitIndex( fromIndex, this.length - 1 );
+ for( var i = fromIndex; i >= 0; i-- ) {
+ if( this[ i ] == value )
+ return i;
+ }
+ return -1;
+ },
+
+
+ some: function( callback, object ) {
+ var length = this.length;
+ for( var i = 0; i < length; i++ ) {
+ var result = object
+ ? callback.call( object, this[ i ], i, this )
+ : callback( this[ i ], i, this );
+ if( result )
+ return true;
+ }
+ return false;
+ },
+
+
+ /* javascript 1.2 array methods */
+
+ concat: function() {
+ var a = arguments;
+ var out = this.copy();
+ for( i = 0; i < a.length; i++ ) {
+ var b = a[ i ];
+ for( j = 0; j < b.length; j++ )
+ out.push( b[ j ] );
+ }
+ return out;
+ },
+
+
+ push: function() {
+ var a = arguments;
+ for( var i = 0; i < a.length; i++ )
+ this[ this.length ] = a[ i ];
+ return this.length;
+ },
+
+
+ pop: function() {
+ if( this.length == 0 )
+ return undefined;
+ var out = this[ this.length - 1 ];
+ this.length--;
+ return out;
+ },
+
+
+ unshift: function() {
+ var a = arguments;
+ for( var i = 0; i < a.length; i++ ) {
+ this[ i + a.length ] = this[ i ];
+ this[ i ] = a[ i ];
+ }
+ return this.length;
+ },
+
+
+ shift: function() {
+ if( this.length == 0 )
+ return undefined;
+ var out = this[ 0 ];
+ for( var i = 1; i < this.length; i++ )
+ this[ i - 1 ] = this[ i ];
+ this.length--;
+ return out;
+ }
+} );
+
+
+/* date extensions */
+
+OBJ.extend(Date, {
+ /* iso 8601 date format parser
+ this was fun to write...
+ thanks to: http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
+
+ matchISOString: new RegExp(
+ "^([0-9]{4})" + // year
+ "(?:-(?=0[1-9]|1[0-2])|$)(..)?" + // month
+ "(?:-(?=0[1-9]|[12][0-9]|3[01])|$)([0-9]{2})?" + // day of the month
+ "(?:T(?=[01][0-9]|2[0-4])|$)T?([0-9]{2})?" + // hours
+ "(?::(?=[0-5][0-9])|\\+|-|Z|$)([0-9]{2})?" + // minutes
+ "(?::(?=[0-5][0-9]|60$|60[+|-|Z]|60.0+)|\\+|-|Z|$):?([0-9]{2})?" + // seconds
+ "(\.[0-9]+)?" + // fractional seconds
+ "(Z|\\+[01][0-9]|\\+2[0-4]|-[01][0-9]|-2[0-4])?" + // timezone hours
+ ":?([0-5][0-9]|60)?$" // timezone minutes
+ ),
+
+
+ fromISOString: function( string ) {
+ var t = this.matchISOString.exec( string );
+ if( !t )
+ return undefined;
+
+ var year = finiteInt( t[ 1 ], 10 );
+ var month = finiteInt( t[ 2 ], 10 ) - 1;
+ var day = finiteInt( t[ 3 ], 10 );
+ var hours = finiteInt( t[ 4 ], 10 );
+ var minutes = finiteInt( t[ 5 ], 10 );
+ var seconds = finiteInt( t[ 6 ], 10 );
+ var milliseconds = finiteInt( Math.round( parseFloat( t[ 7 ] ) * 1000 ) );
+ var tzHours = finiteInt( t[ 8 ], 10 );
+ var tzMinutes = finiteInt( t[ 9 ], 10 );
+
+ var date = new this( 0 );
+ if( defined( t[ 8 ] ) ) {
+ date.setUTCFullYear( year, month, day );
+ date.setUTCHours( hours, minutes, seconds, milliseconds );
+ var offset = (tzHours * 60 + tzMinutes) * 60000;
+ if( offset )
+ date = new this( date - offset );
+ } else {
+ date.setFullYear( year, month, day );
+ date.setHours( hours, minutes, seconds, milliseconds );
+ }
+
+ return date;
+ }
+} );
+
+
+OBJ.extend(Date.prototype, {
+ getISOTimezoneOffset: function() {
+ var offset = -this.getTimezoneOffset();
+ var negative = false;
+ if( offset < 0 ) {
+ negative = true;
+ offset *= -1;
+ }
+ var offsetHours = Math.floor( offset / 60 ).toString().pad( 2, "0" );
+ var offsetMinutes = Math.floor( offset % 60 ).toString().pad( 2, "0" );
+ return (negative ? "-" : "+") + offsetHours + ":" + offsetMinutes;
+ },
+
+
+ toISODateString: function() {
+ var year = this.getFullYear();
+ var month = (this.getMonth() + 1).toString().pad( 2, "0" );
+ var day = this.getDate().toString().pad( 2, "0" );
+ return year + "-" + month + "-" + day;
+ },
+
+
+ toUTCISODateString: function() {
+ var year = this.getUTCFullYear();
+ var month = (this.getUTCMonth() + 1).toString().pad( 2, "0" );
+ var day = this.getUTCDate().toString().pad( 2, "0" );
+ return year + "-" + month + "-" + day;
+ },
+
+
+ toISOTimeString: function() {
+ var hours = this.getHours().toString().pad( 2, "0" );
+ var minutes = this.getMinutes().toString().pad( 2, "0" );
+ var seconds = this.getSeconds().toString().pad( 2, "0" );
+ var milliseconds = this.getMilliseconds().toString().pad( 3, "0" );
+ var timezone = this.getISOTimezoneOffset();
+ return hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
+ },
+
+
+ toUTCISOTimeString: function() {
+ var hours = this.getUTCHours().toString().pad( 2, "0" );
+ var minutes = this.getUTCMinutes().toString().pad( 2, "0" );
+ var seconds = this.getUTCSeconds().toString().pad( 2, "0" );
+ var milliseconds = this.getUTCMilliseconds().toString().pad( 3, "0" );
+ return hours + ":" + minutes + ":" + seconds + "." + milliseconds + "Z";
+ },
+
+
+ toISOString: function() {
+ return this.toISODateString() + "T" + this.toISOTimeString();
+ },
+
+
+ toUTCISOString: function() {
+ return this.toUTCISODateString() + "T" + this.toUTCISOTimeString();
+ }
+} );
+
+
+/* ajax */
+
+if( !defined( window.XMLHttpRequest ) ) {
+ window.XMLHttpRequest = function() {
+ var types = [
+ "Microsoft.XMLHTTP",
+ "MSXML2.XMLHTTP.5.0",
+ "MSXML2.XMLHTTP.4.0",
+ "MSXML2.XMLHTTP.3.0",
+ "MSXML2.XMLHTTP"
+ ];
+
+ for( var i = 0; i < types.length; i++ ) {
+ try {
+ return new ActiveXObject( types[ i ] );
+ } catch( e ) {}
+ }
+
+ return undefined;
+ }
+}
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/datasource.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/datasource.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,148 @@
+// datasource base class, the "M" in MVC
+// subclass this and override theData to provide your data
+
+DataSource = new Class(Object, {
+
+ init: function (initialData) {
+ if ( DataSource.superClass.init )
+ DataSource.superClass.init.apply(this, arguments);
+ this.watchers = [];
+ this.theData = defined(initialData) ? initialData : [];
+ this.sortField = "";
+ this.sortType = "";
+ this.sortDesc = false;
+ },
+
+ addWatcher: function (callback) {
+ this.watchers.add(callback);
+ },
+
+ removeWatcher: function (callback) {
+ this.watchers.remove(callback);
+ },
+
+ // call this if updating data and not using _setData
+ _updated: function () {
+ this.callWatchers();
+ },
+
+ callWatchers: function () {
+ for (var i = 0; i < this.watchers.length; i++)
+ this.watchers[i].apply(this, [this.data()]);
+ },
+
+ setData: function (theData) {
+ this.theData = theData;
+
+ if (this.sortField)
+ this.sortDataBy(this.sortField, this.sortType, this.sortDesc);
+
+ this._setData(theData);
+ },
+
+ _setData: function (theData) {
+ this.theData = theData;
+ this.callWatchers();
+ return theData;
+ },
+
+ data: function () {
+ return this.theData;
+ },
+
+ sortBy: function () {
+ return this.sortField;
+ },
+
+ sortInverted: function () {
+ return this.sortDesc;
+ },
+
+ // mimic some array functionality
+ push: function (data) {
+ this.theData.push(data);
+ this.callWatchers();
+ },
+
+ pop: function () {
+ var val = this.theData.pop();
+ this.callWatchers();
+ return val;
+ },
+
+ indexOf: function (value) {
+ return this.theData.indexOf(value);
+ },
+
+ remove: function (value) {
+ this.theData.remove(value);
+ this.callWatchers();
+ },
+
+ empty: function () {
+ this.theData = [];
+ this.callWatchers();
+ },
+
+ length: function () {
+ return this.theData.length;
+ },
+
+ totalLength: function () {
+ return this.allData().length;
+ },
+
+ allData: function () {
+ var theData = this.theData;
+
+ if (this.dataField && theData)
+ theData = theData[this.dataField];
+
+ return theData;
+ },
+
+ sortDataBy: function (field, type, invert) {
+ this.sortField = field;
+ this.sortDesc = invert;
+ this.sortType = type;
+
+ if (!field || !this.theData || !this.theData.sort)
+ return;
+
+ var sorted = this.theData.sort(function (a, b) {
+ var ad = a[""+field], bd = b[""+field];
+ ad = ad ? ad : "";
+ bd = bd ? bd : "";
+
+ switch(type) {
+
+ case "string":
+ var aname = ad.toUpperCase(), bname = bd.toUpperCase();
+
+ if (aname < bname)
+ return -1;
+ else if (aname > bname)
+ return 1;
+ else
+ return 0;
+
+ case "isodate":
+ var datA = Date.fromISOString(ad) || new Date(0);
+ var datB = Date.fromISOString(bd) || new Date(0);
+
+ return ((datA - datB) || 0);
+
+ default:
+ case "numeric":
+ return ad - bd;
+
+ }
+ });
+
+ if (invert)
+ sorted.reverse();
+
+ this._setData(sorted);
+ }
+
+});
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/devel.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/devel.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,178 @@
+/*
+Development Library
+$Id$
+
+Copyright (c) 2006, Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/* benchmarking */
+
+benchmark = function( callback, iterations ) {
+ var start = new Date();
+ for( var i = 0; i < iterations; i++ )
+ callback();
+ var end = new Date();
+ return (end.getSeconds() - start.getSeconds()) +
+ (end.getMilliseconds() - start.getMilliseconds()) / 1000;
+}
+
+
+inspect = function( object, allProperties, noBreaks ) {
+ var out = "";
+ for( var property in object ) {
+ try {
+ if( !allProperties && !object.hasOwnProperty( property ) )
+ continue;
+ out += property + ": " + object[ property ] +
+ (noBreaks ? "\n" : "<br />");
+ } catch( e ) {}
+ }
+ return out;
+}
+
+
+/* logging, alert override */
+
+Logger = new Class( Object, {
+ width: 320,
+ height: 240,
+ windowName: "log",
+
+
+ log: function() {
+ try {
+ // concat arguments
+ var args = [];
+ for( var i = 0; i < arguments.length; i++ )
+ args[ i ] = arguments[ i ];
+ var msg = args.join( "" );
+
+ // create window
+ this.createWindow();
+
+ // check for no window
+ if( !this.window ) {
+ confirm( "Logger popup window blocked. Using confirm() instead.\n\n" + msg );
+ return true;
+ }
+
+ // create div
+ var div = this.window.document.createElement( "div" );
+ div.style.backgroundColor = (this.count % 2) ? "#eee" : "#fff";
+ div.style.width = "auto";
+ div.style.padding = "3px";
+ div.innerHTML = msg;
+
+ // append to window
+ this.window.document.body.appendChild( div );
+ this.window.scroll( 0, this.window.document.body.scrollHeight );
+ this.count++;
+ return true;
+ } catch( e ) {}
+ },
+
+
+ createWindow: function() {
+ if( this.window && this.window.document )
+ return;
+
+ // create window
+ var x = "auto";
+ var y = "auto";
+ var attr = "resizable=yes, menubar=no, location=no, directories=no, scrollbars=yes, status=no, " +
+ "width=" + this.width + ", height=" + this.height +
+ "screenX=" + x + ", screenY=" + y + ", " +
+ "left=" + x + ", top=" + y + ", ";
+ this.window = window.open( "", this.windowName, attr );
+
+ // check for blocked popup
+ if( !this.window )
+ return;
+
+ var instance;
+ try {
+ instance = this.window.__Logger;
+ }
+
+ catch( e ) {
+ this.window.location.replace( "about:blank" );
+ }
+
+ // check for pre-existing instance
+ if( instance ) {
+ // create divider div
+ var div = this.window.document.createElement( "div" );
+ div.style.backgroundColor = "#f00";
+ div.style.width = "auto";
+ div.style.height = "2px";
+ div.style.fontSize = "0.1px";
+ div.style.lineHeight = "0.1px";
+ this.window.document.body.appendChild( div );
+ }
+ else {
+ // write body
+ this.window.document.open( "text/html", "replace" );
+ this.window.document.write( "<html><head><title>JavaScript Loggers</title></head><body></body></html>" );
+ this.window.document.close();
+
+ // setup style
+ this.window.title = "JavaScript Loggers";
+ this.window.document.body.style.margin = "0";
+ this.window.document.body.style.padding = "0";
+ this.window.document.body.style.fontFamily = "verdana, 'lucida grande', geneva, arial, helvetica, sans-serif";
+ this.window.document.body.style.fontSize = "10px";
+ }
+
+ // get previous instance and attach new instance
+ this.prev = instance;
+ this.window.__Logger = this;
+
+ // dereference previous previous
+ if( this.prev )
+ this.prev.prev = null;
+
+ // copy message count
+ this.count = this.prev ? this.prev.count : 0;
+ }
+} );
+
+
+log =
+Logger.log = function() {
+ if( !Logger.singleton )
+ Logger.singleton = new Logger();
+ if( Logger.singleton )
+ return Logger.singleton.log.apply( Logger.singleton, arguments );
+
+ return true;
+}
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/dom.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/dom.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,784 @@
+/*
+DOM Library - Copyright 2005 Six Apart
+$Id: dom.js 261 2008-02-26 23:40:50Z janine $
+
+Copyright (c) 2005, Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+/* Node class */
+
+if( !defined( window.Node ) )
+ Node = {};
+
+try {
+ OBJ.extend( Node, {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_FRAGMENT_NODE: 11
+ } );
+} catch( e ) {}
+
+
+/* DOM class */
+
+if( !defined( window.DOM ) )
+ DOM = {};
+
+
+OBJ.extend( DOM, {
+ getElement: function( e ) {
+ return (typeof e == "string" || typeof e == "number") ? document.getElementById( e ) : e;
+ },
+
+
+ addEventListener: function( e, eventName, func, useCapture ) {
+ try {
+ if( e.addEventListener )
+ e.addEventListener( eventName, func, useCapture );
+ else if( e.attachEvent )
+ e.attachEvent( "on" + eventName, func );
+ else
+ e[ "on" + eventName ] = func;
+ } catch( e ) {}
+ },
+
+
+ removeEventListener: function( e, eventName, func, useCapture ) {
+ try {
+ if( e.removeEventListener )
+ e.removeEventListener( eventName, func, useCapture );
+ else if( e.detachEvent )
+ e.detachEvent( "on" + eventName, func );
+ else
+ e[ "on" + eventName ] = undefined;
+ } catch( e ) {}
+ },
+
+
+ focus: function( e ) {
+ try {
+ e = DOM.getElement( e );
+ e.focus();
+ } catch( e ) {}
+ },
+
+
+ blur: function( e ) {
+ try {
+ e = DOM.getElement( e );
+ e.blur();
+ } catch( e ) {}
+ },
+
+
+ /* style */
+
+ getComputedStyle: function( e ) {
+ if( e.currentStyle )
+ return e.currentStyle;
+ var style = {};
+ var owner = DOM.getOwnerDocument( e );
+ if( owner && owner.defaultView && owner.defaultView.getComputedStyle ) {
+ try {
+ style = owner.defaultView.getComputedStyle( e, null );
+ } catch( e ) {}
+ }
+ return style;
+ },
+
+
+ getStyle: function( e, p ) {
+ var s = DOM.getComputedStyle( e );
+ return s[ p ];
+ },
+
+
+ // given a window (or defaulting to current window), returns
+ // object with .x and .y of client's usable area
+ getClientDimensions: function( w ) {
+ if( !w )
+ w = window;
+
+ var d = {};
+
+ // most browsers
+ if( w.innerHeight ) {
+ d.x = w.innerWidth;
+ d.y = w.innerHeight;
+ return d;
+ }
+
+ // IE6, strict
+ var de = w.document.documentElement;
+ if( de && de.clientHeight ) {
+ d.x = de.clientWidth;
+ d.y = de.clientHeight;
+ return d;
+ }
+
+ // IE, misc
+ if( document.body ) {
+ d.x = document.body.clientWidth;
+ d.y = document.body.clientHeight;
+ return d;
+ }
+
+ return undefined;
+ },
+
+
+ getDimensions: function( e ) {
+ if( !e )
+ return undefined;
+
+ var style = DOM.getComputedStyle( e );
+
+ return {
+ offsetLeft: e.offsetLeft,
+ offsetTop: e.offsetTop,
+ offsetWidth: e.offsetWidth,
+ offsetHeight: e.offsetHeight,
+ clientWidth: e.clientWidth,
+ clientHeight: e.clientHeight,
+
+ offsetRight: e.offsetLeft + e.offsetWidth,
+ offsetBottom: e.offsetTop + e.offsetHeight,
+ clientLeft: finiteInt( style.borderLeftWidth ) + finiteInt( style.paddingLeft ),
+ clientTop: finiteInt( style.borderTopWidth ) + finiteInt( style.paddingTop ),
+ clientRight: e.clientLeft + e.clientWidth,
+ clientBottom: e.clientTop + e.clientHeight
+ };
+ },
+
+
+ getAbsoluteDimensions: function( e ) {
+ var d = DOM.getDimensions( e );
+ if( !d )
+ return d;
+ d.absoluteLeft = d.offsetLeft;
+ d.absoluteTop = d.offsetTop;
+ d.absoluteRight = d.offsetRight;
+ d.absoluteBottom = d.offsetBottom;
+ var bork = 0;
+ while( e ) {
+ try { // IE 6 sometimes gives an unwarranted error ("htmlfile: Unspecified error").
+ e = e.offsetParent;
+ } catch ( err ) {
+ log( "In DOM.getAbsoluteDimensions: " + err.message );
+ if ( ++bork > 25 )
+ return null;
+ }
+ if( !e )
+ return d;
+ d.absoluteLeft += e.offsetLeft;
+ d.absoluteTop += e.offsetTop;
+ d.absoluteRight += e.offsetLeft;
+ d.absoluteBottom += e.offsetTop;
+ }
+ return d;
+ },
+
+
+ getIframeAbsoluteDimensions: function( e ) {
+ var d = DOM.getAbsoluteDimensions( e );
+ if( !d )
+ return d;
+ var iframe = DOM.getOwnerIframe( e );
+ if( !defined( iframe ) )
+ return d;
+
+ var d2 = DOM.getIframeAbsoluteDimensions( iframe );
+ var scroll = DOM.getWindowScroll( iframe.contentWindow );
+ var left = d2.absoluteLeft - scroll.left;
+ var top = d2.absoluteTop - scroll.top;
+
+ d.absoluteLeft += left;
+ d.absoluteTop += top;
+ d.absoluteRight += left;
+ d.absoluteBottom += top;
+
+ return d;
+ },
+
+
+ setLeft: function( e, v ) { e.style.left = finiteInt( v ) + "px"; },
+ setTop: function( e, v ) { e.style.top = finiteInt( v ) + "px"; },
+ setRight: function( e, v ) { e.style.right = finiteInt( v ) + "px"; },
+ setBottom: function( e, v ) { e.style.bottom = finiteInt( v ) + "px"; },
+ setWidth: function( e, v ) { e.style.width = max( 0, finiteInt( v ) ) + "px"; },
+ setHeight: function( e, v ) { e.style.height = max( 0, finiteInt( v ) ) + "px"; },
+ setZIndex: function( e, v ) { e.style.zIndex = finiteInt( v ); },
+
+
+ getWindowScroll: function( w ) {
+ var s = {
+ left: 0,
+ top: 0
+ };
+
+ if (!w) w = window;
+ var d = w.document;
+ var de = d.documentElement;
+
+ // most browsers
+ if ( defined( w.pageXOffset ) ) {
+ s.left = w.pageXOffset;
+ s.top = w.pageYOffset;
+ }
+
+ // ie
+ else if( de && defined( de.scrollLeft ) ) {
+ s.left = de.scrollLeft;
+ s.top = de.scrollTop;
+ }
+
+ // safari
+ else if( defined( w.scrollX ) ) {
+ s.left = w.scrollX;
+ s.top = w.scrollY;
+ }
+
+ // opera
+ else if( d.body && defined( d.body.scrollLeft ) ) {
+ s.left = d.body.scrollLeft;
+ s.top = d.body.scrollTop;
+ }
+
+
+ return s;
+ },
+
+
+ getAbsoluteCursorPosition: function( event ) {
+ event = event || window.event;
+ var s = DOM.getWindowScroll( window );
+ return {
+ x: s.left + event.clientX,
+ y: s.top + event.clientY
+ };
+ },
+
+
+ invisibleStyle: {
+ display: "block",
+ position: "absolute",
+ left: 0,
+ top: 0,
+ width: 0,
+ height: 0,
+ margin: 0,
+ border: 0,
+ padding: 0,
+ fontSize: "0.1px",
+ lineHeight: 0,
+ opacity: 0,
+ MozOpacity: 0,
+ filter: "alpha(opacity=0)"
+ },
+
+
+ makeInvisible: function( e ) {
+ for( var p in this.invisibleStyle ) {
+ if( this.invisibleStyle.hasOwnProperty( p ) )
+ e.style[ p ] = this.invisibleStyle[ p ];
+ }
+ },
+
+
+ /* text and selection related methods */
+
+ mergeTextNodes: function( n ) {
+ var c = 0;
+ while( n ) {
+ if( n.nodeType == Node.TEXT_NODE && n.nextSibling && n.nextSibling.nodeType == Node.TEXT_NODE ) {
+ n.nodeValue += n.nextSibling.nodeValue;
+ n.parentNode.removeChild( n.nextSibling );
+ c++;
+ } else {
+ if( n.firstChild )
+ c += DOM.mergeTextNodes( n.firstChild );
+ n = n.nextSibling;
+ }
+ }
+ return c;
+ },
+
+
+ selectElement: function( e ) {
+ var d = e.ownerDocument;
+
+ // internet explorer
+ if( d.body.createControlRange ) {
+ var r = d.body.createControlRange();
+ r.addElement( e );
+ r.select();
+ }
+ },
+
+
+ /* dom methods */
+
+ isImmutable: function( n ) {
+ try {
+ if( n.getAttribute( "contenteditable" ) == "false" )
+ return true;
+ } catch( e ) {}
+ return false;
+ },
+
+
+ getImmutable: function( n ) {
+ var immutable = null;
+ while( n ) {
+ if( DOM.isImmutable( n ) )
+ immutable = n;
+ n = n.parentNode;
+ }
+ return immutable;
+ },
+
+
+ getOwnerDocument: function( n ) {
+ if( !n )
+ return document;
+ if( n.ownerDocument )
+ return n.ownerDocument;
+ if( n.getElementById )
+ return n;
+ return document;
+ },
+
+
+ getOwnerWindow: function( n ) {
+ if( !n )
+ return window;
+ if( n.parentWindow )
+ return n.parentWindow;
+ var doc = DOM.getOwnerDocument( n );
+ if( doc && doc.defaultView )
+ return doc.defaultView;
+ return window;
+ },
+
+
+ getOwnerIframe: function( n ) {
+ if( !n )
+ return undefined;
+ var nw = DOM.getOwnerWindow( n );
+ var nd = DOM.getOwnerDocument( n );
+ var pw = nw.parent || nw.parentWindow;
+ if( !pw )
+ return undefined;
+ var parentDocument = pw.document;
+ var es = parentDocument.getElementsByTagName( "iframe" );
+ for( var i = 0; i < es.length; i++ ) {
+ var e = es[ i ];
+ try {
+ var d = e.contentDocument || e.contentWindow.document;
+ if( d === nd )
+ return e;
+ }catch(err) {};
+ }
+ return undefined;
+ },
+
+
+ filterElementsByClassName: function( es, className ) {
+ var filtered = [];
+ for( var i = 0; i < es.length; i++ ) {
+ var e = es[ i ];
+ if( DOM.hasClassName( e, className ) )
+ filtered[ filtered.length ] = e;
+ }
+ return filtered;
+ },
+
+
+ filterElementsByAttribute: function( es, attr ) {
+ if( !es )
+ return [];
+ if( !defined( attr ) || attr == null || attr == "" )
+ return es;
+ var filtered = [];
+ for( var i = 0; i < es.length; i++ ) {
+ var element = es[ i ];
+ if( !element )
+ continue;
+ if( element.getAttribute && ( element.getAttribute( attr ) ) )
+ filtered[ filtered.length ] = element;
+ }
+ return filtered;
+ },
+
+
+ filterElementsByTagName: function( es, tagName ) {
+ if( tagName == "*" )
+ return es;
+ var filtered = [];
+ tagName = tagName.toLowerCase();
+ for( var i = 0; i < es.length; i++ ) {
+ var e = es[ i ];
+ if( e.tagName && e.tagName.toLowerCase() == tagName )
+ filtered[ filtered.length ] = e;
+ }
+ return filtered;
+ },
+
+
+ getElementsByTagAndAttribute: function( root, tagName, attr ) {
+ if( !root )
+ root = document;
+ var es = root.getElementsByTagName( tagName );
+ return DOM.filterElementsByAttribute( es, attr );
+ },
+
+
+ getElementsByAttribute: function( root, attr ) {
+ return DOM.getElementsByTagAndAttribute( root, "*", attr );
+ },
+
+
+ getElementsByAttributeAndValue: function( root, attr, value ) {
+ var es = DOM.getElementsByTagAndAttribute( root, "*", attr );
+ var filtered = [];
+ for ( var i = 0; i < es.length; i++ )
+ if ( es[ i ].getAttribute( attr ) == value )
+ filtered.push( es[ i ] );
+ return filtered;
+ },
+
+
+ getElementsByTagAndClassName: function( root, tagName, className ) {
+ if( !root )
+ root = document;
+ var elements = root.getElementsByTagName( tagName );
+ return DOM.filterElementsByClassName( elements, className );
+ },
+
+
+ getElementsByClassName: function( root, className ) {
+ return DOM.getElementsByTagAndClassName( root, "*", className );
+ },
+
+
+ getAncestors: function( n, includeSelf ) {
+ if( !n )
+ return [];
+ var as = includeSelf ? [ n ] : [];
+ n = n.parentNode;
+ while( n ) {
+ as.push( n );
+ n = n.parentNode;
+ }
+ return as;
+ },
+
+
+ getAncestorsByTagName: function( n, tagName, includeSelf ) {
+ var es = DOM.getAncestors( n, includeSelf );
+ return DOM.filterElementsByTagName( es, tagName );
+ },
+
+
+ getFirstAncestorByTagName: function( n, tagName, includeSelf ) {
+ return DOM.getAncestorsByTagName( n, tagName, includeSelf )[ 0 ];
+ },
+
+
+ getAncestorsByClassName: function( n, className, includeSelf ) {
+ var es = DOM.getAncestors( n, includeSelf );
+ return DOM.filterElementsByClassName( es, className );
+ },
+
+
+ getFirstAncestorByClassName: function( n, className, includeSelf ) {
+ return DOM.getAncestorsByClassName( n, className, includeSelf )[ 0 ];
+ },
+
+
+ getAncestorsByTagAndClassName: function( n, tagName, className, includeSelf ) {
+ var es = DOM.getAncestorsByTagName( n, tagName, includeSelf );
+ return DOM.filterElementsByClassName( es, className );
+ },
+
+
+ getFirstAncestorByTagAndClassName: function( n, tagName, className, includeSelf ) {
+ return DOM.getAncestorsByTagAndClassName( n, tagName, className, includeSelf )[ 0 ];
+ },
+
+
+ getPreviousElement: function( n ) {
+ n = n.previousSibling;
+ while( n ) {
+ if( n.nodeType == Node.ELEMENT_NODE )
+ return n;
+ n = n.previousSibling;
+ }
+ return null;
+ },
+
+
+ getNextElement: function( n ) {
+ n = n.nextSibling;
+ while( n ) {
+ if( n.nodeType == Node.ELEMENT_NODE )
+ return n;
+ n = n.nextSibling;
+ }
+ return null;
+ },
+
+
+ isInlineNode: function( n ) {
+ // text nodes are inline
+ if( n.nodeType == Node.TEXT_NODE )
+ return n;
+
+ // document nodes are non-inline
+ if( n.nodeType == Node.DOCUMENT_NODE )
+ return false;
+
+ // all nonelement nodes are inline
+ if( n.nodeType != Node.ELEMENT_NODE )
+ return n;
+
+ // br elements are not inline
+ if( n.tagName && n.tagName.toLowerCase() == "br" )
+ return false;
+
+ // examine the style property of the inline n
+ var display = DOM.getStyle( n, "display" );
+ if( display && display.indexOf( "inline" ) >= 0 )
+ return n;
+ },
+
+
+ isTextNode: function( n ) {
+ if( n.nodeType == Node.TEXT_NODE )
+ return n;
+ },
+
+
+ isInlineTextNode: function( n ) {
+ if( n.nodeType == Node.TEXT_NODE )
+ return n;
+ if( !DOM.isInlineNode( n ) )
+ return null;
+ },
+
+
+ /* this and the following classname functions honor w3c case-sensitive classnames */
+
+ getClassNames: function( e ) {
+ if( !e || !e.className )
+ return [];
+ return e.className.split( /\s+/g );
+ },
+
+
+ hasClassName: function( e, className ) {
+ if( !e || !e.className )
+ return false;
+ var cs = DOM.getClassNames( e );
+ for( var i = 0; i < cs.length; i++ ) {
+ if( cs[ i ] == className )
+ return true;
+ }
+ return false;
+ },
+
+
+ addClassName: function( e, className ) {
+ if( !e || !className )
+ return false;
+ var cs = DOM.getClassNames( e );
+ for( var i = 0; i < cs.length; i++ ) {
+ if( cs[ i ] == className )
+ return true;
+ }
+ cs.push( className );
+ e.className = cs.join( " " );
+ return false;
+ },
+
+
+ removeClassName: function( e, className ) {
+ var r = false;
+ if( !e || !e.className || !className )
+ return r;
+ var cs = (e.className && e.className.length)
+ ? e.className.split( /\s+/g )
+ : [];
+ var ncs = [];
+ for( var i = 0; i < cs.length; i++ ) {
+ if( cs[ i ] == className ) {
+ r = true;
+ continue;
+ }
+ ncs.push( cs[ i ] );
+ }
+ if( r )
+ e.className = ncs.join( " " );
+ return r;
+ },
+
+
+ /* tree manipulation methods */
+
+ replaceWithChildNodes: function( n ) {
+ var firstChild = n.firstChild;
+ var parentNode = n.parentNode;
+ while( n.firstChild )
+ parentNode.insertBefore( n.removeChild( n.firstChild ), n );
+ parentNode.removeChild( n );
+ return firstChild;
+ },
+
+
+ /* factory methods */
+
+ createInvisibleInput: function( d ) {
+ if( !d )
+ d = window.document;
+ var e = document.createElement( "input" );
+ e.setAttribute( "autocomplete", "off" );
+ e.autocomplete = "off";
+ DOM.makeInvisible( e );
+ return e;
+ },
+
+
+ getMouseEventAttribute: function( event, a ) {
+ if( !a )
+ return;
+ var es = DOM.getAncestors( event.target, true );
+ for( var i = 0; i < es.length; i++ ) {
+ try {
+ var e = es[ i ]
+ var v = e.getAttribute ? e.getAttribute( a ) : null;
+ if( v ) {
+ event.attributeElement = e;
+ event.attribute = v;
+ return v;
+ }
+ } catch( e ) {}
+ }
+ },
+
+
+ setElementAttribute: function( e, a, v ) {
+ /* safari workaround
+ * safari's setAttribute assumes you want to use a namespace
+ * when you have a colon in your attribute
+ */
+ if ( navigator.userAgent.toLowerCase().match(/webkit/) ) {
+ var at = e.attributes;
+ for ( var i = 0; i < at.length; i++ )
+ if ( at[ i ].name == a )
+ return at[ i ].nodeValue = v;
+ } else
+ e.setAttribute( a, v );
+ },
+
+
+ swapAttributes: function( e, tg, at ) {
+ var ar = e.getAttribute( tg );
+ if( !ar )
+ return false;
+
+ /* clone the node with all children */
+ if ( e.tagName.toLowerCase() == 'script' ) {
+ /* only clone and replace script tags */
+ var cl = e.cloneNode( true );
+ if ( !cl )
+ return false;
+
+ DOM.setElementAttribute( cl, at, ar );
+ cl.removeAttribute( tg );
+
+ /* replace new, old */
+ return e.parentNode.replaceChild( cl, e );
+ } else {
+ DOM.setElementAttribute( e, at, ar );
+ e.removeAttribute( tg );
+ }
+ },
+
+
+ findPosX: function( e ) {
+ var curleft = 0;
+
+ if (e.offsetParent) {
+ while (1) {
+ curleft += e.offsetLeft;
+ if (!e.offsetParent) {
+ break;
+ }
+ e = e.offsetParent;
+ }
+ } else if (e.x) {
+ curleft += e.x;
+ }
+
+ return curleft;
+ },
+
+
+ findPosY: function( e ) {
+ var curtop = 0;
+
+ if (e.offsetParent) {
+ while (1) {
+ curtop += e.offsetTop;
+ if (!e.offsetParent) {
+ break;
+ }
+ e = e.offsetParent;
+ }
+ } else if (e.y) {
+ curtop += e.y;
+ }
+
+ return curtop;
+ }
+
+
+} );
+
+
+$ = DOM.getElement;
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/hourglass.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/hourglass.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,59 @@
+// LiveJournal javascript standard interface routines
+
+// create a little animated hourglass at (x,y) with a unique-ish ID
+// returns the element created
+Hourglass = new Class( Object, {
+ init: function(widget, classname) {
+ this.ele = document.createElement("img");
+ if (!this.ele) return;
+
+ var imgprefix = Site ? Site.imgprefix : '';
+
+ this.ele.src = imgprefix ? imgprefix + "/hourglass.gif" : "/img/hourglass.gif";
+ this.ele.style.position = "absolute";
+
+ DOM.addClassName(this.ele, classname);
+
+ if (widget)
+ this.hourglass_at_widget(widget);
+ },
+
+ hourglass_at: function (x, y) {
+ this.ele.width = 17;
+ this.ele.height = 17;
+ this.ele.style.top = (y - 8) + "px";
+ this.ele.style.left = (x - 8) + "px";
+
+ // unique ID
+ this.ele.id = "lj_hourglass" + x + "." + y;
+
+ document.body.appendChild(this.ele);
+ },
+
+ add_class_name: function (classname) {
+ if (this.ele)
+ DOM.addClassName(this.ele, classname);
+ },
+
+ hourglass_at_widget: function (widget) {
+ var dim = DOM.getAbsoluteDimensions(widget);
+ var x = dim.absoluteLeft;
+ var y = dim.absoluteTop;
+ var w = dim.absoluteRight - x;
+ var h = dim.absoluteBottom - y;
+ if (w && h) {
+ x += w/2;
+ y += h/2;
+ }
+ this.hourglass_at(x, y);
+ },
+
+ hide: function () {
+ if (this.ele) {
+ try {
+ document.body.removeChild(this.ele);
+ } catch (e) {}
+ }
+ }
+
+} );
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/httpreq.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/httpreq.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,113 @@
+var HTTPReq = new Object;
+
+HTTPReq.create = function () {
+ var xtr;
+ var ex;
+
+ if (typeof(XMLHttpRequest) != "undefined") {
+ xtr = new XMLHttpRequest();
+ } else {
+ try {
+ xtr = new ActiveXObject("Msxml2.XMLHTTP.4.0");
+ } catch (ex) {
+ try {
+ xtr = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (ex) {
+ }
+ }
+ }
+
+ // let me explain this. Opera 8 does XMLHttpRequest, but not setRequestHeader.
+ // no problem, we thought: we'll test for setRequestHeader and if it's not present
+ // then fall back to the old behavior (treat it as not working). BUT --- IE6 won't
+ // let you even test for setRequestHeader without throwing an exception (you need
+ // to call .open on the .xtr first or something)
+ try {
+ if (xtr && ! xtr.setRequestHeader)
+ xtr = null;
+ } catch (ex) { }
+
+ return xtr;
+};
+
+// opts:
+// url, onError, onData, method (GET or POST), data
+// url: where to get/post to
+// onError: callback on error
+// onData: callback on data received
+// method: HTTP method, GET by default
+// data: what to send to the server (urlencoded)
+HTTPReq.getJSON = function (opts) {
+ var req = HTTPReq.create();
+ if (! req) {
+ if (opts.onError) opts.onError("noxmlhttprequest");
+ return;
+ }
+
+ var state_callback = function () {
+ if (req.readyState != 4) return;
+
+ if (req.status != 200) {
+ if (opts.onError) opts.onError(req.status ? "status: " + req.status : "no data");
+ return;
+ }
+
+ var resObj;
+ var e;
+ try {
+ eval("resObj = " + req.responseText + ";");
+ } catch (e) {
+ }
+
+ if (e || ! resObj) {
+ if (opts.onError)
+ opts.onError("Error parsing response: \"" + req.responseText + "\"");
+
+ return;
+ }
+
+ if (opts.onData)
+ opts.onData(resObj);
+ };
+
+ req.onreadystatechange = state_callback;
+
+ var method = opts.method || "GET";
+ var data = opts.data || null;
+
+ var url = opts.url;
+ if (opts.method == "GET" && opts.data) {
+ url += url.match(/\?/) ? "&" : "?";
+ url += opts.data
+ }
+
+ url += url.match(/\?/) ? "&" : "?";
+ url += "_rand=" + Math.random();
+
+ req.open(method, url, true);
+
+ // we should send null unless we're in a POST
+ var to_send = null;
+
+ if (method.toUpperCase() == "POST") {
+ req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ to_send = data;
+ }
+
+ req.send(to_send);
+};
+
+HTTPReq.formEncoded = function (vars) {
+ var enc = [];
+ var e;
+ for (var key in vars) {
+ try {
+ if (!vars.hasOwnProperty(key))
+ continue;
+ enc.push(encodeURIComponent(key) + "=" + encodeURIComponent(vars[key]));
+ } catch( e ) {}
+ }
+ return enc.join("&");
+
+};
+
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/image-region-select.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/image-region-select.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,337 @@
+/*
+ Copyright (c) 2006, Six Apart, Ltd.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/* ***************************************************************************
+
+ Class: ImageRegionSelect
+
+ About:
+
+ Constructor:
+
+*************************************************************************** */
+
+var ImageRegionSelect = new Class( Object, {
+ init: function () {
+ var self = this;
+
+ if (arguments.length != 1) {
+ alert("Bogus args");
+ return;
+ }
+
+ var opts = arguments[0];
+ ["onRegionChange",
+ "onRegionChanged",
+ "onClick",
+ "onDebug",
+ ].forEach(function (v) {
+ self[v] = opts[v];
+ });
+
+ if (opts.src && typeof opts.src == 'object') {
+ this.imgEle = opts.src;
+ } else {
+ this.imgEle = $(opts.src);
+ }
+
+ var imgEle = this.imgEle;
+
+ if (!imgEle) {
+ this.error = "no image element";
+ return;
+ }
+
+ var w = imgEle.width;
+ var h = imgEle.height;
+ this.width = w;
+ this.height = h;
+
+ this.keepSquareAspect = false;
+
+ var containerDiv = this.containerDiv = document.createElement("div");
+ //containerDiv.style.border = "2px solid red";
+ containerDiv.style.width = w + "px";
+ containerDiv.style.height = h + "px";
+ containerDiv.style.background = "yellow";
+ containerDiv.style.position = "relative";
+ containerDiv.style.cursor = "crosshair";
+
+ imgEle.parentNode.replaceChild(containerDiv, imgEle);
+ containerDiv.appendChild(imgEle);
+ imgEle.style.position = "absolute";
+ imgEle.style.top = "0px";
+ imgEle.style.left = "0px";
+
+ // IE-specific attribute to disable the on-image toolbar:
+ imgEle.setAttribute("galleryimg", "no");
+
+ // make the black and white dotted ants
+ var makeAnts = function (color) {
+ var ele = document.createElement("div");
+ ele.style.position = "absolute";
+ ele.style.top = "0px";
+ ele.style.left = "0px";
+ ele.style.width = w + "px";
+ ele.style.height = h + "px";
+ ele.style.border = "2px dashed " + color;
+ containerDiv.appendChild(ele);
+ return ele;
+ };
+ this.ants1 = makeAnts("white");
+ this.ants2 = makeAnts("black");
+
+ var coverNode = document.createElement("div");
+ coverNode.style.width = w + "px";
+ coverNode.style.height = h + "px";
+ //coverNode.style.border = "2px solid green";
+ coverNode.style.position = "absolute";
+ coverNode.style.top = "0px";
+ coverNode.style.left = "0px";
+ containerDiv.appendChild(coverNode);
+
+ // setup event handlers
+ var eatEvent = function (e) {
+ e = Event.prep(e);
+ return e.stop();
+ };
+ imgEle.onmousemove = eatEvent;
+ containerDiv.onmousemove = eatEvent;
+ containerDiv.onmousedown = ImageRegionSelect.containerMouseDown.bindEventListener(this);
+
+ this.setEnabled(true);
+ this.reset();
+ },
+
+ fireOnRegionChanged: function () {
+ if (!this.onRegionChanged) return;
+ this.onRegionChanged(this.getSelectedRegion());
+ },
+
+ getSelectedRegion: function () {
+ return {
+ x1: this.tlx,
+ y1: this.tly,
+ x2: this.brx,
+ y2: this.bry
+ };
+ },
+
+ setEnabled: function (onoff) {
+ this.enabled = onoff;
+ [this.ants1, this.ants2].forEach(function (ele) { ele.style.display = onoff ? "block" : "none"; });
+ },
+
+ dbg: function (msg) {
+ if (this.onDebug)
+ this.onDebug(msg);
+ },
+
+ reset: function () {
+ this.tlx = 0;
+ this.brx = this.width;
+ this.tly = 0;
+ this.bry = this.height;
+ this.adjustAnts();
+ this.fireOnRegionChanged();
+ },
+
+ handleClick: function (e) {
+ if (! this.enabled) return;
+
+ e = Event.prep(e);
+ var pos = this.relPos(e);
+
+ if (this.onClick) {
+ this.onClick(pos); // contains .x and .y
+ }
+ },
+
+ relPos: function (e) {
+ e = Event.prep(e);
+ var loc = DOM.getAbsoluteCursorPosition(e);
+ var ctrDim = DOM.getAbsoluteDimensions(this.containerDiv);
+ return {x: loc.x - ctrDim.absoluteLeft,
+ y: loc.y - ctrDim.absoluteTop };
+ },
+
+ sortPoints: function () {
+ var t;
+ if (this.tlx > this.brx) {
+ t = this.tlx;
+ this.tlx = this.brx;
+ this.brx = t;
+ }
+
+ if (this.tly > this.bry) {
+ t = this.tly;
+ this.tly = this.bry;
+ this.bry = t;
+ }
+ },
+
+ setTopLeft: function (x, y) {
+ if (! this.enabled) return;
+
+ x = max(0, min(x, this.width));
+ y = max(0, min(y, this.height));
+ this.tlx = x;
+ this.tly = y;
+ this.adjustAnts();
+ },
+
+ setBottomRight: function (x, y, isShift) {
+ if (! this.enabled) return;
+
+ x = max(0, min(x, this.width));
+ y = max(0, min(y, this.height));
+
+ if (isShift) {
+ var dx = Math.abs(this.tlx - x);
+ var dy = Math.abs(this.tly - y);
+ var d = max(dx, dy);
+
+ this.brx = min(this.tlx + ((x > this.tlx) ? 1 : -1) * d, this.width);
+ this.bry = min(this.tly + ((y > this.tly) ? 1 : -1) * d, this.height);
+ if (this.brx < 0) this.brx = 0;
+ if (this.bry < 0) this.bry = 0;
+ } else {
+ this.brx = x;
+ this.bry = y;
+ }
+ this.adjustAnts();
+ },
+
+ adjustAnts: function () {
+ if (! this.enabled) return;
+
+ var minx = min(this.tlx, this.brx);
+ var miny = min(this.tly, this.bry);
+ var width = max(4, Math.abs(this.brx - this.tlx));
+ var height = max(4, Math.abs(this.bry - this.tly));
+
+ if (this.onRegionChange) {
+ this.onRegionChange({
+ x1: minx,
+ y1: miny,
+ x2: minx + width,
+ y2: miny + height
+ });
+ }
+
+ this.ants1.style.left = minx + "px";
+ this.ants1.style.top = miny + "px";
+ this.ants1.style.width = width + "px";
+ this.ants1.style.height = height + "px";
+
+ this.ants2.style.left = (minx + 2) + "px";
+ this.ants2.style.top = (miny + 2) + "px";
+ this.ants2.style.width = (width - 4) + "px";
+ this.ants2.style.height = (height - 4) + "px";
+ },
+
+ keepSquare: function (keepSquareAspect) {
+ this.keepSquareAspect = keepSquareAspect;
+ },
+
+ dummy: 1
+});
+
+ImageRegionSelect.containerMouseDown = function (e) {
+ //this.dbg("onKeyDown, code="+code+", shift="+e.shiftKey);
+
+ e = Event.prep(e);
+ var dpos = this.relPos(e);
+ var self = this;
+
+ var ctrDiv = this.containerDiv;
+ var did_topleft = false;
+ var imgEle = this.imgEle;
+
+ var isClose = function (pos) {
+ // this looks stupid, but it's the only way that'll work: I tried
+ // to just return the expression in the if block, but it wasn't working.
+ // not sure what I'm not understanding here. --brad
+ if (Math.abs(pos.x - dpos.x) < 10 &&
+ Math.abs(pos.y - dpos.y) < 10) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+
+ // IE's onmousemove event comes in from a different place than the mousedown/up.
+ // whatever.
+ imgEle.onmousemove = ctrDiv.onmousemove = function (emove) {
+ emove = Event.prep(emove);
+ var mpos = self.relPos(emove);
+
+ var isShift = emove.shiftKey || self.keepSquareAspect;
+ //log(trackerPlane + ": mouse move");
+
+ if (did_topleft) {
+ self.setBottomRight(mpos.x, mpos.y, isShift);
+ } else if (! isClose(mpos)) {
+ did_topleft = true;
+ self.setTopLeft(dpos.x, dpos.y);
+ self.setBottomRight(mpos.x, mpos.y, isShift);
+ }
+
+ return emove.stop();
+ };
+
+ ctrDiv.onmouseup = function (eup) {
+ eup = Event.prep(eup);
+ var upos = self.relPos(eup);
+
+ ctrDiv.onmousemove = null;
+ ctrDiv.onmouseup = null;
+ imgEle.onmousemove = null;
+
+ if (!did_topleft) {
+ self.handleClick(eup);
+ return eup.stop();
+ }
+
+ self.sortPoints();
+
+ self.fireOnRegionChanged();
+
+ return eup.stop();
+
+ };
+
+ return e.stop();
+};
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/inputcomplete.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/inputcomplete.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,426 @@
+/* input completion library */
+
+/* TODO:
+ -- test on non-US keyboard layouts (too much use of KeyCode)
+ -- lazy data model (xmlhttprequest, or generic callbacks)
+ -- drop-down menu?
+ -- option to disable comma-separated mode (or explicitly ask for it)
+*/
+
+/*
+ Copyright (c) 2005, Six Apart, Ltd.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+/* ***************************************************************************
+
+ Class: InputCompleteData
+
+ About: An InputComplete object needs a data source to auto-complete
+ from. This is that model. You can create one from an
+ array, or create a lazy version that gets its data over the
+ network, on demand. You will probably not use this class'
+ methods directly, as they're called by the InputComplete
+ object.
+
+ The closer a word is to the beginning of the array, the more
+ likely it will be recommended as the word the user is typing.
+
+ If you pass the string "ignorecase" as the second argument in
+ the constructor, then the case of both the user's input and
+ the data in the array will be ignored when looking for a match.
+
+ Constructor:
+
+ var model = new InputCompleteData ([ "foo", "bar", "alpha" ]);
+
+*************************************************************************** */
+
+var InputCompleteData = new Class ( Object, {
+ init: function () {
+ if (arguments[0] instanceof Array) {
+ this.source = [];
+
+ // copy the user-provided array (which is sorted most
+ // likely to least likely) into our internal form, which
+ // is opposite, with most likely at the end.
+ var arg = arguments[0];
+ for (var i=arg.length-1; i>=0; i--) {
+ this.source.length++;
+ this.source[this.source.length-1] = arg[i];
+ }
+ }
+
+ this.ignoreCase = 0;
+ if (arguments[1] == "ignorecase") {
+ this.ignoreCase = 1;
+ }
+ },
+
+ // method: given prefix, returns best suffix, or null if no answer
+ bestFinish: function (pre) {
+ if (! pre || pre.length == 0)
+ return null;
+
+ if (! this.source)
+ return null;
+
+ var i;
+ for (i=this.source.length-1; i>=0; i--) {
+ var item = this.source[i];
+
+ var itemToCompare = item;
+ var preToCompare = pre;
+ if (this.ignoreCase) {
+ item += '';
+ pre += '';
+ itemToCompare = item.toLowerCase();
+ preToCompare = pre.toLowerCase();
+ }
+
+ if (itemToCompare.substring(0, pre.length) == preToCompare) {
+ var suff = item.substring(pre.length, item.length);
+ return suff;
+ }
+ }
+
+ return null;
+ },
+
+ // method: given a piece of data, learn it, and prioritize it for future completions
+ learn: function (word) {
+ if (!word) return false;
+ if (!this.source) return false;
+ this.source[this.source.length++] = word;
+
+ if (this.onModelChange)
+ this.onModelChange();
+ },
+
+ getItems: function () {
+ if (!this.source) return [];
+
+ // return only unique items to caller
+ var uniq = [];
+ var seen = {};
+ for (i=this.source.length-1; i>=0; i--) {
+ var item = this.source[i];
+ if (! seen[item]) {
+ seen[item] = 1;
+ uniq.length++;
+ uniq[uniq.length - 1] = item;
+ }
+ }
+
+ return uniq;
+ },
+
+ dummy: 1
+});
+
+/* ***************************************************************************
+
+ Class: InputComplete
+
+ About:
+
+ Constructor:
+
+*************************************************************************** */
+
+var InputComplete = new Class( Object, {
+ init: function () {
+ var opts = arguments[0];
+ var ele;
+ var model;
+ var debug;
+
+ if (arguments.length == 1) {
+ ele = opts["target"];
+ model = opts["model"];
+ debug = opts["debug"];
+ } else {
+ ele = arguments[0];
+ model = arguments[1];
+ debug = arguments[2];
+ }
+
+ this.ele = ele;
+ this.model = model;
+ this.debug = debug;
+
+ // no model? don't setup object.
+ if (! ele) {
+ this.disabled = true;
+ return;
+ }
+
+ // return false if auto-complete won't work anyway
+ if (! (("selectionStart" in ele) || (document.selection && document.selection.createRange)) ) {
+ this.disabled = true;
+ return false;
+ }
+
+ DOM.addEventListener(ele, "focus", InputComplete.onFocus.bindEventListener(this));
+ DOM.addEventListener(ele, "keydown", InputComplete.onKeyDown.bindEventListener(this));
+ DOM.addEventListener(ele, "keyup", InputComplete.onKeyUp.bindEventListener(this));
+ DOM.addEventListener(ele, "blur", InputComplete.onBlur.bindEventListener(this));
+ },
+
+ dbg: function (msg) {
+ if (this.debug) {
+ this.debug(msg);
+ }
+ },
+
+ // returns the word currently being typed, or null
+ wordInProgress: function () {
+ var sel = this.getSelectedRange();
+ if (!sel) return null;
+
+ var cidx = sel.selectionStart; // current indx
+ var sidx = cidx; // start of word index
+ while (sidx > 0 && this.ele.value.charAt(sidx) != ',') {
+ sidx--;
+ }
+ var skipStartForward = function (chr) { return (chr == "," || chr == " "); }
+
+ while (skipStartForward(this.ele.value.charAt(sidx))) {
+ sidx++;
+ }
+
+ return this.ele.value.substring(sidx, this.ele.value.length);
+ },
+
+ // appends some selected text after the care
+ addSelectedText: function (chars) {
+ var sel = this.getSelectedRange();
+ this.ele.value = this.ele.value + chars;
+ this.setSelectedRange(sel.selectionStart, this.ele.value.length);
+ },
+
+ moveCaretToEnd: function () {
+ var len = this.ele.value.length;
+ this.setSelectedRange(len, len);
+ },
+
+ getSelectedRange: function () {
+ var ret = {};
+ var ele = this.ele;
+
+ if ("selectionStart" in ele) {
+ ret.selectionStart = ele.selectionStart;
+ ret.selectionEnd = ele.selectionEnd;
+ return ret;
+ }
+
+ if (document.selection && document.selection.createRange) {
+ var range = document.selection.createRange();
+ ret.selectionStart = InputComplete.IEOffset(range, "StartToStart");
+ ret.selectionEnd = InputComplete.IEOffset(range, "EndToEnd");
+ return ret;
+ }
+
+ return null;
+ },
+
+ setSelectedRange: function (sidx, eidx) {
+ var ele = this.ele;
+
+ // preferred to setting selectionStart and end
+ if (ele.setSelectionRange) {
+ ele.focus();
+ ele.setSelectionRange(sidx, eidx);
+ return true;
+ }
+
+ // IE
+ if (document.selection && document.selection.createRange) {
+ ele.focus();
+ var sel = document.selection.createRange ();
+ sel.moveStart('character', -ele.value.length);
+ sel.moveStart('character', sidx);
+ sel.moveEnd('character', eidx - sidx);
+ sel.select();
+ return true;
+ }
+
+ // mozilla
+ if ("selectionStart" in ele) {
+ ele.selectionStart = sidx;
+ ele.selectionEnd = eidx;
+ return true;
+ }
+
+ return false;
+ },
+
+ // returns true if caret is at end of line, or everything to the right
+ // of us is selected
+ caretAtEndOfNotSelected: function (sel) {
+ sel = sel || this.getSelectedRange();
+ var len = this.ele.value.length;
+ return sel.selectionEnd == len;
+ },
+
+ disable: function () {
+ this.disabled = true;
+ },
+
+ dummy: 1
+});
+
+InputComplete.onKeyDown = function (e) {
+ if (this.disabled) return;
+
+ var code = e.keyCode || e.which;
+
+ this.dbg("onKeyDown, code="+code+", shift="+e.shiftKey);
+
+ // if comma, but not with a shift which would be "<". (FIXME: what about other keyboards layouts?)
+ //FIXME: may be there is a stable cross-browser way to detect so-called other keyboard layouts - but i don't know anything easier than ... (see onKeyUp changes in tis revision)
+ /*if ((code == 188 || code == 44) && ! e.shiftKey && this.caretAtEndOfNotSelected()) {
+ this.moveCaretToEnd();
+ return Event.stop(e);
+ }*/
+
+ return true;
+};
+
+InputComplete.onKeyUp = function (e) {
+ if (this.disabled) return;
+
+ var val = this.ele.value;
+
+ var code = e.keyCode || e.which;
+ this.dbg("keyUp = " + code);
+
+
+ // ignore tab, backspace, left, right, delete, and enter
+ if (code == 9 || code == 8 || code == 37 || code == 39 || code == 46 || code == 13)
+ return false;
+
+ var sel = this.getSelectedRange();
+
+ var ss = sel.selectionStart;
+ var se = sel.selectionEnd;
+
+ this.dbg("keyUp, got ss="+ss + ", se="+se+", val.length="+val.length);
+
+ // only auto-complete if we're at the end of the line
+ if (se != val.length) return false;
+
+ var chr = String.fromCharCode(code);
+
+ this.dbg("keyUp, got chr="+chr);
+ //if (code == 188 || chr == ",") {
+ if(/,$/.test(val)){
+ if (! this.caretAtEndOfNotSelected(sel)) {
+ return false;
+ }
+
+ this.dbg("hit comma! .. value = " + this.ele.value);
+
+ this.ele.value = this.ele.value.replace(/[\s,]+$/, "") + ", ";
+ this.moveCaretToEnd();
+
+ return Event.stop(e);
+ }
+
+
+ var inProg = this.wordInProgress();
+ if (!inProg) return true;
+
+ var rest = this.model.bestFinish(inProg);
+
+ if (rest && rest.length > 0) {
+ this.addSelectedText(rest);
+ }
+};
+
+InputComplete.onBlur = function (e) {
+ if (this.disabled) return;
+
+ var tg = e.target;
+ var list = tg.value;
+
+ var noendjunk = list.replace(/[\s,]+$/, "");
+ if (noendjunk != list) {
+ tg.value = list = noendjunk;
+ }
+
+ var tags = list.split(",");
+ for (var i =0; i<tags.length; i++) {
+ var tag = tags[i].replace(/^\s+/,"").replace(/\s+$/,"");
+ if (tag.length) {
+ this.model.learn(tag);
+ }
+ }
+};
+
+InputComplete.onFocus = function (e) {
+ if (this.disabled) return;
+};
+
+
+InputComplete.IEOffset = function ( range, compareType ) {
+ if (this.disabled) return;
+
+ var range2 = range.duplicate();
+ range2.collapse( true );
+ var parent = range2.parentElement();
+ var length = range2.text.length;
+ range2.move("character", -parent.value.length);
+
+ var delta = max( 1, finiteInt( length * 0.5 ) );
+ range2.collapse( true );
+ var offset = 0;
+ var steps = 0;
+
+ // bail after 10k iterations in case of borkage
+ while( (test = range2.compareEndPoints( compareType, range )) != 0 ) {
+ if( test < 0 ) {
+ range2.move( "character", delta );
+ offset += delta;
+ } else {
+ range2.move( "character", -delta );
+ offset -= delta;
+ }
+ delta = max( 1, finiteInt( delta * 0.5 ) );
+ steps++;
+ if( steps > 1000 )
+ throw "unable to find textrange endpoint in " + steps + " steps";
+ }
+
+ return offset;
+};
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/ippu.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/ippu.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,732 @@
+/*
+ IPPU methods:
+ init([innerHTML]) -- takes innerHTML as optional argument
+ show() -- shows the popup
+ hide() -- hides popup
+ cancel() -- hides and calls cancel callback
+
+ Content setters:
+ setContent(innerHTML) -- set innerHTML
+ setContentElement(element) -- adds element as a child of the popup
+
+ Accessors:
+ getElement() -- returns popup DIV element
+ visible() -- returns whether the popup is visible or not
+
+ Titlebar:
+ setTitlebar(show) -- true: show titlebar / false: no titlebar
+ setTitle(title) -- sets the titlebar text
+ getTitlebarElement() -- returns the titlebar element
+ setTitlebarClass(className) -- set the class of the titlebar
+
+ Styling:
+ setOverflow(overflow) -- sets ele.style.overflow to overflow
+ addClass(className) -- adds class to popup
+ removeClass(className) -- removes class to popup
+
+ Browser Hacks:
+ setAutoHideSelects(autohide) -- when the popup is shown should it find all the selects
+ on the page and hide them (and show them again) (for IE)
+
+ Positioning/Sizing:
+ setLocation(left, top) -- set popup location: will be pixels if units not specified
+ setLeft(left) -- set left location
+ setTop(top) -- set top location
+ setDimensions(width, height) -- set popup dimensions: will be pixels if units not specified
+ setAutoCenter(x, y) -- what dimensions to auto-center
+ center() -- centers popup on screen
+ centerX() -- centers popup horizontally
+ centerY() -- centers popup vertically
+ setFixedPosition(fixed) -- should the popup stay fixed on the page when it scrolls?
+ centerOnWidget(widget) -- center popup on this widget
+ setAutoCenterCallback(callback) -- calls callback with this IPPU instance as a parameter
+ for auto-centering. Some common built-in class methods
+ you can use as callbacks are:
+ IPPU.center
+ IPPU.centerX
+ IPPU.centerY
+
+ moveForward(amount) -- increases the zIndex by one or amount if specified
+ moveBackward(amount) -- decreases the zIndex by one or amount if specified
+
+ Modality:
+ setClickToClose(clickToClose) -- if clickToClose is true, clicking outside of the popup
+ will close it
+ setModal(modality) -- If modality is true, then popup will capture all mouse events
+ and optionally gray out the rest of the page. (overrides clickToClose)
+ setOverlayVisible(visible) -- If visible is true, when this popup is on the page it
+ will gray out the rest of the page if this is modal
+
+ Callbacks:
+ setCancelledCallback(callback) -- call this when the dialog is closed through clicking
+ outside, titlebar close button, etc...
+ setHiddenCallback(callback) -- called when the dialog is closed in any fashion
+
+ Fading:
+ setFadeIn(fadeIn) -- set whether or not to automatically fade the ippu in
+ setFadeOut(fadeOut) -- set whether or not to automatically fade the ippu out
+ setFadeSpeed(secs) -- sets fade speed
+
+ Class Methods:
+ Handy callbacks:
+ IPPU.center
+ IPPU.centerX
+ IPPU.centerY
+ Browser testing:
+ IPPU.isIE() -- is the browser internet exploder?
+ IPPU.ieSafari() -- is this safari?
+
+////////////////////
+
+
+ippu.setModalDenialCallback(IPPU.cssBorderFlash);
+
+
+ private:
+ Properties:
+ ele -- DOM node of div
+ shown -- boolean; if element is in DOM
+ autoCenterX -- boolean; auto-center horiz
+ autoCenterY -- boolean; auto-center vertical
+ fixedPosition -- boolean; stay in fixed position when browser scrolls?
+ titlebar -- titlebar element
+ title -- string; text to go in titlebar
+ showTitlebar -- boolean; whether or not to show titlebar
+ content -- DIV containing user's specified content
+ clickToClose -- boolean; clicking outside popup will close it
+ clickHandlerSetup -- boolean; have we set up the click handlers?
+ docOverlay -- DIV that overlays the document for capturing clicks
+ modal -- boolean; capture all events and prevent user from doing anything
+ until dialog is dismissed
+ visibleOverlay -- boolean; make overlay slightly opaque
+ clickHandlerFunc -- function; function to handle document clicks
+ resizeHandlerFunc -- function; function to handle document resizing
+ autoCenterCallback -- function; what callback to call for auto-centering
+ cancelledCallback -- function; called when dialog is cancelled
+ setAutoHideSelects -- boolean; autohide all SELECT elements on the page when popup is visible
+ hiddenSelects -- array; SELECT elements that have been hidden
+ hiddenCallback -- funciton; called when dialog is hidden
+ fadeIn, fadeOut, fadeSpeed -- fading settings
+ fadeMode -- current fading mode (in, out) if there is fading going on
+
+ Methods:
+ updateTitlebar() -- create titlebar if it doesn't exist,
+ hide it if titlebar == false,
+ update titlebar text
+ updateContent() -- makes sure all currently specified properties are applied
+ setupClickCapture() -- if modal, create document-sized div overlay to capture click events
+ otherwise install document onclick handler
+ removeClickHandlers() -- remove overlay, event handlers
+ clickHandler() -- event handler for clicks
+ updateOverlay() -- if we have an overlay, make sure it's where it should be and (in)visible
+ if it should be
+ autoCenter() -- centers popup on screen according to autoCenterX and autoCenterY
+ hideSelects() -- hide all select element on page
+ showSelects() -- show all selects
+ _hide () -- actually hides everything, called by hide(), which does fading if necessary
+*/
+
+// this belongs somewhere else:
+function changeOpac(id, opacity) {
+ var e = $(id);
+ if (e && e.style) {
+ var object = e.style;
+ if (object) {
+ //reduce flicker
+ if (IPPU.isSafari() && opacity >= 100)
+ opacity = 99.99;
+
+ // IE
+ if (object.filters)
+ object.filters.alpha.opacity = opacity * 100;
+
+ object.opacity = opacity;
+ }
+ }
+}
+
+IPPU = new Class( Object, {
+ setFixedPosition: function (fixed) {
+ // no fixed position for IE
+ if (IPPU.isIE())
+ return;
+
+ this.fixedPosition = fixed;
+ this.updateContent();
+ },
+
+ clickHandler : function (evt) {
+ if (!this.clickToClose) return;
+ if (!this.visible()) return;
+
+ evt = Event.prep(evt);
+ var target = evt.target;
+ // don't do anything if inside the popup
+ if (DOM.getAncestorsByClassName(target, "ippu", true).length > 0) return;
+ this.cancel();
+ },
+
+ setCancelledCallback : function (callback) {
+ this.cancelledCallback = callback;
+ },
+
+ cancel : function () {
+ if (this.cancelledCallback)
+ this.cancelledCallback();
+ this.hide();
+ },
+
+ setHiddenCallback: function (callback) {
+ this.hiddenCallback = callback;
+ },
+
+ setupClickCapture : function () {
+ if (!this.visible() || this.clickHandlerSetup){return;}
+ if (!this.clickToClose && !this.modal) {return;}
+
+ this.clickHandlerFunc = this.clickHandler.bindEventListener(this);
+
+ if (this.modal) {
+ // create document-sized div to capture events
+ if (this.overlay) return; // wtf? shouldn't exist yet
+ this.overlay = document.createElement("div");
+ this.overlay.style.left = "0px";
+ this.overlay.style.top = "0px";
+ this.overlay.style.margin = "0px";
+ this.overlay.style.padding = "0px";
+
+ this.overlay.style.backgroundColor = "#000000";
+ this.overlay.style.zIndex="900";
+ if (IPPU.isIE()){
+ this.overlay.style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity=50)";
+ this.overlay.style.position="absolute";
+ this.overlay.style.width=document.body.scrollWidth;
+ this.overlay.style.height=document.body.scrollHeight;
+ }
+ else{
+ this.overlay.style.position = "fixed";
+ }
+
+ this.ele.parentNode.insertBefore(this.overlay, this.ele);
+ this.updateOverlay();
+
+ DOM.addEventListener(this.overlay, "click", this.clickHandlerFunc);
+ } else {
+ // simple document onclick handler
+ DOM.addEventListener(document, "click", this.clickHandlerFunc);
+ }
+
+ this.clickHandlerSetup = true;
+ },
+
+ updateOverlay : function () {
+ if (this.overlay) {
+ var cd = DOM.getClientDimensions();
+ this.overlay.style.width = (cd.x - 1) + "px";
+ if(!IPPU.isIE()){
+ this.overlay.style.height = (cd.y - 1) + "px";
+ }
+ if (this.visibleOverlay) {
+ this.overlay.backgroundColor = "#000000";
+ changeOpac(this.overlay, 0.50);
+ } else {
+ this.overlay.backgroundColor = "#FFFFFF";
+ changeOpac(this.overlay, 0.0);
+ }
+ }
+ },
+
+ resizeHandler : function (evt) {
+ this.updateContent();
+ },
+
+ removeClickHandlers : function () {
+ if (!this.clickHandlerSetup) return;
+
+ var myself = this;
+ var handlerFunc = function (evt) {
+ myself.clickHandler(evt);
+ };
+
+ DOM.removeEventListener(document, "click", this.clickHandlerFunc, false);
+
+ if (this.overlay) {
+ DOM.removeEventListener(this.overlay, "click", this.clickHandlerFunc, true);
+ this.overlay.parentNode.removeChild(this.overlay);
+ this.overlay = undefined;
+ }
+
+ this.clickHandlerFunc = undefined;
+ this.clickHandlerSetup = false;
+ },
+
+ setClickToClose : function (clickToClose) {
+ this.clickToClose = clickToClose;
+
+ if (!this.clickHandlerSetup && clickToClose && this.visible()) {
+ // popup is already visible, need to set up click handler
+ var setupClickCaptureCallback = this.setupClickCapture.bind(this);
+ window.setTimeout(setupClickCaptureCallback, 100);
+ } else if (!clickToClose && this.clickHandlerSetup) {
+ this.removeClickHandlers();
+ }
+
+ this.updateContent();
+ },
+
+ setModal : function (modal) {
+ var changed = (this.modal == modal);
+
+ // if it's modal, we don't want click-to-close
+ if (modal)
+ this.setClickToClose(false);
+
+ this.modal = modal;
+ if (changed) {
+ this.removeClickHandlers();
+ this.updateContent();
+ }
+ },
+
+ setOverlayVisible : function (vis) {
+ this.visibleOverlay = vis;
+ this.updateContent();
+ },
+
+ updateContent : function () {
+ this.autoCenter();
+ this.updateTitlebar();
+ this.updateOverlay();
+ if (this.titlebar)
+ this.setTitlebarClass(this.titlebar.className);
+
+ var setupClickCaptureCallback = this.setupClickCapture.bind(this);
+ window.setTimeout(setupClickCaptureCallback, 100);
+
+ if (this.fixedPosition && this.ele.style.position != "fixed")
+ this.ele.style.position = "fixed";
+ else if (!this.fixedPosition && this.ele.style.position == "fixed")
+ this.ele.style.position = "absolute";
+ },
+
+ getTitlebarElement : function () {
+ return this.titlebar;
+ },
+
+ setTitlebarClass : function (className) {
+ if (this.titlebar)
+ this.titlebar.className = className;
+ },
+
+ setOverflow : function (overflow) {
+ if (this.ele)
+ this.ele.style.overflow = overflow;
+ },
+
+ visible : function () {
+ return this.shown;
+ },
+
+ setTitlebar : function (show) {
+ this.showTitlebar = show;
+
+ if (show) {
+ if (!this.titlebar) {
+ // titlebar hasn't been created. Create it.
+ var tbar = document.createElement("div");
+ if (!tbar) return;
+ tbar.style.width = "100%";
+
+ if (this.title) tbar.innerHTML = this.title;
+ this.ele.insertBefore(tbar, this.content);
+ this.titlebar = tbar;
+
+ }
+ } else if (this.titlebar) {
+ this.ele.removeChild(this.titlebar);
+ this.titlebar = false;
+ }
+ },
+
+ setTitle : function (title) {
+ this.title = title;
+ this.updateTitlebar();
+ },
+
+ updateTitlebar : function() {
+ if (this.showTitlebar && this.titlebar && this.title != this.titlebar.innerHTML) {
+ this.titlebar.innerHTML = this.title;
+ }
+ },
+
+ addClass : function (className) {
+ DOM.addClassName(this.ele, className);
+ },
+
+ removeClass : function (className) {
+ DOM.removeClassName(this.ele, className);
+ },
+
+ setAutoCenterCallback : function (callback) {
+ this.autoCenterCallback = callback;
+ },
+
+ autoCenter : function () {
+ if (!this.visible || !this.visible()) return;
+
+ if (this.autoCenterCallback) {
+ this.autoCenterCallback(this);
+ return;
+ }
+
+ if (this.autoCenterX)
+ this.centerX();
+
+ if (this.autoCenterY)
+ this.centerY();
+ },
+
+ center : function () {
+ this.centerX();
+ this.centerY();
+ },
+
+ centerOnWidget : function (widget, offsetTop, offsetLeft) {
+ offsetTop = offsetTop || 0;
+ offsetLeft = offsetLeft || 0;
+ this.setAutoCenter(false, false);
+ this.setAutoCenterCallback(null);
+ var wd = DOM.getAbsoluteDimensions(widget);
+ var ed = DOM.getAbsoluteDimensions(this.ele);
+ var newleft = (wd.absoluteRight - wd.offsetWidth / 2 - ed.offsetWidth / 2) + offsetLeft;
+ var newtop = (wd.absoluteBottom - wd.offsetHeight / 2 - ed.offsetHeight / 2) + offsetTop;
+
+ newleft = newleft < 0 ? 0 : newleft;
+ newtop = newtop < 0 ? 0 : newtop;
+ DOM.setLeft(this.ele, newleft);
+ DOM.setTop(this.ele, newtop);
+ },
+
+ centerX : function () {
+ if (!this.visible || !this.visible()) return;
+
+ var cd = DOM.getClientDimensions();
+ var newleft = cd.x / 2 - DOM.getDimensions(this.ele).offsetWidth / 2;
+
+ // If not fixed position, center relative to the left of the page
+ if (!this.fixedPosition) {
+ var wd = DOM.getWindowScroll();
+ newleft += wd.left;
+ }
+
+ DOM.setLeft(this.ele, newleft);
+ },
+
+ centerY : function () {
+ if (!this.visible || !this.visible()) return;
+
+ var cd = DOM.getClientDimensions();
+ var newtop = cd.y / 2 - DOM.getDimensions(this.ele).offsetHeight / 2;
+
+ // If not fixed position, center relative to the top of the page
+ if (!this.fixedPosition) {
+ var wd = DOM.getWindowScroll();
+ newtop += wd.top;
+ }
+
+ DOM.setTop(this.ele, newtop);
+ },
+
+ setAutoCenter : function (autoCenterX, autoCenterY) {
+ this.autoCenterX = autoCenterX || false;
+ this.autoCenterY = autoCenterY || false;
+
+ if (!autoCenterX && !autoCenterY) {
+ this.setAutoCenterCallback(null);
+ return;
+ }
+
+ this.autoCenter();
+ },
+
+ setDimensions : function (width, height) {
+ width = width + "";
+ height = height + "";
+ if (width.match(/^\d+$/)) width += "px";
+ if (height.match(/^\d+$/)) height += "px";
+
+ this.ele.style.width = width;
+ this.ele.style.height = height;
+ },
+
+ moveForward : function (howMuch) {
+ if (!howMuch) howMuch = 1;
+ if (! this.ele) return;
+
+ this.ele.style.zIndex += howMuch;
+ },
+
+ moveBackward : function (howMuch) {
+ if (!howMuch) howMuch = 1;
+ if (! this.ele) return;
+
+ this.ele.style.zIndex -= howMuch;
+ },
+
+ setLocation : function (left, top) {
+ this.setLeft(left);
+ this.setTop(top);
+ },
+
+ setTop : function (top) {
+ top = top + "";
+ if (top.match(/^\d+$/)) top += "px";
+ this.ele.style.top = top;
+ },
+
+ setLeft : function (left) {
+ left = left + "";
+ if (left.match(/^\d+$/)) left += "px";
+ this.ele.style.left = left;
+ },
+
+ getElement : function () {
+ return this.ele;
+ },
+
+ setContent : function (html) {
+ this.content.innerHTML = html;
+ },
+
+ setContentElement : function (element) {
+ // remove child nodes
+ while (this.content.firstChild) {
+ this.content.removeChild(this.content.firstChild);
+ };
+
+ this.content.appendChild(element);
+ },
+
+ setFadeIn : function (fadeIn) {
+ this.fadeIn = fadeIn;
+ },
+
+ setFadeOut : function (fadeOut) {
+ this.fadeOut = fadeOut;
+ },
+
+ setFadeSpeed : function (fadeSpeed) {
+ this.fadeSpeed = fadeSpeed;
+ },
+
+ show : function () {
+ this.shown = true;
+
+ if (this.fadeIn) {
+ var opp = 0.01;
+
+ changeOpac(this.ele, opp);
+ }
+
+ document.body.appendChild(this.ele);
+ this.ele.style.position = "absolute";
+ if (this.autoCenterX || this.autoCenterY) this.center();
+
+ this.updateContent();
+
+ if (!this.resizeHandlerFunc) {
+ this.resizeHandlerFunc = this.resizeHandler.bindEventListener(this);
+ DOM.addEventListener(window, "resize", this.resizeHandlerFunc, false);
+ }
+
+ if (this.fadeIn)
+ this.fade("in");
+
+ this.hideSelects();
+ },
+
+ fade : function (mode, callback) {
+ var opp;
+ var delta;
+
+ var steps = 10.0;
+
+ if (mode == "in") {
+ delta = 1 / steps;
+ opp = 0.1;
+ } else {
+ if (this.ele.style.opacity)
+ opp = finiteFloat(this.ele.style.opacity);
+ else
+ opp = 0.99;
+
+ delta = -1 / steps;
+ }
+
+ var fadeSpeed = this.fadeSpeed;
+ if (!fadeSpeed) fadeSpeed = 1;
+
+ var fadeInterval = steps / fadeSpeed * 5;
+
+ this.fadeMode = mode;
+
+ var self = this;
+ var fade = function () {
+ opp += delta;
+
+ // did someone start a fade in the other direction? if so,
+ // cancel this fade
+ if (self.fadeMode && self.fadeMode != mode) {
+ if (callback)
+ callback.call(self, []);
+
+ return;
+ }
+
+ if (opp <= 0.1) {
+ if (callback)
+ callback.call(self, []);
+
+ self.fadeMode = null;
+
+ return;
+ } else if (opp >= 1.0) {
+ if (callback)
+ callback.call(self, []);
+
+ self.fadeMode = null;
+
+ return;
+ } else {
+ changeOpac(self.ele, opp);
+ window.setTimeout(fade, fadeInterval);
+ }
+ };
+
+ fade();
+ },
+
+ hide : function () {
+ if (! this.visible()) return;
+
+ if (this.fadeOut && this.ele) {
+ this.fade("out", this._hide.bind(this));
+ } else {
+ this._hide();
+ }
+ },
+
+ _hide : function () {
+ if (this.hiddenCallback)
+ this.hiddenCallback();
+
+ this.shown = false;
+ this.removeClickHandlers();
+
+ if (this.ele)
+ document.body.removeChild(this.ele);
+
+ if (this.resizeHandlerFunc)
+ DOM.removeEventListener(window, "resize", this.resizeHandlerFunc);
+
+ this.showSelects();
+ },
+
+ // you probably want this for IE being dumb
+ // (IE thinks select elements are cool and puts them in front of every element on the page)
+ setAutoHideSelects : function (autohide) {
+ this.autoHideSelects = autohide;
+ this.updateContent();
+ },
+
+ hideSelects : function () {
+ if (!this.autoHideSelects || !IPPU.isIE()) return;
+ var sels = document.getElementsByTagName("select");
+ var ele;
+ for (var i = 0; i < sels.length; i++) {
+ ele = sels[i];
+ if (!ele) continue;
+
+ // if this element is inside the ippu, skip it
+ if (DOM.getAncestorsByClassName(ele, "ippu", true).length > 0) continue;
+
+ if (ele.style.visibility != 'hidden') {
+ ele.style.visibility = 'hidden';
+ this.hiddenSelects.push(ele);
+ }
+ }
+ },
+
+ showSelects : function () {
+ if (! this.autoHideSelects) return;
+ var ele;
+ while (ele = this.hiddenSelects.pop())
+ ele.style.visibility = '';
+ },
+
+ init: function (html) {
+ var ele = document.createElement("div");
+ this.ele = ele;
+ this.shown = false;
+ this.autoCenterX = false;
+ this.autoCenterY = false;
+ this.titlebar = null;
+ this.title = "";
+ this.showTitlebar = false;
+ this.clickToClose = false;
+ this.modal = false;
+ this.clickHandlerSetup = false;
+ this.docOverlay = false;
+ this.visibleOverlay = false;
+ this.clickHandlerFunc = false;
+ this.resizeHandlerFunc = false;
+ this.fixedPosition = false;
+ this.autoCenterCallback = null;
+ this.cancelledCallback = null;
+ this.autoHideSelects = false;
+ this.hiddenCallback = null;
+ this.fadeOut = false;
+ this.fadeIn = false;
+ this.hiddenSelects = [];
+ this.fadeMode = null;
+
+ ele.style.position = "absolute";
+ ele.style.zIndex = "1000";
+
+ // plz don't remove thx
+ DOM.addClassName(ele, "ippu");
+
+ // create DIV to hold user's content
+ this.content = document.createElement("div");
+
+ this.content.innerHTML = html;
+
+ this.ele.appendChild(this.content);
+ }
+});
+
+// class methods
+IPPU.center = function (obj) {
+ obj.centerX();
+ obj.centerY();
+};
+
+IPPU.centerX = function (obj) {
+ obj.centerX();
+};
+
+IPPU.centerY = function (obj) {
+ obj.centerY();
+};
+
+IPPU.isIE = function () {
+ var UA = navigator.userAgent.toLowerCase();
+ if (UA.indexOf('msie') != -1) return true;
+ return false;
+};
+
+IPPU.isSafari = function () {
+ var UA = navigator.userAgent.toLowerCase();
+ if (UA.indexOf('safari') != -1) return true;
+ return false;
+};
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/json.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/json.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,132 @@
+/*
+JavaSript Object Notation (JSON)
+$Id$
+
+Copyright (c) 2005-2006, Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+JSON = {
+ parse: function( string ) {
+ string = string.replace( /=/g, "\\u3D" );
+ string = string.replace( /\(/g, "\\u28" );
+ try {
+ return eval( "(" + string + ")" );
+ } catch( e ) {}
+ return undefined;
+ }
+}
+
+
+Boolean.prototype.toJSON = function() {
+ return this.toString();
+}
+
+
+Number.prototype.toJSON = function() {
+ return isFinite( this ) ? this.toString() : "0";
+}
+
+
+Date.prototype.toJSON = function() {
+ return this.toUTCISOString
+ ? this.toUTCISOString().toJSON()
+ : this.toString().toJSON();
+}
+
+
+String.prototype.toJSON = function() {
+ return '"' + this.escapeJS() + '"';
+}
+
+
+RegExp.prototype.toJSON = function() {
+ return this.toString().toJSON();
+}
+
+
+Function.prototype.toJSON = function() {
+ return this.toString().toJSON();
+}
+
+
+Array.prototype.toJSON = function( root ) {
+ // crude recursion detection
+ if( !root )
+ root = this;
+ else if( root == this )
+ return "[]";
+
+ var out = [ "[" ];
+ for( var i = 0; i < this.length; i++ ) {
+ if( out.length > 1 )
+ out.push( "," );
+ if( typeof this[ i ] == "undefined" || this[ i ] == null )
+ out.push( "null" );
+ else if( !this[ i ].toJSON )
+ out.push( "{}" );
+ else
+ out.push( this[ i ].toJSON( root ) );
+ }
+ out.push( "]" );
+ return out.join( "" );
+}
+
+
+OBJ.toJSON = function( obj_this, root ) {
+ // crude recursion detection
+ if( !root )
+ root = obj_this;
+ else if( root == obj_this )
+ return "{}";
+
+ var out = [ "{" ];
+ for( var i in obj_this ) {
+ if( typeof obj_this[ i ] == "undefined" ||
+ (obj_this.hasOwnProperty && !obj_this.hasOwnProperty( i )) )
+ continue;
+ if( out.length > 1 )
+ out.push( "," );
+ out.push( OBJ.toJSON(i) );
+ if( this[ i ] == null )
+ out.push( ":null" );
+ else if( typeof obj_this[ i ] == "function" )
+ continue;
+ else if( !OBJ.toJSON(obj_this[ i ]) )
+ out.push( ":{}" );
+ else
+ out.push( ":", OBJ.toJSON(this[ i ], root) );
+ }
+ out.push( "}" );
+ return out.join( "" );
+}
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/perlbal-uploadtrack.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/perlbal-uploadtrack.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,88 @@
+////// public interface:
+
+function UploadTracker (formele, cb) {
+ this.form = formele;
+ this.callback = cb;
+ this.session = UploadTracker._generateSession();
+ this.stopped = false;
+
+ var action = this.form.action;
+ if (action.match(/\bclient_up_sess=(\w+)/)) {
+ action = action.replace(/\bclient_up_sess=(\w+)/, "client_up_sess=" + this.session);
+ } else {
+ action += (action.match(/\?/) ? "&" : "?");
+ action += "client_up_sess=" + this.session;
+ }
+ this.form.action = action;
+
+ this._startCheckStatus();
+}
+
+
+// method to stop tracking a form's upload status
+UploadTracker.prototype.stopTracking = function () {
+ this.stopped = true;
+};
+
+
+// private implementation details:
+UploadTracker._XTR = function () {
+ var xtr;
+ var ex;
+
+ if (typeof(XMLHttpRequest) != "undefined") {
+ xtr = new XMLHttpRequest();
+ } else {
+ try {
+ xtr = new ActiveXObject("Msxml2.XMLHTTP.4.0");
+ } catch (ex) {
+ try {
+ xtr = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (ex) {
+ }
+ }
+ }
+
+ // let me explain this. Opera 8 does XMLHttpRequest, but not setRequestHeader.
+ // no problem, we thought: we'll test for setRequestHeader and if it's not present
+ // then fall back to the old behavior (treat it as not working). BUT --- IE6 won't
+ // let you even test for setRequestHeader without throwing an exception (you need
+ // to call .open on the .xtr first or something)
+ try {
+ if (xtr && ! xtr.setRequestHeader)
+ xtr = null;
+ } catch (ex) { }
+
+ return xtr;
+};
+
+
+UploadTracker._generateSession = function () {
+ var str = Math.random() + "";
+ return curSession = str.replace(/[^\d]/, "");
+};
+
+
+UploadTracker.prototype._startCheckStatus = function () {
+ var uptrack = this;
+ if (uptrack.stopped) return true;
+
+ var xtr = UploadTracker._XTR();
+ if (!xtr) return;
+
+ var callback = function () {
+ if (xtr.readyState != 4) return;
+ if (uptrack.stopped) return;
+
+ if (xtr.status == 200) {
+ var val;
+ eval("val = " + xtr.responseText + ";");
+ uptrack.callback(val);
+ }
+ setTimeout(function () { uptrack._startCheckStatus(); }, 1000);
+ };
+
+ xtr.onreadystatechange = callback;
+ xtr.open("GET", "/__upload_status?client_up_sess=" + uptrack.session + "&rand=" + Math.random());
+ xtr.send(null);
+}
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/progressbar.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/progressbar.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,140 @@
+/*
+ Javascript progress bar class
+
+ To use: create a div you wish to be the progress bar, and
+ instantiate a ProgressBar with the div element
+
+ To style it you need to define several classes, a container class which
+ defines the progress bar container, an indefinite class which has your
+ "barber shop" background tile, and an overlay class which defines the look
+ of the progress bar.
+
+ requires core.js, dom.js
+*/
+
+ProgressBar = new Class ( Object, {
+ init: function (pbar) {
+ this.max = 0;
+ this.value = 0;
+ this.pbar = pbar; // container
+ this.containerClassName = "";
+ this.indefiniteClassName = "";
+ this.overlayClassName = "";
+ this.indefinite = 1;
+ this.overlay = null;
+ this.update();
+ },
+
+ setContainerClassName: function (classname) {
+ if (!this.pbar)
+ return;
+
+ DOM.removeClassName(this.pbar, classname);
+ this.containerClassName = classname;
+ this.update();
+ },
+
+ setIndefiniteClassName: function (classname) {
+ this.indefiniteClassName = classname;
+ this.update();
+ },
+
+ setOverlayClassName: function (classname) {
+ this.overlayClassName = classname;
+ this.update();
+ },
+
+ setWidth: function (w) {
+ if (!this.pbar)
+ return;
+
+ if (w+0 == w)
+ DOM.setWidth(this.pbar, w);
+ else
+ this.pbar.style.width = w;
+ },
+
+ setMax: function (max) {
+ this.max = max;
+ this.update();
+ },
+
+ setValue: function (value) {
+ this.value = value;
+ this.indefinite = false;
+ this.update();
+ },
+
+ setIndefinite: function (indef) {
+ this.indefinite = indef;
+ this.update();
+ },
+
+ max: function () {
+ return this.max;
+ },
+
+ value: function () {
+ return this.value;
+ },
+
+ hide: function () {
+ if (!this.pbar)
+ return;
+
+ this.pbar.style.display = "none";
+ },
+
+ show: function () {
+ if (!this.pbar)
+ return;
+
+ this.pbar.style.display = "";
+ },
+
+ update: function () {
+ if (!this.pbar)
+ return;
+
+ DOM.addClassName(this.pbar, this.containerClassName);
+
+ // definite or indefinite bar?
+ if (this.indefinite || this.value < 0) {
+ // barber shop
+ // is there an overlay? if so, kill it
+ if (this.overlay) {
+ this.overlay.parentNode.removeChild(this.overlay);
+ this.overlay = null;
+ }
+
+ // set the indefinite class
+ DOM.addClassName(this.pbar, this.indefiniteClassName);
+ return;
+ }
+
+ DOM.removeClassName(this.pbar, this.indefiniteClassName);
+
+ var overlay = this.overlay;
+
+ // does the progress bar container have the overlay?
+ if (!this.overlay) {
+ overlay = document.createElement("div");
+
+ if (!overlay)
+ return;
+
+ this.pbar.appendChild(overlay);
+ }
+
+ DOM.addClassName(overlay, this.overlayClassName);
+
+ var dim = DOM.getAbsoluteDimensions(this.pbar);
+ var pct = this.value/this.max;
+ var oldWidth = dim.absoluteRight - dim.absoluteLeft;
+ var newWidth = oldWidth * pct;
+ DOM.setWidth(overlay, newWidth);
+ DOM.setHeight(overlay, dim.absoluteBottom - dim.absoluteTop);
+
+ this.overlay = overlay;
+ }
+});
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/selectable_table.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/selectable_table.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,179 @@
+/*
+ This is a datasource you can attach to a table. It will enable
+ the selection of rows or cells in the table.
+
+ The data in the datasource is elements that are selected.
+
+ $id:$
+*/
+
+SelectableTable = new Class(DataSource, {
+
+ // options:
+ // table: what table element to attach to
+ // selectableClass: if you only want elements with a certain class to be selectable,
+ // specifiy this class with selectableClass
+ // multiple: can more than one thing be selected at once? default is true
+ // selectedClass: class to apply to selected elements
+ // checkboxClass: since there are frequently checkboxes associated with selectable elements,
+ // you can specify the class of your checkboxes to make them stay in sync
+ // selectableItem: What type of elements can be selected. Values are "cell" or "row"
+ init: function (opts) {
+ if ( SelectableTable.superClass.init )
+ SelectableTable.superClass.init.apply(this, []);
+
+ var table = opts.table;
+ var selectableClass = opts.selectableClass;
+ var multiple = opts.multiple;
+ var selectedClass = opts.selectedClass
+ var checkboxClass = opts.checkboxClass
+ var selectableItem = opts.selectableItem;
+
+ selectableItem = selectableItem == "cell" ? "cell" : "row";
+
+ if (!defined(multiple)) multiple = true;
+
+ this.table = table;
+ this.selectableClass = selectableClass;
+ this.multiple = multiple;
+ this.selectedClass = opts.selectedClass;
+ this.checkboxClass = opts.checkboxClass;
+
+ this.selectedElements = [];
+
+ // if it's not a table, die
+ if (!table || !table.tagName || table.tagName.toLowerCase() != "table") return null;
+
+ // get selectable items
+ var tableElements = table.getElementsByTagName("*");
+
+ var selectableElements;
+
+ if (selectableItem == "cell") {
+ selectableElements = DOM.filterElementsByTagName(tableElements, "td");
+ } else {
+ selectableElements = DOM.filterElementsByTagName(tableElements, "tr");
+ }
+
+ var self = this;
+ selectableElements.forEach(function(ele) {
+ // if selectableClass is defined and this element doesn't have the class, skip it
+ if (selectableClass && !DOM.hasClassName(ele, selectableClass)) return;
+
+ // attach click handler to every element inside the element
+ var itemElements = ele.getElementsByTagName("*");
+ for (var i = 0; i < itemElements.length; i++) {
+ self.attachClickHandler(itemElements[i], ele);
+ }
+
+ // attach click handler to the element itself
+ self.attachClickHandler(ele, ele);
+ });
+ },
+
+ // stop our handling of this event
+ stopHandlingEvent: function (evt) {
+ if (!evt) return;
+
+ // w3c
+ if (evt.stopPropagation)
+ evt.stopPropagation();
+
+ // ie
+ try {
+ event.cancelBubble = true;
+ } catch(e) {}
+ },
+
+ // attach a click handler to this element
+ attachClickHandler: function (ele, parent) {
+ if (!ele) return;
+
+ var self = this;
+
+ var rowClicked = function (evt) {
+ // if it was a control-click or a command-click
+ // they're probably trying to open a new tab or something.
+ // let's not handle it
+ if (evt && (evt.ctrlKey || evt.metaKey)) return false;
+
+ var tagName = ele.tagName.toLowerCase();
+
+ // if this is a link or has an onclick handler,
+ // return true and tell other events to return true
+ if ((ele.href && tagName != "img") || ele.onclick) {
+ self.stopHandlingEvent(evt);
+ return true;
+ }
+
+ // if this is the child of a link, propagate the event up
+ var ancestors = DOM.getAncestors(ele, true);
+ for (var i = 0; i < ancestors.length; i++) {
+ var ancestor = ancestors[i];
+ if (ancestor.href && ancestor.tagName.toLowerCase() != "img") {
+ return true;
+ }
+ }
+
+ // if this is an input or select element, skip it
+ if ((tagName == "select" || tagName == "input") && parent.checkbox != ele) {
+ self.stopHandlingEvent(evt);
+ return true;
+ }
+
+ // toggle selection of this parent element
+ if (self.selectedElements.indexOf(parent) != -1) {
+ if (self.selectedClass) DOM.removeClassName(parent, self.selectedClass);
+
+ self.selectedElements.remove(parent);
+ } else {
+ if (self.selectedClass) DOM.addClassName(parent, self.selectedClass);
+
+ if (self.multiple) {
+ self.selectedElements.push(parent);
+ } else {
+ if (self.selectedClass && self.selectedElements.length > 0) {
+ var oldParent = self.selectedElements[0];
+ if (oldParent) {
+ DOM.removeClassName(oldParent, self.selectedClass);
+ if (oldParent.checkbox) oldParent.checkbox.checked = "";
+ }
+ }
+
+ self.selectedElements = [parent];
+ }
+ }
+
+ // update our data
+ self.setData(self.selectedElements);
+
+ // if there's a checkbox associated with this parent, set it's value
+ // to the parent selected value
+ if (parent.checkbox) parent.checkbox.checked = (self.selectedElements.indexOf(parent) != -1) ? "on" : '';
+ if (parent.checkbox == ele) { self.stopHandlingEvent(evt); return true; }
+
+ // always? not sure
+ if (evt)
+ Event.stop(evt);
+ }
+
+ // if this is a checkbox we need to keep in sync, set up its event handler
+ if (this.checkboxClass && ele.tagName.toLowerCase() == "input"
+ && ele.type == "checkbox" && DOM.hasClassName(ele, this.checkboxClass)) {
+
+ parent.checkbox = ele;
+
+ // override default event handler for the checkbox
+ DOM.addEventListener(ele, "click", function (evt) {
+ return true;
+ });
+ }
+
+ // attach a method to the row so other people can programatically
+ // select it.
+ ele.rowClicked = rowClicked;
+
+ DOM.addEventListener(ele, "click", rowClicked);
+ }
+
+});
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/template.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/template.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,225 @@
+/*
+Template - Copyright 2005 Six Apart
+$Id: template.js 35 2006-02-18 00:46:55Z mischa $
+
+Copyright (c) 2005, Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+/* core template object */
+
+Template = new Class( Object, {
+ beginToken: "[#",
+ endToken: "#]",
+
+
+ init: function( source ) {
+ if( source )
+ this.compile( source );
+ },
+
+
+ compile: function( source ) {
+ var statements = [
+ "context.open();",
+ "with( context.vars ) {"
+ ];
+
+ var start = 0, end = -this.endToken.length;
+ while( start < source.length ) {
+ end += this.endToken.length;
+
+ // plaintext
+ start = source.indexOf( this.beginToken, end );
+ if( start < 0 )
+ start = source.length;
+ if( start > end )
+ statements.push( "context.write( ", source.substring( end, start ).toJSON(), " );" );
+ start += this.beginToken.length;
+
+ // code
+ if( start >= source.length )
+ break;
+ end = source.indexOf( this.endToken, start );
+ if( end < 0 )
+ throw "Template parsing error: Unable to find matching end token (" + this.endToken + ").";
+ var length = (end - start);
+
+ // empty tag
+ if( length <= 0 )
+ continue;
+
+ // comment
+ else if( length >= 4 &&
+ source.charAt( start ) == "-" && source.charAt( start + 1 ) == "-" &&
+ source.charAt( end - 1 ) == "-" && source.charAt( end - 2 ) == "-" )
+ continue;
+
+ // write
+ else if( source.charAt( start ) == "=" )
+ statements.push( "context.write( ", source.substring( start + 1, end ), " );" );
+
+ // filters
+ else if( source.charAt( start ) == "|" ) {
+ start += 1;
+
+ // find the first whitespace
+ var afterfilters = source.substring(start,end).search(/\s/);
+
+ var filters;
+ if (afterfilters > 0) {
+ // allow pipes or commas to seperate filters
+ // split the string, reverse and rejoin to reverse it
+ filters = source.substring(start,start + afterfilters).replace(/,|\|/g,"").split('');
+ afterfilters += 1; // data starts after whitespace and filter list
+ } else {
+ // default to escapeHTML
+ filters = ["h"];
+ }
+ // we have to do them in reverse order
+ filters = filters.reverse();
+
+ // start with our original filter number
+ var numfilters = filters.length;
+
+ // add the text between [#| #]
+ filters.push(source.substring( start + afterfilters, end ));
+
+ // adjust each filter into a function call
+ // eg. u ( h ( H ( blah ) ) )
+ for (i=0; i<numfilters; i++) {
+ filters[i] = "context.f."+filters[i]+"( ";
+ filters.push(" )");
+ }
+
+ statements.push( "context.write( " + filters.join('') + " );");
+ }
+
+ // evaluate
+ else
+ statements.push( source.substring( start, end ) );
+ }
+
+ statements.push( "} return context.close();" );
+
+ this.exec = new Function( "context", statements.join( "\n" ) );
+ },
+
+
+ exec: function( context ) {
+ return "";
+ }
+} );
+
+
+/* static members */
+
+Template.templates = {};
+
+
+/* context object */
+
+Template.Context = new Class( Object, {
+ init: function( vars, templates ) {
+ this.vars = vars || {};
+ this.templates = templates || Template.templates;
+ this.stack = [];
+ this.out = [];
+ this.f = Template.Filter;
+ },
+
+
+ include: function( name ) {
+ return this.templates[ name ].exec( this );
+ },
+
+
+ write: function() {
+ this.out.push.apply( this.out, arguments );
+ },
+
+
+ writeln: function() {
+ this.write.apply( this, arguments );
+ this.write( "\n" );
+ },
+
+
+ clear: function() {
+ this.out.length = 0;
+ },
+
+
+ getOutput: function() {
+ return this.out.join( "" );
+ },
+
+
+ open: function() {
+ this.stack.push( this.out );
+ this.out = [];
+ },
+
+
+ close: function() {
+ var result = this.getOutput();
+ this.out = this.stack.pop() || [];
+ return result;
+ }
+
+} );
+
+/* filters */
+
+Template.Filter = {
+
+ // escapeHTML
+ h: function(obj) {
+ var div = document.createElement('div');
+ var textNode = document.createTextNode(obj);
+ div.appendChild(textNode);
+ return (div.innerHTML);
+ },
+
+ // unescapeHTML
+ H: function(obj) {
+ return (unescape(obj));
+ },
+
+ // encodeURL
+ u: function(obj) {
+ return (escape(obj).replace(/\//g,"%2F"));
+ }
+
+};
+
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/timer.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/timer.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,121 @@
+/*
+Timer Library
+$Id$
+
+Copyright (c) 2005, Six Apart, Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the name of "Six Apart" nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+Timer = new Class( Object, {
+ init: function( callback, delay, count ) {
+ this.callback = callback;
+ this.delay = max( delay, 1 );
+ this.nextDelay = this.delay;
+ this.startTime = 0;
+ this.count = count;
+ this.execCount = 0;
+ this.state = "new";
+ this.timeout = null;
+ this.id = Unique.id();
+ this.start();
+ },
+
+
+ destroy: function() {
+ this.stop();
+ this.callback = null;
+ },
+
+
+ exec: function() {
+ this.execCount++;
+ this.callback( this );
+ if ( this.count && this.execCount >= this.count ) {
+ return this.destroy();
+ }
+ if( this.state == "started" )
+ this.run();
+ },
+
+
+ run: function() {
+ this.state = "started";
+ this.timeout = window.setTimeout( this.exec.bind( this ), this.nextDelay );
+ this.nextDelay = this.delay;
+ var date = new Date();
+ this.startTime = date.UTC;
+ },
+
+
+ start: function() {
+ switch( this.state ) {
+ case "new":
+ case "paused":
+ case "stopped":
+ this.run();
+ break;
+ }
+ },
+
+
+ stop: function() {
+ this.state = "stopped";
+ try {
+ window.clearTimeout( this.timeout );
+ } catch( e ) {}
+ this.timeout = null;
+ },
+
+
+ pause: function() {
+ if( this.state != "started" )
+ return;
+ this.stop();
+ this.state = "paused";
+ var date = new Date();
+ this.nextDelay = max( this.delay - (date.UTC - this.startTime), 1 );
+ },
+
+
+ reset: function( delay ) {
+ if( this.state != "started" )
+ return;
+ if( defined( delay ) )
+ this.delay = this.nextDelay = max( delay, 1 );
+ try {
+ window.clearTimeout( this.timeout );
+ } catch( e ) {}
+ this.timeout = window.setTimeout( this.exec.bind( this ), this.nextDelay );
+ }
+
+} );
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/js/6alib/view.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/6alib/view.js Tue May 01 17:55:19 2012 +0800
@@ -0,0 +1,99 @@
+// the V in MVC
+// renders content into "view" element, calls data() on "datasource"
+
+View = new Class(Object, {
+
+ init: function (opts) {
+ if ( View.superClass.init )
+ View.superClass.init.apply(this, arguments);
+ this.watchers = [];
+ this.datasource = opts.datasource;
+ this.view = opts.view;
+ this.controller = opts.controller;
+
+ this.rendered = false;
+
+ if (opts.showHourglass) {
+ this.hourglass = new Hourglass();
+ this.hourglass.init(view);
+ }
+
+ if (opts.datasource)
+ opts.datasource.addWatcher(this.dataUpdated.bind(this));
+ },
+
+ addWatcher: function (callback) {
+ if (!this.watchers)
+ return;
+
+ this.watchers.add(callback);
+ },
+
+ removeWatcher: function (callback) {
+ if (!this.watchers)
+ return;
+
+ this.watchers.remove(callback);
+ },
+
+ callWatchers: function () {
+ if (!this.watchers)
+ return;
+
+ for (var i = 0; i < this.watchers.length; i++)
+ this.watchers[i].apply(this);
+ },
+
+ getView: function () {
+ return this.view;
+ },
+
+ dataUpdated: function () {
+ this._render();
+
+ if (this.hourglass) {
+ this.hourglass.hide();
+ this.hourglass = null;
+ }
+ },
+
+ setContent: function (content) {
+ if (this.view) {
+ var children = this.view.childNodes;
+ for (var i = 0; i < children.length; i++) {
+ this.view.removeChild(children[i]);
+ }
+ }
+
+ this.view.appendChild(content);
+ },
+
+ _render: function () {
+ var ds = this.datasource;
+ var view = this.view;
+
+ if (!view)
+ return;
+
+ var data;
+
+ if (ds) {
+ data = ds.data();
+ if (!this.rendered && this.unRender)
+ this.unRender(data, ds);
+ }
+
+ if (this.render) {
+ this.render(data, ds);
+ this.rendered = true;
+ }
+
+ this.callWatchers();
+ },
+
+ destroy: function () {
+ if (this.rendered)
+ this.unRender();
+ }
+
+});
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/tools/userpicfactory.bml
--- a/htdocs/tools/userpicfactory.bml Tue May 01 16:18:41 2012 +0800
+++ b/htdocs/tools/userpicfactory.bml Tue May 01 17:55:19 2012 +0800
@@ -26,9 +26,9 @@
}
LJ::need_res(qw(
- js/core.js
- js/dom.js
- js/image-region-select.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/image-region-select.js
));
# optional suffix, for beta testing. can be removed soon after 2006-03-29
diff -r cb15f9c272f5 -r 4b328d722eab htdocs/update.bml
--- a/htdocs/update.bml Tue May 01 16:18:41 2012 +0800
+++ b/htdocs/update.bml Tue May 01 17:55:19 2012 +0800
@@ -82,7 +82,7 @@
LJ::Hooks::run_hooks("transform_update_$POST{transform}", \%GET, \%POST) if $POST{transform};
LJ::need_res( { priority => $LJ::OLD_RES_PRIORITY }, 'stc/entry.css' );
- LJ::need_res('stc/display_none.css', 'stc/lj_base.css', 'js/inputcomplete.js');
+ LJ::need_res('stc/display_none.css', 'stc/lj_base.css', 'js/6alib/inputcomplete.js');
## figure out times
my $now = DateTime->now;
@@ -525,9 +525,9 @@
my $ret = $_[1]->{'head'};
LJ::need_res(qw(
- js/core.js
- js/dom.js
- js/httpreq.js
+ js/6alib/core.js
+ js/6alib/dom.js
+ js/6alib/httpreq.js
js/livejournal.js
js/entry.js
js/poll.js
diff -r cb15f9c272f5 -r 4b328d722eab views/dev/tests/commentmanage.js
--- a/views/dev/tests/commentmanage.js Tue May 01 16:18:41 2012 +0800
+++ b/views/dev/tests/commentmanage.js Tue May 01 17:55:19 2012 +0800
@@ -1,6 +1,6 @@
/* INCLUDE:
-old: js/commentmanage.js
+old: js/6alib/commentmanage.js
jquery: js/jquery/jquery.ui.widget.js
jquery: js/jquery.ajaxtip.js
jquery: js/jquery.commentmanage.js
diff -r cb15f9c272f5 -r 4b328d722eab views/dev/tests/libfunctions.js
--- a/views/dev/tests/libfunctions.js Tue May 01 16:18:41 2012 +0800
+++ b/views/dev/tests/libfunctions.js Tue May 01 17:55:19 2012 +0800
@@ -1,33 +1,33 @@
/* INCLUDE:
-old: js/core.js
-old: js/dom.js
-old: js/json.js
-old: js/httpreq.js
-old: js/hourglass.js
-old: js/inputcomplete.js
-old: js/datasource.js
-old: js/selectable_table.js
+old: js/6alib/core.js
+old: js/6alib/dom.js
+old: js/6alib/json.js
+old: js/6alib/httpreq.js
+old: js/6alib/hourglass.js
+old: js/6alib/inputcomplete.js
+old: js/6alib/datasource.js
+old: js/6alib/selectable_table.js
-old: js/checkallbutton.js
+old: js/6alib/checkallbutton.js
-old: js/progressbar.js
-old: js/ljprogressbar.js
+old: js/6alib/progressbar.js
+old: js/6alib/ljprogressbar.js
-old: js/ippu.js
-old: js/lj_ippu.js
-old: js/template.js
-old: js/userpicselect.js
+old: js/6alib/ippu.js
+old: js/6alib/lj_ippu.js
+old: js/6alib/template.js
+old: js/6alib/userpicselect.js
-old: js/view.js
-old: js/directorysearch.js
-old: js/directorysearchconstraints.js
-old: js/directorysearchresults.js
+old: js/6alib/view.js
+old: js/6alib/directorysearch.js
+old: js/6alib/directorysearchconstraints.js
+old: js/6alib/directorysearchresults.js
-old: js/esnmanager.js
+old: js/6alib/esnmanager.js
-old: js/ljwidget.js
-old: js/ljwidget_ippu.js
-old: js/widget_ippu/settingprod.js
+old: js/6alib/ljwidget.js
+old: js/6alib/ljwidget_ippu.js
+old: js/6alib/widget_ippu/settingprod.js
*/
module( "old" );
diff -r cb15f9c272f5 -r 4b328d722eab views/dev/tests/login.js
--- a/views/dev/tests/login.js Tue May 01 16:18:41 2012 +0800
+++ b/views/dev/tests/login.js Tue May 01 17:55:19 2012 +0800
@@ -1,6 +1,6 @@
/* INCLUDE:
js/md5.js
-old: js/login.js
+old: js/6alib/login.js
jquery: js/login-jquery.js
*/
diff -r cb15f9c272f5 -r 4b328d722eab views/dev/tests/quickreply.js
--- a/views/dev/tests/quickreply.js Tue May 01 16:18:41 2012 +0800
+++ b/views/dev/tests/quickreply.js Tue May 01 17:55:19 2012 +0800
@@ -1,6 +1,6 @@
/* INCLUDE:
-old: js/x_core.js
-old: js/quickreply.js
+old: js/6alib/x_core.js
+old: js/6alib/quickreply.js
jquery: js/jquery/jquery.ui.widget.js
jquery: js/jquery.quickreply.js
*/
--------------------------------------------------------------------------------
