[KSS-checkins] r50811 - in kukit/kukit.js/trunk: 3rd_party/johnnydebris.net 3rd_party/johnnydebris.net/dommer 3rd_party/johnnydebris.net/jsbase 3rd_party/johnnydebris.net/jsbase/testing 3rd_party/johnnydebris.net/minisax.js kukit tests

gotcha at codespeak.net gotcha at codespeak.net
Sun Jan 20 20:43:20 CET 2008


Author: gotcha
Date: Sun Jan 20 20:43:18 2008
New Revision: 50811

Added:
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/CHANGES.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/LICENSE.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/README.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/conftest.py
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/dommer.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/example.html
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/run_tests.html
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/test_dommer.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/version.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/LICENSE.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/README.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/__init__.py
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/array.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/conftest.py
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/exception.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/function.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/misclib.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/number.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/server.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/string.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/test_array.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/test_misclib.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/test_number.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/test_string.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/testing/
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/testing.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/testing/findtests.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/testing/testbase.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/version.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/LICENSE.txt
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/conftest.py
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/example.html
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/helpers.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/minisax.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/test_minisax.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/testhandler.js
   kukit/kukit.js/trunk/3rd_party/johnnydebris.net/minisax.js/version.txt
Modified:
   kukit/kukit.js/trunk/kukit/kukit.js
   kukit/kukit.js/trunk/kukit/utils.js
   kukit/kukit.js/trunk/tests/runner.html
   kukit/kukit.js/trunk/tests/runtests.js
   kukit/kukit.js/trunk/tests/runtests.sh
   kukit/kukit.js/trunk/tests/test_utils.js
Log:
* add dommer.js code from Guido Wesdorp (johnnydebris)
  This will allow better unit testing of KSS as it implements DOM in js.

* setup of that code in tests infrastructure

* refactor base URL computation to allow unit testing

