]> err.no Git - sope/commitdiff
started WEPrototype library
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 10 Jul 2005 22:01:40 +0000 (22:01 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 10 Jul 2005 22:01:40 +0000 (22:01 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@876 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

33 files changed:
sope-appserver/NGObjWeb/DynamicElements/WOJavaScript.m
sope-appserver/WEPrototype/COPYING [new file with mode: 0644]
sope-appserver/WEPrototype/COPYRIGHT [new file with mode: 0644]
sope-appserver/WEPrototype/ChangeLog [new file with mode: 0644]
sope-appserver/WEPrototype/GNUmakefile [new file with mode: 0644]
sope-appserver/WEPrototype/GNUmakefile.postamble [new file with mode: 0644]
sope-appserver/WEPrototype/GNUmakefile.preamble [new file with mode: 0644]
sope-appserver/WEPrototype/README [new file with mode: 0644]
sope-appserver/WEPrototype/Version [new file with mode: 0644]
sope-appserver/WEPrototype/WELiveLink.m [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeBundle.m [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeElemBuilder.m [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeScript.api [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeScript.h [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeScript.jsm [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeScript.m [new file with mode: 0644]
sope-appserver/WEPrototype/WEPrototypeScriptAction.m [new file with mode: 0644]
sope-appserver/WEPrototype/bundle-info.plist [new file with mode: 0644]
sope-appserver/WEPrototype/common.h [new file with mode: 0644]
sope-appserver/WEPrototype/fhs.make [new file with mode: 0644]
sope-appserver/WEPrototype/js2m.sh [new file with mode: 0755]
sope-appserver/WEPrototype/prototype/AUTHORS [new file with mode: 0644]
sope-appserver/WEPrototype/prototype/LICENSE [new file with mode: 0644]
sope-appserver/WEPrototype/prototype/README [new file with mode: 0644]
sope-appserver/WEPrototype/prototype/prototype.js [new file with mode: 0644]
sope-appserver/samples/TestPrototype/ChangeLog [new file with mode: 0644]
sope-appserver/samples/TestPrototype/GNUmakefile [new file with mode: 0644]
sope-appserver/samples/TestPrototype/GNUmakefile.preamble [new file with mode: 0644]
sope-appserver/samples/TestPrototype/Main.m [new file with mode: 0644]
sope-appserver/samples/TestPrototype/Main.wo/Main.html [new file with mode: 0644]
sope-appserver/samples/TestPrototype/Main.wo/Main.wod [new file with mode: 0644]
sope-appserver/samples/TestPrototype/TestPrototype.m [new file with mode: 0644]
sope-appserver/samples/TestPrototype/common.h [new file with mode: 0644]

index e70fa0dea438a4e6743dc4531f30bf76f6fe6143..6951041862cfea0ded64432c8559d765e845adb8 100644 (file)
   }
   
   /* add URL to script */
-  if (self->scriptSource) {
+  if (self->scriptSource != nil) {
     st = [self->scriptSource stringValueInComponent:sComponent];
     WOResponse_AddCString(_response, " src=\"");
     [_response appendContentHTMLAttributeValue:st];
diff --git a/sope-appserver/WEPrototype/COPYING b/sope-appserver/WEPrototype/COPYING
new file mode 100644 (file)
index 0000000..2f599d8
--- /dev/null
@@ -0,0 +1,485 @@
+IMPORTANT NOTE: the prototype JavaScript source has a different license.
+
+
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 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.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, 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 library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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.
+\f
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  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 library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; 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.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/sope-appserver/WEPrototype/COPYRIGHT b/sope-appserver/WEPrototype/COPYRIGHT
new file mode 100644 (file)
index 0000000..cfb1b37
--- /dev/null
@@ -0,0 +1,7 @@
+Copyright (C) 2005 Helge Hess
+Contact: helge.hess@opengroupware.org
+
+The JavaScript Prototype library sources are:
+Copyright (c) 2005 Sam Stephenson
+
+Please see the LICENSE file in the prototype subdirectory.
diff --git a/sope-appserver/WEPrototype/ChangeLog b/sope-appserver/WEPrototype/ChangeLog
new file mode 100644 (file)
index 0000000..0913c9b
--- /dev/null
@@ -0,0 +1,5 @@
+2005-07-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * imported Prototype library v1.2.0
+
+       * created project
diff --git a/sope-appserver/WEPrototype/GNUmakefile b/sope-appserver/WEPrototype/GNUmakefile
new file mode 100644 (file)
index 0000000..7209794
--- /dev/null
@@ -0,0 +1,32 @@
+# GNUstep makefile
+
+-include ../../config.make
+include $(GNUSTEP_MAKEFILES)/common.make
+include ../Version
+include ./Version
+
+LIBRARY_NAME     = libWEPrototype
+BUNDLE_NAME      = WEPrototype
+BUNDLE_EXTENSION = .wox
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/WOxElemBuilders-$(MAJOR_VERSION).$(MINOR_VERSION)/
+
+FHS_MANPAGES += doc/*.3
+
+libWEPrototype_HEADER_FILES_DIR         = .
+libWEPrototype_HEADER_FILES_INSTALL_DIR = /WEPrototype
+
+libWEPrototype_HEADER_FILES =
+
+libWEPrototype_OBJC_FILES = \
+       WEPrototypeScriptAction.m       \
+       WEPrototypeScript.m             \
+       WELiveLink.m                    \
+
+WEPrototype_OBJC_FILES      = WEPrototypeBundle.m
+WEPrototype_PRINCIPAL_CLASS = WEPrototypeBundle
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/library.make
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+-include fhs.make
diff --git a/sope-appserver/WEPrototype/GNUmakefile.postamble b/sope-appserver/WEPrototype/GNUmakefile.postamble
new file mode 100644 (file)
index 0000000..694cce0
--- /dev/null
@@ -0,0 +1,8 @@
+# postprocessing makefile 
+
+WEPrototypeScript.jsm : prototype/prototype.js
+       sh js2m.sh $< $@
+       touch WEPrototypeScript.m
+
+before-all :: WEPrototypeScript.jsm
+
diff --git a/sope-appserver/WEPrototype/GNUmakefile.preamble b/sope-appserver/WEPrototype/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..433444d
--- /dev/null
@@ -0,0 +1,86 @@
+# compiler flags
+
+
+ADDITIONAL_CPPFLAGS += \
+        -Wall -DCOMPILE_FOR_GSTEP_MAKE=1        \
+        -DSOPE_MAJOR_VERSION=$(MAJOR_VERSION)   \
+        -DSOPE_MINOR_VERSION=$(MINOR_VERSION)   \
+        -DWEP_SUBMINOR_VERSION=$(SUBMINOR_VERSION)
+
+ADDITIONAL_CPPFLAGS += -Wall
+ADDITIONAL_INCLUDE_DIRS += \
+       -I.. -I../.. -I../NGObjWeb      \
+       -I../../sope-core/NGStreams     \
+       -I../../sope-core/NGExtensions  \
+       -I../../sope-core               \
+       -I../../sope-xml
+
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+after-WEPrototype-all ::
+       @(cp bundle-info.plist \
+         $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
+else
+after-WEPrototype-all ::
+       @(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
+         cp ../bundle-info.plist .)
+endif
+
+libWEPrototype_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+libWEPrototype_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)
+
+libWEPrototype_LIBRARIES_DEPEND_UPON += \
+       -lNGObjWeb      \
+       -lNGMime        \
+       -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+RELBUILD_DIR_APPSERVER=$(GNUSTEP_BUILD_DIR)/..
+RELBUILD_DIR_MIME=$(GNUSTEP_BUILD_DIR)/../../sope-mime
+RELBUILD_DIR_SxCore=$(GNUSTEP_BUILD_DIR)/../../sope-core
+RELBUILD_DIR_SxXml=$(GNUSTEP_BUILD_DIR)/../../sope-xml
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(GNUSTEP_OBJ_DIR)                                            \
+        -L$(RELBUILD_DIR_APPSERVER)/NGObjWeb/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_MIME)/$(GNUSTEP_OBJ_DIR_NAME)                 \
+        -L$(RELBUILD_DIR_SxCore)/NGStreams/$(GNUSTEP_OBJ_DIR_NAME)      \
+        -L$(RELBUILD_DIR_SxCore)/NGExtensions/$(GNUSTEP_OBJ_DIR_NAME)   \
+        -L$(RELBUILD_DIR_SxCore)/EOControl/$(GNUSTEP_OBJ_DIR_NAME)             \
+        -L$(RELBUILD_DIR_SxXml)/XmlRpc/$(GNUSTEP_OBJ_DIR_NAME)         \
+        -L$(RELBUILD_DIR_SxXml)/DOM/$(GNUSTEP_OBJ_DIR_NAME)            \
+        -L$(RELBUILD_DIR_SxXml)/SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
+else
+ADDITIONAL_LIB_DIRS += \
+       -L./$(GNUSTEP_OBJ_DIR)                                  \
+        -L../NGObjWeb/$(GNUSTEP_OBJ_DIR)                       \
+        -L../../sope-mime/$(GNUSTEP_OBJ_DIR)                   \
+        -L../../sope-core/NGStreams/$(GNUSTEP_OBJ_DIR)         \
+        -L../../sope-core/NGExtensions/$(GNUSTEP_OBJ_DIR)      \
+        -L../../sope-core/EOControl/$(GNUSTEP_OBJ_DIR)         \
+        -L../../sope-xml/XmlRpc/$(GNUSTEP_OBJ_DIR)             \
+        -L../../sope-xml/DOM/$(GNUSTEP_OBJ_DIR)                        \
+        -L../../sope-xml/SaxObjC/$(GNUSTEP_OBJ_DIR)
+endif
+
+WEPrototype_BUNDLE_LIBS   += \
+       -lWEPrototype   \
+       -lNGObjWeb      \
+       -lNGMime        \
+       -lNGStreams -lNGExtensions -lEOControl \
+       -lXmlRpc -lDOM -lSaxObjC
+WEPrototype_WOBUNDLE_LIBS += $(WEPrototype_BUNDLE_LIBS)
+
+ifneq ($(GNUSTEP_BUILD_DIR),)
+WEPrototype_LIB_DIRS += -L$(GNUSTEP_OBJ_DIR)
+else
+WEPrototype_LIB_DIRS += -L./$(GNUSTEP_OBJ_DIR)
+endif
+
+# Apple
+
+#ifeq ($(FOUNDATION_LIB),apple)
+#libWEPrototype_PREBIND_ADDR="TODO TODO"
+#libWEPrototype_LDFLAGS += -seg1addr $(libWEPrototype_PREBIND_ADDR)
+#endif
diff --git a/sope-appserver/WEPrototype/README b/sope-appserver/WEPrototype/README
new file mode 100644 (file)
index 0000000..8a73d61
--- /dev/null
@@ -0,0 +1,174 @@
+WEPrototype
+===========
+
+This framework contains dynamic elements wrapping and connecting the
+excellent Prototype JavaScript library.
+
+http://api.rubyonrails.com/classes/ActionView/Helpers/JavaScriptHelper.html#M000394
+
+Prototype functions
+===================
+
+Prototype
+=========
+
+Prototype
+- 'Version' property
+
+Class
+  .create()
+
+Abstract
+
+[Object]
+  .extend(otherobject) - copy properties of 'otherobject' to receiver
+
+[Function]
+  .bind(object)
+  .bindAsEventListener(object)
+
+[Number]
+  .toColorPart()
+
+Try
+
+PeriodicalExecuter
+  .initialize(callback, frequency)
+  .registerCallback()
+  .onTimerEvent
+
+$(...)
+- run getElementById() for arguments
+- return array for multiple, a single for one
+
+
+Form
+====
+
+Field
+  .clear(...)        - resolve names using $() and reset value
+    eg: Field.clear("sender", "from", "to")
+  .present(...)      - check whether all elements have values
+  .focus(element)    - lookup element using $() and focus
+  .select(element)   - lookup element using $() and select
+  .activate(element) - lookup element using $() and focus+select
+
+Form
+  .serialize(form)
+  .getElements(form)
+  .disable(form)
+  .focusFirstElement(form)
+  .reset(form)
+
+Form.Element
+  .serialize(element)
+  .getValue(element)
+
+Form.Element.Serializers
+
+Abstract.TimedObserver
+  .initialize(element, frequency, callback)
+
+Form.Element.Observer : Abstract.TimedObserver
+  .getValue
+
+Form.Observer : Abstract.TimedObserver
+  .getValue
+
+
+AJAX
+====
+
+Ajax.getTransport()
+- return XMLHTTP object depending on browser
+
+Ajax.Base()
+  .setOptions(dict)
+    method       - post
+    asynchronous - true
+    parameters   - ''
+
+Ajax.Request()
+  - states: Uninitialized, Loading, Loaded, Interactive, Complete
+  .initialize(url, options)
+
+Ajax.Updater()
+  .initialize(container, url, options)
+   options:
+   - Base options
+   'insertion' => function(container, responseText) => default: .innerHTML
+
+
+Effects
+=======
+TODO
+
+
+DOM
+===
+
+document.getElementsByClasName(className)
+
+Element
+  .toggle(...)         - toggle style between "None" and ""
+  .hide(...)
+  .show(...)
+  .remove(elemName)    - removed named element (lookup using $())
+  .getHeight(elemName)
+
+Toggle
+  .display(..)         - same like Element.toggle()
+
+Abstract.Insertion(adjacency)
+  .initialize(element, content)
+
+Insertion.Before : Abstract.Insertion
+
+Insertion.Top    : Abstract.Insertion
+
+Insertion.Bottom : Abstract.Insertion
+
+Insertion.After  : Abstract.Insertion
+
+
+Compat
+======
+TODO
+
+
+RoR
+===
+<form action="/articles/comment/46" 
+      class="commentform" 
+      id="commentform" method="post" 
+      onsubmit="new Ajax.Updater('commentList', '/articles/comment/46', {onLoading:function(request){item_loading()}, onComplete:function(request){item_added()}, parameters:Form.serialize(this), insertion:Insertion.Bottom, evalScripts:true, asynchronous:true}); return false;"
+>
+
+
+        <td> <input id="comment_author" name="comment[author]" size="20" type="text" value="" /> <small><a href="javascript:Element.toggle('guest_url')">(leave url &#187;)</a></small></td>
+
+
+link_to_remote word,
+      :url => { :action => "action" },
+      404 => "alert('Not found...? Wrong URL...?')",
+      :failure => "alert('HTTP Error ' + request.status + '!')"
+
+
+link_to_remove
+  :url
+  :update
+    :update => "emails"
+    or
+    :update => { :success => "posts", :failure => "error" }
+  :position
+    - :before, :top, :bottom, :after
+ Callbacks
+  :complete
+  :loading
+  :loaded
+  :interactive
+  :failure
+  :confirm     - add confirmation dialog
+  :condition
+  :before      - before request is initiated
+  :after       - after request was initiated and before :loading
diff --git a/sope-appserver/WEPrototype/Version b/sope-appserver/WEPrototype/Version
new file mode 100644 (file)
index 0000000..ee9b5f9
--- /dev/null
@@ -0,0 +1,5 @@
+# version file
+
+SUBMINOR_VERSION:=1
+
+# v4.5.1 requires libNGObjWeb v4.5.170
diff --git a/sope-appserver/WEPrototype/WELiveLink.m b/sope-appserver/WEPrototype/WELiveLink.m
new file mode 100644 (file)
index 0000000..b1a657b
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#import <NGObjWeb/WODynamicElement.h>
+
+/*
+  WELiveLink
+
+  Inspired by the link_to_remote() RoR function.
+*/
+
+@interface WELiveLink : WODynamicElement
+{
+  WOAssociation *string;
+  WOAssociation *updateID;
+  WOAssociation *position;
+  
+  WOAssociation *actionClass;
+  WOAssociation *directActionName;
+  WOAssociation *href;
+  
+  WOAssociation *confirmText;
+  
+  WOElement *template;
+}
+
+@end
+
+#include "WEPrototypeScript.h"
+#include "common.h"
+
+@implementation WELiveLink
+
+- (id)initWithName:(NSString *)_name
+  associations:(NSDictionary *)_config
+  template:(WOElement *)_tmp
+{
+  if ((self = [super initWithName:_name associations:_config template:_tmp])) {
+    self->template = [_tmp retain];
+    
+    self->string           = WEPExtGetProperty(_config, @"string");
+    self->updateID         = WEPExtGetProperty(_config, @"updateID");
+    self->position         = WEPExtGetProperty(_config, @"position");
+    self->actionClass      = WEPExtGetProperty(_config, @"actionClass");
+    self->directActionName = WEPExtGetProperty(_config, @"directActionName");
+    self->href             = WEPExtGetProperty(_config, @"href");
+    self->confirmText      = WEPExtGetProperty(_config, @"confirmText");
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->updateID         release];
+  [self->position         release];
+  [self->actionClass      release];
+  [self->directActionName release];
+  [self->href             release];
+  [self->confirmText      release];
+  [self->string           release];
+  [self->template         release];
+  [super dealloc];
+}
+
+/* generating response */
+
+- (NSString *)linkInContext:(WOContext *)_ctx {
+  if (self->directActionName != nil) {
+    NSString *ac, *da;
+    
+    ac = [self->actionClass      stringValueInComponent:[_ctx component]];
+    da = [self->directActionName stringValueInComponent:[_ctx component]];
+
+    if ([ac length] > 0)
+      da = [[ac stringByAppendingString:@"/"] stringByAppendingString:da];
+    
+    return [_ctx directActionURLForActionNamed:da queryDictionary:nil];
+  }
+  
+  if (self->href != nil)
+    return [self->href stringValueInComponent:[_ctx component]];
+  
+  [self logWithFormat:@"ERROR: no binding for link!"];
+  return nil;
+}
+
+- (void)appendJavaScriptToResponse:(WOResponse *)_response
+  inContext:(WOContext *)_ctx
+{
+  /*
+    new Ajax.Updater('time_div', 
+                     '/hello_world/say_when', 
+                     {insertion:Insertion.After, asynchronous:true}); 
+    return false;
+  */
+  WOComponent *sComponent;
+  NSString *s;
+  BOOL     closeBracket = NO, isDOM = NO;
+  
+  sComponent = [_ctx component];
+  
+  /* check for confirm panel */
+  
+  s = [self->confirmText stringValueInComponent:sComponent];
+  if ([s length] > 0) {
+    [_response appendContentString:@"if (confirm('"];
+    [_response appendContentHTMLAttributeValue:s];
+    [_response appendContentString:@"')) { "];
+    closeBracket = YES;
+  }
+  
+  /* whether to update an element */
+  
+  s = [self->updateID stringValueInComponent:sComponent];
+  if ([s length] > 0) {
+    [_response appendContentString:@"new Ajax.Updater('"];
+    [_response appendContentHTMLAttributeValue:s];
+    [_response appendContentString:@"', '"];
+    isDOM = YES;
+  }
+  else {
+    [_response appendContentString:@"new Ajax.Request('"];
+  }
+  
+  /* Link */
+  
+  if ((s = [self linkInContext:_ctx]) != nil)
+    [_response appendContentHTMLAttributeValue:s];
+  [_response appendContentString:@"'"];
+  
+  /* parameters */
+
+  [_response appendContentString:@", {"];
+  
+  if (isDOM) {
+    s = [self->position stringValueInComponent:sComponent];
+    if ([s length] > 0) {
+      [_response appendContentString:@"insertion: Insertion."];
+      [_response appendContentString:[s capitalizedString]];
+      [_response appendContentString:@", "];
+    }
+  }
+  
+  [_response appendContentString:@"asynchronous: true }"];
+  
+  /* close function */
+  
+  [_response appendContentString:@");"];
+  
+  /* close confirm panel if */
+  
+  if (closeBracket) [_response appendContentString:@"}"];
+  
+  /* always: do not follow link target */
+  [_response appendContentString:@" return false;"];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *s;
+  
+  /* first ensure that prototype is loaded */
+  [WEPrototypeScript appendToResponse:_response inContext:_ctx];
+  
+  /* start link tag */
+  
+  [_response appendContentString:@"<a href=\"#\" onclick=\""];
+  
+  /* generate JavaScript */
+
+  [self appendJavaScriptToResponse:_response inContext:_ctx];
+  
+  /* finish link start tag */
+  
+  [_response appendContentString:@"\""];
+  
+  [self appendExtraAttributesToResponse:_response inContext:_ctx];
+  if (self->otherTagString != nil) {
+    [_response appendContentString:@" "];
+    s = [self->otherTagString stringValueInComponent:[_ctx component]];
+    [_response appendContentString:s];
+  }
+  [_response appendContentString:@">"];
+  
+  /* generate content */
+  
+  if ((s = [self->string stringValueInComponent:[_ctx component]]) != nil)
+    [_response appendContentHTMLString:s];
+  
+  [self->template appendToResponse:_response inContext:_ctx];
+  
+  /* close anker */
+  [_response appendContentString:@"</a>"];
+}
+
+@end /* WELiveLink */
diff --git a/sope-appserver/WEPrototype/WEPrototypeBundle.m b/sope-appserver/WEPrototype/WEPrototypeBundle.m
new file mode 100644 (file)
index 0000000..c6a6328
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#import <Foundation/NSObject.h>
+
+@interface WEPrototypeBundle : NSObject
+@end
+
+@implementation WEPrototypeBundle
+@end /* WEPrototypeBundle */
diff --git a/sope-appserver/WEPrototype/WEPrototypeElemBuilder.m b/sope-appserver/WEPrototype/WEPrototypeElemBuilder.m
new file mode 100644 (file)
index 0000000..7125f19
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#include <NGObjWeb/WOxElemBuilder.h>
+
+/*
+  This builder builds various elements from the WEPrototype library.
+  
+  All tags are mapped into the <var:> namespace (XMLNS_OD_BIND).
+
+  Supported tags:
+*/
+
+@interface WEPrototypeElemBuilder : WOxTagClassElemBuilder
+{
+}
+
+@end
+
+#include <SaxObjC/XMLNamespaces.h>
+#include "common.h"
+
+@implementation WEPrototypeElemBuilder
+
+- (Class)classForElement:(id<DOMElement>)_element {
+  NSString *tagName;
+  unsigned tl;
+  unichar c1;
+  
+  if (![[_element namespaceURI] isEqualToString:XMLNS_OD_BIND])
+    return Nil;
+  
+  tagName = [_element tagName];
+  if ((tl = [tagName length]) < 2)
+    return Nil;
+
+  c1 = [tagName characterAtIndex:0];
+  
+  switch (c1) {
+  case 'l':
+    if ([tagName isEqualToString:@"live-link"])
+      return NSClassFromString(@"WELiveLink");
+  default:
+    return Nil;
+  }
+}
+
+@end /* WEPrototypeElemBuilder */
diff --git a/sope-appserver/WEPrototype/WEPrototypeScript.api b/sope-appserver/WEPrototype/WEPrototypeScript.api
new file mode 100644 (file)
index 0000000..f9b25fe
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="yes"?>
+
+<wo class="WEPrototypeScript">
+</wo>
diff --git a/sope-appserver/WEPrototype/WEPrototypeScript.h b/sope-appserver/WEPrototype/WEPrototypeScript.h
new file mode 100644 (file)
index 0000000..d97443e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#ifndef __WEPrototypeScript_H__
+#define __WEPrototypeScript_H__
+
+#import <NGObjWeb/WODynamicElement.h>
+
+/*
+  WEPrototypeScript
+  
+  Generates a link to the direct action which delivers the prototype.js file.
+  
+  The method is also exposed as a class method so that other methods can
+  trigger it. It will generate its content only once (protected by a context
+  variable).
+*/
+
+@class WOContext, WOResponse;
+
+@interface WEPrototypeScript : WODynamicElement
+{
+}
+
++ (BOOL)wasDeliveredInContext:(WOContext *)_ctx;
++ (void)markDeliveredInContext:(WOContext *)_ctx;
++ (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __WEPrototypeScript_H__ */
diff --git a/sope-appserver/WEPrototype/WEPrototypeScript.jsm b/sope-appserver/WEPrototype/WEPrototypeScript.jsm
new file mode 100644 (file)
index 0000000..e752dbe
--- /dev/null
@@ -0,0 +1,695 @@
+/* automatically generated from prototype/prototype.js, do not edit ! */
+@"/*  Prototype: an object-oriented Javascript library, version 1.2.0\n"
+@" *  (c) 2005 Sam Stephenson <sam@conio.net>\n"
+@" *\n"
+@" *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff\n"
+@" *  against the source tree, available from the Prototype darcs repository. \n"
+@" *\n"
+@" *  Prototype is freely distributable under the terms of an MIT-style license.\n"
+@" *\n"
+@" *  For details, see the Prototype web site: http://prototype.conio.net/\n"
+@" *\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var Prototype = {\n"
+@"  Version: '1.2.0'\n"
+@"}\n"
+@"var Class = {\n"
+@"  create: function() {\n"
+@"    return function() { \n"
+@"      this.initialize.apply(this, arguments);\n"
+@"    }\n"
+@"  }\n"
+@"}\n"
+@"var Abstract = new Object();\n"
+@"Object.prototype.extend = function(object) {\n"
+@"  for (property in object) {\n"
+@"    this[property] = object[property];\n"
+@"  }\n"
+@"  return this;\n"
+@"}\n"
+@"Function.prototype.bind = function(object) {\n"
+@"  var method = this;\n"
+@"  return function() {\n"
+@"    method.apply(object, arguments);\n"
+@"  }\n"
+@"}\n"
+@"Function.prototype.bindAsEventListener = function(object) {\n"
+@"  var method = this;\n"
+@"  return function(event) {\n"
+@"    method.call(object, event || window.event);\n"
+@"  }\n"
+@"}\n"
+@"Number.prototype.toColorPart = function() {\n"
+@"  var digits = this.toString(16);\n"
+@"  if (this < 16) return '0' + digits;\n"
+@"  return digits;\n"
+@"}\n"
+@"var Try = {\n"
+@"  these: function() {\n"
+@"    var returnValue;\n"
+@"    \n"
+@"    for (var i = 0; i < arguments.length; i++) {\n"
+@"      var lambda = arguments[i];\n"
+@"      try {\n"
+@"        returnValue = lambda();\n"
+@"        break;\n"
+@"      } catch (e) {}\n"
+@"    }\n"
+@"    \n"
+@"    return returnValue;\n"
+@"  }\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var PeriodicalExecuter = Class.create();\n"
+@"PeriodicalExecuter.prototype = {\n"
+@"  initialize: function(callback, frequency) {\n"
+@"    this.callback = callback;\n"
+@"    this.frequency = frequency;\n"
+@"    this.currentlyExecuting = false;\n"
+@"    \n"
+@"    this.registerCallback();\n"
+@"  },\n"
+@"  \n"
+@"  registerCallback: function() {\n"
+@"    setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);\n"
+@"  },\n"
+@"  \n"
+@"  onTimerEvent: function() {\n"
+@"    if (!this.currentlyExecuting) {\n"
+@"      try { \n"
+@"        this.currentlyExecuting = true;\n"
+@"        this.callback(); \n"
+@"      } finally { \n"
+@"        this.currentlyExecuting = false;\n"
+@"      }\n"
+@"    }\n"
+@"    \n"
+@"    this.registerCallback();\n"
+@"  }\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"function $() {\n"
+@"  var elements = new Array();\n"
+@"  \n"
+@"  for (var i = 0; i < arguments.length; i++) {\n"
+@"    var element = arguments[i];\n"
+@"    if (typeof element == 'string')\n"
+@"      element = document.getElementById(element);\n"
+@"    if (arguments.length == 1) \n"
+@"      return element;\n"
+@"      \n"
+@"    elements.push(element);\n"
+@"  }\n"
+@"  \n"
+@"  return elements;\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"if (!Array.prototype.push) {\n"
+@"  Array.prototype.push = function() {\n"
+@"             var startLength = this.length;\n"
+@"             for (var i = 0; i < arguments.length; i++)\n"
+@"      this[startLength + i] = arguments[i];\n"
+@"       return this.length;\n"
+@"  }\n"
+@"}\n"
+@"if (!Function.prototype.apply) {\n"
+@"  // Based on code from http://www.youngpup.net/\n"
+@"  Function.prototype.apply = function(object, parameters) {\n"
+@"    var parameterStrings = new Array();\n"
+@"    if (!object)     object = window;\n"
+@"    if (!parameters) parameters = new Array();\n"
+@"    \n"
+@"    for (var i = 0; i < parameters.length; i++)\n"
+@"      parameterStrings[i] = 'x[' + i + ']';\n"
+@"    \n"
+@"    object.__apply__ = this;\n"
+@"    var result = eval('obj.__apply__(' + \n"
+@"      parameterStrings[i].join(', ') + ')');\n"
+@"    object.__apply__ = null;\n"
+@"    \n"
+@"    return result;\n"
+@"  }\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var Ajax = {\n"
+@"  getTransport: function() {\n"
+@"    return Try.these(\n"
+@"      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\n"
+@"      function() {return new ActiveXObject('Microsoft.XMLHTTP')},\n"
+@"      function() {return new XMLHttpRequest()}\n"
+@"    ) || false;\n"
+@"  },\n"
+@"  \n"
+@"  emptyFunction: function() {}\n"
+@"}\n"
+@"Ajax.Base = function() {};\n"
+@"Ajax.Base.prototype = {\n"
+@"  setOptions: function(options) {\n"
+@"    this.options = {\n"
+@"      method:       'post',\n"
+@"      asynchronous: true,\n"
+@"      parameters:   ''\n"
+@"    }.extend(options || {});\n"
+@"  }\n"
+@"}\n"
+@"Ajax.Request = Class.create();\n"
+@"Ajax.Request.Events = \n"
+@"  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\n"
+@"Ajax.Request.prototype = (new Ajax.Base()).extend({\n"
+@"  initialize: function(url, options) {\n"
+@"    this.transport = Ajax.getTransport();\n"
+@"    this.setOptions(options);\n"
+@"  \n"
+@"    try {\n"
+@"      if (this.options.method == 'get')\n"
+@"        url += '?' + this.options.parameters + '&_=';\n"
+@"    \n"
+@"      this.transport.open(this.options.method, url, true);\n"
+@"      \n"
+@"      if (this.options.asynchronous) {\n"
+@"        this.transport.onreadystatechange = this.onStateChange.bind(this);\n"
+@"        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);\n"
+@"      }\n"
+@"              \n"
+@"      this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n"
+@"      this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);\n"
+@"      if (this.options.method == 'post') {\n"
+@"        this.transport.setRequestHeader('Connection', 'close');\n"
+@"        this.transport.setRequestHeader('Content-type',\n"
+@"          'application/x-www-form-urlencoded');\n"
+@"      }\n"
+@"      \n"
+@"      this.transport.send(this.options.method == 'post' ? \n"
+@"        this.options.parameters + '&_=' : null);\n"
+@"                      \n"
+@"    } catch (e) {\n"
+@"    }    \n"
+@"  },\n"
+@"      \n"
+@"  onStateChange: function() {\n"
+@"    var readyState = this.transport.readyState;\n"
+@"    if (readyState != 1)\n"
+@"      this.respondToReadyState(this.transport.readyState);\n"
+@"  },\n"
+@"  \n"
+@"  respondToReadyState: function(readyState) {\n"
+@"    var event = Ajax.Request.Events[readyState];\n"
+@"    (this.options['on' + event] || Ajax.emptyFunction)(this.transport);\n"
+@"  }\n"
+@"});\n"
+@"Ajax.Updater = Class.create();\n"
+@"Ajax.Updater.prototype = (new Ajax.Base()).extend({\n"
+@"  initialize: function(container, url, options) {\n"
+@"    this.container = $(container);\n"
+@"    this.setOptions(options);\n"
+@"  \n"
+@"    if (this.options.asynchronous) {\n"
+@"      this.onComplete = this.options.onComplete;\n"
+@"      this.options.onComplete = this.updateContent.bind(this);\n"
+@"    }\n"
+@"    \n"
+@"    this.request = new Ajax.Request(url, this.options);\n"
+@"    \n"
+@"    if (!this.options.asynchronous)\n"
+@"      this.updateContent();\n"
+@"  },\n"
+@"  \n"
+@"  updateContent: function() {\n"
+@"    if (this.options.insertion) {\n"
+@"      new this.options.insertion(this.container,\n"
+@"        this.request.transport.responseText);\n"
+@"    } else {\n"
+@"      this.container.innerHTML = this.request.transport.responseText;\n"
+@"    }\n"
+@"    if (this.onComplete) {\n"
+@"      setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);\n"
+@"    }\n"
+@"  }\n"
+@"});\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var Field = {\n"
+@"  clear: function() {\n"
+@"    for (var i = 0; i < arguments.length; i++)\n"
+@"      $(arguments[i]).value = '';\n"
+@"  },\n"
+@"  focus: function(element) {\n"
+@"    $(element).focus();\n"
+@"  },\n"
+@"  \n"
+@"  present: function() {\n"
+@"    for (var i = 0; i < arguments.length; i++)\n"
+@"      if ($(arguments[i]).value == '') return false;\n"
+@"    return true;\n"
+@"  },\n"
+@"  \n"
+@"  select: function(element) {\n"
+@"    $(element).select();\n"
+@"  },\n"
+@"   \n"
+@"  activate: function(element) {\n"
+@"    $(element).focus();\n"
+@"    $(element).select();\n"
+@"  }\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var Form = {\n"
+@"  serialize: function(form) {\n"
+@"    var elements = Form.getElements($(form));\n"
+@"    var queryComponents = new Array();\n"
+@"    \n"
+@"    for (var i = 0; i < elements.length; i++) {\n"
+@"      var queryComponent = Form.Element.serialize(elements[i]);\n"
+@"      if (queryComponent)\n"
+@"        queryComponents.push(queryComponent);\n"
+@"    }\n"
+@"    \n"
+@"    return queryComponents.join('&');\n"
+@"  },\n"
+@"  \n"
+@"  getElements: function(form) {\n"
+@"    form = $(form);\n"
+@"    var elements = new Array();\n"
+@"    for (tagName in Form.Element.Serializers) {\n"
+@"      var tagElements = form.getElementsByTagName(tagName);\n"
+@"      for (var j = 0; j < tagElements.length; j++)\n"
+@"        elements.push(tagElements[j]);\n"
+@"    }\n"
+@"    return elements;\n"
+@"  },\n"
+@"  \n"
+@"  disable: function(form) {\n"
+@"    var elements = Form.getElements(form);\n"
+@"    for (var i = 0; i < elements.length; i++) {\n"
+@"      var element = elements[i];\n"
+@"      element.blur();\n"
+@"      element.disable = 'true';\n"
+@"    }\n"
+@"  },\n"
+@"  focusFirstElement: function(form) {\n"
+@"    form = $(form);\n"
+@"    var elements = Form.getElements(form);\n"
+@"    for (var i = 0; i < elements.length; i++) {\n"
+@"      var element = elements[i];\n"
+@"      if (element.type != 'hidden' && !element.disabled) {\n"
+@"        Field.activate(element);\n"
+@"        break;\n"
+@"      }\n"
+@"    }\n"
+@"  },\n"
+@"  reset: function(form) {\n"
+@"    $(form).reset();\n"
+@"  }\n"
+@"}\n"
+@"Form.Element = {\n"
+@"  serialize: function(element) {\n"
+@"    element = $(element);\n"
+@"    var method = element.tagName.toLowerCase();\n"
+@"    var parameter = Form.Element.Serializers[method](element);\n"
+@"    \n"
+@"    if (parameter)\n"
+@"      return encodeURIComponent(parameter[0]) + '=' + \n"
+@"        encodeURIComponent(parameter[1]);                   \n"
+@"  },\n"
+@"  \n"
+@"  getValue: function(element) {\n"
+@"    element = $(element);\n"
+@"    var method = element.tagName.toLowerCase();\n"
+@"    var parameter = Form.Element.Serializers[method](element);\n"
+@"    \n"
+@"    if (parameter) \n"
+@"      return parameter[1];\n"
+@"  }\n"
+@"}\n"
+@"Form.Element.Serializers = {\n"
+@"  input: function(element) {\n"
+@"    switch (element.type.toLowerCase()) {\n"
+@"      case 'hidden':\n"
+@"      case 'password':\n"
+@"      case 'text':\n"
+@"        return Form.Element.Serializers.textarea(element);\n"
+@"      case 'checkbox':  \n"
+@"      case 'radio':\n"
+@"        return Form.Element.Serializers.inputSelector(element);\n"
+@"    }\n"
+@"    return false;\n"
+@"  },\n"
+@"  inputSelector: function(element) {\n"
+@"    if (element.checked)\n"
+@"      return [element.name, element.value];\n"
+@"  },\n"
+@"  textarea: function(element) {\n"
+@"    return [element.name, element.value];\n"
+@"  },\n"
+@"  select: function(element) {\n"
+@"    var index = element.selectedIndex;\n"
+@"    var value = element.options[index].value || element.options[index].text;\n"
+@"    return [element.name, (index >= 0) ? value : ''];\n"
+@"  }\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var $F = Form.Element.getValue;\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"Abstract.TimedObserver = function() {}\n"
+@"Abstract.TimedObserver.prototype = {\n"
+@"  initialize: function(element, frequency, callback) {\n"
+@"    this.frequency = frequency;\n"
+@"    this.element   = $(element);\n"
+@"    this.callback  = callback;\n"
+@"    \n"
+@"    this.lastValue = this.getValue();\n"
+@"    this.registerCallback();\n"
+@"  },\n"
+@"  \n"
+@"  registerCallback: function() {\n"
+@"    setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);\n"
+@"  },\n"
+@"  \n"
+@"  onTimerEvent: function() {\n"
+@"    var value = this.getValue();\n"
+@"    if (this.lastValue != value) {\n"
+@"      this.callback(this.element, value);\n"
+@"      this.lastValue = value;\n"
+@"    }\n"
+@"    \n"
+@"    this.registerCallback();\n"
+@"  }\n"
+@"}\n"
+@"Form.Element.Observer = Class.create();\n"
+@"Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({\n"
+@"  getValue: function() {\n"
+@"    return Form.Element.getValue(this.element);\n"
+@"  }\n"
+@"});\n"
+@"Form.Observer = Class.create();\n"
+@"Form.Observer.prototype = (new Abstract.TimedObserver()).extend({\n"
+@"  getValue: function() {\n"
+@"    return Form.serialize(this.element);\n"
+@"  }\n"
+@"});\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"document.getElementsByClassName = function(className) {\n"
+@"  var children = document.getElementsByTagName('*') || document.all;\n"
+@"  var elements = new Array();\n"
+@"  \n"
+@"  for (var i = 0; i < children.length; i++) {\n"
+@"    var child = children[i];\n"
+@"    var classNames = child.className.split(' ');\n"
+@"    for (var j = 0; j < classNames.length; j++) {\n"
+@"      if (classNames[j] == className) {\n"
+@"        elements.push(child);\n"
+@"        break;\n"
+@"      }\n"
+@"    }\n"
+@"  }\n"
+@"  \n"
+@"  return elements;\n"
+@"}\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var Element = {\n"
+@"  toggle: function() {\n"
+@"    for (var i = 0; i < arguments.length; i++) {\n"
+@"      var element = $(arguments[i]);\n"
+@"      element.style.display = \n"
+@"        (element.style.display == 'none' ? '' : 'none');\n"
+@"    }\n"
+@"  },\n"
+@"  hide: function() {\n"
+@"    for (var i = 0; i < arguments.length; i++) {\n"
+@"      var element = $(arguments[i]);\n"
+@"      element.style.display = 'none';\n"
+@"    }\n"
+@"  },\n"
+@"  show: function() {\n"
+@"    for (var i = 0; i < arguments.length; i++) {\n"
+@"      var element = $(arguments[i]);\n"
+@"      element.style.display = '';\n"
+@"    }\n"
+@"  },\n"
+@"  remove: function(element) {\n"
+@"    element = $(element);\n"
+@"    element.parentNode.removeChild(element);\n"
+@"  },\n"
+@"   \n"
+@"  getHeight: function(element) {\n"
+@"    element = $(element);\n"
+@"    return element.offsetHeight; \n"
+@"  }\n"
+@"}\n"
+@"var Toggle = new Object();\n"
+@"Toggle.display = Element.toggle;\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"Abstract.Insertion = function(adjacency) {\n"
+@"  this.adjacency = adjacency;\n"
+@"}\n"
+@"Abstract.Insertion.prototype = {\n"
+@"  initialize: function(element, content) {\n"
+@"    this.element = $(element);\n"
+@"    this.content = content;\n"
+@"    \n"
+@"    if (this.adjacency && this.element.insertAdjacentHTML) {\n"
+@"      this.element.insertAdjacentHTML(this.adjacency, this.content);\n"
+@"    } else {\n"
+@"      this.range = this.element.ownerDocument.createRange();\n"
+@"      if (this.initializeRange) this.initializeRange();\n"
+@"      this.fragment = this.range.createContextualFragment(this.content);\n"
+@"      this.insertContent();\n"
+@"    }\n"
+@"  }\n"
+@"}\n"
+@"var Insertion = new Object();\n"
+@"Insertion.Before = Class.create();\n"
+@"Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({\n"
+@"  initializeRange: function() {\n"
+@"    this.range.setStartBefore(this.element);\n"
+@"  },\n"
+@"  \n"
+@"  insertContent: function() {\n"
+@"    this.element.parentNode.insertBefore(this.fragment, this.element);\n"
+@"  }\n"
+@"});\n"
+@"Insertion.Top = Class.create();\n"
+@"Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({\n"
+@"  initializeRange: function() {\n"
+@"    this.range.selectNodeContents(this.element);\n"
+@"    this.range.collapse(true);\n"
+@"  },\n"
+@"  \n"
+@"  insertContent: function() {  \n"
+@"    this.element.insertBefore(this.fragment, this.element.firstChild);\n"
+@"  }\n"
+@"});\n"
+@"Insertion.Bottom = Class.create();\n"
+@"Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({\n"
+@"  initializeRange: function() {\n"
+@"    this.range.selectNodeContents(this.element);\n"
+@"    this.range.collapse(this.element);\n"
+@"  },\n"
+@"  \n"
+@"  insertContent: function() {\n"
+@"    this.element.appendChild(this.fragment);\n"
+@"  }\n"
+@"});\n"
+@"Insertion.After = Class.create();\n"
+@"Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({\n"
+@"  initializeRange: function() {\n"
+@"    this.range.setStartAfter(this.element);\n"
+@"  },\n"
+@"  \n"
+@"  insertContent: function() {\n"
+@"    this.element.parentNode.insertBefore(this.fragment, \n"
+@"      this.element.nextSibling);\n"
+@"  }\n"
+@"});\n"
+@"/*--------------------------------------------------------------------------*/\n"
+@"var Effect = new Object();\n"
+@"Effect.Highlight = Class.create();\n"
+@"Effect.Highlight.prototype = {\n"
+@"  initialize: function(element) {\n"
+@"    this.element = $(element);\n"
+@"    this.start  = 153;\n"
+@"    this.finish = 255;\n"
+@"    this.current = this.start;\n"
+@"    this.fade();\n"
+@"  },\n"
+@"  \n"
+@"  fade: function() {\n"
+@"    if (this.isFinished()) return;\n"
+@"    if (this.timer) clearTimeout(this.timer);\n"
+@"    this.highlight(this.element, this.current);\n"
+@"    this.current += 17;\n"
+@"    this.timer = setTimeout(this.fade.bind(this), 250);\n"
+@"  },\n"
+@"  \n"
+@"  isFinished: function() {\n"
+@"    return this.current > this.finish;\n"
+@"  },\n"
+@"  \n"
+@"  highlight: function(element, current) {\n"
+@"    element.style.backgroundColor = \"#ffff\" + current.toColorPart();\n"
+@"  }\n"
+@"}\n"
+@"Effect.Fade = Class.create();\n"
+@"Effect.Fade.prototype = {\n"
+@"  initialize: function(element) {\n"
+@"    this.element = $(element);\n"
+@"    this.start  = 100;\n"
+@"    this.finish = 0;\n"
+@"    this.current = this.start;\n"
+@"    this.fade();\n"
+@"  },\n"
+@"  \n"
+@"  fade: function() {\n"
+@"    if (this.isFinished()) { this.element.style.display = 'none'; return; }\n"
+@"    if (this.timer) clearTimeout(this.timer);\n"
+@"    this.setOpacity(this.element, this.current);\n"
+@"    this.current -= 10;\n"
+@"    this.timer = setTimeout(this.fade.bind(this), 50);\n"
+@"  },\n"
+@"  \n"
+@"  isFinished: function() {\n"
+@"    return this.current <= this.finish;\n"
+@"  },\n"
+@"  \n"
+@"  setOpacity: function(element, opacity) {\n"
+@"    opacity = (opacity == 100) ? 99.999 : opacity;\n"
+@"    element.style.filter = \"alpha(opacity:\"+opacity+\")\";\n"
+@"    element.style.opacity = opacity/100 /*//*/;\n"
+@"  }\n"
+@"}\n"
+@"Effect.Scale = Class.create();\n"
+@"Effect.Scale.prototype = {\n"
+@"  initialize: function(element, percent) {\n"
+@"    this.element = $(element);\n"
+@"    this.startScale    = 1.0;\n"
+@"    this.startHeight   = this.element.offsetHeight;\n"
+@"    this.startWidth    = this.element.offsetWidth;\n"
+@"    this.currentHeight = this.startHeight;\n"
+@"    this.currentWidth  = this.startWidth;\n"
+@"    this.finishScale   = (percent/100) /*//*/;\n"
+@"    if (this.element.style.fontSize==\"\") this.sizeEm = 1.0;\n"
+@"    if (this.element.style.fontSize.indexOf(\"em\")>0)\n"
+@"       this.sizeEm      = parseFloat(this.element.style.fontSize);\n"
+@"    if(this.element.effect_scale) {\n"
+@"      clearTimeout(this.element.effect_scale.timer);\n"
+@"      this.startScale  = this.element.effect_scale.currentScale;\n"
+@"      this.startHeight = this.element.effect_scale.startHeight;\n"
+@"      this.startWidth  = this.element.effect_scale.startWidth;\n"
+@"      if(this.element.effect_scale.sizeEm) \n"
+@"        this.sizeEm    = this.element.effect_scale.sizeEm;      \n"
+@"    }\n"
+@"    this.element.effect_scale = this;\n"
+@"    this.currentScale  = this.startScale;\n"
+@"    this.factor        = this.finishScale - this.startScale;\n"
+@"    this.options       = arguments[2] || {}; \n"
+@"    this.scale();\n"
+@"  },\n"
+@"  \n"
+@"  scale: function() {\n"
+@"    if (this.isFinished()) { \n"
+@"      this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale);\n"
+@"      if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + \"em\";\n"
+@"      if(this.options.complete) this.options.complete(this);\n"
+@"      return; \n"
+@"    }\n"
+@"    if (this.timer) clearTimeout(this.timer);\n"
+@"    if (this.options.step) this.options.step(this);\n"
+@"    this.setDimensions(this.element, this.currentWidth, this.currentHeight);\n"
+@"    if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + \"em\";\n"
+@"    this.currentScale += (this.factor/10) /*//*/;\n"
+@"    this.currentWidth = this.startWidth * this.currentScale;\n"
+@"    this.currentHeight = this.startHeight * this.currentScale;\n"
+@"    this.timer = setTimeout(this.scale.bind(this), 50);\n"
+@"  },\n"
+@"  \n"
+@"  isFinished: function() {\n"
+@"    return (this.factor < 0) ? \n"
+@"      this.currentScale <= this.finishScale : this.currentScale >= this.finishScale;\n"
+@"  },\n"
+@"  \n"
+@"  setDimensions: function(element, width, height) {\n"
+@"    element.style.width = width + 'px';\n"
+@"    element.style.height = height + 'px';\n"
+@"  }\n"
+@"}\n"
+@"Effect.Squish = Class.create();\n"
+@"Effect.Squish.prototype = {\n"
+@"  initialize: function(element) {\n"
+@"    this.element = $(element);\n"
+@"    new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } );\n"
+@"  },\n"
+@"  hide: function() {\n"
+@"    this.element.style.display = 'none';\n"
+@"  } \n"
+@"}\n"
+@"Effect.Puff = Class.create();\n"
+@"Effect.Puff.prototype = {\n"
+@"  initialize: function(element) {\n"
+@"    this.element = $(element);\n"
+@"    this.opacity = 100;\n"
+@"    this.startTop  = this.element.top || this.element.offsetTop;\n"
+@"    this.startLeft = this.element.left || this.element.offsetLeft;\n"
+@"    new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } );\n"
+@"  },\n"
+@"  fade: function(effect) {\n"
+@"    topd    = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2;\n"
+@"    leftd   = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2;\n"
+@"    this.element.style.position='absolute';\n"
+@"    this.element.style.top = this.startTop-topd + \"px\";\n"
+@"    this.element.style.left = this.startLeft-leftd + \"px\";\n"
+@"    this.opacity -= 10;\n"
+@"    this.setOpacity(this.element, this.opacity); \n"
+@"    if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari\n"
+@"  },\n"
+@"  hide: function() {\n"
+@"    this.element.style.display = 'none';\n"
+@"  },\n"
+@"  setOpacity: function(element, opacity) {\n"
+@"    opacity = (opacity == 100) ? 99.999 : opacity;\n"
+@"    element.style.filter = \"alpha(opacity:\"+opacity+\")\";\n"
+@"    element.style.opacity = opacity/100 /*//*/;\n"
+@"  }\n"
+@"}\n"
+@"Effect.Appear = Class.create();\n"
+@"Effect.Appear.prototype = {\n"
+@"  initialize: function(element) {\n"
+@"    this.element = $(element);\n"
+@"    this.start  = 0;\n"
+@"    this.finish = 100;\n"
+@"    this.current = this.start;\n"
+@"    this.fade();\n"
+@"  },\n"
+@"  \n"
+@"  fade: function() {\n"
+@"    if (this.isFinished()) return;\n"
+@"    if (this.timer) clearTimeout(this.timer);\n"
+@"    this.setOpacity(this.element, this.current);\n"
+@"    this.current += 10;\n"
+@"    this.timer = setTimeout(this.fade.bind(this), 50);\n"
+@"  },\n"
+@"  \n"
+@"  isFinished: function() {\n"
+@"    return this.current > this.finish;\n"
+@"  },\n"
+@"  \n"
+@"  setOpacity: function(element, opacity) {\n"
+@"    opacity = (opacity == 100) ? 99.999 : opacity;\n"
+@"    element.style.filter = \"alpha(opacity:\"+opacity+\")\";\n"
+@"    element.style.opacity = opacity/100 /*//*/;\n"
+@"    element.style.display = '';\n"
+@"  }\n"
+@"}\n"
+@"Effect.ContentZoom = Class.create();\n"
+@"Effect.ContentZoom.prototype = {\n"
+@"  initialize: function(element, percent) {\n"
+@"    this.element = $(element);\n"
+@"    if (this.element.style.fontSize==\"\") this.sizeEm = 1.0;\n"
+@"    if (this.element.style.fontSize.indexOf(\"em\")>0)\n"
+@"       this.sizeEm = parseFloat(this.element.style.fontSize);\n"
+@"    if(this.element.effect_contentzoom) {\n"
+@"      this.sizeEm = this.element.effect_contentzoom.sizeEm;\n"
+@"    }\n"
+@"    this.element.effect_contentzoom = this;\n"
+@"    this.element.style.fontSize = this.sizeEm*(percent/100) + \"em\" /*//*/;\n"
+@"    if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; };\n"
+@"  }\n"
+@"}\n"
diff --git a/sope-appserver/WEPrototype/WEPrototypeScript.m b/sope-appserver/WEPrototype/WEPrototypeScript.m
new file mode 100644 (file)
index 0000000..c9ec1d4
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#include "WEPrototypeScript.h"
+#include "common.h"
+
+@implementation WEPrototypeScript
+
+static NSString *WEPrototypeScriptKey = @"WEPrototypeScriptKey";
+
+/* generating response */
+
++ (BOOL)wasDeliveredInContext:(WOContext *)_ctx {
+  return [[_ctx objectForKey:WEPrototypeScriptKey] boolValue];
+}
+
++ (void)markDeliveredInContext:(WOContext *)_ctx {
+  [_ctx setObject:@"YES" forKey:WEPrototypeScriptKey];
+}
+
++ (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  NSString *url;
+
+  if ([self wasDeliveredInContext:_ctx])
+    return;
+  
+  url = [_ctx directActionURLForActionNamed:@"WEPrototypeScriptAction/default"
+             queryDictionary:nil];
+  
+  [_response appendContentString:@"<script type=\"text/javascript\" src=\""];
+  [_response appendContentHTMLAttributeValue:url];
+  [_response appendContentString:@"\"> </script>"];
+  
+  [self markDeliveredInContext:_ctx];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+  [[self class] appendToResponse:_response inContext:_ctx];
+}
+
+@end /* WEPrototypeScript */
diff --git a/sope-appserver/WEPrototype/WEPrototypeScriptAction.m b/sope-appserver/WEPrototype/WEPrototypeScriptAction.m
new file mode 100644 (file)
index 0000000..38ad677
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#import <NGObjWeb/WODirectAction.h>
+
+@interface WEPrototypeScriptAction : WODirectAction
+@end
+
+#include "common.h"
+
+@implementation WEPrototypeScriptAction
+
+static NSString *etag = nil;
+static NSString *script =
+#include "WEPrototypeScript.jsm"
+      ;
+
++ (void)initialize {
+  if (etag == nil) {
+    etag = [[NSString alloc] initWithFormat:@"\"sope/%i.%i-wep/%03i\"",
+                            SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION,
+                            WEP_SUBMINOR_VERSION];
+  }
+}
+
+- (id)defaultAction {
+  WOResponse *r;
+  NSString *s;
+  
+  r = [[self context] response];
+  [r setHeader:@"application/x-javascript" forKey:@"content-type"];
+  [r setHeader:etag                        forKey:@"etag"];
+  
+  /* check preconditions */
+  
+  s = [[[self context] request] headerForKey:@"if-none-match"];
+  if ([s rangeOfString:etag].length > 0) {
+    /* client already has the proper entity */
+    [r setStatus:304 /* Not Modified */];
+    return r;
+  }
+  
+  /* send script */
+  
+  [r setStatus:200 /* OK */];
+  [r appendContentString:script];
+  return r;
+}
+
+@end /* WEPrototypeScriptAction */
diff --git a/sope-appserver/WEPrototype/bundle-info.plist b/sope-appserver/WEPrototype/bundle-info.plist
new file mode 100644 (file)
index 0000000..e1fa8f4
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  requires = {
+    bundleManagerVersion = 1;
+    
+    classes = (
+      { name = NSObject; }
+    );
+  };
+
+  provides = {
+    WOxElemBuilder = (
+      { name = "WEPrototypeElemBuilder"; },
+    );
+    
+    WODynamicElements = (
+      { name = "WELiveLink"; },
+    );
+    
+    classes = (
+      { name = "WEPrototypeElemBuilder"; },
+    );
+  };
+}
diff --git a/sope-appserver/WEPrototype/common.h b/sope-appserver/WEPrototype/common.h
new file mode 100644 (file)
index 0000000..b2ad6cf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2005 Helge Hess
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#ifndef __WEPrototype_common_H__
+#define __WEPrototype_common_H__
+
+#import <Foundation/Foundation.h>
+
+#include <NGExtensions/NGExtensions.h>
+#include <NGObjWeb/NGObjWeb.h>
+
+#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY
+#  include <NGExtensions/NGObjectMacros.h>
+#endif
+
+static inline id WEPExtGetProperty(NSDictionary *_set, NSString *_name) {
+  id propValue = [_set objectForKey:_name];
+
+  if (propValue != nil) {
+    propValue = [propValue retain];
+    [(NSMutableDictionary *)_set removeObjectForKey:_name];
+  }
+  return propValue;
+}
+
+#endif /* __WEPrototype_common_H__ */
diff --git a/sope-appserver/WEPrototype/fhs.make b/sope-appserver/WEPrototype/fhs.make
new file mode 100644 (file)
index 0000000..c5ed213
--- /dev/null
@@ -0,0 +1,55 @@
+# postprocessing
+
+# FHS support (this is a hack and is going to be done by gstep-make!)
+
+ifneq ($(FHS_INSTALL_ROOT),)
+
+FHS_INCLUDE_DIR=$(FHS_INSTALL_ROOT)/include/
+FHS_LIB_DIR=$(FHS_INSTALL_ROOT)/lib/
+FHS_BIN_DIR=$(FHS_INSTALL_ROOT)/bin/
+FHS_WOx_DIR=$(FHS_LIB_DIR)sope-$(MAJOR_VERSION).$(MINOR_VERSION)/wox-builders/
+FHS_MAN_DIR=$(FHS_INSTALL_ROOT)/man
+
+NONFHS_LIBDIR="$(GNUSTEP_LIBRARIES)/$(GNUSTEP_TARGET_LDIR)/"
+NONFHS_LIBNAME="$(LIBRARY_NAME)$(LIBRARY_NAME_SUFFIX)$(SHARED_LIBEXT)"
+
+
+fhs-header-dirs ::
+       $(MKDIRS) $(FHS_INCLUDE_DIR)$(libWEPrototype_HEADER_FILES_INSTALL_DIR)
+
+fhs-wox-dirs ::
+       $(MKDIRS) $(FHS_WOx_DIR)
+
+fhs-man-dirs ::
+       $(MKDIRS) $(FHS_MAN_DIR)
+
+move-headers-to-fhs :: fhs-header-dirs
+       @echo "moving headers to $(FHS_INCLUDE_DIR) .."
+       mv $(GNUSTEP_HEADERS)$(libWEPrototype_HEADER_FILES_INSTALL_DIR)/*.h \
+         $(FHS_INCLUDE_DIR)$(libWEPrototype_HEADER_FILES_INSTALL_DIR)/
+
+move-libs-to-fhs :: 
+       @echo "moving libs to $(FHS_LIB_DIR) .."
+       mv $(NONFHS_LIBDIR)/$(NONFHS_LIBNAME)* $(FHS_LIB_DIR)/
+
+move-bundles-to-fhs :: fhs-wox-dirs
+       @echo "moving bundles $(BUNDLE_INSTALL_DIR) to $(FHS_WOx_DIR) .."
+       for i in $(BUNDLE_NAME); do \
+          j="$(FHS_WOx_DIR)/$${i}$(BUNDLE_EXTENSION)"; \
+         if test -d $$j; then rm -r $$j; fi; \
+         mv "$(BUNDLE_INSTALL_DIR)/$${i}$(BUNDLE_EXTENSION)" $$j; \
+       done
+
+move-to-fhs :: move-headers-to-fhs move-libs-to-fhs move-bundles-to-fhs
+
+install-fhs-manpages :: fhs-man-dirs
+       @echo "installing manpages in $(FHS_MAN_DIR) ..."
+       for i in $(FHS_MANPAGES); do \
+         msection="$(FHS_MAN_DIR)/man`echo -n $$i | tail -c 1`"; \
+         $(MKDIRS) $$msection; \
+         $(INSTALL_DATA) $$i $$msection; \
+       done
+
+after-install :: install-fhs-manpages move-to-fhs
+
+endif
diff --git a/sope-appserver/WEPrototype/js2m.sh b/sope-appserver/WEPrototype/js2m.sh
new file mode 100755 (executable)
index 0000000..c1b7737
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+jsfile=$1
+mfile=$2
+
+if [ "x${jsfile}" = "x" ]; then
+  echo "usage: $0 <jsfile> <mfile>"
+  exit 1;
+fi
+if [ "x${mfile}" = "x" ]; then
+  echo "usage: $0 <jsfile> <mfile>"
+  exit 1;
+fi
+
+if [ ! -f $jsfile ]; then
+  echo "$0: file '${jsfile}' can't be found !"
+  exit 2;
+fi
+
+echo "transforming ${jsfile} to ${mfile} .."
+
+IFS="
+"
+replaceto='\\"'
+
+SEDCMD=sed
+ECHOCMD=echo
+
+$ECHOCMD >$mfile "/* automatically generated from ${jsfile}, do not edit ! */"
+for i in `${SEDCMD} "s|\\"|$replaceto|g" <${jsfile}`; do
+  $ECHOCMD -n >>$mfile "@\""
+  $ECHOCMD -n >>$mfile "${i}"
+  $ECHOCMD >>$mfile "\\n\""
+done
diff --git a/sope-appserver/WEPrototype/prototype/AUTHORS b/sope-appserver/WEPrototype/prototype/AUTHORS
new file mode 100644 (file)
index 0000000..7745617
--- /dev/null
@@ -0,0 +1,6 @@
+Creator and maintainer
+* Sam Stephenson -- http://conio.net/
+---
+* Thomas Fuchs -- http://mir.aculo.us/
+* David Heinemeier Hansson -- http://www.loudthinking.com/
+* Matthew McCray -- http://www.mattmccray.com/
diff --git a/sope-appserver/WEPrototype/prototype/LICENSE b/sope-appserver/WEPrototype/prototype/LICENSE
new file mode 100644 (file)
index 0000000..45ac250
--- /dev/null
@@ -0,0 +1,16 @@
+Copyright (c) 2005 Sam Stephenson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/sope-appserver/WEPrototype/prototype/README b/sope-appserver/WEPrototype/prototype/README
new file mode 100644 (file)
index 0000000..c09679a
--- /dev/null
@@ -0,0 +1,52 @@
+= Prototype
+==== An object-oriented Javascript library
+
+(c) 2005 Sam Stephenson (mailto:sam@conio.net)
+
+Prototype is a Javascript library that aims to ease development of dynamic web applications.  Its development is driven heavily by the Ruby on Rails framework, but it can be used in any environment.
+
+=== Targeted platforms
+
+Prototype currently targets the following platforms:
+
+* Microsoft Internet Explorer for Windows, version 6.0 and higher
+* Mozilla Firefox 1.0/Mozilla 1.7 and higher
+* Apple Safari 1.2 and higher
+
+== Using Prototype
+
+To use Prototype in your application, download the latest release from the Prototype web site (http://prototype.conio.net/) and copy <tt>dist/prototype.js</tt> to a suitable location. Then include it in your HTML like so:
+
+  <script type="text/javascript" src="/path/to/prototype.js"></script>
+
+=== Building Prototype from source
+
+<tt>prototype.js</tt> is a composite file generated from many source files in the <tt>src/</tt> directory. To build Prototype, you'll need:
+
+* a copy of the Prototype source tree, either from a distribution tarball or
+  from the darcs repository (see below)
+* Ruby 1.8.2 or higher (http://www.ruby-lang.org/)
+* Rake -- Ruby Make (http://rake.rubyforge.org/)
+* RDoc, if your Ruby distribution does not include it
+* darcs 1.0.1 or higher (http://abridgegame.org/darcs/; static binaries 
+  available at http://www.scannedinavian.org/DarcsWiki/CategoryBinaries)
+
+From the root Prototype directory,
+
+* <tt>rake generate_dist_prototype</tt> will run <tt>script/make-dist.rb</tt>,
+  which preprocesses the Prototype source and generates the single-file
+  <tt>dist/prototype.js</tt>.
+* <tt>rake generate_dist_tarball</tt> will run the aforementioned task and 
+  create a distribution tarball of your current darcs repository with 
+  <tt>darcs dist</tt>. (<tt>rake dist</tt>, or just <tt>rake</tt>, can be used
+  for this, too.)
+
+== Contributing to Prototype
+
+You'll need the tools mentioned above. Modify the files in <tt>src/</tt>, add tests in <tt>test/</tt> if possible, generate a new dist file, and record the changes with <tt>darcs record -al</tt>. Then email patches to mailto:sam@conio.net using <tt>darcs send</tt>.
+
+== Documentation
+
+Prototype is embarrassingly lacking in documentation. (The source code should be fairly easy to comprehend; I'm committed to using a clean style with meaningful identifiers. But I know that only goes so far.)
+
+Much of the problem is that there is no easy way to document it from within the source code itself. I've tried JSDoc[http://jsdoc.sf.net/] and a Perl script included with JsUnit[http://www.edwardh.com/jsunit/]; neither groks Prototype's hash-style class definitions or inheritance scheme. Making them work would require major changes, and I don't have the time for that right now.
diff --git a/sope-appserver/WEPrototype/prototype/prototype.js b/sope-appserver/WEPrototype/prototype/prototype.js
new file mode 100644 (file)
index 0000000..dd5c9b0
--- /dev/null
@@ -0,0 +1,764 @@
+/*  Prototype: an object-oriented Javascript library, version 1.2.0
+ *  (c) 2005 Sam Stephenson <sam@conio.net>
+ *
+ *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
+ *  against the source tree, available from the Prototype darcs repository. 
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *
+ *  For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+  Version: '1.2.0'
+}
+
+var Class = {
+  create: function() {
+    return function() { 
+      this.initialize.apply(this, arguments);
+    }
+  }
+}
+
+var Abstract = new Object();
+
+Object.prototype.extend = function(object) {
+  for (property in object) {
+    this[property] = object[property];
+  }
+  return this;
+}
+
+Function.prototype.bind = function(object) {
+  var method = this;
+  return function() {
+    method.apply(object, arguments);
+  }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+  var method = this;
+  return function(event) {
+    method.call(object, event || window.event);
+  }
+}
+
+Number.prototype.toColorPart = function() {
+  var digits = this.toString(16);
+  if (this < 16) return '0' + digits;
+  return digits;
+}
+
+var Try = {
+  these: function() {
+    var returnValue;
+    
+    for (var i = 0; i < arguments.length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+    
+    return returnValue;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+    
+    this.registerCallback();
+  },
+  
+  registerCallback: function() {
+    setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+  
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try { 
+        this.currentlyExecuting = true;
+        this.callback(); 
+      } finally { 
+        this.currentlyExecuting = false;
+      }
+    }
+    
+    this.registerCallback();
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+function $() {
+  var elements = new Array();
+  
+  for (var i = 0; i < arguments.length; i++) {
+    var element = arguments[i];
+    if (typeof element == 'string')
+      element = document.getElementById(element);
+
+    if (arguments.length == 1) 
+      return element;
+      
+    elements.push(element);
+  }
+  
+  return elements;
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!Array.prototype.push) {
+  Array.prototype.push = function() {
+               var startLength = this.length;
+               for (var i = 0; i < arguments.length; i++)
+      this[startLength + i] = arguments[i];
+         return this.length;
+  }
+}
+
+if (!Function.prototype.apply) {
+  // Based on code from http://www.youngpup.net/
+  Function.prototype.apply = function(object, parameters) {
+    var parameterStrings = new Array();
+    if (!object)     object = window;
+    if (!parameters) parameters = new Array();
+    
+    for (var i = 0; i < parameters.length; i++)
+      parameterStrings[i] = 'x[' + i + ']';
+    
+    object.__apply__ = this;
+    var result = eval('obj.__apply__(' + 
+      parameterStrings[i].join(', ') + ')');
+    object.__apply__ = null;
+    
+    return result;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
+      function() {return new XMLHttpRequest()}
+    ) || false;
+  },
+  
+  emptyFunction: function() {}
+}
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+  setOptions: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      parameters:   ''
+    }.extend(options || {});
+  }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events = 
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = (new Ajax.Base()).extend({
+  initialize: function(url, options) {
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+  
+    try {
+      if (this.options.method == 'get')
+        url += '?' + this.options.parameters + '&_=';
+    
+      this.transport.open(this.options.method, url, true);
+      
+      if (this.options.asynchronous) {
+        this.transport.onreadystatechange = this.onStateChange.bind(this);
+        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
+      }
+              
+      this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+      this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);
+
+      if (this.options.method == 'post') {
+        this.transport.setRequestHeader('Connection', 'close');
+        this.transport.setRequestHeader('Content-type',
+          'application/x-www-form-urlencoded');
+      }
+      
+      this.transport.send(this.options.method == 'post' ? 
+        this.options.parameters + '&_=' : null);
+                      
+    } catch (e) {
+    }    
+  },
+      
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState != 1)
+      this.respondToReadyState(this.transport.readyState);
+  },
+  
+  respondToReadyState: function(readyState) {
+    var event = Ajax.Request.Events[readyState];
+    (this.options['on' + event] || Ajax.emptyFunction)(this.transport);
+  }
+});
+
+Ajax.Updater = Class.create();
+Ajax.Updater.prototype = (new Ajax.Base()).extend({
+  initialize: function(container, url, options) {
+    this.container = $(container);
+    this.setOptions(options);
+  
+    if (this.options.asynchronous) {
+      this.onComplete = this.options.onComplete;
+      this.options.onComplete = this.updateContent.bind(this);
+    }
+    
+    this.request = new Ajax.Request(url, this.options);
+    
+    if (!this.options.asynchronous)
+      this.updateContent();
+  },
+  
+  updateContent: function() {
+    if (this.options.insertion) {
+      new this.options.insertion(this.container,
+        this.request.transport.responseText);
+    } else {
+      this.container.innerHTML = this.request.transport.responseText;
+    }
+
+    if (this.onComplete) {
+      setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);
+    }
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+var Field = {
+  clear: function() {
+    for (var i = 0; i < arguments.length; i++)
+      $(arguments[i]).value = '';
+  },
+
+  focus: function(element) {
+    $(element).focus();
+  },
+  
+  present: function() {
+    for (var i = 0; i < arguments.length; i++)
+      if ($(arguments[i]).value == '') return false;
+    return true;
+  },
+  
+  select: function(element) {
+    $(element).select();
+  },
+   
+  activate: function(element) {
+    $(element).focus();
+    $(element).select();
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Form = {
+  serialize: function(form) {
+    var elements = Form.getElements($(form));
+    var queryComponents = new Array();
+    
+    for (var i = 0; i < elements.length; i++) {
+      var queryComponent = Form.Element.serialize(elements[i]);
+      if (queryComponent)
+        queryComponents.push(queryComponent);
+    }
+    
+    return queryComponents.join('&');
+  },
+  
+  getElements: function(form) {
+    form = $(form);
+    var elements = new Array();
+
+    for (tagName in Form.Element.Serializers) {
+      var tagElements = form.getElementsByTagName(tagName);
+      for (var j = 0; j < tagElements.length; j++)
+        elements.push(tagElements[j]);
+    }
+    return elements;
+  },
+  
+  disable: function(form) {
+    var elements = Form.getElements(form);
+    for (var i = 0; i < elements.length; i++) {
+      var element = elements[i];
+      element.blur();
+      element.disable = 'true';
+    }
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    var elements = Form.getElements(form);
+    for (var i = 0; i < elements.length; i++) {
+      var element = elements[i];
+      if (element.type != 'hidden' && !element.disabled) {
+        Field.activate(element);
+        break;
+      }
+    }
+  },
+
+  reset: function(form) {
+    $(form).reset();
+  }
+}
+
+Form.Element = {
+  serialize: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    var parameter = Form.Element.Serializers[method](element);
+    
+    if (parameter)
+      return encodeURIComponent(parameter[0]) + '=' + 
+        encodeURIComponent(parameter[1]);                   
+  },
+  
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    var parameter = Form.Element.Serializers[method](element);
+    
+    if (parameter) 
+      return parameter[1];
+  }
+}
+
+Form.Element.Serializers = {
+  input: function(element) {
+    switch (element.type.toLowerCase()) {
+      case 'hidden':
+      case 'password':
+      case 'text':
+        return Form.Element.Serializers.textarea(element);
+      case 'checkbox':  
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element);
+    }
+    return false;
+  },
+
+  inputSelector: function(element) {
+    if (element.checked)
+      return [element.name, element.value];
+  },
+
+  textarea: function(element) {
+    return [element.name, element.value];
+  },
+
+  select: function(element) {
+    var index = element.selectedIndex;
+    var value = element.options[index].value || element.options[index].text;
+    return [element.name, (index >= 0) ? value : ''];
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+  initialize: function(element, frequency, callback) {
+    this.frequency = frequency;
+    this.element   = $(element);
+    this.callback  = callback;
+    
+    this.lastValue = this.getValue();
+    this.registerCallback();
+  },
+  
+  registerCallback: function() {
+    setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+  
+  onTimerEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+    
+    this.registerCallback();
+  }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+
+/*--------------------------------------------------------------------------*/
+
+document.getElementsByClassName = function(className) {
+  var children = document.getElementsByTagName('*') || document.all;
+  var elements = new Array();
+  
+  for (var i = 0; i < children.length; i++) {
+    var child = children[i];
+    var classNames = child.className.split(' ');
+    for (var j = 0; j < classNames.length; j++) {
+      if (classNames[j] == className) {
+        elements.push(child);
+        break;
+      }
+    }
+  }
+  
+  return elements;
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Element = {
+  toggle: function() {
+    for (var i = 0; i < arguments.length; i++) {
+      var element = $(arguments[i]);
+      element.style.display = 
+        (element.style.display == 'none' ? '' : 'none');
+    }
+  },
+
+  hide: function() {
+    for (var i = 0; i < arguments.length; i++) {
+      var element = $(arguments[i]);
+      element.style.display = 'none';
+    }
+  },
+
+  show: function() {
+    for (var i = 0; i < arguments.length; i++) {
+      var element = $(arguments[i]);
+      element.style.display = '';
+    }
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+  },
+   
+  getHeight: function(element) {
+    element = $(element);
+    return element.offsetHeight; 
+  }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+  this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+  initialize: function(element, content) {
+    this.element = $(element);
+    this.content = content;
+    
+    if (this.adjacency && this.element.insertAdjacentHTML) {
+      this.element.insertAdjacentHTML(this.adjacency, this.content);
+    } else {
+      this.range = this.element.ownerDocument.createRange();
+      if (this.initializeRange) this.initializeRange();
+      this.fragment = this.range.createContextualFragment(this.content);
+      this.insertContent();
+    }
+  }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
+  initializeRange: function() {
+    this.range.setStartBefore(this.element);
+  },
+  
+  insertContent: function() {
+    this.element.parentNode.insertBefore(this.fragment, this.element);
+  }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(true);
+  },
+  
+  insertContent: function() {  
+    this.element.insertBefore(this.fragment, this.element.firstChild);
+  }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(this.element);
+  },
+  
+  insertContent: function() {
+    this.element.appendChild(this.fragment);
+  }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
+  initializeRange: function() {
+    this.range.setStartAfter(this.element);
+  },
+  
+  insertContent: function() {
+    this.element.parentNode.insertBefore(this.fragment, 
+      this.element.nextSibling);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = new Object();
+
+Effect.Highlight = Class.create();
+Effect.Highlight.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+    this.start  = 153;
+    this.finish = 255;
+    this.current = this.start;
+    this.fade();
+  },
+  
+  fade: function() {
+    if (this.isFinished()) return;
+    if (this.timer) clearTimeout(this.timer);
+    this.highlight(this.element, this.current);
+    this.current += 17;
+    this.timer = setTimeout(this.fade.bind(this), 250);
+  },
+  
+  isFinished: function() {
+    return this.current > this.finish;
+  },
+  
+  highlight: function(element, current) {
+    element.style.backgroundColor = "#ffff" + current.toColorPart();
+  }
+}
+
+
+Effect.Fade = Class.create();
+Effect.Fade.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+    this.start  = 100;
+    this.finish = 0;
+    this.current = this.start;
+    this.fade();
+  },
+  
+  fade: function() {
+    if (this.isFinished()) { this.element.style.display = 'none'; return; }
+    if (this.timer) clearTimeout(this.timer);
+    this.setOpacity(this.element, this.current);
+    this.current -= 10;
+    this.timer = setTimeout(this.fade.bind(this), 50);
+  },
+  
+  isFinished: function() {
+    return this.current <= this.finish;
+  },
+  
+  setOpacity: function(element, opacity) {
+    opacity = (opacity == 100) ? 99.999 : opacity;
+    element.style.filter = "alpha(opacity:"+opacity+")";
+    element.style.opacity = opacity/100 /*//*/;
+  }
+}
+
+Effect.Scale = Class.create();
+Effect.Scale.prototype = {
+  initialize: function(element, percent) {
+    this.element = $(element);
+    this.startScale    = 1.0;
+    this.startHeight   = this.element.offsetHeight;
+    this.startWidth    = this.element.offsetWidth;
+    this.currentHeight = this.startHeight;
+    this.currentWidth  = this.startWidth;
+    this.finishScale   = (percent/100) /*//*/;
+    if (this.element.style.fontSize=="") this.sizeEm = 1.0;
+    if (this.element.style.fontSize.indexOf("em")>0)
+       this.sizeEm      = parseFloat(this.element.style.fontSize);
+    if(this.element.effect_scale) {
+      clearTimeout(this.element.effect_scale.timer);
+      this.startScale  = this.element.effect_scale.currentScale;
+      this.startHeight = this.element.effect_scale.startHeight;
+      this.startWidth  = this.element.effect_scale.startWidth;
+      if(this.element.effect_scale.sizeEm) 
+        this.sizeEm    = this.element.effect_scale.sizeEm;      
+    }
+    this.element.effect_scale = this;
+    this.currentScale  = this.startScale;
+    this.factor        = this.finishScale - this.startScale;
+    this.options       = arguments[2] || {}; 
+    this.scale();
+  },
+  
+  scale: function() {
+    if (this.isFinished()) { 
+      this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale);
+      if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em";
+      if(this.options.complete) this.options.complete(this);
+      return; 
+    }
+    if (this.timer) clearTimeout(this.timer);
+    if (this.options.step) this.options.step(this);
+    this.setDimensions(this.element, this.currentWidth, this.currentHeight);
+    if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em";
+    this.currentScale += (this.factor/10) /*//*/;
+    this.currentWidth = this.startWidth * this.currentScale;
+    this.currentHeight = this.startHeight * this.currentScale;
+    this.timer = setTimeout(this.scale.bind(this), 50);
+  },
+  
+  isFinished: function() {
+    return (this.factor < 0) ? 
+      this.currentScale <= this.finishScale : this.currentScale >= this.finishScale;
+  },
+  
+  setDimensions: function(element, width, height) {
+    element.style.width = width + 'px';
+    element.style.height = height + 'px';
+  }
+}
+
+Effect.Squish = Class.create();
+Effect.Squish.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+    new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } );
+  },
+  hide: function() {
+    this.element.style.display = 'none';
+  } 
+}
+
+Effect.Puff = Class.create();
+Effect.Puff.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+    this.opacity = 100;
+    this.startTop  = this.element.top || this.element.offsetTop;
+    this.startLeft = this.element.left || this.element.offsetLeft;
+    new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } );
+  },
+  fade: function(effect) {
+    topd    = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2;
+    leftd   = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2;
+    this.element.style.position='absolute';
+    this.element.style.top = this.startTop-topd + "px";
+    this.element.style.left = this.startLeft-leftd + "px";
+    this.opacity -= 10;
+    this.setOpacity(this.element, this.opacity); 
+    if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari
+  },
+  hide: function() {
+    this.element.style.display = 'none';
+  },
+  setOpacity: function(element, opacity) {
+    opacity = (opacity == 100) ? 99.999 : opacity;
+    element.style.filter = "alpha(opacity:"+opacity+")";
+    element.style.opacity = opacity/100 /*//*/;
+  }
+}
+
+Effect.Appear = Class.create();
+Effect.Appear.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+    this.start  = 0;
+    this.finish = 100;
+    this.current = this.start;
+    this.fade();
+  },
+  
+  fade: function() {
+    if (this.isFinished()) return;
+    if (this.timer) clearTimeout(this.timer);
+    this.setOpacity(this.element, this.current);
+    this.current += 10;
+    this.timer = setTimeout(this.fade.bind(this), 50);
+  },
+  
+  isFinished: function() {
+    return this.current > this.finish;
+  },
+  
+  setOpacity: function(element, opacity) {
+    opacity = (opacity == 100) ? 99.999 : opacity;
+    element.style.filter = "alpha(opacity:"+opacity+")";
+    element.style.opacity = opacity/100 /*//*/;
+    element.style.display = '';
+  }
+}
+
+Effect.ContentZoom = Class.create();
+Effect.ContentZoom.prototype = {
+  initialize: function(element, percent) {
+    this.element = $(element);
+    if (this.element.style.fontSize=="") this.sizeEm = 1.0;
+    if (this.element.style.fontSize.indexOf("em")>0)
+       this.sizeEm = parseFloat(this.element.style.fontSize);
+    if(this.element.effect_contentzoom) {
+      this.sizeEm = this.element.effect_contentzoom.sizeEm;
+    }
+    this.element.effect_contentzoom = this;
+    this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/;
+    if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; };
+  }
+}
diff --git a/sope-appserver/samples/TestPrototype/ChangeLog b/sope-appserver/samples/TestPrototype/ChangeLog
new file mode 100644 (file)
index 0000000..a6b5dd0
--- /dev/null
@@ -0,0 +1,4 @@
+2005-07-10  Helge Hess  <helge.hess@opengroupware.org>
+
+       * created ChangeLog / project
+
diff --git a/sope-appserver/samples/TestPrototype/GNUmakefile b/sope-appserver/samples/TestPrototype/GNUmakefile
new file mode 100644 (file)
index 0000000..371142d
--- /dev/null
@@ -0,0 +1,13 @@
+# GNUstep makefile
+
+-include ../../../config.make
+include $(GNUSTEP_MAKEFILES)/common.make
+
+WOAPP_NAME = TestPrototype
+
+TestPrototype_OBJC_FILES += TestPrototype.m Main.m
+TestPrototype_COMPONENTS += Main.wo
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/woapp.make
+-include GNUmakefile.postamble
diff --git a/sope-appserver/samples/TestPrototype/GNUmakefile.preamble b/sope-appserver/samples/TestPrototype/GNUmakefile.preamble
new file mode 100644 (file)
index 0000000..11f6709
--- /dev/null
@@ -0,0 +1,16 @@
+# compile settings
+
+APPSERVER="../.."
+
+ADDITIONAL_LIB_DIRS += \
+       -L$(APPSERVER)/WEPrototype/$(GNUSTEP_OBJ_DIR)   \
+       -L$(APPSERVER)/NGObjWeb/$(GNUSTEP_OBJ_DIR)      \
+
+# static references required for Mach linker
+
+ADDITIONAL_TOOL_LIBS += \
+       -lWEPrototype   \
+       -lEOControl     \
+       -lDOM -lXmlRpc -lSaxObjC
+
+ADDITIONAL_LIB_DIRS += -L/usr/local/lib -L/usr/lib
diff --git a/sope-appserver/samples/TestPrototype/Main.m b/sope-appserver/samples/TestPrototype/Main.m
new file mode 100644 (file)
index 0000000..37eefb0
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2005 SKYRIX Software AG
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface Main : WOComponent
+{
+  NSArray *items;
+  id      item;
+}
+
+@end
+
+#include "common.h"
+
+@implementation Main
+
+- (id)initWithContext:(id)_ctx {
+  if ((self = [super initWithContext:_ctx])) {
+    NSMutableArray *ma;
+    int i;
+
+    ma = [[NSMutableArray alloc] init];
+    for (i = 0; i < 1000; i++) {
+      char buf[16];
+      NSString *s;
+      sprintf(buf, "%i", i);
+      s = [[NSString alloc] initWithCString:buf];
+      [ma addObject:s];
+      [s release];
+    }
+    self->items = ma;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self->items release];
+  [self->item  release];
+  [super dealloc];
+}
+
+/* accessors */
+
+- (void)setItem:(id)_item {
+  ASSIGN(self->item, _item);
+}
+- (id)item {
+  return self->item;
+}
+
+- (NSArray *)list {
+  return self->items;
+}
+
+/* actions */
+
+- (id)sayWhenAction {
+  WOResponse *r = [[self context] response];
+  
+  [r appendContentString:@"<p>The time is <b>"];
+  [r appendContentString:[[NSCalendarDate date] description]];
+  [r appendContentString:@"</b></p>"];
+  
+  return r;
+}
+
+/* response generation */
+
+- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
+  NSDate *s;
+
+  s = [NSDate date];
+  [super appendToResponse:_r inContext:_ctx];
+  printf("duration: %.3f\n", [[NSDate date] timeIntervalSinceDate:s]);
+}
+
+@end /* Main */
diff --git a/sope-appserver/samples/TestPrototype/Main.wo/Main.html b/sope-appserver/samples/TestPrototype/Main.wo/Main.html
new file mode 100644 (file)
index 0000000..0e2cb30
--- /dev/null
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>Test WEPrototype</title>
+
+    <#Prototype/>
+  </head>
+
+  <body bgcolor="#FFFFFF">
+    <h2>Test WEPrototype</h2>
+
+    <div id="time_div">
+      I don't have the time, but
+      <#TimeLink>click here</#TimeLink>
+      and I will look it up.
+    </div>
+  </body>
+</html>
diff --git a/sope-appserver/samples/TestPrototype/Main.wo/Main.wod b/sope-appserver/samples/TestPrototype/Main.wo/Main.wod
new file mode 100644 (file)
index 0000000..aa10fb9
--- /dev/null
@@ -0,0 +1,15 @@
+// bind template to controller
+
+Prototype: WEPrototypeScript {}
+
+TimeLink: WELiveLink {
+  updateID         = "time_div";
+  position         = "after";
+  actionClass      = "Main";
+  directActionName = "sayWhen";
+  confirmText      = "Really update time?";
+}
+
+AppName: WOString {
+  value = application.name;
+}
\ No newline at end of file
diff --git a/sope-appserver/samples/TestPrototype/TestPrototype.m b/sope-appserver/samples/TestPrototype/TestPrototype.m
new file mode 100644 (file)
index 0000000..499feff
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2005 SKYRIX Software AG
+
+  This file is part of SOPE.
+
+  SOPE is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  SOPE 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 Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with SOPE; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#include <NGObjWeb/WOApplication.h>
+
+@interface TestPrototype : WOApplication
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation TestPrototype
+@end /* TestPrototype */
+
+int main(int argc, char **argv, char **env) {
+  NSAutoreleasePool *pool;
+
+  pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+  [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+  
+  WOApplicationMain(@"TestPrototype", argc, (void*)argv);
+
+  [pool release];
+  return 0;
+}
diff --git a/sope-appserver/samples/TestPrototype/common.h b/sope-appserver/samples/TestPrototype/common.h
new file mode 100644 (file)
index 0000000..1312749
--- /dev/null
@@ -0,0 +1,3 @@
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>