pax_global_header00006660000000000000000000000064137204660360014521gustar00rootroot0000000000000052 comment=27003afab7a0ab6cbf2e24d4b94a602830d9d27f nurpawiki-1.2.4/000077500000000000000000000000001372046603600135365ustar00rootroot00000000000000nurpawiki-1.2.4/.gitignore000066400000000000000000000000361372046603600155250ustar00rootroot00000000000000*~ _build META src/version.ml nurpawiki-1.2.4/CHANGES.md000066400000000000000000000116601372046603600151340ustar00rootroot000000000000001.2.4 (2020-08-23) ================== * Adoption by Stéphane Glondu and migration to GitHub * Use proper connection-dependent PostgreSQL escaping * Port to modern Ocsigen stack (mainly Eliom 6.12.1 and lwt_ppx) * Fix schema installation failure with PostgreSQL 12 1.2.3 (2009-09-07) ================== * Many good patches applied from various people. Summary below. * Bunch of Lwtizations by Stéphane Glondu applied. * Bunch of build flow improvements from Stéphane Glondu * Allow specifying the database host in the nurpawiki database config. Thanks Stéphane! * URL validation issues: issues 63, 64 and 65 all fixed. Thanks Bjoern.Appel, vzapolskiy and animist for patches. 1.2.2 (2008-12-07) ================== * Automatic installation of the database schema on first use (issue 62). This simplifies installations as there are less manual steps to get Nurpawiki going. * More logging in for diagnosing potential database installation problems. * Don't show Logout and My Preferences links when a user is not logged in. * Modify to work on Ocsigen 1.1.0 and latest OCaml Calendar. Thanks again Stéphane for help. * Debian package for Nurpawiki. Thanks Stéphane! 1.2.1 (2008-10-01) ================== **Warning** Requires Ocsigen 1.0.0 in order to work. Just let GODI update the package. **Warning** Re-create all your configuration files with `gen_ocsigen_config` script. * Modify to work on Ocsigen 1.0.0. Thanks to Stephane Glondu for his changes! * Fixed issue 54 - if an unknown todo ID was specified in a wiki page, the server crashed and become unresponsive. 1.2.0 (2008-02-24) ================== **Warning** Take a database backup before upgrading -- this release alters your DB schema. Once upgraded, you can't go back to the previous version. **Caveats** Be sure to create "var/lib" directory in the server working directory when starting the server (see NurpawikiGodiInstallation), otherwise login might start failing. * Support for installing on Postgresql 8.3 (issue 51). Postgresql 8.3 has tsearch2 built-in and that didn't play well with our schema installation script. * Set session timeouts to infinity so that users don't get logged out after a while of inactivity (issue 47). * Extend the schema to make migrating Nurpawiki installation from Postgresql 8.2 to Postgresql 8.3 easy. 1.1.2 (2008-02-09) ================== * Split /history view into multiple pages to make viewing recent changes snappier. * Give the user ability to configure his preferred homepage (thanks Stephane Glondu!). * Performance optimizations in /history view. * Added a Selenium IDE based functional test suite. 1.1.1 (2008-01-05) ================== * Read-only access that lets in non-logged in users who are allowed to view the site content but not to modify it (issue 33) * Highlight a moved task in the to-do list if it's been moved up or down in priorities (issue 8) * Connection pooling (although restricted to only one concurreent connection) * Attempt to re-try database connections if the database server has been restarted while Nurpawiki has been running. * Less database queries during page loads with many to-dos * Login screen problems in issue 40 will be automatically fixed by Ocsigen 0.9.5 (release to be expected in Jan 2008). * A few smaller bugfixes & code improvements. 1.1.0 (2007-12-25) ================== * **Warning** Take a database backup before upgrading -- this release alters your DB schema. Once upgraded, you can't go back to the previous version. * Reason for minor version upgrade: database schema changes. * Implement wiki page revision history: * Users can now view old versions of wiki pages * Several database schema improvements: * Set current DB locale on upgrade (enables users to migrate an existing Nurpawiki DB to a Postgresql installation on a different locale) * Start seq's from 1 (old schema.psql shouldn't have set their start values at all) * Link to nurpawiki main page after a database upgrade 1.0.2 (2007-12-23) ================== * Implement "undo complete task" that allows users to undo if they accidentally closed a task. * Check/uncheck button for (de)selecting all tasks for editing in scheduler. * Created a GODI package. A few changes went into configuration scripts to enable this. * Rename `configure` to `gen_ocsigen_config`. * Rename `site.cma` to `nurpawiki.cma` (Requires you to update your Ocsigen config). * Strip down JSCalendar to make Nurpawiki release package smaller (113KB from 380KB). * Work arounds for IE compatibility 1.0.1 (2007-12-19) ================== * Automatically create WikiStart and WikiMarkup wiki pages on DB init so that the user is taken to a simple help screen after first install. * Implement bold, italic and code styles in wiki markup. * Fix a bug in bullet list whitespace handling. 1.0.0 (2007-12-16) ================== * First ever public release. nurpawiki-1.2.4/COPYING000066400000000000000000000431031372046603600145720ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. nurpawiki-1.2.4/META.in000066400000000000000000000002331372046603600146120ustar00rootroot00000000000000requires = "unix,extlib,postgresql,calendar,pcre,str" version = "%_NURPAWIKI_VERSION_%" archive(byte) = "nurpawiki.cma" archive(native) = "nurpawiki.cmxs" nurpawiki-1.2.4/Makefile000066400000000000000000000015671372046603600152070ustar00rootroot00000000000000CAMLBUILD := ocamlbuild -use-ocamlfind -classic-display CMA := src/nurpawiki.cma CMXA := src/nurpawiki.cmxa CMXS := src/nurpawiki.cmxs TARGETS := $(CMA) ifneq ($(shell command -v ocamlopt),) TARGETS += $(CMXA) ifneq ($(wildcard $(shell ocamlc -where)/dynlink.cmxa),) TARGETS += $(CMXS) endif endif .PHONY: all install all: $(TARGETS) META $(CMA): src/version.ml $(CAMLBUILD) $@ $(CMXA): src/version.ml $(CAMLBUILD) $@ $(CMXS): src/version.ml $(CAMLBUILD) $@ NWIKI_VER=$(shell cat VERSION) src/version.ml: src/version.ml.in VERSION sed -e "s|%_NURPAWIKI_VERSION_%|$(NWIKI_VER)|g" $< > $@ META: META.in VERSION sed -e "s|%_NURPAWIKI_VERSION_%|$(NWIKI_VER)|g" $< > $@ clean: $(CAMLBUILD) -clean -rm -Rf _build META src/version.ml install: ocamlfind install nurpawiki META $(foreach T,$(TARGETS),_build/$(T) $(if $(findstring .cmxa,$(T)),_build/$(T:.cmxa=.a))) nurpawiki-1.2.4/README.md000066400000000000000000000021521372046603600150150ustar00rootroot00000000000000Nurpawiki ========= What is Nurpawiki? ------------------ Nurpawiki is a personal information manager (PIM) application that combines a wiki, a to-do list and a simple scheduler to help you get organized. It aims to ease note taking and action planning. Actions (to-dos) are always associated with notes or plans (wiki pages). Read about [its history](doc/History.md). Get started! ------------ * [Installation](doc/Installation.md) * [Tutorial](doc/Tutorial.md) * [Upgrading from a previous version](doc/Upgrading.md) Development ----------- The application is written in [OCaml](https://ocaml.org/) and uses the fantastic [Ocsigen web programming framework](https://www.ocsigen.org/). It runs in a web server and uses SQL for persistence. It can thus be hosted on Linux and used on on Windows or any other web browser capable platform. Want to help? ------------- Don't like something? Have an improvement suggestion? Code review comments? File a bug to the issue database and we'll see what can be done about it. Releases -------- * [Release notes](CHANGES.md) * [Release process](doc/ReleaseProcess.md) nurpawiki-1.2.4/VERSION000066400000000000000000000000061372046603600146020ustar00rootroot000000000000001.2.4 nurpawiki-1.2.4/_tags000066400000000000000000000003621372046603600145570ustar00rootroot00000000000000"src": include : thread, package(threads), package(netstring), package(calendar), package(extlib), package(postgresql), package(eliom.server), package(lwt_ppx) : for-pack(Nurpawiki) : -for-pack(Nurpawiki) nurpawiki-1.2.4/doc/000077500000000000000000000000001372046603600143035ustar00rootroot00000000000000nurpawiki-1.2.4/doc/DatabaseInstallation.md000066400000000000000000000025621372046603600207200ustar00rootroot00000000000000How to setup the Nurpawiki database with Postgresql =================================================== The installation procedure here explains a setup in which you install Postgresql from source into your home directory. Installing Postgresql --------------------- ### Configure, build, install Postgresql ``` ./configure --prefix=$HOME/opt/postgresql-12.4 make make install ``` I've also made a symlink from the install dir to "psql" to simplify my command lines: ``` cd $HOME/opt ln -s postgresql-12.4 psql ``` Create DB storage and our DB ---------------------------- Note the use of UTF-8! ``` # Create data storage nurpamac:~/opt/postgresql-12.4 janne$ ./bin/initdb -E UTF-8 --locale=en_US.UTF-8 data ``` You can now start Postgresql (Postgresql prints this after successful installation): ``` Success. You can now start the database server using: bin/postgres -D $HOME/opt/psql/data or bin/pg_ctl -D $HOME/opt/psql/data -l logfile start ``` ``` # Create DB: nurpamac:~/opt/postgresql-12.4 janne$ ./bin/createdb -E UTF-8 nurpawiki ``` Install OCaml postgresql bindings --------------------------------- OCaml's postgresql bindings will by default pick up the wrong Postgresql installation (the one in /usr) which might cause compilation to fail. To have them pick up the right PostgreSQL installation, add `$HOME/opt/psql/bin` to your `PATH` environment variable. nurpawiki-1.2.4/doc/DatabaseInstallationDebian.md000066400000000000000000000025371372046603600220250ustar00rootroot00000000000000Configuring Postgresql for Nurpawiki ==================================== These installation instructions apply to both Debian and Ubuntu. Package versions may change depending on your distribution. Install Postgresql and postgresql OCaml bindings ------------------------------------------------ * `apt-get install postgresql postgresql-client postgresql-contrib libpq-dev` * Make sure your distro has Postgresql 8.3 or newer, otherwise things might not go so smoothly with installation. Create DB & configure --------------------- ### Install DB and configure * `sudo -u postgres createdb -E UTF-8 nurpawiki` #### Method #1: Setup postgres user authentication to the database This is the preferred method on making the DB connection authenticate properly. * Set postgres DB password for the nurpawiki database * Connect to DB: `sudo -u postgres psql nurpawiki` * `ALTER USER postgres PASSWORD 'barfoo';` You can now test that your newly set password actually lets you access you database: * _As a normal user_ do: `psql -h localhost -W -U postgres nurpawiki` and type in the password you used above. Note that the password for `postgres` Unix user and the DB password are not the same. When creating Nurpawiki's configuration with `gen_ocsigen_config` script, be sure to specify the same password you used in the above ALTER statement. nurpawiki-1.2.4/doc/DevTestPlan.md000066400000000000000000000014371372046603600170230ustar00rootroot00000000000000How to test a new release ========================= Each version, be it major, minor or patch needs to pass these tests: * Check that VERSION matches About box's version (should be automatic) * Go through the sample wiki page to check that Wiki markup is parsing hasn't regressed * SeleniumFunctionalTests (FIXME) Patch revision releases ----------------------- Patch revision releases should never add or modify the DB schema, so they're slightly easier to QA. Minor revision releases ----------------------- * Try installation on an empty database (dropdb, createdb) * This is already tested by Selenium tests * Try installation on an existing database (take personal db and install on it) * Benchmarks Major revision releases ----------------------- * TODO DB upgrades nurpawiki-1.2.4/doc/History.md000066400000000000000000000024411372046603600162670ustar00rootroot00000000000000A brief history of Nurpawiki ============================ (By Janne Hellsten) I had long been struggling to keep my todo lists and notes organized. I had been trying to use a set of text files for todos but it quickly got either too long or too unorganized. I also tried to use a wiki todo lists but my tasks got quickly hidden into the depths of my wiki. I also setup an elaborate reminder system using a calendar but didn't like it that the tasks got lost if I didn't complete them immediately after being reminded about them. At some point I learned about an Emacs app called [planner-mode](http://www.emacswiki.org/cgi-bin/emacs/PlannerMode) and used it for a while. Planner was pretty neat and had most of the features I had been wanting for a long time. I especially liked the ability of being able to freely embed tasks into wiki pages. Another great feature was to be able to have tasks turn themselves on at a certain date (and keep out of my todo list until then). For reasons I don't anymore remember, I wasn't 100% happy with Planner either and wanted a better solution. As it happened, I learnt about Ocsigen which inspired me to try web programming in [my favorite programming language](http://caml.inria.fr). During my Xmas holiday in 2006 I finally wrote the first version of Nurpawiki. nurpawiki-1.2.4/doc/Installation.md000066400000000000000000000020611372046603600172650ustar00rootroot00000000000000Installation ============ Nurpawiki can be installed in various ways. By far the simplest method is to use the Nurpawiki Debian package. ## 1. Installation via the Nurpawiki Debian package (recommended) Debian installation: [installing Nurpawiki on Debian](NurpawikiDebianInstallation.md). If you successfully installed using the above link, you can stop reading now. ## 2. Installation via source ### Install Postgresql & create a database See [Debian DB instructions](DatabaseInstallationDebian.md) for instructions on installing using Debian's packages. This should work for both Debian and Ubuntu. The instructions should be easily adaptable for other distributions. See [DB from source](DatabaseInstallation.md) for installing everything from source (not recommended). ### Install Nurpawiki * [Install Nurpawiki from source](NurpawikiSourceInstallation.md) See [here](SiteConfiguration.md) for more configuration options. ### Test it! Point your browser to http://localhost:8080/view?p=WikiStart and login as "admin" (leave the password field empty). nurpawiki-1.2.4/doc/NurpawikiDebianInstallation.md000066400000000000000000000037271372046603600222740ustar00rootroot00000000000000Nurpawiki installation on Debian ================================ This page describes how to install Nurpawiki using the [Nurpawiki Debian package](http://packages.debian.org/nurpawiki). ## 1. Package installation Nurpawiki is currently only in Debian unstable, so it's likely that you need to include unstable packages in your `/etc/apt/sources.list`. Install required Debian packages: ``` apt-get install postgresql apt-get install nurpawiki ``` ## 2. Database setup With Bullseye's PostgreSQL (version 12.4), the steps on the SQL server are: 1. Create a user in the database: ``` sudo -u postgres createuser ${DBUSER} ``` 2. Create the database for Nurpawiki: ``` sudo -u postgres createdb -O ${DBUSER} -E UTF-8 ${DBNAME} ``` 3. Set a password for the user accessing the database: ``` sudo -u postgres psql ${DBNAME} ${DBUSER} ALTER ${DBUSER} PASSWORD '${DBPASSWORD}'; \q ``` You can take, for example, DBUSER=ocsigen and DBNAME=nurpawiki (beware of commands executed in psql shell). ## 3. Ocsigen configuration A sample template for a configuration file is available in `/usr/share/doc/nurpawiki/examples`. Filling it with proper database user, database name and password will give you a `` that can be run with `ocsigen -c ` (as root). Ocsigen will then be listening on port 8080, as user ocsigen, and be serving Nurpawiki only (at /). If satisfied, and if you don't use any other Ocsigen-based service, you can directly use that configuration file as /etc/ocsigen/ocsigenserver.conf and use an initscript or systemd unit to launch ocsigen. Of course, Nurpawiki can be used with other Ocsigen-based services, but you'll have to edit /etc/ocsigen/ocsigenserver.conf yourself. At installation, a wiki user "admin" with an empty password is created. If everything went right and Ocsigen was properly started, you should be able to get into Nurpawiki by browsing to http://localhost:8080 ## More details More details are available in `/usr/share/doc/nurpawiki/README.Debian`. nurpawiki-1.2.4/doc/NurpawikiSourceInstallation.md000066400000000000000000000027451372046603600223510ustar00rootroot00000000000000Install Nurpawiki from source ============================= Note: this approach is harder than other methods, but is provided as a reference for developers or in case something goes wrong with packaged Nurpawiki. Install Ocsigen & other required packages ----------------------------------------- Install Ocsigen server and Eliom through your favourite distribution or [OPAM](https://opam.ocaml.org). For Windows, I find it convenient to run Linux in vmware and use Linux for serving pages and Windows for browsing. Get the source -------------- Download the latest release from the [downloads page](https://github.com/glondu/nurpawiki/releases). You can also go for the latest and greatest by getting the source from [GitHub](https://github.com/glondu/nurpawiki). Configuration ------------- Run `gen_ocsigen_config` like so: ``` # NOTE: This depends on the way you configured your Postgresql. # NOTE 3: See DB installation page for info on postgres user password & authentication env DBNAME=nurpawiki DBUSER=postgres DBPASSWD= ./gen_ocsigen_config > nurpawiki.conf.local ``` The script will complain if some of the dependent libraries are not installed via ocamlfind. Output of `gen_ocsigen_config` is piped to a file and will later on be passed to Ocsigen server when you start it. See [SiteConfiguration](SiteConfiguration.md) for more info on configuring Nurpawiki. Build Nurpawiki --------------- Run `make`. Start server ------------ Run `ocsigenserver -c nurpawiki.conf.local`. nurpawiki-1.2.4/doc/ReleaseProcess.md000066400000000000000000000020121372046603600175370ustar00rootroot00000000000000Release Process =============== 1. Review documentation to ensure that the docs are up-to-date for the version to be released. 2. Update CHANGES.md 3. Update VERSION to the version number being released 4. Make a release candidate out of the current head * Untar the release candidate, configure and build it 5. QA the package according to [DevTestPlan](DevTestPlan.md) 6. Test the release candidate tarball with Debian 7. Make a tag 8. Upload the Debian Package 9. **Eat your own dog food**: Upgrade personal installation to use the release version from Debian. This is good for various reasons: * New Debian releases of Nurpawiki don't start to lag behind, as the latest features are installed to my own personal installation via releases. * Debian package gets tested on a real installation * Setting up Nurpawiki from Debian gets tested and hopefully will become streamlined over time as I get reminded about the installation procedure on each release. 10. Announce nurpawiki-1.2.4/doc/SiteConfiguration.md000066400000000000000000000053141372046603600202640ustar00rootroot00000000000000Configuration ============= This page details Nurpawiki's configuration options. The configuration file is passed to the Ocsigen when you start its web server (`ocsigenserver -c `). If you want to go beyond configuring the basic capabilities of Nurpawiki, for example, if you want to configure the web server ports or users, you need to refer to Ocsigen web server's configuration manual. Read [here](http://www.ocsigen.org/config) for more info. The Nurpawiki-specific configuration options can be found from the Ocsigen server configuration file under the XML element ``. Here's an example of a Nurpawiki site configuration: ``` ``` Using an example configuration ------------------------------ If you installed Nurpawiki from an installation package (e.g., Debian package), you may wish to review the contents of `/example.conf`. At the bare minimum, you need to configure the default settings of your database. Generating a new configuration file ----------------------------------- If you've installed Nurpawiki from source, you can generate your own base configuration file by running `nurpawiki/gen_ocsigen_config` script. The created configuration should work well as a default configuration. You may want to edit it to better suit your needs. Configuration options --------------------- The configuration elements inside the Nurpawiki `` element are: ### Element: nurpawiki _Attribute list_: * homepage (optional): name of the wiki page to go to by default. If the user navigates to http://localhost:8080, he will be automatically redirected to http://localhost:8080/view?p=homepage . If this option is left unspecified, the default is to use WikiStart. * allow_read_only_guests (optional): if "yes", allow read-only access to the full wiki. Guests can read all wiki pages, inspect todos, but are not allowed to modify any of the data. Default is to disallow read-only guests. ### Element: database _Attribute list_: * name (required): name of the Nurpawiki database. Example: "nurpawiki". * user (required): database user for accessing the Nurpawiki database. Example: "postgres". * password (required): password used to let database _user_ access the database. * port (optional): database is running on this port. * host (optional): host where the database is running. Defaults to localhost. nurpawiki-1.2.4/doc/Tutorial.md000066400000000000000000000110401372046603600164240ustar00rootroot00000000000000First page ========== The first thing to do after installing and starting Nurpawiki is to point your browser at http://localhost:8080/view?p=WikiStart . You will arrive at a login screen. Type in "admin" as your login and leave the password empty. That's the default after a fresh install. Adding to-dos ============= We will now showcase the to-do feature of this wiki. Let's make a page called "NurpaWiki" and place the following contents on it: ``` = NurpaWiki project = This page is used to take notes & draft actions for the Nurpawiki SW project. == Ocsigen related == * [todo Send an introduction e-mail to Ocsigen mailing list once build flow & documentation is good enough for public review] == Web documentation == * [todo Write a short description of Nurpawiki on the Project Home] * [todo Take screenshots of Nurpawiki todo list] * [todo Take screenshots of Nurpawiki scheduler] ``` You will note that the wikitext conforms mostly to the one used in MediaWiki. However, there is one notable exception: the `[todo ]` tag. When you embed a `[todo]` in your wiki page, it will be picked up by the wiki parser and added to your global to-do list when you save the wiki page. After you've saved your wiki page along with your to-do items, note the to-do list table that appeared on the left navbar. The to-do items you inserted into your wikitext got added onto your to-do list! Their appearance also changed on the wiki page to indicate that they're tasks embedded onto your page. You can edit a task's priority by clicking the up/down arrows. This will move it up or down on the left to-do list. You can also mark it as completed by clicking the checkbox by the priority up/down buttons. When you mark a to-do as completed, it will disappear from your to-do list but it will remain grayed on your wiki page. Moving tasks to different wiki pages ------------------------------------ After saving the wiki page, you will note that your `[todo ]` tags got modified to include a task ID. For example, a to-do in wikitext might now look like `[todo:4 Take screenshots of Nurpawiki todo list]`. The number in `[todo:N <...>]` is the task ID and is used to uniquely identify a certain to-do item. If you want to move a certain to-do item to another wikipage, just copy&paste the `[todo:N <...>]` text into another wiki page and save. A single to-do can reside on several different wiki pages. There's no reason to limit a to-do's existence to only a single page. In fact, it's very useful to associate a given task with several contexts (wiki pages). Scheduling tasks ================ To-do lists have a tendency to become very long over time. The longer your to-do list gets, the harder it is to choose which tasks to complete any given day. Prioritizing them helps, but even your high priority list might become long. To reduce your daily load, you can trigger tasks to only appear on your to-do list after a certain date. Another, perhaps more important use-case for to-do scheduling is reminder-style tasks that cannot really be completed until a certain date. You don't want to see such tasks on your to-do list before you can actually do something about it but you still want to be reminded about it once you can actually do something about it. Nurpawiki has a feature called the Scheduler that can be used to move tasks around in time in order to have them appear on your to-do list only after a certain date. Scheduler --------- Click on the "Scheduler" link on the upper left corner of the web page. ### Scheduling a single to-do To schedule a to-do, click on the small pencil icon to the left of a todo to edit it. You will be taken to a "to-do editor": To edit the trigger date, click on the edit box below the to-do description. A date selector popup will appear. Select the date you want to assign to the task and click Save. If a task A depends on another task B, you can postpone task A for a few days. A will pop up on the to-do list after a few days. If B is completed, you can complete A and mark it as completed. If you're still unable to complete A, you can postpone it again using the Scheduler. ### Scheduling a batch of tasks Sometimes it's useful to assign a larger group of tasks the same trigger date. To do this, tick off the checkboxes for the tasks you want to move and click the "Mass edit" button. History ======= Sometimes it's useful to look back at your week and recall what wiki pages you worked on, what notes you were taking or what tasks you created or completed. Click on the History button to see a log of latest action in your wiki. nurpawiki-1.2.4/doc/Upgrading.md000066400000000000000000000013541372046603600165500ustar00rootroot00000000000000How to upgrade to a newer release ================================= **NOTE: always take a database backup before upgrading!** If you have compiled Nurpawiki from source, you need to get the new source and compile it. If you're using a packaged Nurpawiki, just install the latest package. Configuration files may require changes from time to time. See e.g., [SiteConfiguration](SiteConfiguration.md) for notes. The nurpawiki database will be automatically upgraded when you try to access any of your Nurpawiki pages with your browser. You're strongly recommended to backup your database before attempting an upgrade. Note that it is **impossible to go back to an earlier version** of your database once you have upgraded to a later version. nurpawiki-1.2.4/files/000077500000000000000000000000001372046603600146405ustar00rootroot00000000000000nurpawiki-1.2.4/files/arrow_down.png000066400000000000000000000066761372046603600175460ustar00rootroot00000000000000PNG  IHDR &q iCCPICC Profilexy8]ǿc_}HVd_o5f#cJ EQIӮVӪkQJmHh#Q<\rϹ|\r8XI_аp` @>n4v 3_B<yZ<0PB)bh\ 3@L#@Dg&YtF Sh, |gt@vI4V0 '9 hD\ '̟kz%OZ_))'@D7{o{R"-6;Gyl@@H`@HXXXDBTXLR\LBZRLJBZ(-##K%N ɓUTUT5444Ț:::&N62661bjjj6|4 VV6vv3fΜ9kLqqqu=? `N``PPpHHHhhxxDDddTttyTjL N3qqLfsDp8\.7.L_hQFKdffeeg/],'7gyyy+WZzuA5k׮[~ qM7oٲum۷رs]Żwٳw};pҲC#G=v'N8eqgTVVU={\u.\xҥ˗\zڵoܸyvvm[oݹs{oohhl|𠩩9G?~ӧ--mQmmϞ?EGLG˗^~۷޽C7O}}?2008Pȷo߿3Q!!aq!Q 1Qq) QIq)i)"QFZVFN$7AN~L7Пd`8hdcS33ө-,Oa7s#:? 0(((88$$44,,<"2"**:zyT*FظxfBBB"Jbvr279%eԂ  {ٲg~Z`Z`'h˘xݹÂƀ1 @۳gs7 Ia81~OX&tR>'R4RlxD$WEZ^xJ&W_NST5!O>T@ORJ!Tu{ a[kC:l]3݁Uzg7:)Hʨnco1).fBfצ.7LS͖Vr6lfL)6e юfNpj:/qqwpq}gY>^*o*s| <"r?tKؼpO#F͈67Uz7f5͛.Modn[:?1ÚvX'suR&yi O߸('gU,Kd/(O&S~ʊUWD+(e݅%~codypK vn.vf`q={@C^sc'=q䡊Se^Uwܓ ._IZ7jo5I[wF҃>j*ݡ*k{YÚ|>0z%UfA9X I6v;\4 I(BVKQxE$L'P  & Z |+d!%tGXCU#\#&5- '"Aht\*Y-e.U./MKd&ʔɚVQI(Rlyr:Vt%%ʡʇGTJTgPSwW(ՌВJкF^mI瘮.{>3d'O0V7541eiYi$iMnUw[Y%[GڸZM:8KpV֬a~nǷN].7.]{f==彴||b36)<fNXY=ewm?7~α_-1V!N;+?r_G={?`}Ei*ógG8^kkO}Z_[ @$AH6\F7L$n H  t r*f x\=%f)V% ~K"J[2_JOFA!a*6ʭ&yO K!LQF^i+ՓjA:Ú\]zݓ0z3qiM4`~ r6f'9sSOͮpo9cG_P:5H$xjHD+ბQW R]c>0bWu0YnpH.HZر(2mIxlΜܗ+RW&,tX`=mCƬZ[mhh]SJH;\#GO|;rP.]꺲Fڂ7=חޗiHklirl铴խ6g׿RΝ!]orm#cuo>>|xi ׼!5CCÌۑM#/Y|]Z>}/$(D6Eq:X=dH1yr]8x T).sbX;Y0  | XKJ.c[=HRFR)issөΞBxX'xgA` &jAT$vAL*Rd$d :HOE"H80`2}\0Mt2qY'bӶmޘ<#I?v3>dq40x .Xs~a "`8'>>f({C/\G8 \77ˋpTg4X˔IENDB`nurpawiki-1.2.4/files/arrow_up.png000066400000000000000000000066721372046603600172170ustar00rootroot00000000000000PNG  IHDR &q iCCPICC Profilexy8]ǿc_}HVd_o5f#cJ EQIӮVӪkQJmHh#Q<\rϹ|\r8XI_аp` @>n4v 3_B<yZ<0PB)bh\ 3@L#@Dg&YtF Sh, |gt@vI4V0 '9 hD\ '̟kz%OZ_))'@D7{o{R"-6;Gyl@@H`@HXXXDBTXLR\LBZRLJBZ(-##K%N ɓUTUT5444Ț:::&N62661bjjj6|4 VV6vv3fΜ9kLqqqu=? `N``PPpHHHhhxxDDddTttyTjL N3qqLfsDp8\.7.L_hQFKdffeeg/],'7gyyy+WZzuA5k׮[~ qM7oٲum۷رs]Żwٳw};pҲC#G=v'N8eqgTVVU={\u.\xҥ˗\zڵoܸyvvm[oݹs{oohhl|𠩩9G?~ӧ--mQmmϞ?EGLG˗^~۷޽C7O}}?2008Pȷo߿3Q!!aq!Q 1Qq) QIq)i)"QFZVFN$7AN~L7Пd`8hdcS33ө-,Oa7s#:? 0(((88$$44,,<"2"**:zyT*FظxfBBB"Jbvr279%eԂ  {ٲg~Z`Z`'h˘xݹÂƀ1 @۳gs7 Ia81~OX&tR>'R4RlxD$WEZ^xJ&W_NST5!O>T@ORJ!Tu{ a[kC:l]3݁Uzg7:)Hʨnco1).fBfצ.7LS͖Vr6lfL)6e юfNpj:/qqwpq}gY>^*o*s| <"r?tKؼpO#F͈67Uz7f5͛.Modn[:?1ÚvX'suR&yi O߸('gU,Kd/(O&S~ʊUWD+(e݅%~codypK vn.vf`q={@C^sc'=q䡊Se^Uwܓ ._IZ7jo5I[wF҃>j*ݡ*k{YÚ|>0z%UfA9X I6v;\4 I(BVKQxE$L'P  & Z |+d!%tGXCU#\#&5- '"Aht\*Y-e.U./MKd&ʔɚVQI(Rlyr:Vt%%ʡʇGTJTgPSwW(ՌВJкF^mI瘮.{>3d'O0V7541eiYi$iMnUw[Y%[GڸZM:8KpV֬a~nǷN].7.]{f==彴||b36)<fNXY=ewm?7~α_-1V!N;+?r_G={?`}Ei*ógG8^kkO}Z_[ @$AH6\F7L$n H  t r*f x\=%f)V% ~K"J[2_JOFA!a*6ʭ&yO K!LQF^i+ՓjA:Ú\]zݓ0z3qiM4`~ r6f'9sSOͮpo9cG_P:5H$xjHD+ბQW R]c>0bWu0YnpH.HZر(2mIxlΜܗ+RW&,tX`=mCƬZ[mhh]SJH;\#GO|;rP.]꺲Fڂ7=חޗiHklirl铴խ6g׿RΝ!]orm#cuo>>|xi ׼!5CCÌۑM#/Y|]Z>}/$(D6Eq:X=dH1yr]8x T).sbX;Y0  | XKJ.c[=HRFR)issөΞBxX'xgA` &jAT$vAL*Rd$d :HOE"H80`2}\0Mt2qY'bӶmޘ<#I?v3>dq40x .Xs~a "`8'a1jLNήns__8dIhXxDdԲq+VƯb%9Ĥd5TpH,IK_~C7m޲˯mӎwosw/{a} OG{\\|יҲ_V;ke.^|k}[Uշkܩ[w g[ZZ_|T?07CCoe54utL43̰j9zL[;Y]̝s? 0(`iDdԲ"|V%+PX + @_U}Nmݺ{<m/_utvvuu(WV UE1NSKN?hD3ISLf5zL]\̝7B/o"R,ds.[be*+w!yI}JQr+4"Pcӓg-/^z ghc *c9ۀ΀Q! Dee)(K@dJTР ]aň|TMAA% JCp( JՌO=LLmSqVV9rS\U_"m"MB;DRS۩V֡^Јء73fͳZZEVMt !KctźzL*7n`hPd4|d9a„ gL.2N<``6`^8idɗ_XYtM91U``=jt?k]ffښJ9Q߱sAnkugAYly'_$ 2Y$<41lCE"dѓb<Wfilv11Q??9k+u '@дv+>&Lw͸p;Fjvce_o͹;~{| 5 쾼<?.=|#U!Eak-nNRIEbCp(7UzUUU;iiZZ?r&=ǹ7eŞwzٯθp֨w?^u[8;uFd_ٌ*#=Puv`~~'&O[Z;z2=IBD/ņ¡4Y8dwUE:UECSRARQA "8쎦ǷMd7zrFo6}yqI9e3S\I'$kHCdO6r<~:VNe]z{{ T{C?4xc;T?4|lLE8/1>+ȡ@' `b/7Ԅ%”+]*my~tC( ` !#DjV`ܖCWw (@rS#/U\|Ddfܿ ` !5! ` !bHB2 |pINp3$3Ed K(sLA0M2R G/TzHIDAT8푱 0EOlwR ğEݺS3PU&Bý0Jlˏ(4+mo㨨5q @Yak{C`xvt<y:cBgݽ'I߇H)Y{ZAUUm/w8UJS?1֩:҇iAIENDB`nurpawiki-1.2.4/files/edit.png000066400000000000000000000004561372046603600163000ustar00rootroot00000000000000PNG  IHDRk pHYs  tIME 3IDATx= _WL$un<+yAp uݸ,b"ƿB!"c̗ &)D4I !\x?޷y2y=}͕ma1jLNήns__8dIhXxDdԲq+VƯb%9Ĥd5TpH,IK_~C7m޲˯mӎwosw/{a} OG{\\|יҲ_V;ke.^|k}[Uշkܩ[w g[ZZ_|T?07CCoe54utL43̰j9zL[;Y]̝s? 0(`iDdԲ"|V%+PX + @_U}Nmݺ{<m/_utvvuu(WV UE1NSKN?hD3ISLf5zL]\̝7B/o"R,ds.[be*+w!yI}JQr+4"Pcӓg-/^z ghc *c9ۀ΀Q! Dee)(K@dJTР ]aň|TMAA% JCp( JՌO=LLmSqVV9rS\U_"m"MB;DRS۩V֡^Јء73fͳZZEVMt !KctźzL*7n`hPd4|d9a„ gL.2N<``6`^8idɗ_XYtM91U``=jt?k]ffښJ9Q߱sAnkugAYly'_$ 2Y$<41lCE"dѓb<Wfilv11Q??9k+u '@дv+>&Lw͸p;Fjvce_o͹;~{| 5 쾼<?.=|#U!Eak-nNRIEbCp(7UzUUU;iiZZ?r&=ǹ7eŞwzٯθp֨w?^u[8;uFd_ٌ*#=Puv`~~'&O[Z;z2=IBD/ņ¡4Y8dwUE:UECSRARQA "8쎦ǷMd7zrFo6}yqI9e3S\I'$kHCdO6r<~:VNe]z{{ T{C?4xc;T?4|lLE8/1>+ȡ@' `b/7Ԅ%”+]*my~tC( ` !#DjV`ܖCWw (@rS#/U\|Ddfܿ ` !5! ` !bHB2 |pINp3$3Ed K(sLA0M2R G/TzHIDAT 0 ߆{ +ZpnV+0.(8 An[DV=ܙ9 h_Wcsws~^k%`c 3c-fTkmoXwϟ^F]ocIENDB`nurpawiki-1.2.4/files/external_link.png000066400000000000000000000002361372046603600202060ustar00rootroot00000000000000PNG  IHDR s;eIDATM 0LDDd($1|A7p}򹑇 jYT 5 u)L)֝u?˯~j }:;^&̚*IENDB`nurpawiki-1.2.4/files/home.png000066400000000000000000000027531372046603600163050ustar00rootroot00000000000000PNG  IHDRp ngAMA|Q cHRMz%u0`:ovIDATxb? K @ }+ 0c.xP秈@}o`W^ 0!#GG@p{|7B{F\&@ A;>@ +/}ʼ  IW"@`z0;%3bql d of{A13L@ ƙ /G8^%?8AmO_So]zlv7?{c Z/sc_vxqӳaS'E)0b t{xr<BV@[C8@@:7PDd 3zsMo@;/4H}w׼6ۇOV&P2g .5~Ӯ5վ98ۼo?_<ZkS. p3YLoك-%]d۲{ l+[@ȆO[-?.0}7@S[Tg5Lo{f~d-01,zr(\@ ]5cl2@Yd(O1L?0a?^Mb 9 6b \ҽg/Sv]o X>yao̬p;P @(ܹ@R7@%\/Z%3ņw&E*Ϟf.@![t`4>л;nE@A‚Tz^Ͼg;?u^ 4g: dhT߽2@u ȥO?~ȵa™~<*ܺ@ ]@NlN .92~33OIENDB`nurpawiki-1.2.4/files/jscalendar/000077500000000000000000000000001372046603600167465ustar00rootroot00000000000000nurpawiki-1.2.4/files/jscalendar/README000066400000000000000000000016161372046603600176320ustar00rootroot00000000000000The DHTML Calendar ------------------- Author: Mihai Bazon, http://dynarch.com/mishoo/ This program is free software published under the terms of the GNU Lesser General Public License. For the entire license text please refer to http://www.gnu.org/licenses/lgpl.html Contents --------- calendar.js -- the main program file lang/*.js -- internalization files *.css -- color themes cal.html -- example usage file doc/ -- documentation, in PDF and HTML simple-1.html -- quick setup examples [popup calendars] simple-2.html -- quick setup example for flat calendar calendar.php -- PHP wrapper test.php -- test file for the PHP wrapper Homepage --------- For details and latest versions please refer to calendar homepage, located on my website: http://dynarch.com/mishoo/calendar.epl nurpawiki-1.2.4/files/jscalendar/calendar-blue.css000066400000000000000000000113361372046603600221620ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #556; font-size: 11px; color: #000; cursor: default; background: #eef; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ } .calendar .nav { background: #778 url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #fff; color: #000; padding: 2px; } .calendar thead .headrow { /* Row containing navigation buttons */ background: #778; color: #fff; } .calendar thead .daynames { /* Row containing the day names */ background: #bdf; } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #556; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #a66; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background-color: #aaf; color: #000; border: 1px solid #04f; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background-color: #77c; padding: 2px 0px 0px 2px; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; color: #456; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #bbb; } .calendar tbody .day.othermonth.oweekend { color: #fbb; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #bdf; } .calendar tbody .rowhilite td { background: #def; } .calendar tbody .rowhilite td.wn { background: #eef; } .calendar tbody td.hilite { /* Hovered cells */ background: #def; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ background: #cde; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #fff; color: #000; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #a66; } .calendar tbody td.today { /* Cell showing selected date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #556; color: #fff; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #fff; color: #445; border-top: 1px solid #556; padding: 1px; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #aaf; border: 1px solid #04f; color: #000; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #77c; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #655; background: #def; color: #000; font-size: 90%; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .hilite { background: #acf; } .calendar .combo .active { border-top: 1px solid #46a; border-bottom: 1px solid #46a; background: #eef; font-weight: bold; } .calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #f4f0e8; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #667; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-blue2.css000066400000000000000000000116161372046603600222450ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #206A9B; font-size: 11px; color: #000; cursor: default; background: #F1F8FC; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ } .calendar .nav { background: #007ED1 url(menuarrow2.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #000; color: #fff; padding: 2px; } .calendar thead tr { /* Row containing navigation buttons */ background: #007ED1; color: #fff; } .calendar thead .daynames { /* Row containing the day names */ background: #C7E1F3; } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #206A9B; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #a66; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background-color: #34ABFA; color: #000; border: 1px solid #016DC5; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background-color: #006AA9; border: 1px solid #008AFF; padding: 2px 0px 0px 2px; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; color: #456; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #bbb; } .calendar tbody .day.othermonth.oweekend { color: #fbb; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #C7E1F3; } .calendar tbody .rowhilite td { background: #def; } .calendar tbody .rowhilite td.wn { background: #F1F8FC; } .calendar tbody td.hilite { /* Hovered cells */ background: #def; padding: 1px 3px 1px 1px; border: 1px solid #8FC4E8; } .calendar tbody td.active { /* Active (pressed) cells */ background: #cde; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #fff; color: #000; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #a66; } .calendar tbody td.today { /* Cell showing selected date */ font-weight: bold; color: #D50000; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #206A9B; color: #fff; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #000; color: #fff; border-top: 1px solid #206A9B; padding: 1px; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #B8DAF0; border: 1px solid #178AEB; color: #000; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #006AA9; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #655; background: #def; color: #000; font-size: 90%; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .hilite { background: #34ABFA; border-top: 1px solid #46a; border-bottom: 1px solid #46a; font-weight: bold; } .calendar .combo .active { border-top: 1px solid #46a; border-bottom: 1px solid #46a; background: #F1F8FC; font-weight: bold; } .calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #E3F0F9; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #F1F8FC; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #267DB7; color: #fff; } .calendar td.time span.active { border-color: red; background-color: #000; color: #A5FF00; } nurpawiki-1.2.4/files/jscalendar/calendar-brown.css000066400000000000000000000111541372046603600223600ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #655; font-size: 11px; color: #000; cursor: default; background: #ffd; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ } .calendar .nav { background: #edc url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #654; color: #fed; padding: 2px; } .calendar thead .headrow { /* Row containing navigation buttons */ background: #edc; color: #000; } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #655; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background-color: #faa; color: #000; border: 1px solid #f40; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background-color: #c77; padding: 2px 0px 0px 2px; } .calendar thead .daynames { /* Row containing the day names */ background: #fed; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #bbb; } .calendar tbody .day.othermonth.oweekend { color: #fbb; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #fed; } .calendar tbody .rowhilite td { background: #ddf; } .calendar tbody .rowhilite td.wn { background: #efe; } .calendar tbody td.hilite { /* Hovered cells */ background: #ffe; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ background: #ddc; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #fea; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { font-weight: bold; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #988; color: #000; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ border-top: 1px solid #655; background: #dcb; color: #840; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #faa; border: 1px solid #f40; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #c77; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #655; background: #ffe; color: #000; font-size: 90%; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .hilite { background: #fc8; } .calendar .combo .active { border-top: 1px solid #a64; border-bottom: 1px solid #a64; background: #fee; font-weight: bold; } .calendar td.time { border-top: 1px solid #a88; padding: 1px 0px; text-align: center; background-color: #fed; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #988; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #866; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-green.css000066400000000000000000000112551372046603600223330ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #565; font-size: 11px; color: #000; cursor: default; background: #efe; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ background: #676; color: #fff; font-size: 90%; } .calendar .nav { background: #676 url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; padding: 2px; background: #250; color: #efa; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #565; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #a66; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background-color: #afa; color: #000; border: 1px solid #084; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background-color: #7c7; padding: 2px 0px 0px 2px; } .calendar thead .daynames { /* Row containing the day names */ background: #dfb; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; color: #564; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #bbb; } .calendar tbody .day.othermonth.oweekend { color: #fbb; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #8a8; background: #dfb; } .calendar tbody .rowhilite td { background: #dfd; } .calendar tbody .rowhilite td.wn { background: #efe; } .calendar tbody td.hilite { /* Hovered cells */ background: #efd; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ background: #dec; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #f8fff8; color: #000; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #a66; } .calendar tbody td.today { font-weight: bold; color: #0a0; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #565; color: #fff; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ padding: 2px; background: #250; color: #efa; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #afa; border: 1px solid #084; color: #000; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #7c7; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #565; background: #efd; color: #000; font-size: 90%; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .hilite { background: #af8; } .calendar .combo .active { border-top: 1px solid #6a4; border-bottom: 1px solid #6a4; background: #efe; font-weight: bold; } .calendar td.time { border-top: 1px solid #8a8; padding: 1px 0px; text-align: center; background-color: #dfb; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #898; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #686; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-setup.js000066400000000000000000000212251372046603600222150ustar00rootroot00000000000000/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/ * --------------------------------------------------------------------------- * * The DHTML Calendar * * Details and latest version at: * http://dynarch.com/mishoo/calendar.epl * * This script is distributed under the GNU Lesser General Public License. * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html * * This file defines helper functions for setting up the calendar. They are * intended to help non-programmers get a working calendar on their site * quickly. This script should not be seen as part of the calendar. It just * shows you what one can do with the calendar, while in the same time * providing a quick and simple method for setting it up. If you need * exhaustive customization of the calendar creation process feel free to * modify this code to suit your needs (this is recommended and much better * than modifying calendar.js itself). */ // $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $ /** * This function "patches" an input field (or other element) to use a calendar * widget for date selection. * * The "params" is a single object that can have the following properties: * * prop. name | description * ------------------------------------------------------------------------------------------------- * inputField | the ID of an input field to store the date * displayArea | the ID of a DIV or other element to show the date * button | ID of a button or other element that will trigger the calendar * eventName | event that will trigger the calendar, without the "on" prefix (default: "click") * ifFormat | date format that will be stored in the input field * daFormat | the date format that will be used to display the date in displayArea * singleClick | (true/false) wether the calendar is in single click mode or not (default: true) * firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc. * align | alignment (default: "Br"); if you don't know what's this see the calendar documentation * range | array with 2 elements. Default: [1900, 2999] -- the range of years available * weekNumbers | (true/false) if it's true (default) the calendar will display week numbers * flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID * flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar) * disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar * onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay) * onClose | function that gets called when the calendar is closed. [default] * onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar. * date | the date that the calendar will be initially displayed to * showsTime | default: false; if true the calendar will include a time selector * timeFormat | the time format; can be "12" or "24", default is "12" * electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close * step | configures the step of the years in drop-down boxes; default: 2 * position | configures the calendar absolute position; default: null * cache | if "true" (but default: "false") it will reuse the same calendar object, where possible * showOthers | if "true" (but default: "false") it will show days from other months too * * None of them is required, they all have default values. However, if you * pass none of "inputField", "displayArea" or "button" you'll get a warning * saying "nothing to setup". */ Calendar.setup = function (params) { function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } }; param_default("inputField", null); param_default("displayArea", null); param_default("button", null); param_default("eventName", "click"); param_default("ifFormat", "%Y/%m/%d"); param_default("daFormat", "%Y/%m/%d"); param_default("singleClick", true); param_default("disableFunc", null); param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined param_default("dateText", null); param_default("firstDay", null); param_default("align", "Br"); param_default("range", [1900, 2999]); param_default("weekNumbers", true); param_default("flat", null); param_default("flatCallback", null); param_default("onSelect", null); param_default("onClose", null); param_default("onUpdate", null); param_default("date", null); param_default("showsTime", false); param_default("timeFormat", "24"); param_default("electric", true); param_default("step", 2); param_default("position", null); param_default("cache", false); param_default("showOthers", false); param_default("multiple", null); var tmp = ["inputField", "displayArea", "button"]; for (var i in tmp) { if (typeof params[tmp[i]] == "string") { params[tmp[i]] = document.getElementById(params[tmp[i]]); } } if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) { alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code"); return false; } function onSelect(cal) { var p = cal.params; var update = (cal.dateClicked || p.electric); if (update && p.inputField) { p.inputField.value = cal.date.print(p.ifFormat); if (typeof p.inputField.onchange == "function") p.inputField.onchange(); } if (update && p.displayArea) p.displayArea.innerHTML = cal.date.print(p.daFormat); if (update && typeof p.onUpdate == "function") p.onUpdate(cal); if (update && p.flat) { if (typeof p.flatCallback == "function") p.flatCallback(cal); } if (update && p.singleClick && cal.dateClicked) cal.callCloseHandler(); }; if (params.flat != null) { if (typeof params.flat == "string") params.flat = document.getElementById(params.flat); if (!params.flat) { alert("Calendar.setup:\n Flat specified but can't find parent."); return false; } var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect); cal.showsOtherMonths = params.showOthers; cal.showsTime = params.showsTime; cal.time24 = (params.timeFormat == "24"); cal.params = params; cal.weekNumbers = params.weekNumbers; cal.setRange(params.range[0], params.range[1]); cal.setDateStatusHandler(params.dateStatusFunc); cal.getDateText = params.dateText; if (params.ifFormat) { cal.setDateFormat(params.ifFormat); } if (params.inputField && typeof params.inputField.value == "string") { cal.parseDate(params.inputField.value); } cal.create(params.flat); cal.show(); return false; } var triggerEl = params.button || params.displayArea || params.inputField; triggerEl["on" + params.eventName] = function() { var dateEl = params.inputField || params.displayArea; var dateFmt = params.inputField ? params.ifFormat : params.daFormat; var mustCreate = false; var cal = window.calendar; if (dateEl) params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt); if (!(cal && params.cache)) { window.calendar = cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect, params.onClose || function(cal) { cal.hide(); }); cal.showsTime = params.showsTime; cal.time24 = (params.timeFormat == "24"); cal.weekNumbers = params.weekNumbers; mustCreate = true; } else { if (params.date) cal.setDate(params.date); cal.hide(); } if (params.multiple) { cal.multiple = {}; for (var i = params.multiple.length; --i >= 0;) { var d = params.multiple[i]; var ds = d.print("%Y%m%d"); cal.multiple[ds] = d; } } cal.showsOtherMonths = params.showOthers; cal.yearStep = params.step; cal.setRange(params.range[0], params.range[1]); cal.params = params; cal.setDateStatusHandler(params.dateStatusFunc); cal.getDateText = params.dateText; cal.setDateFormat(dateFmt); if (mustCreate) cal.create(); cal.refresh(); if (!params.position) cal.showAtElement(params.button || params.displayArea || params.inputField, params.align); else cal.showAt(params.position[0], params.position[1]); return false; }; return cal; }; nurpawiki-1.2.4/files/jscalendar/calendar-setup_stripped.js000066400000000000000000000114671372046603600241360ustar00rootroot00000000000000/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/ * --------------------------------------------------------------------------- * * The DHTML Calendar * * Details and latest version at: * http://dynarch.com/mishoo/calendar.epl * * This script is distributed under the GNU Lesser General Public License. * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html * * This file defines helper functions for setting up the calendar. They are * intended to help non-programmers get a working calendar on their site * quickly. This script should not be seen as part of the calendar. It just * shows you what one can do with the calendar, while in the same time * providing a quick and simple method for setting it up. If you need * exhaustive customization of the calendar creation process feel free to * modify this code to suit your needs (this is recommended and much better * than modifying calendar.js itself). */ Calendar.setup=function(params){function param_default(pname,def){if(typeof params[pname]=="undefined"){params[pname]=def;}};param_default("inputField",null);param_default("displayArea",null);param_default("button",null);param_default("eventName","click");param_default("ifFormat","%Y/%m/%d");param_default("daFormat","%Y/%m/%d");param_default("singleClick",true);param_default("disableFunc",null);param_default("dateStatusFunc",params["disableFunc"]);param_default("dateText",null);param_default("firstDay",null);param_default("align","Br");param_default("range",[1900,2999]);param_default("weekNumbers",true);param_default("flat",null);param_default("flatCallback",null);param_default("onSelect",null);param_default("onClose",null);param_default("onUpdate",null);param_default("date",null);param_default("showsTime",false);param_default("timeFormat","24");param_default("electric",true);param_default("step",2);param_default("position",null);param_default("cache",false);param_default("showOthers",false);param_default("multiple",null);var tmp=["inputField","displayArea","button"];for(var i in tmp){if(typeof params[tmp[i]]=="string"){params[tmp[i]]=document.getElementById(params[tmp[i]]);}}if(!(params.flat||params.multiple||params.inputField||params.displayArea||params.button)){alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code");return false;}function onSelect(cal){var p=cal.params;var update=(cal.dateClicked||p.electric);if(update&&p.inputField){p.inputField.value=cal.date.print(p.ifFormat);if(typeof p.inputField.onchange=="function")p.inputField.onchange();}if(update&&p.displayArea)p.displayArea.innerHTML=cal.date.print(p.daFormat);if(update&&typeof p.onUpdate=="function")p.onUpdate(cal);if(update&&p.flat){if(typeof p.flatCallback=="function")p.flatCallback(cal);}if(update&&p.singleClick&&cal.dateClicked)cal.callCloseHandler();};if(params.flat!=null){if(typeof params.flat=="string")params.flat=document.getElementById(params.flat);if(!params.flat){alert("Calendar.setup:\n Flat specified but can't find parent.");return false;}var cal=new Calendar(params.firstDay,params.date,params.onSelect||onSelect);cal.showsOtherMonths=params.showOthers;cal.showsTime=params.showsTime;cal.time24=(params.timeFormat=="24");cal.params=params;cal.weekNumbers=params.weekNumbers;cal.setRange(params.range[0],params.range[1]);cal.setDateStatusHandler(params.dateStatusFunc);cal.getDateText=params.dateText;if(params.ifFormat){cal.setDateFormat(params.ifFormat);}if(params.inputField&&typeof params.inputField.value=="string"){cal.parseDate(params.inputField.value);}cal.create(params.flat);cal.show();return false;}var triggerEl=params.button||params.displayArea||params.inputField;triggerEl["on"+params.eventName]=function(){var dateEl=params.inputField||params.displayArea;var dateFmt=params.inputField?params.ifFormat:params.daFormat;var mustCreate=false;var cal=window.calendar;if(dateEl)params.date=Date.parseDate(dateEl.value||dateEl.innerHTML,dateFmt);if(!(cal&¶ms.cache)){window.calendar=cal=new Calendar(params.firstDay,params.date,params.onSelect||onSelect,params.onClose||function(cal){cal.hide();});cal.showsTime=params.showsTime;cal.time24=(params.timeFormat=="24");cal.weekNumbers=params.weekNumbers;mustCreate=true;}else{if(params.date)cal.setDate(params.date);cal.hide();}if(params.multiple){cal.multiple={};for(var i=params.multiple.length;--i>=0;){var d=params.multiple[i];var ds=d.print("%Y%m%d");cal.multiple[ds]=d;}}cal.showsOtherMonths=params.showOthers;cal.yearStep=params.step;cal.setRange(params.range[0],params.range[1]);cal.params=params;cal.setDateStatusHandler(params.dateStatusFunc);cal.getDateText=params.dateText;cal.setDateFormat(dateFmt);if(mustCreate)cal.create();cal.refresh();if(!params.position)cal.showAtElement(params.button||params.displayArea||params.inputField,params.align);else cal.showAt(params.position[0],params.position[1]);return false;};return cal;};nurpawiki-1.2.4/files/jscalendar/calendar-system.css000066400000000000000000000131131372046603600225520ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ .calendar { position: relative; display: none; border: 1px solid; border-color: #fff #000 #000 #fff; font-size: 11px; cursor: default; background: Window; color: WindowText; font-family: tahoma,verdana,sans-serif; } .calendar table { border: 1px solid; border-color: #fff #000 #000 #fff; font-size: 11px; cursor: default; background: Window; color: WindowText; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; padding: 1px; border: 1px solid; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; background: ButtonFace; } .calendar .nav { background: ButtonFace url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; padding: 1px; border: 1px solid #000; background: ActiveCaption; color: CaptionText; text-align: center; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .daynames { /* Row containing the day names */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid ButtonShadow; padding: 2px; text-align: center; background: ButtonFace; color: ButtonText; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ border: 2px solid; padding: 0px; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; } .calendar thead .active { /* Active (pressed) buttons in header */ border-width: 1px; padding: 2px 0px 0px 2px; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #aaa; } .calendar tbody .day.othermonth.oweekend { color: #faa; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid ButtonShadow; background: ButtonFace; color: ButtonText; } .calendar tbody .rowhilite td { background: Highlight; color: HighlightText; } .calendar tbody td.hilite { /* Hovered cells */ padding: 1px 3px 1px 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar tbody td.active { /* Active (pressed) cells */ padding: 2px 2px 0px 2px; border: 1px solid; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; } .calendar tbody td.selected { /* Cell showing selected date */ font-weight: bold; border: 1px solid; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; padding: 2px 2px 0px 2px; background: ButtonFace; color: ButtonText; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { /* Cell showing today date */ font-weight: bold; color: #00f; } .calendar tbody td.disabled { color: GrayText; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: ButtonFace; padding: 1px; border: 1px solid; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; color: ButtonText; text-align: center; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; padding: 1px; background: #e4e0d8; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; width: 4em; top: 0px; left: 0px; cursor: default; border: 1px solid; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; background: Menu; color: MenuText; font-size: 90%; padding: 1px; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .active { padding: 0px; border: 1px solid #000; } .calendar .combo .hilite { background: Highlight; color: HighlightText; } .calendar td.time { border-top: 1px solid ButtonShadow; padding: 1px 0px; text-align: center; background-color: ButtonFace; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: Menu; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: Highlight; color: HighlightText; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-tas.css000066400000000000000000000122751372046603600220250ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #655; font-size: 11px; color: #000; cursor: default; background: #ffd; font-family: tahoma,verdana,sans-serif; filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#DDDCCC,EndColorStr=#FFFFFF); } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ color:#363636; } .calendar .nav { background: #edc url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #654; color: #363636; padding: 2px; filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#ffffff,EndColorStr=#dddccc); } .calendar thead .headrow { /* Row containing navigation buttons */ /*background: #3B86A0;*/ color: #363636; font-weight: bold; filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#ffffff,EndColorStr=#3b86a0); } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #655; padding: 2px; text-align: center; color: #363636; filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#DDDCCC,EndColorStr=#FFFFFF); } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background-color: #ffcc86; color: #000; border: 1px solid #b59345; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background-color: #c77; padding: 2px 0px 0px 2px; } .calendar thead .daynames { /* Row containing the day names */ background: #fed; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #aaa; } .calendar tbody .day.othermonth.oweekend { color: #faa; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #fed; } .calendar tbody .rowhilite td { background: #ddf; } .calendar tbody .rowhilite td.wn { background: #efe; } .calendar tbody td.hilite { /* Hovered cells */ background: #ffe; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ background: #ddc; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #fea; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { font-weight: bold; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #988; color: #000; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ border-top: 1px solid #655; background: #dcb; color: #363636; font-weight: bold; filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#FFFFFF,EndColorStr=#DDDCCC); } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #faa; border: 1px solid #f40; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #c77; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #655; background: #ffe; color: #000; font-size: smaller; z-index: 100; } .combo .label, .combo .label-IEfix { text-align: center; padding: 1px; } .combo .label-IEfix { width: 4em; } .combo .hilite { background: #fc8; } .combo .active { border-top: 1px solid #a64; border-bottom: 1px solid #a64; background: #fee; font-weight: bold; } .calendar td.time { border-top: 1px solid #a88; padding: 1px 0px; text-align: center; background-color: #fed; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #988; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #866; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-win2k-1.css000066400000000000000000000135421372046603600224240ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ .calendar { position: relative; display: none; border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; font-size: 11px; color: #000; cursor: default; background: #d4d0c8; font-family: tahoma,verdana,sans-serif; } .calendar table { border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; font-size: 11px; color: #000; cursor: default; background: #d4d0c8; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; padding: 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar .nav { background: transparent url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; padding: 1px; border: 1px solid #000; background: #848078; color: #fff; text-align: center; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .daynames { /* Row containing the day names */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #000; padding: 2px; text-align: center; background: #f4f0e8; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; padding: 0px; background-color: #e4e0d8; } .calendar thead .active { /* Active (pressed) buttons in header */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; background-color: #c4c0b8; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #aaa; } .calendar tbody .day.othermonth.oweekend { color: #faa; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #f4f0e8; } .calendar tbody .rowhilite td { background: #e4e0d8; } .calendar tbody .rowhilite td.wn { background: #d4d0c8; } .calendar tbody td.hilite { /* Hovered cells */ padding: 1px 3px 1px 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar tbody td.active { /* Active (pressed) cells */ padding: 2px 2px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar tbody td.selected { /* Cell showing selected date */ font-weight: bold; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; padding: 2px 2px 0px 2px; background: #e4e0d8; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { /* Cell showing today date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #f4f0e8; padding: 1px; border: 1px solid #000; background: #848078; color: #fff; text-align: center; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; padding: 1px; background: #e4e0d8; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; width: 4em; top: 0px; left: 0px; cursor: default; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; background: #e4e0d8; font-size: 90%; padding: 1px; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .active { background: #c4c0b8; padding: 0px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar .combo .hilite { background: #048; color: #fea; } .calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #f4f0e8; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #766; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-win2k-2.css000066400000000000000000000135421372046603600224250ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ .calendar { position: relative; display: none; border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; font-size: 11px; color: #000; cursor: default; background: #d4c8d0; font-family: tahoma,verdana,sans-serif; } .calendar table { border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; font-size: 11px; color: #000; cursor: default; background: #d4c8d0; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; padding: 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar .nav { background: transparent url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; padding: 1px; border: 1px solid #000; background: #847880; color: #fff; text-align: center; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .daynames { /* Row containing the day names */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #000; padding: 2px; text-align: center; background: #f4e8f0; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; padding: 0px; background-color: #e4d8e0; } .calendar thead .active { /* Active (pressed) buttons in header */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; background-color: #c4b8c0; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #aaa; } .calendar tbody .day.othermonth.oweekend { color: #faa; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #f4e8f0; } .calendar tbody .rowhilite td { background: #e4d8e0; } .calendar tbody .rowhilite td.wn { background: #d4c8d0; } .calendar tbody td.hilite { /* Hovered cells */ padding: 1px 3px 1px 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar tbody td.active { /* Active (pressed) cells */ padding: 2px 2px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar tbody td.selected { /* Cell showing selected date */ font-weight: bold; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; padding: 2px 2px 0px 2px; background: #e4d8e0; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { /* Cell showing today date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #f4e8f0; padding: 1px; border: 1px solid #000; background: #847880; color: #fff; text-align: center; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; padding: 1px; background: #e4d8e0; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; width: 4em; top: 0px; left: 0px; cursor: default; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; background: #e4d8e0; font-size: 90%; padding: 1px; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .active { background: #d4c8d0; padding: 0px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar .combo .hilite { background: #408; color: #fea; } .calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #f4f0e8; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #766; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-win2k-cold-1.css000066400000000000000000000132261372046603600233420ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ .calendar { position: relative; display: none; border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; font-size: 11px; color: #000; cursor: default; background: #c8d0d4; font-family: tahoma,verdana,sans-serif; } .calendar table { border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; font-size: 11px; color: #000; cursor: default; background: #c8d0d4; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; padding: 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar .nav { background: transparent url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; padding: 1px; border: 1px solid #000; background: #788084; color: #fff; text-align: center; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .daynames { /* Row containing the day names */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #000; padding: 2px; text-align: center; background: #e8f0f4; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; padding: 0px; background-color: #d8e0e4; } .calendar thead .active { /* Active (pressed) buttons in header */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; background-color: #b8c0c4; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #aaa; } .calendar tbody .day.othermonth.oweekend { color: #faa; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #e8f4f0; } .calendar tbody .rowhilite td { background: #d8e4e0; } .calendar tbody .rowhilite td.wn { background: #c8d4d0; } .calendar tbody td.hilite { /* Hovered cells */ padding: 1px 3px 1px 1px; border: 1px solid; border-color: #fff #000 #000 #fff; } .calendar tbody td.active { /* Active (pressed) cells */ padding: 2px 2px 0px 2px; border: 1px solid; border-color: #000 #fff #fff #000; } .calendar tbody td.selected { /* Cell showing selected date */ font-weight: bold; padding: 2px 2px 0px 2px; border: 1px solid; border-color: #000 #fff #fff #000; background: #d8e0e4; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { /* Cell showing today date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #e8f0f4; padding: 1px; border: 1px solid #000; background: #788084; color: #fff; text-align: center; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; padding: 1px; background: #d8e0e4; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; width: 4em; top: 0px; left: 0px; cursor: default; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; background: #d8e0e4; font-size: 90%; padding: 1px; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .active { background: #c8d0d4; padding: 0px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar .combo .hilite { background: #048; color: #aef; } .calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #e8f0f4; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #667; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar-win2k-cold-2.css000066400000000000000000000135421372046603600233440ustar00rootroot00000000000000/* The main calendar widget. DIV containing a table. */ .calendar { position: relative; display: none; border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; font-size: 11px; color: #000; cursor: default; background: #c8d4d0; font-family: tahoma,verdana,sans-serif; } .calendar table { border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; font-size: 11px; color: #000; cursor: default; background: #c8d4d0; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; padding: 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar .nav { background: transparent url(menuarrow.gif) no-repeat 100% 100%; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; padding: 1px; border: 1px solid #000; background: #788480; color: #fff; text-align: center; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .daynames { /* Row containing the day names */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #000; padding: 2px; text-align: center; background: #e8f4f0; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #f00; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ border-top: 2px solid #fff; border-right: 2px solid #000; border-bottom: 2px solid #000; border-left: 2px solid #fff; padding: 0px; background-color: #d8e4e0; } .calendar thead .active { /* Active (pressed) buttons in header */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; background-color: #b8c4c0; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #aaa; } .calendar tbody .day.othermonth.oweekend { color: #faa; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #e8f4f0; } .calendar tbody .rowhilite td { background: #d8e4e0; } .calendar tbody .rowhilite td.wn { background: #c8d4d0; } .calendar tbody td.hilite { /* Hovered cells */ padding: 1px 3px 1px 1px; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; } .calendar tbody td.active { /* Active (pressed) cells */ padding: 2px 2px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar tbody td.selected { /* Cell showing selected date */ font-weight: bold; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; padding: 2px 2px 0px 2px; background: #d8e4e0; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #f00; } .calendar tbody td.today { /* Cell showing today date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #e8f4f0; padding: 1px; border: 1px solid #000; background: #788480; color: #fff; text-align: center; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; padding: 1px; background: #d8e4e0; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ padding: 2px 0px 0px 2px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; width: 4em; top: 0px; left: 0px; cursor: default; border-top: 1px solid #fff; border-right: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #fff; background: #d8e4e0; font-size: 90%; padding: 1px; z-index: 100; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .active { background: #c8d4d0; padding: 0px; border-top: 1px solid #000; border-right: 1px solid #fff; border-bottom: 1px solid #fff; border-left: 1px solid #000; } .calendar .combo .hilite { background: #048; color: #aef; } .calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #e8f0f4; } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #fff; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { border-color: #000; background-color: #667; color: #fff; } .calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; } nurpawiki-1.2.4/files/jscalendar/calendar.js000066400000000000000000001401251372046603600210600ustar00rootroot00000000000000/* Copyright Mihai Bazon, 2002-2005 | www.bazon.net/mishoo * ----------------------------------------------------------- * * The DHTML Calendar, version 1.0 "It is happening again" * * Details and latest version at: * www.dynarch.com/projects/calendar * * This script is developed by Dynarch.com. Visit us at www.dynarch.com. * * This script is distributed under the GNU Lesser General Public License. * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html */ // $Id: calendar.js,v 1.51 2005/03/07 16:44:31 mishoo Exp $ /** The Calendar object constructor. */ Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) { // member variables this.activeDiv = null; this.currentDateEl = null; this.getDateStatus = null; this.getDateToolTip = null; this.getDateText = null; this.timeout = null; this.onSelected = onSelected || null; this.onClose = onClose || null; this.dragging = false; this.hidden = false; this.minYear = 1970; this.maxYear = 2050; this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"]; this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"]; this.isPopup = true; this.weekNumbers = true; this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc. this.showsOtherMonths = false; this.dateStr = dateStr; this.ar_days = null; this.showsTime = false; this.time24 = true; this.yearStep = 2; this.hiliteToday = true; this.multiple = null; // HTML elements this.table = null; this.element = null; this.tbody = null; this.firstdayname = null; // Combo boxes this.monthsCombo = null; this.yearsCombo = null; this.hilitedMonth = null; this.activeMonth = null; this.hilitedYear = null; this.activeYear = null; // Information this.dateClicked = false; // one-time initializations if (typeof Calendar._SDN == "undefined") { // table of short day names if (typeof Calendar._SDN_len == "undefined") Calendar._SDN_len = 3; var ar = new Array(); for (var i = 8; i > 0;) { ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len); } Calendar._SDN = ar; // table of short month names if (typeof Calendar._SMN_len == "undefined") Calendar._SMN_len = 3; ar = new Array(); for (var i = 12; i > 0;) { ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len); } Calendar._SMN = ar; } }; // ** constants /// "static", needed for event handlers. Calendar._C = null; /// detect a special case of "web browser" Calendar.is_ie = ( /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) ); Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) ); /// detect Opera browser Calendar.is_opera = /opera/i.test(navigator.userAgent); /// detect KHTML-based browsers Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent); // BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate // library, at some point. Calendar.getAbsolutePos = function(el) { var SL = 0, ST = 0; var is_div = /^div$/i.test(el.tagName); if (is_div && el.scrollLeft) SL = el.scrollLeft; if (is_div && el.scrollTop) ST = el.scrollTop; var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST }; if (el.offsetParent) { var tmp = this.getAbsolutePos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; Calendar.isRelated = function (el, evt) { var related = evt.relatedTarget; if (!related) { var type = evt.type; if (type == "mouseover") { related = evt.fromElement; } else if (type == "mouseout") { related = evt.toElement; } } while (related) { if (related == el) { return true; } related = related.parentNode; } return false; }; Calendar.removeClass = function(el, className) { if (!(el && el.className)) { return; } var cls = el.className.split(" "); var ar = new Array(); for (var i = cls.length; i > 0;) { if (cls[--i] != className) { ar[ar.length] = cls[i]; } } el.className = ar.join(" "); }; Calendar.addClass = function(el, className) { Calendar.removeClass(el, className); el.className += " " + className; }; // FIXME: the following 2 functions totally suck, are useless and should be replaced immediately. Calendar.getElement = function(ev) { var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget; while (f.nodeType != 1 || /^div$/i.test(f.tagName)) f = f.parentNode; return f; }; Calendar.getTargetElement = function(ev) { var f = Calendar.is_ie ? window.event.srcElement : ev.target; while (f.nodeType != 1) f = f.parentNode; return f; }; Calendar.stopEvent = function(ev) { ev || (ev = window.event); if (Calendar.is_ie) { ev.cancelBubble = true; ev.returnValue = false; } else { ev.preventDefault(); ev.stopPropagation(); } return false; }; Calendar.addEvent = function(el, evname, func) { if (el.attachEvent) { // IE el.attachEvent("on" + evname, func); } else if (el.addEventListener) { // Gecko / W3C el.addEventListener(evname, func, true); } else { el["on" + evname] = func; } }; Calendar.removeEvent = function(el, evname, func) { if (el.detachEvent) { // IE el.detachEvent("on" + evname, func); } else if (el.removeEventListener) { // Gecko / W3C el.removeEventListener(evname, func, true); } else { el["on" + evname] = null; } }; Calendar.createElement = function(type, parent) { var el = null; if (document.createElementNS) { // use the XHTML namespace; IE won't normally get here unless // _they_ "fix" the DOM2 implementation. el = document.createElementNS("http://www.w3.org/1999/xhtml", type); } else { el = document.createElement(type); } if (typeof parent != "undefined") { parent.appendChild(el); } return el; }; // END: UTILITY FUNCTIONS // BEGIN: CALENDAR STATIC FUNCTIONS /** Internal -- adds a set of events to make some element behave like a button. */ Calendar._add_evs = function(el) { with (Calendar) { addEvent(el, "mouseover", dayMouseOver); addEvent(el, "mousedown", dayMouseDown); addEvent(el, "mouseout", dayMouseOut); if (is_ie) { addEvent(el, "dblclick", dayMouseDblClick); el.setAttribute("unselectable", true); } } }; Calendar.findMonth = function(el) { if (typeof el.month != "undefined") { return el; } else if (typeof el.parentNode.month != "undefined") { return el.parentNode; } return null; }; Calendar.findYear = function(el) { if (typeof el.year != "undefined") { return el; } else if (typeof el.parentNode.year != "undefined") { return el.parentNode; } return null; }; Calendar.showMonthsCombo = function () { var cal = Calendar._C; if (!cal) { return false; } var cal = cal; var cd = cal.activeDiv; var mc = cal.monthsCombo; if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } if (cal.activeMonth) { Calendar.removeClass(cal.activeMonth, "active"); } var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()]; Calendar.addClass(mon, "active"); cal.activeMonth = mon; var s = mc.style; s.display = "block"; if (cd.navtype < 0) s.left = cd.offsetLeft + "px"; else { var mcw = mc.offsetWidth; if (typeof mcw == "undefined") // Konqueror brain-dead techniques mcw = 50; s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px"; } s.top = (cd.offsetTop + cd.offsetHeight) + "px"; }; Calendar.showYearsCombo = function (fwd) { var cal = Calendar._C; if (!cal) { return false; } var cal = cal; var cd = cal.activeDiv; var yc = cal.yearsCombo; if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } if (cal.activeYear) { Calendar.removeClass(cal.activeYear, "active"); } cal.activeYear = null; var Y = cal.date.getFullYear() + (fwd ? 1 : -1); var yr = yc.firstChild; var show = false; for (var i = 12; i > 0; --i) { if (Y >= cal.minYear && Y <= cal.maxYear) { yr.innerHTML = Y; yr.year = Y; yr.style.display = "block"; show = true; } else { yr.style.display = "none"; } yr = yr.nextSibling; Y += fwd ? cal.yearStep : -cal.yearStep; } if (show) { var s = yc.style; s.display = "block"; if (cd.navtype < 0) s.left = cd.offsetLeft + "px"; else { var ycw = yc.offsetWidth; if (typeof ycw == "undefined") // Konqueror brain-dead techniques ycw = 50; s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px"; } s.top = (cd.offsetTop + cd.offsetHeight) + "px"; } }; // event handlers Calendar.tableMouseUp = function(ev) { var cal = Calendar._C; if (!cal) { return false; } if (cal.timeout) { clearTimeout(cal.timeout); } var el = cal.activeDiv; if (!el) { return false; } var target = Calendar.getTargetElement(ev); ev || (ev = window.event); Calendar.removeClass(el, "active"); if (target == el || target.parentNode == el) { Calendar.cellClick(el, ev); } var mon = Calendar.findMonth(target); var date = null; if (mon) { date = new Date(cal.date); if (mon.month != date.getMonth()) { date.setMonth(mon.month); cal.setDate(date); cal.dateClicked = false; cal.callHandler(); } } else { var year = Calendar.findYear(target); if (year) { date = new Date(cal.date); if (year.year != date.getFullYear()) { date.setFullYear(year.year); cal.setDate(date); cal.dateClicked = false; cal.callHandler(); } } } with (Calendar) { removeEvent(document, "mouseup", tableMouseUp); removeEvent(document, "mouseover", tableMouseOver); removeEvent(document, "mousemove", tableMouseOver); cal._hideCombos(); _C = null; return stopEvent(ev); } }; Calendar.tableMouseOver = function (ev) { var cal = Calendar._C; if (!cal) { return; } var el = cal.activeDiv; var target = Calendar.getTargetElement(ev); if (target == el || target.parentNode == el) { Calendar.addClass(el, "hilite active"); Calendar.addClass(el.parentNode, "rowhilite"); } else { if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2))) Calendar.removeClass(el, "active"); Calendar.removeClass(el, "hilite"); Calendar.removeClass(el.parentNode, "rowhilite"); } ev || (ev = window.event); if (el.navtype == 50 && target != el) { var pos = Calendar.getAbsolutePos(el); var w = el.offsetWidth; var x = ev.clientX; var dx; var decrease = true; if (x > pos.x + w) { dx = x - pos.x - w; decrease = false; } else dx = pos.x - x; if (dx < 0) dx = 0; var range = el._range; var current = el._current; var count = Math.floor(dx / 10) % range.length; for (var i = range.length; --i >= 0;) if (range[i] == current) break; while (count-- > 0) if (decrease) { if (--i < 0) i = range.length - 1; } else if ( ++i >= range.length ) i = 0; var newval = range[i]; el.innerHTML = newval; cal.onUpdateTime(); } var mon = Calendar.findMonth(target); if (mon) { if (mon.month != cal.date.getMonth()) { if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } Calendar.addClass(mon, "hilite"); cal.hilitedMonth = mon; } else if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } } else { if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } var year = Calendar.findYear(target); if (year) { if (year.year != cal.date.getFullYear()) { if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } Calendar.addClass(year, "hilite"); cal.hilitedYear = year; } else if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } } else if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } } return Calendar.stopEvent(ev); }; Calendar.tableMouseDown = function (ev) { if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) { return Calendar.stopEvent(ev); } }; Calendar.calDragIt = function (ev) { var cal = Calendar._C; if (!(cal && cal.dragging)) { return false; } var posX; var posY; if (Calendar.is_ie) { posY = window.event.clientY + document.body.scrollTop; posX = window.event.clientX + document.body.scrollLeft; } else { posX = ev.pageX; posY = ev.pageY; } cal.hideShowCovered(); var st = cal.element.style; st.left = (posX - cal.xOffs) + "px"; st.top = (posY - cal.yOffs) + "px"; return Calendar.stopEvent(ev); }; Calendar.calDragEnd = function (ev) { var cal = Calendar._C; if (!cal) { return false; } cal.dragging = false; with (Calendar) { removeEvent(document, "mousemove", calDragIt); removeEvent(document, "mouseup", calDragEnd); tableMouseUp(ev); } cal.hideShowCovered(); }; Calendar.dayMouseDown = function(ev) { var el = Calendar.getElement(ev); if (el.disabled) { return false; } var cal = el.calendar; cal.activeDiv = el; Calendar._C = cal; if (el.navtype != 300) with (Calendar) { if (el.navtype == 50) { el._current = el.innerHTML; addEvent(document, "mousemove", tableMouseOver); } else addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver); addClass(el, "hilite active"); addEvent(document, "mouseup", tableMouseUp); } else if (cal.isPopup) { cal._dragStart(ev); } if (el.navtype == -1 || el.navtype == 1) { if (cal.timeout) clearTimeout(cal.timeout); cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250); } else if (el.navtype == -2 || el.navtype == 2) { if (cal.timeout) clearTimeout(cal.timeout); cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250); } else { cal.timeout = null; } return Calendar.stopEvent(ev); }; Calendar.dayMouseDblClick = function(ev) { Calendar.cellClick(Calendar.getElement(ev), ev || window.event); if (Calendar.is_ie) { document.selection.empty(); } }; Calendar.dayMouseOver = function(ev) { var el = Calendar.getElement(ev); if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) { return false; } if (el.ttip) { if (el.ttip.substr(0, 1) == "_") { el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1); } el.calendar.tooltips.innerHTML = el.ttip; } if (el.navtype != 300) { Calendar.addClass(el, "hilite"); if (el.caldate) { Calendar.addClass(el.parentNode, "rowhilite"); } } return Calendar.stopEvent(ev); }; Calendar.dayMouseOut = function(ev) { with (Calendar) { var el = getElement(ev); if (isRelated(el, ev) || _C || el.disabled) return false; removeClass(el, "hilite"); if (el.caldate) removeClass(el.parentNode, "rowhilite"); if (el.calendar) el.calendar.tooltips.innerHTML = _TT["SEL_DATE"]; return stopEvent(ev); } }; /** * A generic "click" handler :) handles all types of buttons defined in this * calendar. */ Calendar.cellClick = function(el, ev) { var cal = el.calendar; var closing = false; var newdate = false; var date = null; if (typeof el.navtype == "undefined") { if (cal.currentDateEl) { Calendar.removeClass(cal.currentDateEl, "selected"); Calendar.addClass(el, "selected"); closing = (cal.currentDateEl == el); if (!closing) { cal.currentDateEl = el; } } cal.date.setDateOnly(el.caldate); date = cal.date; var other_month = !(cal.dateClicked = !el.otherMonth); if (!other_month && !cal.currentDateEl) cal._toggleMultipleDate(new Date(date)); else newdate = !el.disabled; // a date was clicked if (other_month) cal._init(cal.firstDayOfWeek, date); } else { if (el.navtype == 200) { Calendar.removeClass(el, "hilite"); cal.callCloseHandler(); return; } date = new Date(cal.date); if (el.navtype == 0) date.setDateOnly(new Date()); // TODAY // unless "today" was clicked, we assume no date was clicked so // the selected handler will know not to close the calenar when // in single-click mode. // cal.dateClicked = (el.navtype == 0); cal.dateClicked = false; var year = date.getFullYear(); var mon = date.getMonth(); function setMonth(m) { var day = date.getDate(); var max = date.getMonthDays(m); if (day > max) { date.setDate(max); } date.setMonth(m); }; switch (el.navtype) { case 400: Calendar.removeClass(el, "hilite"); var text = Calendar._TT["ABOUT"]; if (typeof text != "undefined") { text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : ""; } else { // FIXME: this should be removed as soon as lang files get updated! text = "Help and about box text is not translated into this language.\n" + "If you know this language and you feel generous please update\n" + "the corresponding file in \"lang\" subdir to match calendar-en.js\n" + "and send it back to to get it into the distribution ;-)\n\n" + "Thank you!\n" + "http://dynarch.com/mishoo/calendar.epl\n"; } alert(text); return; case -2: if (year > cal.minYear) { date.setFullYear(year - 1); } break; case -1: if (mon > 0) { setMonth(mon - 1); } else if (year-- > cal.minYear) { date.setFullYear(year); setMonth(11); } break; case 1: if (mon < 11) { setMonth(mon + 1); } else if (year < cal.maxYear) { date.setFullYear(year + 1); setMonth(0); } break; case 2: if (year < cal.maxYear) { date.setFullYear(year + 1); } break; case 100: cal.setFirstDayOfWeek(el.fdow); return; case 50: var range = el._range; var current = el.innerHTML; for (var i = range.length; --i >= 0;) if (range[i] == current) break; if (ev && ev.shiftKey) { if (--i < 0) i = range.length - 1; } else if ( ++i >= range.length ) i = 0; var newval = range[i]; el.innerHTML = newval; cal.onUpdateTime(); return; case 0: // TODAY will bring us here if ((typeof cal.getDateStatus == "function") && cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) { return false; } break; } if (!date.equalsTo(cal.date)) { cal.setDate(date); newdate = true; } else if (el.navtype == 0) newdate = closing = true; } if (newdate) { ev && cal.callHandler(); } if (closing) { Calendar.removeClass(el, "hilite"); ev && cal.callCloseHandler(); } }; // END: CALENDAR STATIC FUNCTIONS // BEGIN: CALENDAR OBJECT FUNCTIONS /** * This function creates the calendar inside the given parent. If _par is * null than it creates a popup calendar inside the BODY element. If _par is * an element, be it BODY, then it creates a non-popup calendar (still * hidden). Some properties need to be set before calling this function. */ Calendar.prototype.create = function (_par) { var parent = null; if (! _par) { // default parent is the document body, in which case we create // a popup calendar. parent = document.getElementsByTagName("body")[0]; this.isPopup = true; } else { parent = _par; this.isPopup = false; } this.date = this.dateStr ? new Date(this.dateStr) : new Date(); var table = Calendar.createElement("table"); this.table = table; table.cellSpacing = 0; table.cellPadding = 0; table.calendar = this; Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown); var div = Calendar.createElement("div"); this.element = div; div.className = "calendar"; if (this.isPopup) { div.style.position = "absolute"; div.style.display = "none"; } div.appendChild(table); var thead = Calendar.createElement("thead", table); var cell = null; var row = null; var cal = this; var hh = function (text, cs, navtype) { cell = Calendar.createElement("td", row); cell.colSpan = cs; cell.className = "button"; if (navtype != 0 && Math.abs(navtype) <= 2) cell.className += " nav"; Calendar._add_evs(cell); cell.calendar = cal; cell.navtype = navtype; cell.innerHTML = "
" + text + "
"; return cell; }; row = Calendar.createElement("tr", thead); var title_length = 6; (this.isPopup) && --title_length; (this.weekNumbers) && ++title_length; hh("?", 1, 400).ttip = Calendar._TT["INFO"]; this.title = hh("", title_length, 300); this.title.className = "title"; if (this.isPopup) { this.title.ttip = Calendar._TT["DRAG_TO_MOVE"]; this.title.style.cursor = "move"; hh("×", 1, 200).ttip = Calendar._TT["CLOSE"]; } row = Calendar.createElement("tr", thead); row.className = "headrow"; this._nav_py = hh("«", 1, -2); this._nav_py.ttip = Calendar._TT["PREV_YEAR"]; this._nav_pm = hh("‹", 1, -1); this._nav_pm.ttip = Calendar._TT["PREV_MONTH"]; this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0); this._nav_now.ttip = Calendar._TT["GO_TODAY"]; this._nav_nm = hh("›", 1, 1); this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"]; this._nav_ny = hh("»", 1, 2); this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"]; // day names row = Calendar.createElement("tr", thead); row.className = "daynames"; if (this.weekNumbers) { cell = Calendar.createElement("td", row); cell.className = "name wn"; cell.innerHTML = Calendar._TT["WK"]; } for (var i = 7; i > 0; --i) { cell = Calendar.createElement("td", row); if (!i) { cell.navtype = 100; cell.calendar = this; Calendar._add_evs(cell); } } this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild; this._displayWeekdays(); var tbody = Calendar.createElement("tbody", table); this.tbody = tbody; for (i = 6; i > 0; --i) { row = Calendar.createElement("tr", tbody); if (this.weekNumbers) { cell = Calendar.createElement("td", row); } for (var j = 7; j > 0; --j) { cell = Calendar.createElement("td", row); cell.calendar = this; Calendar._add_evs(cell); } } if (this.showsTime) { row = Calendar.createElement("tr", tbody); row.className = "time"; cell = Calendar.createElement("td", row); cell.className = "time"; cell.colSpan = 2; cell.innerHTML = Calendar._TT["TIME"] || " "; cell = Calendar.createElement("td", row); cell.className = "time"; cell.colSpan = this.weekNumbers ? 4 : 3; (function(){ function makeTimePart(className, init, range_start, range_end) { var part = Calendar.createElement("span", cell); part.className = className; part.innerHTML = init; part.calendar = cal; part.ttip = Calendar._TT["TIME_PART"]; part.navtype = 50; part._range = []; if (typeof range_start != "number") part._range = range_start; else { for (var i = range_start; i <= range_end; ++i) { var txt; if (i < 10 && range_end >= 10) txt = '0' + i; else txt = '' + i; part._range[part._range.length] = txt; } } Calendar._add_evs(part); return part; }; var hrs = cal.date.getHours(); var mins = cal.date.getMinutes(); var t12 = !cal.time24; var pm = (hrs > 12); if (t12 && pm) hrs -= 12; var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23); var span = Calendar.createElement("span", cell); span.innerHTML = ":"; span.className = "colon"; var M = makeTimePart("minute", mins, 0, 59); var AP = null; cell = Calendar.createElement("td", row); cell.className = "time"; cell.colSpan = 2; if (t12) AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]); else cell.innerHTML = " "; cal.onSetTime = function() { var pm, hrs = this.date.getHours(), mins = this.date.getMinutes(); if (t12) { pm = (hrs >= 12); if (pm) hrs -= 12; if (hrs == 0) hrs = 12; AP.innerHTML = pm ? "pm" : "am"; } H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs; M.innerHTML = (mins < 10) ? ("0" + mins) : mins; }; cal.onUpdateTime = function() { var date = this.date; var h = parseInt(H.innerHTML, 10); if (t12) { if (/pm/i.test(AP.innerHTML) && h < 12) h += 12; else if (/am/i.test(AP.innerHTML) && h == 12) h = 0; } var d = date.getDate(); var m = date.getMonth(); var y = date.getFullYear(); date.setHours(h); date.setMinutes(parseInt(M.innerHTML, 10)); date.setFullYear(y); date.setMonth(m); date.setDate(d); this.dateClicked = false; this.callHandler(); }; })(); } else { this.onSetTime = this.onUpdateTime = function() {}; } var tfoot = Calendar.createElement("tfoot", table); row = Calendar.createElement("tr", tfoot); row.className = "footrow"; cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300); cell.className = "ttip"; if (this.isPopup) { cell.ttip = Calendar._TT["DRAG_TO_MOVE"]; cell.style.cursor = "move"; } this.tooltips = cell; div = Calendar.createElement("div", this.element); this.monthsCombo = div; div.className = "combo"; for (i = 0; i < Calendar._MN.length; ++i) { var mn = Calendar.createElement("div"); mn.className = Calendar.is_ie ? "label-IEfix" : "label"; mn.month = i; mn.innerHTML = Calendar._SMN[i]; div.appendChild(mn); } div = Calendar.createElement("div", this.element); this.yearsCombo = div; div.className = "combo"; for (i = 12; i > 0; --i) { var yr = Calendar.createElement("div"); yr.className = Calendar.is_ie ? "label-IEfix" : "label"; div.appendChild(yr); } this._init(this.firstDayOfWeek, this.date); parent.appendChild(this.element); }; /** keyboard navigation, only for popup calendars */ Calendar._keyEvent = function(ev) { var cal = window._dynarch_popupCalendar; if (!cal || cal.multiple) return false; (Calendar.is_ie) && (ev = window.event); var act = (Calendar.is_ie || ev.type == "keypress"), K = ev.keyCode; if (ev.ctrlKey) { switch (K) { case 37: // KEY left act && Calendar.cellClick(cal._nav_pm); break; case 38: // KEY up act && Calendar.cellClick(cal._nav_py); break; case 39: // KEY right act && Calendar.cellClick(cal._nav_nm); break; case 40: // KEY down act && Calendar.cellClick(cal._nav_ny); break; default: return false; } } else switch (K) { case 32: // KEY space (now) Calendar.cellClick(cal._nav_now); break; case 27: // KEY esc act && cal.callCloseHandler(); break; case 37: // KEY left case 38: // KEY up case 39: // KEY right case 40: // KEY down if (act) { var prev, x, y, ne, el, step; prev = K == 37 || K == 38; step = (K == 37 || K == 39) ? 1 : 7; function setVars() { el = cal.currentDateEl; var p = el.pos; x = p & 15; y = p >> 4; ne = cal.ar_days[y][x]; };setVars(); function prevMonth() { var date = new Date(cal.date); date.setDate(date.getDate() - step); cal.setDate(date); }; function nextMonth() { var date = new Date(cal.date); date.setDate(date.getDate() + step); cal.setDate(date); }; while (1) { switch (K) { case 37: // KEY left if (--x >= 0) ne = cal.ar_days[y][x]; else { x = 6; K = 38; continue; } break; case 38: // KEY up if (--y >= 0) ne = cal.ar_days[y][x]; else { prevMonth(); setVars(); } break; case 39: // KEY right if (++x < 7) ne = cal.ar_days[y][x]; else { x = 0; K = 40; continue; } break; case 40: // KEY down if (++y < cal.ar_days.length) ne = cal.ar_days[y][x]; else { nextMonth(); setVars(); } break; } break; } if (ne) { if (!ne.disabled) Calendar.cellClick(ne); else if (prev) prevMonth(); else nextMonth(); } } break; case 13: // KEY enter if (act) Calendar.cellClick(cal.currentDateEl, ev); break; default: return false; } return Calendar.stopEvent(ev); }; /** * (RE)Initializes the calendar to the given date and firstDayOfWeek */ Calendar.prototype._init = function (firstDayOfWeek, date) { var today = new Date(), TY = today.getFullYear(), TM = today.getMonth(), TD = today.getDate(); this.table.style.visibility = "hidden"; var year = date.getFullYear(); if (year < this.minYear) { year = this.minYear; date.setFullYear(year); } else if (year > this.maxYear) { year = this.maxYear; date.setFullYear(year); } this.firstDayOfWeek = firstDayOfWeek; this.date = new Date(date); var month = date.getMonth(); var mday = date.getDate(); var no_days = date.getMonthDays(); // calendar voodoo for computing the first day that would actually be // displayed in the calendar, even if it's from the previous month. // WARNING: this is magic. ;-) date.setDate(1); var day1 = (date.getDay() - this.firstDayOfWeek) % 7; if (day1 < 0) day1 += 7; date.setDate(-day1); date.setDate(date.getDate() + 1); var row = this.tbody.firstChild; var MN = Calendar._SMN[month]; var ar_days = this.ar_days = new Array(); var weekend = Calendar._TT["WEEKEND"]; var dates = this.multiple ? (this.datesCells = {}) : null; for (var i = 0; i < 6; ++i, row = row.nextSibling) { var cell = row.firstChild; if (this.weekNumbers) { cell.className = "day wn"; cell.innerHTML = date.getWeekNumber(); cell = cell.nextSibling; } row.className = "daysrow"; var hasdays = false, iday, dpos = ar_days[i] = []; for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) { iday = date.getDate(); var wday = date.getDay(); cell.className = "day"; cell.pos = i << 4 | j; dpos[j] = cell; var current_month = (date.getMonth() == month); if (!current_month) { if (this.showsOtherMonths) { cell.className += " othermonth"; cell.otherMonth = true; } else { cell.className = "emptycell"; cell.innerHTML = " "; cell.disabled = true; continue; } } else { cell.otherMonth = false; hasdays = true; } cell.disabled = false; cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday; if (dates) dates[date.print("%Y%m%d")] = cell; if (this.getDateStatus) { var status = this.getDateStatus(date, year, month, iday); if (this.getDateToolTip) { var toolTip = this.getDateToolTip(date, year, month, iday); if (toolTip) cell.title = toolTip; } if (status === true) { cell.className += " disabled"; cell.disabled = true; } else { if (/disabled/i.test(status)) cell.disabled = true; cell.className += " " + status; } } if (!cell.disabled) { cell.caldate = new Date(date); cell.ttip = "_"; if (!this.multiple && current_month && iday == mday && this.hiliteToday) { cell.className += " selected"; this.currentDateEl = cell; } if (date.getFullYear() == TY && date.getMonth() == TM && iday == TD) { cell.className += " today"; cell.ttip += Calendar._TT["PART_TODAY"]; } if (weekend.indexOf(wday.toString()) != -1) cell.className += cell.otherMonth ? " oweekend" : " weekend"; } } if (!(hasdays || this.showsOtherMonths)) row.className = "emptyrow"; } this.title.innerHTML = Calendar._MN[month] + ", " + year; this.onSetTime(); this.table.style.visibility = "visible"; this._initMultipleDates(); // PROFILE // this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms"; }; Calendar.prototype._initMultipleDates = function() { if (this.multiple) { for (var i in this.multiple) { var cell = this.datesCells[i]; var d = this.multiple[i]; if (!d) continue; if (cell) cell.className += " selected"; } } }; Calendar.prototype._toggleMultipleDate = function(date) { if (this.multiple) { var ds = date.print("%Y%m%d"); var cell = this.datesCells[ds]; if (cell) { var d = this.multiple[ds]; if (!d) { Calendar.addClass(cell, "selected"); this.multiple[ds] = date; } else { Calendar.removeClass(cell, "selected"); delete this.multiple[ds]; } } } }; Calendar.prototype.setDateToolTipHandler = function (unaryFunction) { this.getDateToolTip = unaryFunction; }; /** * Calls _init function above for going to a certain date (but only if the * date is different than the currently selected one). */ Calendar.prototype.setDate = function (date) { if (!date.equalsTo(this.date)) { this._init(this.firstDayOfWeek, date); } }; /** * Refreshes the calendar. Useful if the "disabledHandler" function is * dynamic, meaning that the list of disabled date can change at runtime. * Just * call this function if you think that the list of disabled dates * should * change. */ Calendar.prototype.refresh = function () { this._init(this.firstDayOfWeek, this.date); }; /** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */ Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) { this._init(firstDayOfWeek, this.date); this._displayWeekdays(); }; /** * Allows customization of what dates are enabled. The "unaryFunction" * parameter must be a function object that receives the date (as a JS Date * object) and returns a boolean value. If the returned value is true then * the passed date will be marked as disabled. */ Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) { this.getDateStatus = unaryFunction; }; /** Customization of allowed year range for the calendar. */ Calendar.prototype.setRange = function (a, z) { this.minYear = a; this.maxYear = z; }; /** Calls the first user handler (selectedHandler). */ Calendar.prototype.callHandler = function () { if (this.onSelected) { this.onSelected(this, this.date.print(this.dateFormat)); } }; /** Calls the second user handler (closeHandler). */ Calendar.prototype.callCloseHandler = function () { if (this.onClose) { this.onClose(this); } this.hideShowCovered(); }; /** Removes the calendar object from the DOM tree and destroys it. */ Calendar.prototype.destroy = function () { var el = this.element.parentNode; el.removeChild(this.element); Calendar._C = null; window._dynarch_popupCalendar = null; }; /** * Moves the calendar element to a different section in the DOM tree (changes * its parent). */ Calendar.prototype.reparent = function (new_parent) { var el = this.element; el.parentNode.removeChild(el); new_parent.appendChild(el); }; // This gets called when the user presses a mouse button anywhere in the // document, if the calendar is shown. If the click was outside the open // calendar this function closes it. Calendar._checkCalendar = function(ev) { var calendar = window._dynarch_popupCalendar; if (!calendar) { return false; } var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev); for (; el != null && el != calendar.element; el = el.parentNode); if (el == null) { // calls closeHandler which should hide the calendar. window._dynarch_popupCalendar.callCloseHandler(); return Calendar.stopEvent(ev); } }; /** Shows the calendar. */ Calendar.prototype.show = function () { var rows = this.table.getElementsByTagName("tr"); for (var i = rows.length; i > 0;) { var row = rows[--i]; Calendar.removeClass(row, "rowhilite"); var cells = row.getElementsByTagName("td"); for (var j = cells.length; j > 0;) { var cell = cells[--j]; Calendar.removeClass(cell, "hilite"); Calendar.removeClass(cell, "active"); } } this.element.style.display = "block"; this.hidden = false; if (this.isPopup) { window._dynarch_popupCalendar = this; Calendar.addEvent(document, "keydown", Calendar._keyEvent); Calendar.addEvent(document, "keypress", Calendar._keyEvent); Calendar.addEvent(document, "mousedown", Calendar._checkCalendar); } this.hideShowCovered(); }; /** * Hides the calendar. Also removes any "hilite" from the class of any TD * element. */ Calendar.prototype.hide = function () { if (this.isPopup) { Calendar.removeEvent(document, "keydown", Calendar._keyEvent); Calendar.removeEvent(document, "keypress", Calendar._keyEvent); Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar); } this.element.style.display = "none"; this.hidden = true; this.hideShowCovered(); }; /** * Shows the calendar at a given absolute position (beware that, depending on * the calendar element style -- position property -- this might be relative * to the parent's containing rectangle). */ Calendar.prototype.showAt = function (x, y) { var s = this.element.style; s.left = x + "px"; s.top = y + "px"; this.show(); }; /** Shows the calendar near a given element. */ Calendar.prototype.showAtElement = function (el, opts) { var self = this; var p = Calendar.getAbsolutePos(el); if (!opts || typeof opts != "string") { this.showAt(p.x, p.y + el.offsetHeight); return true; } function fixPosition(box) { if (box.x < 0) box.x = 0; if (box.y < 0) box.y = 0; var cp = document.createElement("div"); var s = cp.style; s.position = "absolute"; s.right = s.bottom = s.width = s.height = "0px"; document.body.appendChild(cp); var br = Calendar.getAbsolutePos(cp); document.body.removeChild(cp); if (Calendar.is_ie) { br.y += document.body.scrollTop; br.x += document.body.scrollLeft; } else { br.y += window.scrollY; br.x += window.scrollX; } var tmp = box.x + box.width - br.x; if (tmp > 0) box.x -= tmp; tmp = box.y + box.height - br.y; if (tmp > 0) box.y -= tmp; }; this.element.style.display = "block"; Calendar.continuation_for_the_fucking_khtml_browser = function() { var w = self.element.offsetWidth; var h = self.element.offsetHeight; self.element.style.display = "none"; var valign = opts.substr(0, 1); var halign = "l"; if (opts.length > 1) { halign = opts.substr(1, 1); } // vertical alignment switch (valign) { case "T": p.y -= h; break; case "B": p.y += el.offsetHeight; break; case "C": p.y += (el.offsetHeight - h) / 2; break; case "t": p.y += el.offsetHeight - h; break; case "b": break; // already there } // horizontal alignment switch (halign) { case "L": p.x -= w; break; case "R": p.x += el.offsetWidth; break; case "C": p.x += (el.offsetWidth - w) / 2; break; case "l": p.x += el.offsetWidth - w; break; case "r": break; // already there } p.width = w; p.height = h + 40; self.monthsCombo.style.display = "none"; fixPosition(p); self.showAt(p.x, p.y); }; if (Calendar.is_khtml) setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10); else Calendar.continuation_for_the_fucking_khtml_browser(); }; /** Customizes the date format. */ Calendar.prototype.setDateFormat = function (str) { this.dateFormat = str; }; /** Customizes the tooltip date format. */ Calendar.prototype.setTtDateFormat = function (str) { this.ttDateFormat = str; }; /** * Tries to identify the date represented in a string. If successful it also * calls this.setDate which moves the calendar to the given date. */ Calendar.prototype.parseDate = function(str, fmt) { if (!fmt) fmt = this.dateFormat; this.setDate(Date.parseDate(str, fmt)); }; Calendar.prototype.hideShowCovered = function () { if (!Calendar.is_ie && !Calendar.is_opera) return; function getVisib(obj){ var value = obj.style.visibility; if (!value) { if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C if (!Calendar.is_khtml) value = document.defaultView. getComputedStyle(obj, "").getPropertyValue("visibility"); else value = ''; } else if (obj.currentStyle) { // IE value = obj.currentStyle.visibility; } else value = ''; } return value; }; var tags = new Array("applet", "iframe", "select"); var el = this.element; var p = Calendar.getAbsolutePos(el); var EX1 = p.x; var EX2 = el.offsetWidth + EX1; var EY1 = p.y; var EY2 = el.offsetHeight + EY1; for (var k = tags.length; k > 0; ) { var ar = document.getElementsByTagName(tags[--k]); var cc = null; for (var i = ar.length; i > 0;) { cc = ar[--i]; p = Calendar.getAbsolutePos(cc); var CX1 = p.x; var CX2 = cc.offsetWidth + CX1; var CY1 = p.y; var CY2 = cc.offsetHeight + CY1; if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) { if (!cc.__msh_save_visibility) { cc.__msh_save_visibility = getVisib(cc); } cc.style.visibility = cc.__msh_save_visibility; } else { if (!cc.__msh_save_visibility) { cc.__msh_save_visibility = getVisib(cc); } cc.style.visibility = "hidden"; } } } }; /** Internal function; it displays the bar with the names of the weekday. */ Calendar.prototype._displayWeekdays = function () { var fdow = this.firstDayOfWeek; var cell = this.firstdayname; var weekend = Calendar._TT["WEEKEND"]; for (var i = 0; i < 7; ++i) { cell.className = "day name"; var realday = (i + fdow) % 7; if (i) { cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]); cell.navtype = 100; cell.calendar = this; cell.fdow = realday; Calendar._add_evs(cell); } if (weekend.indexOf(realday.toString()) != -1) { Calendar.addClass(cell, "weekend"); } cell.innerHTML = Calendar._SDN[(i + fdow) % 7]; cell = cell.nextSibling; } }; /** Internal function. Hides all combo boxes that might be displayed. */ Calendar.prototype._hideCombos = function () { this.monthsCombo.style.display = "none"; this.yearsCombo.style.display = "none"; }; /** Internal function. Starts dragging the element. */ Calendar.prototype._dragStart = function (ev) { if (this.dragging) { return; } this.dragging = true; var posX; var posY; if (Calendar.is_ie) { posY = window.event.clientY + document.body.scrollTop; posX = window.event.clientX + document.body.scrollLeft; } else { posY = ev.clientY + window.scrollY; posX = ev.clientX + window.scrollX; } var st = this.element.style; this.xOffs = posX - parseInt(st.left); this.yOffs = posY - parseInt(st.top); with (Calendar) { addEvent(document, "mousemove", calDragIt); addEvent(document, "mouseup", calDragEnd); } }; // BEGIN: DATE OBJECT PATCHES /** Adds the number of days array to the Date object. */ Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31); /** Constants used for time computations */ Date.SECOND = 1000 /* milliseconds */; Date.MINUTE = 60 * Date.SECOND; Date.HOUR = 60 * Date.MINUTE; Date.DAY = 24 * Date.HOUR; Date.WEEK = 7 * Date.DAY; Date.parseDate = function(str, fmt) { var today = new Date(); var y = 0; var m = -1; var d = 0; var a = str.split(/\W+/); var b = fmt.match(/%./g); var i = 0, j = 0; var hr = 0; var min = 0; for (i = 0; i < a.length; ++i) { if (!a[i]) continue; switch (b[i]) { case "%d": case "%e": d = parseInt(a[i], 10); break; case "%m": m = parseInt(a[i], 10) - 1; break; case "%Y": case "%y": y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); break; case "%b": case "%B": for (j = 0; j < 12; ++j) { if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } } break; case "%H": case "%I": case "%k": case "%l": hr = parseInt(a[i], 10); break; case "%P": case "%p": if (/pm/i.test(a[i]) && hr < 12) hr += 12; else if (/am/i.test(a[i]) && hr >= 12) hr -= 12; break; case "%M": min = parseInt(a[i], 10); break; } } if (isNaN(y)) y = today.getFullYear(); if (isNaN(m)) m = today.getMonth(); if (isNaN(d)) d = today.getDate(); if (isNaN(hr)) hr = today.getHours(); if (isNaN(min)) min = today.getMinutes(); if (y != 0 && m != -1 && d != 0) return new Date(y, m, d, hr, min, 0); y = 0; m = -1; d = 0; for (i = 0; i < a.length; ++i) { if (a[i].search(/[a-zA-Z]+/) != -1) { var t = -1; for (j = 0; j < 12; ++j) { if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } } if (t != -1) { if (m != -1) { d = m+1; } m = t; } } else if (parseInt(a[i], 10) <= 12 && m == -1) { m = a[i]-1; } else if (parseInt(a[i], 10) > 31 && y == 0) { y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); } else if (d == 0) { d = a[i]; } } if (y == 0) y = today.getFullYear(); if (m != -1 && d != 0) return new Date(y, m, d, hr, min, 0); return today; }; /** Returns the number of days in the current month */ Date.prototype.getMonthDays = function(month) { var year = this.getFullYear(); if (typeof month == "undefined") { month = this.getMonth(); } if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { return 29; } else { return Date._MD[month]; } }; /** Returns the number of day in the year. */ Date.prototype.getDayOfYear = function() { var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); var time = now - then; return Math.floor(time / Date.DAY); }; /** Returns the number of the week in year, as defined in ISO 8601. */ Date.prototype.getWeekNumber = function() { var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); var DoW = d.getDay(); d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu var ms = d.valueOf(); // GMT d.setMonth(0); d.setDate(4); // Thu in Week 1 return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; }; /** Checks date and time equality */ Date.prototype.equalsTo = function(date) { return ((this.getFullYear() == date.getFullYear()) && (this.getMonth() == date.getMonth()) && (this.getDate() == date.getDate()) && (this.getHours() == date.getHours()) && (this.getMinutes() == date.getMinutes())); }; /** Set only the year, month, date parts (keep existing time) */ Date.prototype.setDateOnly = function(date) { var tmp = new Date(date); this.setDate(1); this.setFullYear(tmp.getFullYear()); this.setMonth(tmp.getMonth()); this.setDate(tmp.getDate()); }; /** Prints the date in a string according to the given format. */ Date.prototype.print = function (str) { var m = this.getMonth(); var d = this.getDate(); var y = this.getFullYear(); var wn = this.getWeekNumber(); var w = this.getDay(); var s = {}; var hr = this.getHours(); var pm = (hr >= 12); var ir = (pm) ? (hr - 12) : hr; var dy = this.getDayOfYear(); if (ir == 0) ir = 12; var min = this.getMinutes(); var sec = this.getSeconds(); s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N] s["%A"] = Calendar._DN[w]; // full weekday name s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N] s["%B"] = Calendar._MN[m]; // full month name // FIXME: %c : preferred date and time representation for the current locale s["%C"] = 1 + Math.floor(y / 100); // the century number s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) s["%e"] = d; // the day of the month (range 1 to 31) // FIXME: %D : american date style: %m/%d/%y // FIXME: %E, %F, %G, %g, %h (man strftime) s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) s["%k"] = hr; // hour, range 0 to 23 (24h format) s["%l"] = ir; // hour, range 1 to 12 (12h format) s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12 s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 s["%n"] = "\n"; // a newline character s["%p"] = pm ? "PM" : "AM"; s["%P"] = pm ? "pm" : "am"; // FIXME: %r : the time in am/pm notation %I:%M:%S %p // FIXME: %R : the time in 24-hour notation %H:%M s["%s"] = Math.floor(this.getTime() / 1000); s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 s["%t"] = "\t"; // a tab character // FIXME: %T : the time in 24-hour notation (%H:%M:%S) s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) // FIXME: %x : preferred date representation for the current locale without the time // FIXME: %X : preferred time representation for the current locale without the date s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) s["%Y"] = y; // year with the century s["%%"] = "%"; // a literal '%' character var re = /%./g; if (!Calendar.is_ie5 && !Calendar.is_khtml) return str.replace(re, function (par) { return s[par] || par; }); var a = str.match(re); for (var i = 0; i < a.length; i++) { var tmp = s[a[i]]; if (tmp) { re = new RegExp(a[i], 'g'); str = str.replace(re, tmp); } } return str; }; Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear; Date.prototype.setFullYear = function(y) { var d = new Date(this); d.__msh_oldSetFullYear(y); if (d.getMonth() != this.getMonth()) this.setDate(28); this.__msh_oldSetFullYear(y); }; // END: DATE OBJECT PATCHES // global object that remembers the calendar window._dynarch_popupCalendar = null; nurpawiki-1.2.4/files/jscalendar/calendar_stripped.js000066400000000000000000001030131372046603600227650ustar00rootroot00000000000000/* Copyright Mihai Bazon, 2002-2005 | www.bazon.net/mishoo * ----------------------------------------------------------- * * The DHTML Calendar, version 1.0 "It is happening again" * * Details and latest version at: * www.dynarch.com/projects/calendar * * This script is developed by Dynarch.com. Visit us at www.dynarch.com. * * This script is distributed under the GNU Lesser General Public License. * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html */ Calendar=function(firstDayOfWeek,dateStr,onSelected,onClose){this.activeDiv=null;this.currentDateEl=null;this.getDateStatus=null;this.getDateToolTip=null;this.getDateText=null;this.timeout=null;this.onSelected=onSelected||null;this.onClose=onClose||null;this.dragging=false;this.hidden=false;this.minYear=1970;this.maxYear=2050;this.dateFormat=Calendar._TT["DEF_DATE_FORMAT"];this.ttDateFormat=Calendar._TT["TT_DATE_FORMAT"];this.isPopup=true;this.weekNumbers=true;this.firstDayOfWeek=typeof firstDayOfWeek=="number"?firstDayOfWeek:Calendar._FD;this.showsOtherMonths=false;this.dateStr=dateStr;this.ar_days=null;this.showsTime=false;this.time24=true;this.yearStep=2;this.hiliteToday=true;this.multiple=null;this.table=null;this.element=null;this.tbody=null;this.firstdayname=null;this.monthsCombo=null;this.yearsCombo=null;this.hilitedMonth=null;this.activeMonth=null;this.hilitedYear=null;this.activeYear=null;this.dateClicked=false;if(typeof Calendar._SDN=="undefined"){if(typeof Calendar._SDN_len=="undefined")Calendar._SDN_len=3;var ar=new Array();for(var i=8;i>0;){ar[--i]=Calendar._DN[i].substr(0,Calendar._SDN_len);}Calendar._SDN=ar;if(typeof Calendar._SMN_len=="undefined")Calendar._SMN_len=3;ar=new Array();for(var i=12;i>0;){ar[--i]=Calendar._MN[i].substr(0,Calendar._SMN_len);}Calendar._SMN=ar;}};Calendar._C=null;Calendar.is_ie=(/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent));Calendar.is_ie5=(Calendar.is_ie&&/msie 5\.0/i.test(navigator.userAgent));Calendar.is_opera=/opera/i.test(navigator.userAgent);Calendar.is_khtml=/Konqueror|Safari|KHTML/i.test(navigator.userAgent);Calendar.getAbsolutePos=function(el){var SL=0,ST=0;var is_div=/^div$/i.test(el.tagName);if(is_div&&el.scrollLeft)SL=el.scrollLeft;if(is_div&&el.scrollTop)ST=el.scrollTop;var r={x:el.offsetLeft-SL,y:el.offsetTop-ST};if(el.offsetParent){var tmp=this.getAbsolutePos(el.offsetParent);r.x+=tmp.x;r.y+=tmp.y;}return r;};Calendar.isRelated=function(el,evt){var related=evt.relatedTarget;if(!related){var type=evt.type;if(type=="mouseover"){related=evt.fromElement;}else if(type=="mouseout"){related=evt.toElement;}}while(related){if(related==el){return true;}related=related.parentNode;}return false;};Calendar.removeClass=function(el,className){if(!(el&&el.className)){return;}var cls=el.className.split(" ");var ar=new Array();for(var i=cls.length;i>0;){if(cls[--i]!=className){ar[ar.length]=cls[i];}}el.className=ar.join(" ");};Calendar.addClass=function(el,className){Calendar.removeClass(el,className);el.className+=" "+className;};Calendar.getElement=function(ev){var f=Calendar.is_ie?window.event.srcElement:ev.currentTarget;while(f.nodeType!=1||/^div$/i.test(f.tagName))f=f.parentNode;return f;};Calendar.getTargetElement=function(ev){var f=Calendar.is_ie?window.event.srcElement:ev.target;while(f.nodeType!=1)f=f.parentNode;return f;};Calendar.stopEvent=function(ev){ev||(ev=window.event);if(Calendar.is_ie){ev.cancelBubble=true;ev.returnValue=false;}else{ev.preventDefault();ev.stopPropagation();}return false;};Calendar.addEvent=function(el,evname,func){if(el.attachEvent){el.attachEvent("on"+evname,func);}else if(el.addEventListener){el.addEventListener(evname,func,true);}else{el["on"+evname]=func;}};Calendar.removeEvent=function(el,evname,func){if(el.detachEvent){el.detachEvent("on"+evname,func);}else if(el.removeEventListener){el.removeEventListener(evname,func,true);}else{el["on"+evname]=null;}};Calendar.createElement=function(type,parent){var el=null;if(document.createElementNS){el=document.createElementNS("http://www.w3.org/1999/xhtml",type);}else{el=document.createElement(type);}if(typeof parent!="undefined"){parent.appendChild(el);}return el;};Calendar._add_evs=function(el){with(Calendar){addEvent(el,"mouseover",dayMouseOver);addEvent(el,"mousedown",dayMouseDown);addEvent(el,"mouseout",dayMouseOut);if(is_ie){addEvent(el,"dblclick",dayMouseDblClick);el.setAttribute("unselectable",true);}}};Calendar.findMonth=function(el){if(typeof el.month!="undefined"){return el;}else if(typeof el.parentNode.month!="undefined"){return el.parentNode;}return null;};Calendar.findYear=function(el){if(typeof el.year!="undefined"){return el;}else if(typeof el.parentNode.year!="undefined"){return el.parentNode;}return null;};Calendar.showMonthsCombo=function(){var cal=Calendar._C;if(!cal){return false;}var cal=cal;var cd=cal.activeDiv;var mc=cal.monthsCombo;if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}if(cal.activeMonth){Calendar.removeClass(cal.activeMonth,"active");}var mon=cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];Calendar.addClass(mon,"active");cal.activeMonth=mon;var s=mc.style;s.display="block";if(cd.navtype<0)s.left=cd.offsetLeft+"px";else{var mcw=mc.offsetWidth;if(typeof mcw=="undefined")mcw=50;s.left=(cd.offsetLeft+cd.offsetWidth-mcw)+"px";}s.top=(cd.offsetTop+cd.offsetHeight)+"px";};Calendar.showYearsCombo=function(fwd){var cal=Calendar._C;if(!cal){return false;}var cal=cal;var cd=cal.activeDiv;var yc=cal.yearsCombo;if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}if(cal.activeYear){Calendar.removeClass(cal.activeYear,"active");}cal.activeYear=null;var Y=cal.date.getFullYear()+(fwd?1:-1);var yr=yc.firstChild;var show=false;for(var i=12;i>0;--i){if(Y>=cal.minYear&&Y<=cal.maxYear){yr.innerHTML=Y;yr.year=Y;yr.style.display="block";show=true;}else{yr.style.display="none";}yr=yr.nextSibling;Y+=fwd?cal.yearStep:-cal.yearStep;}if(show){var s=yc.style;s.display="block";if(cd.navtype<0)s.left=cd.offsetLeft+"px";else{var ycw=yc.offsetWidth;if(typeof ycw=="undefined")ycw=50;s.left=(cd.offsetLeft+cd.offsetWidth-ycw)+"px";}s.top=(cd.offsetTop+cd.offsetHeight)+"px";}};Calendar.tableMouseUp=function(ev){var cal=Calendar._C;if(!cal){return false;}if(cal.timeout){clearTimeout(cal.timeout);}var el=cal.activeDiv;if(!el){return false;}var target=Calendar.getTargetElement(ev);ev||(ev=window.event);Calendar.removeClass(el,"active");if(target==el||target.parentNode==el){Calendar.cellClick(el,ev);}var mon=Calendar.findMonth(target);var date=null;if(mon){date=new Date(cal.date);if(mon.month!=date.getMonth()){date.setMonth(mon.month);cal.setDate(date);cal.dateClicked=false;cal.callHandler();}}else{var year=Calendar.findYear(target);if(year){date=new Date(cal.date);if(year.year!=date.getFullYear()){date.setFullYear(year.year);cal.setDate(date);cal.dateClicked=false;cal.callHandler();}}}with(Calendar){removeEvent(document,"mouseup",tableMouseUp);removeEvent(document,"mouseover",tableMouseOver);removeEvent(document,"mousemove",tableMouseOver);cal._hideCombos();_C=null;return stopEvent(ev);}};Calendar.tableMouseOver=function(ev){var cal=Calendar._C;if(!cal){return;}var el=cal.activeDiv;var target=Calendar.getTargetElement(ev);if(target==el||target.parentNode==el){Calendar.addClass(el,"hilite active");Calendar.addClass(el.parentNode,"rowhilite");}else{if(typeof el.navtype=="undefined"||(el.navtype!=50&&(el.navtype==0||Math.abs(el.navtype)>2)))Calendar.removeClass(el,"active");Calendar.removeClass(el,"hilite");Calendar.removeClass(el.parentNode,"rowhilite");}ev||(ev=window.event);if(el.navtype==50&&target!=el){var pos=Calendar.getAbsolutePos(el);var w=el.offsetWidth;var x=ev.clientX;var dx;var decrease=true;if(x>pos.x+w){dx=x-pos.x-w;decrease=false;}else dx=pos.x-x;if(dx<0)dx=0;var range=el._range;var current=el._current;var count=Math.floor(dx/10)%range.length;for(var i=range.length;--i>=0;)if(range[i]==current)break;while(count-->0)if(decrease){if(--i<0)i=range.length-1;}else if(++i>=range.length)i=0;var newval=range[i];el.innerHTML=newval;cal.onUpdateTime();}var mon=Calendar.findMonth(target);if(mon){if(mon.month!=cal.date.getMonth()){if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}Calendar.addClass(mon,"hilite");cal.hilitedMonth=mon;}else if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}}else{if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}var year=Calendar.findYear(target);if(year){if(year.year!=cal.date.getFullYear()){if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}Calendar.addClass(year,"hilite");cal.hilitedYear=year;}else if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}}else if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}}return Calendar.stopEvent(ev);};Calendar.tableMouseDown=function(ev){if(Calendar.getTargetElement(ev)==Calendar.getElement(ev)){return Calendar.stopEvent(ev);}};Calendar.calDragIt=function(ev){var cal=Calendar._C;if(!(cal&&cal.dragging)){return false;}var posX;var posY;if(Calendar.is_ie){posY=window.event.clientY+document.body.scrollTop;posX=window.event.clientX+document.body.scrollLeft;}else{posX=ev.pageX;posY=ev.pageY;}cal.hideShowCovered();var st=cal.element.style;st.left=(posX-cal.xOffs)+"px";st.top=(posY-cal.yOffs)+"px";return Calendar.stopEvent(ev);};Calendar.calDragEnd=function(ev){var cal=Calendar._C;if(!cal){return false;}cal.dragging=false;with(Calendar){removeEvent(document,"mousemove",calDragIt);removeEvent(document,"mouseup",calDragEnd);tableMouseUp(ev);}cal.hideShowCovered();};Calendar.dayMouseDown=function(ev){var el=Calendar.getElement(ev);if(el.disabled){return false;}var cal=el.calendar;cal.activeDiv=el;Calendar._C=cal;if(el.navtype!=300)with(Calendar){if(el.navtype==50){el._current=el.innerHTML;addEvent(document,"mousemove",tableMouseOver);}else addEvent(document,Calendar.is_ie5?"mousemove":"mouseover",tableMouseOver);addClass(el,"hilite active");addEvent(document,"mouseup",tableMouseUp);}else if(cal.isPopup){cal._dragStart(ev);}if(el.navtype==-1||el.navtype==1){if(cal.timeout)clearTimeout(cal.timeout);cal.timeout=setTimeout("Calendar.showMonthsCombo()",250);}else if(el.navtype==-2||el.navtype==2){if(cal.timeout)clearTimeout(cal.timeout);cal.timeout=setTimeout((el.navtype>0)?"Calendar.showYearsCombo(true)":"Calendar.showYearsCombo(false)",250);}else{cal.timeout=null;}return Calendar.stopEvent(ev);};Calendar.dayMouseDblClick=function(ev){Calendar.cellClick(Calendar.getElement(ev),ev||window.event);if(Calendar.is_ie){document.selection.empty();}};Calendar.dayMouseOver=function(ev){var el=Calendar.getElement(ev);if(Calendar.isRelated(el,ev)||Calendar._C||el.disabled){return false;}if(el.ttip){if(el.ttip.substr(0,1)=="_"){el.ttip=el.caldate.print(el.calendar.ttDateFormat)+el.ttip.substr(1);}el.calendar.tooltips.innerHTML=el.ttip;}if(el.navtype!=300){Calendar.addClass(el,"hilite");if(el.caldate){Calendar.addClass(el.parentNode,"rowhilite");}}return Calendar.stopEvent(ev);};Calendar.dayMouseOut=function(ev){with(Calendar){var el=getElement(ev);if(isRelated(el,ev)||_C||el.disabled)return false;removeClass(el,"hilite");if(el.caldate)removeClass(el.parentNode,"rowhilite");if(el.calendar)el.calendar.tooltips.innerHTML=_TT["SEL_DATE"];return stopEvent(ev);}};Calendar.cellClick=function(el,ev){var cal=el.calendar;var closing=false;var newdate=false;var date=null;if(typeof el.navtype=="undefined"){if(cal.currentDateEl){Calendar.removeClass(cal.currentDateEl,"selected");Calendar.addClass(el,"selected");closing=(cal.currentDateEl==el);if(!closing){cal.currentDateEl=el;}}cal.date.setDateOnly(el.caldate);date=cal.date;var other_month=!(cal.dateClicked=!el.otherMonth);if(!other_month&&!cal.currentDateEl)cal._toggleMultipleDate(new Date(date));else newdate=!el.disabled;if(other_month)cal._init(cal.firstDayOfWeek,date);}else{if(el.navtype==200){Calendar.removeClass(el,"hilite");cal.callCloseHandler();return;}date=new Date(cal.date);if(el.navtype==0)date.setDateOnly(new Date());cal.dateClicked=false;var year=date.getFullYear();var mon=date.getMonth();function setMonth(m){var day=date.getDate();var max=date.getMonthDays(m);if(day>max){date.setDate(max);}date.setMonth(m);};switch(el.navtype){case 400:Calendar.removeClass(el,"hilite");var text=Calendar._TT["ABOUT"];if(typeof text!="undefined"){text+=cal.showsTime?Calendar._TT["ABOUT_TIME"]:"";}else{text="Help and about box text is not translated into this language.\n"+"If you know this language and you feel generous please update\n"+"the corresponding file in \"lang\" subdir to match calendar-en.js\n"+"and send it back to to get it into the distribution ;-)\n\n"+"Thank you!\n"+"http://dynarch.com/mishoo/calendar.epl\n";}alert(text);return;case-2:if(year>cal.minYear){date.setFullYear(year-1);}break;case-1:if(mon>0){setMonth(mon-1);}else if(year-->cal.minYear){date.setFullYear(year);setMonth(11);}break;case 1:if(mon<11){setMonth(mon+1);}else if(year=0;)if(range[i]==current)break;if(ev&&ev.shiftKey){if(--i<0)i=range.length-1;}else if(++i>=range.length)i=0;var newval=range[i];el.innerHTML=newval;cal.onUpdateTime();return;case 0:if((typeof cal.getDateStatus=="function")&&cal.getDateStatus(date,date.getFullYear(),date.getMonth(),date.getDate())){return false;}break;}if(!date.equalsTo(cal.date)){cal.setDate(date);newdate=true;}else if(el.navtype==0)newdate=closing=true;}if(newdate){ev&&cal.callHandler();}if(closing){Calendar.removeClass(el,"hilite");ev&&cal.callCloseHandler();}};Calendar.prototype.create=function(_par){var parent=null;if(!_par){parent=document.getElementsByTagName("body")[0];this.isPopup=true;}else{parent=_par;this.isPopup=false;}this.date=this.dateStr?new Date(this.dateStr):new Date();var table=Calendar.createElement("table");this.table=table;table.cellSpacing=0;table.cellPadding=0;table.calendar=this;Calendar.addEvent(table,"mousedown",Calendar.tableMouseDown);var div=Calendar.createElement("div");this.element=div;div.className="calendar";if(this.isPopup){div.style.position="absolute";div.style.display="none";}div.appendChild(table);var thead=Calendar.createElement("thead",table);var cell=null;var row=null;var cal=this;var hh=function(text,cs,navtype){cell=Calendar.createElement("td",row);cell.colSpan=cs;cell.className="button";if(navtype!=0&&Math.abs(navtype)<=2)cell.className+=" nav";Calendar._add_evs(cell);cell.calendar=cal;cell.navtype=navtype;cell.innerHTML="
"+text+"
";return cell;};row=Calendar.createElement("tr",thead);var title_length=6;(this.isPopup)&&--title_length;(this.weekNumbers)&&++title_length;hh("?",1,400).ttip=Calendar._TT["INFO"];this.title=hh("",title_length,300);this.title.className="title";if(this.isPopup){this.title.ttip=Calendar._TT["DRAG_TO_MOVE"];this.title.style.cursor="move";hh("×",1,200).ttip=Calendar._TT["CLOSE"];}row=Calendar.createElement("tr",thead);row.className="headrow";this._nav_py=hh("«",1,-2);this._nav_py.ttip=Calendar._TT["PREV_YEAR"];this._nav_pm=hh("‹",1,-1);this._nav_pm.ttip=Calendar._TT["PREV_MONTH"];this._nav_now=hh(Calendar._TT["TODAY"],this.weekNumbers?4:3,0);this._nav_now.ttip=Calendar._TT["GO_TODAY"];this._nav_nm=hh("›",1,1);this._nav_nm.ttip=Calendar._TT["NEXT_MONTH"];this._nav_ny=hh("»",1,2);this._nav_ny.ttip=Calendar._TT["NEXT_YEAR"];row=Calendar.createElement("tr",thead);row.className="daynames";if(this.weekNumbers){cell=Calendar.createElement("td",row);cell.className="name wn";cell.innerHTML=Calendar._TT["WK"];}for(var i=7;i>0;--i){cell=Calendar.createElement("td",row);if(!i){cell.navtype=100;cell.calendar=this;Calendar._add_evs(cell);}}this.firstdayname=(this.weekNumbers)?row.firstChild.nextSibling:row.firstChild;this._displayWeekdays();var tbody=Calendar.createElement("tbody",table);this.tbody=tbody;for(i=6;i>0;--i){row=Calendar.createElement("tr",tbody);if(this.weekNumbers){cell=Calendar.createElement("td",row);}for(var j=7;j>0;--j){cell=Calendar.createElement("td",row);cell.calendar=this;Calendar._add_evs(cell);}}if(this.showsTime){row=Calendar.createElement("tr",tbody);row.className="time";cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=2;cell.innerHTML=Calendar._TT["TIME"]||" ";cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=this.weekNumbers?4:3;(function(){function makeTimePart(className,init,range_start,range_end){var part=Calendar.createElement("span",cell);part.className=className;part.innerHTML=init;part.calendar=cal;part.ttip=Calendar._TT["TIME_PART"];part.navtype=50;part._range=[];if(typeof range_start!="number")part._range=range_start;else{for(var i=range_start;i<=range_end;++i){var txt;if(i<10&&range_end>=10)txt='0'+i;else txt=''+i;part._range[part._range.length]=txt;}}Calendar._add_evs(part);return part;};var hrs=cal.date.getHours();var mins=cal.date.getMinutes();var t12=!cal.time24;var pm=(hrs>12);if(t12&&pm)hrs-=12;var H=makeTimePart("hour",hrs,t12?1:0,t12?12:23);var span=Calendar.createElement("span",cell);span.innerHTML=":";span.className="colon";var M=makeTimePart("minute",mins,0,59);var AP=null;cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=2;if(t12)AP=makeTimePart("ampm",pm?"pm":"am",["am","pm"]);else cell.innerHTML=" ";cal.onSetTime=function(){var pm,hrs=this.date.getHours(),mins=this.date.getMinutes();if(t12){pm=(hrs>=12);if(pm)hrs-=12;if(hrs==0)hrs=12;AP.innerHTML=pm?"pm":"am";}H.innerHTML=(hrs<10)?("0"+hrs):hrs;M.innerHTML=(mins<10)?("0"+mins):mins;};cal.onUpdateTime=function(){var date=this.date;var h=parseInt(H.innerHTML,10);if(t12){if(/pm/i.test(AP.innerHTML)&&h<12)h+=12;else if(/am/i.test(AP.innerHTML)&&h==12)h=0;}var d=date.getDate();var m=date.getMonth();var y=date.getFullYear();date.setHours(h);date.setMinutes(parseInt(M.innerHTML,10));date.setFullYear(y);date.setMonth(m);date.setDate(d);this.dateClicked=false;this.callHandler();};})();}else{this.onSetTime=this.onUpdateTime=function(){};}var tfoot=Calendar.createElement("tfoot",table);row=Calendar.createElement("tr",tfoot);row.className="footrow";cell=hh(Calendar._TT["SEL_DATE"],this.weekNumbers?8:7,300);cell.className="ttip";if(this.isPopup){cell.ttip=Calendar._TT["DRAG_TO_MOVE"];cell.style.cursor="move";}this.tooltips=cell;div=Calendar.createElement("div",this.element);this.monthsCombo=div;div.className="combo";for(i=0;i0;--i){var yr=Calendar.createElement("div");yr.className=Calendar.is_ie?"label-IEfix":"label";div.appendChild(yr);}this._init(this.firstDayOfWeek,this.date);parent.appendChild(this.element);};Calendar._keyEvent=function(ev){var cal=window._dynarch_popupCalendar;if(!cal||cal.multiple)return false;(Calendar.is_ie)&&(ev=window.event);var act=(Calendar.is_ie||ev.type=="keypress"),K=ev.keyCode;if(ev.ctrlKey){switch(K){case 37:act&&Calendar.cellClick(cal._nav_pm);break;case 38:act&&Calendar.cellClick(cal._nav_py);break;case 39:act&&Calendar.cellClick(cal._nav_nm);break;case 40:act&&Calendar.cellClick(cal._nav_ny);break;default:return false;}}else switch(K){case 32:Calendar.cellClick(cal._nav_now);break;case 27:act&&cal.callCloseHandler();break;case 37:case 38:case 39:case 40:if(act){var prev,x,y,ne,el,step;prev=K==37||K==38;step=(K==37||K==39)?1:7;function setVars(){el=cal.currentDateEl;var p=el.pos;x=p&15;y=p>>4;ne=cal.ar_days[y][x];};setVars();function prevMonth(){var date=new Date(cal.date);date.setDate(date.getDate()-step);cal.setDate(date);};function nextMonth(){var date=new Date(cal.date);date.setDate(date.getDate()+step);cal.setDate(date);};while(1){switch(K){case 37:if(--x>=0)ne=cal.ar_days[y][x];else{x=6;K=38;continue;}break;case 38:if(--y>=0)ne=cal.ar_days[y][x];else{prevMonth();setVars();}break;case 39:if(++x<7)ne=cal.ar_days[y][x];else{x=0;K=40;continue;}break;case 40:if(++ythis.maxYear){year=this.maxYear;date.setFullYear(year);}this.firstDayOfWeek=firstDayOfWeek;this.date=new Date(date);var month=date.getMonth();var mday=date.getDate();var no_days=date.getMonthDays();date.setDate(1);var day1=(date.getDay()-this.firstDayOfWeek)%7;if(day1<0)day1+=7;date.setDate(-day1);date.setDate(date.getDate()+1);var row=this.tbody.firstChild;var MN=Calendar._SMN[month];var ar_days=this.ar_days=new Array();var weekend=Calendar._TT["WEEKEND"];var dates=this.multiple?(this.datesCells={}):null;for(var i=0;i<6;++i,row=row.nextSibling){var cell=row.firstChild;if(this.weekNumbers){cell.className="day wn";cell.innerHTML=date.getWeekNumber();cell=cell.nextSibling;}row.className="daysrow";var hasdays=false,iday,dpos=ar_days[i]=[];for(var j=0;j<7;++j,cell=cell.nextSibling,date.setDate(iday+1)){iday=date.getDate();var wday=date.getDay();cell.className="day";cell.pos=i<<4|j;dpos[j]=cell;var current_month=(date.getMonth()==month);if(!current_month){if(this.showsOtherMonths){cell.className+=" othermonth";cell.otherMonth=true;}else{cell.className="emptycell";cell.innerHTML=" ";cell.disabled=true;continue;}}else{cell.otherMonth=false;hasdays=true;}cell.disabled=false;cell.innerHTML=this.getDateText?this.getDateText(date,iday):iday;if(dates)dates[date.print("%Y%m%d")]=cell;if(this.getDateStatus){var status=this.getDateStatus(date,year,month,iday);if(this.getDateToolTip){var toolTip=this.getDateToolTip(date,year,month,iday);if(toolTip)cell.title=toolTip;}if(status===true){cell.className+=" disabled";cell.disabled=true;}else{if(/disabled/i.test(status))cell.disabled=true;cell.className+=" "+status;}}if(!cell.disabled){cell.caldate=new Date(date);cell.ttip="_";if(!this.multiple&¤t_month&&iday==mday&&this.hiliteToday){cell.className+=" selected";this.currentDateEl=cell;}if(date.getFullYear()==TY&&date.getMonth()==TM&&iday==TD){cell.className+=" today";cell.ttip+=Calendar._TT["PART_TODAY"];}if(weekend.indexOf(wday.toString())!=-1)cell.className+=cell.otherMonth?" oweekend":" weekend";}}if(!(hasdays||this.showsOtherMonths))row.className="emptyrow";}this.title.innerHTML=Calendar._MN[month]+", "+year;this.onSetTime();this.table.style.visibility="visible";this._initMultipleDates();};Calendar.prototype._initMultipleDates=function(){if(this.multiple){for(var i in this.multiple){var cell=this.datesCells[i];var d=this.multiple[i];if(!d)continue;if(cell)cell.className+=" selected";}}};Calendar.prototype._toggleMultipleDate=function(date){if(this.multiple){var ds=date.print("%Y%m%d");var cell=this.datesCells[ds];if(cell){var d=this.multiple[ds];if(!d){Calendar.addClass(cell,"selected");this.multiple[ds]=date;}else{Calendar.removeClass(cell,"selected");delete this.multiple[ds];}}}};Calendar.prototype.setDateToolTipHandler=function(unaryFunction){this.getDateToolTip=unaryFunction;};Calendar.prototype.setDate=function(date){if(!date.equalsTo(this.date)){this._init(this.firstDayOfWeek,date);}};Calendar.prototype.refresh=function(){this._init(this.firstDayOfWeek,this.date);};Calendar.prototype.setFirstDayOfWeek=function(firstDayOfWeek){this._init(firstDayOfWeek,this.date);this._displayWeekdays();};Calendar.prototype.setDateStatusHandler=Calendar.prototype.setDisabledHandler=function(unaryFunction){this.getDateStatus=unaryFunction;};Calendar.prototype.setRange=function(a,z){this.minYear=a;this.maxYear=z;};Calendar.prototype.callHandler=function(){if(this.onSelected){this.onSelected(this,this.date.print(this.dateFormat));}};Calendar.prototype.callCloseHandler=function(){if(this.onClose){this.onClose(this);}this.hideShowCovered();};Calendar.prototype.destroy=function(){var el=this.element.parentNode;el.removeChild(this.element);Calendar._C=null;window._dynarch_popupCalendar=null;};Calendar.prototype.reparent=function(new_parent){var el=this.element;el.parentNode.removeChild(el);new_parent.appendChild(el);};Calendar._checkCalendar=function(ev){var calendar=window._dynarch_popupCalendar;if(!calendar){return false;}var el=Calendar.is_ie?Calendar.getElement(ev):Calendar.getTargetElement(ev);for(;el!=null&&el!=calendar.element;el=el.parentNode);if(el==null){window._dynarch_popupCalendar.callCloseHandler();return Calendar.stopEvent(ev);}};Calendar.prototype.show=function(){var rows=this.table.getElementsByTagName("tr");for(var i=rows.length;i>0;){var row=rows[--i];Calendar.removeClass(row,"rowhilite");var cells=row.getElementsByTagName("td");for(var j=cells.length;j>0;){var cell=cells[--j];Calendar.removeClass(cell,"hilite");Calendar.removeClass(cell,"active");}}this.element.style.display="block";this.hidden=false;if(this.isPopup){window._dynarch_popupCalendar=this;Calendar.addEvent(document,"keydown",Calendar._keyEvent);Calendar.addEvent(document,"keypress",Calendar._keyEvent);Calendar.addEvent(document,"mousedown",Calendar._checkCalendar);}this.hideShowCovered();};Calendar.prototype.hide=function(){if(this.isPopup){Calendar.removeEvent(document,"keydown",Calendar._keyEvent);Calendar.removeEvent(document,"keypress",Calendar._keyEvent);Calendar.removeEvent(document,"mousedown",Calendar._checkCalendar);}this.element.style.display="none";this.hidden=true;this.hideShowCovered();};Calendar.prototype.showAt=function(x,y){var s=this.element.style;s.left=x+"px";s.top=y+"px";this.show();};Calendar.prototype.showAtElement=function(el,opts){var self=this;var p=Calendar.getAbsolutePos(el);if(!opts||typeof opts!="string"){this.showAt(p.x,p.y+el.offsetHeight);return true;}function fixPosition(box){if(box.x<0)box.x=0;if(box.y<0)box.y=0;var cp=document.createElement("div");var s=cp.style;s.position="absolute";s.right=s.bottom=s.width=s.height="0px";document.body.appendChild(cp);var br=Calendar.getAbsolutePos(cp);document.body.removeChild(cp);if(Calendar.is_ie){br.y+=document.body.scrollTop;br.x+=document.body.scrollLeft;}else{br.y+=window.scrollY;br.x+=window.scrollX;}var tmp=box.x+box.width-br.x;if(tmp>0)box.x-=tmp;tmp=box.y+box.height-br.y;if(tmp>0)box.y-=tmp;};this.element.style.display="block";Calendar.continuation_for_the_fucking_khtml_browser=function(){var w=self.element.offsetWidth;var h=self.element.offsetHeight;self.element.style.display="none";var valign=opts.substr(0,1);var halign="l";if(opts.length>1){halign=opts.substr(1,1);}switch(valign){case "T":p.y-=h;break;case "B":p.y+=el.offsetHeight;break;case "C":p.y+=(el.offsetHeight-h)/2;break;case "t":p.y+=el.offsetHeight-h;break;case "b":break;}switch(halign){case "L":p.x-=w;break;case "R":p.x+=el.offsetWidth;break;case "C":p.x+=(el.offsetWidth-w)/2;break;case "l":p.x+=el.offsetWidth-w;break;case "r":break;}p.width=w;p.height=h+40;self.monthsCombo.style.display="none";fixPosition(p);self.showAt(p.x,p.y);};if(Calendar.is_khtml)setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()",10);else Calendar.continuation_for_the_fucking_khtml_browser();};Calendar.prototype.setDateFormat=function(str){this.dateFormat=str;};Calendar.prototype.setTtDateFormat=function(str){this.ttDateFormat=str;};Calendar.prototype.parseDate=function(str,fmt){if(!fmt)fmt=this.dateFormat;this.setDate(Date.parseDate(str,fmt));};Calendar.prototype.hideShowCovered=function(){if(!Calendar.is_ie&&!Calendar.is_opera)return;function getVisib(obj){var value=obj.style.visibility;if(!value){if(document.defaultView&&typeof(document.defaultView.getComputedStyle)=="function"){if(!Calendar.is_khtml)value=document.defaultView. getComputedStyle(obj,"").getPropertyValue("visibility");else value='';}else if(obj.currentStyle){value=obj.currentStyle.visibility;}else value='';}return value;};var tags=new Array("applet","iframe","select");var el=this.element;var p=Calendar.getAbsolutePos(el);var EX1=p.x;var EX2=el.offsetWidth+EX1;var EY1=p.y;var EY2=el.offsetHeight+EY1;for(var k=tags.length;k>0;){var ar=document.getElementsByTagName(tags[--k]);var cc=null;for(var i=ar.length;i>0;){cc=ar[--i];p=Calendar.getAbsolutePos(cc);var CX1=p.x;var CX2=cc.offsetWidth+CX1;var CY1=p.y;var CY2=cc.offsetHeight+CY1;if(this.hidden||(CX1>EX2)||(CX2EY2)||(CY229)?1900:2000);break;case "%b":case "%B":for(j=0;j<12;++j){if(Calendar._MN[j].substr(0,a[i].length).toLowerCase()==a[i].toLowerCase()){m=j;break;}}break;case "%H":case "%I":case "%k":case "%l":hr=parseInt(a[i],10);break;case "%P":case "%p":if(/pm/i.test(a[i])&&hr<12)hr+=12;else if(/am/i.test(a[i])&&hr>=12)hr-=12;break;case "%M":min=parseInt(a[i],10);break;}}if(isNaN(y))y=today.getFullYear();if(isNaN(m))m=today.getMonth();if(isNaN(d))d=today.getDate();if(isNaN(hr))hr=today.getHours();if(isNaN(min))min=today.getMinutes();if(y!=0&&m!=-1&&d!=0)return new Date(y,m,d,hr,min,0);y=0;m=-1;d=0;for(i=0;i31&&y==0){y=parseInt(a[i],10);(y<100)&&(y+=(y>29)?1900:2000);}else if(d==0){d=a[i];}}if(y==0)y=today.getFullYear();if(m!=-1&&d!=0)return new Date(y,m,d,hr,min,0);return today;};Date.prototype.getMonthDays=function(month){var year=this.getFullYear();if(typeof month=="undefined"){month=this.getMonth();}if(((0==(year%4))&&((0!=(year%100))||(0==(year%400))))&&month==1){return 29;}else{return Date._MD[month];}};Date.prototype.getDayOfYear=function(){var now=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0);var then=new Date(this.getFullYear(),0,0,0,0,0);var time=now-then;return Math.floor(time/Date.DAY);};Date.prototype.getWeekNumber=function(){var d=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0);var DoW=d.getDay();d.setDate(d.getDate()-(DoW+6)%7+3);var ms=d.valueOf();d.setMonth(0);d.setDate(4);return Math.round((ms-d.valueOf())/(7*864e5))+1;};Date.prototype.equalsTo=function(date){return((this.getFullYear()==date.getFullYear())&&(this.getMonth()==date.getMonth())&&(this.getDate()==date.getDate())&&(this.getHours()==date.getHours())&&(this.getMinutes()==date.getMinutes()));};Date.prototype.setDateOnly=function(date){var tmp=new Date(date);this.setDate(1);this.setFullYear(tmp.getFullYear());this.setMonth(tmp.getMonth());this.setDate(tmp.getDate());};Date.prototype.print=function(str){var m=this.getMonth();var d=this.getDate();var y=this.getFullYear();var wn=this.getWeekNumber();var w=this.getDay();var s={};var hr=this.getHours();var pm=(hr>=12);var ir=(pm)?(hr-12):hr;var dy=this.getDayOfYear();if(ir==0)ir=12;var min=this.getMinutes();var sec=this.getSeconds();s["%a"]=Calendar._SDN[w];s["%A"]=Calendar._DN[w];s["%b"]=Calendar._SMN[m];s["%B"]=Calendar._MN[m];s["%C"]=1+Math.floor(y/100);s["%d"]=(d<10)?("0"+d):d;s["%e"]=d;s["%H"]=(hr<10)?("0"+hr):hr;s["%I"]=(ir<10)?("0"+ir):ir;s["%j"]=(dy<100)?((dy<10)?("00"+dy):("0"+dy)):dy;s["%k"]=hr;s["%l"]=ir;s["%m"]=(m<9)?("0"+(1+m)):(1+m);s["%M"]=(min<10)?("0"+min):min;s["%n"]="\n";s["%p"]=pm?"PM":"AM";s["%P"]=pm?"pm":"am";s["%s"]=Math.floor(this.getTime()/1000);s["%S"]=(sec<10)?("0"+sec):sec;s["%t"]="\t";s["%U"]=s["%W"]=s["%V"]=(wn<10)?("0"+wn):wn;s["%u"]=w+1;s["%w"]=w;s["%y"]=(''+y).substr(2,2);s["%Y"]=y;s["%%"]="%";var re=/%./g;if(!Calendar.is_ie5&&!Calendar.is_khtml)return str.replace(re,function(par){return s[par]||par;});var a=str.match(re);for(var i=0;i // Translator: Valentin Sheiretsky, // Encoding: Windows-1251 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("", "", "", "", "", "", "", ""); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("", "", "", "", "", "", "", ""); // full month names Calendar._MN = new Array ("", "", "", "", "", "", "", "", "", "", "", ""); // short month names Calendar._SMN = new Array ("", "", "", "", "", "", "", "", "", "", "", ""); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = " "; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Date selection:\n" + "- Use the \xab, \xbb buttons to select year\n" + "- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + "- Hold mouse button on any of the above buttons for faster selection."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Time selection:\n" + "- Click on any of the time parts to increase it\n" + "- or Shift-click to decrease it\n" + "- or click and drag for faster selection."; Calendar._TT["PREV_YEAR"] = " ( )"; Calendar._TT["PREV_MONTH"] = " ( )"; Calendar._TT["GO_TODAY"] = " "; Calendar._TT["NEXT_MONTH"] = " ( )"; Calendar._TT["NEXT_YEAR"] = " ( )"; Calendar._TT["SEL_DATE"] = " "; Calendar._TT["DRAG_TO_MOVE"] = ""; Calendar._TT["PART_TODAY"] = " ()"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "%s "; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = ""; Calendar._TT["TODAY"] = ""; Calendar._TT["TIME_PART"] = "(Shift-)Click drag "; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%A - %e %B %Y"; Calendar._TT["WK"] = ""; Calendar._TT["TIME"] = ":"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-big5-utf8.js000066400000000000000000000067051372046603600235160ustar00rootroot00000000000000// ** I18N // Calendar big5-utf8 language // Author: Gary Fu, // Encoding: utf8 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("日", "一", "二", "三", "四", "五", "六", "日"); // full month names Calendar._MN = new Array ("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"); // short month names Calendar._SMN = new Array ("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "關於"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "日期選擇方法:\n" + "- 使用 \xab, \xbb 按鈕可選擇年份\n" + "- 使用 " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " 按鈕可選擇月份\n" + "- 按住上面的按鈕可以加快選取"; Calendar._TT["ABOUT_TIME"] = "\n\n" + "時間選擇方法:\n" + "- 點擊任何的時間部份可增加其值\n" + "- 同時按Shift鍵再點擊可減少其值\n" + "- 點擊並拖曳可加快改變的值"; Calendar._TT["PREV_YEAR"] = "上一年 (按住選單)"; Calendar._TT["PREV_MONTH"] = "下一年 (按住選單)"; Calendar._TT["GO_TODAY"] = "到今日"; Calendar._TT["NEXT_MONTH"] = "上一月 (按住選單)"; Calendar._TT["NEXT_YEAR"] = "下一月 (按住選單)"; Calendar._TT["SEL_DATE"] = "選擇日期"; Calendar._TT["DRAG_TO_MOVE"] = "拖曳"; Calendar._TT["PART_TODAY"] = " (今日)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "將 %s 顯示在前"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "關閉"; Calendar._TT["TODAY"] = "今日"; Calendar._TT["TIME_PART"] = "點擊or拖曳可改變時間(同時按Shift為減)"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "週"; Calendar._TT["TIME"] = "Time:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-big5.js000066400000000000000000000063321372046603600226260ustar00rootroot00000000000000// ** I18N // Calendar big5 language // Author: Gary Fu, // Encoding: big5 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("P", "P@", "PG", "PT", "P|", "P", "P", "P"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("", "@", "G", "T", "|", "", "", ""); // full month names Calendar._MN = new Array ("@", "G", "T", "|", "", "", "C", "K", "E", "Q", "Q@", "QG"); // short month names Calendar._SMN = new Array ("@", "G", "T", "|", "", "", "C", "K", "E", "Q", "Q@", "QG"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = ""; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "ܤk:\n" + "- ϥ \xab, \xbb siܦ~\n" + "- ϥ " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " siܤ\n" + "- WsiH[ֿ"; Calendar._TT["ABOUT_TIME"] = "\n\n" + "ɶܤk:\n" + "- I󪺮ɶiW[\n" + "- PɫShiftAIi֨\n" + "- Ié즲i[֧ܪ"; Calendar._TT["PREV_YEAR"] = "W@~ ()"; Calendar._TT["PREV_MONTH"] = "U@~ ()"; Calendar._TT["GO_TODAY"] = "줵"; Calendar._TT["NEXT_MONTH"] = "W@ ()"; Calendar._TT["NEXT_YEAR"] = "U@ ()"; Calendar._TT["SEL_DATE"] = "ܤ"; Calendar._TT["DRAG_TO_MOVE"] = "즲"; Calendar._TT["PART_TODAY"] = " ()"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "N %s ܦbe"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = ""; Calendar._TT["TODAY"] = ""; Calendar._TT["TIME_PART"] = "Ior즲iܮɶ(PɫShift)"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "g"; Calendar._TT["TIME"] = "Time:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-br.js000066400000000000000000000071721372046603600224060ustar00rootroot00000000000000// ** I18N // Calendar pt-BR language // Author: Fernando Dourado, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sabádo", "Domingo"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names // [No changes using default values] // full month names Calendar._MN = new Array ("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"); // short month names // [No changes using default values] // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Sobre o calendário"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Translate to portuguese Brazil (pt-BR) by Fernando Dourado (fernando.dourado@ig.com.br)\n" + "Tradução para o português Brasil (pt-BR) por Fernando Dourado (fernando.dourado@ig.com.br)" + "\n\n" + "Selecionar data:\n" + "- Use as teclas \xab, \xbb para selecionar o ano\n" + "- Use as teclas " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para selecionar o mês\n" + "- Clique e segure com o mouse em qualquer botão para selecionar rapidamente."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Selecionar hora:\n" + "- Clique em qualquer uma das partes da hora para aumentar\n" + "- ou Shift-clique para diminuir\n" + "- ou clique e arraste para selecionar rapidamente."; Calendar._TT["PREV_YEAR"] = "Ano anterior (clique e segure para menu)"; Calendar._TT["PREV_MONTH"] = "Mês anterior (clique e segure para menu)"; Calendar._TT["GO_TODAY"] = "Ir para a data atual"; Calendar._TT["NEXT_MONTH"] = "Próximo mês (clique e segure para menu)"; Calendar._TT["NEXT_YEAR"] = "Próximo ano (clique e segure para menu)"; Calendar._TT["SEL_DATE"] = "Selecione uma data"; Calendar._TT["DRAG_TO_MOVE"] = "Clique e segure para mover"; Calendar._TT["PART_TODAY"] = " (hoje)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Exibir %s primeiro"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Fechar"; Calendar._TT["TODAY"] = "Hoje"; Calendar._TT["TIME_PART"] = "(Shift-)Clique ou arraste para mudar o valor"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%d de %B de %Y"; Calendar._TT["WK"] = "sem"; Calendar._TT["TIME"] = "Hora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-ca.js000066400000000000000000000070151372046603600223620ustar00rootroot00000000000000// ** I18N // Calendar CA language // Author: Mihai Bazon, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"); // full month names Calendar._MN = new Array ("Gener", "Febrer", "Mar", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"); // short month names Calendar._SMN = new Array ("Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Sobre el calendari"; Calendar._TT["ABOUT"] = "DHTML Selector de Data/Hora\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Sel.lecci de Dates:\n" + "- Fes servir els botons \xab, \xbb per sel.leccionar l'any\n" + "- Fes servir els botons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " per se.lecciconar el mes\n" + "- Mant el ratol apretat en qualsevol dels anteriors per sel.lecci rpida."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Time selection:\n" + "- claca en qualsevol de les parts de la hora per augmentar-les\n" + "- o Shift-click per decrementar-la\n" + "- or click and arrastra per sel.lecci rpida."; Calendar._TT["PREV_YEAR"] = "Any anterior (Mantenir per menu)"; Calendar._TT["PREV_MONTH"] = "Mes anterior (Mantenir per menu)"; Calendar._TT["GO_TODAY"] = "Anar a avui"; Calendar._TT["NEXT_MONTH"] = "Mes segent (Mantenir per menu)"; Calendar._TT["NEXT_YEAR"] = "Any segent (Mantenir per menu)"; Calendar._TT["SEL_DATE"] = "Sel.leccionar data"; Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar per moure"; Calendar._TT["PART_TODAY"] = " (avui)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Mostra %s primer"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Tanca"; Calendar._TT["TODAY"] = "Avui"; Calendar._TT["TIME_PART"] = "(Shift-)Click a arrastra per canviar el valor"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "st"; Calendar._TT["TIME"] = "Hora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-cs-utf8.js000066400000000000000000000054101372046603600232650ustar00rootroot00000000000000/* calendar-cs-win.js language: Czech encoding: windows-1250 author: Lubos Jerabek (xnet@seznam.cz) Jan Uhlir (espinosa@centrum.cz) */ // ** I18N Calendar._DN = new Array('Neděle','Pondělí','Úterý','Středa','Čtvrtek','Pátek','Sobota','Neděle'); Calendar._SDN = new Array('Ne','Po','Út','St','Čt','Pá','So','Ne'); Calendar._MN = new Array('Leden','Únor','Březen','Duben','Květen','Červen','Červenec','Srpen','Září','Říjen','Listopad','Prosinec'); Calendar._SMN = new Array('Led','Úno','Bře','Dub','Kvě','Črv','Čvc','Srp','Zář','Říj','Lis','Pro'); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "O komponentě kalendář"; Calendar._TT["TOGGLE"] = "Změna prvního dne v týdnu"; Calendar._TT["PREV_YEAR"] = "Předchozí rok (přidrž pro menu)"; Calendar._TT["PREV_MONTH"] = "Předchozí měsíc (přidrž pro menu)"; Calendar._TT["GO_TODAY"] = "Dnešní datum"; Calendar._TT["NEXT_MONTH"] = "Další měsíc (přidrž pro menu)"; Calendar._TT["NEXT_YEAR"] = "Další rok (přidrž pro menu)"; Calendar._TT["SEL_DATE"] = "Vyber datum"; Calendar._TT["DRAG_TO_MOVE"] = "Chyť a táhni, pro přesun"; Calendar._TT["PART_TODAY"] = " (dnes)"; Calendar._TT["MON_FIRST"] = "Ukaž jako první Pondělí"; //Calendar._TT["SUN_FIRST"] = "Ukaž jako první Neděli"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Výběr datumu:\n" + "- Use the \xab, \xbb buttons to select year\n" + "- Použijte tlačítka " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " k výběru měsíce\n" + "- Podržte tlačítko myši na jakémkoliv z těch tlačítek pro rychlejší výběr."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Výběr času:\n" + "- Klikněte na jakoukoliv z částí výběru času pro zvýšení.\n" + "- nebo Shift-click pro snížení\n" + "- nebo klikněte a táhněte pro rychlejší výběr."; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Zobraz %s první"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Zavřít"; Calendar._TT["TODAY"] = "Dnes"; Calendar._TT["TIME_PART"] = "(Shift-)Klikni nebo táhni pro změnu hodnoty"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "d.m.yy"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "Čas:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-cs-win.js000066400000000000000000000052211372046603600231740ustar00rootroot00000000000000/* calendar-cs-win.js language: Czech encoding: windows-1250 author: Lubos Jerabek (xnet@seznam.cz) Jan Uhlir (espinosa@centrum.cz) */ // ** I18N Calendar._DN = new Array('Nedle','Pondl','ter','Steda','tvrtek','Ptek','Sobota','Nedle'); Calendar._SDN = new Array('Ne','Po','t','St','t','P','So','Ne'); Calendar._MN = new Array('Leden','nor','Bezen','Duben','Kvten','erven','ervenec','Srpen','Z','jen','Listopad','Prosinec'); Calendar._SMN = new Array('Led','no','Be','Dub','Kv','rv','vc','Srp','Z','j','Lis','Pro'); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "O komponent kalend"; Calendar._TT["TOGGLE"] = "Zmna prvnho dne v tdnu"; Calendar._TT["PREV_YEAR"] = "Pedchoz rok (pidr pro menu)"; Calendar._TT["PREV_MONTH"] = "Pedchoz msc (pidr pro menu)"; Calendar._TT["GO_TODAY"] = "Dnen datum"; Calendar._TT["NEXT_MONTH"] = "Dal msc (pidr pro menu)"; Calendar._TT["NEXT_YEAR"] = "Dal rok (pidr pro menu)"; Calendar._TT["SEL_DATE"] = "Vyber datum"; Calendar._TT["DRAG_TO_MOVE"] = "Chy a thni, pro pesun"; Calendar._TT["PART_TODAY"] = " (dnes)"; Calendar._TT["MON_FIRST"] = "Uka jako prvn Pondl"; //Calendar._TT["SUN_FIRST"] = "Uka jako prvn Nedli"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Vbr datumu:\n" + "- Use the \xab, \xbb buttons to select year\n" + "- Pouijte tlatka " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " k vbru msce\n" + "- Podrte tlatko myi na jakmkoliv z tch tlatek pro rychlej vbr."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Vbr asu:\n" + "- Kliknte na jakoukoliv z st vbru asu pro zven.\n" + "- nebo Shift-click pro snen\n" + "- nebo kliknte a thnte pro rychlej vbr."; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Zobraz %s prvn"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Zavt"; Calendar._TT["TODAY"] = "Dnes"; Calendar._TT["TIME_PART"] = "(Shift-)Klikni nebo thni pro zmnu hodnoty"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "d.m.yy"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "as:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-da.js000066400000000000000000000066541372046603600223730ustar00rootroot00000000000000// ** I18N // Calendar DA language // Author: Michael Thingmand Henriksen, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"); // full month names Calendar._MN = new Array ("Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Om Kalenderen"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For den seneste version besøg: http://www.dynarch.com/projects/calendar/\n"; + "Distribueret under GNU LGPL. Se http://gnu.org/licenses/lgpl.html for detajler." + "\n\n" + "Valg af dato:\n" + "- Brug \xab, \xbb knapperne for at vælge år\n" + "- Brug " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " knapperne for at vælge måned\n" + "- Hold knappen på musen nede på knapperne ovenfor for hurtigere valg."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Valg af tid:\n" + "- Klik på en vilkårlig del for større værdi\n" + "- eller Shift-klik for for mindre værdi\n" + "- eller klik og træk for hurtigere valg."; Calendar._TT["PREV_YEAR"] = "Ét år tilbage (hold for menu)"; Calendar._TT["PREV_MONTH"] = "Én måned tilbage (hold for menu)"; Calendar._TT["GO_TODAY"] = "Gå til i dag"; Calendar._TT["NEXT_MONTH"] = "Én måned frem (hold for menu)"; Calendar._TT["NEXT_YEAR"] = "Ét år frem (hold for menu)"; Calendar._TT["SEL_DATE"] = "Vælg dag"; Calendar._TT["DRAG_TO_MOVE"] = "Træk vinduet"; Calendar._TT["PART_TODAY"] = " (i dag)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Vis %s først"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Luk"; Calendar._TT["TODAY"] = "I dag"; Calendar._TT["TIME_PART"] = "(Shift-)klik eller træk for at ændre værdi"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "Uge"; Calendar._TT["TIME"] = "Tid:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-de.js000066400000000000000000000074271372046603600223760ustar00rootroot00000000000000// ** I18N // Calendar DE language // Author: Jack (tR), // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"); // full month names Calendar._MN = new Array ("Januar", "Februar", "M\u00e4rz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "M\u00e4r", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "\u00DCber dieses Kalendarmodul"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Datum ausw\u00e4hlen:\n" + "- Benutzen Sie die \xab, \xbb Buttons um das Jahr zu w\u00e4hlen\n" + "- Benutzen Sie die " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " Buttons um den Monat zu w\u00e4hlen\n" + "- F\u00fcr eine Schnellauswahl halten Sie die Maustaste \u00fcber diesen Buttons fest."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Zeit ausw\u00e4hlen:\n" + "- Klicken Sie auf die Teile der Uhrzeit, um diese zu erh\u00F6hen\n" + "- oder klicken Sie mit festgehaltener Shift-Taste um diese zu verringern\n" + "- oder klicken und festhalten f\u00fcr Schnellauswahl."; Calendar._TT["TOGGLE"] = "Ersten Tag der Woche w\u00e4hlen"; Calendar._TT["PREV_YEAR"] = "Voriges Jahr (Festhalten f\u00fcr Schnellauswahl)"; Calendar._TT["PREV_MONTH"] = "Voriger Monat (Festhalten f\u00fcr Schnellauswahl)"; Calendar._TT["GO_TODAY"] = "Heute ausw\u00e4hlen"; Calendar._TT["NEXT_MONTH"] = "N\u00e4chst. Monat (Festhalten f\u00fcr Schnellauswahl)"; Calendar._TT["NEXT_YEAR"] = "N\u00e4chst. Jahr (Festhalten f\u00fcr Schnellauswahl)"; Calendar._TT["SEL_DATE"] = "Datum ausw\u00e4hlen"; Calendar._TT["DRAG_TO_MOVE"] = "Zum Bewegen festhalten"; Calendar._TT["PART_TODAY"] = " (Heute)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Woche beginnt mit %s "; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Schlie\u00dfen"; Calendar._TT["TODAY"] = "Heute"; Calendar._TT["TIME_PART"] = "(Shift-)Klick oder Festhalten und Ziehen um den Wert zu \u00e4ndern"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "Zeit:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-du.js000066400000000000000000000021671372046603600224120ustar00rootroot00000000000000// ** I18N Calendar._DN = new Array ("Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"); Calendar._MN = new Array ("Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"); // tooltips Calendar._TT = {}; Calendar._TT["TOGGLE"] = "Toggle startdag van de week"; Calendar._TT["PREV_YEAR"] = "Vorig jaar (indrukken voor menu)"; Calendar._TT["PREV_MONTH"] = "Vorige month (indrukken voor menu)"; Calendar._TT["GO_TODAY"] = "Naar Vandaag"; Calendar._TT["NEXT_MONTH"] = "Volgende Maand (indrukken voor menu)"; Calendar._TT["NEXT_YEAR"] = "Volgend jaar (indrukken voor menu)"; Calendar._TT["SEL_DATE"] = "Selecteer datum"; Calendar._TT["DRAG_TO_MOVE"] = "Sleep om te verplaatsen"; Calendar._TT["PART_TODAY"] = " (vandaag)"; Calendar._TT["MON_FIRST"] = "Toon Maandag eerst"; Calendar._TT["SUN_FIRST"] = "Toon Zondag eerst"; Calendar._TT["CLOSE"] = "Sluiten"; Calendar._TT["TODAY"] = "Vandaag"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "y-mm-dd"; Calendar._TT["TT_DATE_FORMAT"] = "D, M d"; Calendar._TT["WK"] = "wk"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-el.js000066400000000000000000000062511372046603600224000ustar00rootroot00000000000000// ** I18N Calendar._DN = new Array ("Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"); Calendar._SDN = new Array ("Κυ", "Δε", "Tρ", "Τε", "Πε", "Πα", "Σα", "Κυ"); Calendar._MN = new Array ("Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάϊος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"); Calendar._SMN = new Array ("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Για το ημερολόγιο"; Calendar._TT["ABOUT"] = "Επιλογέας ημερομηνίας/ώρας σε DHTML\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Για τελευταία έκδοση: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Επιλογή ημερομηνίας:\n" + "- Χρησιμοποιείστε τα κουμπιά \xab, \xbb για επιλογή έτους\n" + "- Χρησιμοποιείστε τα κουμπιά " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " για επιλογή μήνα\n" + "- Κρατήστε κουμπί ποντικού πατημένο στα παραπάνω κουμπιά για πιο γρήγορη επιλογή."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Επιλογή ώρας:\n" + "- Κάντε κλικ σε ένα από τα μέρη της ώρας για αύξηση\n" + "- ή Shift-κλικ για μείωση\n" + "- ή κλικ και μετακίνηση για πιο γρήγορη επιλογή."; Calendar._TT["TOGGLE"] = "Μπάρα πρώτης ημέρας της εβδομάδας"; Calendar._TT["PREV_YEAR"] = "Προηγ. έτος (κρατήστε για το μενού)"; Calendar._TT["PREV_MONTH"] = "Προηγ. μήνας (κρατήστε για το μενού)"; Calendar._TT["GO_TODAY"] = "Σήμερα"; Calendar._TT["NEXT_MONTH"] = "Επόμενος μήνας (κρατήστε για το μενού)"; Calendar._TT["NEXT_YEAR"] = "Επόμενο έτος (κρατήστε για το μενού)"; Calendar._TT["SEL_DATE"] = "Επιλέξτε ημερομηνία"; Calendar._TT["DRAG_TO_MOVE"] = "Σύρτε για να μετακινήσετε"; Calendar._TT["PART_TODAY"] = " (σήμερα)"; Calendar._TT["MON_FIRST"] = "Εμφάνιση Δευτέρας πρώτα"; Calendar._TT["SUN_FIRST"] = "Εμφάνιση Κυριακής πρώτα"; Calendar._TT["CLOSE"] = "Κλείσιμο"; Calendar._TT["TODAY"] = "Σήμερα"; Calendar._TT["TIME_PART"] = "(Shift-)κλικ ή μετακίνηση για αλλαγή"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; Calendar._TT["TT_DATE_FORMAT"] = "D, d M"; Calendar._TT["WK"] = "εβδ"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-en.js000066400000000000000000000070201372046603600223750ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Mihai Bazon, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"); // First day of the week. "0" means display Sunday first, "1" means display // Monday first, etc. Calendar._FD = 0; // full month names Calendar._MN = new Array ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "About the calendar"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Date selection:\n" + "- Use the \xab, \xbb buttons to select year\n" + "- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + "- Hold mouse button on any of the above buttons for faster selection."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Time selection:\n" + "- Click on any of the time parts to increase it\n" + "- or Shift-click to decrease it\n" + "- or click and drag for faster selection."; Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)"; Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)"; Calendar._TT["GO_TODAY"] = "Go Today"; Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)"; Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)"; Calendar._TT["SEL_DATE"] = "Select date"; Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; Calendar._TT["PART_TODAY"] = " (today)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Display %s first"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Close"; Calendar._TT["TODAY"] = "Today"; Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "Time:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-es.js000066400000000000000000000075151372046603600224130ustar00rootroot00000000000000// ** I18N // Calendar ES (spanish) language // Author: Mihai Bazon, // Updater: Servilio Afre Puentes // Updated: 2004-06-03 // Encoding: utf-8 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Domingo", "Lunes", "Martes", "Mircoles", "Jueves", "Viernes", "Sbado", "Domingo"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Dom", "Lun", "Mar", "Mi", "Jue", "Vie", "Sb", "Dom"); // First day of the week. "0" means display Sunday first, "1" means display // Monday first, etc. Calendar._FD = 1; // full month names Calendar._MN = new Array ("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"); // short month names Calendar._SMN = new Array ("Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Acerca del calendario"; Calendar._TT["ABOUT"] = "Selector DHTML de Fecha/Hora\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Para conseguir la ltima versin visite: http://www.dynarch.com/projects/calendar/\n" + "Distribuido bajo licencia GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para ms detalles." + "\n\n" + "Seleccin de fecha:\n" + "- Use los botones \xab, \xbb para seleccionar el ao\n" + "- Use los botones " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar el mes\n" + "- Mantenga pulsado el ratn en cualquiera de estos botones para una seleccin rpida."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Seleccin de hora:\n" + "- Pulse en cualquiera de las partes de la hora para incrementarla\n" + "- o pulse las maysculas mientras hace clic para decrementarla\n" + "- o haga clic y arrastre el ratn para una seleccin ms rpida."; Calendar._TT["PREV_YEAR"] = "Ao anterior (mantener para men)"; Calendar._TT["PREV_MONTH"] = "Mes anterior (mantener para men)"; Calendar._TT["GO_TODAY"] = "Ir a hoy"; Calendar._TT["NEXT_MONTH"] = "Mes siguiente (mantener para men)"; Calendar._TT["NEXT_YEAR"] = "Ao siguiente (mantener para men)"; Calendar._TT["SEL_DATE"] = "Seleccionar fecha"; Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar para mover"; Calendar._TT["PART_TODAY"] = " (hoy)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Hacer %s primer da de la semana"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Cerrar"; Calendar._TT["TODAY"] = "Hoy"; Calendar._TT["TIME_PART"] = "(Mayscula-)Clic o arrastre para cambiar valor"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; Calendar._TT["WK"] = "sem"; Calendar._TT["TIME"] = "Hora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-fi.js000066400000000000000000000053361372046603600224010ustar00rootroot00000000000000// ** I18N // Calendar FI language (Finnish, Suomi) // Author: Jarno Käyhkö, // Encoding: UTF-8 // Distributed under the same terms as the calendar itself. // full day names Calendar._DN = new Array ("Sunnuntai", "Maanantai", "Tiistai", "Keskiviikko", "Torstai", "Perjantai", "Lauantai", "Sunnuntai"); // short day names Calendar._SDN = new Array ("Su", "Ma", "Ti", "Ke", "To", "Pe", "La", "Su"); // full month names Calendar._MN = new Array ("Tammikuu", "Helmikuu", "Maaliskuu", "Huhtikuu", "Toukokuu", "Kesäkuu", "Heinäkuu", "Elokuu", "Syyskuu", "Lokakuu", "Marraskuu", "Joulukuu"); // short month names Calendar._SMN = new Array ("Tam", "Hel", "Maa", "Huh", "Tou", "Kes", "Hei", "Elo", "Syy", "Lok", "Mar", "Jou"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Tietoja kalenterista"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Uusin versio osoitteessa: http://www.dynarch.com/projects/calendar/\n" + "Julkaistu GNU LGPL lisenssin alaisuudessa. Lisätietoja osoitteessa http://gnu.org/licenses/lgpl.html" + "\n\n" + "Päivämäärä valinta:\n" + "- Käytä \xab, \xbb painikkeita valitaksesi vuosi\n" + "- Käytä " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " painikkeita valitaksesi kuukausi\n" + "- Pitämällä hiiren painiketta minkä tahansa yllä olevan painikkeen kohdalla, saat näkyviin valikon nopeampaan siirtymiseen."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Ajan valinta:\n" + "- Klikkaa kellonajan numeroita lisätäksesi aikaa\n" + "- tai pitämällä Shift-näppäintä pohjassa saat aikaa taaksepäin\n" + "- tai klikkaa ja pidä hiiren painike pohjassa sekä liikuta hiirtä muuttaaksesi aikaa nopeasti eteen- ja taaksepäin."; Calendar._TT["PREV_YEAR"] = "Edell. vuosi (paina hetki, näet valikon)"; Calendar._TT["PREV_MONTH"] = "Edell. kuukausi (paina hetki, näet valikon)"; Calendar._TT["GO_TODAY"] = "Siirry tähän päivään"; Calendar._TT["NEXT_MONTH"] = "Seur. kuukausi (paina hetki, näet valikon)"; Calendar._TT["NEXT_YEAR"] = "Seur. vuosi (paina hetki, näet valikon)"; Calendar._TT["SEL_DATE"] = "Valitse päivämäärä"; Calendar._TT["DRAG_TO_MOVE"] = "Siirrä kalenterin paikkaa"; Calendar._TT["PART_TODAY"] = " (tänään)"; Calendar._TT["MON_FIRST"] = "Näytä maanantai ensimmäisenä"; Calendar._TT["SUN_FIRST"] = "Näytä sunnuntai ensimmäisenä"; Calendar._TT["CLOSE"] = "Sulje"; Calendar._TT["TODAY"] = "Tänään"; Calendar._TT["TIME_PART"] = "(Shift-) Klikkaa tai liikuta muuttaaksesi aikaa"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%d.%m.%Y"; Calendar._TT["WK"] = "Vko"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-fr.js000066400000000000000000000072371372046603600224140ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Mihai Bazon, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // Translator: David Duret, from previous french version // full day names Calendar._DN = new Array ("Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Dim", "Lun", "Mar", "Mar", "Jeu", "Ven", "Sam", "Dim"); // full month names Calendar._MN = new Array ("Janvier", "Fvrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aot", "Septembre", "Octobre", "Novembre", "Dcembre"); // short month names Calendar._SMN = new Array ("Jan", "Fev", "Mar", "Avr", "Mai", "Juin", "Juil", "Aout", "Sep", "Oct", "Nov", "Dec"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "A propos du calendrier"; Calendar._TT["ABOUT"] = "DHTML Date/Heure Selecteur\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Pour la derniere version visitez : http://www.dynarch.com/projects/calendar/\n" + "Distribu par GNU LGPL. Voir http://gnu.org/licenses/lgpl.html pour les details." + "\n\n" + "Selection de la date :\n" + "- Utiliser les bouttons \xab, \xbb pour selectionner l\'annee\n" + "- Utiliser les bouttons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pour selectionner les mois\n" + "- Garder la souris sur n'importe quels boutons pour une selection plus rapide"; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Selection de l\'heure :\n" + "- Cliquer sur heures ou minutes pour incrementer\n" + "- ou Maj-clic pour decrementer\n" + "- ou clic et glisser-deplacer pour une selection plus rapide"; Calendar._TT["PREV_YEAR"] = "Anne prc. (maintenir pour menu)"; Calendar._TT["PREV_MONTH"] = "Mois prc. (maintenir pour menu)"; Calendar._TT["GO_TODAY"] = "Atteindre la date du jour"; Calendar._TT["NEXT_MONTH"] = "Mois suiv. (maintenir pour menu)"; Calendar._TT["NEXT_YEAR"] = "Anne suiv. (maintenir pour menu)"; Calendar._TT["SEL_DATE"] = "Slectionner une date"; Calendar._TT["DRAG_TO_MOVE"] = "Dplacer"; Calendar._TT["PART_TODAY"] = " (Aujourd'hui)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Afficher %s en premier"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Fermer"; Calendar._TT["TODAY"] = "Aujourd'hui"; Calendar._TT["TIME_PART"] = "(Maj-)Clic ou glisser pour modifier la valeur"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "Sem."; Calendar._TT["TIME"] = "Heure :"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-he-utf8.js000066400000000000000000000075171372046603600232660ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Idan Sofer, // Encoding: UTF-8 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("א", "ב", "ג", "ד", "ה", "ו", "ש", "א"); // full month names Calendar._MN = new Array ("ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"); // short month names Calendar._SMN = new Array ("ינא", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "אודות השנתון"; Calendar._TT["ABOUT"] = "בחרן תאריך/שעה DHTML\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "הגירסא האחרונה זמינה ב: http://www.dynarch.com/projects/calendar/\n" + "מופץ תחת זיכיון ה GNU LGPL. עיין ב http://gnu.org/licenses/lgpl.html לפרטים נוספים." + "\n\n" + בחירת תאריך:\n" + "- השתמש בכפתורים \xab, \xbb לבחירת שנה\n" + "- השתמש בכפתורים " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " לבחירת חודש\n" + "- החזק העכבר לחוץ מעל הכפתורים המוזכרים לעיל לבחירה מהירה יותר."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "בחירת זמן:\n" + "- לחץ על כל אחד מחלקי הזמן כדי להוסיף\n" + "- או shift בשילוב עם לחיצה כדי להחסיר\n" + "- או לחץ וגרור לפעולה מהירה יותר."; Calendar._TT["PREV_YEAR"] = "שנה קודמת - החזק לקבלת תפריט"; Calendar._TT["PREV_MONTH"] = "חודש קודם - החזק לקבלת תפריט"; Calendar._TT["GO_TODAY"] = "עבור להיום"; Calendar._TT["NEXT_MONTH"] = "חודש הבא - החזק לתפריט"; Calendar._TT["NEXT_YEAR"] = "שנה הבאה - החזק לתפריט"; Calendar._TT["SEL_DATE"] = "בחר תאריך"; Calendar._TT["DRAG_TO_MOVE"] = "גרור להזזה"; Calendar._TT["PART_TODAY"] = " )היום("; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "הצג %s קודם"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "6"; Calendar._TT["CLOSE"] = "סגור"; Calendar._TT["TODAY"] = "היום"; Calendar._TT["TIME_PART"] = "(שיפט-)לחץ וגרור כדי לשנות ערך"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "שעה::"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-hr-utf8.js000066400000000000000000000030211372046603600232650ustar00rootroot00000000000000/* Croatian language file for the DHTML Calendar version 0.9.2 * Author Krunoslav Zubrinic , June 2003. * Feel free to use this script under the terms of the GNU Lesser General * Public License, as long as you do not remove or alter this notice. */ Calendar._DN = new Array ("Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota", "Nedjelja"); Calendar._MN = new Array ("Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"); // tooltips Calendar._TT = {}; Calendar._TT["TOGGLE"] = "Promjeni dan s kojim počinje tjedan"; Calendar._TT["PREV_YEAR"] = "Prethodna godina (dugi pritisak za meni)"; Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (dugi pritisak za meni)"; Calendar._TT["GO_TODAY"] = "Idi na tekući dan"; Calendar._TT["NEXT_MONTH"] = "Slijedeći mjesec (dugi pritisak za meni)"; Calendar._TT["NEXT_YEAR"] = "Slijedeća godina (dugi pritisak za meni)"; Calendar._TT["SEL_DATE"] = "Izaberite datum"; Calendar._TT["DRAG_TO_MOVE"] = "Pritisni i povuci za promjenu pozicije"; Calendar._TT["PART_TODAY"] = " (today)"; Calendar._TT["MON_FIRST"] = "Prikaži ponedjeljak kao prvi dan"; Calendar._TT["SUN_FIRST"] = "Prikaži nedjelju kao prvi dan"; Calendar._TT["CLOSE"] = "Zatvori"; Calendar._TT["TODAY"] = "Danas"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; Calendar._TT["TT_DATE_FORMAT"] = "DD, dd.mm.y"; Calendar._TT["WK"] = "Tje";nurpawiki-1.2.4/files/jscalendar/lang/calendar-hr.js000066400000000000000000000060201372046603600224030ustar00rootroot00000000000000/* Croatian language file for the DHTML Calendar version 0.9.2 * Author Krunoslav Zubrinic <krunoslav.zubrinic@vip.hr>, June 2003. * Feel free to use this script under the terms of the GNU Lesser General * Public License, as long as you do not remove or alter this notice. */ Calendar._DN = new Array ("Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", " etvrtak", "Petak", "Subota", "Nedjelja"); Calendar._MN = new Array ("Sije anj", "Velja a", "O~ujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"); // tooltips Calendar._TT = {}; Calendar._TT["TOGGLE"] = "Promjeni dan s kojim po inje tjedan"; Calendar._TT["PREV_YEAR"] = "Prethodna godina (dugi pritisak za meni)"; Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (dugi pritisak za meni)"; Calendar._TT["GO_TODAY"] = "Idi na tekui dan"; Calendar._TT["NEXT_MONTH"] = "Slijedei mjesec (dugi pritisak za meni)"; Calendar._TT["NEXT_YEAR"] = "Slijedea godina (dugi pritisak za meni)"; Calendar._TT["SEL_DATE"] = "Izaberite datum"; Calendar._TT["DRAG_TO_MOVE"] = "Pritisni i povuci za promjenu pozicije"; Calendar._TT["PART_TODAY"] = " (today)"; Calendar._TT["MON_FIRST"] = "Prika~i ponedjeljak kao prvi dan"; Calendar._TT["SUN_FIRST"] = "Prika~i nedjelju kao prvi dan"; Calendar._TT["CLOSE"] = "Zatvori"; Calendar._TT["TODAY"] = "Danas"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; Calendar._TT["TT_DATE_FORMAT"] = "DD, dd.mm.y"; Calendar._TT["WK"] = "Tje";nurpawiki-1.2.4/files/jscalendar/lang/calendar-hu.js000066400000000000000000000070231372046603600224120ustar00rootroot00000000000000// ** I18N // Calendar HU language // Author: ??? // Modifier: KARASZI Istvan, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Vasrnap", "Htf", "Kedd", "Szerda", "Cstrtk", "Pntek", "Szombat", "Vasrnap"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("v", "h", "k", "sze", "cs", "p", "szo", "v"); // full month names Calendar._MN = new Array ("janur", "februr", "mrcius", "prilis", "mjus", "jnius", "jlius", "augusztus", "szeptember", "oktber", "november", "december"); // short month names Calendar._SMN = new Array ("jan", "feb", "mr", "pr", "mj", "jn", "jl", "aug", "sze", "okt", "nov", "dec"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "A kalendriumrl"; Calendar._TT["ABOUT"] = "DHTML dtum/id kivlaszt\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "a legfrissebb verzi megtallhat: http://www.dynarch.com/projects/calendar/\n" + "GNU LGPL alatt terjesztve. Lsd a http://gnu.org/licenses/lgpl.html oldalt a rszletekhez." + "\n\n" + "Dtum vlaszts:\n" + "- hasznlja a \xab, \xbb gombokat az v kivlasztshoz\n" + "- hasznlja a " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " gombokat a hnap kivlasztshoz\n" + "- tartsa lenyomva az egrgombot a gyors vlasztshoz."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Id vlaszts:\n" + "- kattintva nvelheti az idt\n" + "- shift-tel kattintva cskkentheti\n" + "- lenyomva tartva s hzva gyorsabban kivlaszthatja."; Calendar._TT["PREV_YEAR"] = "Elz v (tartsa nyomva a menhz)"; Calendar._TT["PREV_MONTH"] = "Elz hnap (tartsa nyomva a menhz)"; Calendar._TT["GO_TODAY"] = "Mai napra ugrs"; Calendar._TT["NEXT_MONTH"] = "Kv. hnap (tartsa nyomva a menhz)"; Calendar._TT["NEXT_YEAR"] = "Kv. v (tartsa nyomva a menhz)"; Calendar._TT["SEL_DATE"] = "Vlasszon dtumot"; Calendar._TT["DRAG_TO_MOVE"] = "Hzza a mozgatshoz"; Calendar._TT["PART_TODAY"] = " (ma)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "%s legyen a ht els napja"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Bezr"; Calendar._TT["TODAY"] = "Ma"; Calendar._TT["TIME_PART"] = "(Shift-)Klikk vagy hzs az rtk vltoztatshoz"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%b %e, %a"; Calendar._TT["WK"] = "ht"; Calendar._TT["TIME"] = "id:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-it.js000066400000000000000000000070611372046603600224140ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Mihai Bazon, // Translator: Fabio Di Bernardini, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato", "Domenica"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"); // full month names Calendar._MN = new Array ("Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Augosto", "Settembre", "Ottobre", "Novembre", "Dicembre"); // short month names Calendar._SMN = new Array ("Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Informazioni sul calendario"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Per gli aggiornamenti: http://www.dynarch.com/projects/calendar/\n" + "Distribuito sotto licenza GNU LGPL. Vedi http://gnu.org/licenses/lgpl.html per i dettagli." + "\n\n" + "Selezione data:\n" + "- Usa \xab, \xbb per selezionare l'anno\n" + "- Usa " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " per i mesi\n" + "- Tieni premuto a lungo il mouse per accedere alle funzioni di selezione veloce."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Selezione orario:\n" + "- Clicca sul numero per incrementarlo\n" + "- o Shift+click per decrementarlo\n" + "- o click e sinistra o destra per variarlo."; Calendar._TT["PREV_YEAR"] = "Anno prec.(clicca a lungo per il menù)"; Calendar._TT["PREV_MONTH"] = "Mese prec. (clicca a lungo per il menù)"; Calendar._TT["GO_TODAY"] = "Oggi"; Calendar._TT["NEXT_MONTH"] = "Pross. mese (clicca a lungo per il menù)"; Calendar._TT["NEXT_YEAR"] = "Pross. anno (clicca a lungo per il menù)"; Calendar._TT["SEL_DATE"] = "Seleziona data"; Calendar._TT["DRAG_TO_MOVE"] = "Trascina per spostarlo"; Calendar._TT["PART_TODAY"] = " (oggi)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Mostra prima %s"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Chiudi"; Calendar._TT["TODAY"] = "Oggi"; Calendar._TT["TIME_PART"] = "(Shift-)Click o trascina per cambiare il valore"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a:%b:%e"; Calendar._TT["WK"] = "set"; Calendar._TT["TIME"] = "Ora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-jp.js000066400000000000000000000016211372046603600224050ustar00rootroot00000000000000// ** I18N Calendar._DN = new Array ("", "", "", "", "", "", "y", ""); Calendar._MN = new Array ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); // tooltips Calendar._TT = {}; Calendar._TT["TOGGLE"] = "T̍ŏ̗j؂ւ"; Calendar._TT["PREV_YEAR"] = "ON"; Calendar._TT["PREV_MONTH"] = "O"; Calendar._TT["GO_TODAY"] = ""; Calendar._TT["NEXT_MONTH"] = ""; Calendar._TT["NEXT_YEAR"] = "N"; Calendar._TT["SEL_DATE"] = "tI"; Calendar._TT["DRAG_TO_MOVE"] = "EBhËړ"; Calendar._TT["PART_TODAY"] = " ()"; Calendar._TT["MON_FIRST"] = "j擪"; Calendar._TT["SUN_FIRST"] = "j擪"; Calendar._TT["CLOSE"] = "‚"; Calendar._TT["TODAY"] = ""; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "y-mm-dd"; Calendar._TT["TT_DATE_FORMAT"] = "%m %d (%a)"; Calendar._TT["WK"] = "T"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-ko-utf8.js000066400000000000000000000067601372046603600233020ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Mihai Bazon, // Translation: Yourim Yi // Encoding: EUC-KR // lang : ko // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("일", "월", "화", "수", "목", "금", "토", "일"); // full month names Calendar._MN = new Array ("1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"); // short month names Calendar._SMN = new Array ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "calendar 에 대해서"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "\n"+ "최신 버전을 받으시려면 http://www.dynarch.com/projects/calendar/ 에 방문하세요\n" + "\n"+ "GNU LGPL 라이센스로 배포됩니다. \n"+ "라이센스에 대한 자세한 내용은 http://gnu.org/licenses/lgpl.html 을 읽으세요." + "\n\n" + "날짜 선택:\n" + "- 연도를 선택하려면 \xab, \xbb 버튼을 사용합니다\n" + "- 달을 선택하려면 " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " 버튼을 누르세요\n" + "- 계속 누르고 있으면 위 값들을 빠르게 선택하실 수 있습니다."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "시간 선택:\n" + "- 마우스로 누르면 시간이 증가합니다\n" + "- Shift 키와 함께 누르면 감소합니다\n" + "- 누른 상태에서 마우스를 움직이면 좀 더 빠르게 값이 변합니다.\n"; Calendar._TT["PREV_YEAR"] = "지난 해 (길게 누르면 목록)"; Calendar._TT["PREV_MONTH"] = "지난 달 (길게 누르면 목록)"; Calendar._TT["GO_TODAY"] = "오늘 날짜로"; Calendar._TT["NEXT_MONTH"] = "다음 달 (길게 누르면 목록)"; Calendar._TT["NEXT_YEAR"] = "다음 해 (길게 누르면 목록)"; Calendar._TT["SEL_DATE"] = "날짜를 선택하세요"; Calendar._TT["DRAG_TO_MOVE"] = "마우스 드래그로 이동 하세요"; Calendar._TT["PART_TODAY"] = " (오늘)"; Calendar._TT["MON_FIRST"] = "월요일을 한 주의 시작 요일로"; Calendar._TT["SUN_FIRST"] = "일요일을 한 주의 시작 요일로"; Calendar._TT["CLOSE"] = "닫기"; Calendar._TT["TODAY"] = "오늘"; Calendar._TT["TIME_PART"] = "(Shift-)클릭 또는 드래그 하세요"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%b/%e [%a]"; Calendar._TT["WK"] = "주"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-ko.js000066400000000000000000000062701372046603600224120ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Mihai Bazon, // Translation: Yourim Yi // Encoding: EUC-KR // lang : ko // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Ͽ", "", "ȭ", "", "", "ݿ", "", "Ͽ"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("", "", "ȭ", "", "", "", "", ""); // full month names Calendar._MN = new Array ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); // short month names Calendar._SMN = new Array ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "calendar ؼ"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "\n"+ "ֽ ÷ http://www.dynarch.com/projects/calendar/ 湮ϼ\n" + "\n"+ "GNU LGPL ̼ ˴ϴ. \n"+ "̼ ڼ http://gnu.org/licenses/lgpl.html ." + "\n\n" + "¥ :\n" + "- Ϸ \xab, \xbb ư մϴ\n" + "- Ϸ " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " ư \n" + "- Ͻ ֽϴ."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "ð :\n" + "- 콺 ð մϴ\n" + "- Shift Ű Բ մϴ\n" + "- ¿ 콺 ̸ մϴ.\n"; Calendar._TT["PREV_YEAR"] = " ( )"; Calendar._TT["PREV_MONTH"] = " ( )"; Calendar._TT["GO_TODAY"] = " ¥"; Calendar._TT["NEXT_MONTH"] = " ( )"; Calendar._TT["NEXT_YEAR"] = " ( )"; Calendar._TT["SEL_DATE"] = "¥ ϼ"; Calendar._TT["DRAG_TO_MOVE"] = "콺 巡׷ ̵ ϼ"; Calendar._TT["PART_TODAY"] = " ()"; Calendar._TT["MON_FIRST"] = " Ϸ"; Calendar._TT["SUN_FIRST"] = "Ͽ Ϸ"; Calendar._TT["CLOSE"] = "ݱ"; Calendar._TT["TODAY"] = ""; Calendar._TT["TIME_PART"] = "(Shift-)Ŭ Ǵ 巡 ϼ"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%b/%e [%a]"; Calendar._TT["WK"] = ""; nurpawiki-1.2.4/files/jscalendar/lang/calendar-lt-utf8.js000066400000000000000000000065501372046603600233050ustar00rootroot00000000000000// ** I18N // Calendar LT language // Author: Martynas Majeris, // Encoding: UTF-8 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Pentadienis", "Šeštadienis", "Sekmadienis"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Sek", "Pir", "Ant", "Tre", "Ket", "Pen", "Šeš", "Sek"); // full month names Calendar._MN = new Array ("Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"); // short month names Calendar._SMN = new Array ("Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rgp", "Rgs", "Spa", "Lap", "Gru"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Apie kalendorių"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Naujausią versiją rasite: http://www.dynarch.com/projects/calendar/\n" + "Platinamas pagal GNU LGPL licenciją. Aplankykite http://gnu.org/licenses/lgpl.html" + "\n\n" + "Datos pasirinkimas:\n" + "- Metų pasirinkimas: \xab, \xbb\n" + "- Mėnesio pasirinkimas: " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "\n" + "- Nuspauskite ir laikykite pelės klavišą greitesniam pasirinkimui."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Laiko pasirinkimas:\n" + "- Spustelkite ant valandų arba minučių - skaičius padidės vienetu.\n" + "- Jei spausite kartu su Shift, skaičius sumažės.\n" + "- Greitam pasirinkimui spustelkite ir pajudinkite pelę."; Calendar._TT["PREV_YEAR"] = "Ankstesni metai (laikykite, jei norite meniu)"; Calendar._TT["PREV_MONTH"] = "Ankstesnis mėnuo (laikykite, jei norite meniu)"; Calendar._TT["GO_TODAY"] = "Pasirinkti šiandieną"; Calendar._TT["NEXT_MONTH"] = "Kitas mėnuo (laikykite, jei norite meniu)"; Calendar._TT["NEXT_YEAR"] = "Kiti metai (laikykite, jei norite meniu)"; Calendar._TT["SEL_DATE"] = "Pasirinkite datą"; Calendar._TT["DRAG_TO_MOVE"] = "Tempkite"; Calendar._TT["PART_TODAY"] = " (šiandien)"; Calendar._TT["MON_FIRST"] = "Pirma savaitės diena - pirmadienis"; Calendar._TT["SUN_FIRST"] = "Pirma savaitės diena - sekmadienis"; Calendar._TT["CLOSE"] = "Uždaryti"; Calendar._TT["TODAY"] = "Šiandien"; Calendar._TT["TIME_PART"] = "Spustelkite arba tempkite jei norite pakeisti"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%A, %Y-%m-%d"; Calendar._TT["WK"] = "sav"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-lt.js000066400000000000000000000065101372046603600224150ustar00rootroot00000000000000// ** I18N // Calendar LT language // Author: Martynas Majeris, // Encoding: Windows-1257 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Sekmadienis", "Pirmadienis", "Antradienis", "Treiadienis", "Ketvirtadienis", "Pentadienis", "etadienis", "Sekmadienis"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Sek", "Pir", "Ant", "Tre", "Ket", "Pen", "e", "Sek"); // full month names Calendar._MN = new Array ("Sausis", "Vasaris", "Kovas", "Balandis", "Gegu", "Birelis", "Liepa", "Rugpjtis", "Rugsjis", "Spalis", "Lapkritis", "Gruodis"); // short month names Calendar._SMN = new Array ("Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rgp", "Rgs", "Spa", "Lap", "Gru"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Apie kalendori"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Naujausi versij rasite: http://www.dynarch.com/projects/calendar/\n" + "Platinamas pagal GNU LGPL licencij. Aplankykite http://gnu.org/licenses/lgpl.html" + "\n\n" + "Datos pasirinkimas:\n" + "- Met pasirinkimas: \xab, \xbb\n" + "- Mnesio pasirinkimas: " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "\n" + "- Nuspauskite ir laikykite pels klavi greitesniam pasirinkimui."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Laiko pasirinkimas:\n" + "- Spustelkite ant valand arba minui - skaius padids vienetu.\n" + "- Jei spausite kartu su Shift, skaiius sumas.\n" + "- Greitam pasirinkimui spustelkite ir pajudinkite pel."; Calendar._TT["PREV_YEAR"] = "Ankstesni metai (laikykite, jei norite meniu)"; Calendar._TT["PREV_MONTH"] = "Ankstesnis mnuo (laikykite, jei norite meniu)"; Calendar._TT["GO_TODAY"] = "Pasirinkti iandien"; Calendar._TT["NEXT_MONTH"] = "Kitas mnuo (laikykite, jei norite meniu)"; Calendar._TT["NEXT_YEAR"] = "Kiti metai (laikykite, jei norite meniu)"; Calendar._TT["SEL_DATE"] = "Pasirinkite dat"; Calendar._TT["DRAG_TO_MOVE"] = "Tempkite"; Calendar._TT["PART_TODAY"] = " (iandien)"; Calendar._TT["MON_FIRST"] = "Pirma savaits diena - pirmadienis"; Calendar._TT["SUN_FIRST"] = "Pirma savaits diena - sekmadienis"; Calendar._TT["CLOSE"] = "Udaryti"; Calendar._TT["TODAY"] = "iandien"; Calendar._TT["TIME_PART"] = "Spustelkite arba tempkite jei norite pakeisti"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%A, %Y-%m-%d"; Calendar._TT["WK"] = "sav"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-lv.js000066400000000000000000000070231372046603600224170ustar00rootroot00000000000000// ** I18N // Calendar LV language // Author: Juris Valdovskis, // Encoding: cp1257 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Svtdiena", "Pirmdiena", "Otrdiena", "Trediena", "Ceturdiena", "Piektdiena", "Sestdiena", "Svtdiena"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se", "Sv"); // full month names Calendar._MN = new Array ("Janvris", "Februris", "Marts", "Aprlis", "Maijs", "Jnijs", "Jlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "Mar", "Apr", "Mai", "Jn", "Jl", "Aug", "Sep", "Okt", "Nov", "Dec"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Par kalendru"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Datuma izvle:\n" + "- Izmanto \xab, \xbb pogas, lai izvltos gadu\n" + "- Izmanto " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "pogas, lai izvltos mnesi\n" + "- Turi nospiestu peles pogu uz jebkuru no augstk mintajm pogm, lai patrintu izvli."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Laika izvle:\n" + "- Uzklikini uz jebkuru no laika dam, lai palielintu to\n" + "- vai Shift-klikis, lai samazintu to\n" + "- vai noklikini un velc uz attiecgo virzienu lai maintu trk."; Calendar._TT["PREV_YEAR"] = "Iepr. gads (turi izvlnei)"; Calendar._TT["PREV_MONTH"] = "Iepr. mnesis (turi izvlnei)"; Calendar._TT["GO_TODAY"] = "odien"; Calendar._TT["NEXT_MONTH"] = "Nkoais mnesis (turi izvlnei)"; Calendar._TT["NEXT_YEAR"] = "Nkoais gads (turi izvlnei)"; Calendar._TT["SEL_DATE"] = "Izvlies datumu"; Calendar._TT["DRAG_TO_MOVE"] = "Velc, lai prvietotu"; Calendar._TT["PART_TODAY"] = " (odien)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Attlot %s k pirmo"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "1,7"; Calendar._TT["CLOSE"] = "Aizvrt"; Calendar._TT["TODAY"] = "odien"; Calendar._TT["TIME_PART"] = "(Shift-)Klikis vai prvieto, lai maintu"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "Laiks:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-nl.js000066400000000000000000000042721372046603600224120ustar00rootroot00000000000000// ** I18N Calendar._DN = new Array ("Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"); Calendar._SDN_len = 2; Calendar._MN = new Array ("Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Info"; Calendar._TT["ABOUT"] = "DHTML Datum/Tijd Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + "Ga voor de meest recente versie naar: http://www.dynarch.com/projects/calendar/\n" + "Verspreid onder de GNU LGPL. Zie http://gnu.org/licenses/lgpl.html voor details." + "\n\n" + "Datum selectie:\n" + "- Gebruik de \xab \xbb knoppen om een jaar te selecteren\n" + "- Gebruik de " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " knoppen om een maand te selecteren\n" + "- Houd de muis ingedrukt op de genoemde knoppen voor een snellere selectie."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Tijd selectie:\n" + "- Klik op een willekeurig onderdeel van het tijd gedeelte om het te verhogen\n" + "- of Shift-klik om het te verlagen\n" + "- of klik en sleep voor een snellere selectie."; //Calendar._TT["TOGGLE"] = "Selecteer de eerste week-dag"; Calendar._TT["PREV_YEAR"] = "Vorig jaar (ingedrukt voor menu)"; Calendar._TT["PREV_MONTH"] = "Vorige maand (ingedrukt voor menu)"; Calendar._TT["GO_TODAY"] = "Ga naar Vandaag"; Calendar._TT["NEXT_MONTH"] = "Volgende maand (ingedrukt voor menu)"; Calendar._TT["NEXT_YEAR"] = "Volgend jaar (ingedrukt voor menu)"; Calendar._TT["SEL_DATE"] = "Selecteer datum"; Calendar._TT["DRAG_TO_MOVE"] = "Klik en sleep om te verplaatsen"; Calendar._TT["PART_TODAY"] = " (vandaag)"; //Calendar._TT["MON_FIRST"] = "Toon Maandag eerst"; //Calendar._TT["SUN_FIRST"] = "Toon Zondag eerst"; Calendar._TT["DAY_FIRST"] = "Toon %s eerst"; Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Sluiten"; Calendar._TT["TODAY"] = "(vandaag)"; Calendar._TT["TIME_PART"] = "(Shift-)Klik of sleep om de waarde te veranderen"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b %Y"; Calendar._TT["WK"] = "wk"; Calendar._TT["TIME"] = "Tijd:";nurpawiki-1.2.4/files/jscalendar/lang/calendar-no.js000066400000000000000000000061521372046603600224140ustar00rootroot00000000000000// ** I18N // Calendar NO language // Author: Daniel Holmen, // Encoding: UTF-8 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"); // full month names Calendar._MN = new Array ("Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Om kalenderen"; Calendar._TT["ABOUT"] = "DHTML Dato-/Tidsvelger\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For nyeste versjon, gå til: http://www.dynarch.com/projects/calendar/\n" + "Distribuert under GNU LGPL. Se http://gnu.org/licenses/lgpl.html for detaljer." + "\n\n" + "Datovalg:\n" + "- Bruk knappene \xab og \xbb for å velge år\n" + "- Bruk knappene " + String.fromCharCode(0x2039) + " og " + String.fromCharCode(0x203a) + " for å velge måned\n" + "- Hold inne musknappen eller knappene over for raskere valg."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Tidsvalg:\n" + "- Klikk på en av tidsdelene for å øke den\n" + "- eller Shift-klikk for å senke verdien\n" + "- eller klikk-og-dra for raskere valg.."; Calendar._TT["PREV_YEAR"] = "Forrige. år (hold for meny)"; Calendar._TT["PREV_MONTH"] = "Forrige. måned (hold for meny)"; Calendar._TT["GO_TODAY"] = "Gå til idag"; Calendar._TT["NEXT_MONTH"] = "Neste måned (hold for meny)"; Calendar._TT["NEXT_YEAR"] = "Neste år (hold for meny)"; Calendar._TT["SEL_DATE"] = "Velg dato"; Calendar._TT["DRAG_TO_MOVE"] = "Dra for å flytte"; Calendar._TT["PART_TODAY"] = " (idag)"; Calendar._TT["MON_FIRST"] = "Vis mandag først"; Calendar._TT["SUN_FIRST"] = "Vis søndag først"; Calendar._TT["CLOSE"] = "Lukk"; Calendar._TT["TODAY"] = "Idag"; Calendar._TT["TIME_PART"] = "(Shift-)Klikk eller dra for å endre verdi"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "uke";nurpawiki-1.2.4/files/jscalendar/lang/calendar-pl-utf8.js000066400000000000000000000051131372046603600232730ustar00rootroot00000000000000// ** I18N // Calendar PL language // Author: Dariusz Pietrzak, // Author: Janusz Piwowarski, // Encoding: utf-8 // Distributed under the same terms as the calendar itself. Calendar._DN = new Array ("Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"); Calendar._SDN = new Array ("Nie", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "Nie"); Calendar._MN = new Array ("Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"); Calendar._SMN = new Array ("Sty", "Lut", "Mar", "Kwi", "Maj", "Cze", "Lip", "Sie", "Wrz", "Paź", "Lis", "Gru"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "O kalendarzu"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Aby pobrać najnowszą wersję, odwiedź: http://www.dynarch.com/projects/calendar/\n" + "Dostępny na licencji GNU LGPL. Zobacz szczegóły na http://gnu.org/licenses/lgpl.html." + "\n\n" + "Wybór daty:\n" + "- Użyj przycisków \xab, \xbb by wybrać rok\n" + "- Użyj przycisków " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " by wybrać miesiąc\n" + "- Przytrzymaj klawisz myszy nad jednym z powyższych przycisków dla szybszego wyboru."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Wybór czasu:\n" + "- Kliknij na jednym z pól czasu by zwiększyć jego wartość\n" + "- lub kliknij trzymając Shift by zmiejszyć jego wartość\n" + "- lub kliknij i przeciągnij dla szybszego wyboru."; //Calendar._TT["TOGGLE"] = "Zmień pierwszy dzień tygodnia"; Calendar._TT["PREV_YEAR"] = "Poprzedni rok (przytrzymaj dla menu)"; Calendar._TT["PREV_MONTH"] = "Poprzedni miesiąc (przytrzymaj dla menu)"; Calendar._TT["GO_TODAY"] = "Idź do dzisiaj"; Calendar._TT["NEXT_MONTH"] = "Następny miesiąc (przytrzymaj dla menu)"; Calendar._TT["NEXT_YEAR"] = "Następny rok (przytrzymaj dla menu)"; Calendar._TT["SEL_DATE"] = "Wybierz datę"; Calendar._TT["DRAG_TO_MOVE"] = "Przeciągnij by przesunąć"; Calendar._TT["PART_TODAY"] = " (dzisiaj)"; Calendar._TT["MON_FIRST"] = "Wyświetl poniedziałek jako pierwszy"; Calendar._TT["SUN_FIRST"] = "Wyświetl niedzielę jako pierwszą"; Calendar._TT["CLOSE"] = "Zamknij"; Calendar._TT["TODAY"] = "Dzisiaj"; Calendar._TT["TIME_PART"] = "(Shift-)Kliknij lub przeciągnij by zmienić wartość"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%e %B, %A"; Calendar._TT["WK"] = "ty"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-pl.js000066400000000000000000000045561372046603600224210ustar00rootroot00000000000000// ** I18N // Calendar PL language // Author: Artur Filipiak, // January, 2004 // Encoding: UTF-8 Calendar._DN = new Array ("Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"); Calendar._SDN = new Array ("N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"); Calendar._MN = new Array ("Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"); Calendar._SMN = new Array ("Sty", "Lut", "Mar", "Kwi", "Maj", "Cze", "Lip", "Sie", "Wrz", "Paź", "Lis", "Gru"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "O kalendarzu"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Wybór daty:\n" + "- aby wybrać rok użyj przycisków \xab, \xbb\n" + "- aby wybrać miesiąc użyj przycisków " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "\n" + "- aby przyspieszyć wybór przytrzymaj wciśnięty przycisk myszy nad ww. przyciskami."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Wybór czasu:\n" + "- aby zwiększyć wartość kliknij na dowolnym elemencie selekcji czasu\n" + "- aby zmniejszyć wartość użyj dodatkowo klawisza Shift\n" + "- możesz również poruszać myszkę w lewo i prawo wraz z wciśniętym lewym klawiszem."; Calendar._TT["PREV_YEAR"] = "Poprz. rok (przytrzymaj dla menu)"; Calendar._TT["PREV_MONTH"] = "Poprz. miesiąc (przytrzymaj dla menu)"; Calendar._TT["GO_TODAY"] = "Pokaż dziś"; Calendar._TT["NEXT_MONTH"] = "Nast. miesiąc (przytrzymaj dla menu)"; Calendar._TT["NEXT_YEAR"] = "Nast. rok (przytrzymaj dla menu)"; Calendar._TT["SEL_DATE"] = "Wybierz datę"; Calendar._TT["DRAG_TO_MOVE"] = "Przesuń okienko"; Calendar._TT["PART_TODAY"] = " (dziś)"; Calendar._TT["MON_FIRST"] = "Pokaż Poniedziałek jako pierwszy"; Calendar._TT["SUN_FIRST"] = "Pokaż Niedzielę jako pierwszą"; Calendar._TT["CLOSE"] = "Zamknij"; Calendar._TT["TODAY"] = "Dziś"; Calendar._TT["TIME_PART"] = "(Shift-)klik | drag, aby zmienić wartość"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y.%m.%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "wk";nurpawiki-1.2.4/files/jscalendar/lang/calendar-pt.js000066400000000000000000000067061372046603600224300ustar00rootroot00000000000000// ** I18N // Calendar pt_BR language // Author: Adalberto Machado, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Domingo", "Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado", "Domingo"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab", "Dom"); // full month names Calendar._MN = new Array ("Janeiro", "Fevereiro", "Marco", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"); // short month names Calendar._SMN = new Array ("Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Sobre o calendario"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Ultima versao visite: http://www.dynarch.com/projects/calendar/\n" + "Distribuido sobre GNU LGPL. Veja http://gnu.org/licenses/lgpl.html para detalhes." + "\n\n" + "Selecao de data:\n" + "- Use os botoes \xab, \xbb para selecionar o ano\n" + "- Use os botoes " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para selecionar o mes\n" + "- Segure o botao do mouse em qualquer um desses botoes para selecao rapida."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Selecao de hora:\n" + "- Clique em qualquer parte da hora para incrementar\n" + "- ou Shift-click para decrementar\n" + "- ou clique e segure para selecao rapida."; Calendar._TT["PREV_YEAR"] = "Ant. ano (segure para menu)"; Calendar._TT["PREV_MONTH"] = "Ant. mes (segure para menu)"; Calendar._TT["GO_TODAY"] = "Hoje"; Calendar._TT["NEXT_MONTH"] = "Prox. mes (segure para menu)"; Calendar._TT["NEXT_YEAR"] = "Prox. ano (segure para menu)"; Calendar._TT["SEL_DATE"] = "Selecione a data"; Calendar._TT["DRAG_TO_MOVE"] = "Arraste para mover"; Calendar._TT["PART_TODAY"] = " (hoje)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Mostre %s primeiro"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Fechar"; Calendar._TT["TODAY"] = "Hoje"; Calendar._TT["TIME_PART"] = "(Shift-)Click ou arraste para mudar valor"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; Calendar._TT["WK"] = "sm"; Calendar._TT["TIME"] = "Hora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-ro.js000066400000000000000000000040121372046603600224110ustar00rootroot00000000000000// ** I18N Calendar._DN = new Array ("Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"); Calendar._SDN_len = 2; Calendar._MN = new Array ("Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Despre calendar"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Pentru ultima versiune vizitaţi: http://www.dynarch.com/projects/calendar/\n" + "Distribuit sub GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Selecţia datei:\n" + "- Folosiţi butoanele \xab, \xbb pentru a selecta anul\n" + "- Folosiţi butoanele " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pentru a selecta luna\n" + "- Tineţi butonul mouse-ului apăsat pentru selecţie mai rapidă."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Selecţia orei:\n" + "- Click pe ora sau minut pentru a mări valoarea cu 1\n" + "- Sau Shift-Click pentru a micşora valoarea cu 1\n" + "- Sau Click şi drag pentru a selecta mai repede."; Calendar._TT["PREV_YEAR"] = "Anul precedent (lung pt menu)"; Calendar._TT["PREV_MONTH"] = "Luna precedentă (lung pt menu)"; Calendar._TT["GO_TODAY"] = "Data de azi"; Calendar._TT["NEXT_MONTH"] = "Luna următoare (lung pt menu)"; Calendar._TT["NEXT_YEAR"] = "Anul următor (lung pt menu)"; Calendar._TT["SEL_DATE"] = "Selectează data"; Calendar._TT["DRAG_TO_MOVE"] = "Trage pentru a mişca"; Calendar._TT["PART_TODAY"] = " (astăzi)"; Calendar._TT["DAY_FIRST"] = "Afişează %s prima zi"; Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Închide"; Calendar._TT["TODAY"] = "Astăzi"; Calendar._TT["TIME_PART"] = "(Shift-)Click sau drag pentru a selecta"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; Calendar._TT["TT_DATE_FORMAT"] = "%A, %d %B"; Calendar._TT["WK"] = "spt"; Calendar._TT["TIME"] = "Ora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-ru.js000066400000000000000000000104051372046603600224220ustar00rootroot00000000000000// ** I18N // Calendar RU language // Translation: Sly Golovanov, http://golovanov.net, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("вск", "пон", "втр", "срд", "чет", "пят", "суб", "вск"); // full month names Calendar._MN = new Array ("январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"); // short month names Calendar._SMN = new Array ("янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "О календаре..."; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "Как выбрать дату:\n" + "- При помощи кнопок \xab, \xbb можно выбрать год\n" + "- При помощи кнопок " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " можно выбрать месяц\n" + "- Подержите эти кнопки нажатыми, чтобы появилось меню быстрого выбора."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Как выбрать время:\n" + "- При клике на часах или минутах они увеличиваются\n" + "- при клике с нажатой клавишей Shift они уменьшаются\n" + "- если нажать и двигать мышкой влево/вправо, они будут меняться быстрее."; Calendar._TT["PREV_YEAR"] = "На год назад (удерживать для меню)"; Calendar._TT["PREV_MONTH"] = "На месяц назад (удерживать для меню)"; Calendar._TT["GO_TODAY"] = "Сегодня"; Calendar._TT["NEXT_MONTH"] = "На месяц вперед (удерживать для меню)"; Calendar._TT["NEXT_YEAR"] = "На год вперед (удерживать для меню)"; Calendar._TT["SEL_DATE"] = "Выберите дату"; Calendar._TT["DRAG_TO_MOVE"] = "Перетаскивайте мышкой"; Calendar._TT["PART_TODAY"] = " (сегодня)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Первый день недели будет %s"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Закрыть"; Calendar._TT["TODAY"] = "Сегодня"; Calendar._TT["TIME_PART"] = "(Shift-)клик или нажать и двигать"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%e %b, %a"; Calendar._TT["WK"] = "нед"; Calendar._TT["TIME"] = "Время:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-ru_win_.js000066400000000000000000000070731372046603600234450ustar00rootroot00000000000000// ** I18N // Calendar RU language // Translation: Sly Golovanov, http://golovanov.net, // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("", "", "", "", "", "", "", ""); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("", "", "", "", "", "", "", ""); // full month names Calendar._MN = new Array ("", "", "", "", "", "", "", "", "", "", "", ""); // short month names Calendar._SMN = new Array ("", "", "", "", "", "", "", "", "", "", "", ""); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = " ..."; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + " :\n" + "- \xab, \xbb \n" + "- " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " \n" + "- , ."; Calendar._TT["ABOUT_TIME"] = "\n\n" + " :\n" + "- \n" + "- Shift \n" + "- /, ."; Calendar._TT["PREV_YEAR"] = " ( )"; Calendar._TT["PREV_MONTH"] = " ( )"; Calendar._TT["GO_TODAY"] = ""; Calendar._TT["NEXT_MONTH"] = " ( )"; Calendar._TT["NEXT_YEAR"] = " ( )"; Calendar._TT["SEL_DATE"] = " "; Calendar._TT["DRAG_TO_MOVE"] = " "; Calendar._TT["PART_TODAY"] = " ()"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = " %s"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = ""; Calendar._TT["TODAY"] = ""; Calendar._TT["TIME_PART"] = "(Shift-) "; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%e %b, %a"; Calendar._TT["WK"] = ""; Calendar._TT["TIME"] = ":"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-si.js000066400000000000000000000051741372046603600224160ustar00rootroot00000000000000/* Slovenian language file for the DHTML Calendar version 0.9.2 * Author David Milost , January 2004. * Feel free to use this script under the terms of the GNU Lesser General * Public License, as long as you do not remove or alter this notice. */ // full day names Calendar._DN = new Array ("Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"); // short day names Calendar._SDN = new Array ("Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"); // full month names Calendar._MN = new Array ("Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"); // tooltips // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "O koledarju"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Za zadnjo verzijo pojdine na naslov: http://www.dynarch.com/projects/calendar/\n" + "Distribuirano pod GNU LGPL. Poglejte http://gnu.org/licenses/lgpl.html za podrobnosti." + "\n\n" + "Izbor datuma:\n" + "- Uporabite \xab, \xbb gumbe za izbor leta\n" + "- Uporabite " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " gumbe za izbor meseca\n" + "- Zadržite klik na kateremkoli od zgornjih gumbov za hiter izbor."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Izbor ćasa:\n" + "- Kliknite na katerikoli del ćasa za poveć. le-tega\n" + "- ali Shift-click za zmanj. le-tega\n" + "- ali kliknite in povlecite za hiter izbor."; Calendar._TT["TOGGLE"] = "Spremeni dan s katerim se prićne teden"; Calendar._TT["PREV_YEAR"] = "Predhodnje leto (dolg klik za meni)"; Calendar._TT["PREV_MONTH"] = "Predhodnji mesec (dolg klik za meni)"; Calendar._TT["GO_TODAY"] = "Pojdi na tekoći dan"; Calendar._TT["NEXT_MONTH"] = "Naslednji mesec (dolg klik za meni)"; Calendar._TT["NEXT_YEAR"] = "Naslednje leto (dolg klik za meni)"; Calendar._TT["SEL_DATE"] = "Izberite datum"; Calendar._TT["DRAG_TO_MOVE"] = "Pritisni in povleci za spremembo pozicije"; Calendar._TT["PART_TODAY"] = " (danes)"; Calendar._TT["MON_FIRST"] = "Prikaži ponedeljek kot prvi dan"; Calendar._TT["SUN_FIRST"] = "Prikaži nedeljo kot prvi dan"; Calendar._TT["CLOSE"] = "Zapri"; Calendar._TT["TODAY"] = "Danes"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "Ted";nurpawiki-1.2.4/files/jscalendar/lang/calendar-sk.js000066400000000000000000000051451372046603600224160ustar00rootroot00000000000000// ** I18N // Calendar SK language // Author: Peter Valach (pvalach@gmx.net) // Encoding: utf-8 // Last update: 2003/10/29 // Distributed under the same terms as the calendar itself. // full day names Calendar._DN = new Array ("NedeÄľa", "Pondelok", "Utorok", "Streda", "Ĺ tvrtok", "Piatok", "Sobota", "NedeÄľa"); // short day names Calendar._SDN = new Array ("Ned", "Pon", "Uto", "Str", "Ĺ tv", "Pia", "Sob", "Ned"); // full month names Calendar._MN = new Array ("Január", "Február", "Marec", "AprĂ­l", "Máj", "JĂşn", "JĂşl", "August", "September", "OktĂłber", "November", "December"); // short month names Calendar._SMN = new Array ("Jan", "Feb", "Mar", "Apr", "Máj", "JĂşn", "JĂşl", "Aug", "Sep", "Okt", "Nov", "Dec"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "O kalendári"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + "PoslednĂş verziu nájdete na: http://www.dynarch.com/projects/calendar/\n" + "DistribuovanĂ© pod GNU LGPL. ViÄŹ http://gnu.org/licenses/lgpl.html pre detaily." + "\n\n" + "VĂ˝ber dátumu:\n" + "- PouĹľite tlaÄŤidlá \xab, \xbb pre vĂ˝ber roku\n" + "- PouĹľite tlaÄŤidlá " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pre vĂ˝ber mesiaca\n" + "- Ak ktorĂ©koÄľvek z tĂ˝chto tlaÄŤidiel podržíte dlhšie, zobrazĂ­ sa rĂ˝chly vĂ˝ber."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "VĂ˝ber ÄŤasu:\n" + "- Kliknutie na niektorĂş poloĹľku ÄŤasu ju zvýši\n" + "- Shift-klik ju znĂ­Ĺľi\n" + "- Ak podržíte tlaÄŤĂ­tko stlaÄŤenĂ©, posĂşvanĂ­m menĂ­te hodnotu."; Calendar._TT["PREV_YEAR"] = "PredošlĂ˝ rok (podrĹľte pre menu)"; Calendar._TT["PREV_MONTH"] = "PredošlĂ˝ mesiac (podrĹľte pre menu)"; Calendar._TT["GO_TODAY"] = "PrejsĹĄ na dnešok"; Calendar._TT["NEXT_MONTH"] = "Nasl. mesiac (podrĹľte pre menu)"; Calendar._TT["NEXT_YEAR"] = "Nasl. rok (podrĹľte pre menu)"; Calendar._TT["SEL_DATE"] = "ZvoÄľte dátum"; Calendar._TT["DRAG_TO_MOVE"] = "PodrĹľanĂ­m tlaÄŤĂ­tka zmenĂ­te polohu"; Calendar._TT["PART_TODAY"] = " (dnes)"; Calendar._TT["MON_FIRST"] = "ZobraziĹĄ pondelok ako prvĂ˝"; Calendar._TT["SUN_FIRST"] = "ZobraziĹĄ nedeÄľu ako prvĂş"; Calendar._TT["CLOSE"] = "ZavrieĹĄ"; Calendar._TT["TODAY"] = "Dnes"; Calendar._TT["TIME_PART"] = "(Shift-)klik/ĹĄahanie zmenĂ­ hodnotu"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "$d. %m. %Y"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %e. %b"; Calendar._TT["WK"] = "týž"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-sp.js000066400000000000000000000057071372046603600224270ustar00rootroot00000000000000// ** I18N // Calendar SP language // Author: Rafael Velasco // Encoding: any // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"); Calendar._SDN = new Array ("Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab", "Dom"); // full month names Calendar._MN = new Array ("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"); // short month names Calendar._SMN = new Array ("Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Informacin del Calendario"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Nuevas versiones en: http://www.dynarch.com/projects/calendar/\n" + "Distribuida bajo licencia GNU LGPL. Para detalles vea http://gnu.org/licenses/lgpl.html ." + "\n\n" + "Seleccin de Fechas:\n" + "- Use \xab, \xbb para seleccionar el ao\n" + "- Use " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar el mes\n" + "- Mantenga presionado el botn del ratn en cualquiera de las opciones superiores para un acceso rapido ."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Seleccin del Reloj:\n" + "- Seleccione la hora para cambiar el reloj\n" + "- o presione Shift-click para disminuirlo\n" + "- o presione click y arrastre del ratn para una seleccin rapida."; Calendar._TT["PREV_YEAR"] = "Ao anterior (Presione para menu)"; Calendar._TT["PREV_MONTH"] = "Mes Anterior (Presione para menu)"; Calendar._TT["GO_TODAY"] = "Ir a Hoy"; Calendar._TT["NEXT_MONTH"] = "Mes Siguiente (Presione para menu)"; Calendar._TT["NEXT_YEAR"] = "Ao Siguiente (Presione para menu)"; Calendar._TT["SEL_DATE"] = "Seleccione fecha"; Calendar._TT["DRAG_TO_MOVE"] = "Arrastre y mueva"; Calendar._TT["PART_TODAY"] = " (Hoy)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "Mostrar %s primero"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "Cerrar"; Calendar._TT["TODAY"] = "Hoy"; Calendar._TT["TIME_PART"] = "(Shift-)Click o arrastra para cambar el valor"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%dd-%mm-%yy"; Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; Calendar._TT["WK"] = "Sm"; Calendar._TT["TIME"] = "Hora:"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-sv.js000066400000000000000000000062051372046603600224270ustar00rootroot00000000000000// ** I18N // Calendar SV language (Swedish, svenska) // Author: Mihai Bazon, // Translation team: // Translator: Leonard Norrgrd // Last translator: Leonard Norrgrd // Encoding: iso-latin-1 // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("sndag", "mndag", "tisdag", "onsdag", "torsdag", "fredag", "lrdag", "sndag"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. Calendar._SDN_len = 2; Calendar._SMN_len = 3; // full month names Calendar._MN = new Array ("januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "Om kalendern"; Calendar._TT["ABOUT"] = "DHTML Datum/tid-vljare\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "Fr senaste version g till: http://www.dynarch.com/projects/calendar/\n" + "Distribueras under GNU LGPL. Se http://gnu.org/licenses/lgpl.html fr detaljer." + "\n\n" + "Val av datum:\n" + "- Anvnd knapparna \xab, \xbb fr att vlja r\n" + "- Anvnd knapparna " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " fr att vlja mnad\n" + "- Hll musknappen nedtryckt p ngon av ovanstende knappar fr snabbare val."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Val av tid:\n" + "- Klicka p en del av tiden fr att ka den delen\n" + "- eller skift-klicka fr att minska den\n" + "- eller klicka och drag fr snabbare val."; Calendar._TT["PREV_YEAR"] = "Fregende r (hll fr menu)"; Calendar._TT["PREV_MONTH"] = "Fregende mnad (hll fr menu)"; Calendar._TT["GO_TODAY"] = "G till dagens datum"; Calendar._TT["NEXT_MONTH"] = "Fljande mnad (hll fr menu)"; Calendar._TT["NEXT_YEAR"] = "Fljande r (hll fr menu)"; Calendar._TT["SEL_DATE"] = "Vlj datum"; Calendar._TT["DRAG_TO_MOVE"] = "Drag fr att flytta"; Calendar._TT["PART_TODAY"] = " (idag)"; Calendar._TT["MON_FIRST"] = "Visa mndag frst"; Calendar._TT["SUN_FIRST"] = "Visa sndag frst"; Calendar._TT["CLOSE"] = "Stng"; Calendar._TT["TODAY"] = "Idag"; Calendar._TT["TIME_PART"] = "(Skift-)klicka eller drag fr att ndra tid"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%A %d %b %Y"; Calendar._TT["WK"] = "vecka"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-tr.js000066400000000000000000000033101372046603600224160ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////////////////////////// // Turkish Translation by Nuri AKMAN // Location: Ankara/TURKEY // e-mail : nuriakman@hotmail.com // Date : April, 9 2003 // // Note: if Turkish Characters does not shown on you screen // please include falowing line your html code: // // // ////////////////////////////////////////////////////////////////////////////////////////////// // ** I18N Calendar._DN = new Array ("Pazar", "Pazartesi", "Sal", "aramba", "Perembe", "Cuma", "Cumartesi", "Pazar"); Calendar._MN = new Array ("Ocak", "ubat", "Mart", "Nisan", "Mays", "Haziran", "Temmuz", "Austos", "Eyll", "Ekim", "Kasm", "Aralk"); // tooltips Calendar._TT = {}; Calendar._TT["TOGGLE"] = "Haftann ilk gnn kaydr"; Calendar._TT["PREV_YEAR"] = "nceki Yl (Men iin basl tutunuz)"; Calendar._TT["PREV_MONTH"] = "nceki Ay (Men iin basl tutunuz)"; Calendar._TT["GO_TODAY"] = "Bugn'e git"; Calendar._TT["NEXT_MONTH"] = "Sonraki Ay (Men iin basl tutunuz)"; Calendar._TT["NEXT_YEAR"] = "Sonraki Yl (Men iin basl tutunuz)"; Calendar._TT["SEL_DATE"] = "Tarih seiniz"; Calendar._TT["DRAG_TO_MOVE"] = "Tamak iin srkleyiniz"; Calendar._TT["PART_TODAY"] = " (bugn)"; Calendar._TT["MON_FIRST"] = "Takvim Pazartesi gnnden balasn"; Calendar._TT["SUN_FIRST"] = "Takvim Pazar gnnden balasn"; Calendar._TT["CLOSE"] = "Kapat"; Calendar._TT["TODAY"] = "Bugn"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; Calendar._TT["TT_DATE_FORMAT"] = "d MM y, DD"; Calendar._TT["WK"] = "Hafta"; nurpawiki-1.2.4/files/jscalendar/lang/calendar-zh.js000066400000000000000000000060121372046603600224140ustar00rootroot00000000000000// ** I18N // Calendar ZH language // Author: muziq, // Encoding: GB2312 or GBK // Distributed under the same terms as the calendar itself. // full day names Calendar._DN = new Array ("", "һ", "ڶ", "", "", "", "", ""); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("", "һ", "", "", "", "", "", ""); // full month names Calendar._MN = new Array ("һ", "", "", "", "", "", "", "", "", "ʮ", "ʮһ", "ʮ"); // short month names Calendar._SMN = new Array ("һ", "", "", "", "", "", "", "", "", "ʮ", "ʮһ", "ʮ"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = ""; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: http://www.dynarch.com/projects/calendar/\n" + "Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + "\n\n" + "ѡ:\n" + "- \xab, \xbb ťѡ\n" + "- " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " ťѡ·\n" + "- ϰťɴӲ˵пѡݻ·"; Calendar._TT["ABOUT_TIME"] = "\n\n" + "ѡʱ:\n" + "- Сʱӿʹֵһ\n" + "- סShiftСʱӿʹֵһ\n" + "- ϶ɽпѡ"; Calendar._TT["PREV_YEAR"] = "һ (ס˵)"; Calendar._TT["PREV_MONTH"] = "һ (ס˵)"; Calendar._TT["GO_TODAY"] = "ת"; Calendar._TT["NEXT_MONTH"] = "һ (ס˵)"; Calendar._TT["NEXT_YEAR"] = "һ (ס˵)"; Calendar._TT["SEL_DATE"] = "ѡ"; Calendar._TT["DRAG_TO_MOVE"] = "϶"; Calendar._TT["PART_TODAY"] = " ()"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "ʾ%s"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "ر"; Calendar._TT["TODAY"] = ""; Calendar._TT["TIME_PART"] = "(Shift-)϶ıֵ"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%A, %b %e"; Calendar._TT["WK"] = ""; Calendar._TT["TIME"] = "ʱ:"; nurpawiki-1.2.4/files/jscalendar/lang/cn_utf8.js000066400000000000000000000110261372046603600215730ustar00rootroot00000000000000// ** I18N // Calendar EN language // Author: Mihai Bazon, // Encoding: any // Translator : Niko // Distributed under the same terms as the calendar itself. // For translators: please use UTF-8 if possible. We strongly believe that // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. // full day names Calendar._DN = new Array ("\u5468\u65e5",//\u5468\u65e5 "\u5468\u4e00",//\u5468\u4e00 "\u5468\u4e8c",//\u5468\u4e8c "\u5468\u4e09",//\u5468\u4e09 "\u5468\u56db",//\u5468\u56db "\u5468\u4e94",//\u5468\u4e94 "\u5468\u516d",//\u5468\u516d "\u5468\u65e5");//\u5468\u65e5 // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here // for exemplification on how one can customize the short day names, but if // they are simply the first N letters of the full name you can simply say: // // Calendar._SDN_len = N; // short day name length // Calendar._SMN_len = N; // short month name length // // If N = 3 then this is not needed either since we assume a value of 3 if not // present, to be compatible with translation files that were written before // this feature. // short day names Calendar._SDN = new Array ("\u5468\u65e5", "\u5468\u4e00", "\u5468\u4e8c", "\u5468\u4e09", "\u5468\u56db", "\u5468\u4e94", "\u5468\u516d", "\u5468\u65e5"); // full month names Calendar._MN = new Array ("\u4e00\u6708", "\u4e8c\u6708", "\u4e09\u6708", "\u56db\u6708", "\u4e94\u6708", "\u516d\u6708", "\u4e03\u6708", "\u516b\u6708", "\u4e5d\u6708", "\u5341\u6708", "\u5341\u4e00\u6708", "\u5341\u4e8c\u6708"); // short month names Calendar._SMN = new Array ("\u4e00\u6708", "\u4e8c\u6708", "\u4e09\u6708", "\u56db\u6708", "\u4e94\u6708", "\u516d\u6708", "\u4e03\u6708", "\u516b\u6708", "\u4e5d\u6708", "\u5341\u6708", "\u5341\u4e00\u6708", "\u5341\u4e8c\u6708"); // tooltips Calendar._TT = {}; Calendar._TT["INFO"] = "\u5173\u4e8e"; Calendar._TT["ABOUT"] = " DHTML \u65e5\u8d77/\u65f6\u95f4\u9009\u62e9\u63a7\u4ef6\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) "For latest version visit: \u6700\u65b0\u7248\u672c\u8bf7\u767b\u9646http://www.dynarch.com/projects/calendar/\u5bdf\u770b\n" + "\u9075\u5faaGNU LGPL. \u7ec6\u8282\u53c2\u9605 http://gnu.org/licenses/lgpl.html" + "\n\n" + "\u65e5\u671f\u9009\u62e9:\n" + "- \u70b9\u51fb\xab(\xbb)\u6309\u94ae\u9009\u62e9\u4e0a(\u4e0b)\u4e00\u5e74\u5ea6.\n" + "- \u70b9\u51fb" + String.fromCharCode(0x2039) + "(" + String.fromCharCode(0x203a) + ")\u6309\u94ae\u9009\u62e9\u4e0a(\u4e0b)\u4e2a\u6708\u4efd.\n" + "- \u957f\u65f6\u95f4\u6309\u7740\u6309\u94ae\u5c06\u51fa\u73b0\u66f4\u591a\u9009\u62e9\u9879."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "\u65f6\u95f4\u9009\u62e9:\n" + "-\u5728\u65f6\u95f4\u90e8\u5206(\u5206\u6216\u8005\u79d2)\u4e0a\u5355\u51fb\u9f20\u6807\u5de6\u952e\u6765\u589e\u52a0\u5f53\u524d\u65f6\u95f4\u90e8\u5206(\u5206\u6216\u8005\u79d2)\n" + "-\u5728\u65f6\u95f4\u90e8\u5206(\u5206\u6216\u8005\u79d2)\u4e0a\u6309\u4f4fShift\u952e\u540e\u5355\u51fb\u9f20\u6807\u5de6\u952e\u6765\u51cf\u5c11\u5f53\u524d\u65f6\u95f4\u90e8\u5206(\u5206\u6216\u8005\u79d2)."; Calendar._TT["PREV_YEAR"] = "\u4e0a\u4e00\u5e74"; Calendar._TT["PREV_MONTH"] = "\u4e0a\u4e2a\u6708"; Calendar._TT["GO_TODAY"] = "\u5230\u4eca\u5929"; Calendar._TT["NEXT_MONTH"] = "\u4e0b\u4e2a\u6708"; Calendar._TT["NEXT_YEAR"] = "\u4e0b\u4e00\u5e74"; Calendar._TT["SEL_DATE"] = "\u9009\u62e9\u65e5\u671f"; Calendar._TT["DRAG_TO_MOVE"] = "\u62d6\u52a8"; Calendar._TT["PART_TODAY"] = " (\u4eca\u5929)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. Calendar._TT["DAY_FIRST"] = "%s\u4e3a\u8fd9\u5468\u7684\u7b2c\u4e00\u5929"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "\u5173\u95ed"; Calendar._TT["TODAY"] = "\u4eca\u5929"; Calendar._TT["TIME_PART"] = "(\u6309\u7740Shift\u952e)\u5355\u51fb\u6216\u62d6\u52a8\u6539\u53d8\u503c"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e\u65e5"; Calendar._TT["WK"] = "\u5468"; Calendar._TT["TIME"] = "\u65f6\u95f4:"; nurpawiki-1.2.4/files/jscalendar/menuarrow.gif000066400000000000000000000001041372046603600214470ustar00rootroot00000000000000GIF89a!,D%J(QD%J;nurpawiki-1.2.4/files/jscalendar/menuarrow2.gif000066400000000000000000000000611372046603600215330ustar00rootroot00000000000000GIF89aBBB!,yc;nurpawiki-1.2.4/files/jscalendar/skins/000077500000000000000000000000001372046603600200755ustar00rootroot00000000000000nurpawiki-1.2.4/files/jscalendar/skins/aqua/000077500000000000000000000000001372046603600210245ustar00rootroot00000000000000nurpawiki-1.2.4/files/jscalendar/skins/aqua/active-bg.gif000066400000000000000000000001311372046603600233470ustar00rootroot00000000000000GIF89a(S4l", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ background: url("title-bg.gif") repeat-x 0 100%; color: #000; font-weight: bold; } .calendar .nav { font-family: verdana,tahoma,sans-serif; } .calendar .nav div { background: transparent url("menuarrow.gif") no-repeat 100% 100%; } .calendar thead tr { background: url("title-bg.gif") repeat-x 0 100%; color: #000; } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; padding: 2px; background: url("title-bg.gif") repeat-x 0 100%; color: #000; } .calendar thead .headrow { /* Row containing navigation buttons */ } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #797979; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #c44; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background: url("hover-bg.gif"); border-bottom: 1px solid #797979; padding: 2px 2px 1px 2px; } .calendar thead .active { /* Active (pressed) buttons in header */ background: url("active-bg.gif"); color: #fff; padding: 3px 1px 0px 3px; border-bottom: 1px solid #797979; } .calendar thead .daynames { /* Row containing the day names */ background: url("dark-bg.gif"); } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ font-family: verdana,tahoma,sans-serif; width: 2em; color: #000; text-align: right; padding: 2px 4px 2px 2px; } .calendar tbody .day.othermonth { font-size: 80%; color: #999; } .calendar tbody .day.othermonth.oweekend { color: #f99; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #797979; background: url("dark-bg.gif"); } .calendar tbody .rowhilite td, .calendar tbody .rowhilite td.wn { background: url("rowhover-bg.gif"); } .calendar tbody td.today { font-weight: bold; /* background: url("today-bg.gif") no-repeat 70% 50%; */ } .calendar tbody td.hilite { /* Hovered cells */ background: url("hover-bg.gif"); padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ padding: 2px 2px 0px 2px; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #c44; } .calendar tbody td.selected { /* Cell showing selected date */ font-weight: bold; border: 1px solid #797979; padding: 1px 3px 1px 1px; background: url("active-bg.gif"); color: #fff; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #565; color: #fff; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ padding: 2px; background: url("status-bg.gif") repeat-x 0 0; color: #000; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #afa; border: 1px solid #084; color: #000; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #7c7; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .calendar .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border-width: 0 1px 1px 1px; border-style: solid; border-color: #797979; background: url("normal-bg.gif"); color: #000; z-index: 100; font-size: 90%; } .calendar .combo .label, .calendar .combo .label-IEfix { text-align: center; padding: 1px; } .calendar .combo .label-IEfix { width: 4em; } .calendar .combo .hilite { background: url("hover-bg.gif"); color: #000; } .calendar .combo .active { background: url("active-bg.gif"); color: #fff; font-weight: bold; } .calendar td.time { border-top: 1px solid #797979; padding: 1px 0px; text-align: center; background: url("dark-bg.gif"); } .calendar td.time .hour, .calendar td.time .minute, .calendar td.time .ampm { padding: 0px 5px 0px 6px; font-weight: bold; background: url("normal-bg.gif"); color: #000; } .calendar td.time .hour, .calendar td.time .minute { font-family: monospace; } .calendar td.time .ampm { text-align: center; } .calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } .calendar td.time span.hilite { background: url("hover-bg.gif"); color: #000; } .calendar td.time span.active { background: url("active-bg.gif"); color: #fff; } nurpawiki-1.2.4/files/jscalendar/skins/aqua/title-bg.gif000066400000000000000000000001641372046603600232230ustar00rootroot00000000000000GIF89ayyy!Created with The GIMP,5v[(5CPCĠD;nurpawiki-1.2.4/files/jscalendar/skins/aqua/today-bg.gif000066400000000000000000000021421372046603600232200ustar00rootroot00000000000000GIF89a    "#"!/1,-?C4NS0156?D9MAHCUVTdgh^bfwuxs~! ,H -XE"J'5z/?ǑIG%R( -Τ'/2(C@ ALx!@ + K,d9x&+(QXI PI+f`n "$ȇLV9 < I$Aa^ϓ8)'S0 J[W| БeP9uem d @`Q 4YK-fQ+U(0D)FDr w(Q@;nurpawiki-1.2.4/files/mark_complete.png000066400000000000000000000003301372046603600201640ustar00rootroot00000000000000PNG  IHDR &qbKGDC pHYs  tIME |^DeIDATxڥ 0MI[V#-Z)| I6lfmfZս4TVt,IJ$ zʋo6"tw<~ -MaK4IENDB`nurpawiki-1.2.4/files/nurpawiki.js000066400000000000000000000004571372046603600172150ustar00rootroot00000000000000 function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = func; } else { window.onload = function() { if (oldonload) { oldonload(); } func(); } } } nurpawiki-1.2.4/files/nurpawiki_calendar.js000066400000000000000000000014771372046603600210510ustar00rootroot00000000000000 // Register jscalendar selectors for cal_trigger named buttons. Each // cal_trigger named button has an id of form 'button_' where // is the todo's DB id. For each such element, there should exist a // 'calendar_' element that contains the date to be edited. function nwRegisterCalendar() { cals = document.getElementsByTagName("button"); re = new RegExp("^cal_button_([0-9]+)$"); for (var i = 0; i < cals.length; i++) { var m = re.exec(cals[i].id); if (m != null) { var todo_id = m[1]; Calendar.setup( { inputField : "calendar_"+todo_id, ifFormat : "%Y-%m-%d", button : m[0] } ); } } } addLoadEvent(nwRegisterCalendar); nurpawiki-1.2.4/files/nurpawiki_scheduler.js000066400000000000000000000013351372046603600212470ustar00rootroot00000000000000 function nwSetButtonCheckedState(v) { var inputs = document.getElementsByTagName("input"); var re = new RegExp("^t-([0-9]+)$"); for (var i = 0; i < inputs.length; i++) { var m = re.exec(inputs[i].name); if (m != null) { inputs[i].checked = v; } } } function nwSelectAllButton() { nwSetButtonCheckedState(true); } function nwDeselectAllButton() { nwSetButtonCheckedState(false); } function nwRegisterSchedulerButtons() { var b = document.getElementById("button_select_all"); b.onclick = nwSelectAllButton; var b = document.getElementById("button_deselect_all"); b.onclick = nwDeselectAllButton; } addLoadEvent(nwRegisterSchedulerButtons); nurpawiki-1.2.4/files/style.css000066400000000000000000000100451372046603600165120ustar00rootroot00000000000000body { font-family: Verdana,Geneva,Arial,Sans-serif; font-size: 12px; background-color : #FFFFFF } img { border: 0px none; } a:visited { color : #000080; ; text-decoration : underline; } a:link { color : #2222FF; ; text-decoration : underline; } a:hover { text-decoration : none; } a.cancel_edit { color : Red; font-weight:bold; } a.wiki_pri_lo { background-color: #ada; } a.wiki_pri_med { background-color: #dda; } a.wiki_pri_hi { background-color: #daa; } a.missing_page:visited { color : Red; text-decoration : underline; } a.missing_page:link { color : Red; text-decoration : underline; } a.missing_page:hover { color : Red; text-decoration : none; } /* Accesskey'd links -- first letter underlined */ a.ak { text-decoration: underline; } a.ak:hover { color:#2222FF; text-decoration: none;} a.ak:focus { color:#2222FF; text-decoration: none;} a.ak:first-letter { color:#2222FF; text-decoration: none; font-weight:bold; } a.palette0 { color:rgb(128, 6, 25); } a.palette1 { color:rgb(0, 104, 28); } a.palette2 { color:rgb(0, 148, 145); } a.palette3 { color:rgb(91, 16, 148); } a.palette4 { color:rgb(170, 107, 0); } a.palette5 { color:rgb(211, 0, 96); } a.palette6 { color:rgb(0, 91, 105); } a.palette7 { color:rgb(185, 0, 56); } a.palette8 { color:rgb(0, 98, 84); } a.palette9 { color:rgb(0, 104, 53); } a.palette10 { color:rgb(132, 102, 0); } a.palette11 { color:rgb(51, 0, 153); } .no_break { white-space:nowrap; } /* TODO items */ .todo_descr { color:#222; font-size : smaller; } .todo_descr_completed { color:#777; text-decoration : line-through; font-size: smaller; } .todo_pri_lo { background-color: #cfc; } .todo_pri_med { background-color: #ffc; } .todo_pri_hi { background-color: #fcc; } .todo_table_completed { text-decoration : line-through; color:#555; } .todo_table { font-size : smaller; } .todo_priority_changed { font-weight: bold; } .todo_completed_row { background-color:#ddd; } .rm_odd_row { background-color:#ddf; } .rm_even_row { background-color:#bbe; } .rm_table_heading { color:#777; font-size:smaller; text-align:right; font-style:italic; } .rm_edit { text-align:right; } .h_date_heading { color:#777; text-align:right; font-style:italic; } .act_date_input { text-align: center; background-color: #ccc; } .scheduler_check_button { font-size: 0.75em; } .error { color : Red; font-weight:bold; } .todo_owner { color : #558; } /* Search results */ .sr_link { font-size: 1.15em; } .sr_hilite { background-color: #ff9; } code { color : #000070 } pre { color : #000070 } h4.entry { text-decoration: underline } h1 { text-align: left; color:#AF4040; } h1.left_aligned { text-align: left; } h4 { margin-bottom:0px; margin-top:0px; } h2 {color:#BF3030; } html, body { margin: 0; padding: 0; } .top_menu_size { width:100%; } .top_menu_left_align { text-align: left; vertical-align: bottom; padding: 5px; } .top_menu_right_align { text-align: right; vertical-align: bottom; padding: 5px; } #login_outer { height:100%; } #login_align_middle { position:absolute; top: 35%; left: 30%; text-align:left; padding: 5px; } .login_text { font-weight:bold; color:#fff; } .login_text_descr { color:#fff; } table.login_box { background-color:#77c; padding: 5px; border: 3px solid #99f; } .login_link_big { font-size:1.2em; font-weight:bold; } .action_bar { padding-left:10px; padding-right:10px; padding-top:3px; padding-bottom:3px; background-color:#ff9; color:#000; } .undo_link { color:#338; } #topbar { margin-top:5px; margin-left:10px; margin-right:10px; float:top; height:50px; border-bottom: 2px solid #ccf; } #top_action_bar { margin-top:5px; margin-left:10px; margin-right:10px; margin-bottom:5px; float:top; height:10px;; background-color:#fff; padding:10px; text-align:center; font-weight:bold; } #navbar { width: 300px; float: left; margin-left: 0px; margin-top: 2px; padding: 12px; } #content { padding: 5px; margin-left: 400px; } a#login_help_url { color : Black; font-weight:bold; } nurpawiki-1.2.4/gen_ocsigen_config000077500000000000000000000053771372046603600173050ustar00rootroot00000000000000#!/bin/sh #------------------------------------------------------------------ # Configure OCaml library paths based on information queried from # ocamlfind & command line and creates a configuration file for # Ocsigen. #------------------------------------------------------------------ set -e # Bail out on errors site_cma="_build/nurpawiki.cma" static_root="." if [ -z $1 ]; then true else if [ "$1" = "--godi-install" ]; then site_cma=`ocamlfind query nurpawiki`/nurpawiki.cma static_root="$LOCALBASE/share/nurpawiki" else echo Invalid args exit 1 fi fi stdlib_path=`ocamlfind ocamlc -where` str_path=`ocamlfind query str` nums_path="$stdlib_path" pcre_path=`ocamlfind query pcre` calendar_path=`ocamlfind query calendar` extlib_path=`ocamlfind query extlib` postgresql_path=`ocamlfind query postgresql` sqlite3_path=`ocamlfind query sqlite3` cryptokit_path=`ocamlfind query cryptokit` # The way we find Ocsigen METAS directory is extremely hacky. I don't # know of a better way. ocsigen_metas_dir="`ocamlfind printconf stdlib`" if [ "$DEBUG" != "" ]; then echo $str_path echo $pcre_path echo $calendar_path echo $extlib_path echo $postgresql_path echo $sqlite3_path echo $ocsigen_metas_dir fi mkdir -p var/log mkdir -p var/run if [ "$DBNAME" = "" ]; then echo echo ERROR! echo echo DBNAME environment variable must be set to point to your nurpawiki DB echo exit 1 fi if [ "$DBUSER" = "" ]; then echo echo ERROR! echo echo DBUSER environment variable must be set to your nurpawiki DB username echo exit 1 fi if [ "$DBPASSWD" = "" ]; then echo echo ERROR! echo echo DBPASSWD environment variable must be set to your nurpawiki DB echo postgres user password. See DB installation instructions for echo more information on how to configure this. echo exit 1 fi cat ocsigenserver.conf.in | \ sed -e "s|%_OCSIGEN_ROOT_%|$OCSIGEN_ROOT|g" | \ sed -e "s|%_STR_CMA_%|${str_path}/str.cma|g" | \ sed -e "s|%_NUMS_CMA_%|${nums_path}/nums.cma|g" | \ sed -e "s|%_CALENDAR_CMA_%|${calendar_path}/calendarLib.cmo|g" | \ sed -e "s|%_PCRE_CMA_%|${pcre_path}/pcre.cma|g" | \ sed -e "s|%_EXTLIB_CMA_%|${extlib_path}/extLib.cma|g" | \ sed -e "s|%_POSTGRESQL_CMA_%|${postgresql_path}/postgresql.cma|g" | \ sed -e "s|%_CRYPTOKIT_CMA_%|${cryptokit_path}/cryptokit.cma|g" | \ sed -e "s|%_STATIC_ROOT_%|${static_root}|g" | \ sed -e "s|%_NURPAWIKI_CMA_%|${site_cma}|g" | \ sed -e "s|%_DBNAME_%|${DBNAME}|g" | \ sed -e "s|%_DBPASSWD_%|${DBPASSWD}|g" | \ sed -e "s|%_SQLITE3_CMA_%|${sqlite3_path}/sqlite3.cma|g" | \ sed -e "s|%_OCSIGEN_METAS_DIR_%|${ocsigen_metas_dir}|g" | \ sed -e "s|%_DBUSER_%|${DBUSER}|g" nurpawiki-1.2.4/ocsigenserver.conf.in000066400000000000000000000025311372046603600176710ustar00rootroot00000000000000 8080 ./var/log ./var/lib UTF-8 ./var/run/ocsigen_command nurpawiki-1.2.4/src/000077500000000000000000000000001372046603600143255ustar00rootroot00000000000000nurpawiki-1.2.4/src/about.ml000066400000000000000000000026611372046603600157760ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Eliom_content.Html.F open Lwt open Services open Types let about_page_html = [h1 [txt "About Nurpawiki"]; p [txt ("Nurpawiki v" ^ Version.version); br (); br (); txt "Copyright © 2007-2008 Janne Hellsten"; txt "Copyright © 2008-2020 Stéphane Glondu"; br (); br (); txt "See the "; Raw.a ~a:[a_href (uri_of_string (fun () -> "https://github.com/glondu/nurpawiki"))] [txt "project homepage"]; txt "."]] let _ = Eliom_registration.Html.register about_page (fun () () -> Session.with_guest_login (fun cur_user -> return (Html_util.html_stub (Html_util.navbar_html ~cur_user about_page_html)))) nurpawiki-1.2.4/src/config.ml000066400000000000000000000055261372046603600161340ustar00rootroot00000000000000(* Copyright (c) 2007-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) module P = Printf open Xml type db_config = { db_name : string; db_user : string; db_host : string option; db_port : string option; db_pass : string option; } type site_config = { cfg_allow_ro_guests : bool; cfg_homepage : string; } let get_attr_opt attr attrs = try Some (List.assoc attr attrs) with Not_found -> None let get_attr_with_err e attr attrs = try (List.assoc attr attrs) with Not_found -> raise (Ocsigen_extensions.Error_in_config_file ("Expecting "^e^"."^attr^" attribute in Nurpawiki config")) let dbcfg = let rec find_dbcfg = function (Element ("database", attrs, _)::_) -> let dbname = get_attr_with_err "database" "name" attrs in let dbuser = get_attr_with_err "database" "user" attrs in let dbhost = get_attr_opt "host" attrs in let dbport = get_attr_opt "port" attrs in let dbpass = get_attr_opt "password" attrs in { db_name = dbname; db_user = dbuser; db_host = dbhost; db_port = dbport; db_pass = dbpass; } | x::xs -> find_dbcfg xs | [] -> raise (Ocsigen_extensions.Error_in_config_file ("Couldn't find database element from config")) in find_dbcfg (Eliom_config.get_config ()) let site = let rec find_site_cfg = function (Element ("nurpawiki", attrs, _))::_ -> let allow_ro_guests = (match get_attr_opt "allow_read_only_guests" attrs with Some s -> s = "yes" | None -> false) in let homepage = (match get_attr_opt "homepage" attrs with Some s -> s | None -> "WikiStart") in { cfg_allow_ro_guests = allow_ro_guests; cfg_homepage = homepage; } | (Element (x,_,_))::xs -> Ocsigen_messages.errlog x; find_site_cfg xs | _ -> { cfg_allow_ro_guests = false; cfg_homepage = "WikiStart"; } in let cfg = find_site_cfg (Eliom_config.get_config ()) in Ocsigen_messages.warning (P.sprintf "read-only guests allowed %b" cfg.cfg_allow_ro_guests); cfg nurpawiki-1.2.4/src/database.ml000066400000000000000000000531411372046603600164270ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Types module Psql = Postgresql module P = Printf open Config type connection = Psql.connection let ( |> ) f g = g f module ConnectionPool = struct open Psql (* We have only one connection to pool from for now. This will likely be extended for more connetcions in the future. There's no need for it yet though. *) let connection_mutex = Mutex.create () let connection : Postgresql.connection option ref = ref None let with_mutex m f = Mutex.lock m; try let r = f () in Mutex.unlock m; r with x -> Mutex.unlock m; raise x (* NOTE we may get a deadlock here if someone uses nested with_conn calls. This should not happen unless there's a programming error somewhere. This case should go away if there are more than one DB connections available for with_conn. Currently there's only one connection though. *) let with_conn_priv (f : (Psql.connection -> 'a)) = (* TODO the error handling here is not still very robust. *) with_mutex connection_mutex (fun () -> match !connection with Some c -> (* Re-use the old connection. *) (match c#status with Ok -> f c | Bad -> Ocsigen_messages.errlog "Database connection bad. Trying reset"; c#reset; match c#status with Ok -> f c | Bad -> Ocsigen_messages.errlog "Database connection still bad. Bail out"; raise (Error (Psql.Connection_failure "bad connection"))) | None -> let host = Option.default "localhost" dbcfg.db_host in let port = Option.default "" dbcfg.db_port in let password = Option.default "" dbcfg.db_pass in let c = new Psql.connection ~host ~port ~password ~dbname:dbcfg.db_name ~user:dbcfg.db_user () in connection := Some c; (* Search tables from nurpawiki schema first: *) f c) let with_conn f = try with_conn_priv f with (Psql.Error e) as ex -> Ocsigen_messages.errlog (P.sprintf "psql failed : %s\n" (Psql.string_of_error e)); raise ex | x -> raise x end let with_conn f = Lwt_preemptive.detach ConnectionPool.with_conn f (* Escape a string for SQL query *) let escape ~(conn:connection) s = conn#escape_string s let todos_user_login_join = "FROM nw.todos LEFT OUTER JOIN nw.users ON nw.todos.user_id = nw.users.id" (* Use this tuple format when querying TODOs to be parsed by parse_todo_result *) let todo_tuple_format = "nw.todos.id,descr,completed,priority,activation_date,user_id,nw.users.login" let todo_of_row row = let id = int_of_string (List.nth row 0) in let descr = List.nth row 1 in let completed = (List.nth row 2) = "t" in let owner_id = List.nth row 5 in let owner = if owner_id = "" then None else Some { owner_id = int_of_string owner_id; owner_login = List.nth row 6; } in let pri = List.nth row 3 in { t_id = id; t_descr = descr; t_completed = completed; t_priority = int_of_string pri; t_activation_date = List.nth row 4; t_owner = owner; } let parse_todo_result res = List.fold_left (fun acc row -> let id = int_of_string (List.nth row 0) in IMap.add id (todo_of_row row) acc) IMap.empty res#get_all_lst let guarded_exec ~(conn : Psql.connection) query = try conn#exec query with (Psql.Error e) as ex -> (match e with Psql.Connection_failure msg -> P.eprintf "psql failed : %s\n" msg; raise ex | _ -> P.eprintf "psql failed : %s\n" (Psql.string_of_error e); raise ex) let insert_todo_activity ~user_id todo_id ?(page_ids=None) activity = let user_id_s = string_of_int user_id in match page_ids with None -> "INSERT INTO nw.activity_log(activity_id,user_id,todo_id) VALUES ("^ (string_of_int (int_of_activity_type activity))^", "^user_id_s^ ", "^todo_id^")" | Some pages -> let insert_pages = List.map (fun page_id -> "INSERT INTO nw.activity_in_pages(activity_log_id,page_id) "^ "VALUES (CURRVAL('nw.activity_log_id_seq'), "^string_of_int page_id^")") pages in let page_act_insert = String.concat "; " insert_pages in "INSERT INTO nw.activity_log(activity_id,user_id,todo_id) VALUES ("^ (string_of_int (int_of_activity_type activity))^", "^ user_id_s^", "^todo_id^"); "^ page_act_insert let insert_save_page_activity ~user_id (page_id : int) = with_conn (fun conn -> let sql = "BEGIN; INSERT INTO nw.activity_log(activity_id, user_id) VALUES ("^(string_of_int (int_of_activity_type AT_edit_page))^ " ,"^(string_of_int user_id)^"); INSERT INTO nw.activity_in_pages(activity_log_id,page_id) VALUES (CURRVAL('nw.activity_log_id_seq'), "^string_of_int page_id^"); COMMIT" in ignore (guarded_exec ~conn sql) ) let query_todos_by_ids_raw todo_ids conn = if todo_ids <> [] then let ids = String.concat "," (List.map string_of_int todo_ids) in let r = guarded_exec ~conn ("SELECT "^todo_tuple_format^" "^todos_user_login_join^" WHERE nw.todos.id IN ("^ids^")") in List.map todo_of_row (r#get_all_lst) else [] let query_todos_by_ids todo_ids = with_conn (query_todos_by_ids_raw todo_ids) let query_todo id = with_conn (fun conn -> match query_todos_by_ids_raw [id] conn with [task] -> Some task | [] -> None | _ -> None ) let todo_exists id = match%lwt query_todo id with Some _ -> Lwt.return true | None -> Lwt.return false let update_todo_activation_date todo_id new_date = with_conn (fun conn -> let sql = "UPDATE nw.todos SET activation_date = '"^new_date^"' WHERE id = "^ (string_of_int todo_id) in ignore (guarded_exec ~conn sql) ) let update_todo_descr todo_id new_descr = with_conn (fun conn -> let sql = "UPDATE nw.todos SET descr = '"^escape ~conn new_descr^"' WHERE id = "^ (string_of_int todo_id) in ignore (guarded_exec ~conn sql) ) let update_todo_owner_id todo_id owner_id = with_conn (fun conn -> let owner_id_s = match owner_id with Some id -> string_of_int id | None -> "NULL" in let sql = "UPDATE nw.todos SET user_id = "^owner_id_s^" WHERE id = "^ (string_of_int todo_id) in ignore (guarded_exec ~conn sql) ) let select_current_user id = (match id with None -> "" | Some user_id -> " AND (user_id = "^string_of_int user_id^" OR user_id IS NULL) ") (* Query TODOs and sort by priority & completeness *) let query_all_active_todos ~current_user_id () = with_conn (fun conn -> let r = guarded_exec ~conn ("SELECT "^todo_tuple_format^" "^todos_user_login_join^" "^ "WHERE activation_date <= current_date AND completed = 'f' "^ select_current_user current_user_id^ "ORDER BY completed,priority,id") in List.map todo_of_row r#get_all_lst ) let query_upcoming_todos ~current_user_id date_criterion = with_conn (fun conn -> let date_comparison = let dayify d = "'"^string_of_int d^" days'" in match date_criterion with (None,Some days) -> "(activation_date > now()) AND (now()+interval "^dayify days^ " >= activation_date)" | (Some d1,Some d2) -> let sd1 = dayify d1 in let sd2 = dayify d2 in "(activation_date > now()+interval "^sd1^") AND (now()+interval "^sd2^ " >= activation_date)" | (Some d1,None) -> let sd1 = dayify d1 in "(activation_date > now()+interval "^sd1^")" | (None,None) -> "activation_date <= now()" in let r = guarded_exec ~conn ("SELECT "^todo_tuple_format^" "^todos_user_login_join^" "^ "WHERE "^date_comparison^ select_current_user current_user_id^ " AND completed='f' ORDER BY activation_date,priority,id") in List.map todo_of_row r#get_all_lst ) let new_todo ~conn page_id user_id descr = (* TODO: could wrap this into BEGIN .. COMMIT if I knew how to return the data from the query! *) let sql = "INSERT INTO nw.todos(user_id,descr) values('"^(string_of_int user_id)^"','"^escape ~conn descr^"'); INSERT INTO nw.todos_in_pages(todo_id,page_id) values(CURRVAL('nw.todos_id_seq'), " ^string_of_int page_id^");"^ (insert_todo_activity ~user_id "(SELECT CURRVAL('nw.todos_id_seq'))" ~page_ids:(Some [page_id]) AT_create_todo)^"; SELECT CURRVAL('nw.todos_id_seq')" in let r = guarded_exec ~conn sql in (* Get ID of the inserted item: *) (r#get_tuple 0).(0) (* Mapping from a todo_id to page list *) let todos_in_pages_raw todo_ids conn = (* Don't query if the list is empty: *) if todo_ids = [] then IMap.empty else let ids = String.concat "," (List.map string_of_int todo_ids) in let sql = "SELECT todo_id,page_id,page_descr "^ "FROM nw.todos_in_pages,nw.pages WHERE todo_id IN ("^ids^") AND page_id = nw.pages.id" in let r = guarded_exec ~conn sql in let rows = r#get_all_lst in List.fold_left (fun acc row -> let todo_id = int_of_string (List.nth row 0) in let page_id = int_of_string (List.nth row 1) in let page_descr = List.nth row 2 in let lst = try IMap.find todo_id acc with Not_found -> [] in IMap.add todo_id ({ p_id = page_id; p_descr = page_descr }::lst) acc) IMap.empty rows let todos_in_pages todo_ids = with_conn (todos_in_pages_raw todo_ids) (* TODO must not query ALL activities. Later we only want to currently visible activities => pages available. *) let query_activity_in_pages ~min_id ~max_id = with_conn (fun conn -> let sql = "SELECT activity_log_id,page_id,page_descr FROM nw.activity_in_pages,nw.pages WHERE page_id = pages.id AND (activity_log_id > "^string_of_int min_id^" AND activity_log_id <= "^string_of_int max_id^")" in let r = guarded_exec ~conn sql in List.fold_left (fun acc row -> let act_id = int_of_string (List.nth row 0) in let page_id = int_of_string (List.nth row 1) in let page_descr = List.nth row 2 in let lst = try IMap.find act_id acc with Not_found -> [] in IMap.add act_id ({ p_id = page_id; p_descr = page_descr }::lst) acc) IMap.empty (r#get_all_lst) ) (* Note: This function should only be used in contexts where there will be no concurrency issues. Automated sessions should be used for real ID inserts. In its current form, this function is used to get the highest activity log item ID in order to display history separated into multiple web pages. *) let query_highest_activity_id () = with_conn (fun conn -> let sql = "SELECT last_value FROM nw.activity_log_id_seq" in let r = guarded_exec ~conn sql in int_of_string (r#get_tuple 0).(0) ) (* Collect todos in the current page *) let query_page_todos page_id = with_conn (fun conn -> let sql = "SELECT "^todo_tuple_format^" "^todos_user_login_join^" WHERE nw.todos.id in "^ "(SELECT todo_id FROM nw.todos_in_pages WHERE page_id = "^string_of_int page_id^")" in let r = guarded_exec ~conn sql in parse_todo_result r ) (* Make sure todos are assigned to correct pages and that pages don't contain old todos moved to other pages or removed. *) let update_page_todos page_id todos = with_conn (fun conn -> let page_id' = string_of_int page_id in let sql = "BEGIN; DELETE FROM nw.todos_in_pages WHERE page_id = "^page_id'^";"^ (String.concat "" (List.map (fun todo_id -> "INSERT INTO nw.todos_in_pages(todo_id,page_id)"^ " values("^(string_of_int todo_id)^", "^page_id'^");") todos)) ^ "COMMIT" in ignore (guarded_exec ~conn sql) ) (* Mark task as complete and set completion date for today *) let complete_task_generic ~user_id id op = with_conn (fun conn -> let (activity,task_complete_flag) = match op with `Complete_task -> (AT_complete_todo, "t") | `Resurrect_task -> (AT_uncomplete_todo, "f") in let page_ids = try Some (List.map (fun p -> p.p_id) (IMap.find id (todos_in_pages_raw [id] conn))) with Not_found -> None in let ids = string_of_int id in let sql = "BEGIN; UPDATE nw.todos SET completed = '"^task_complete_flag^"' where id="^ids^";"^ (insert_todo_activity ~user_id ids ~page_ids activity)^"; COMMIT" in ignore (guarded_exec ~conn sql) ) (* Mark task as complete and set completion date for today *) let complete_task ~user_id id = complete_task_generic ~user_id id `Complete_task let uncomplete_task ~user_id id = complete_task_generic ~user_id id `Resurrect_task let query_task_priority ~conn id = let sql = "SELECT priority FROM nw.todos WHERE id = "^string_of_int id in let r = guarded_exec ~conn sql in int_of_string (r#get_tuple 0).(0) (* TODO offset_task_priority can probably be written in one query instead of two (i.e., first one SELECT and then UPDATE based on that. *) let offset_task_priority id incr = with_conn (fun conn -> let pri = min (max (query_task_priority ~conn id + incr) 1) 3 in let sql = "UPDATE nw.todos SET priority = '"^(string_of_int pri)^ "' where id="^string_of_int id in ignore (guarded_exec ~conn sql) ) let up_task_priority id = offset_task_priority id (-1) let down_task_priority id = offset_task_priority id 1 let new_wiki_page ~user_id page = with_conn (fun conn -> let sql = "INSERT INTO nw.pages (page_descr) VALUES ('"^escape ~conn page^"'); INSERT INTO nw.wikitext (page_id,page_created_by_user_id,page_text) VALUES ((SELECT CURRVAL('nw.pages_id_seq')), "^string_of_int user_id^", ''); "^ "SELECT CURRVAL('nw.pages_id_seq')" in let r = guarded_exec ~conn sql in int_of_string ((r#get_tuple 0).(0)) ) (* See WikiPageVersioning on docs wiki for more details on the SQL queries. *) let save_wiki_page page_id ~user_id lines = with_conn (fun conn -> let page_id_s = string_of_int page_id in let user_id_s = string_of_int user_id in let escaped = escape ~conn (String.concat "\n" lines) in (* Ensure no one else can update the head revision while we're modifying it Selecting for UPDATE means no one else can SELECT FOR UPDATE this row. If value (head_revision+1) is only computed and used inside this row lock, we should be protected against two (or more) users creating the same revision head. *) let sql = " BEGIN; SELECT * from nw.pages WHERE id = "^page_id_s^"; -- Set ID of next revision UPDATE nw.pages SET head_revision = nw.pages.head_revision+1 WHERE id = "^page_id_s^"; -- Kill search vectors for previous version so that only -- the latest version of the wikitext can be found using -- full text search. -- -- NOTE tsearch2 indexing trigger is set to run index updates -- only on INSERTs and not on UPDATEs. I wanted to be -- more future proof and set it trigger on UPDATE as well, -- but I don't know how to NOT have tsearch2 trigger -- overwrite the below UPDATE with its own index. UPDATE nw.wikitext SET page_searchv = NULL WHERE page_id = "^page_id_s^"; INSERT INTO nw.wikitext (page_id, page_created_by_user_id, page_revision, page_text) VALUES ("^page_id_s^", "^user_id_s^", (SELECT head_revision FROM nw.pages where id = "^page_id_s^"), E'"^escaped^"'); COMMIT" in ignore (guarded_exec ~conn sql) ) let find_page_id_raw descr conn = let sql = "SELECT id FROM nw.pages WHERE page_descr = '"^escape ~conn descr^"' LIMIT 1" in let r = guarded_exec ~conn sql in if r#ntuples = 0 then None else Some (int_of_string (r#get_tuple 0).(0)) let find_page_id descr = with_conn (find_page_id_raw descr) let page_id_of_page_name descr = with_conn (fun conn -> Option.get (find_page_id_raw descr conn)) let wiki_page_exists page_descr = with_conn (fun conn -> find_page_id_raw page_descr conn <> None) let is_legal_page_revision ~conn page_id_s rev_id = let sql = " SELECT page_id FROM nw.wikitext WHERE page_id="^page_id_s^" AND page_revision="^string_of_int rev_id in let r = guarded_exec ~conn sql in r#ntuples <> 0 (* Load a certain revision of a wiki page. If the given revision is not known, default to head revision. *) let load_wiki_page ?(revision_id=None) page_id = with_conn (fun conn -> let page_id_s = string_of_int page_id in let head_rev_select = "(SELECT head_revision FROM nw.pages WHERE id = "^page_id_s^")" in let revision_s = match revision_id with None -> head_rev_select | Some r -> if is_legal_page_revision ~conn page_id_s r then string_of_int r else head_rev_select in let sql = " SELECT page_text FROM nw.wikitext WHERE page_id="^string_of_int page_id^" AND page_revision="^revision_s^" LIMIT 1" in let r = guarded_exec ~conn sql in (r#get_tuple 0).(0) ) let query_page_revisions page_descr = with_conn (fun conn -> match find_page_id_raw page_descr conn with None -> [] | Some page_id -> let option_of_empty s f = if s = "" then None else Some (f s) in let sql = " SELECT page_revision,nw.users.id,nw.users.login,date_trunc('second', page_created) FROM nw.wikitext LEFT OUTER JOIN nw.users on page_created_by_user_id = nw.users.id WHERE page_id = "^string_of_int page_id^" ORDER BY page_revision DESC" in let r = guarded_exec ~conn sql in List.map (fun r -> { pr_revision = int_of_string (List.nth r 0); pr_owner_id = option_of_empty (List.nth r 1) int_of_string; pr_owner_login = option_of_empty (List.nth r 2) Std.identity; pr_created = List.nth r 3; }) (r#get_all_lst) ) let query_past_activity ~min_id ~max_id = with_conn (fun conn -> let sql = "SELECT nw.activity_log.id,activity_id,activity_timestamp,nw.todos.descr,nw.users.login FROM nw.activity_log LEFT OUTER JOIN nw.todos ON nw.activity_log.todo_id = nw.todos.id LEFT OUTER JOIN nw.users ON nw.activity_log.user_id = nw.users.id WHERE nw.activity_log.activity_timestamp < now() AND (nw.activity_log.id > "^string_of_int min_id^" AND nw.activity_log.id <= "^string_of_int max_id^") ORDER BY activity_timestamp DESC" in let r = guarded_exec ~conn sql in r#get_all_lst |> List.map (fun row -> let id = int_of_string (List.nth row 0) in let act_id = List.nth row 1 in let time = List.nth row 2 in let descr = List.nth row 3 in let user = List.nth row 4 in { a_id = id; a_activity = activity_type_of_int (int_of_string act_id); a_date = time; a_todo_descr = if descr = "" then None else Some descr; a_changed_by = if user = "" then None else Some user }) ) (* Search features *) let search_wikipage str = with_conn (fun conn -> let escaped_ss = escape ~conn str in let sql = "SELECT page_id,headline,page_descr FROM nw.findwikipage('"^escaped_ss^"') "^ "LEFT OUTER JOIN nw.pages on page_id = nw.pages.id ORDER BY rank DESC" in let r = guarded_exec ~conn sql in r#get_all_lst |> List.map (fun row -> let id = int_of_string (List.nth row 0) in let hl = List.nth row 1 in { sr_id = id; sr_headline = hl; sr_page_descr = Some (List.nth row 2); sr_result_type = SR_page }) ) let user_query_string = "SELECT id,login,passwd,real_name,email FROM nw.users" let user_of_sql_row row = let id = int_of_string (List.nth row 0) in { user_id = id; user_login = (List.nth row 1); user_passwd = (List.nth row 2); user_real_name = (List.nth row 3); user_email = (List.nth row 4); } let query_users () = with_conn (fun conn -> let sql = user_query_string ^ " ORDER BY id" in let r = guarded_exec ~conn sql in r#get_all_lst |> List.map user_of_sql_row ) let query_user username = with_conn (fun conn -> let sql = user_query_string ^" WHERE login = '"^escape ~conn username^"' LIMIT 1" in let r = guarded_exec ~conn sql in if r#ntuples = 0 then None else Some (user_of_sql_row (r#get_tuple_lst 0)) ) let add_user ~conn ~login ~passwd ~real_name ~email = let sql = "INSERT INTO nw.users (login,passwd,real_name,email) "^ "VALUES ("^(String.concat "," (List.map (fun s -> "'"^escape ~conn s^"'") [login; passwd; real_name; email]))^")" in ignore (guarded_exec ~conn sql) let update_user ~conn~user_id ~passwd ~real_name ~email = let sql = "UPDATE nw.users SET "^ (match passwd with None -> "" | Some passwd -> "passwd = '"^escape ~conn passwd^"',")^ "real_name = '"^escape ~conn real_name^"', email = '"^escape ~conn email^"' WHERE id = "^(string_of_int user_id) in ignore (guarded_exec ~conn sql) (* Highest upgrade schema below must match this version *) let nurpawiki_schema_version = 3 nurpawiki-1.2.4/src/database.mli000066400000000000000000000056231372046603600166020ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) type connection val with_conn : (connection -> 'a) -> 'a Lwt.t val guarded_exec : conn:connection -> string -> Postgresql.result val insert_save_page_activity : user_id:int -> int -> unit Lwt.t val query_todos_by_ids : int list -> Types.todo list Lwt.t val query_todo : int -> Types.todo option Lwt.t val todo_exists : int -> bool Lwt.t val update_todo_activation_date : int -> string -> unit Lwt.t val update_todo_descr : int -> string -> unit Lwt.t val update_todo_owner_id : int -> int option -> unit Lwt.t val query_all_active_todos : current_user_id:int option -> unit -> Types.todo list Lwt.t val query_upcoming_todos : current_user_id:int option -> int option * int option -> Types.todo list Lwt.t val new_todo : conn:connection -> int -> int -> string -> string val todos_in_pages : int list -> Types.page list Types.IMap.t Lwt.t val query_activity_in_pages : min_id:int -> max_id:int -> Types.page list Types.IMap.t Lwt.t val query_highest_activity_id : unit -> int Lwt.t val query_page_todos : int -> Types.todo Types.IMap.t Lwt.t val update_page_todos : int -> int list -> unit Lwt.t val complete_task : user_id:int -> Types.IMap.key -> unit Lwt.t val uncomplete_task : user_id:int -> Types.IMap.key -> unit Lwt.t val up_task_priority : int -> unit Lwt.t val down_task_priority : int -> unit Lwt.t val new_wiki_page : user_id:int -> string -> int Lwt.t val save_wiki_page : int -> user_id:int -> string list -> unit Lwt.t val find_page_id : string -> int option Lwt.t val page_id_of_page_name : string -> int Lwt.t val wiki_page_exists : string -> bool Lwt.t val load_wiki_page : ?revision_id:int option -> int -> string Lwt.t val query_page_revisions : string -> Types.page_revision list Lwt.t val query_past_activity : min_id:int -> max_id:int -> Types.activity list Lwt.t val search_wikipage : string -> Types.search_result list Lwt.t val query_users : unit -> Types.user list Lwt.t val query_user : string -> Types.user option Lwt.t val add_user : conn:connection -> login:string -> passwd:string -> real_name:string -> email:string -> unit val update_user : conn:connection -> user_id:int -> passwd:string option -> real_name:string -> email:string -> unit val nurpawiki_schema_version : int nurpawiki-1.2.4/src/database_schema.ml000066400000000000000000000100541372046603600177430ustar00rootroot00000000000000(* Copyright (c) 2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) module Psql = Postgresql open Database let install_schema () = with_conn (fun conn -> let sql = " -- -- PostgreSQL database dump -- SET client_encoding = 'UTF8'; SET standard_conforming_strings = off; SET check_function_bodies = false; SET client_min_messages = warning; SET escape_string_warning = off; SET search_path TO public, pg_catalog; -- -- Name: findwikipage_t; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE findwikipage_t AS ( page_id bigint, headline text, rank real ); CREATE FUNCTION findwikipage(text) RETURNS SETOF findwikipage_t AS $_$ SELECT page_id, ts_headline(page_text, q), ts_rank(page_searchv, q) FROM wikitext, to_tsquery($1) AS q WHERE page_searchv @@ q ORDER BY ts_rank(page_searchv, q) DESC$_$ LANGUAGE sql; SET default_tablespace = ''; CREATE TABLE activity_in_pages ( activity_log_id bigint NOT NULL, page_id bigint NOT NULL ); CREATE TABLE activity_log ( id integer NOT NULL, activity_timestamp timestamp without time zone DEFAULT now(), activity_id bigint NOT NULL, todo_id bigint ); CREATE SEQUENCE activity_log_id_seq INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; ALTER SEQUENCE activity_log_id_seq OWNED BY activity_log.id; CREATE TABLE pages ( id integer NOT NULL, page_descr character varying(256) ); CREATE SEQUENCE pages_id_seq INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; ALTER SEQUENCE pages_id_seq OWNED BY pages.id; CREATE TABLE todos ( id integer NOT NULL, completed boolean DEFAULT false, created timestamp without time zone DEFAULT now(), priority integer DEFAULT 3, descr text, activation_date date DEFAULT now(), CONSTRAINT todos_priority CHECK ((((priority = 1) OR (priority = 2)) OR (priority = 3))) ); CREATE SEQUENCE todos_id_seq INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; ALTER SEQUENCE todos_id_seq OWNED BY todos.id; CREATE TABLE todos_in_pages ( todo_id bigint NOT NULL, page_id bigint NOT NULL ); CREATE TABLE wikitext ( page_id bigint, page_text text, page_searchv tsvector ); ALTER TABLE activity_log ALTER COLUMN id SET DEFAULT nextval('activity_log_id_seq'::regclass); ALTER TABLE pages ALTER COLUMN id SET DEFAULT nextval('pages_id_seq'::regclass); ALTER TABLE todos ALTER COLUMN id SET DEFAULT nextval('todos_id_seq'::regclass); ALTER TABLE ONLY activity_log ADD CONSTRAINT activity_log_pkey PRIMARY KEY (id); ALTER TABLE ONLY pages ADD CONSTRAINT pages_pkey PRIMARY KEY (id); ALTER TABLE ONLY todos ADD CONSTRAINT todos_pkey PRIMARY KEY (id); CREATE INDEX wikitext_index ON wikitext USING gist (page_searchv); ALTER TABLE ONLY todos_in_pages ADD CONSTRAINT \"$1\" FOREIGN KEY (todo_id) REFERENCES todos(id); ALTER TABLE ONLY activity_in_pages ADD CONSTRAINT \"$1\" FOREIGN KEY (activity_log_id) REFERENCES activity_log(id); ALTER TABLE ONLY activity_log ADD CONSTRAINT \"$2\" FOREIGN KEY (todo_id) REFERENCES todos(id); ALTER TABLE ONLY todos_in_pages ADD CONSTRAINT \"$2\" FOREIGN KEY (page_id) REFERENCES pages(id); ALTER TABLE ONLY activity_in_pages ADD CONSTRAINT \"$2\" FOREIGN KEY (page_id) REFERENCES pages(id); ALTER TABLE ONLY wikitext ADD CONSTRAINT wikitext_page_id_fkey FOREIGN KEY (page_id) REFERENCES pages(id); " in ignore (guarded_exec ~conn sql); ignore (Database_upgrade.upgrade_schema_raw conn) ) nurpawiki-1.2.4/src/database_upgrade.ml000066400000000000000000000202761372046603600201410ustar00rootroot00000000000000(* Copyright (c) 2007-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) module Psql = Postgresql open Database let insert_initial_wiki_pages = "-- Insert main page and WikiMarkup pages into the DB INSERT INTO nw.pages (page_descr) VALUES ('WikiStart'); INSERT INTO nw.wikitext (page_id,page_text) VALUES ((SELECT CURRVAL('nw.pages_id_seq')), ' = Nurpawiki = See WikiMarkup for help on getting started. '); INSERT INTO nw.pages (page_descr) VALUES ('WikiMarkup'); INSERT INTO nw.wikitext (page_id,page_text) VALUES ((SELECT CURRVAL('nw.pages_id_seq')), ' = Wiki Markup Page = == Section heading == === Sub-section heading === == Formatting == === Italic === _Italic text_. Single _italic_ word. _Two_ _italic_ words. === Bold === *Bold faced text*. *Bold* word. *Bold* _with_ italic in same sentence. === Preformatted === Use `
` or `8<`:
8<
Preformatted text
WikiLink
[http://localhost/foo]
8<

== Bullet list ==

Paragraph of text.

Second paragraph of text.

* Bullet list top-level
* Another bullet on top-level
** Sub bullet
* Top-level again

== Links ==

A [wiki:WikiStart link] to the WikiStart main page.

Another [http://www.google.com link], this time to [http://www.google.com].

This !WikiText that does not become a link.  Write these as `!WikiText` to make Nurpawiki not regard it as a !WikiLink.  I.e., prefix it with a bang (!).
');"

let logged_exec ~conn logmsg sql =
  Buffer.add_string logmsg ("  "^sql^"\n");
  ignore (guarded_exec ~conn sql)

(* Migrate all tables to version 1 from schema v0: *)
let upgrade_schema_from_0 ~conn logmsg =
  Buffer.add_string logmsg "Upgrading schema to version 1\n";
  (* Create version table and set version to 1: *)
  let sql =
    "CREATE TABLE version (schema_version integer NOT NULL);
     INSERT INTO version (schema_version) VALUES('1')" in
  logged_exec ~conn logmsg sql;

  let empty_passwd = (Digest.to_hex (Digest.string "")) in
  let sql =
    "CREATE TABLE users (id SERIAL,
                         login text NOT NULL,
                         passwd varchar(64) NOT NULL,
                         real_name text,
                         email varchar(64));
     INSERT INTO users (login,passwd) VALUES('admin', '"^empty_passwd^"')" in
  logged_exec ~conn logmsg sql;

  (* Todos are now owned by user_id=0 *)
  let sql =
    "ALTER TABLE todos ADD COLUMN user_id integer" in
  logged_exec ~conn logmsg sql;

  (* Add user_id field to activity log table *)
  let sql =
    "ALTER TABLE activity_log ADD COLUMN user_id integer" in
  logged_exec ~conn logmsg sql


let table_exists ~conn ~schema ~table =
  let sql =
    "SELECT * from pg_tables WHERE schemaname = '"^schema^"'
     AND tablename = '"^table^"'" in
  let r = guarded_exec ~conn sql in
  r#ntuples <> 0

let function_exists ~conn fn =
  let sql =
    "SELECT proname from pg_proc WHERE proname = '"^fn^"'" in
  let r = guarded_exec ~conn sql in
  r#ntuples <> 0

let redefine_wikitext_search ~conn schema =
  let version =
    match function_exists ~conn "tsvector_update_trigger" with
      true -> `Built_in_tsearch2
    | false ->
        if function_exists ~conn "tsearch2" then
          `No_built_in_tsearch2
        else (* TODO no tsearch2 installed, ISSUE ERROR! *)
          assert false in
  let proc =
    match version with
      `No_built_in_tsearch2 ->
        "tsearch2('page_searchv', 'page_text')"
    | `Built_in_tsearch2 ->
        "tsvector_update_trigger(page_searchv, 'pg_catalog.english', page_text)" in
  "
-- Redefine wikitext tsearch2 update trigger to not trigger
-- on UPDATEs
DROP TRIGGER IF EXISTS wikitext_searchv_update ON "^schema^".wikitext;

CREATE TRIGGER wikitext_searchv_update
    BEFORE INSERT ON "^schema^".wikitext
    FOR EACH ROW
    EXECUTE PROCEDURE "^proc

let upgrade_schema_from_1 ~conn logmsg =
  Buffer.add_string logmsg "Upgrading schema to version 2\n";
  let sql =
    "ALTER TABLE pages ADD COLUMN head_revision bigint not null default 0" in
  logged_exec ~conn logmsg sql;

  let sql =
    "ALTER TABLE wikitext ADD COLUMN page_revision bigint not null default 0" in
  logged_exec ~conn logmsg sql;

  let sql =
    "ALTER TABLE wikitext
     ADD COLUMN page_created timestamp not null default now()" in
  logged_exec ~conn logmsg sql;

  let sql = "ALTER TABLE wikitext ADD COLUMN page_created_by_user_id bigint" in
  logged_exec ~conn logmsg sql;

  (* Change various tsearch2 default behaviour: *)
  if table_exists ~conn ~schema:"public" ~table:"pg_ts_cfg" then
    let sql = "UPDATE pg_ts_cfg SET locale = current_setting('lc_collate')
 WHERE ts_name = 'default'" in
    logged_exec ~conn logmsg sql
  else
    ();
  let sql = redefine_wikitext_search ~conn "public" in
  logged_exec ~conn logmsg sql;

  logged_exec ~conn logmsg "UPDATE version SET schema_version = 2"

let findwikipage_function_sql prfx =
  "CREATE FUNCTION nw.findwikipage(text) RETURNS SETOF nw.findwikipage_t
    AS $_$
SELECT page_id, "^prfx^"headline(page_text, q), "^prfx^"rank(page_searchv, q) FROM nw.wikitext, to_tsquery($1) AS q WHERE page_searchv @@ q ORDER BY "^prfx^"rank(page_searchv, q) DESC$_$
    LANGUAGE sql"

(* Version 2 -> 3: move all tables under 'nw' schema *)
let upgrade_schema_from_2 ~conn logmsg =
  let tables =
    ["users"; "todos"; "activity_in_pages"; "activity_log";
     "pages"; "version"; "wikitext"; "todos_in_pages"] in
  logged_exec ~conn logmsg "CREATE SCHEMA nw";
  List.iter
    (fun tbl ->
       let sql = "ALTER TABLE "^tbl^" SET SCHEMA nw" in
       logged_exec ~conn logmsg sql) tables;

  logged_exec ~conn logmsg (redefine_wikitext_search ~conn "nw");

  logged_exec ~conn logmsg "ALTER TYPE findwikipage_t SET SCHEMA nw";
  logged_exec ~conn logmsg "DROP FUNCTION findwikipage(text)";

  let create_find_fn_sql =
    if function_exists ~conn "ts_rank" then
      findwikipage_function_sql "ts_"
    else
      if function_exists ~conn "rank" then
        findwikipage_function_sql ""
      else
        assert false in
  logged_exec ~conn logmsg create_find_fn_sql;

  logged_exec ~conn logmsg insert_initial_wiki_pages;

  (* TODO seqs, findwikipage *)
  logged_exec ~conn logmsg "UPDATE nw.version SET schema_version = 3"

(* TODO clean up *)
let db_schema_version_raw conn =
  if table_exists ~conn ~schema:"nw" ~table:"version" then
    let r = guarded_exec ~conn "SELECT (nw.version.schema_version) FROM nw.version" in
    int_of_string (r#get_tuple 0).(0)
  else
    if not (table_exists ~conn ~schema:"public" ~table:"version") then
      0
    else
      let r = guarded_exec ~conn "SELECT (version.schema_version) FROM version" in
      int_of_string (r#get_tuple 0).(0)

let db_schema_version () = with_conn db_schema_version_raw

let upgrade_schema_raw conn =
  (* First find out schema version.. *)
  let logmsg = Buffer.create 0 in
  if db_schema_version_raw conn = 0 then
    begin
      Buffer.add_string logmsg "Schema is at version 0\n";
      upgrade_schema_from_0 ~conn logmsg
    end;
  if db_schema_version_raw conn = 1 then
    begin
      Buffer.add_string logmsg "Schema is at version 1\n";
      upgrade_schema_from_1 ~conn logmsg
    end;
  if db_schema_version_raw conn = 2 then
    begin
      Buffer.add_string logmsg "Schema is at version 2\n";
      upgrade_schema_from_2 ~conn logmsg
    end;
  assert (db_schema_version_raw conn == nurpawiki_schema_version);
  Buffer.contents logmsg

let upgrade_schema () = with_conn upgrade_schema_raw

(** Check whether the nurpawiki schema is properly installed on Psql *)
let is_schema_installed () = with_conn (fun conn ->
  let sql =
    "SELECT * from pg_tables WHERE (schemaname = 'public' OR schemaname = 'nw') AND "^
      "tablename = 'todos'" in
  let r = guarded_exec ~conn sql in
  r#ntuples <> 0
)
nurpawiki-1.2.4/src/history.ml000066400000000000000000000173601372046603600163670ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten  *)

(*
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  You should have received
 * a copy of the GNU General Public License along with this program.
 * If not, see .
 *)

module P = Printf
open Eliom_content.Html.F

open Eliom_parameter
open Eliom_service

open Lwt
open ExtList
open ExtString

open Services
open Types
open Util

open CalendarLib

module Db = Database

let ( & ) f x = f x

let n_log_items_per_page = 300

let descr_of_activity_type = function
    AT_create_todo -> "Created"
  | AT_complete_todo -> "Completed"
  | AT_work_on_todo -> "Worked on"
  | AT_create_page -> "Created"
  | AT_edit_page -> "Edited"
  | AT_uncomplete_todo -> "Resurrected"

module ReverseOrdString =
  struct
    type t = String.t
    let compare a b = String.compare b a
  end

module RSMap = Map.Make (ReverseOrdString)

type act_group =
    {
      ag_created_todos : (string * string * page list) list;
      ag_completed_todos : (string * string * page list) list;
      ag_resurrected_todos : (string * string * page list) list;
      ag_edited_pages : page list;
      ag_page_editors : string list;
    }

let empty_act_group =
  {
      ag_created_todos = [];
      ag_completed_todos = [];
      ag_resurrected_todos = [];
      ag_page_editors = [];
      ag_edited_pages = [];
  }

let group_activities activities activity_in_pages =
  List.fold_left
    (fun acc a ->
        let date = date_of_date_time_string a.a_date in
        let d = Printer.DatePrinter.sprint "%Y-%m-%d" date in
        let ag = try RSMap.find d acc with Not_found -> empty_act_group in
        let pages = try IMap.find a.a_id activity_in_pages with Not_found -> [] in
        let opt_to_str o = Option.default "" o in
        let ag' =
          let changed_by = opt_to_str a.a_changed_by in
          match a.a_activity with
            AT_create_todo ->
              (match a.a_todo_descr with
                 Some descr ->
                   let e = (descr, changed_by, pages)::ag.ag_created_todos in
                   { ag with ag_created_todos = e }
               | None -> P.eprintf "no descr in activity_log %i\n" a.a_id; ag)
          | AT_complete_todo ->
              (match a.a_todo_descr with
                 Some descr ->
                   let e = (descr, changed_by, pages)::ag.ag_completed_todos in
                   { ag with ag_completed_todos = e }
               | None -> P.eprintf "no descr in activity_log %i\n" a.a_id; ag)
          | AT_uncomplete_todo ->
              (match a.a_todo_descr with
                 Some descr ->
                   let e = (descr, changed_by, pages)::ag.ag_resurrected_todos in
                   { ag with ag_resurrected_todos = e }
               | None -> P.eprintf "no descr in activity_log %i\n" a.a_id; ag)
          | AT_create_page | AT_edit_page ->
              let add_editor e acc =
                if List.mem e acc then acc else e::acc in
              { ag with
                  ag_page_editors = add_editor changed_by ag.ag_page_editors;
                  ag_edited_pages = pages @ ag.ag_edited_pages }
          | AT_work_on_todo -> ag in
        RSMap.add d ag' acc)
    RSMap.empty activities

let remove_duplicates strs =
  let module PSet =
    Set.Make (struct
                type t = page
                let compare a b =  compare a.p_descr b.p_descr
              end) in
  let s =
    List.fold_left (fun acc e -> PSet.add e acc) PSet.empty strs in
  PSet.fold (fun e acc -> e::acc) s []

let page_links cur_page max_pages =
  let links = ref [] in
  for i = 0 to max_pages do
    let p = string_of_int i in
    let link =
      if cur_page = i then
        strong [txt p]
      else
        a ~service:history_page [txt p] (Some i) in
    links := link :: txt " " :: !links
  done;
  txt "More pages: " :: List.rev !links

let view_history_page ~cur_user ~nth_page =
  let%lwt highest_log_id = Database.query_highest_activity_id () in
  (* max_id is inclusive, min_id exclusive, hence 1 and 0 *)
  let max_id = max 1 (highest_log_id - nth_page * n_log_items_per_page) in
  let min_id = max 0 (max_id - n_log_items_per_page) in
  let n_total_pages = highest_log_id / n_log_items_per_page in
  let%lwt activity =
    Database.query_past_activity ~min_id ~max_id in
  let%lwt activity_in_pages =
    Database.query_activity_in_pages ~min_id ~max_id in

  let prettify_date d =
    let d = date_of_date_time_string d in
    Printer.DatePrinter.sprint "%a %b %d, %Y" d in

  let activity_groups = group_activities activity activity_in_pages in

  let act_table =
    table ~a:[a_class ["todo_table"]] @@
      (tr [th [];
           th [txt "Activity"];
           th [txt "By"];
           th [txt "Details"]]) ::
      (List.rev
         (fst
            (RSMap.fold
               (fun date e (lst_acc,prev_date) ->
                  let prettified_date = prettify_date date in
                  let date_text =
                    if prev_date = prettified_date then
                      []
                    else
                      [txt prettified_date] in

                  let todo_html ty lst =
                    List.rev
                      (List.mapi
                         (fun ndx (todo,changed_by,pages) ->
                            (tr [td [];
                                 td (if ndx = 0 then [txt ty] else []);
                                 td ~a:[a_class ["todo_owner"]] [txt changed_by];
                                 td ([txt todo] @
                                        (Html_util.todo_page_links_of_pages
                                           ~colorize:true pages))]))
                         lst) in

                  let created_todos =
                    todo_html "Created" e.ag_created_todos in
                  let completed_todos =
                    todo_html "Completed" e.ag_completed_todos in
                  let resurrected_todos =
                    todo_html "Resurrected" e.ag_resurrected_todos in
                  let pages_html =
                    if e.ag_edited_pages <> [] then
                      [tr [td [];
                           td [txt "Edited"];
                           td
                             ~a:[a_class ["todo_owner"]]
                             [txt (String.concat "," e.ag_page_editors)];
                           td (Html_util.todo_page_links_of_pages
                                 ~colorize:true ~insert_parens:false
                                 (remove_duplicates e.ag_edited_pages))]]
                    else
                      [] in

                  (* NOTE: 'tr' comes last as we're building the page
                     in reverse order *)
                  (pages_html @ created_todos @ completed_todos @ resurrected_todos @
                     [tr [td ~a:[a_class ["no_break"; "h_date_heading"]] date_text]] @ lst_acc,
                   prettified_date))
               activity_groups ([],"")))) in
  return & Html_util.html_stub
    (Html_util.navbar_html ~cur_user
       ([h1 [txt "Blast from the past"]] @
          (page_links nth_page n_total_pages) @ [br (); br ()] @
          [act_table]))

(* /history *)
let _ =
  Eliom_registration.Html.register history_page
    (fun nth_page () ->
       Session.with_guest_login
         (fun cur_user ->
            let page = Option.default 0 nth_page in
            view_history_page ~cur_user ~nth_page:page))
nurpawiki-1.2.4/src/html_util.ml000066400000000000000000000155531372046603600166710ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten  *)

(*
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  You should have received
 * a copy of the GNU General Public License along with this program.
 * If not, see .
 *)

open Eliom_content.Html.F
open Eliom_content.Html.F.Form

open Eliom_parameter
open Eliom_service

open Lwt

open Config
open Types
open Services

let make_static_uri name =
  make_uri (static_dir ()) name

let disconnect_box s =
  a ~service:disconnect_page [txt s] ()

(* Use this as the basis for all pages.  Includes CSS etc. *)
let html_stub ?(javascript=[]) body_html =
  let script src =
    js_script ~a:[a_defer ()] ~uri:(make_static_uri src) () in
  let scripts  =
    script ["nurpawiki.js"] :: (List.map script javascript) in
  html ~a:[a_xmlns `W3_org_1999_xhtml]
    (head
       (title (txt ""))
       ((scripts) @
          [css_link ~a:[] ~uri:(make_uri ~service:(static_dir ())
                                  ["style.css"]) ();
           css_link ~a:[] ~uri:(make_uri ~service:(static_dir ())
                                  ["jscalendar"; "calendar-blue2.css"]) ()]))
    (body body_html)

let is_guest user =
  user.user_login = "guest"

let navbar_html ~cur_user ?(top_info_bar=[]) ?(wiki_revisions_link=[]) ?(wiki_page_links=[]) ?(todo_list_table=[]) content =
  let home_link link_text =
    a ~service:wiki_view_page
      ~a:[a_accesskey 'h'; a_class ["ak"]] link_text
      (Config.site.cfg_homepage, (None, (None, None))) in
  let scheduler_link =
    a ~service:scheduler_page
      ~a:[a_accesskey 'r'; a_class ["ak"]]
      [img ~alt:"Scheduler" ~src:(make_static_uri ["calendar.png"]) ();
       txt "Scheduler"] () in
  let history_link =
    a ~service:history_page
      ~a:[a_accesskey 'r'; a_class ["ak"]]
      [img ~alt:"History" ~src:(make_static_uri ["home.png"]) ();
       txt "History"] None in

  let search_input =
    [get_form search_page
       (fun (chain : ([`One of string] param_name)) ->
          [p [input ~input_type:`Submit ~value:"Search" Form.string;
              input ~input_type:`Text ~name:chain Form.string]])] in

  (* Greet user and offer Login link if guest *)
  let user_greeting =
    txt ("Howdy "^cur_user.user_login^"!  ") ::
      if is_guest cur_user then
        [br(); br ();
         txt "To login as an existing user, click ";
         a ~a:[a_class ["login_link_big"]] ~service:wiki_view_page
           [txt "here"]
           (Config.site.cfg_homepage,(None,(None, Some true)));
         txt ".";
         br (); br ();
         txt "Guests cannot modify the site.  Ask the site admin for an account to be able to edit content."]
      else
        [] in

  let disconnect_link =
    if is_guest cur_user then [] else [disconnect_box "Logout"] in

  let my_preferences_link =
    if is_guest cur_user then
      []
    else
      [a ~service:edit_user_page [txt "My Preferences"]
         (None,cur_user.user_login)] in

  let edit_users_link =
    if Privileges.can_view_users cur_user then
      [a ~service:user_admin_page [txt "Edit Users"] ()]
    else
      [] in

  [div ~a:[a_id "topbar"]
     [table ~a:[a_class ["top_menu_size"]]
        [tr
           [td ~a:[a_class ["top_menu_left_align"]]
              [table
                 [tr [td [home_link
                            [img ~alt:"Home" ~src:(make_static_uri ["home.png"]) ();
                             txt "Home"]];
                      td [scheduler_link];
                      td [history_link];
                      td wiki_page_links]]
                 ];
            td ~a:[a_class ["top_menu_right_align"]]
              ([a ~service:about_page [txt "About"] ()] @
                 [txt " "] @
                 my_preferences_link @
                 [txt " "] @
                 edit_users_link @
                 [txt " "] @
                 disconnect_link)]]]]
  @
    (if top_info_bar = [] then [] else [div ~a:[a_id "top_action_bar"] top_info_bar])
  @
    [div ~a:[a_id "navbar"]
       (user_greeting @ [br ()] @ search_input @ wiki_revisions_link @ todo_list_table);
     div ~a:[a_id "content"]
       content]

let error text =
  span ~a:[a_class ["error"]] [txt text]

let error_page msg =
  html_stub
    [p [error msg]]


let string_of_priority = function
    3 -> "lo"
  | 2 -> "med"
  | 1 -> "hi"
  | _ -> "INTERNAL ERROR: PRIORITY OUT OF RANGE"

let priority_css_class p =
  "todo_pri_"^(string_of_priority p)

(* Hash page description to a CSS palette entry.  Used to syntax
   highlight wiki page links based on their names. *)
let css_palette_ndx_of_wikipage page_id =
  "palette"^(string_of_int (page_id mod 12))

let todo_page_links_of_pages ?(colorize=false) ?(link_css_class=None) ?(insert_parens=true) pages =
  let attrs page =
    let color_css =
      if colorize then [css_palette_ndx_of_wikipage page.p_id] else [] in
    match link_css_class with
      Some c -> [a_class ([c] @ color_css)]
    | None -> [a_class color_css] in
  let link page =
    a ~a:(attrs page) ~service:wiki_view_page [txt page.p_descr]
      (page.p_descr,(None,(None,None))) in
  let rec insert_commas acc = function
      (x::_::xs) as lst ->
        insert_commas (txt ", "::x::acc) (List.tl lst)
    | x::[] ->
        insert_commas (x::acc) []
    | [] -> List.rev acc in
  let insert_parens_html lst =
    txt " ("::lst @ [txt ")"] in
  if pages <> [] then
    let lst = insert_commas [] (List.map link pages) in
    if insert_parens then
      insert_parens_html lst
    else
      lst
  else
    []

let todo_page_links todo_in_pages ?(colorize=false) ?(link_css_class=None) ?(insert_parens=true) id =
  let pages = try IMap.find id todo_in_pages with Not_found -> [] in
  todo_page_links_of_pages ~colorize pages

let todo_edit_img_link page_cont task_id =
  [a ~a:[a_title "Edit"] ~service:edit_todo_get_page
     [img ~alt:"Edit"
        ~src:(make_static_uri ["edit_small.png"]) ()]
     (page_cont, Some task_id)]

let complete_task_img_link task_id =
  let img_html =
    [img ~alt:"Mark complete"
       ~src:(make_static_uri ["mark_complete.png"]) ()] in
  a ~service:task_side_effect_complete_action
    ~a:[a_title "Mark as completed!"] img_html task_id

let todo_descr_html descr owner =
  match owner with
    None -> [txt descr]
  | Some o ->
      [txt descr;
       span ~a:[a_class ["todo_owner"]] [txt (" ["^o.owner_login^"] ")]]


(* Use to create a "cancel" button for user submits *)
let cancel_link service params =
  a ~a:[a_class ["cancel_edit"]] ~service:service
    [txt "Cancel"]
    params
nurpawiki-1.2.4/src/main.ml000066400000000000000000000714151372046603600156130ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten  *)

(*
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  You should have received
 * a copy of the GNU General Public License along with this program.
 * If not, see .
 *)

open Eliom_content.Html.F
open Eliom_content.Html.F.Form

open Eliom_parameter
open Eliom_service

open Lwt
open ExtList
open ExtString

open Services
open Types
open Util

module Db = Database
module Psql = Postgresql
module P = Printf

(* TODO no need to extract here *)
let matches_pcre rex s =
  try ignore (Pcre.extract ~rex s); true with Not_found -> false

let ( |> ) f g = g f
let ( & ) f g = f g

let rec filter_map f = function
  | [] -> return []
  | x::xs ->
    let%lwt ys = filter_map f xs in
    match%lwt f x with
      | Some y -> return & y::ys
      | None -> return ys

let newline_re = Pcre.regexp "\n"

let task_side_effect_complete task_id () =
  Session.action_with_user_login
    (fun user ->
      let%lwt b = Privileges.can_complete_task task_id user in
      if b then
        begin
          Db.complete_task ~user_id:user.user_id task_id;%lwt
          let table = Eliom_request_info.get_request_cache () in
          return & Polytables.set ~table ~key:action_completed_task ~value:task_id
        end
      else return ())


let task_side_effect_undo_complete task_id () =
  Session.action_with_user_login
    (fun user ->
      let%lwt b = Privileges.can_complete_task task_id user in
      if b then Db.uncomplete_task ~user_id:user.user_id task_id
      else return ())

let task_side_effect_mod_priority (task_id, dir) () =
  Session.action_with_user_login
    (fun user ->
      let%lwt b = Privileges.can_modify_task_priority task_id user in
      if b then
        begin
          if dir = false then
            Db.down_task_priority task_id
          else
            Db.up_task_priority task_id;%lwt
          let table = Eliom_request_info.get_request_cache () in
          return & Polytables.set ~table ~key:action_task_priority_changed ~value:task_id
        end
      else return ())

let () =
  Eliom_registration.Action.register
    ~service:task_side_effect_complete_action task_side_effect_complete;
  Eliom_registration.Action.register
    ~service:task_side_effect_undo_complete_action task_side_effect_undo_complete;
  Eliom_registration.Action.register
    ~service:task_side_effect_mod_priority_action task_side_effect_mod_priority

let make_static_uri = Html_util.make_static_uri

(* Deal with Wiki markup *)
module WikiML =
  struct
    type preproc_line =
        [ `Wiki of string
        | `NoWiki of string list
        ]

    let ws_or_empty_re = Pcre.regexp "^([ \t\n\r]*)$"

    let h1_re = Pcre.regexp "^=(.*)=([ \n\r]*)?$"
    let h2_re = Pcre.regexp "^==(.*)==([ \n\r]*)?$"
    let h3_re = Pcre.regexp "^===(.*)===([ \n\r]*)?$"
    let list_re = Pcre.regexp "^[ ]?([*]+) (.*)([ \n\r]*)?$"

    let is_list = function
        `Wiki line ->
          match_pcre_option list_re line
      | `NoWiki _ ->
          None

    let is_list_or_empty = function
        `Wiki line ->
          matches_pcre list_re line || matches_pcre ws_or_empty_re line
      | `NoWiki _ -> false

    let take_while pred lines =
      let rec loop acc = function
          (x::xs) as lst ->
            if pred x then
              loop (x::acc) xs
            else
              (lst, List.rev acc)
        | [] ->
            ([], List.rev acc) in
      loop [] lines

    let accepted_chars_ = "a-zA-Z\128-\2550-9_!\"#%&/()=?+.,;:{}'@\\$\\^\\*`<>~"
    let accepted_chars_sans_ws = "["^accepted_chars_^"-]+"
    let accepted_chars = "["^accepted_chars_^" -]+"

    let italic_re =
      Pcre.regexp ("^(_("^(del_substring accepted_chars "_")^")_)")

    let bold_re =
      Pcre.regexp ("^(\\*("^del_substring accepted_chars "\\*" ^")\\*)")

    let code_re =
      Pcre.regexp ("^(`("^del_substring accepted_chars "`" ^")`)")

    let text_re = Pcre.regexp ("^("^accepted_chars_sans_ws^")")
    let wikilink_re = Pcre.regexp "^([!]?[A-Z][a-z]+([A-Z][a-z]+)+)"

    let wikilinkanum_re =
      Pcre.regexp ("^(\\[(wiki|file|http|https|ftp):("^accepted_chars_sans_ws^
                    ")[ ]+("^accepted_chars^")\\])")

    let wikilinkanum_no_text_re =
      Pcre.regexp ("^(\\[(wiki|file|http|https|ftp):("^accepted_chars_sans_ws^")\\])")

    let todo_re =
      Pcre.regexp ("\\[todo:([0-9]+)( "^accepted_chars^")?\\]")

    let open_pre_re = Pcre.regexp "^(
|8<)\\s*$"
    let close_pre_re = Pcre.regexp "^(
|8<)\\s*$" (* WikiML preprocessor: translate a list of lines into normal lines and blocks of PRE blocks that contain verbatim lines. *) let preprocess lines = let rec loop acc = function x::xs -> (match match_pcre_option open_pre_re x with Some m -> begin (* Handle
..
*) let (after_pre,contents) = take_while (fun x -> match_pcre_option close_pre_re x = None) xs in let next = match after_pre with [] -> [] | _::next -> next in loop (`NoWiki contents :: acc) next end | None -> loop (`Wiki x::acc) xs) | [] -> List.rev acc in loop [] lines let wikitext_of_preprocessed_lines preproc_lines = List.flatten (List.map (function `Wiki text -> [text] | `NoWiki lines -> ("
" :: lines) @ ["
"]) preproc_lines) (* Todo item manipulation HTML *) let complete_todo id = [Html_util.complete_task_img_link id] let priority_arrow id up_or_down = let (title,arrow_img,dir) = if up_or_down then ("Raise priority!", "arrow_up.png", true) else ("Lower priority!", "arrow_down.png", false) in let arrow_img = img ~alt:"Logo" ~src:(make_static_uri [arrow_img]) () in a ~a:[a_title title] ~service:task_side_effect_mod_priority_action [arrow_img] (id, dir) let mod_priorities pri id = [priority_arrow id true; priority_arrow id false] let todo_editor_link todo_id page = Html_util.todo_edit_img_link (ET_view page) todo_id let todo_modify_buttons ~cur_user page todo_id todo = let completed = todo.t_completed in span ~a:[a_class ["no_break"]] (if completed || not (Privileges.can_edit_task todo cur_user) then [] else (todo_editor_link todo_id page @ mod_priorities todo.t_priority todo_id @ complete_todo todo_id)) let translate_list items = let add_ul t lst = t @ [ul lst] in let rec loop = function ((nesting1,text1)::(nesting2,text2)::xs) as lst -> if nesting1 = nesting2 then (li text1)::loop (List.tl lst) else if nesting1 < nesting2 then (* enter *) let (next_same_level,same_or_higher) = take_while (fun (n,_) -> n >= nesting2) (List.tl lst) in (li (add_ul text1 (loop same_or_higher)))::loop next_same_level else (* leave *) loop (List.tl lst) | (nesting,text)::[] -> [(li text)] | [] -> [] in let list_items = loop items in ul list_items let parse_lines ~cur_user cur_page (todo_data : todo IMap.t) preprocessed_lines = let wikilink scheme page text = let ext_img = img ~alt:"External link" ~src:(make_static_uri ["external_link.png"]) () in if scheme = "wiki" || scheme = "" then let t = if text = "" then page else text in let%lwt b = Db.wiki_page_exists page in if b then a wiki_view_page [txt t] (page, (None, (None, None))) |> return else a ~a:[a_class ["missing_page"]] ~service:wiki_view_page [txt t] (page,(None,(None,None))) |> return else (* External link *) let url = scheme^":"^page in let t = if text = "" then url else text in return & Raw.a ~a:[a_href (uri_of_string (fun () -> url))] [txt t] in let add_html html_acc html = html::html_acc in let add_todo acc todo = let todo_id = int_of_string todo in let html = try let todo = IMap.find todo_id todo_data in let completed = todo.t_completed in let style = if completed then ["todo_descr_completed"] else ["todo_descr"; Html_util.priority_css_class todo.t_priority] in span [todo_modify_buttons ~cur_user cur_page todo_id todo; span ~a:[a_class style] (Html_util.todo_descr_html todo.t_descr todo.t_owner)] with Not_found -> (txt "UNKNOWN TODO ID!") in add_html acc html in let seqmatch s charpos ~default = let rec loop = function (x,f)::xs -> (match match_pcre_option ~charpos x s with Some m -> let fmlen = String.length m.(0) in f fmlen m | None -> loop xs) | [] -> default () in loop in let rec parse_text acc s = let wiki_error s charpos = let s = (String.sub s charpos ((String.length s)-charpos)) in return & add_html acc (Html_util.error ("WIKI SYNTAX ERROR on line: '"^s^"'")) in let len = String.length s in let rec loop acc charpos = if charpos >= len then return acc else if s.[charpos] = '\t' then let m = "\t" in loop (add_html acc (txt m)) (charpos+1) else if s.[charpos] = ' ' then let m = " " in loop (add_html acc (txt m)) (charpos+1) else if s.[charpos] = '\r' || s.[charpos] = '\n' then return acc else seqmatch s charpos ~default:(fun () -> wiki_error s charpos) [(todo_re, (fun fmlen r -> let todo_id = r.(1) in loop (add_todo acc todo_id) (charpos+fmlen))); (wikilink_re, (fun fmlen r -> let m = r.(1) in (* If the WikiLink starts with a bang (!), don't create a link but leave it as text. *) if m.[0] = '!' then let s = String.sub m 1 (String.length m - 1) in loop (add_html acc (txt s)) (charpos+(String.length m)) else let%lwt h = wikilink "" m m in loop (add_html acc h) (charpos+fmlen))); (wikilinkanum_re, (fun fmlen r -> let scheme = r.(2) in let page = r.(3) in let text = r.(4) in let%lwt h = wikilink scheme page text in loop (add_html acc h) (charpos+fmlen))); (wikilinkanum_no_text_re, (fun fmlen r -> let scheme = r.(2) in let page = r.(3) in let text = "" in let%lwt h = wikilink scheme page text in loop (add_html acc h) (charpos+fmlen))); (italic_re, (fun fmlen r -> let h = em [txt r.(2)] in loop (add_html acc h) (charpos+fmlen))); (bold_re, (fun fmlen r -> let h = strong [txt r.(2)] in loop (add_html acc h) (charpos+fmlen))); (code_re, (fun fmlen r -> let h = code [txt r.(2)] in loop (add_html acc h) (charpos+fmlen))); (text_re, (fun fmlen r -> loop (add_html acc (txt r.(1))) (charpos+fmlen)))] in loop acc 0 >>= wrap1 List.rev in let rec pcre_first_match str pos = let rec loop = function (rex,f)::xs -> (try Some (Pcre.extract ~rex ~pos str, f) with Not_found -> loop xs) | [] -> None in loop in let rec loop acc = function ((`Wiki x)::xs) as lst -> let parse_list r = (* Grab all lines starting with '*': *) let (after_bullets,bullets) = take_while is_list_or_empty lst in let%lwt list_items = filter_map (function (`Wiki e) as wl -> if matches_pcre ws_or_empty_re e then (* Empty line, ignore *) return None else begin match is_list wl with Some r -> let n_stars = String.length r.(1) in let%lwt x = parse_text [] r.(2) in return & Some (n_stars, x) | None -> assert false end | `NoWiki _ -> assert false) bullets in loop ((translate_list list_items)::acc) after_bullets in let wiki_pats = [(h3_re, (fun r -> loop ((h3 [txt r.(1)])::acc) xs)); (h2_re, (fun r -> loop ((h2 [txt r.(1)])::acc) xs)); (h1_re, (fun r -> loop ((h1 [txt r.(1)])::acc) xs)); (ws_or_empty_re, (fun r -> loop acc xs)); (list_re, (fun r -> parse_list r))] in begin match pcre_first_match x 0 wiki_pats with Some (res, action) -> action res | None -> let%lwt x = parse_text [] x in loop ((p x)::acc) xs end | (`NoWiki x::xs) -> loop (pre [txt (String.concat "\n" x)]::acc) xs | [] -> return & List.rev acc in loop [] preprocessed_lines end let load_wiki_page ~revision_id page_id = let%lwt page = Db.load_wiki_page ~revision_id page_id in Pcre.split ~rex:newline_re page |> WikiML.preprocess |> return let wikiml_to_html ~cur_user (page_id:int) (page_name:string) ~revision_id todo_data = load_wiki_page page_id ~revision_id >>= WikiML.parse_lines ~cur_user page_name todo_data let todo_list_table_html ~cur_user cur_page todos = (* Which pages contain TODOs, mapping from todo_id -> {pages} *) let%lwt todo_in_pages = Db.todos_in_pages (List.map (fun todo -> todo.t_id) todos) in let todo_page_link todo = let descr = todo.t_descr in let page_links = let c = "wiki_pri_"^Html_util.string_of_priority todo.t_priority in Html_util.todo_page_links todo_in_pages ~link_css_class:(Some c) (todo.t_id) in Html_util.todo_descr_html descr todo.t_owner @ page_links in let priority_changes = Session.any_task_priority_changes () in return & table ~a:[a_class ["todo_table"]] @@ (tr [th [txt "Id"]; th [txt "Description"]]) :: (List.map (fun todo -> let id = todo.t_id in let completed = todo.t_completed in let row_pri_style = if completed then "todo_completed_row" else Html_util.priority_css_class todo.t_priority in let row_class = row_pri_style:: (if priority_changes = Some id then ["todo_priority_changed"] else []) in (tr [td ~a:[a_class row_class] [txt (string_of_int id)]; td ~a:[a_class row_class] (todo_page_link todo); td [(WikiML.todo_modify_buttons ~cur_user cur_page id todo)]])) todos) let wiki_page_menu_html ~cur_user page content = let edit_link = [a ~service:wiki_edit_page ~a:[a_accesskey '1'; a_class ["ak"]] [img ~alt:"Edit" ~src:(make_static_uri ["edit.png"]) (); txt "Edit page"] page] in let printable_link = [a ~service:wiki_view_page ~a:[a_accesskey 'p'; a_class ["ak"]] [txt "Print"] (page, (Some true,(None,None)))] in let revisions_link = [a ~service:page_revisions_page [txt "View past versions"] page; br (); br ()] in let current_user_id = Some cur_user.user_id in let%lwt todo_list = let%lwt x = Db.query_all_active_todos ~current_user_id () in todo_list_table_html ~cur_user page x in let undo_task_id = Session.any_complete_undos () in let top_info_bar = match undo_task_id with None -> [] | Some id -> [span ~a:[a_class ["action_bar"]] [txt ("Completed task "^string_of_int id^" "); a ~a:[a_class ["undo_link"]] ~service:task_side_effect_undo_complete_action [txt "Undo"] id]] in return & Html_util.navbar_html ~cur_user ~wiki_page_links:(edit_link @ [txt " "] @ printable_link) ~wiki_revisions_link:revisions_link ~top_info_bar ~todo_list_table:[todo_list] content let wiki_page_contents_html ~cur_user ~revision_id page_id page_name todo_data ?(content=[]) () = let%lwt h = wikiml_to_html ~cur_user ~revision_id page_id page_name todo_data in wiki_page_menu_html ~cur_user page_name (content @ h) let view_page ~cur_user ?(revision_id=None) page_id page_name ~printable = let%lwt todos = Db.query_page_todos page_id in if printable <> None && Option.get printable = true then let%lwt page_content = wikiml_to_html ~cur_user page_id page_name ~revision_id todos in return & Html_util.html_stub page_content else let%lwt page_content = (wiki_page_contents_html ~cur_user page_id page_name ~revision_id todos ()) in return & Html_util.html_stub page_content (* Parse existing todo's from the current to-be-saved wiki page and update the DB relation on what todos are on the page. Todo descriptions are inspected and if they've been changed, modify them in the DB. It's also possible to resurrect completed tasks here by removing the '(x)' part from a task description. *) let check_new_and_removed_todos ~cur_user page_id lines = let search_forward ?groups pat s pos = let result = Pcre.exec ~rex:pat ~pos s in (fst (Pcre.get_substring_ofs result 0), result) in (* Figure out which TODOs are mentioned on the wiki page: *) let page_todos = List.fold_left (fun acc -> function `Wiki line -> let rec loop acc n = try let (offs,res) = search_forward WikiML.todo_re line n in let m = try Some (Pcre.get_substring res 2) with Not_found -> None in loop ((Pcre.get_substring res 1, m)::acc) (offs+(String.length (Pcre.get_substring res 0))) with Not_found -> acc in loop acc 0 | `NoWiki _ -> acc) [] lines in (* Query todos that reside on this page. Don't update DB for todos that did NOT change *) let%lwt todos_on_page = Db.query_page_todos page_id in let completed_re = Pcre.regexp "^\\s*\\(x\\) (.*)$" in let remove_ws_re = Pcre.regexp "^\\s*(.*)$" in (* Update todo descriptions & resurrect completed tasks *) Lwt_list.iter_s (fun (id_s,descr) -> match descr with Some descr -> (match match_pcre_option completed_re descr with Some _ -> (* Task has already been completed, do nothing: *) return () | None -> let id = int_of_string id_s in (* Update task description (if not empty): *) (match match_pcre_option remove_ws_re descr with Some r -> begin try let new_descr = r.(1) in (* Only modify task description in DB if it's changed from its previous value: *) let todo = IMap.find id todos_on_page in (* Resurrect completed task *) if todo.t_completed then Db.uncomplete_task ~user_id:cur_user.user_id id else return ();%lwt if todo.t_descr <> new_descr then Db.update_todo_descr id new_descr else return () with Not_found -> (* Internal inconsistency, should not happen. *) return () end | None -> return ())) | None -> return ()) page_todos;%lwt filter_map (fun e -> let id = int_of_string (fst e) in let%lwt b = Db.todo_exists id in if b then return & Some id else return & None) page_todos >>= (* Update DB "todos in pages" relation *) Db.update_page_todos page_id let global_substitute ?groups pat subst s = Pcre.substitute_substrings ~rex:pat ~subst:(fun r -> subst r) s let new_todo_re = Pcre.regexp ("\\[todo ("^WikiML.accepted_chars^")\\]") (* Insert new TODOs from the wiki ML into DB and replace [todo descr] by [todo:ID] *) let convert_new_todo_items cur_user page items = Db.with_conn (fun conn -> let owner_id = cur_user.user_id in List.map (function `Wiki line -> `Wiki (global_substitute new_todo_re (fun r -> let descr = Pcre.get_substring r 1 in let id = Db.new_todo ~conn page owner_id descr in "[todo:"^id^" "^descr^"]") line) | (`NoWiki _) as x -> x) items) (* Save page as a result of /edit?p=Page *) let service_save_page_post = Eliom_registration.Html.create_attached_post ~fallback:wiki_view_page ~post_params:(string "value") (fun (page, _) value -> Session.with_user_login (fun cur_user -> (* Check if there are any new or removed [todo:#id] tags and updated DB page mappings accordingly: *) let wikitext = Pcre.split ~rex:newline_re value |> WikiML.preprocess in let user_id = cur_user.user_id in let%lwt page_id = Db.page_id_of_page_name page in check_new_and_removed_todos ~cur_user page_id wikitext;%lwt (* Convert [todo Description] items into [todo:ID] format, save descriptions to database and save the wiki page contents. *) let%lwt wiki_plaintext = convert_new_todo_items cur_user page_id wikitext >>= wrap1 WikiML.wikitext_of_preprocessed_lines in (* Log activity: *) Db.insert_save_page_activity ~user_id page_id;%lwt Db.save_wiki_page page_id ~user_id wiki_plaintext;%lwt view_page ~cur_user page_id page ~printable:(Some false))) (* Convert [todo:ID] into [todo:ID 'Description'] before going into Wiki page edit textarea. *) let annotate_old_todo_items page page_todos (lines : WikiML.preproc_line list) = List.map (function `Wiki line -> `Wiki (global_substitute WikiML.todo_re (fun r -> let id = Pcre.get_substring r 1 in let (descr,completed) = try let todo = IMap.find (int_of_string id) page_todos in (todo.t_descr,if todo.t_completed then "(x) " else "") with Not_found -> ("UNKNOWN TODO","") in "[todo:"^id^" "^completed^descr^"]") line) | (`NoWiki line) as x -> x) lines (* /edit?p=Page *) let _ = let handle_edit ~cur_user page_name = let%lwt (page_id, page_todos, preproc_wikitext) = let%lwt b = Db.wiki_page_exists page_name in if b then let%lwt page_id = Db.page_id_of_page_name page_name in let%lwt current_page_todos = Db.query_page_todos page_id in let%lwt x = load_wiki_page page_id ~revision_id:None in return & (page_id, current_page_todos, annotate_old_todo_items page_name current_page_todos x) else begin let%lwt x = Db.new_wiki_page ~user_id:cur_user.user_id page_name in return (x, IMap.empty, []) end in let wikitext = String.concat "\n" (WikiML.wikitext_of_preprocessed_lines preproc_wikitext) in let f = post_form service_save_page_post (fun chain -> [(p [input ~input_type:`Submit ~value:"Save" Form.string; Html_util.cancel_link wiki_view_page (page_name,(None,(None,None))); br (); textarea ~name:chain ~a:[a_rows 30; a_cols 80] ~value:wikitext ()])]) (page_name,(None,(None,None))) in let%lwt h = wiki_page_contents_html ~cur_user ~revision_id:None page_id page_name page_todos ~content:[f] () in return & Html_util.html_stub h in Eliom_registration.Html.register wiki_edit_page (fun page_name () -> Session.with_user_login (fun cur_user -> handle_edit ~cur_user page_name)) let view_wiki_page ~cur_user (page_name, (printable, (revision_id, _))) = match%lwt Db.find_page_id page_name with Some page_id -> view_page ~cur_user ~revision_id page_id page_name ~printable | None -> let f = a wiki_edit_page [txt "Create new page"] page_name in let%lwt h = wiki_page_menu_html ~cur_user page_name [f] in return & Html_util.html_stub h (* /view?p=Page *) let _ = Eliom_registration.Html.register wiki_view_page (fun ((_, (_, (_, force_login))) as params) () -> (* If forced login is not requested, we'll let read-only guests in (if current configuration allows it) *) let login f = match force_login with Some true -> Session.with_user_login f | Some _ | None -> Session.with_guest_login f in login (fun cur_user -> view_wiki_page ~cur_user params)) (* /benchmark?test=empty,one_db *) let _ = let gen_html = function "empty" -> (html (head (title (txt "")) []) (body [p [txt "Empty page"]])) | "db1" -> (* TODO TODO add simple SQL query here *) (* ignore (Db.query_activities ());*) (html (head (title (txt "")) []) (body [p [txt "Test one DB query"]])) | _ -> (html (head (title (txt "")) []) (body [p [txt "invalid 'test' param!"]])) in Eliom_registration.Html.register benchmark_page (fun test_id () -> return (gen_html test_id)) (* /search?q=[keyword list] *) let _ = (* Parse tags from headline and convert to b tags. *) let html_of_headline h = let rec html_of_elem = function Nethtml.Element ("b",_,c) -> let c = List.flatten (List.rev (List.fold_left (fun acc e -> (html_of_elem e)::acc) [] c)) in [(span ~a:[a_class ["sr_hilite"]] c)] | Nethtml.Element (_,_,_) -> [] | Nethtml.Data s -> [txt s] in let ch = new Netchannels.input_string h in let doc = Nethtml.parse ch in List.flatten (List.rev (List.fold_left (fun acc e -> (html_of_elem e)::acc) [] doc) )in let render_results search_results = List.flatten (List.map (fun sr -> match sr.sr_result_type with SR_page -> let link descr = a ~a:[a_class ["sr_link"]] ~service:wiki_view_page [txt descr] (descr,(None,(None,None))) in [p ([link (Option.get sr.sr_page_descr); br ()] @ html_of_headline sr.sr_headline)] | SR_todo -> assert false) search_results) in let gen_search_page ~cur_user search_str = let%lwt search_results = Db.search_wikipage search_str in return (Html_util.html_stub (Html_util.navbar_html ~cur_user ([h1 [txt "Search results"]] @ (render_results search_results)))) in Eliom_registration.Html.register search_page (fun search_str () -> Session.with_guest_login (fun cur_user -> gen_search_page cur_user search_str)) nurpawiki-1.2.4/src/nurpawiki.mlpack000066400000000000000000000002421372046603600175250ustar00rootroot00000000000000Version Config Types Util Database Database_upgrade Database_schema Services Privileges Html_util Session User_editor Page_revisions Main Scheduler History About nurpawiki-1.2.4/src/page_revisions.ml000066400000000000000000000035571372046603600177060ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Eliom_content.Html.F open Eliom_parameter open Eliom_service open Lwt open ExtList open ExtString open Services open Types module Db = Database let revision_table page_descr = let%lwt revisions = Db.query_page_revisions page_descr in let page_link descr (rev:int) = a ~service:wiki_view_page [txt ("Revision "^(string_of_int rev))] (descr, (None, (Some rev, None))) in let rows = List.map (fun r -> tr [td [page_link page_descr r.pr_revision]; td [txt r.pr_created]; td [txt (Option.default "" r.pr_owner_login)]]) revisions in return [table @@ (tr [th [txt "Revision"]; th [txt "When"]; th [txt "Changed by"]]) :: rows] let view_page_revisions page_descr = Session.with_guest_login (fun cur_user -> revision_table page_descr >>= fun revisions -> return (Html_util.html_stub (Html_util.navbar_html ~cur_user (h1 [txt (page_descr ^ " Revisions")] :: revisions)))) (* /page_revisions?page_id= *) let _ = Eliom_registration.Html.register page_revisions_page (fun page_descr () -> view_page_revisions page_descr) nurpawiki-1.2.4/src/privileges.ml000066400000000000000000000056561372046603600170440ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) (* Logic to handle user privileges. Instead of cluttering HTML generation and other logic with privilege handling, abstract it behind a tight interface. This interface also allows for a later addition of a more fine-grained access control. *) open Types (** with_can_create_user [user f on_fail] calls [f ()] if user is privileged enough to perform the operation. Otherwise call [on_fail error] to handle the error case. *) let with_can_create_user cur_user f ~on_fail = if cur_user.user_login = "admin" then f () else on_fail ("User '"^cur_user.user_login^"' is not permitted to create new users") let can_view_users cur_user = cur_user.user_login = "admin" (** with_can_view_users [user f] calls [f ()] if user is privileged enough to view a list of all users. Otherwise return an error message. *) let with_can_view_users cur_user f ~on_fail = if can_view_users cur_user then f () else on_fail ("User '"^cur_user.user_login^"' is not permitted to view other users") (** with_can_edit_user [user cur_user user_to_edit f] calls [f ()] if user is privileged enough to perform the operation. Otherwise return an error message. *) let with_can_edit_user cur_user target f ~on_fail = if cur_user.user_login = "admin" || cur_user.user_login = target.user_login then f () else on_fail ("User '"^cur_user.user_login^"' is not permitted to edit users other than self") (** Privileged enough to schedule tasks for all users? *) let can_schedule_all_tasks cur_user = cur_user.user_login = "admin" let user_owns_task_or_is_admin todo cur_user = if cur_user.user_login = "admin" then true else match todo.t_owner with Some o -> o.owner_id = cur_user.user_id | None -> false let can_edit_task todo cur_user = user_owns_task_or_is_admin todo cur_user let can_complete_task task_id cur_user = let%lwt todo = Database.query_todo task_id in match todo with Some t -> Lwt.return (user_owns_task_or_is_admin t cur_user) | None -> Lwt.return false let can_modify_task_priority task_id cur_user = let%lwt todo = Database.query_todo task_id in match todo with Some t -> Lwt.return (user_owns_task_or_is_admin t cur_user) | None -> Lwt.return false nurpawiki-1.2.4/src/scheduler.ml000066400000000000000000000266431372046603600166500ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Eliom_content.Html.F open Eliom_parameter open Eliom_service open Lwt open ExtList open ExtString open Services open Types open Util open CalendarLib let ( & ) f x = f x module Db = Database let clamp_date_to_today date = let today = Date.today () in let d = date_of_string date in begin match Date.compare today d with -1 -> d | 0 | 1 -> today | _ -> assert false end let wiki_page_links todo_in_pages todo = let id = todo.t_id in let c = "wiki_pri_"^Html_util.string_of_priority todo.t_priority in Html_util.todo_page_links todo_in_pages ~link_css_class:(Some c) id let view_scheduler_page ~cur_user = let scheduler_page_internal ~cur_user = let today = Date.today () in let prettify_activation_date d = let d = date_of_string d in (* Clamp & prettify activation date *) begin match Date.compare today d with -1 -> Printer.DatePrinter.sprint "%a %b %d, %Y" d | 0 | 1 -> "today" | _ -> assert false end in let todo_table_html todos todos_in_pages = let prev_heading = ref "" in let todo_rows = List.map (fun (heading,todo) -> let todo_id_s = string_of_int todo.t_id in let heading_row = if !prev_heading <> heading then begin prev_heading := heading; [tr [td ~a:[a_class ["rm_table_heading"]] [txt heading]]] end else [] in let pri_style = Html_util.priority_css_class todo.t_priority in let todo_row = tr [td ~a:[a_class ["rm_edit"]] (Html_util.todo_edit_img_link ET_scheduler todo.t_id); td [input ~a:[a_input_type `Checkbox; a_name ("t-"^ todo_id_s); a_value "0"] ()]; td [Html_util.complete_task_img_link todo.t_id]; (td ~a:[a_class ["no_break"; pri_style]] [txt (prettify_activation_date todo.t_activation_date)]); td ~a:[a_class [pri_style]] (Html_util.todo_descr_html todo.t_descr todo.t_owner @ wiki_page_links todos_in_pages todo)] in heading_row @ [todo_row]) todos in List.flatten todo_rows in let todo_section todos todos_in_pages = (todo_table_html todos todos_in_pages) in let query_todos = if Privileges.can_schedule_all_tasks cur_user || cur_user.user_login = "guest" then Database.query_upcoming_todos ~current_user_id:None else (* Query this users's tasks only: *) Database.query_upcoming_todos ~current_user_id:(Some cur_user.user_id) in let%lwt upcoming_pending = query_todos (None,None) in let%lwt upcoming_tomorrow = query_todos (None,Some 1) in let%lwt upcoming_todos_7_days = query_todos (Some 1,Some 7) in let%lwt upcoming_todos_14_days = query_todos (Some 7, Some 14) in let%lwt upcoming_all = query_todos (Some 14, None) in let mark_todo_hdr h = List.map (fun e -> (h, e)) in let merged_todos = (mark_todo_hdr "Today" upcoming_pending) @ (mark_todo_hdr "Tomorrow" upcoming_tomorrow) @ (mark_todo_hdr "Next 7 days" upcoming_todos_7_days) @ (mark_todo_hdr "Next 2 weeks" upcoming_todos_14_days) @ (mark_todo_hdr "Everything else" upcoming_all) in let%lwt todos_in_pages = Database.todos_in_pages (List.map (fun (_,todo) -> todo.t_id) merged_todos) in (* TODO merge this HTML generation with other pages. PROBLEM: don't know how to easily do that without duplicating the parameter passing of pages. *) let table () = [p [input ~a:[a_input_type `Submit; a_value "Mass edit"] ()]; table @@ (tr [th []; th []; th []; th [txt "Activates on"]; th [txt "Todo"]]) :: (todo_section merged_todos todos_in_pages); table [tr [td [button ~a:[a_class ["scheduler_check_button"]; a_id "button_select_all"] [txt "Select All"]]; td [button ~a:[a_class ["scheduler_check_button"]; a_id "button_deselect_all"] [txt "Unselect All"]]]] ] in let table' = Form.post_form edit_todo_page table (ET_scheduler, None) in return & Html_util.html_stub ~javascript:[["nurpawiki_scheduler.js"]] (Html_util.navbar_html ~cur_user ([h1 [txt "Road ahead"]] @ [table'])) in scheduler_page_internal ~cur_user let render_edit_todo_cont_page ~cur_user = function ET_scheduler -> view_scheduler_page ~cur_user | ET_view wiki_page -> Main.view_wiki_page ~cur_user (wiki_page, (None, (None, None))) (* /scheduler *) let _ = Eliom_registration.Html.register scheduler_page (fun todo_id () -> Session.with_guest_login (fun cur_user -> view_scheduler_page ~cur_user)) let scheduler_page_discard_todo_id = Eliom_registration.Html.create ~path:(Path ["scheduler"]) ~meth:(Get ((user_type et_cont_of_string string_of_et_cont "src_service"))) (fun src_page_cont () -> Session.with_user_login (fun cur_user -> render_edit_todo_cont_page ~cur_user src_page_cont)) (* Save page as a result of /edit_todo?todo_id=ID *) let service_save_todo_item = Eliom_registration.Html.create_attached_post ~fallback:scheduler_page_discard_todo_id ~post_params:(list "todos" ((int "todo_id") ** (string "activation_date") ** (string "descr") ** (string "owner_id"))) (fun src_page_cont todos -> Session.with_user_login (fun cur_user -> (* TODO security hole: would need to check user privileges for these DB operations. *) Lwt_list.iter_s (fun (todo_id, (activation_date, (descr, owner_id))) -> Database.update_todo_descr todo_id descr;%lwt let owner_id_opt = if owner_id = "" then None else Some (int_of_string owner_id) in Database.update_todo_owner_id todo_id owner_id_opt;%lwt Database.update_todo_activation_date todo_id activation_date) todos;%lwt render_edit_todo_cont_page ~cur_user src_page_cont)) let rec render_todo_editor ~cur_user (src_page_cont, todos_to_edit) = let%lwt users = Database.query_users () in let todos_str = String.concat "," (List.map string_of_int todos_to_edit) in let%lwt todos = Database.query_todos_by_ids todos_to_edit in let%lwt f = let%lwt todo_in_pages = Database.todos_in_pages (List.map (fun todo -> todo.t_id) todos) in let cancel_page cont = match cont with ET_scheduler -> Html_util.cancel_link scheduler_page () | ET_view wiki -> Html_util.cancel_link wiki_view_page (wiki, (None, (None, None))) in let owner_selection chain todo = let match_owner u = function Some o -> o.owner_id = u.user_id | None -> false in let options = List.map (fun u -> Form.Option ([], string_of_int u.user_id, Some (txt u.user_login), match_owner u todo.t_owner)) users in Form.select Form.string ~name:chain (Form.Option ([], "", None, false)) options in let todo_descr chain v = Form.input ~input_type:`Text ~name:chain ~value:v Form.string in (* See nurpawiki_calendar.js for JavaScript calendar binding details. *) let create_listform f = [table @@ (tr [th [txt "ID"]; th [txt "Description"]; th [txt "Activates on"]]) :: (f.it (fun (tv_id,(tv_act_date,(tv_descr,tv_owner_id))) todo accu -> let pri_style = Html_util.priority_css_class todo.t_priority in (tr ~a:[a_class [pri_style]] [td [txt (string_of_int todo.t_id)]; td (todo_descr tv_descr todo.t_descr :: wiki_page_links todo_in_pages todo); td ~a:[a_class ["no_break"]] [Form.input ~a:[a_readonly (); a_id ("calendar_"^(string_of_int todo.t_id))] ~input_type:`Text ~name:tv_act_date ~value:todo.t_activation_date Form.string; button ~a:[a_id ("cal_button_"^(string_of_int todo.t_id))] [txt "..."]]; td [owner_selection tv_owner_id todo; Form.input ~name:tv_id ~input_type:`Hidden ~value:todo.t_id Form.int]])::accu) todos [tr [td [Form.input ~input_type:`Submit ~value:"Save" Form.string; cancel_page src_page_cont]]])] in return & Form.post_form ~service:service_save_todo_item create_listform src_page_cont in let heading = [txt ("Edit TODOs "^todos_str)] in let help_str = txt "NOTE: Below activation date will be assigned for all the items" in let calendar_js = [["jscalendar"; "calendar.js"]; ["jscalendar"; "lang"; "calendar-en.js"]; ["jscalendar"; "calendar-setup.js"]; ["nurpawiki_calendar.js"]] in return & Html_util.html_stub ~javascript:calendar_js (Html_util.navbar_html ~cur_user ((h1 heading)::[help_str; br(); f])) let error_page msg = Html_util.html_stub [h1 [txt ("ERROR: "^msg)]] let render_todo_get_page ~cur_user (src_page_cont, todo) = match todo with Some todo_id -> render_todo_editor ~cur_user (src_page_cont, [todo_id]) | None -> (* Bogus input as we didn't get any todos to edit.. But let's just take the user back to where he came from rather than issueing an error message. *) render_edit_todo_cont_page ~cur_user src_page_cont let _ = Eliom_registration.Html.register edit_todo_get_page (fun get_params () -> Session.with_user_login (fun cur_user -> render_todo_get_page ~cur_user get_params)) let todo_id_re = Pcre.regexp "^t-([0-9]+)$" let parse_todo_ids todo_ids = try List.map (fun (todo_id_str,b) -> match match_pcre_option todo_id_re todo_id_str with Some r -> int_of_string r.(1) | None -> raise Not_found) todo_ids with Not_found -> [] let _ = Eliom_registration.Html.register edit_todo_page (fun (src_page_cont, single_tid) (todo_ids : (string * string) list) -> Session.with_user_login (fun cur_user -> if todo_ids = [] then render_todo_get_page ~cur_user (src_page_cont, single_tid) else render_todo_editor ~cur_user (src_page_cont, (parse_todo_ids todo_ids)))) nurpawiki-1.2.4/src/services.ml000066400000000000000000000052271372046603600165100ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Eliom_content.Html.F open Eliom_parameter open Eliom_service open Config open Types open Lwt let wiki_view_page = create ~path:(Path ["view"]) ~meth:(Get ((string "p") ** (opt (bool "printable")) ** (opt (int "r")) ** (opt (bool "force_login")))) () let wiki_start = Eliom_registration.Redirection.create ~path:(Path []) ~meth:(Get unit) (fun () () -> return (Eliom_registration.Redirection (preapply ~service:wiki_view_page (Config.site.cfg_homepage, (None, (None, None)))))) let wiki_edit_page = create ~path:(Path ["edit"]) ~meth:(Get (string "p")) () let scheduler_page = create ~path:(Path ["scheduler"]) ~meth:(Get unit) () let edit_todo_get_page = create ~path:(Path ["edit_todo"]) ~meth:(Get ((user_type et_cont_of_string string_of_et_cont "src_service") ** (opt (int "tid")))) () let edit_todo_page = create_attached_post ~fallback:edit_todo_get_page ~post_params:any () let history_page = create ~path:(Path ["history"]) ~meth:(Get (opt (int "nth_p"))) () let search_page = create ~path:(Path ["search"]) ~meth:(Get (string "q")) () let benchmark_page = create ~path:(Path ["benchmark"]) ~meth:(Get (string "test")) () let user_admin_page = create ~path:(Path ["user_admin"]) ~meth:(Get unit) () let edit_user_page = create ~path:(Path ["edit_user"]) ~meth:(Get (opt (string "caller") ** (string "user_to_edit"))) () let disconnect_page = create ~path:(Path ["disconnect"]) ~meth:(Get unit) () let about_page = create ~path:(Path ["about"]) ~meth:(Get unit) () let page_revisions_page = create ~path:(Path ["page_revisions"]) ~meth:(Get (string "p")) () let task_side_effect_complete_action = create ~path:No_path ~meth:(Get (int "task_id")) () let task_side_effect_undo_complete_action = create ~path:No_path ~meth:(Get (int "task_id")) () let task_side_effect_mod_priority_action = create ~path:No_path ~meth:(Get ((int "task_id") ** bool "dir")) () nurpawiki-1.2.4/src/session.ml000066400000000000000000000230441372046603600163450ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Lwt open Eliom_content.Html.F open Eliom_content.Html.F.Form open Eliom_service open Eliom_parameter open Services open Types open Config module Db = Database module Dbu = Database_upgrade let seconds_in_day = 60.0 *. 60.0 *. 24.0 let scope_hierarchy = Eliom_common.create_scope_hierarchy "nurpawiki_session_data" let scope = `Session scope_hierarchy let login_eref = Eliom_reference.eref ~scope ~persistent:"login_info" None (* Set password & login into session. We set the cookie expiration into 24h from now so that the user can even close his browser window, re-open it and still retain his logged in status. *) let set_password_in_session login_info = let open Eliom_state in let cookie_scope = scope in set_service_state_timeout ~cookie_scope None; set_persistent_data_state_timeout ~cookie_scope None >>= fun () -> set_persistent_data_cookie_exp_date ~cookie_scope (Some 3153600000.0) >>= fun () -> Eliom_reference.set login_eref (Some login_info) let upgrade_page = create ~path:(Path ["upgrade"]) ~meth:(Get unit) () let schema_install_page = create ~path:(Path ["schema_install"]) ~meth:(Get unit) () let connect_action = create ~path:No_path ~meth:(Post (unit, (string "login") ** (string "passwd"))) () let link_to_nurpawiki_main sp = a ~service:wiki_view_page [txt "Take me to Nurpawiki"] (Config.site.cfg_homepage,(None,(None,None))) (* Get logged in user as an option *) let get_login_user () = Eliom_reference.get login_eref let db_upgrade_warning () = [h1 [txt "Database Upgrade Warning!"]; p [txt "An error occured when Nurpawiki was trying to access database."; br (); strong [ txt "You might be seeing this for a couple of reasons:"; br ()]; br (); txt "1) You just installed Nurpawiki and this is the first time you're running Nurpawiki on your database!"; br (); txt "2) You have upgraded an existing Nurpawiki installation and this is the first time you're running it since upgrade."; br (); br (); txt "In order to continue, your DB needs to be upgraded. "; txt "If you have valuable data in your DB, please take a backup of it before proceeding!"; br (); br (); a ~service:upgrade_page [txt "Upgrade now!"] ()]] let db_installation_error () = [div [h1 [txt "Database schema not installed"]; br (); p [txt "It appears you're using your Nurpawiki installation for the first time. "; br (); br (); txt "In order to complete Nurpawiki installation, your Nurpawiki database schema needs to be initialized."]; p [txt "Follow this link to complete installation:"; br (); br (); a ~service:schema_install_page [txt "Install schema!"] ()]]] let login_html ~err = let help_text = [br (); br (); strong [txt "Please read "]; Raw.a ~a:[a_id "login_help_url"; a_href (uri_of_string (fun () -> "https://github.com/glondu/nurpawiki/blob/master/doc/Tutorial.md"))] [txt "Nurpawiki tutorial"]; txt " if you're logging in for the first time."; br ()] in Html_util.html_stub [div ~a:[a_id "login_outer"] [div ~a:[a_id "login_align_middle"] [post_form connect_action (fun (loginname,passwd) -> [table ~a:[a_class ["login_box"]] [tr [td ~a:[a_class ["login_text"]] (txt "Welcome to Nurpawiki!"::help_text)]; tr [td [txt ""]]; tr [td ~a:[a_class ["login_text_descr"]] [txt "Username:"]]; tr [td [input ~input_type:`Text ~name:loginname Form.string]]; tr [td ~a:[a_class ["login_text_descr"]] [txt "Password:"]]; tr [td [input ~input_type:`Password ~name:passwd Form.string]]; tr [td [input ~input_type:`Submit ~value:"Login" Form.string]]]; p err]) ()]]] let with_db_installed f = (* Check if the DB is installed. If so, check that it doesn't need an upgrade. *) let%lwt b = Dbu.is_schema_installed () in if not b then return (Html_util.html_stub (db_installation_error ())) else let%lwt v = Dbu.db_schema_version () in if v < Db.nurpawiki_schema_version then return (Html_util.html_stub (db_upgrade_warning ())) else f () (** Wrap page service calls inside with_user_login to have them automatically check for user login and redirect to login screen if not logged in. *) let with_user_login ?(allow_read_only=false) f = let login () = get_login_user () >>= function | Some (login,passwd) -> begin Db.query_user login >>= function | Some user -> let passwd_md5 = Digest.to_hex (Digest.string passwd) in (* Autheticate user against his password *) if passwd_md5 <> user.user_passwd then return (login_html [Html_util.error ("Wrong password given for user '"^login^"'")]) else f user | None -> return (login_html [Html_util.error ("Unknown user '"^login^"'")]) end | None -> if allow_read_only && Config.site.cfg_allow_ro_guests then let guest_user = { user_id = 0; user_login = "guest"; user_passwd = ""; user_real_name = "Guest"; user_email = ""; } in f guest_user else return (login_html []) in with_db_installed login (* Either pretend to be logged in as 'guest' (if allowed by config options) or require a proper login. If logging in as 'guest', we setup a dummy user 'guest' that is not a real user. It won't have access to write to any tables. *) let with_guest_login f = with_user_login ~allow_read_only:true f (* Same as with_user_login except that we can't generate HTML for any errors here. Neither can we present the user with a login box. If there are any errors, just bail out without doing anything harmful. *) let action_with_user_login f = let%lwt db_version = Dbu.db_schema_version () in if db_version = Db.nurpawiki_schema_version then get_login_user () >>= function | Some (login,passwd) -> begin Db.query_user login >>= function | Some user -> let passwd_md5 = Digest.to_hex (Digest.string passwd) in (* Autheticate user against his password *) if passwd_md5 = user.user_passwd then f user else return () | None -> return () end | None -> return () else return () let update_session_password login new_password = Eliom_state.discard ~scope () >>= fun () -> set_password_in_session (login, new_password) (* Check session to see what happened during page servicing. If any actions were called, some of them might've set values into session that we want to use for rendering the current page. *) let any_complete_undos () = let table = Eliom_request_info.get_request_cache () in try Some (Polytables.get ~table ~key:action_completed_task) with Not_found -> None (* Same as any_complete_undos except we check for changed task priorities. *) let any_task_priority_changes () = let table = Eliom_request_info.get_request_cache () in try Some (Polytables.get ~table ~key:action_task_priority_changed) with Not_found -> None let connect_action_handler () login_nfo = Eliom_state.discard ~scope () >>= fun () -> set_password_in_session login_nfo >>= fun () -> return () let () = Eliom_registration.Action.register ~service:connect_action connect_action_handler (* /schema_install initializes the database schema (if needed) *) let _ = Eliom_registration.Html.register schema_install_page (fun () () -> Database_schema.install_schema ();%lwt return (Html_util.html_stub [h1 [txt "Database installation completed"]; p [br (); link_to_nurpawiki_main ()]])) (* /upgrade upgrades the database schema (if needed) *) let _ = Eliom_registration.Html.register upgrade_page (fun () () -> let%lwt msg = Dbu.upgrade_schema () in return (Html_util.html_stub [h1 [txt "Upgrade DB schema"]; (pre [txt msg]); p [br (); link_to_nurpawiki_main ()]])) let _ = Eliom_registration.Html.register disconnect_page (fun () () -> Eliom_state.discard ~scope () >>= fun () -> return (Html_util.html_stub [h1 [txt "Logged out!"]; p [br (); link_to_nurpawiki_main ()]])) nurpawiki-1.2.4/src/types.ml000066400000000000000000000060231372046603600160240ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) module OrdInt = struct type t = int let compare a b = compare a b end module IMap = Map.Make (OrdInt) (* Sides-effects of Eliom actions *) let action_completed_task : int Polytables.key = Polytables.make_key () let action_task_priority_changed : int Polytables.key = Polytables.make_key () type user = { user_id : int; user_login : string; user_passwd : string; user_real_name : string; user_email : string; } type todo = { t_id : int; t_descr : string; t_completed : bool; t_priority : int; t_activation_date : string; t_owner : owner option; } and owner = { owner_id : int; owner_login : string; } type page = { p_id : int; p_descr : string; } type page_revision = { pr_revision : int; pr_created : string; pr_owner_id : int option; pr_owner_login : string option; } type activity_type = AT_create_todo | AT_complete_todo | AT_work_on_todo | AT_create_page | AT_edit_page | AT_uncomplete_todo type activity = { a_id : int; a_activity : activity_type; a_date : string; a_todo_descr : string option; a_changed_by : string option; } type search_result_type = SR_page | SR_todo type search_result = { sr_id : int; sr_headline : string; sr_result_type : search_result_type; sr_page_descr : string option; } type et_cont = ET_scheduler | ET_view of string let et_cont_view_re = Pcre.regexp "^v_(.*)$" let string_of_et_cont = function ET_scheduler -> "s" | ET_view src_page -> "v_"^src_page let match_pcre_option rex s = try Some (Pcre.extract ~rex s) with Not_found -> None let et_cont_of_string s = if s = "s" then ET_scheduler else begin match match_pcre_option et_cont_view_re s with None -> raise (Failure "et_cont_of_string") | Some s -> ET_view s.(1) end let int_of_activity_type = function AT_create_todo -> 1 | AT_complete_todo -> 2 | AT_work_on_todo -> 3 | AT_create_page -> 4 | AT_edit_page -> 5 | AT_uncomplete_todo -> 6 let activity_type_of_int = function 1 -> AT_create_todo | 2 -> AT_complete_todo | 3 -> AT_work_on_todo | 4 -> AT_create_page | 5 -> AT_edit_page | 6 -> AT_uncomplete_todo | _ -> assert false nurpawiki-1.2.4/src/user_editor.ml000066400000000000000000000232001372046603600172000ustar00rootroot00000000000000(* Copyright (c) 2006-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open Lwt open Eliom_content.Html.F open Eliom_content.Html.F.Form open Eliom_parameter open Eliom_service open Services open Types module Db = Database let service_create_new_user = create_attached_post ~fallback:user_admin_page ~post_params:((string "login") ** (string "pass") ** (string "pass2") ** (* re-type *) (string "name") ** (string "email")) () let service_save_user_edit = create_attached_post ~fallback:edit_user_page ~post_params:((string "pass") ** (string "pass2") ** (* re-type *) (string "name") ** (string "email")) () let rec view_user_admin_page ~err ~cur_user = let%lwt users = Db.query_users () in let users_table = table @@ (tr [th [txt "Id"]; th [txt "Login"]; th [txt "Real Name"]; th [txt "E-mail"]]) :: (List.map (fun user -> tr [td [txt (string_of_int user.user_id)]; td [txt user.user_login]; td [txt user.user_real_name]; td [txt user.user_email]; td [a ~service:edit_user_page [txt "Edit"] (Some "user_admin", user.user_login)]]) users) in return (Html_util.html_stub (Html_util.navbar_html ~cur_user ([h1 [txt "Edit users"]; users_table] @ err @ [post_form ~service:service_create_new_user (fun (login,(passwd,(passwd2,(name,email)))) -> [h2 [txt "Create a new user"]; (table [tr [td [txt "Login:"]; td [input ~input_type:`Text ~name:login Form.string]]; tr [td [txt "Password:"]; td [input ~input_type:`Password ~name:passwd Form.string]]; tr [td [txt "Re-type password:"]; td [input ~input_type:`Password ~name:passwd2 Form.string]]; tr [td [txt "Name:"]; td [input ~input_type:`Text ~name:name Form.string]]; tr [td [txt "E-mail address:"]; td [input ~input_type:`Text ~name:email Form.string]]; tr [td [input ~input_type:`Submit ~value:"Add User" Form.string]] ])]) ()]))) (* Only allow certain types of login names to avoid surprises *) let sanitize_login_name name = let rex = Pcre.regexp "^[a-zA-Z_][a-zA-Z0-9_]*$" in try Some (Pcre.extract ~rex name).(0) with Not_found -> None let save_user ~update_user ~login ~passwd ~passwd2 ~real_name ~email = let sanitized_login = sanitize_login_name login in match sanitized_login with None -> return [Html_util.error ("Only alphanumeric chars are allowed in login name! Got '"^login^"'")] | Some login -> Db.query_user login >>= fun old_user -> if not update_user && old_user <> None then return [Html_util.error ("User '"^login^"' already exists!")] else if login = "guest" then return [Html_util.error ("Cannot create '"^login^"' user. The login name 'guest' is reserved for internal use!")] else if passwd <> passwd2 then return [Html_util.error "Re-typed password doesn't match your password!"] else begin let passwd_md5 = Digest.to_hex (Digest.string passwd) in if update_user then begin match old_user with Some u -> (* If no password was entered, set it to old value: *) let new_passwd_md5 = if passwd = "" then None else Some passwd_md5 in Db.with_conn (fun conn -> Db.update_user ~conn ~user_id:u.user_id ~passwd:new_passwd_md5 ~real_name ~email) >>= fun _ -> return [] | None -> assert false end else Db.with_conn (fun conn -> Db.add_user ~conn ~login ~passwd:passwd_md5 ~real_name ~email) >>= fun _ -> return [] end let _ = Eliom_registration.Html.register service_create_new_user (fun () (login, (passwd, (passwd2, (real_name, email)))) -> Session.with_user_login (fun cur_user -> Privileges.with_can_create_user cur_user (fun () -> save_user ~update_user:false ~login ~passwd ~passwd2 ~real_name ~email >>= fun err -> view_user_admin_page ~err ~cur_user) ~on_fail:(fun e -> return (Html_util.error_page e)))) let save_user_prefs c_passwd c_passwd2 (c_name,old_name) (c_email,old_email) = (table [tr [td [txt "New Password:"]; td [input ~input_type:`Password ~name:c_passwd Form.string]; ]; tr [td [txt "Re-type Password:"]; td [input ~input_type:`Password ~name:c_passwd2 Form.string]]; tr [td [txt "Name:"]; td [input ~input_type:`Text ~name:c_name ~value:old_name Form.string]]; tr [td [txt "E-mail Address:"]; td [input ~input_type:`Text ~name:c_email ~value:old_email Form.string]]; tr [td [input ~input_type:`Submit ~value:"Save User" Form.string]] ]) let _ = Eliom_registration.Html.register user_admin_page (fun _ () -> Session.with_user_login (fun cur_user -> Privileges.with_can_view_users cur_user (fun () -> view_user_admin_page ~err:[] ~cur_user) ~on_fail:(fun e -> return (Html_util.error_page e)))) let rec view_edit_user_page caller ~err ~cur_user user_to_edit = Html_util.html_stub (Html_util.navbar_html ~cur_user ([h1 [txt "Edit User"]] @ err @ [post_form ~service:service_save_user_edit (fun (passwd,(passwd2,(name,email))) -> [h2 [txt ("Edit User '"^user_to_edit.user_login^"'")]; save_user_prefs passwd passwd2 (name,user_to_edit.user_real_name) (email,user_to_edit.user_email)]) (caller, user_to_edit.user_login)])) let _ = Eliom_registration.Html.register service_save_user_edit (fun (caller, login) (passwd, (passwd2, (real_name, email))) -> Session.with_user_login (fun cur_user -> Db.query_user login >>= function | Some user_to_edit -> Privileges.with_can_edit_user cur_user user_to_edit (fun () -> save_user ~update_user:true ~login:login ~passwd ~passwd2 ~real_name ~email >>= fun err -> (* Update password in the session if we're editing current user: *) (if err = [] && passwd <> "" && cur_user.user_login = login then Session.update_session_password login passwd else return () ) >>= fun () -> Session.with_user_login (fun cur_user -> match caller with Some "user_admin" -> view_user_admin_page ~err ~cur_user | Some _ -> return (Html_util.error_page "Invalid caller service!") | None -> Db.query_user login >>= function | Some user -> return (view_edit_user_page caller ~err ~cur_user user) | None -> return (Html_util.error_page "Invalid user!"))) ~on_fail:(fun e -> return (Html_util.error_page e)) | None -> return (Html_util.error_page ("Trying to edit unknown user '"^login^"'")))) let _ = Eliom_registration.Html.register edit_user_page (fun (caller, editing_login) () -> Session.with_user_login (fun cur_user -> Db.query_user editing_login >>= function | Some user_to_edit -> Privileges.with_can_edit_user cur_user user_to_edit (fun () -> return (view_edit_user_page caller ~err:[] ~cur_user user_to_edit)) ~on_fail:(fun e -> return (Html_util.error_page e)) | None -> return (Html_util.error_page ("Unknown user '"^editing_login^"'")))) nurpawiki-1.2.4/src/util.ml000066400000000000000000000042631372046603600156410ustar00rootroot00000000000000(* Copyright (c) 2007-2008 Janne Hellsten *) (* * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. You should have received * a copy of the GNU General Public License along with this program. * If not, see . *) open CalendarLib let match_pcre_option ?(charpos=0) rex s = (* Pcre's ~pos seems to work quite differently from Str's begin character. The below sub string hack is to make Pcre extract behave the same way as Str's match *) let s = String.sub s charpos ((String.length s) - charpos) in try Some (Pcre.extract (* ~pos:charpos *) ~rex s) with Not_found -> None let iso_date_re = Pcre.regexp "([0-9]+)-([0-9]+)-([0-9]+)" let date_of_string s = match match_pcre_option iso_date_re s with Some r -> let year = int_of_string r.(1) in let month = int_of_string r.(2) in let day = int_of_string r.(3) in Date.make year month day | None -> assert false let iso_date_time_re = Pcre.regexp "([0-9]+)-([0-9]+)-([0-9]+) .*" let date_of_date_time_string s = match (match_pcre_option iso_date_time_re s, match_pcre_option iso_date_re s) with (Some r,_)|(_,Some r) -> let year = int_of_string r.(1) in let month = int_of_string r.(2) in let day = int_of_string r.(3) in Date.make year month day | _ -> Ocsigen_messages.errlog ("invalid date '"^s^"'"); assert false (** [del_substring s c] return [s] with all occurrences of substring [c] removed. *) let del_substring s c = let q = Pcre.regexp (Pcre.quote c) in Pcre.replace ~rex:q ~templ:"" s (* Unit tests *) let _ = let a = "\\*foo\\*baz\\*" in assert (del_substring a "\\*" = "foobaz"); let b = "__foo__" in assert (del_substring b "_" = "foo") nurpawiki-1.2.4/src/version.ml.in000066400000000000000000000000471372046603600167520ustar00rootroot00000000000000 let version = "%_NURPAWIKI_VERSION_%" nurpawiki-1.2.4/test/000077500000000000000000000000001372046603600145155ustar00rootroot00000000000000nurpawiki-1.2.4/test/bench.sh000077500000000000000000000014411372046603600161330ustar00rootroot00000000000000#!/bin/sh N=100 BN=500 test_wiki_start() { i=0 while [ "$i" -lt $N ]; do curl "http://localhost:8080/view?p=WikiStart" > /dev/null 2> /dev/null i=`expr $i + 1` done } test_history() { i=0 while [ "$i" -lt $N ]; do curl "http://localhost:8080/history" > /dev/null 2> /dev/null i=`expr $i + 1` done } test_benchmark() { i=0 while [ "$i" -lt $BN ]; do curl "http://localhost:8080/benchmark?test=$1" > /dev/null 2> /dev/null i=`expr $i + 1` done } echo View WikiStart $N times time -p test_wiki_start echo echo "View /history $N times" time -p test_history echo echo "View /benchmark?test=empty $BN times" time -p test_benchmark empty echo echo "View /benchmark?test=db1 $BN times" time -p test_benchmark db1 nurpawiki-1.2.4/test/functional/000077500000000000000000000000001372046603600166575ustar00rootroot00000000000000nurpawiki-1.2.4/test/functional/README000066400000000000000000000002341372046603600175360ustar00rootroot00000000000000This directory contains .html files that are to be used with Selenium Core (or IDE). See the Nurpawiki docs for instructions on how to run the test suite. nurpawiki-1.2.4/test/functional/TestSuite.html000066400000000000000000000012631372046603600215000ustar00rootroot00000000000000
Nurpawiki test suite
First run after DB creation
Create test1 user and login with it
Change test1 user password and login with new user
test4_create_FooBar_wiki_page
Add a to-do
Complete the added to-do
nurpawiki-1.2.4/test/functional/test1.html000066400000000000000000000011541372046603600206060ustar00rootroot00000000000000 test1
test1
open /upgrade
clickAndWait link=Take me to Nurpawiki
clickAndWait link=About
verifyTextPresent Nurpawiki
verifyTextPresent Copyright
nurpawiki-1.2.4/test/functional/test2.html000066400000000000000000000035221372046603600206100ustar00rootroot00000000000000 test2
test2
open /about
clickAndWait link=Logout
clickAndWait link=Take me to Nurpawiki
clickAndWait link=here
type login admin
type passwd
clickAndWait //input[@value='Login']
clickAndWait link=Edit Users
type login test1
type pass test1
type pass2 test1
type name Test User
type email foo@foo.com
clickAndWait //input[@value='Add User']
verifyTextPresent Test User
clickAndWait link=Logout
clickAndWait link=Take me to Nurpawiki
clickAndWait link=here
type login test1
type passwd test1
clickAndWait //input[@value='Login']
clickAndWait link=My Preferences
verifyTextPresent Edit User
verifyTextPresent test1
nurpawiki-1.2.4/test/functional/test3_change_test1_passwd.html000066400000000000000000000031011372046603600246100ustar00rootroot00000000000000 test3_change_test1_passwd
test3_change_test1_passwd
open /view?p=WikiStart
clickAndWait link=Logout
clickAndWait link=Take me to Nurpawiki
clickAndWait link=here
type login test1
type passwd test1
clickAndWait //input[@value='Login']
clickAndWait link=My Preferences
type pass test1x
type pass2 test1x
type name Test User
clickAndWait //input[@value='Save User']
clickAndWait link=Logout
clickAndWait link=Take me to Nurpawiki
clickAndWait link=here
type login test1
type passwd test1x
clickAndWait //input[@value='Login']
verifyTextPresent test1
nurpawiki-1.2.4/test/functional/test4_create_FooBar_wiki_page.html000066400000000000000000000027151372046603600254070ustar00rootroot00000000000000 test4_create_FooBar_wiki_page
test4_create_FooBar_wiki_page
open /view?p=WikiStart
clickAndWait link=Logout
clickAndWait link=Take me to Nurpawiki
clickAndWait link=here
type login admin
type passwd
clickAndWait //input[@value='Login']
clickAndWait link=Edit page
type value = Nurpawiki =

See WikiMarkup for help on getting started.

Wiki page FooBar
clickAndWait //input[@value='Save']
clickAndWait link=FooBar
clickAndWait link=Create new page
type value = New Page =

Foo bar page.
clickAndWait //input[@value='Save']
verifyTextPresent Foo bar page
nurpawiki-1.2.4/test/functional/test5_add_a_todo.html000066400000000000000000000022061372046603600227460ustar00rootroot00000000000000 test5_add_a_todo
test5_add_a_todo
open /disconnect
clickAndWait link=Take me to Nurpawiki
clickAndWait link=FooBar
clickAndWait link=Edit page
type login test1
type login admin
type passwd
clickAndWait //input[@value='Login']
type value = New Page =

Foo bar page.

* [todo Add todo 1]
clickAndWait //input[@value='Save']
clickAndWait link=Home
verifyTextPresent Add todo 1
nurpawiki-1.2.4/test/functional/test6_complete_todo.html000066400000000000000000000016421372046603600235320ustar00rootroot00000000000000 test6_complete_todo
test6_complete_todo
open /view?p=WikiStart
clickAndWait link=Logout
clickAndWait link=Take me to Nurpawiki
clickAndWait link=here
type login admin
type passwd
clickAndWait //input[@value='Login']
clickAndWait //img[@alt='Mark complete']
verifyTextPresent Completed task
nurpawiki-1.2.4/test/postgresql/000077500000000000000000000000001372046603600167205ustar00rootroot00000000000000nurpawiki-1.2.4/test/postgresql/Makefile000066400000000000000000000002051372046603600203550ustar00rootroot00000000000000 CAMLC = ocamlfind ocamlc -thread -g $(LIB) LIB = -package extlib,postgresql -linkpkg all: $(CAMLC) $(LIB) psqltest.ml -o psqltest nurpawiki-1.2.4/test/postgresql/psqltest.ml000066400000000000000000000017741372046603600211420ustar00rootroot00000000000000 module Psql = Postgresql module P = Printf let guarded_exec ~(conn : Psql.connection) query = try conn#exec query with (Psql.Error e) as ex -> (match e with Psql.Connection_failure msg -> P.eprintf "psql failed : %s\n" msg; raise ex | _ -> P.eprintf "psql failed : %s\n" (Psql.string_of_error e); raise ex) let _ = Printf.printf "Postgresql <-> Nurpawiki DB installation test.\n"; let db_user = "postgres" in let db_name = "nurpawiki" in let db_passwd = "barfoo" in let conn = new Psql.connection ~host:"localhost" ~dbname:db_name ~user:db_user (* ~port:(Option.default "" dbcfg.db_port)*) ~password:db_passwd () in let sql = "SELECT schemaname,tablename from pg_tables WHERE (schemaname = 'public' OR schemaname = 'nw') AND tablename = 'todos'" in let r = guarded_exec ~conn sql in let row_str = String.concat "." (List.hd r#get_all_lst) in Printf.printf "DB result: '%s'\n" row_str nurpawiki-1.2.4/test/results.txt000066400000000000000000000005551372046603600167640ustar00rootroot00000000000000 unit of measurement: page view/s Date WikiStart /history "bm empty" "bm db1" ---------------------------------------------------------- 2007-01-31 0.065 0.195 2007-03-06 0.051 0.217 0.017 0.019 2007-03-13 0.051 0.24 0.017 0.020 2007-04-14 0.075 0.31 0.026 0.27 nurpawiki-1.2.4/test/stress/000077500000000000000000000000001372046603600160405ustar00rootroot00000000000000nurpawiki-1.2.4/test/stress/stress.sh000066400000000000000000000002141372046603600177140ustar00rootroot00000000000000#!/bin/sh mkdir tmp for i in `seq 0 10000`; do echo $i wget -r http://localhost:8080/view?p=WikiStart -o /dev/null -l1 -P tmp done