* tests for base URL computation


Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/CHANGES.txt
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/CHANGES.txt	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,17 @@
+Changes in the Dommer library
+=============================
+
+Version 0.4
+-----------
+
+  * Changed the unit tests so they can be ran from py.test (using some
+    new JSBase feature, currently this rules out browser testing but that
+    should be fixed later).
+
+  * Fixed some bugs in comment handling.
+
+  * Replaced my old helpers lib with a new one, which has a slightly different
+    way of defining methods (uses a module namespace). Note that this does not
+    change the dependencies, as the functionality required is copied to the
+    main lib on release creation.
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/LICENSE.txt
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/LICENSE.txt	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,340 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/README.txt
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/README.txt	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,60 @@
+Dommer
+======
+
+What is it?
+-----------
+
+Dommer is a DOM level 2 library (currently not complete, not sure if it ever
+will either, but it's a usable subset) that is almost entirely compliant with
+the DOM standard. This allows DOM developers to write proper XML parsing code
+for all browsers that support core JavaScript. DOM for instance properly
+supports namespaces, a feature which IE's DOM support lacks, thus allowing
+XML to be parsed with proper namespace and prefix handling on that platform.
+
+What's missing?
+---------------
+
+Currently a number of features are missing, features marked with a * will most
+probably be added in the near future, others are not certain to be implemented
+at all.
+
+- CDATA*
+- DTD processing
+- HTML support
+- some more exotic DOM functions such as isSupported()
+- (there's probably more I can't remember right now ;)
+
+What's different from the standard?
+-----------------------------------
+
+Since there's no proper way to update one property when another is set in IE,
+all properties on a node should be considered read-only, they should never be
+modified except with dedicated API calls. To allow setting the prefix of a
+node without updating e.g. .nodeName, a new method was added to the Node
+interface, called 'setPrefix'. If this library is used *solely* on platforms
+that *do* support dynamic property updates (__defineGetter__ and
+__defineSetter__), you can set the switch WARN_ON_PREFIX to false and set
+.prefix the conventional way.
+
+Usage
+-----
+
+For an example of how to use the library, see 'example.html'. For API
+documentation, see any DOM level 2 reference.
+
+Note that this library depends on version 0.3 of the 'minisax.js' library, 
+and version 0.1 of the JSBase lib, both of which can be downloaded (under the
+same GPL license) from http://johnnydebris.net/javascript/.
+
+Questions, remarks, bug reports, etc.
+-------------------------------------
+
+If you have questions, remarks, bug reports, etc. you can send email to
+johnny at johnnydebris.net. More information and newer versions of this library
+can be found on http://johnnydebris.net.
+
+Note: this product contains some code written by the Kupu developers (some of
+the functionality in helpers.js). Kupu is an HTML editor written in
+JavaScript, released under a BSD-style license. See http://kupu.oscom.org for
+more information about Kupu and its license.
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/conftest.py
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/conftest.py	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,18 @@
+# JS unit test support for py.test - (c) 2007 Guido Wesdorp. All rights
+# reserved
+#
+# This software is distributed under the terms of the JSBase
+# License. See LICENSE.txt for license text.
+
+import py
+here = py.magic.autopath().dirpath()
+
+from jsbase.conftest import JSTest, JSChecker, Directory as _Directory
+
+class Directory(_Directory):
+    def run(self):
+        if self.fspath == here:
+            return [p.basename for p in self.fspath.listdir('test_*') if
+                    p.ext == '.js']
+        return super(Directory, self).run()
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/dommer.js
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/dommer.js	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,1213 @@
+/*  dommer.js - a (mostly) compliant subset of DOM level 2 for JS
+    (c) Guido Wesdorp 2004-2007
+    email johnny at debris.demon.nl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    dommer.js
+
+    This library provides a mostly compliant subset of the DOM API in core
+    JavaScript. A number of methods aren't implemented, and there are a few
+    semantic differences between the standard and this implementations, but
+    it provides most of DOM level 2's features and is usable in almost all JS
+    environments (also stand-alone ones).
+
+    I started writing this mainly because of IE's lack of proper namespace 
+    support, and to have a portable, reliable DOM implementation.
+
+    Non-standard are:
+
+    - Whitespace is never ignored.
+
+    - Because of JS doesn't (by default) allow computing attributes on request,
+      this API doesn't create Element.nodeName on setting element.prefix, 
+      therefore a new method was added: Element.setPrefix (note that this
+      is not required if the library is not used on browsers that don't
+      support __defineGetter__ and __defineSetter__ (such as IE)).
+
+    $Id: minisax.js,v 1.5 2004/07/31 00:10:15 johnny Exp $
+
+*/
+
+// If the following switch is set to true, setting Element.prefix
+// will result in an exception. This serves to make sure scripts work
+// cross-browser: IE does not support __defineSetter__, which is used
+// to ensure Element.nodeName is updated if Element.prefix
+// is changed (and also to ensure Element.nodeName and 
+// Element.localName can't be changed directly). The lack of this
+// method on IE means that on that platform it is possible to break
+// integrity (by setting .prefix directly, .nodeName will be out-of-date).
+// Note that this means that if you intend to use this lib only on Mozilla
+// (or other browsers that support dynamic properties), you can safely 
+// set this to false and set .prefix without breaking integrity.
+var WARN_ON_PREFIX = true;
+
+// give this a namespace...
+try {
+    var global = window;
+} catch(e) {
+    var global = this;
+};
+global.dommer = new function() {
+    /* Exceptions */
+    function DOMException(errorcode, message) {
+        this.code = null;
+        this.error = null;
+        this.message = message
+        for (var attr in DOMException) {
+            if (DOMException[attr] == errorcode) {
+                this.error = attr;
+                break;
+            };
+        };
+        this.code = errorcode;
+        if (!this.error) {
+            this.error = 'Unknown';
+        };
+        this.stack = stack = createStack();
+        this.lineNumber = getLineNo(stack);
+        this.fileName = getFileName(stack);
+    };
+
+    this.DOMException = DOMException;
+
+    // error codes
+    // XXX should we make these global, like in the specs?
+    DOMException.INDEX_SIZE_ERR = 1,
+    DOMException.DOMSTRING_SIZE_ERR = 2;
+    DOMException.HIERARCHY_REQUEST_ERR = 3;
+    DOMException.WRONG_DOCUMENT_ERR = 4;
+    DOMException.INVALID_CHARACTER_ERR = 5;
+    DOMException.NO_DATA_ALLOWED_ERR = 6;
+    DOMException.NO_MODIFICATION_ALLOWED_ERR = 7;
+    DOMException.NOT_FOUND_ERR = 8;
+    DOMException.NOT_SUPPORTED_ERR = 9;
+    DOMException.INUSE_ATTRIBUTE_ERR = 10;
+    DOMException.INVALID_STATE_ERR = 11;
+    DOMException.SYNTAX_ERR = 12;
+    DOMException.INVALID_MODIFICATION_ERR = 13;
+    DOMException.NAMESPACE_ERR = 14;
+    DOMException.INVALID_ACCESS_ERR = 15;
+
+    DOMException.prototype.toString = function() {
+        var ret = 'DOMException: ' + this.error + ' (' + this.code + ')';
+        if (this.message) {
+            ret += ' - ' + this.message;
+        };
+        return ret;
+    };
+
+    /* Node interface */
+    function Node() {
+        this.ELEMENT_NODE = 1;
+        this.ATTRIBUTE_NODE = 2;
+        this.TEXT_NODE = 3;
+        this.CDATA_SECTION_NODE = 4;
+        this.ENTITY_REFERENCE_NODE = 5;
+        this.ENTITY_NODE = 6;
+        this.PROCESSING_INSTRUCTION_NODE = 7;
+        this.COMMENT_NODE = 8;
+        this.DOCUMENT_NODE = 9;
+        this.DOCUMENT_TYPE_NODE = 10;
+        this.DOCUMENT_FRAGMENT_NODE = 11;
+        this.NOTATION_NODE = 12;
+        
+        // These are defined in-line rather than on .prototype to allow using
+        // them below, too. This way we don't have to check whether attributes
+        // are already protected while this constructor is ran or not (in JS,
+        // when you set 'Foo.prototype = new Bar;', the Bar constructor is
+        // actually ran, in our case this means that the state of the 
+        // superclass changes).
+        this._protectAttribute = function(attr) {
+            /* make an attribute read-only */
+            this.__defineSetter__(attr,
+                function(value) {
+                    throw(
+                        (new DOMException(
+                            DOMException.NO_MODIFICATION_ALLOWED_ERR, attr))
+                    );
+                }
+            );
+            this.__defineGetter__(attr,
+                function() {
+                    return this['_' + attr];
+                }
+            );
+        };
+
+        this._setProtected = function(name, value) {
+            /* set a read-only attribute
+
+                THIS IS AN INTERNAL METHOD that should not get used as part 
+                of the API
+            */
+            this['_' + name] = value;
+            if (!this.__defineSetter__) {
+                this[name] = value;
+            };
+        };
+
+        this.nodeValue = null;
+        if (this.__defineSetter__) {
+            // on browsers that support __define[GS]etter__, perform integrity
+            // checks
+            // nodeValue should be settable on certain nodeTypes
+            this.__defineSetter__('nodeValue',
+                function(nodeValue) {
+                    if (this.nodeType != this.TEXT_NODE &&
+                            this.nodeType != this.ATTRIBUTE_NODE && 
+                            this.nodeType != this.COMMENT_NODE) {
+                        throw(
+                            (new DOMException(
+                                DOMException.NO_DATA_ALLOWED_ERR,
+                                'nodeValue'))
+                        );
+                    };
+                    // XXX should check on allowed chars here, but not 
+                    // sure which?
+                    this._nodeValue = nodeValue;
+                }
+            );
+            // XXX not sure if we should protect reading .nodeValue
+            this.__defineGetter__('nodeValue',
+                function() {
+                    if (this.nodeType != this.TEXT_NODE &&
+                            this.nodeType != this.ATTRIBUTE_NODE &&
+                            this.nodeType != this.COMMENT_NODE) {
+                        throw(
+                            (new DOMException(
+                                DOMException.NO_DATA_ALLOWED_ERR,
+                                'nodeValue'))
+                        );
+                    };
+                    return this._nodeValue;
+                }
+            );
+            var toprotect = ['nodeType', 'nodeName', 'parentNode', 
+                                'childNodes', 'firstChild', 'lastChild', 
+                                'previousSibling', 'nextSibling', 
+                                'attributes', 'ownerDocument', 'namespaceURI', 
+                                'localName'];
+            for (var i=0; i < toprotect.length; i++) {
+                this._protectAttribute(toprotect[i]);
+            };
+        };
+            
+        this._setProtected('namespaceURI', null);
+        this._setProtected('prefix', null);
+        this._setProtected('nodeName', null);
+        this._setProtected('localName', null);
+        this._setProtected('parentNode', null);
+        // note that this is shared between subclass instances, so should be
+        // re-set in every .initialize() (so below is just for show)
+        this._setProtected('childNodes', []);
+        this._setProtected('firstChild', null);
+        this._setProtected('lastChild', null);
+        this._setProtected('previousSibling', null);
+        this._setProtected('nextSibling', null);
+        this._setProtected('ownerDocument', null);
+    };
+
+    this.Node = Node;
+
+    var thrownotsupported = function() {throw('not supported');};
+
+    // XXX these should be implemented at some point...
+    Node.prototype.normalize = thrownotsupported;
+    Node.prototype.isSupported = thrownotsupported; // hehehe...
+
+    // non-standard method, use this always instead of setting .prefix 
+    // yourself, as this will update the .nodeName property too
+    Node.prototype.setPrefix = function(prefix) {
+        if (this.__defineSetter__) {
+            this._prefix = prefix;
+            this._nodeName = prefix + ':' + this.localName;
+        } else {
+            this.prefix = prefix;
+            this.nodeName = prefix + ':' + this.localName;
+        };
+    };
+
+    Node.prototype.cloneNode = function() {
+        throw(
+            (new DOMException(DOMException.NOT_SUPPORTED_ERR))
+        );
+    };
+
+    Node.prototype.hasChildNodes = function() {
+        return (this.childNodes && this.childNodes.length > 0);
+    };
+
+    Node.prototype.hasAttributes = function() {
+        return (this.attributes !== undefined && this.attributes.length);
+    };
+
+    Node.prototype.appendChild = function(newChild) {
+        this._checkModificationAllowed();
+        this._attach(newChild);
+    };
+
+    Node.prototype.removeChild = function(oldChild) {
+        this._checkModificationAllowed();
+        this._checkIsChild(oldChild);
+        var newChildren = new NodeList();
+        var found = false;
+        for (var i=0; i < this.childNodes.length; i++) {
+            if (this.childNodes[i] === oldChild) {
+                oldChild._setProtected('parentNode', null);
+                var previous = oldChild.previousSibling;
+                if (previous) {
+                    oldChild._setProtected('previousSibling', null);
+                    previous._setProtected('nextSibling', 
+                        oldChild.nextSibling);
+                };
+                var next = oldChild.nextSibling;
+                if (next) {
+                    next._setProtected('previousSibling', previous);
+                    oldChild._setProtected('nextSibling', null);
+                };
+                continue;
+            };
+            newChildren.push(this.childNodes[i]);
+        };
+        this._setProtected('childNodes', newChildren);
+        this._setProtected('firstChild', 
+                (this.childNodes.length > 0 ? this.childNodes[0] : null));
+        this._setProtected('lastChild', (
+                this.childNodes.length > 0 ? 
+                    this.childNodes[this.childNodes.length - 1] : null));
+    };
+
+    Node.prototype.replaceChild = function(newChild, refChild) {
+        this._checkModificationAllowed();
+        this._checkIsChild(refChild);
+        this._attach(newChild, refChild, true);
+    };
+
+    Node.prototype.insertBefore = function(newChild, refChild) {
+        this._checkModificationAllowed();
+        this._checkIsChild(refChild);
+        this._attach(newChild, refChild);
+    };
+
+    Node.prototype._attach = function(newChild, refChild, replace) {
+        // see if the child is in the same document
+        if (newChild.ownerDocument != this.ownerDocument) {
+            throw(
+                (new DOMException(DOMException.WRONG_DOCUMENT_ERR))
+            );
+        };
+        // see if the child is of an allowed type
+        if (newChild.nodeType != newChild.ELEMENT_NODE && 
+                newChild.nodeType != newChild.TEXT_NODE &&
+                newChild.nodeType != newChild.CDATA_SECTION_NODE &&
+                newChild.nodeType != newChild.COMMENT_NODE) {
+            throw(
+                (new DOMException(DOMException.HIERARCHY_REQUEST_ERR))
+            );
+        };
+        // see if the child isn't a (grand)parent of ourselves
+        var currparent = this;
+        while (currparent && currparent.nodeType != newChild.DOCUMENT_NODE) {
+            if (currparent === newChild) {
+                throw(
+                    (new DOMException(DOMException.HIERARCHY_REQUEST_ERR))
+                );
+            };
+            currparent = currparent.parentNode;
+        };
+        // seems to be okay, add it
+        newChild._setProtected('parentNode', this);
+        if (!refChild) {
+            if (this.childNodes.length) {
+                this.childNodes[this.childNodes.length - 1]._setProtected(
+                    'nextSibling', newChild);
+                newChild._setProtected('previousSibling',
+                    this.childNodes[this.childNodes.length - 1]);
+            };
+            this.childNodes.push(newChild);
+        } else {
+            var newchildren = [];
+            var found = false;
+            for (var i=0; i < this.childNodes.length; i++) {
+                var currChild = this.childNodes[i];
+                if (currChild === refChild) {
+                    newchildren.push(newChild);
+                    var previous = this.childNodes[i - 1];
+                    if (previous) {
+                        newChild._setProtected('previousSibling', previous);
+                        previous._setProtected('nextSibling', newChild);
+                    };
+                    if (!replace) {
+                        newchildren.push(currChild);
+                        currChild._setProtected('previousSibling', newChild);
+                        newChild._setProtected('nextSibling', currChild);
+                    } else {
+                        currChild._setProtected('parentNode', null);
+                        currChild._setProtected('previousSibling', null);
+                        currChild._setProtected('nextSibling', null);
+                        var next = this.childNodes[i + 1];
+                        newChild._setProtected('nextSibling', next);
+                        next._setProtected('previousSibling', newChild);
+                    };
+                    found = true;
+                } else {
+                    newchildren.push(currChild);
+                };
+            };
+            if (!found) {
+                throw(
+                    (new DOMException(DOMException.NOT_FOUND_ERR))
+                );
+            };
+            this._setProtected('childNodes', newchildren);
+        };
+        this._setProtected('firstChild', this.childNodes[0]);
+        this._setProtected('lastChild', 
+            this.childNodes[this.childNodes.length - 1]);
+    };
+
+    Node.prototype._checkModificationAllowed = function() {
+        if (this.nodeType != this.ELEMENT_NODE &&
+                this.nodeType != this.DOCUMENT_NODE &&
+                this.nodeType != this.DOCUMENT_FRAGMENT_NODE) {
+            throw(
+                (new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR))
+            );
+        };
+    };
+
+    Node.prototype._checkIsChild = function(refChild) {
+        if (refChild.parentNode !== this) {
+            throw(
+                (new DOMException(DOMException.NOT_FOUND_ERR))
+            );
+        };
+    };
+
+    function DocumentFragment() {
+        this._setProtected('nodeType', 11);
+    };
+
+    DocumentFragment.prototype = new Node;
+    this.DocumentFragment = DocumentFragment;
+
+    function Element() {
+        this._setProtected('nodeType', 1);
+    };
+
+    Element.prototype = new Node;
+    this.Element = Element;
+
+    Element.prototype.initialize = function(namespaceURI, qname, 
+                                                    ownerDocument) {
+        // XXX the specs are very vague about an id, it says the DOM 
+        // implementation must have info about which attributes are of the id 
+        // type, I'll just use the property here for now...
+        this.id = ''; // empty string like in Mozilla, seems weird to me though
+
+        this._setProtected('attributes', []);
+        this._setProtected('childNodes', []);
+        this._setProtected('ownerDocument', ownerDocument);
+
+        // try to ensure integrity by defining getters and setters for certain
+        // properties, since this only works in certain browsers it makes sense to 
+        // test your applications on one of those platforms, see also 
+        // WARN_ON_PREFIX in the top of the document
+        if (this.__defineSetter__) {
+            this._nodeName = this.nodeName;
+            this.__defineSetter__('nodeName', function() {
+                            throw(
+                                (new DOMException(
+                                    DOMException.NO_MODIFICATION_ALLOWED_ERR)))
+                            });
+            this.__defineGetter__('nodeName', 
+                                    function() {return this._nodeName});
+            this.__defineSetter__('prefix', 
+                                function(value) {
+                                    if (WARN_ON_PREFIX) {
+                                        throw('Setting prefix directly ' +
+                                                'breaks integrity of the ' +
+                                                'XML DOM in Internet ' +
+                                                'Explorer browsers!');
+                                    };
+                                    this._prefix = value;
+                                    this._nodeName = this._prefix + 
+                                                        this._localName;
+                                });
+            this.__defineGetter__('prefix', function() {return this._prefix});
+        };
+        // XXX both the ns and qname need integrity checks
+        this._setProtected('namespaceURI', namespaceURI);
+        if (qname.indexOf(':') > -1) {
+            var tup = qname.split(':');
+            this.setPrefix(tup.shift());
+            this._setProtected('localName', tup.join(':'));
+        } else {
+            this.setPrefix(null);
+            this._setProtected('localName', qname);
+        };
+        if (this.prefix) {
+            this._setProtected('nodeName', this.prefix + ':' + this.localName);
+        } else {
+            this._setProtected('nodeName', this.localName);
+        };
+    };
+
+    Element.prototype.toString = function() {
+        return '<Element "' + this.nodeName + '" (type ' + 
+                    this.nodeType + ')>';
+    };
+
+    Element.prototype.toXML = function(context) {
+        // context is used when toXML is called recursively
+        // marker
+        var no_prefix_id = '::no_prefix::';
+        if (!context) {
+            context = {
+                namespace_stack: []
+            };
+        };
+        var new_namespaces = {}; // any namespaces that weren't declared yet
+        var current_namespaces = {};
+        var last_namespaces = context.namespace_stack[
+                                    context.namespace_stack.length - 1];
+        context.namespace_stack.push(current_namespaces);
+        if (last_namespaces) {
+            for (var prefix in last_namespaces) {
+                current_namespaces[prefix] = last_namespaces[prefix];
+            };
+        };
+        var xml = '<' + this.nodeName;
+        var prefix = this.prefix || no_prefix_id;
+        if (this.namespaceURI && 
+                (current_namespaces[prefix] != this.namespaceURI)) {
+            current_namespaces[prefix] = this.namespaceURI;
+            new_namespaces[prefix] = this.namespaceURI;
+        };
+        for (var i=0; i < this.attributes.length; i++) {
+            var attr = this.attributes[i];
+            var aprefix = attr.prefix || no_prefix_id;
+            if (attr.namespaceURI &&
+                    current_namespaces[aprefix] != attr.namespaceURI) {
+                current_namespaces[aprefix] = attr.namespaceURI;
+                new_namespaces[aprefix] = attr.namespaceURI;
+            };
+            xml += ' ' + attr.nodeName + '="' + 
+                    string.entitize(attr.nodeValue) + '"';
+        };
+
+        // take care of any new namespaces
+        for (var prefix in new_namespaces) {
+            xml += ' xmlns';
+            if (prefix != no_prefix_id) {
+                xml += ':' + prefix;
+            };
+            xml += '="' + string.entitize(new_namespaces[prefix]) + '"';
+        };
+        
+        if (this.childNodes.length) {
+            xml += '>';
+            for (var i=0; i < this.childNodes.length; i++) {
+                xml += this.childNodes[i].toXML(context);
+            };
+            xml += '</' + this.nodeName + '>';
+        } else {
+            xml += ' />';
+        };
+        context.namespace_stack.pop();
+        return xml;
+    };
+
+    Element.prototype.cloneNode = function(deep) {
+        var el = new Element();
+        el.initialize(this.namespaceURI, this.nodeName, this.ownerDocument);
+        for (var i=0; i < this.attributes.length; i++) {
+            var clone = this.attributes[i].cloneNode();
+            clone._setProtected('ownerElement', el);
+            el.attributes.push(clone);
+        };
+        if (deep) {
+            for (var i=0; i < this.childNodes.length; i++) {
+                var clone = this.childNodes[i].cloneNode(true);
+                clone._setProtected('parentNode', el);
+                el.appendChild(clone);
+            };
+        };
+        return el;
+    };
+
+    Element.prototype.getAttributeNodeNS = function(namespaceURI, qname) {
+        for (var i=0; i < this.attributes.length; i++) {
+            var attr = this.attributes[i];
+            if (attr.namespaceURI == namespaceURI && attr.nodeName == qname) {
+                return attr;
+            };
+        };
+    };
+
+    Element.prototype.getAttributeNode = function(name) {
+        return this.getAttributeNodeNS(undefined, name);
+    };
+
+    Element.prototype.getAttribute = function(name) {
+        var attr = this.getAttributeNode(name)
+        return (attr ? attr.nodeValue : null);
+    };
+
+    Element.prototype.getAttributeNS = function(namespaceURI, name) {
+        var attr = this.getAttributeNodeNS(namespaceURI, name);
+        return (attr ? attr.nodeValue : null);
+    };
+
+    Element.prototype.hasAttributeNS = function(namespaceURI, name) {
+        return !!(this.getAttributeNS(namespaceURI, name));
+    };
+
+    Element.prototype.hasAttribute = function(name) {
+        return this.hasAttributeNS(this.namespaceURI, name);
+    };
+
+    Element.prototype.setAttributeNS = function(namespaceURI, name, value) {
+        for (var i=0; i < this.attributes.length; i++) {
+            var attr = this.attributes[i];
+            if (attr.namespaceURI == namespaceURI && attr.nodeName == name) {
+                attr.nodeValue = value;
+                return;
+            };
+        };
+        var attr = new Attribute();
+        attr.initialize(namespaceURI, name, value, this.ownerDocument);
+        attr._setProtected('ownerElement', this);
+        this.attributes.push(attr);
+    };
+
+    Element.prototype.setAttribute = function(name, value) {
+        this.setAttributeNS(undefined, name, value);
+    };
+
+    Element.prototype.setAttributeNodeNS = function(newAttr) {
+        for (var i=0; i < this.attributes.length; i++) {
+            var attr = this.attributes[i];
+            if (attr.namespaceURI == newAttr.namespaceURI && 
+                    attr.nodeName == newAttr.nodeName) {
+                throw(
+                    (new DOMException(DOMException.INUSE_ATTRIBUTE_ERR))
+                );
+            };
+        };
+        this.attributes.push(newAttr);
+    };
+
+    Element.prototype.setAttributeNode = function(newAttr) {
+        // XXX should this fail if no namespaceURI is available or something?
+        this.setAttributeNodeNS(newAttr);
+    };
+
+    Element.prototype.removeAttributeNS = function(namespaceURI, name) {
+        for (var i=0; i < this.attributes.length; i++) {
+            var attr = this.attributes[i];
+            if (attr.namespaceURI == namespaceURI && attr.nodeName == name) {
+                delete this.attributes[i];
+                return true;
+            };
+        };
+        return false;
+    };
+
+    Element.prototype.removeAttribute = function(name) {
+        return this.removeAttributeNS(this.namespaceURI, name);
+    };
+
+    Element.prototype.getElementsByTagNameNS = function(namespaceURI, 
+                                                                name, ret) {
+        // XXX *very* slow!!!
+        // needs to be optimized later on (probably by using some mapping)
+        if (!ret) {
+            ret = [];
+        };
+        for (var i=0; i < this.childNodes.length; i++) {
+            var child = this.childNodes[i];
+            if (name == child.nodeName || name == '*') {
+                if ((!namespaceURI && !child.namespaceURI) || 
+                        (namespaceURI == child.namespaceURI)) {
+                    ret.push(child);
+                };
+            };
+            if (child.nodeType == 1) {
+                child.getElementsByTagNameNS(namespaceURI, name, ret);
+            };
+        };
+        return ret;
+    };
+
+    Element.prototype.getElementsByTagName = function(name) {
+        return this.getElementsByTagNameNS(this.namespaceURI, name);
+    };
+
+    Element.prototype.getElementById = function(id) {
+        // XXX *very* slow!!!
+        // needs to be optimized later on (probably by using some mapping)
+        if (this.id == id) {
+            return this;
+        };
+        for (var i=0; i < this.childNodes.length; i++) {
+            var child = this.childNodes[i];
+            if (child.id == id) {
+                return child;
+            };
+            if (child.nodeType == 1) {
+                var found = this.childNodes[i].getElementById(id);
+                if (found) {
+                    return found;
+                };
+            };
+        };
+    };
+
+    function TextNode() {
+        this._setProtected('nodeType', 3);
+        this._setProtected('nodeName', '#text');
+    };
+
+    TextNode.prototype = new Node;
+    this.TextNode = TextNode;
+
+    TextNode.prototype.initialize = function(data, ownerDocument) {
+        this._setProtected('ownerDocument', ownerDocument);
+        this._setProtected('childNodes', new NodeList());
+        // nodeValue is not protected
+        this.nodeValue = data;
+    };
+
+    TextNode.prototype.toXML = function() {
+        return string.entitize(this.nodeValue);
+    };
+
+    TextNode.prototype.cloneNode = function() {
+        var node = new TextNode();
+        node.initialize(this.nodeValue, this.ownerDocument);
+        return node;
+    };
+
+    function CommentNode() {
+        /* a comment node */
+        this._setProtected('nodeType', 8);
+        this._setProtected('nodeName', '#comment');
+    };
+
+    CommentNode.prototype = new TextNode;
+    this.CommentNode = CommentNode;
+
+    CommentNode.prototype.initialize = function(data, ownerDocument) {
+        this._setProtected('ownerDocument', ownerDocument);
+        this._setProtected('childNodes', []);
+        this._setProtected('nodeValue', data);
+    };
+
+    CommentNode.prototype.toXML = function() {
+        return "<!--" + this.nodeValue + "-->";
+    };
+
+    // Attribute, subclass of TextNode because of the nice implementation
+    function Attribute() {
+        /* an attribute node */
+        this._setProtected('nodeType', 2);
+    };
+
+    Attribute.prototype = new Node;
+    this.Attribute = Attribute;
+
+    Attribute.prototype.initialize = function(namespaceURI, qname, value,
+                                                    ownerDocument) {
+        // XXX some code duplication here...
+        if (qname.match(/[^a-zA-Z0-9_\-:]/g)) {
+            throw(
+                (new DOMException(DOMException.INVALID_CHARACTER_ERR))
+            );
+        };
+        this._setProtected('ownerDocument', ownerDocument);
+        this._setProtected('namespaceURI', namespaceURI);
+        this._setProtected('nodeValue', value);
+        this._setProtected('childNodes', []);
+
+        // try to ensure integrity by defining getters and setters for certain
+        // properties, since this only works in certain browsers it makes sense to 
+        // test your applications on one of those platforms, see also 
+        // WARN_ON_PREFIX in the top of the document
+        if (this.__defineSetter__) {
+            this._nodeName = this.nodeName;
+            this.__defineSetter__('nodeName', function() {
+                            throw(
+                                (new DOMException(
+                                    DOMException.NO_MODIFICATION_ALLOWED_ERR)))
+                            });
+            this.__defineGetter__('nodeName', 
+                                    function() {return this._nodeName});
+            this.__defineSetter__('prefix', 
+                                function(value) {
+                                    if (WARN_ON_PREFIX) {
+                                        throw('Setting prefix directly ' +
+                                                'breaks integrity of the ' +
+                                                'XML DOM in Internet ' +
+                                                'Explorer browsers!');
+                                    };
+                                    this._prefix = value;
+                                    this._nodeName = this._prefix + 
+                                                        this._localName;
+                                });
+            this.__defineGetter__('prefix', function() {return this._prefix});
+            this._protectAttribute('ownerElement');
+        };
+        this._setProtected('ownerElement', null);
+        if (qname.indexOf(':') > -1) {
+            var tup = qname.split(':');
+            this.setPrefix(tup.shift());
+            this._setProtected('localName', tup.join(':'));
+        } else {
+            this.setPrefix(null);
+            this._setProtected('localName', qname);
+        };
+        if (this.prefix) {
+            this._setProtected('nodeName', this.prefix + ':' + this.localName);
+        } else {
+            this._setProtected('nodeName', this.localName);
+        };
+    };
+
+    Attribute.prototype.toXML = function() {
+        ret = this.nodeName + '="' + string.entitize(this.nodeValue) + '"';
+        return ret;
+    };
+
+    Attribute.prototype.cloneNode = function() {
+        var attr = new Attribute();
+        attr.initialize(this.namespaceURI, this.nodeName, this.nodeValue, 
+                        this.ownerDocument);
+        return attr;
+    };
+
+    Attribute.prototype.toString = function() {
+        return this.nodeValue;
+    };
+
+    function Document() {
+        /* the document node */
+        this._setProtected('nodeType', 9);
+        this._setProtected('nodeName', '#document');
+    };
+
+    Document.prototype = new Element;
+    this.Document = Document;
+
+    Document.prototype.initialize = function() {
+        this._setProtected('ownerDocument', this);
+        this._setProtected('childNodes', []);
+        this.documentElement = null;
+        this.namespaceToPrefix = {};
+    };
+
+    Document.prototype.toXML = function() {
+        return this.documentElement.toXML();
+    };
+
+    Document.prototype.appendChild = function(newChild) {
+        if (this.documentElement) {
+            throw(
+                (new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
+                    'document already has a document element'))
+            );
+        };
+        this._checkModificationAllowed();
+        this._attach(newChild);
+        this.documentElement = newChild;
+    };
+
+
+    Document.prototype.createElement = function(nodeName) {
+        return this.createElementNS(this.namespaceURI, nodeName);
+    };
+
+    Document.prototype.createElementNS = function(namespaceURI, nodeName) {
+        var el = new Element();
+        el.initialize(namespaceURI, nodeName, this);
+        return el;
+    };
+
+    Document.prototype.createTextNode = function(data) {
+        var el = new TextNode();
+        el.initialize(string.deentitize(data), this);
+        return el;
+    };
+
+    Document.prototype.createAttributeNS = function(namespaceURI, nodeName) {
+        var el = new Attribute();
+        el.initialize(namespaceURI, nodeName, null, this);
+        return el;
+    };
+
+    Document.prototype.createAttribute = function(nodeName) {
+        return this.createAttributeNS(undefined, nodeName);
+    };
+
+    Document.prototype.createComment = function(data) {
+        var el = new CommentNode();
+        el.initialize(data, this);
+        return el;
+    };
+
+    Document.prototype.importNode = function(node) {
+        node._setProtected('ownerDocument', this);
+    };
+
+    function DOMHandler() {
+        /* SAX handler to convert a piece of XML to a DOM */
+    };
+
+    this.DOMHandler = DOMHandler;
+
+    DOMHandler.prototype.startDocument = function() {
+        this.document = new Document();
+        this.document.initialize();
+        this.current = null;
+        this.namespaces = new Array();
+        this.namespaceToPrefix = {};
+    };
+
+    DOMHandler.prototype.startElement = function(namespaceURI, nodename, 
+                                                        attrs) {
+        if (namespaceURI && !array.contains(this.namespaces, namespaceURI)) {
+            this.namespaces.push(namespaceURI);
+            // update the mapping on the document just to be sure,
+            // that one and the one on this handler should always be in 
+            // sync if a start tag is encountered, since instantiating a 
+            // Element will set the prefix on that element
+            // XXX ??
+            this.document.namespaceToPrefix = this.namespaceToPrefix;
+        };
+        var node = this.document.createElementNS(namespaceURI, nodename);
+        var prefix = undefined;
+        if (namespaceURI) {
+            prefix = this.namespaceToPrefix[namespaceURI];
+            if (prefix) {
+                node.setPrefix(prefix);
+            };
+        };
+        for (var ans in attrs) {
+            // XXX can be optimized by using a dict and just setting the key
+            if (ans && ans != '' && !array.contains(this.namespaces, ans)) {
+                this.namespaces.push(ans);
+            };
+            var nsattrs = attrs[ans];
+            for (var aname in nsattrs) {
+                if (aname == 'prefix') {
+                    continue;
+                };
+                if (ans) {
+                    var attr = this.document.createAttributeNS(ans, aname);
+                    attr.setPrefix(this.namespaceToPrefix[ans]);
+                    attr.nodeValue = nsattrs[aname];
+                    node.setAttributeNodeNS(attr);
+                } else {
+                    var attr = this.document.createAttribute(aname);
+                    attr.nodeValue = nsattrs[aname];
+                    node.setAttributeNode(attr);
+                };
+            };
+        };
+        if (!this.current) {
+            this.document.documentElement = node;
+            this.document._setProtected('childNodes', [node]);
+            this.current = node;
+            this.current._setProtected('parentNode', this.document);
+            this.current._setProtected('ownerDocument', this.document);
+        } else {
+            this.current.appendChild(node);
+            this.current = node;
+        };
+    };
+
+    DOMHandler.prototype.characters = function(data) {
+        if (!this.current && string.strip(data) == '') {
+            return;
+        };
+        var node = this.document.createTextNode(data);
+        this.current.appendChild(node);
+    };
+
+    DOMHandler.prototype.comment = function(data) {
+        if (!this.current && string.strip(data) == '') {
+            return;
+        };
+        var node = this.document.createComment(data);
+        if (this.current) {
+            this.current.appendChild(node);
+        } else {
+            this.document.comment = node;
+        };
+    };
+
+    DOMHandler.prototype.endElement = function(namespaceURI, nodename) {
+        var prefix = this.namespaceToPrefix[namespaceURI];
+        if (nodename != this.current.localName || 
+                namespaceURI != this.current.namespaceURI) {
+            throw('non-matching end tag ' + namespaceURI + ':' + 
+                    prefix + ':' + nodename + ' for start tag ' + 
+                    this.current.namespaceURI + ':' + this.current.nodeName);
+        };
+        this.current = this.current.parentNode;
+    };
+
+    DOMHandler.prototype.endDocument = function() {
+    };
+
+    function DOM() {
+        /* The DOM API 
+
+            Uses regular expressions to convert <xml> to a simple DOM
+        
+            Provides:
+
+                DOM.parseXML(xml)
+                - parse the XML, return a document element
+
+                DOM.createDocument()
+                - contains the document node of the DOM (which in turn contains
+                    the documentElement)
+
+                DOM.toXML()
+                - returns a serialized XML string
+
+                DOM.buildFromHandler(handler)
+                - build and return a DOM document built from a MiniSAX handler
+        */
+    };
+
+    this.DOM = DOM;
+
+    DOM.prototype.createDocument = function() {
+        var document = new Document();
+        document.initialize();
+        return document;
+    };
+
+    DOM.prototype.toXML = function(docOrEl, encoding) {
+        /* serialize to XML */
+        var xml = '<?xml version="1.0"';
+        if (encoding) {
+            xml += ' encoding="' + encoding + '"';
+        };
+        xml += '?>\n';
+        return xml + docOrEl.toXML();
+    };
+
+    DOM.prototype.parseXML = function(xml) {
+        /* parse XML into a DOM 
+        
+            returns a Document node
+        */
+        var handler = new DOMHandler();
+        var parser = new SAXParser();
+        parser.initialize(xml, handler);
+        parser.parse();
+        var document = handler.document;
+        this._copyNamespaceMapping(document, handler.namespaceToPrefix);
+        return document;
+    };
+
+    DOM.prototype.buildFromHandler = function(handler) {
+        /* create a DOM from a SAX handler */
+        var document = handler.document;
+        this._copyNamespaceMapping(document, handler.namespaceToPrefix);
+        return document;
+    };
+
+    DOM.prototype._copyNamespaceMapping = function(document, namespaces) {
+        document.namespaceToPrefix = namespaces;
+    };
+
+    // an implementation of an array, exactly the same as the one in JS 
+    // (although incomplete) itself, this because friggin' IE has problems 
+    // using Array as prototype (it won't update .length on mutations)
+    function BaseArray() {
+        for (var i=0; i < arguments.length; i++) {
+            this[i] = arguments[i];
+        };
+        this.length = arguments.length;
+    };
+
+    BaseArray.prototype.concat = function() {
+        throw('Not supported');
+    };
+
+    BaseArray.prototype.join = function() {
+        throw('Not supported');
+    };
+
+    BaseArray.prototype.pop = function() {
+        var item = this[this.length - 1];
+        delete this[this.length - 1];
+        this.length = this.length - 1;
+        return item;
+    };
+
+    BaseArray.prototype.push = function(item) {
+        this[this.length] = item;
+        this.length = this.length + 1;
+        return item;
+    };
+
+    BaseArray.prototype.reverse = function() {
+        throw('Not supported');
+    };
+
+    BaseArray.prototype.shift = function() {
+        var item = this[0];
+        for (var i=1; i < this.length; i++) {
+            this[i-1] = this[i];
+        };
+        delete this[length - 1];
+        this.length = this.length - 1;
+        return item;
+    };
+
+    BaseArray.prototype.unshift = function(item) {
+        for (var i=0; i < this.length; i++ ) {
+            this[this.length - i] = this[(this.length - i) - 1];
+        };
+        this[0] = item;
+        this.length = this.length + 1;
+        return ;
+    };
+
+    BaseArray.prototype.splice = function() {
+        // XXX we may want to support this later
+        throw('Not supported');
+    };
+
+    BaseArray.prototype.toString = function() {
+        var ret = [];
+        for (var i=1; i < this.length; i++) {
+            ret.push(this[i].toString());
+        };
+        return ret.join(', ');
+    };
+
+    // for subclassing and such...
+    this.BaseArray = BaseArray;
+
+    function NodeList() {
+    };
+
+    NodeList.prototype = new BaseArray;
+    this.NodeList = NodeList;
+
+    NodeList.prototype.item = function(index) {
+        return this[index];
+    };
+
+    function NamedNodeMap() {
+    };
+
+    NamedNodeMap.prototype = new BaseArray;
+    this.NamedNodeMap = NamedNodeMap;
+
+    NamedNodeMap.prototype.item = function(index) {
+        return this[index];
+    };
+
+    NamedNodeMap.prototype.getNamedItem = function(name) {
+        for (var i=0; i < this.length; i++) {
+            if (this[i].nodeName == name) {
+                return this[i];
+            };
+        };
+        return undefined;
+    };
+
+    NamedNodeMap.prototype.setNamedItem = function(arg) {
+        // this should generate exceptions, but I'm not sure when...
+        // XXX how 'bout when arg is not the proper type?!?
+        for (var i=0; i < this.length; i++) {
+            if (this[i].nodeName == arg.nodeName) {
+                this[i] = arg;
+                return;
+            };
+        };
+        this.push(arg);
+    };
+
+    NamedNodeMap.prototype.removeNamedItem = function(name) {
+        // a bit nasty: deleting an element from an array will not actually 
+        // free the index, instead something like undefined or null will end 
+        // up in its place, so we walk the array here, move every element 
+        // behind the item to remove one up, and pop the last item when 
+        // we're done
+        var delete_mode = false;
+        for (var i=0; i < this.length; i++) {
+            if (this[i] === name) {
+                delete_mode = true;
+            };
+            if (delete_mode) {
+                this[i] = this[i + 1];
+            };
+        };
+        if (!delete_mode) {
+            throw(
+                (new DOMException(DOMException.NOT_FOUND_ERR))
+            );
+        };
+        // the last element is now in the array twice
+        this.pop();
+    };
+}();
+
+// XXX shouldn't we make these local?
+function createStack() {
+    // somewhat nasty trick to get a stack trace in Moz
+    var stack = undefined;
+    try {notdefined()} catch(e) {stack = e.stack};
+    if (stack) {
+        stack = stack.split('\n');
+        stack.shift();
+        stack.shift();
+    };
+    return stack ? stack.join('\n') : '';
+};
+
+function getLineNo(stack) {
+    /* tries to get the line no in Moz */
+    if (!stack) {
+        return;
+    };
+    stack = stack.toString().split('\n');
+    var chunks = stack[0].split(':');
+    var lineno = chunks[chunks.length - 1];
+    if (lineno != '0') {
+        return lineno;
+    };
+};
+
+function getFileName(stack) {
+    /* tries to get the filename in Moz */
+    if (!stack) {
+        return;
+    };
+    stack = stack.toString().split('\n');
+    var chunks = stack[0].split(':');
+    var filename = chunks[chunks.length - 2];
+    return filename;
+};
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/example.html
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/example.html	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,62 @@
+<!-- 
+
+    example.html - file for testing Dommer, serves also as an example
+    Copyright (C) 2004 Guido Wesdorp
+    email johnny at debris.demon.nl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    
+-->
+<html>
+  <head>
+    <title>Dommer example</title>
+    <script type="text/javascript" src="../jsbase/array.js"></script>
+    <script type="text/javascript" src="../jsbase/string.js"></script>
+    <script type="text/javascript" src="../minisax.js/minisax.js"></script>
+    <script type="text/javascript" src="dommer.js"></script>
+    <script type="text/javascript">
+    // <![CDATA[
+
+        function run() {
+            // some XML
+            var xml = '<?xml version="1.0" ?>' +
+                        '<foo xmlns="http://debris.demon.nl/foo"\n' + 
+                        'xmlns:baz="http://debris.demon.nl/baz"\n' + 
+                        'xmlns:quux="http://debris.demon.nl/quux"\n' + 
+                        'quuux="quu&amp;uux">\n' +
+                        '<baz:bar foo="bar" quux:quuux="quuuux">' +
+                        '&lt;Qux!&gt;' +
+                        '</baz:bar>\n' +
+                        '</foo>\n';
+            document.getElementById('startxml').appendChild(
+                document.createTextNode(xml)
+            );
+            var dom = new dommer.DOM();
+            var doc = dom.parseXML(xml);
+            document.getElementById('resultxml').appendChild(
+                document.createTextNode(dom.toXML(doc))
+            );
+        };
+
+    // ]]>
+    </script>
+  </head>
+  <body onload="run();">
+    <h4>Start data:</h4>
+    <pre id="startxml"></pre>
+    <h4>Result:</h4>
+    <pre id="resultxml"></pre>
+  </body>
+</html>

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/run_tests.html
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/run_tests.html	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,53 @@
+<!-- 
+
+    run_tests.html - file for testing Dommer, serves also as an example
+    Copyright (C) 2004-2005 Guido Wesdorp
+    email johnny at debris.demon.nl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    
+-->
+<html>
+<head>
+<title>Unit tests for Dommer</title>
+<script type="text/javascript" src="../ecmaunit/ecmaunit.js"> </script>
+<script type="text/javascript" src="../jsbase/array.js"> </script>
+<script type="text/javascript" src="../jsbase/string.js"> </script>
+<script type="text/javascript" src="../minisax.js/minisax.js"> </script>
+<script type="text/javascript" src="dommer.js"> </script>
+<script type="text/javascript" src="tests.js"> </script>
+<script type="text/javascript">
+//<![CDATA[
+
+    function runTests() {
+        var body = document.getElementById('body');
+        var testsuite = new TestSuite(new HTMLReporter(body, true));
+        testsuite.registerTest(DOMTestCase);
+        if (navigator.appName.indexOf('Netscape') > -1 ||
+                navigator.appName.indexOf('Konqueror') > -1) {
+            // disable browser tests in IE, for they will fail...
+            testsuite.registerTest(BrowserDOMTestCase);
+        };
+        testsuite.runSuite();
+    };
+
+//]]>
+</script>
+</head>
+
+<body onload="runTests()" id="body">
+<div style="display:none" id="testdiv" ></div>
+</body>
+</html>

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/test_dommer.js
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/test_dommer.js	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,366 @@
+/*
+    tests.js - unit tests for dommer.js
+    Copyright (C) 2004-2005 Guido Wesdorp
+    email johnny at debris.demon.nl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    $Id: dommer.js,v 1.5 2004/07/31 00:10:15 johnny Exp $
+
+*/
+
+load('../minisax.js/minisax.js');
+load('../jsbase/string.js');
+load('../jsbase/array.js');
+load('dommer.js');
+
+var global = this;
+function setup() {
+    global.dom = new dommer.DOM();
+    global.doc = global.dom.createDocument();
+    global.docfrag = global.doc;
+};
+
+function tearDown() {
+    global.doc = null;
+    delete global.dom;
+};
+
+function test_property_access() {
+    var doc = global.doc;
+    var el = doc.createElement('foo');
+    testing.assertThrows(undefined, function() {el.nodeName = 'foo'});
+};
+
+function test_createElement() {
+    var doc = global.doc;
+    
+    var el1 = doc.createElement('foo');
+    testing.assertEquals(el1.nodeType, 1);
+    testing.assertEquals(el1.nodeName.toLowerCase(), 'foo');
+    testing.assertEquals(el1.namespaceURI, null);
+    testing.assertEquals(el1.ownerDocument, doc);
+
+    var el2 = doc.createElementNS('foo:', 'bar');
+    testing.assertEquals(el2.nodeType, 1);
+    testing.assertEquals(el2.nodeName.toLowerCase(), 'bar');
+    testing.assertEquals(el2.namespaceURI, 'foo:');
+    testing.assertEquals(el2.ownerDocument, doc);
+
+    var attr1 = doc.createAttribute('foo');
+    testing.assertEquals(attr1.nodeType, 2);
+    testing.assertEquals(attr1.nodeName, 'foo');
+    testing.assertEquals(attr1.namespaceURI, null);
+};
+
+function test_appendChild() {
+    var doc = global.doc;
+    var docfrag = global.docfrag;
+
+    var el = doc.createElement('foo');
+    docfrag.appendChild(el);
+    if (docfrag == doc) {
+        // not for browser dom
+        testing.assertEquals(doc.documentElement, el);
+    };
+    testing.assertEquals(el.ownerDocument, doc);
+    testing.assertEquals(el.parentNode, docfrag);
+    testing.assertEquals(el.firstChild, null);
+    testing.assertEquals(el.lastChild, null);
+    testing.assertEquals(el.previousSibling, null);
+    testing.assertEquals(el.nextSibling, null);
+    testing.assertEquals(docfrag.childNodes[0], el);
+
+    var el2 = doc.createElement('foo');
+    if (doc == docfrag) {
+        testing.assertThrows(undefined, doc.appendChild, doc, el2);
+    };
+    el.appendChild(el2);
+    testing.assertEquals(el2.parentNode, el);
+    testing.assertEquals(el.childNodes[0], el2);
+    testing.assertEquals(el.firstChild, el2);
+    testing.assertEquals(el.lastChild, el2);
+    testing.assertEquals(el2.previousSibling, null);
+    testing.assertEquals(el2.nextSibling, null);
+
+    var el3 = doc.createElement('foo');
+    el.appendChild(el3);
+    testing.assertEquals(el3.parentNode, el);
+    testing.assertEquals(el.childNodes[1], el3);
+    testing.assertEquals(el.firstChild, el2);
+    testing.assertEquals(el.lastChild, el3);
+    testing.assertEquals(el2.previousSibling, null);
+    testing.assertEquals(el2.nextSibling, el3);
+    testing.assertEquals(el3.previousSibling, el2);
+    testing.assertEquals(el3.nextSibling, null);
+};
+
+function test_removeChild() {
+    var doc = global.doc;
+    var docfrag = global.docfrag;
+
+    var el = doc.createElement('foo');
+    docfrag.appendChild(el);
+
+    var el2 = doc.createElement('bar');
+    testing.assertEquals(el2.parentNode, null);
+    testing.assertEquals(el.firstChild, null);
+    testing.assertEquals(el.lastChild, null);
+    if (doc == docfrag) {
+        testing.assertThrows(dommer.DOMException, el.removeChild, el, el2);
+    };
+    
+    el.appendChild(el2);
+    testing.assertEquals(el2.parentNode, el);
+    testing.assertEquals(el.firstChild, el2);
+    testing.assertEquals(el.lastChild, el2);
+    testing.assertEquals(el.childNodes[0], el2);
+
+    el3 = doc.createElement('baz');
+    el.appendChild(el3);
+    testing.assertEquals(el3.parentNode, el);
+    testing.assertEquals(el.firstChild, el2);
+    testing.assertEquals(el.lastChild, el3);
+    testing.assertEquals(el2.nextSibling, el3);
+    testing.assertEquals(el3.previousSibling, el2);
+
+    el.removeChild(el2);
+    testing.assertEquals(el2.parentNode, null);
+    testing.assertEquals(el.firstChild, el3);
+    testing.assertEquals(el.lastChild, el3);
+    testing.assertEquals(el.childNodes[0], el3);
+    testing.assertEquals(el2.nextSibling, null);
+    testing.assertEquals(el3.previousSibling, null);
+};
+
+function test_replaceChild() {
+    var doc = global.doc;
+    var docfrag = global.docfrag;
+
+    var el = doc.createElement('foo');
+    docfrag.appendChild(el);
+
+    var child1 = doc.createElement('bar');
+    var child2 = doc.createElement('baz');
+    var child3 = doc.createElement('qux');
+    el.appendChild(child1);
+
+    testing.assertEquals(el.childNodes.length, 1);
+    testing.assertEquals(el.childNodes[0], child1);
+    testing.assertEquals(child1.parentNode, el);
+
+    el.appendChild(child3);
+    testing.assertEquals(el.firstChild, child1);
+    testing.assertEquals(el.lastChild, child3);
+    testing.assertEquals(child1.nextSibling, child3);
+    testing.assertEquals(child3.previousSibling, child1);
+
+    el.replaceChild(child2, child1);
+    testing.assertEquals(child1.parentNode, null);
+    testing.assertEquals(el.childNodes.length, 2);
+    testing.assertEquals(el.firstChild, child2);
+    testing.assertEquals(el.lastChild, child3);
+    testing.assertEquals(child2.parentNode, el);
+    testing.assertEquals(child1.nextSibling, null);
+    testing.assertEquals(child2.nextSibling, child3);
+    testing.assertEquals(child3.previousSibling, child2);
+};
+
+function test_getAttribute() {
+    var doc = global.doc;
+
+    var el = doc.createElement('foo');
+    el.setAttribute('bar', 'baz');
+    testing.assertFalse(el.getAttribute('foo'));
+    var attr = el.getAttribute('bar');
+    testing.assertEquals(el.getAttribute('bar'), 'baz');
+    var attr = el.getAttributeNode('bar');
+    testing.assertEquals(attr.nodeValue, 'baz');
+    testing.assertEquals(attr.nodeType, 2);
+    testing.assertEquals(attr.namespaceURI, null);
+    testing.assertEquals(attr.ownerDocument, doc);
+    testing.assertEquals(attr.parentNode, null);
+    testing.assertEquals(attr.ownerElement, el);
+
+    el.setAttributeNS('foo:', 'bar', 'baz');
+    var attr = el.getAttributeNodeNS('foo:', 'bar');
+    testing.assertEquals(attr.nodeValue, 'baz');
+    testing.assertEquals(attr.namespaceURI, 'foo:');
+};
+
+function test_setAttribute() {
+    var doc = global.doc;
+    
+    var el = doc.createElement('foo');
+    testing.assertThrows(undefined, el.setAttribute, el, 'foo&bar');
+};
+
+function test_toXML() {
+    var doc = global.doc;
+    
+    var foo = doc.createElement('foo');
+    testing.assertEquals(foo.toXML(), '<foo />');
+    
+    foo.setAttribute('bar', 'baz');
+    testing.assertEquals(foo.getAttributeNode('bar').toXML(), 'bar="baz"');
+    testing.assertEquals(foo.toXML(), '<foo bar="baz" />');
+    
+    var parent = doc.createElement('parent');
+    parent.appendChild(foo);
+    testing.assertEquals(parent.toXML(), '<parent><foo bar="baz" /></parent>');
+    
+    doc.appendChild(parent);
+    testing.assertEquals(doc.toXML(), '<parent><foo bar="baz" /></parent>');
+    // using DOM.toXML() adds an XML declaration
+    testing.assertEquals(global.dom.toXML(global.doc), 
+            '<?xml version="1.0"?>\n<parent><foo bar="baz" /></parent>');
+
+    var elwithns = doc.createElementNS('foo:', 'bar');
+    parent.appendChild(elwithns);
+    testing.assertEquals(elwithns.toXML(), '<bar xmlns="foo:" />');
+    testing.assertEquals(doc.toXML(), '<parent><foo bar="baz" />' +
+                                    '<bar xmlns="foo:" /></parent>');
+
+    var el1 = doc.createElementNS('foo:', 'bar');
+    el1.setPrefix('foo');
+    var el2 = doc.createElementNS('foo:', 'baz');
+    el2.setPrefix('foo');
+    el1.appendChild(el2);
+    testing.assertEquals(el1.toXML(),
+        '<foo:bar xmlns:foo="foo:"><foo:baz /></foo:bar>');
+
+    var el1 = doc.createElementNS('foo:', 'bar');
+    el1.setPrefix('foo');
+    var el2 = doc.createElementNS('baz:', 'qux');
+    el2.setPrefix('foo');
+    el1.appendChild(el2);
+    testing.assertEquals(el1.toXML(), 
+        '<foo:bar xmlns:foo="foo:"><foo:qux xmlns:foo="baz:" /></foo:bar>');
+
+    var el1 = doc.createElementNS('foo:', 'foo:bar');
+    el1.setAttributeNS('baz:', 'baz:qux', 'quux');
+    testing.assertEquals(el1.toXML(), 
+            '<foo:bar baz:qux="quux" xmlns:foo="foo:" xmlns:baz="baz:" />');
+};
+
+function test_namedNodeMap() {
+    var nodemap = new dommer.NamedNodeMap();
+
+    var nodes = {};
+    for (var i=0; i < 10; i++) {
+        var node = global.doc.createElement('node-' + i);
+        nodes[i] = node;
+        nodemap.setNamedItem(node);
+    };
+
+    testing.assertEquals(nodemap.length, 10);
+    testing.assertEquals(nodemap[0].nodeName.toLowerCase(), 'node-0');
+    testing.assertEquals(nodemap[0], nodemap.getNamedItem('node-0'));
+    testing.assertEquals(nodemap[nodemap.length - 1], 
+                         nodemap.getNamedItem('node-9'));
+
+    nodemap.removeNamedItem(nodemap[4]);
+    testing.assertEquals(nodemap.length, 9);
+    testing.assertEquals(nodemap[3], nodes[3]);
+    testing.assertEquals(nodemap[4], nodes[5]);
+    testing.assertEquals(nodemap[8], nodes[9]);
+};
+
+function test_cloneNode() {
+    var doc = global.doc;
+
+    var foo = doc.createElement('foo');
+    foo.setAttribute('bar', 'bar');
+    var baz = doc.createElement('baz');
+    baz.appendChild(foo);
+    
+    var clone = baz.cloneNode(false);
+    testing.assertEquals(clone.nodeName.toLowerCase(), 'baz');
+    testing.assertFalse(clone.hasChildNodes());
+    
+    var clone = baz.cloneNode(true);
+    testing.assertEquals(clone.nodeName.toLowerCase(), 'baz');
+    testing.assert(clone.hasChildNodes());
+    testing.assertEquals(clone.childNodes.length, 1);
+    testing.assertEquals(clone.childNodes[0].nodeName.toLowerCase(), 'foo');
+    testing.assertEquals(clone.childNodes[0].attributes.length, 1);
+    testing.assertEquals(
+        clone.childNodes[0].attributes[0].nodeName.toLowerCase(), 'bar');
+    testing.assertEquals(clone.childNodes[0].getAttribute('bar'), 'bar');
+};
+
+function test_parseXML() {
+    var dom = new dommer.DOM();
+
+    var xml1 = '<foo />';
+    var doc = dom.parseXML(xml1);
+    testing.assertEquals(doc.documentElement.nodeName, 'foo');
+    testing.assertEquals(doc.childNodes.length, 1);
+    testing.assertEquals(doc.documentElement.childNodes.length, 0);
+
+    var xml2 = '<foo><bar /></foo>';
+    var doc = dom.parseXML(xml2);
+    testing.assertEquals(doc.documentElement.nodeName, 'foo');
+    testing.assertEquals(doc.documentElement.childNodes.length, 1);
+    testing.assertEquals(doc.documentElement.childNodes[0].nodeName, 'bar');
+
+    var xml3 = '<foo><bar baz="baz" /></foo>';
+    var doc = dom.parseXML(xml3);
+    var bar = doc.documentElement.childNodes[0];
+    testing.assertEquals(bar.attributes.length, 1);
+    testing.assertEquals(bar.attributes[0].nodeName, 'baz');
+    testing.assertEquals(bar.attributes[0].nodeValue, 'baz');
+
+    var xml4 = '<foo xmlns="bar:" />';
+    var doc = dom.parseXML(xml4);
+    testing.assertEquals(doc.documentElement.namespaceURI, 'bar:');
+    testing.assertEquals(doc.documentElement.prefix, null);
+
+    var xml5 = '<foo:bar xmlns:foo="baz:" />';
+    var doc = dom.parseXML(xml5);
+    testing.assertEquals(doc.documentElement.nodeName, 'foo:bar'); 
+    testing.assertEquals(doc.documentElement.localName, 'bar');
+    testing.assertEquals(doc.documentElement.prefix, 'foo');
+    testing.assertEquals(doc.documentElement.namespaceURI, 'baz:');
+
+    var xml6 = '<foo>bar</foo>';
+    var doc = dom.parseXML(xml6);
+    testing.assertEquals(doc.documentElement.childNodes.length, 1);
+    testing.assertEquals(doc.documentElement.firstChild.nodeType, 3);
+    testing.assertEquals(doc.documentElement.firstChild.nodeValue, 'bar');
+
+    var xml7 = '<foo xmlns="foo:" xmlns:bar="bar:" bar:baz="qux" />';
+    var doc = dom.parseXML(xml7);
+    testing.assertEquals(doc.documentElement.attributes.length, 1);
+    testing.assertEquals(doc.documentElement.attributes[0].nodeName,
+                         'bar:baz');
+    testing.assertEquals(doc.documentElement.attributes[0].localName, 'baz');
+    testing.assertEquals(doc.documentElement.attributes[0].nodeValue, 'qux');
+    testing.assertEquals(doc.documentElement.attributes[0].namespaceURI,
+                         'bar:');
+    testing.assertEquals(doc.documentElement.attributes[0].prefix, 'bar');
+
+    var xml8 = '<foo:bar xmlns:foo="foo:"><foo:baz xmlns:foo="bar:" />' +
+               '</foo:bar>';
+    var doc = dom.parseXML(xml8);
+    testing.assertEquals(doc.toXML(), xml8);
+
+    var xml9 = '<foo:bar xmlns:foo="foo:"><bar:baz xmlns:bar="foo:" />' +
+               '</foo:bar>';
+    var expected = '<foo:bar xmlns:foo="foo:"><foo:baz /></foo:bar>';
+    var doc = dom.parseXML(xml9);
+    testing.assertEquals(doc.toXML(), expected);
+};
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/version.txt
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/dommer/version.txt	Sun Jan 20 20:43:18 2008
@@ -0,0 +1 @@
+0.4

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/LICENSE.txt
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/LICENSE.txt	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,31 @@
+JSBase - Copyright (c) 2004-2007, Guido Wesdorp
+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 JSBase 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.

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/README.txt
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/README.txt	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,137 @@
+JSBase
+=======
+
+What is it?
+------------
+
+This is a collection of bits of JavaScript helper functionality, to solve 
+common problems encountered when programming JavaScript code. The library was
+mostly written because I needed certain generic functionality available for
+using in different JS projects, but will be valuable for anyone writing JS
+code. The strenghts of this library are:
+
+  * everything is written in 'modules', which provide their own namespace and
+    are seperately loadable (certain modules do depend on others, but I tried
+    to keep this down to a minimum)
+
+  * care has been taken that it's possible to use this library *at any time, 
+    on any platform*, by not depending on any variables being available, or 
+    isolating the instances where a variable (for instance 'window') is 
+    required
+
+  * the library should not clash with other libraries
+    
+  * no overriding or extending of built-in data types or functionality
+
+  * the library is light-weight, and has no impact on the way the JS is 
+    written, although it shows some patterns to use concerning 'OO' programming
+    in JS, it does not make the code harder to read or understand for people
+    that don't know the library by using or enforcing complex patterns
+
+  * the functionality in this library can, with the exception of few very 
+    browser-specific functions, can be used in any JS environment (e.g. the
+    unit tests are ran using SpiderMonkey, see 'unit tests' below)
+
+  * the library is simple and self-explanatory (of course this is not an excuse
+    for not providing documentation! my excuse for that is lack of time...)
+
+What kind of functionality should I expect?
+--------------------------------------------
+
+This library provides solutions to problems in the core language (e.g.
+functions to deal more easily with arrays and strings) and somewhat lower level
+problems in JS environments (e.g. a cross-platform print() function to write to
+stdout or the document in some way). There are some helpers to solve browser
+incompatibility problems (e.g. a 'getXMLHttpRequest()' function and
+cross-browser event handling) and wrappers for things that are just very badly
+implemented in browsers (e.g.  a schedule() function which you can pass a
+normal callable and additional arguments to, a wrapper to solve the problem
+where 'this' in a method body refers to something else than the object a method
+is implemented on and proper exception classes).
+
+More detailed description of the modules
+------------------------------------------
+
+The modules, with a short description:
+
+  * array.js
+
+    a set of functions to help with arrays, basically stuff that the JS core 
+    should have provided for
+
+  * exception.js
+
+    this provides the Exception base class and some subclasses, the excepsions
+    raised by the library use these to allow distinguishing between different
+    exceptions more easily, and also they provide a traceback if the platform
+    allows that (mainly Mozilla-related platforms)
+
+  * function.js
+
+    this currently provides a single function, that helps fixing the 'this'
+    problem, where 'this' inside methods points to something else than the
+    object which the methods are defined on (happens e.g. on event handling
+    in browsers)
+
+  * misclib.js
+
+    a set of miscellaneous functionality, such as a schedule() method for 
+    scheduling function calls (to replace window.setTimeout), cross-browser
+    event handling (also fixing memory leaks in IE), a repr() function to
+    create string representations of objects (also recursively, if desired),
+    a dir() function to view the attributes of objects, and a print() function
+    that makes messages visible in different ways, depending on the platform
+    you're on (allowing for presenting text to a user both in browsers and 
+    command line environments)
+ 
+  * number.js
+
+    number related functions
+
+  * server.js
+
+    cross-browser server interaction, some higher-level 'AJAX'-related 
+    functions
+
+  * string.js
+
+    string related functions
+
+  * testing.js
+
+    functionality to help debugging and testing your applications, it both
+    harbours a couple of helper functions you can call from your code, as
+    functionality to unit-test that code (with py.test integration, see below)
+    
+Unit testing
+-------------
+
+The 'testing.js' module contains some functions that can be used to write very
+simple unit tests (see the module for more information for now). Also there's
+a 'conftest.py' and some stuff in the 'testing' dir that allows you to run
+JavaScript unit tests using the Python 'py.test' unit test runner, part of the
+`py lib`_ library.
+
+.. _`py lib`: http://codespeak.net/py
+
+Other files
+------------
+
+The other files in the directory are documentation and license information
+and such, and unit tests for the package and related files.
+
+Note
+----
+
+Note that the library is currently not in a state in which it can be considered
+a complete solution: it merely provides me personally the stuff I needed the
+period I used it... Hopefully at some point it will be complete enough to use
+by others, but right now don't expect it to solve all your general JS problems
+yet.
+
+Questions, bug reports, etc.
+-----------------------------
+
+If you have questions, bug reports, patches or remarks, please send an email
+to johnny at johnnydebris.net.
+

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/__init__.py
==============================================================================

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/array.js
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/array.js	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,114 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2004-2007 Guido Wesdorp. All rights reserved.
+ *
+ * This software is distributed under the terms of the JSBase
+ * License. See LICENSE.txt for license text.
+ *
+ *****************************************************************************/
+
+var global = this;
+global.array = new function() {
+    var array = this;
+    
+    this.contains = function(a, element, objectequality) {
+        /* see if some value is in a */
+        // DEPRECATED!!! use array.indexOf instead
+        return (this.indexOf(a, element, !objectequality) > -1);
+    };
+
+    this.indexOf = function(a, element, compareValues) {
+        for (var i=0; i < a.length; i++) {
+            if (!compareValues) {
+                if (element === a[i]) {
+                    return i;
+                };
+            } else {
+                if (element == a[i]) {
+                    return i;
+                };
+            };
+        };
+        return -1;
+    };
+
+    this.removeDoubles = function(a) {
+        var ret = [];
+        for (var i=0; i < a.length; i++) {
+            if (!this.contains(ret, a[i])) {
+                ret.push(a[i]);
+            };
+        };
+        return ret;
+    };
+
+    this.map = function(a, func) {
+        /* apply 'func' to each element in the array (in-place!!) */
+        for (var i=0; i < a.length; i++) {
+            a[i] = func(a[i]);
+        };
+        return this;
+    };
+
+    this.reversed = function(a) {
+        var ret = [];
+        for (var i = a.length; i > 0; i--) {
+            ret.push(a[i - 1]);
+        };
+        return ret;
+    };
+
+    this.StopIteration = function(message) {
+        if (message !== undefined) {
+            this._initialize('StopIteration', message);
+        };
+    };
+
+    if (global.exception) {
+        StopIteration.prototype = global.exception.Exception;
+    };
+
+    var Iterator = this.Iterator = function(a) {
+        if (a) {
+            this._initialize(a);
+        };
+    };
+
+    Iterator._initialize = function(a) {
+        this._array = a;
+        this._i = 0;
+    };
+
+    Iterator.next = function() {
+        if (this._i >= this._array.length) {
+            this._i = 0;
+            throw(StopIteration('no more items'));
+        };
+        return this._i++;
+    };
+
+    this.iterate = function(a) {
+        /*  iterate through array 'a'
+
+            this returns the n-th item of array 'a', where n is the number of
+            times this function has been called on 'a' before
+
+            when the items are all visited, the function resets the counter and
+            starts from the start
+
+            note that this annotates the array with information about iteration
+            using the attribute '__iter_index__', remove this or set to 0 to
+            reset
+
+            this does not work well with arrays that have 'undefined' as one of
+            their values!!
+        */
+        if (!a.__iter_index__) {
+            a.__iter_index__ = 0;
+        } else if (a.__iter_index__ >= a.length) {
+            a.__iter_index__ = undefined;
+            return undefined;
+        };
+        return a[a.__iter_index__++];
+    };
+}();

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/conftest.py
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/conftest.py	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,166 @@
+# JS unit test support for py.test - (c) 2007 Guido Wesdorp. All rights
+# reserved
+#
+# This software is distributed under the terms of the JSBase
+# License. See LICENSE.txt for license text.
+
+import py
+
+here = py.magic.autopath().dirpath()
+
+class JSTest(py.test.collect.Item):
+    def run(self):
+        path = self.fspath
+        test = self.name.split('/')[-1]
+        paths = [path.strpath, 
+                    (here / 'exception.js').strpath,
+                    (here / 'testing.js').strpath,
+                    (here / 'misclib.js').strpath,
+                ]
+        testjs = (here / 'testing/testbase.js').read() % (
+                    paths, test, '__main__')
+        curdir = str(py.path.local('.'))
+        py.std.os.chdir(str(self.fspath.dirpath()))
+        try:
+            jspath = self.fspath.new(basename='__testbase_temp.js')
+            try:
+                jspath.write(testjs)
+                pipe = py.std.os.popen('js "%s"' % (jspath,))
+                try:
+                    data = {}
+                    for line in pipe:
+                        done = self._handle_line(line, data)
+                        if done:
+                            errdata = data[data['current']]
+                            if errdata:
+                                self.fail(errdata)
+                finally:
+                    pipe.close()
+            finally:
+                jspath.remove()
+        finally:
+            py.std.os.chdir(curdir)
+
+    def fail(self, errdata):
+        py.test.fail(
+        '\nJS traceback (most recent last): \n%s\n%s\n' % (
+                (errdata[1:] and 
+                    self._format_tb(errdata[1:-5]) or
+                    'no traceback available'
+                ),
+                errdata[0], 
+            )
+        )
+
+    _handling_traceback = False
+    def _handle_line(self, line, data):
+        line = line[:-1]
+        if line.startswith('end test'):
+            return True
+        if self._handling_traceback and line != 'end traceback':
+            data[data['current']].append(line)
+        if line.startswith('PRINTED: '):
+            print line[9:]
+        elif line.startswith('running test '):
+            testname = line[13:]
+            data['current'] = testname
+            data[testname] = []
+        elif line.startswith('success'):
+            pass
+        elif line.startswith('failure: '):
+            data[data['current']].append(line[9:])
+        elif line.startswith('traceback'):
+            self._handling_traceback = True
+        elif line.startswith('end traceback'):
+            self._handling_traceback = False
+
+    def _format_tb(self, tb):
+        tb.reverse()
+        ret = []
+        for line in tb:
+            line = line.strip()
+            if not line:
+                continue
+            funcsig, lineinfo = line.split('@', 1)
+            fpath, lineno = lineinfo.rsplit(':', 1)
+            fname = py.path.local(fpath).basename
+            # XXX might filter out too much... but it's better than leaving it
+            # all in (since it adds a couple of lines to the end of the tb,
+            # making it harder to find the problem line)
+            if fname in ['__testbase_temp.js', '__testbase_find.js',
+                            'exception.js']: 
+                continue
+            lineno = int(lineno)
+            if lineno == 0:
+                fname = "<unknown>"
+            ret.append('File "%s", line %s, in %s' % (
+                        fname, lineno, funcsig or '?'))
+            if lineno > 0:
+                line = py.path.local(fpath).readlines()[lineno - 1]
+                ret.append('    %s' % (line.strip(),))
+        return '\n'.join(['  %s' % (r,) for r in ret]) 
+            
+class JSChecker(py.test.collect.Module):
+    def __repr__(self): 
+        return py.test.collect.Collector.__repr__(self) 
+
+    def setup(self): 
+        pass 
+
+    def teardown(self): 
+        pass 
+
+    def run(self): 
+        findjs = here.join('testing/findtests.js').read() % (
+                    self.fspath.strpath, '__main__')
+        curdir = str(py.path.local('.'))
+        py.std.os.chdir(str(self.fspath.dirpath()))
+        tests = []
+        try:
+            jspath = self.fspath.new(basename='__findtests.js')
+            try:
+                jspath.write(findjs)
+                stdin, pipe, stderr = py.std.os.popen3('js "%s"' % (jspath,))
+                try:
+                    error = stderr.next()
+                    print 'Error read:', error
+                except StopIteration:
+                    pass
+                else:
+                    if error.find('command not found') > -1:
+                        py.test.skip(
+                            'error running "js" (SpiderMonkey), which is '
+                            'required to run JS tests')
+                    else:
+                        py.test.fail(error)
+                    return
+                try:
+                    for line in pipe:
+                        tests.append(line.strip())
+                finally:
+                    py.std.sys.stdout = py.std.sys.__stdout__
+                    pipe.close()
+            finally:
+                jspath.remove()
+        finally:
+            py.std.os.chdir(curdir)
+        return ['%s/%s' % (self.fspath.basename, test) for test in tests]
+
+    def join(self, name):
+        if py.path.local(name).dirpath().strpath.endswith('.js'):
+            return JSTest(name, self)
+        return super(JSChecker, self).join(name)
+
+class Directory(py.test.collect.Directory):
+    def run(self):
+        if self.fspath == here:
+            return [p.basename for p in self.fspath.listdir('test_*') if
+                    p.ext in ['.py', '.js']]
+        return super(Directory, self).run()
+
+    def join(self, name):
+        if not name.endswith('.js'):
+            return super(Directory, self).join(name)
+        p = self.fspath.join(name)
+        if p.check(file=1):
+            return JSChecker(p, parent=self)

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/exception.js
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/exception.js	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,158 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2004-2007 Guido Wesdorp. All rights reserved.
+ *
+ * This software is distributed under the terms of the JSBase
+ * License. See LICENSE.txt for license text.
+ *
+ *****************************************************************************/
+
+var global = this;
+global.exception = new function() {
+    /* Exception handling in a somewhat coherent manner */
+
+    var exception = this;
+
+    this.Exception = function(message) {
+        /* base class of exceptions */
+        if (message !== undefined) {
+            this._initialize('Exception', message);
+        };
+    };
+
+    this.Exception.prototype._initialize = function(name, message) {
+        this.name = name;
+        this.message = message;
+        var stack = this.stack = exception._createStack();
+        this.lineNo = exception._getLineNo(stack);
+        this.fileName = exception._getFileName(stack);
+    };
+
+    this.Exception.prototype.toString = function() {
+        var lineNo = this.lineNo;
+        var fileName = this.fileName;
+        var stack = this.stack;
+        var exc = this.name + ': ' + this.message + '\n';
+        if (lineNo || fileName || stack) {
+            exc += '\n';
+        };
+        if (fileName) {
+            exc += 'file: ' + fileName;
+            if (lineNo) {
+                exc += ', ';
+            } else {
+                exc += '\n';
+            };
+        };
+        if (lineNo) {
+            exc += 'line: ' + lineNo + '\n';
+        };
+        if (stack) {
+            exc += '\n';
+            var lines = stack.split('\n');
+            for (var i=0; i < lines.length; i++) {
+                var line = lines[i];
+                if (line.charAt(0) == '(') {
+                    line = 'function' + line;
+                };
+                exc += line + '\n';
+            };
+        };
+        return exc;
+    };
+
+    this.ValueError = function(message) {
+        /* raised on providing invalid values */
+        if (message !== undefined) {
+            this._initialize('ValueError', message);
+        };
+    };
+
+    this.ValueError.prototype = new this.Exception;
+
+    this.AssertionError = function(message) {
+        /* raised when an assertion fails */
+        if (message !== undefined) {
+            this._initialize('AssertionError', message);
+        };
+    };
+
+    this.AssertionError.prototype = new this.Exception;
+
+    // XXX need to define a load of useful exceptions here
+    this.NotSupported = function(message) {
+        /* raised when a feature is not supported on the running platform */
+        if (message !== undefined) {
+            this._initialize('NotSupported', message);
+        };
+    };
+
+    this.NotSupported.prototype = new this.Exception;
+    
+    this.NotFound = function(message) {
+        /* raised when something is not found */
+        if (message !== undefined) {
+            this._initialize('NotFound', message);
+        };
+    };
+
+    this.NotFound.prototype = new this.Exception;
+
+    this.HTTPError = function(status) {
+        if (status !== undefined) {
+            // XXX need to get the message for the error here...
+            this._initialize('HTTPError', status);
+        };
+    };
+
+    this.HTTPError.prototype = new this.Exception;
+
+    this.MissingDependency = function(missing, from) {
+        /* raised when some dependency can not be resolved */
+        if (missing !== undefined) {
+            var message = missing;
+            if (from) {
+                message += ' (from ' + from + ')';
+            };
+            this._initialize('MissingDependency', message);
+        };
+    };
+
+    this.NotFound.prototype = new this.Exception;
+
+    this._createStack = function() {
+        /* somewhat nasty trick to get a stack trace in (works only in Moz) */
+        var stack = undefined;
+        try {notdefined()} catch(e) {stack = e.stack};
+        if (stack) {
+            stack = stack.split('\n');
+            stack.shift();
+            stack.shift();
+        };
+        return stack ? stack.join('\n') : '';
+    };
+
+    this._getLineNo = function(stack) {
+        /* tries to get the line no in (works only in Moz) */
+        if (!stack) {
+            return;
+        };
+        stack = stack.toString().split('\n');
+        var chunks = stack[0].split(':');
+        var lineno = chunks[chunks.length - 1];
+        if (lineno != '0') {
+            return lineno;
+        };
+    };
+
+    this._getFileName = function(stack) {
+        /* tries to get the filename in (works only in Moz) */
+        if (!stack) {
+            return;
+        };
+        stack = stack.toString().split('\n');
+        var chunks = stack[0].split(':');
+        var filename = chunks[chunks.length - 2];
+        return filename;
+    };
+}();

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/function.js
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/function.js	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2004-2007 Guido Wesdorp. All rights reserved.
+ *
+ * This software is distributed under the terms of the jsbase
+ * License. See LICENSE.txt for license text.
+ *
+ *****************************************************************************/
+
+var global = this;
+global.func = new function() {
+    this.fixContext = function(f, context) {
+        /* Return a function wrapped, so that 'this' points to 'context'
+            
+            Under certain circumstances, methods get called with the 'this' 
+            variable pointing to something else than the object the method is
+            defined on. In that case, one can use some trick with nested scopes 
+            and Function.apply() to get this to refer to the object again. This
+            method provides a generic wrapper, that not only fixes 'this'
+            but also allows passing additional arguments to handlers.
+
+            Example:
+
+            // create an object with a method that will serve as an event 
+            // handler later on
+            function Foo() {
+                this.bar = 1;
+                this.baz = function(event, some_arg) {
+                    // if the following would be done when this method would not
+                    // get wrapped, 'this' would point to the Event object rather
+                    // than the Foo one, resulting in a name lookup problem
+                    alert('this.bar: ' + this.bar + ', some_arg: ' + some_arg);
+                };
+            };
+
+            // create a Foo
+            var foo = new Foo();
+
+            // get some element to register some event on
+            var el = document.getElementById('some_element');
+
+            // now we're going to register the foo.baz method as an 
+            // event handler for the 'onclick' event on the element,
+            // but we're wrapping it first, and pass in some argument just
+            // for show
+            // using the Mozilla style of event registration, see 
+            // event.js' registerEventHandler() for a cross-browser way
+            el.addEventListener('click', func.fixContext(foo.bar, foo, 2), 
+                                    false);
+
+            The method will be called with the following arguments:
+
+            - the object that 'this' would point to when the method would have
+                been used unwrapped
+
+            - the additional arguments the fixContext method was called with
+
+            - the arguments the wrapped version was called with
+
+        */
+        var orgargs = [];
+        for (var i=0; i < arguments.length; i++) {
+            if (i == 0 || (context && i == 1)) {
+                continue;
+            };
+            orgargs.push(arguments[i]);
+        };
+        if (!context) {
+            context = window;
+        };
+        var wrapper = function() {
+            var funcargs = [this];
+            for (var i=0; i < orgargs.length; i++) {
+                funcargs.push(orgargs[i]);
+            };
+            for (var i=0; i < arguments.length; i++) {
+                funcargs.push(arguments[i]);
+            };
+            return f.apply(context, funcargs);
+        };
+        return wrapper;
+    };
+}();

Added: kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/misclib.js
==============================================================================
--- (empty file)
+++ kukit/kukit.js/trunk/3rd_party/johnnydebris.net/jsbase/misclib.js	Sun Jan 20 20:43:18 2008
@@ -0,0 +1,350 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2004-2007 Guido Wesdorp. All rights reserved.
+ *
+ * This software is distributed under the terms of the JSBase
+ * License. See LICENSE.txt for license text.
+ *
+ *****************************************************************************/
+
+var global = this;
+global.misclib = new function() {
+    /* This lib mostly contains fixes for common problems in JS, additions to
+        the core global functions and wrappers for fixing browser issues.
+
+        See the comments in the code for further explanations.
+    */
+
+    // reference to the lib to reach it from the functions/classes
+    var misclib = this;
+
+    var Timer = function() {
+        /* Wrapper around window.setTimeout, to solve number of problems:
+        
+            * setTimeout gets a string rather than a function reference as an
+                argument
+
+            * setTimeout can not handle arguments to the callable properly, 
+                since it's evaluated in the window namespace, not in the current
+                scope
+
+            Usage:
+
+                // call the global 'schedule' function to register a function
+                // called 'foo' on the current (imaginary) object, passing in
+                // a variable called 'bar' as an argument, so it gets called 
+                // after 1000 msecs
+                window.misclib.schedule(this, this.foo,  1000, bar);
+
+            Note that if you don't care about 'this' inside the function 
+            you register, you can just pass in a ref to the 'window' object
+            as the first argument. No lookup is done in the namespace, the
+            first argument is only used as the 'this' variable inside the
+            function.
+        */
+        this.lastid = 0;
+        this.functions = {};
+        
+        this.registerCallable = function(object, func, timeout) {
+            /* register a function to be called with a timeout
+
+                args: 
+                    object - the context in which to call the function ('this')
+                    func - the function
+                    timeout - timeout in millisecs
+                    
+                all other args will be passed 1:1 to the function when called
+            */
+            var args = new Array();
+            for (var i=3; i < arguments.length; i++) {
+                args.push(arguments[i]);
+            }
+            var id = this._createUniqueId();
+            this.functions[id] = new Array(object, func, args);
+            // setTimeout will be called in the module namespace, where the 
+            // timer_instance variable also resides (see below)
+            setTimeout("window.misclib.timer_instance." +
+                        "_handleFunction(" + id + ")", timeout);
+        };
+
+        this._handleFunction = function(id) {
+            /* private method that does the actual function call */
+            var obj = this.functions[id][0];
+            var func = this.functions[id][1];
+            var args = this.functions[id][2];
+            this.functions[id] = null;
+            func.apply(obj, args);
+        };
+
+        this._createUniqueId = function() {
+            /* create a unique id to store the function by */
+            while (this.lastid in this.functions && 
+                        this.functions[this.lastid]) {
+                this.lastid++;
+                if (this.lastid > 100000) {
+                    this.lastid = 0;
+                }
+            }
+            return this.lastid;
+        };
+    };
+
+    // create a timer instance in the module namespace
+    var timer_instance = this.timer_instance = new Timer();
+
+    // this is the function that should be called to register callables
+    this.schedule = function() {
+            timer_instance.registerCallable.apply(timer_instance, arguments)};
+
+    // cross-browser event registration
+    var events_supported = true;
+    try {
+        window;
+    } catch(e) {
+        events_supported = false;
+    };
+    
+    if (events_supported) {
+        // first some privates
+        
+        // a registry for events so they can be unregistered on unload of the 
+        // body
+        var event_registry = {};
+
+        // an iterator for unique ids
+        var currid = 0;
+
+        // just to make some guy on irc happy, store references to 
+        // browser-specific wrappers so we don't have to find out the type of
+        // browser on every registration (yeah, yeah, i admit it was quite a 
+        // good tip... ;)
+        var reg_handler = null;
+        var unreg_handler = null;
+        if (window.addEventListener) {
+            reg_handler = function(element, eventname, handler) {
+                // XXX not sure if anyone ever uses the last argument...
+                element.addEventListener(eventname, handler, false);
+            };
+            unreg_handler = function(element, eventname, handler) {
+                element.removeEventListener(eventname, handler, false);
+            };
+        } else if (window.attachEvent) {
+            reg_handler = function(element, eventname, handler) {
+                element.attachEvent('on' + eventname, handler);
+            };
+            dereg_handler = function(element, eventname, handler) {
+                element.detachEvent('on' + eventname, handler);
+            };
+        } else {
+            reg_handler = function(element, eventname, handler) {
+                var message = 'Event registration not supported or not ' +
+                                'understood on this platform';
+                if (global.exception) {
+                    throw(new exception.NotSupported(message));
+                } else {
+                    throw(message);
+                };
+            };
+        };
+
+        this.addEventHandler = function(element, eventname, handler, context) {
+            /* Method to register an event handler
+
+                Works in standards compliant browsers and IE, and solves a
+                number of different problems. Most obviously it makes that 
+                there's only a single function to use and memorize, but also 
+                it makes that 'this' inside the function points to the context 
+                (usually you'll want to pass in the object the method is 
+                defined on), and it fixes memory leaks (IE is infamous for 
+                leaking memory, which can lead to problems if you register a 
+                lot of event handlers, especially since the memory leakage 
+                doesn't disappear on page reloads, see e.g. 
+                http://www.bazon.net/mishoo/articles.epl?art_id=824).
+            
+                Arguments:
+                
+                    * element - the object to register the event on
+                    
+                    * eventname - a string describing the event (Mozilla style, 
+                        so without the 'on')
+                    
+                    * handler - a reference to the function to be called when 
+                        the event occurs
+
+                    * context - the 'this' variable inside the function
+
+                The arguments passed to the handler:
+
+                    * event - a reference to the event fired
+
+                    * all arguments passed in to this function besides