From 6ff385e4077bd7048b6f1c64cc240b9abd668876 Mon Sep 17 00:00:00 2001 From: stan Date: Tue, 21 Jun 2011 09:19:10 +0000 Subject: [PATCH] git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@3459 e3e1d417-86f3-4887-817a-d78f3d33393f --- config.h.in | 36 + configure | 85 +- configure.ac | 9 +- db/Makefile.am | 3 +- db/Makefile.in | 3 +- db/zm_create.sql.in | 15 + db/zm_update-1.24.4.sql | 30 + scripts/Makefile.am | 2 +- scripts/Makefile.in | 2 +- scripts/ZoneMinder/Makefile.PL | 2 +- scripts/ZoneMinder/lib/ZoneMinder.pm | 12 +- .../lib/ZoneMinder/ConfigData.pm.in | 172 +- scripts/ZoneMinder/lib/ZoneMinder/Control.pm | 2 +- .../lib/ZoneMinder/Control/AxisV2.pm | 2 +- .../lib/ZoneMinder/Control/Ncs370.pm | 2 +- .../lib/ZoneMinder/Control/PanasonicIP.pm | 2 +- .../lib/ZoneMinder/Control/PelcoD.pm | 4 +- .../lib/ZoneMinder/Control/PelcoP.pm | 4 +- .../lib/ZoneMinder/Control/Visca.pm | 4 +- .../lib/ZoneMinder/Control/mjpgStreamer.pm | 2 +- scripts/ZoneMinder/lib/ZoneMinder/Database.pm | 3 +- scripts/ZoneMinder/lib/ZoneMinder/Debug.pm | 474 - scripts/ZoneMinder/lib/ZoneMinder/General.pm | 6 +- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 852 ++ .../ZoneMinder/lib/ZoneMinder/Memory.pm.in | 2 +- .../lib/ZoneMinder/Memory/Mapped.pm | 2 +- .../lib/ZoneMinder/Memory/Shared.pm | 2 +- .../lib/ZoneMinder/Trigger/Channel.pm | 2 +- .../lib/ZoneMinder/Trigger/Channel/File.pm | 2 +- .../lib/ZoneMinder/Trigger/Channel/Handle.pm | 2 +- .../lib/ZoneMinder/Trigger/Channel/Inet.pm | 2 +- .../lib/ZoneMinder/Trigger/Channel/Serial.pm | 2 +- .../ZoneMinder/Trigger/Channel/Spawning.pm | 2 +- .../lib/ZoneMinder/Trigger/Channel/Unix.pm | 2 +- .../lib/ZoneMinder/Trigger/Connection.pm | 2 +- .../ZoneMinder/Trigger/Connection/Example.pm | 2 +- scripts/zmaudit.pl.in | 474 +- scripts/zmcontrol.pl.in | 19 +- scripts/zmdc.pl.in | 258 +- scripts/zmfilter.pl.in | 11 +- scripts/zmpkg.pl.in | 11 +- scripts/zmtrack.pl.in | 9 +- scripts/zmtrigger.pl.in | 7 +- scripts/zmupdate.pl.in | 148 +- scripts/zmvideo.pl.in | 11 +- scripts/zmwatch.pl.in | 7 +- scripts/zmx10.pl.in | 29 +- src/Makefile.am | 8 +- src/Makefile.in | 36 +- src/zm.h | 6 +- src/zm_comms.cpp | 2 +- src/zm_config.cpp | 31 +- src/zm_config.h.in | 5 + src/zm_config_defines.h | 360 +- src/zm_db.cpp | 3 + src/zm_db.h | 10 +- src/zm_debug.c | 470 - src/zm_debug.h | 118 - src/zm_ffmpeg_camera.cpp | 2 +- src/zm_file_camera.h | 2 + src/zm_image.cpp | 4 +- src/{zm_jpeg.c => zm_jpeg.cpp} | 10 +- src/zm_jpeg.h | 7 + src/zm_local_camera.cpp | 2 +- src/zm_logger.cpp | 569 ++ src/zm_logger.h | 237 + src/zm_remote_camera_rtsp.cpp | 4 +- src/zm_rtsp.cpp | 4 +- src/zm_signal.cpp | 9 +- src/zm_thread.cpp | 2 +- src/zm_timer.cpp | 2 +- src/zm_user.cpp | 7 +- src/zm_utils.cpp | 2 +- src/zma.cpp | 8 +- src/zmc.cpp | 14 +- src/zmf.cpp | 8 +- src/zmfix.cpp | 5 +- src/zms.cpp | 4 +- src/zmstreamer.cpp | 2 +- src/zmu.cpp | 4 +- web/ajax/Makefile.am | 1 + web/ajax/Makefile.in | 1 + web/ajax/log.php | 357 + web/ajax/stream.php | 10 +- web/css/Makefile.am | 4 +- web/css/Makefile.in | 4 +- web/css/overlay.css | 49 + web/css/spinner.css | 19 + web/graphics/Makefile.am | 1 + web/graphics/Makefile.in | 1 + web/graphics/spinner.gif | Bin 0 -> 2545 bytes web/includes/Makefile.am | 3 +- web/includes/Makefile.in | 3 +- web/includes/actions.php | 6 +- web/includes/config.php.in | 13 +- web/includes/database.php | 13 +- web/includes/functions.php | 69 +- web/includes/logger.php | 594 ++ web/index.php | 9 +- web/js/Makefile.am | 4 +- web/js/Makefile.in | 4 +- web/js/logger.js | 116 + web/js/mootools.ext.js | 8 +- web/js/overlay.js | 141 + web/lang/big5_big5.php | 21 + web/lang/cn_zh.php | 21 + web/lang/cs_cz.php | 21 + web/lang/de_de.php | 21 + web/lang/dk_dk.php | 21 + web/lang/en_gb.php | 24 +- web/lang/es_ar.php | 21 + web/lang/es_es.php | 21 + web/lang/et_ee.php | 21 + web/lang/fr_fr.php | 21 + web/lang/he_il.php | 21 + web/lang/hu_hu.php | 21 + web/lang/it_it.php | 21 + web/lang/ja_jp.php | 21 + web/lang/nl_nl.php | 21 + web/lang/pl_pl.php | 21 + web/lang/pt_br.php | 21 + web/lang/ro_ro.php | 21 + web/lang/ru_ru.php | 21 + web/lang/se_se.php | 21 + web/skins/classic/css/skin.css | 92 +- web/skins/classic/graphics/Makefile.am | 2 + web/skins/classic/graphics/Makefile.in | 2 + web/skins/classic/graphics/arrow-s-d.gif | Bin 0 -> 206 bytes web/skins/classic/graphics/arrow-s-u.gif | Bin 0 -> 203 bytes .../classic/includes/export_functions.php | 18 +- web/skins/classic/includes/functions.php | 2 + .../classic/includes/timeline_functions.php | 6 +- web/skins/classic/js/skin.js | 31 +- web/skins/classic/js/skin.js.php | 18 +- web/skins/classic/views/Makefile.am | 1 + web/skins/classic/views/Makefile.in | 1 + web/skins/classic/views/console.php | 2 +- web/skins/classic/views/css/Makefile.am | 1 + web/skins/classic/views/css/Makefile.in | 1 + web/skins/classic/views/css/log.css | 44 + web/skins/classic/views/js/Makefile.am | 1 + web/skins/classic/views/js/Makefile.in | 1 + web/skins/classic/views/js/event.js | 16 +- web/skins/classic/views/js/log.js | 304 + web/skins/classic/views/js/monitor.js.php | 4 +- web/skins/classic/views/js/montage.js | 2 +- web/skins/classic/views/js/timeline.js | 16 +- web/skins/classic/views/js/timeline.js.php | 2 +- web/skins/classic/views/js/watch.js | 40 +- web/skins/classic/views/js/watch.js.php | 2 +- web/skins/classic/views/js/zone.js | 20 +- web/skins/classic/views/js/zone.js.php | 2 +- web/skins/classic/views/log.php | 114 + web/skins/classic/views/monitorprobe.php | 9 +- web/skins/classic/views/options.php | 26 +- web/skins/mobile/includes/functions.php | 2 - web/tools/mootools/Makefile.am | 12 +- web/tools/mootools/Makefile.in | 12 +- web/tools/mootools/mootools-1.2.5-core-nc.js | 4288 --------- web/tools/mootools/mootools-1.2.5-core-yc.js | 3 - .../mootools/mootools-1.2.5.1-more-yc.js | 683 -- web/tools/mootools/mootools-core-1.3.2-nc.js | 5515 +++++++++++ web/tools/mootools/mootools-core-1.3.2-yc.js | 450 + ...more-nc.js => mootools-more-1.3.2.1-nc.js} | 8190 ++++++++++------- .../mootools/mootools-more-1.3.2.1-yc.js | 742 ++ web/views/file.php | 2 +- web/views/image.php | 14 +- 167 files changed, 16737 insertions(+), 10502 deletions(-) create mode 100644 db/zm_update-1.24.4.sql delete mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Debug.pm create mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Logger.pm delete mode 100644 src/zm_debug.c delete mode 100644 src/zm_debug.h rename src/{zm_jpeg.c => zm_jpeg.cpp} (99%) create mode 100644 src/zm_logger.cpp create mode 100644 src/zm_logger.h create mode 100644 web/ajax/log.php create mode 100644 web/css/overlay.css create mode 100644 web/css/spinner.css create mode 100644 web/graphics/spinner.gif create mode 100644 web/includes/logger.php create mode 100644 web/js/logger.js create mode 100644 web/js/overlay.js create mode 100644 web/skins/classic/graphics/arrow-s-d.gif create mode 100644 web/skins/classic/graphics/arrow-s-u.gif create mode 100644 web/skins/classic/views/css/log.css create mode 100644 web/skins/classic/views/js/log.js create mode 100644 web/skins/classic/views/log.php delete mode 100644 web/tools/mootools/mootools-1.2.5-core-nc.js delete mode 100644 web/tools/mootools/mootools-1.2.5-core-yc.js delete mode 100644 web/tools/mootools/mootools-1.2.5.1-more-yc.js create mode 100644 web/tools/mootools/mootools-core-1.3.2-nc.js create mode 100644 web/tools/mootools/mootools-core-1.3.2-yc.js rename web/tools/mootools/{mootools-1.2.5.1-more-nc.js => mootools-more-1.3.2.1-nc.js} (57%) create mode 100644 web/tools/mootools/mootools-more-1.3.2.1-yc.js diff --git a/config.h.in b/config.h.in index 96e8d0d74..b1b495683 100644 --- a/config.h.in +++ b/config.h.in @@ -18,6 +18,9 @@ */ #undef HAVE_ALLOCA_H +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + /* Define to 1 if you have the declaration of `backtrace', and to 0 if you don't. */ #undef HAVE_DECL_BACKTRACE @@ -32,6 +35,9 @@ /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H @@ -62,9 +68,18 @@ /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY +/* Define to 1 if you have the header file. */ +#undef HAVE_GLOB_H + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `ioctl' function. */ +#undef HAVE_IOCTL + +/* Define to 1 if you have the `ioctlsocket' function. */ +#undef HAVE_IOCTLSOCKET + /* Define to 1 if you have the header file. */ #undef HAVE_JPEGLIB_H @@ -177,15 +192,24 @@ /* Define to 1 if you have the header file. */ #undef HAVE_PCRE_PCRE_H +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + /* Define to 1 if the system has the type `siginfo_t'. */ #undef HAVE_SIGINFO_T +/* Define to 1 if you have the `sleep' function. */ +#undef HAVE_SLEEP + /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET @@ -256,6 +280,12 @@ /* Define to 1 if `eip' is a member of `struct sigcontext'. */ #undef HAVE_STRUCT_SIGCONTEXT_EIP +/* Define to 1 if you have the `syscall' function. */ +#undef HAVE_SYSCALL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSCALL_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H @@ -289,12 +319,18 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UN_H + /* Define to 1 if the system has the type `ucontext_t'. */ #undef HAVE_UCONTEXT_T /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `usleep' function. */ +#undef HAVE_USLEEP + /* Define to 1 if you have the header file. */ #undef HAVE_VALUES_H diff --git a/configure b/configure index d6eb42870..1b9847ac0 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for zm 1.24.4. +# Generated by GNU Autoconf 2.65 for zm 1.25.0. # # Report bugs to . # @@ -552,8 +552,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='zm' PACKAGE_TARNAME='ZoneMinder' -PACKAGE_VERSION='1.24.4' -PACKAGE_STRING='zm 1.24.4' +PACKAGE_VERSION='1.25.0' +PACKAGE_STRING='zm 1.25.0' PACKAGE_BUGREPORT='support@zoneminder.com' PACKAGE_URL='http://www.zoneminder.com/downloads.html' @@ -1309,7 +1309,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures zm 1.24.4 to adapt to many kinds of systems. +\`configure' configures zm 1.25.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1375,7 +1375,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of zm 1.24.4:";; + short | recursive ) echo "Configuration of zm 1.25.0:";; esac cat <<\_ACEOF @@ -1491,7 +1491,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -zm configure 1.24.4 +zm configure 1.25.0 generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. @@ -2050,7 +2050,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by zm $as_me 1.24.4, which was +It was created by zm $as_me 1.25.0, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -2861,7 +2861,7 @@ fi # Define the identity of the package. PACKAGE='ZoneMinder' - VERSION='1.24.4' + VERSION='1.25.0' cat >>confdefs.h <<_ACEOF @@ -6257,6 +6257,19 @@ _ACEOF fi done +for ac_func in syscall sleep usleep ioctl ioctlsocket sigaction +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + # Other programs # Extract the first word of "ffmpeg", so it can be a program name with args. @@ -7588,7 +7601,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi -for ac_header in fcntl.h limits.h memory.h netdb.h netinet/in.h stddef.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h values.h +for ac_header in fcntl.h limits.h memory.h stddef.h stdlib.h string.h strings.h sys/param.h sys/time.h syslog.h unistd.h values.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -7602,6 +7615,56 @@ fi done +for ac_header in netdb.h netinet/in.h arpa/inet.h sys/ioctl.h sys/socket.h sys/un.h glob.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in execinfo.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_execinfo_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXECINFO_H 1 +_ACEOF + +fi + +done + +for ac_header in syscall.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "syscall.h" "ac_cv_header_syscall_h" "$ac_includes_default" +if test "x$ac_cv_header_syscall_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYSCALL_H 1 +_ACEOF + +fi + +done + +for ac_header in pthread.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PTHREAD_H 1 +_ACEOF + +fi + +done + for ac_header in linux/videodev.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "linux/videodev.h" "ac_cv_header_linux_videodev_h" "$ac_includes_default" @@ -9904,7 +9967,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by zm $as_me 1.24.4, which was +This file was extended by zm $as_me 1.25.0, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9971,7 +10034,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -zm config.status 1.24.4 +zm config.status 1.25.0 configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 02ae5e9ac..6b6bd6c9f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.59) -AC_INIT(zm,1.24.4,support@zoneminder.com,ZoneMinder,http://www.zoneminder.com/downloads.html) +AC_INIT(zm,1.25.0,support@zoneminder.com,ZoneMinder,http://www.zoneminder.com/downloads.html) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AM_CONFIG_HEADER(config.h) @@ -247,6 +247,7 @@ AC_FUNC_STRFTIME AC_FUNC_STRTOD AC_FUNC_VPRINTF AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap putenv select socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strsignal strspn strstr strtol strtoull]) +AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction]) # Other programs AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no) @@ -285,7 +286,11 @@ AC_CHECK_LIB(z,compress,,) # Checks for header files. AC_FUNC_ALLOCA AC_HEADER_STDC -AC_CHECK_HEADERS([fcntl.h limits.h memory.h netdb.h netinet/in.h stddef.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h values.h]) +AC_CHECK_HEADERS([fcntl.h limits.h memory.h stddef.h stdlib.h string.h strings.h sys/param.h sys/time.h syslog.h unistd.h values.h]) +AC_CHECK_HEADERS([netdb.h netinet/in.h arpa/inet.h sys/ioctl.h sys/socket.h sys/un.h glob.h]) +AC_CHECK_HEADERS(execinfo.h,,,) +AC_CHECK_HEADERS(syscall.h,,,) +AC_CHECK_HEADERS(pthread.h,,,) AC_CHECK_HEADERS(linux/videodev.h,AC_SUBST(ZM_HAS_V4L1,1),AC_SUBST(ZM_HAS_V4L1,0),) AC_CHECK_HEADERS(linux/videodev2.h,AC_SUBST(ZM_HAS_V4L2,1),AC_SUBST(ZM_HAS_V4L2,0),) if test "$ZM_HAS_V4L1" == "1" || test "$ZM_HAS_V4L2" == "1"; then diff --git a/db/Makefile.am b/db/Makefile.am index 1aa6a5a80..384fe7e47 100644 --- a/db/Makefile.am +++ b/db/Makefile.am @@ -40,4 +40,5 @@ EXTRA_DIST = \ zm_update-1.24.0.sql \ zm_update-1.24.1.sql \ zm_update-1.24.2.sql \ - zm_update-1.24.3.sql + zm_update-1.24.3.sql \ + zm_update-1.24.4.sql diff --git a/db/Makefile.in b/db/Makefile.in index 49ade5183..852fa211d 100644 --- a/db/Makefile.in +++ b/db/Makefile.in @@ -222,7 +222,8 @@ EXTRA_DIST = \ zm_update-1.24.0.sql \ zm_update-1.24.1.sql \ zm_update-1.24.2.sql \ - zm_update-1.24.3.sql + zm_update-1.24.3.sql \ + zm_update-1.24.4.sql all: all-am diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index d4bea8e79..d43bd19d6 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -259,6 +259,21 @@ CREATE TABLE `Groups` ( PRIMARY KEY (`Id`) ) ENGINE=@ZM_MYSQL_ENGINE@; +-- +-- Table structure for table `Logs` +-- +CREATE TABLE `Logs` ( + `TimeKey` decimal(16,6) NOT NULL, + `Component` varchar(32) NOT NULL, + `Pid` smallint(6) DEFAULT NULL, + `Level` tinyint(3) NOT NULL, + `Code` char(3) NOT NULL, + `Message` varchar(255) NOT NULL, + `File` varchar(255) DEFAULT NULL, + `Line` smallint(5) unsigned DEFAULT NULL, + KEY `TimeKey` (`TimeKey`) +) ENGINE=@ZM_MYSQL_ENGINE@; + -- -- Table structure for table `MonitorPresets` -- diff --git a/db/zm_update-1.24.4.sql b/db/zm_update-1.24.4.sql new file mode 100644 index 000000000..49253e5c0 --- /dev/null +++ b/db/zm_update-1.24.4.sql @@ -0,0 +1,30 @@ +-- +-- This updates a 1.24.4 database to the next version +-- + +-- +-- Create Logs table +-- TODO - defaults to MyISAM as not easy to import selected engine +-- + +CREATE TABLE `Logs` ( + `TimeKey` decimal(16,6) NOT NULL, + `Component` varchar(32) NOT NULL, + `Pid` smallint(6) DEFAULT NULL, + `Level` tinyint(3) NOT NULL, + `Code` char(3) NOT NULL, + `Message` varchar(255) NOT NULL, + `File` varchar(255) DEFAULT NULL, + `Line` smallint(5) unsigned DEFAULT NULL, + KEY `TimeKey` (`TimeKey`) +) ENGINE=MyISAM; + +-- +-- These are optional, but we might as well do it now +-- +optimize table Frames; +optimize table Events; +optimize table Filters; +optimize table Zones; +optimize table Monitors; +optimize table Stats; diff --git a/scripts/Makefile.am b/scripts/Makefile.am index a6241261d..bbdcb282e 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -44,7 +44,7 @@ EXTRA_DIST = \ ZoneMinder/lib/ZoneMinder.pm \ ZoneMinder/lib/ZoneMinder/Base.pm.in \ ZoneMinder/lib/ZoneMinder/Config.pm.in \ - ZoneMinder/lib/ZoneMinder/Debug.pm \ + ZoneMinder/lib/ZoneMinder/Logger.pm \ ZoneMinder/lib/ZoneMinder/General.pm \ ZoneMinder/lib/ZoneMinder/Database.pm \ ZoneMinder/lib/ZoneMinder/Memory.pm.in \ diff --git a/scripts/Makefile.in b/scripts/Makefile.in index a7a8a86cc..1200dd309 100644 --- a/scripts/Makefile.in +++ b/scripts/Makefile.in @@ -294,7 +294,7 @@ EXTRA_DIST = \ ZoneMinder/lib/ZoneMinder.pm \ ZoneMinder/lib/ZoneMinder/Base.pm.in \ ZoneMinder/lib/ZoneMinder/Config.pm.in \ - ZoneMinder/lib/ZoneMinder/Debug.pm \ + ZoneMinder/lib/ZoneMinder/Logger.pm \ ZoneMinder/lib/ZoneMinder/General.pm \ ZoneMinder/lib/ZoneMinder/Database.pm \ ZoneMinder/lib/ZoneMinder/Memory.pm.in \ diff --git a/scripts/ZoneMinder/Makefile.PL b/scripts/ZoneMinder/Makefile.PL index 8dff6af2d..c7a7434c8 100644 --- a/scripts/ZoneMinder/Makefile.PL +++ b/scripts/ZoneMinder/Makefile.PL @@ -10,9 +10,9 @@ WriteMakefile( 'lib/ZoneMinder.pm' => '$(INST_LIBDIR)/ZoneMinder.pm', 'lib/ZoneMinder/Base.pm' => '$(INST_LIBDIR)/ZoneMinder/Base.pm', 'lib/ZoneMinder/Config.pm' => '$(INST_LIBDIR)/ZoneMinder/Config.pm', - 'lib/ZoneMinder/Debug.pm' => '$(INST_LIBDIR)/ZoneMinder/Debug.pm', 'lib/ZoneMinder/General.pm' => '$(INST_LIBDIR)/ZoneMinder/General.pm', 'lib/ZoneMinder/Database.pm' => '$(INST_LIBDIR)/ZoneMinder/Database.pm', + 'lib/ZoneMinder/Logger.pm' => '$(INST_LIBDIR)/ZoneMinder/Logger.pm', 'lib/ZoneMinder/Memory.pm' => '$(INST_LIBDIR)/ZoneMinder/Memory.pm', 'lib/ZoneMinder/Memory/Shared.pm' => '$(INST_LIBDIR)/ZoneMinder/Memory/Shared.pm', 'lib/ZoneMinder/Memory/Mapped.pm' => '$(INST_LIBDIR)/ZoneMinder/Memory/Mapped.pm', diff --git a/scripts/ZoneMinder/lib/ZoneMinder.pm b/scripts/ZoneMinder/lib/ZoneMinder.pm index 238cbcb58..41c972650 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder.pm @@ -31,12 +31,12 @@ use warnings; require Exporter; use ZoneMinder::Base qw(:all); use ZoneMinder::Config qw(:all); -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::General qw(:all); use ZoneMinder::Database qw(:all); use ZoneMinder::Memory qw(:all); -our @ISA = qw(Exporter ZoneMinder::Base ZoneMinder::Config ZoneMinder::Debug ZoneMinder::General ZoneMinder::Database ZoneMinder::Memory); +our @ISA = qw(Exporter ZoneMinder::Base ZoneMinder::Config ZoneMinder::Logger ZoneMinder::General ZoneMinder::Database ZoneMinder::Memory); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. @@ -53,7 +53,7 @@ our %EXPORT_TAGS = ( @ZoneMinder::Config::EXPORT_OK ], 'debug' => [ - @ZoneMinder::Debug::EXPORT_OK + @ZoneMinder::Logger::EXPORT_OK ], 'general' => [ @ZoneMinder::General::EXPORT_OK @@ -87,7 +87,7 @@ ZoneMinder - Container module for common ZoneMinder modules =head1 DESCRIPTION This module is a convenience container module that uses the -ZoneMinder::Base, ZoneMinder::Common, ZoneMinder::Debug, +ZoneMinder::Base, ZoneMinder::Common, ZoneMinder::Logger, ZoneMinder::Database and ZoneMinder::Memory modules. It also exports by default all symbols provided by the 'all' tag of each of the modules. @@ -96,7 +96,7 @@ Thus 'use'ing this module is equivalent to the following use ZoneMinder::Base qw(:all); use ZoneMinder::Config qw(:all); - use ZoneMinder::Debug qw(:all); + use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); use ZoneMinder::Memory qw(:all); @@ -109,7 +109,7 @@ modules. =head1 SEE ALSO -ZoneMinder::Base, ZoneMinder::Common, ZoneMinder::Debug, +ZoneMinder::Base, ZoneMinder::Common, ZoneMinder::Logger, ZoneMinder::Database, ZoneMinder::Memory http://www.zoneminder.com diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 562fa0ad4..6126265a4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -458,13 +458,144 @@ our @options = type => $types{string}, category => "images", }, + { + name => "ZM_LOG_LEVEL_SYSLOG", + default => "0", + description => "Save logging output to the system log", + help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output that goes to the system log. ZoneMinder binaries have always logged to the system log but now scripts and web logging is also included. To preserve the previous behaviour you should ensure this value is set to Info or Warning. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance. If you want debug you will also need to set a level and component below", + type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, + category => "logging", + }, + { + name => "ZM_LOG_LEVEL_FILE", + default => "-5", + description => "Save logging output to component files", + help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output that goes to individual log files written by specific components. This is how logging worked previously and although useful for tracking down issues in specific components it also resulted in many disparate log files. To preserve this behaviour you should ensure this value is set to Info or Warning. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance though file output has less impact than the other options. If you want debug you will also need to set a level and component below", + type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, + category => "logging", + }, + { + name => "ZM_LOG_LEVEL_WEBLOG", + default => "-5", + description => "Save logging output to the weblog", + help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output from the web interface that goes to the httpd error log. Note that only web logging from PHP and JavaScript files is included and so this option is really only useful for investigating specific issues with those components. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance. If you want debug you will also need to set a level and component below", + type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, + category => "logging", + }, + { + name => "ZM_LOG_LEVEL_DATABASE", + default => "0", + description => "Save logging output to the database", + help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output that is written to the database. This is a new option which can make viewing logging output easier and more intuitive and also makes it easier to get an overall impression of how the system is performing. If you have a large or very busy system then it is possible that use of this option may slow your system down if the table becomes very large. Ensure you use the LOG_DATABASE_LIMIT option to keep the table to a manageable size. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance. If you want debug you will also need to set a level and component below", + type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, + category => "logging", + }, + { + name => "ZM_LOG_DATABASE_LIMIT", + default => "7 day", + description => "Maximum number of log entries to retain", + help => "If you are using database logging then it is possible to quickly build up a large number of entries in the Logs table. This option allows you to specify how many of these entries are kept. If you set this option to a number greater than zero then that number is used to determine the maximum number of rows, less than or equal to zero indicates no limit and is not recommended. You can also set this value to time values such as ' day' which will limit the log entries to those newer than that time. You can specify 'hour', 'day', 'week', 'month' and 'year', note that the values should be singular (no 's' at the end). The Logs table is pruned periodically so it is possible for more than the expected number of rows to be present briefly in the meantime.", + type => $types{string}, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG", + default => "no", + description => "Switch debugging on", + help => "ZoneMinder components usually support debug logging available to help with diagnosing problems. Binary components have several levels of debug whereas more other components have only one. Normally this is disabled to minimise performance penalties and avoid filling logs too quickly. This option lets you switch on other options that allow you to configure additional debug information to be output. Components will pick up this instruction when they are restarted.", + type => $types{boolean}, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG_TARGET", + default => "", + description => "What components should have extra debug enabled", + help => "There are three scopes of debug available. Leaving this option blank means that all components will use extra debug (not recommended). Setting this option to '_', e.g. _zmc, will limit extra debug to that component only. Setting this option to '__', e.g. '_zmc_m1' will limit extra debug to that instance of the component only. This is ordinarily what you probably want to do. To debug scripts use their names without the .pl extension, e.g. '_zmvideo' and to debug issues with the web interface use '_web'. You can specify multiple targets by separating them with '|' characters.", + requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], + type => $types{string}, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG_LEVEL", + default => 1, + description => "What level of extra debug should be enabled", + help => "There are 9 levels of debug available, with higher numbers being more debug and level 0 being no debug. However not all levels are used by all components. Also if there is debug at a high level it is usually likely to be output at such a volume that it may obstruct normal operation. For this reason you should set the level carefully and cautiously until the degree of debug you wish to see is present. Scripts and the web interface only have one level so this is an on/off type option for them.", + requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], + type => { db_type=>"integer", hint=>"1|2|3|4|5|6|7|8|9", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG_FILE", + default => "@ZM_TMPDIR@/zm_debug.log+", + description => "Where extra debug is output to", + help => "This option allows you to specify a different target for debug output. All components have a default log file which will norally be in /tmp or /var/log and this is where debug will be written to if this value is empty. Adding a path here will temporarily redirect debug, and other logging output, to this file. This option is a simple filename and you are debugging several components then they will all try and write to the same file with undesirable consequences. Appending a '+' to the filename will cause the file to be created with a '.' suffix containing your process id. In this way debug from each run of a component is kept separate. This is the recommended setting as it will also prevent subsequent runs from overwriting the same log. You should ensure that permissions are set up to allow writing to the file and directory specified here.", + requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], + type => $types{string}, + category => "logging", + }, + { + name => "ZM_LOG_CHECK_PERIOD", + default => "900", + description => "Time period used when calculating overall system health", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to indicate what period of historical events are used in this calculation. This value is expressed in seconds and is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALERT_WAR_COUNT", + default => "1", + description => "Number of warnings indicating system alert state", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many warnings must have occurred within the defined time period to generate an overall system alert state. A value of zero means warnings are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALERT_ERR_COUNT", + default => "1", + description => "Number of errors indicating system alert state", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many errors must have occurred within the defined time period to generate an overall system alert state. A value of zero means errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALERT_FAT_COUNT", + default => "0", + description => "Number of fatal error indicating system alert state", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many fatal errors (including panics) must have occurred within the defined time period to generate an overall system alert state. A value of zero means fatal errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALARM_WAR_COUNT", + default => "100", + description => "Number of warnings indicating system alarm state", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many warnings must have occurred within the defined time period to generate an overall system alarm state. A value of zero means warnings are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALARM_ERR_COUNT", + default => "10", + description => "Number of errors indicating system alarm state", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many errors must have occurred within the defined time period to generate an overall system alarm state. A value of zero means errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALARM_FAT_COUNT", + default => "1", + description => "Number of fatal error indicating system alarm state", + help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many fatal errors (including panics) must have occurred within the defined time period to generate an overall system alarm state. A value of zero means fatal errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", + type => $types{integer}, + category => "logging", + }, { name => "ZM_RECORD_EVENT_STATS", default => "yes", description => "Record event statistical information, switch off if too slow", help => "This version of ZoneMinder records detailed information about events in the Stats table. This can help in profiling what the optimum settings are for Zones though this is tricky at present. However in future releases this will be done more easily and intuitively, especially with a large sample of events. The default option of 'yes' allows this information to be collected now in readiness for this but if you are concerned about performance you can switch this off in which case no Stats information will be saved.", type => $types{boolean}, - category => "debug", + category => "logging", }, { name => "ZM_RECORD_DIAG_IMAGES", @@ -472,42 +603,7 @@ our @options = description => "Record intermediate alarm diagnostic images, can be very slow", help => "In addition to recording event statistics you can also record the intermediate diagnostic images that display the results of the various checks and processing that occur when trying to determine if an alarm event has taken place. There are several of these images generated for each frame and zone for each alarm or alert frame so this can have a massive impact on performance. Only switch this setting on for debug or analysis purposes and remember to switch it off again once no longer required.", type => $types{boolean}, - category => "debug", - }, - { - name => "ZM_EXTRA_DEBUG", - default => "no", - description => "Switch additional debugging on", - help => "ZoneMinder binary components usually have several levels of debug information they can output. Normally this is set to a fairly low level to avoid filling logs too quickly. This options lets you switch on other options that allow you to configure additional debug information to be output. Components will pick up this instruction when they are restarted.", - type => $types{boolean}, - category => "debug", - }, - { - name => "ZM_EXTRA_DEBUG_TARGET", - default => "", - description => "What components should have extra debug enabled", - help => "There are three scopes of debug available. Leaving this option blank means that all components will use extra debug (not recommended). Setting this option to '_', e.g. _zmc, will limit extra debug to that component only. Setting this option to '__', e.g. '_zmc_m1' will limit extra debug to that instance of the component only. This is ordinarily what you probably want to do.", - requires => [ { name => "ZM_EXTRA_DEBUG", value => "yes" } ], - type => $types{string}, - category => "debug", - }, - { - name => "ZM_EXTRA_DEBUG_LEVEL", - default => 0, - description => "What level of extra debug should be enabled", - help => "There are 9 levels of debug available, with higher numbers being more debug and level 0 being no debug. However not all levels are used by all components. Also if there is debug at a high level it is usually likely to be output at such a volume that it may obstruct normal operation. For this reason you should set the level carefully and cautiously until the degree of debug you wish to see is present.", - requires => [ { name => "ZM_EXTRA_DEBUG", value => "yes" } ], - type => { db_type=>"integer", hint=>"0|1|2|3|4|5|6|7|8|9", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "debug", - }, - { - name => "ZM_EXTRA_DEBUG_LOG", - default => "@ZM_TMPDIR@/zm_debug.log+", - description => "Where extra debug is output to", - help => "Depending on your system configuration you may find that only errors, warning and informational messages are logged to your system log. This option allows you to specify an additional target for these messages and debug. This also has the advantage of partitioning debug for the component you are tracing, from messages from other components. Be warned however that if this is a simple filename and you are debugging several components then they will all try and write to the same file with undesirable consequences. Appending a '+' to the filename will cause the file to be created with a '.' suffix containing your process id. In this way debug from each run of a component is kept separate. This is the recommended setting as it will also prevent subsequent runs from overwriting the same log.", - requires => [ { name => "ZM_EXTRA_DEBUG", value => "yes" } ], - type => $types{string}, - category => "debug", + category => "logging", }, { name => "ZM_DUMP_CORES", @@ -515,7 +611,7 @@ our @options = description => "Create core files on unexpected process failure.", help => "When an unrecoverable error occurs in a ZoneMinder binary process is has traditionally been trapped and the details written to logs to aid in remote analysis. However in some cases it is easier to diagnose the error if a core file, which is a memory dump of the process at the time of the error, is created. This can be interactively analysed in the debugger and may reveal more or better information than that available from the logs. This option is recommended for advanced users only otherwise leave at the default. Note using this option to trigger core files will mean that there will be no indication in the binary logs that a process has died, they will just stop, however the zmdc log will still contain an entry. Also note that you may have to explicitly enable core file creation on your system via the 'ulimit -c' command or other means otherwise no file will be created regardless of the value of this option.", type => $types{boolean}, - category => "debug", + category => "logging", }, { name => "ZM_PATH_MAP", diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index c9ccc44ec..2a646772d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -38,7 +38,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); our $AUTOLOAD; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm index b3dec575a..e5a5882b9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm index ea3684f3d..358aecb2b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm index 08736d3b5..643765e9f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm index 50473ce88..6c507bd1a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Time::HiRes qw( usleep ); @@ -102,7 +102,7 @@ sub close sub printMsg { - if ( zmDbgLevel() > 0 ) + if ( logDebugging() ) { my $self = shift; my $msg = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm index 66a11970a..c743f2b51 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Time::HiRes qw( usleep ); @@ -103,7 +103,7 @@ sub close sub printMsg { - if ( zmDbgLevel() > 0 ) + if ( logDebugging() ) { my $self = shift; my $msg = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm index 217ae3898..37f30dc09 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Time::HiRes qw( usleep ); @@ -103,7 +103,7 @@ sub close sub printMsg { - if ( zmDbgLevel() > 0 ) + if ( logDebugging() ) { my $self = shift; my $msg = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm index 53bdc1f13..c10a2e3fc 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 09c6e8445..d0bae5dde 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -63,7 +63,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); use Carp; @@ -89,6 +89,7 @@ sub zmDbConnect( ;$ ) { $dbh = DBI->connect( "DBI:mysql:database=".ZM_DB_NAME.";host=".ZM_DB_HOST, ZM_DB_USER, ZM_DB_PASS ); } + $dbh->trace( 0 ); } return( $dbh ); } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Debug.pm b/scripts/ZoneMinder/lib/ZoneMinder/Debug.pm deleted file mode 100644 index 0c1ddb016..000000000 --- a/scripts/ZoneMinder/lib/ZoneMinder/Debug.pm +++ /dev/null @@ -1,474 +0,0 @@ -# ========================================================================== -# -# ZoneMinder Debug Module, $Date$, $Revision$ -# Copyright (C) 2001-2008 Philip Coombes -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ========================================================================== -# -# This module contains the debug definitions and functions used by the rest -# of the ZoneMinder scripts -# -package ZoneMinder::Debug; - -use 5.006; -use strict; -use warnings; - -require Exporter; -require ZoneMinder::Base; - -our @ISA = qw(Exporter ZoneMinder::Base); - -# Items to export into callers namespace by default. Note: do not export -# names by default without a very good reason. Use EXPORT_OK instead. -# Do not simply export all your public functions/methods/constants. - -# This allows declaration use ZoneMinder ':all'; -# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK -# will save memory. -our %EXPORT_TAGS = ( - 'constants' => [ qw( - DBG_DEBUG - DBG_INFO - DBG_WARNING - DBG_ERROR - DBG_FATAL - DBG_NOSYSLOG - ) ], - 'functions' => [ qw( - zmDbgInit - zmDbgTerm - zmDbgReinit - zmDbgSetSignal - zmDbgClearSignal - zmDbgId - zmDbgLevel - zmDbgCarp - zmDbgDebugOn - Debug - Info - Warning - Error - Fatal - Panic - ) ] -); -push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; - -our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); - -our @EXPORT = qw(); - -our $VERSION = $ZoneMinder::Base::VERSION; - -# ========================================================================== -# -# Debug Facilities -# -# ========================================================================== - -use ZoneMinder::Config qw(:all); - -use Carp; -use POSIX; -use IO::Handle; -use Time::HiRes qw/gettimeofday/; -use Sys::Syslog qw(:DEFAULT setlogsock); - -use constant DBG_DEBUG => 1; -use constant DBG_INFO => 0; -use constant DBG_WARNING => -1; -use constant DBG_ERROR => -2; -use constant DBG_FATAL => -3; -use constant DBG_NOSYSLOG => -4; - -our $dbg_initialised = undef; -our $dbg_id = "zmundef"; -our $dbg_level = DBG_INFO; -our $dbg_carp = 0; -our $dbg_to_log = 1; -our $dbg_to_term = 0; -our $dbg_to_syslog = DBG_INFO; - -our $dbg_log_file = ""; - -our $_dbg_has_term = 0; - -our %dbg_codes = ( - 1 => "DBG", - 0 => "INF", - -1 => "WAR", - -2 => "ERR", - -3 => "FAT", -); - -our %dbg_priorities = ( - 1 => "debug", - 0 => "info", - -1 => "warning", - -2 => "err", - -3 => "err", -); - -sub zmDbgInit -{ - my $id = shift; - my %options = @_; - - if ( $dbg_initialised ) - { - _dbgCloseLog(); - _dbgCloseSyslog(); - } - - $dbg_id = $id if ( $id ); - $dbg_level = $options{level} if ( defined($options{level}) ); - $dbg_level = $options{carp} if ( defined($options{carp}) ); - $dbg_to_log = $options{to_log} if ( defined($options{to_log}) ); - $dbg_to_term = $options{to_term} if ( defined($options{to_term}) ); - $dbg_to_syslog = $options{to_syslog} if ( defined($options{to_syslog}) ); - - _dbgOpenSyslog(); - _dbgOpenLog(); - - $_dbg_has_term = -t STDERR; - $dbg_initialised = !undef; -} - -sub zmDbgTerm -{ - if ( $dbg_initialised ) - { - _dbgCloseLog(); - _dbgCloseSyslog(); - } - $dbg_initialised = undef; -} - -sub zmDbgReinit -{ - my $saved_errno = $!; - if ( $dbg_initialised ) - { - _dbgCloseLog(); - #_dbgCloseSyslog(); - - #_dbgOpenSyslog(); - _dbgOpenLog(); - } - zmDbgSetSignal(); - $! = $saved_errno; -} - -sub zmDbgSetSignal -{ - $SIG{HUP} = \&zmDbgReinit; -} - -sub zmDbgClearSignal -{ - $SIG{HUP} = 'DEFAULT'; -} - -sub zmDbgId -{ - $dbg_id = $_[0] if ( @_ ); - return( $dbg_id ); -} - -sub zmDbgLevel -{ - $dbg_level = $_[0] if ( @_ ); - return( $dbg_level ); -} - -sub zmDbgCarp -{ - $dbg_carp = $_[0] if ( @_ ); - return( $dbg_carp ); -} - -sub zmDbgToTerm -{ - $dbg_to_term = $_[0] if ( @_ ); - return( $dbg_to_term ); -} - -sub zmDbgToLog -{ - if ( @_ ) - { - if ( $dbg_to_log != $_[0] ) - { - _dbgCloseLog(); - $dbg_to_log = $_[0]; - _dbgOpenLog(); - } - } - return( $dbg_to_log ); -} - -sub zmDbgToSyslog -{ - if ( @_ ) - { - if ( $dbg_to_syslog != $_[0] ) - { - _dbgCloseSyslog(); - $dbg_to_syslog = $_[0]; - _dbgOpenSyslog(); - } - } - return( $dbg_to_syslog ); -} - -sub zmDbgDebugOk -{ - return ( $dbg_level >= DBG_DEBUG ); -} - -sub _dbgOpenSyslog -{ - if ( $dbg_to_syslog > DBG_NOSYSLOG ) - { - #setlogsock( "stream", "/tmp/xxx.log" ); - openlog( $dbg_id, "pid,ndelay", "local1" ) - } -} - -sub _dbgCloseSyslog -{ - if ( $dbg_to_syslog > DBG_NOSYSLOG ) - { - closelog(); - } -} - -sub _dbgOpenLog -{ - if ( $dbg_to_log ) - { - $dbg_log_file = ZM_PATH_LOGS."/".$dbg_id.".log"; - if ( open( LOG, ">>".$dbg_log_file ) ) - { - LOG->autoflush(); - - my $web_uid = (getpwnam( ZM_WEB_USER ))[2]; - my $web_gid = (getgrnam( ZM_WEB_GROUP ))[2]; - if ( $> == 0 ) - { - chown( $web_uid, $web_gid, $dbg_log_file ) or croak( "Can't change permissions on log file: $!" ) - } - } - else - { - warn( "Can't open log file '$dbg_log_file': $!" ); - $dbg_to_log = 0; - } - } -} - -sub _dbgCloseLog -{ - if ( $dbg_to_log ) - { - close( LOG ); - } -} - -sub _dbgPrint -{ - my $level = shift; - my $string = shift; - my $carp = shift; - - if ( $level <= $dbg_level ) - { - if ( !$dbg_initialised ) - { - zmDbgInit( $dbg_id ); - } - - $string =~ s/[\r\n]+$//g; - - my $code = $dbg_codes{$level}; - - my ($seconds, $microseconds) = gettimeofday(); - my $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", localtime( $seconds ) ), $microseconds, $dbg_id, $$, $code, $string ); - if ( $dbg_carp || $carp ) - { - $message = Carp::shortmess( $message ); - } - else - { - $message = $message."\n"; - } - print( STDERR $message ) if ( $dbg_to_term == 1 || ($dbg_to_term == 2 && $_dbg_has_term) ); - print( LOG $message ) if ( $dbg_to_log ); - syslog( $dbg_priorities{$level}, $code." [%s]", $string ) if ( $level <= $dbg_to_syslog ); - } -} - -sub Debug -{ - _dbgPrint( DBG_DEBUG, @_ ); -} - -sub Info -{ - _dbgPrint( DBG_INFO, @_ ); -} - -sub Warning -{ - _dbgPrint( DBG_WARNING, @_ ); -} - -sub Error -{ - _dbgPrint( DBG_ERROR, @_ ); -} - -sub Fatal -{ - _dbgPrint( DBG_FATAL, @_ ); - confess( $_[0] ); -} - -sub Panic -{ - Fatal( @_ ); -} - -1; -__END__ - -=head1 NAME - -ZoneMinder::Debug - ZoneMinder Debug module - -=head1 SYNOPSIS - - use ZoneMinder::Debug; - use ZoneMinder::Debug qw(:all); - - zmDbgInit( "myproc", DBG_DEBUG ); - - Debug( "This is what is happening" ); - Info( "Something interesting is happening" ); - Warning( "Something might be going wrong." ); - Error( "Something has gone wrong!!" ); - Fatal( "Something has gone badly wrong, gotta stop!!" ); - -=head1 DESCRIPTION - -The ZoneMinder:Debug module contains the common debug and error reporting routines used by the ZoneMinder scripts. - -To use debug in your scripts you need to include this module, and call zmDbgInit. Thereafter you can sprinkle Debug or Error calls etc throughout the code safe in the knowledge that they will be reported to your error log, and possibly the syslogger, in a meaningful and consistent format. - -Debug is discussed in terms of levels where 1 and above (currently only 1 for scripts) is considered debug, 0 is considered as informational, -1 is a warning, -2 is an error and -3 is a fatal error or panic. Where levels are mentioned below as thresholds the value given and anything with a lower level (ie. more serious) will be included. - -=head1 METHODS - -=over 4 - -=item zmDbgInit ( $id, %options ); - -Initialises the debug and prepares the logging for forthcoming operations. If not called explicitly it will be called by the first debug call in your script, but with default (and probably meaningless) options. The only compulsory arguments are $id which must be a string that will identify debug coming from this script in mixed logs. Other options may be provided as below, - - Option Default Description - --------- --------- ----------- - level DBG_INFO The initial debug level which defines which statements are output and which are ignored - carp 0 Whether to use the Carp::shortmess format in debug statements to identify where the debug was emitted from - to_log 1 Whether to write debug to a log file of the format of .log in the standard log directory - to_term 0 Whether to write debug to terminal standard error, 0 is no, 1 is yes, 2 is write only if terminal - to_syslog DBG_INFO At what level debug is written to syslog. To disable entirely set this to DBG_NOSYSLOG - -=item zmDbgTerm (); - -Used to end the debug session and close any logs etc. Not usually necessary. - -=item $id = zmDbgId ( [$id] ); - -=item $level = zmDbgLevel ( [$level] ); - -=item $carp = zmDbgId ( [$carp] ); - -=item $to_log = zmDbgToLog ( [$to_log] ); - -=item $to_term = zmDbgToTerm ( [$to_term] ); - -=item $to_syslog = zmDbgToSyslog ( [$to_syslog] ); - -These methods can be used to get and set the current settings as defined in zmDbgInit. - -=item Debug( $string ); - -This method will output a debug message if the current debug level permits it, otherwise does nothing. This message will be tagged with the DBG string in the logs. - -=item Info( $string ); - -This method will output an informational message if the current debug level permits it, otherwise does nothing. This message will be tagged with the INF string in the logs. - -=item Warning( $string ); - -This method will output a warning message if the current debug level permits it, otherwise does nothing. This message will be tagged with the WAR string in the logs. - -=item Error( $string ); - -This method will output an error message if the current debug level permits it, otherwise does nothing. This message will be tagged with the ERR string in the logs. - -=item Fatal( $string ); - -This method will output a fatal error message and then die if the current debug level permits it, otherwise does nothing. This message will be tagged with the FAT string in the logs. - -=item Panic( $string ); - -Synonym for Fatal. - -=head2 EXPORT - -None by default. -The :constants tag will export the debug constants which define the various levels of debug -The :variables tag will export variables containing the current debug id and level -The :functions tag will export the debug functions. This or :all is what you would normally use. -The :all tag will export all above symbols. - - -=head1 SEE ALSO - -Carp -Sys::Syslog - -The ZoneMinder README file Troubleshooting section for an extended discussion on the use and configuration of syslog with ZoneMinder. - -http://www.zoneminder.com - -=head1 AUTHOR - -Philip Coombes, Ephilip.coombes@zoneminder.comE - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2001-2008 Philip Coombes - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself, either Perl version 5.8.3 or, -at your option, any later version of Perl 5 you may have available. - - -=cut diff --git a/scripts/ZoneMinder/lib/ZoneMinder/General.pm b/scripts/ZoneMinder/lib/ZoneMinder/General.pm index 62c5cca44..f05086237 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/General.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/General.pm @@ -67,7 +67,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # ========================================================================== use ZoneMinder::Config qw(:all); -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use POSIX; @@ -77,7 +77,7 @@ sub executeShellCommand( $ ) my $command = shift; my $output = qx( $command ); my $status = $? >> 8; - if ( $status || zmDbgLevel() > 0 ) + if ( $status || logDebugging() ) { Debug( "Command: $command\n" ); chomp( $output ); @@ -177,7 +177,7 @@ sub runCommand( $ ) my $output = qx($command); my $status = $? >> 8; chomp( $output ); - if ( $status || zmDbgLevel() > 0 ) + if ( $status || logDebugging() ) { if ( $status ) { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm new file mode 100644 index 000000000..9fb1b44cf --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -0,0 +1,852 @@ +# ========================================================================== +# +# ZoneMinder Logger Module, $Date$, $Revision$ +# Copyright (C) 2001-2008 Philip Coombes +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ========================================================================== +# +# This module contains the debug definitions and functions used by the rest +# of the ZoneMinder scripts +# +package ZoneMinder::Logger; + +use 5.006; +use strict; +use warnings; + +require Exporter; +require ZoneMinder::Base; + +our @ISA = qw(Exporter ZoneMinder::Base); + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# This allows declaration use ZoneMinder ':all'; +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK +# will save memory. +our %EXPORT_TAGS = ( + 'constants' => [ qw( + DEBUG + INFO + WARNING + ERROR + FATAL + PANIC + NOLOG + ) ], + 'functions' => [ qw( + logInit + logReinit + logTerm + logSetSignal + logClearSignal + logDebugging + logLevel + logTermLevel + logDatabaseLevel + logFileLevel + logSyslogLevel + Mark + Dump + Debug + Info + Warning + Error + Fatal + Panic + ) ] +); +push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; + +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +our @EXPORT = qw(); + +our $VERSION = $ZoneMinder::Base::VERSION; + +# ========================================================================== +# +# Logger Facilities +# +# ========================================================================== + +use ZoneMinder::Config qw(:all); + +use DBI; +use Carp; +use POSIX; +use IO::Handle; +use Data::Dumper; +use Time::HiRes qw/gettimeofday/; +use Sys::Syslog; + +use constant { + DEBUG => 1, + INFO => 0, + WARNING => -1, + ERROR => -2, + FATAL => -3, + PANIC => -4, + NOLOG => -5 +}; + +our %codes = ( + &DEBUG => "DBG", + &INFO => "INF", + &WARNING => "WAR", + &ERROR => "ERR", + &FATAL => "FAT", + &PANIC => "PNC", + &NOLOG => "OFF" +); + +our %priorities = ( + &DEBUG => "debug", + &INFO => "info", + &WARNING => "warning", + &ERROR => "err", + &FATAL => "err", + &PANIC => "err" +); + +our $logger; + +sub new +{ + my $class = shift; + my $this = {}; + + $this->{initialised} = undef; + + #$this->{id} = "zmundef"; + ( $this->{id} ) = $0 =~ m|^(?:.*/)?([^/]+?)(?:\.[^/.]+)?$|; + $this->{idRoot} = $this->{id}; + $this->{idArgs} = ""; + + $this->{level} = INFO; + $this->{termLevel} = NOLOG; + $this->{databaseLevel} = NOLOG; + $this->{fileLevel} = NOLOG; + $this->{syslogLevel} = NOLOG; + $this->{effectiveLevel} = INFO; + + $this->{autoFlush} = 1; + $this->{hasTerm} = -t STDERR; + + ( $this->{fileName} = $0 ) =~ s|^.*/||; + $this->{logPath} = ZM_PATH_LOGS; + $this->{logFile} = $this->{logPath}."/".$this->{id}.".log"; + + $this->{trace} = 0; + + bless( $this, $class ); + return $this; +} + +sub BEGIN +{ + # Fake the config variables that are used in case they are not defined yet + # Only really necessary to support upgrade from previous version + if ( !eval('defined(ZM_LOG_DEBUG)') ) + { + no strict 'subs'; + no strict 'refs'; + my %dbgConfig = ( + ZM_LOG_LEVEL_DATABASE => 0, + ZM_LOG_LEVEL_FILE => 0, + ZM_LOG_LEVEL_SYSLOG => 0, + ZM_LOG_DEBUG => 0, + ZM_LOG_DEBUG_TARGET => "", + ZM_LOG_DEBUG_LEVEL => 1, + ZM_LOG_DEBUG_FILE => "" + ); + while ( my ( $name, $value ) = each( %dbgConfig ) ) + { + *{$name} = sub { $value }; + } + use strict 'subs'; + use strict 'refs'; + } +} + +sub DESTROY +{ + my $this = shift; + $this->terminate(); +} + +sub initialise( @ ) +{ + my $this = shift; + my %options = @_; + + $this->{id} = $options{id} if ( defined($options{id}) ); + + $this->{logPath} = $options{logPath} if ( defined($options{logPath}) ); + + my $tempLogFile; + $tempLogFile = $this->{logPath}."/".$this->{id}.".log"; + $tempLogFile = $options{logFile} if ( defined($options{logFile}) ); + if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) + { + $tempLogFile = $logFile; + } + + my $tempLevel = INFO; + my $tempTermLevel = $this->{termLevel}; + my $tempDatabaseLevel = $this->{databaseLevel}; + my $tempFileLevel = $this->{fileLevel}; + my $tempSyslogLevel = $this->{syslogLevel}; + + $tempTermLevel = $options{termLevel} if ( defined($options{termLevel}) ); + if ( defined($options{databaseLevel}) ) + { + $tempDatabaseLevel = $options{databaseLevel}; + } + else + { + $tempDatabaseLevel = ZM_LOG_LEVEL_DATABASE; + } + if ( defined($options{fileLevel}) ) + { + $tempFileLevel = $options{fileLevel}; + } + else + { + $tempFileLevel = ZM_LOG_LEVEL_FILE; + } + if ( defined($options{syslogLevel}) ) + { + $tempSyslogLevel = $options{syslogLevel}; + } + else + { + $tempSyslogLevel = ZM_LOG_LEVEL_SYSLOG; + } + + if ( defined($ENV{'LOG_PRINT'}) ) + { + $tempTermLevel = $ENV{'LOG_PRINT'}? DEBUG : NOLOG; + } + + my $level; + $tempLevel = $level if ( $level = $this->getTargettedEnv('LOG_LEVEL') ); + + $tempTermLevel = $level if ( $level = $this->getTargettedEnv('LOG_LEVEL_TERM') ); + $tempDatabaseLevel = $level if ( $level = $this->getTargettedEnv('LOG_LEVEL_DATABASE') ); + $tempFileLevel = $level if ( $level = $this->getTargettedEnv('LOG_LEVEL_FILE') ); + $tempSyslogLevel = $level if ( $level = $this->getTargettedEnv('LOG_LEVEL_SYSLOG') ); + + if ( ZM_LOG_DEBUG ) + { + foreach my $target ( split( /\|/, ZM_LOG_DEBUG_TARGET ) ) + { + if ( $target eq $this->{id} || $target eq "_".$this->{id} || $target eq $this->{idRoot} || $target eq "_".$this->{idRoot} || $target eq "" ) + { + if ( ZM_LOG_DEBUG_LEVEL > NOLOG ) + { + $tempLevel = $this->limit( ZM_LOG_DEBUG_LEVEL ); + if ( ZM_LOG_DEBUG_FILE ne "" ) + { + $tempLogFile = ZM_LOG_DEBUG_FILE; + $tempFileLevel = $tempLevel; + } + } + } + } + } + + $this->logFile( $tempLogFile ); + + $this->termLevel( $tempTermLevel ); + $this->databaseLevel( $tempDatabaseLevel ); + $this->fileLevel( $tempFileLevel ); + $this->syslogLevel( $tempSyslogLevel ); + + $this->level( $tempLevel ); + + $this->{trace} = $options{trace} if ( defined($options{trace}) ); + + $this->{autoFlush} = $ENV{'LOG_FLUSH'}?1:0 if ( defined($ENV{'LOG_FLUSH'}) ); + + $this->{initialised} = !undef; + + Debug( "LogOpts: level=".$codes{$this->{level}}."/".$codes{$this->{effectiveLevel}}.", screen=".$codes{$this->{termLevel}}.", database=".$codes{$this->{databaseLevel}}.", logfile=".$codes{$this->{fileLevel}}."->".$this->{logFile}.", syslog=".$codes{$this->{syslogLevel}} ); +} + +sub terminate() +{ + my $this = shift; + return unless ( $this->{initialised} ); + $this->syslogLevel( NOLOG ); + $this->fileLevel( NOLOG ); + $this->databaseLevel( NOLOG ); + $this->termLevel( NOLOG ); +} + +sub reinitialise() +{ + my $this = shift; + + return unless ( $this->{initialised} ); + + # Bit of a nasty hack to reopen connections to log files and the DB + my $syslogLevel = $this->syslogLevel(); + $this->syslogLevel( NOLOG ); + my $logfileLevel = $this->fileLevel(); + $this->fileLevel( NOLOG ); + my $databaseLevel = $this->databaseLevel(); + $this->databaseLevel( NOLOG ); + my $screenLevel = $this->termLevel(); + $this->termLevel( NOLOG ); + + $this->syslogLevel( $syslogLevel ) if ( $syslogLevel > NOLOG ); + $this->fileLevel( $logfileLevel ) if ( $logfileLevel > NOLOG ); + $this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG ); + $this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG ); +} + +sub limit( $ ) +{ + my $this = shift; + my $level = shift; + return( DEBUG ) if ( $level > DEBUG ); + return( NOLOG ) if ( $level < NOLOG ); + return( $level ); +} + +sub getTargettedEnv( $ ) +{ + my $this = shift; + my $name = shift; + my $envName = $name."_".$this->{id}; + my $value = $ENV{$envName} if ( defined($ENV{$envName}) ); + if ( !defined($value) && $this->{id} ne $this->{idRoot} ) + { + $envName = $name."_".$this->{idRoot}; + $value = $ENV{$envName} if ( defined($ENV{$envName}) ); + } + if ( !defined($value) ) + { + $value = $ENV{$name} if ( defined($ENV{$name}) ); + } + return( $value ); +} + +sub fetch() +{ + if ( !$logger ) + { + $logger = ZoneMinder::Logger->new(); + $logger->initialise( undef, 'syslogLevel'=>INFO, 'fileLevel'=>INFO ); + } + return( $logger ); +} + +sub id( ;$ ) +{ + my $this = shift; + my $id = shift; + if ( defined($id) && $this->{id} ne $id ) + { + # Remove whitespace + $id =~ s/\S//g; + # Replace non-alphanum with underscore + $id =~ s/[^a-zA-Z_]/_/g; + + if ( $this->{id} ne $id ) + { + $this->{id} = $this->{idRoot} = $id; + if ( $id =~ /^([^_]+)_(.+)$/ ) + { + $this->{idRoot} = $1; + $this->{idArgs} = $2; + } + } + } + return( $this->{id} ); +} + +sub level( ;$ ) +{ + my $this = shift; + my $level = shift; + if ( defined($level) ) + { + $this->{level} = $this->limit( $level ); + $this->{effectiveLevel} = NOLOG; + $this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} ); + $this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} ); + $this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} ); + $this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{level} ); + $this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{level} ); + } + return( $this->{level} ); +} + +sub debugOn() +{ + my $this = shift; + return( $this->{effectiveLevel} >= DEBUG ); +} + +sub trace( ;$ ) +{ + my $this = shift; + $this->{trace} = $_[0] if ( @_ ); + return( $this->{trace} ); +} + +sub termLevel( ;$ ) +{ + my $this = shift; + my $termLevel = shift; + if ( defined($termLevel) ) + { + $termLevel = NOLOG if ( !$this->{hasTerm} ); + $termLevel = $this->limit( $termLevel ); + if ( $this->{termLevel} != $termLevel ) + { + $this->{termLevel} = $termLevel; + } + } + return( $this->{termLevel} ); +} + +sub databaseLevel( ;$ ) +{ + my $this = shift; + my $databaseLevel = shift; + if ( defined($databaseLevel) ) + { + $databaseLevel = $this->limit( $databaseLevel ); + if ( $this->{databaseLevel} != $databaseLevel ) + { + if ( $databaseLevel > NOLOG && $this->{databaseLevel} <= NOLOG ) + { + if ( !$this->{dbh} ) + { + my ( $host, $port ) = ( ZM_DB_HOST =~ /^([^:]+)(?::(.+))?$/ ); + + if ( defined($port) ) + { + $this->{dbh} = DBI->connect( "DBI:mysql:database=".ZM_DB_NAME.";host=".$host.";port=".$port, ZM_DB_USER, ZM_DB_PASS ); + } + else + { + $this->{dbh} = DBI->connect( "DBI:mysql:database=".ZM_DB_NAME.";host=".ZM_DB_HOST, ZM_DB_USER, ZM_DB_PASS ); + } + if ( !$this->{dbh} ) + { + $databaseLevel = NOLOG; + Error( "Unable to write log entries to DB, can't connect to database '".ZM_DB_NAME."' on host '".ZM_DB_HOST."'" ); + } + else + { + $this->{dbh}->trace( 0 ); + } + } + } + elsif ( $databaseLevel <= NOLOG && $this->{databaseLevel} > NOLOG ) + { + if ( $this->{dbh} ) + { + $this->{dbh}->disconnect(); + undef($this->{dbh}); + } + } + $this->{databaseLevel} = $databaseLevel; + } + } + return( $this->{databaseLevel} ); +} + +sub fileLevel( ;$ ) +{ + my $this = shift; + my $fileLevel = shift; + if ( defined($fileLevel) ) + { + $fileLevel = $this->limit($fileLevel); + if ( $this->{fileLevel} != $fileLevel ) + { + $this->closeFile() if ( $this->{fileLevel} > NOLOG ); + $this->{fileLevel} = $fileLevel; + $this->openFile() if ( $this->{fileLevel} > NOLOG ); + } + } + return( $this->{fileLevel} ); +} + +sub syslogLevel( ;$ ) +{ + my $this = shift; + my $syslogLevel = shift; + if ( defined($syslogLevel) ) + { + $syslogLevel = $this->limit($syslogLevel); + if ( $this->{syslogLevel} != $syslogLevel ) + { + $this->closeSyslog() if ( $syslogLevel <= NOLOG && $this->{syslogLevel} > NOLOG ); + $this->openSyslog() if ( $syslogLevel > NOLOG && $this->{syslogLevel} <= NOLOG ); + $this->{syslogLevel} = $syslogLevel; + } + } + return( $this->{syslogLevel} ); +} + +sub openSyslog() +{ + my $this = shift; + openlog( $this->{id}, "pid", "local1" ); +} + +sub closeSyslog() +{ + my $this = shift; + #closelog(); +} + +sub logFile( $ ) +{ + my $this = shift; + my $logFile = shift; + if ( $logFile =~ /^(.+)\+$/ ) + { + $this->{logFile} = $1.'.'.$$; + } + else + { + $this->{logFile} = $logFile; + } +} + +sub openFile() +{ + my $this = shift; + if ( open( LOGFILE, ">>".$this->{logFile} ) ) + { + LOGFILE->autoflush() if ( $this->{autoFlush} ); + + my $webUid = (getpwnam( ZM_WEB_USER ))[2]; + my $webGid = (getgrnam( ZM_WEB_GROUP ))[2]; + if ( $> == 0 ) + { + chown( $webUid, $webGid, $this->{logFile} ) or Fatal( "Can't change permissions on log file '".$this->{logFile}."': $!" ) + } + } + else + { + $this->fileLevel( NOLOG ); + Error( "Can't open log file '".$this->{logFile}."': $!" ); + } +} + +sub closeFile() +{ + my $this = shift; + close( LOGFILE ) if ( fileno(LOGFILE) ); +} + +sub logPrint( $;$ ) +{ + my $this = shift; + my $level = shift; + my $string = shift; + + if ( $level <= $this->{effectiveLevel} ) + { + $string =~ s/[\r\n]+$//g; + + my $code = $codes{$level}; + + my ($seconds, $microseconds) = gettimeofday(); + my $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", localtime( $seconds ) ), $microseconds, $this->{id}, $$, $code, $string ); + if ( $this->{trace} ) + { + $message = Carp::shortmess( $message ); + } + else + { + $message = $message."\n"; + } + syslog( $priorities{$level}, $code." [%s]", $string ) if ( $level <= $this->{syslogLevel} ); + print( LOGFILE $message ) if ( $level <= $this->{fileLevel} ); + if ( $level <= $this->{databaseLevel} ) + { + my $sql = "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )"; + $this->{sth} = $this->{dbh}->prepare_cached( $sql ); + if ( !$this->{sth} ) + { + $this->{databaseLevel} = NOLOG; + Fatal( "Can't prepare log entry '$sql': ".$this->{dbh}->errstr() ); + } + my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0), $this->{id}, $$, $level, $code, $string, $this->{fileName} ); + if ( !$res ) + { + $this->{databaseLevel} = NOLOG; + Fatal( "Can't execute log entry '$sql': ".$this->{sth}->errstr() ); + } + } + print( STDERR $message ) if ( $level <= $this->{termLevel} ); + } +} + +sub logInit( ;@ ) +{ + my %options = @_ ? @_ : (); + $logger = ZoneMinder::Logger->new() if ( !$logger ); + $logger->initialise( %options ); +} + +sub logReinit() +{ + fetch()->reinitialise(); +} + +sub logTerm +{ + return unless ( $logger ); + $logger->terminate(); + $logger = undef; +} + +sub logHupHandler() +{ + my $savedErrno = $!; + return unless( $logger ); + fetch()->reinitialise(); + logSetSignal(); + $! = $savedErrno; +} + +sub logSetSignal() +{ + $SIG{HUP} = \&logHupHandler; +} + +sub logClearSignal() +{ + $SIG{HUP} = 'DEFAULT'; +} + +sub logLevel( ;$ ) +{ + return( fetch()->level( @_ ) ); +} + +sub logDebugging() +{ + return( fetch()->debugOn() ); +} + +sub logTermLevel( ;$ ) +{ + return( fetch()->termLevel( @_ ) ); +} + +sub logDatabaseLevel( ;$ ) +{ + return( fetch()->databaseLevel( @_ ) ); +} + +sub logFileLevel( ;$ ) +{ + return( fetch()->fileLevel( @_ ) ); +} + +sub logSyslogLevel( ;$ ) +{ + return( fetch()->syslogLevel( @_ ) ); +} + +sub Mark( ;$$ ) +{ + my $level = shift; + $level = DEBUG unless( defined($level) ); + my $tag = "Mark"; + fetch()->logPrint( $level, $tag ); +} + +sub Dump( \$;$ ) +{ + my $var = shift; + my $label = shift; + $label = "VAR" unless( defined($label) ); + fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) ); +} + +sub Debug( @ ) +{ + fetch()->logPrint( DEBUG, @_ ); +} + +sub Info( @ ) +{ + fetch()->logPrint( INFO, @_ ); +} + +sub Warning( @ ) +{ + fetch()->logPrint( WARNING, @_ ); +} + +sub Error( @ ) +{ + fetch()->logPrint( ERROR, @_ ); +} + +sub Fatal( @ ) +{ + fetch()->logPrint( FATAL, @_ ); + exit( -1 ); +} + +sub Panic( @ ) +{ + fetch()->logPrint( PANIC, @_ ); + confess( $_[0] ); +} + +1; +__END__ + +=head1 NAME + +ZoneMinder::Logger - ZoneMinder Logger module + +=head1 SYNOPSIS + + use ZoneMinder::Logger; + use ZoneMinder::Logger qw(:all); + + logInit( "myproc", DEBUG ); + + Debug( "This is what is happening" ); + Info( "Something interesting is happening" ); + Warning( "Something might be going wrong." ); + Error( "Something has gone wrong!!" ); + Fatal( "Something has gone badly wrong, gotta stop!!" ); + Panic( "Something fundamental has gone wrong, die with stack trace ); + +=head1 DESCRIPTION + +The ZoneMinder:Logger module contains the common debug and error reporting routines used by the ZoneMinder scripts. + +To use debug in your scripts you need to include this module, and call logInit. Thereafter you can sprinkle Debug or Error calls etc throughout the code safe in the knowledge that they will be reported to your error log, and possibly the syslogger, in a meaningful and consistent format. + +Debug is discussed in terms of levels where 1 and above (currently only 1 for scripts) is considered debug, 0 is considered as informational, -1 is a warning, -2 is an error and -3 is a fatal error or panic. Where levels are mentioned below as thresholds the value given and anything with a lower level (ie. more serious) will be included. + +=head1 METHODS + +=over 4 + +=item logInit ( $id, %options ); + +Initialises the debug and prepares the logging for forthcoming operations. If not called explicitly it will be called by the first debug call in your script, but with default (and probably meaningless) options. The only compulsory arguments are $id which must be a string that will identify debug coming from this script in mixed logs. Other options may be provided as below, + + Option Default Description + --------- --------- ----------- + level INFO The initial debug level which defines which statements are output and which are ignored + trace 0 Whether to use the Carp::shortmess format in debug statements to identify where the debug was emitted from + termLevel NOLOG At what level debug is written to terminal standard error, 0 is no, 1 is yes, 2 is write only if terminal + databaseLevel INFO At what level debug is written to the Log table in the database; + fileLevel NOLOG At what level debug is written to a log file of the format of .log in the standard log directory. + syslogLevel INFO At what level debug is written to syslog. + +To disable any of these action entirely set to NOLOG + +=item logTerm (); + +Used to end the debug session and close any logs etc. Not usually necessary. + +=item $id = logId ( [$id] ); + +=item $level = logLevel ( [$level] ); + +=item $trace = logTrace ( [$trace] ); + +=item $level = logLevel ( [$level] ); + +=item $termLevel = logTermLevel ( [$termLevel] ); + +=item $databaseLevel = logDatabaseLevel ( [$databaseLevel] ); + +=item $fileLevel = logFileLevel ( [$fileLevel] ); + +=item $syslogLevel = logSyslogLevel ( [$syslogLevel] ); + +These methods can be used to get and set the current settings as defined in logInit. + +=item Debug( $string ); + +This method will output a debug message if the current debug level permits it, otherwise does nothing. This message will be tagged with the DBG string in the logs. + +=item Info( $string ); + +This method will output an informational message if the current debug level permits it, otherwise does nothing. This message will be tagged with the INF string in the logs. + +=item Warning( $string ); + +This method will output a warning message if the current debug level permits it, otherwise does nothing. This message will be tagged with the WAR string in the logs. + +=item Error( $string ); + +This method will output an error message if the current debug level permits it, otherwise does nothing. This message will be tagged with the ERR string in the logs. + +=item Fatal( $string ); + +This method will output a fatal error message and then die if the current debug level permits it, otherwise does nothing. This message will be tagged with the FAT string in the logs. + +=item Panic( $string ); + +This method will output a panic error message and then die with a stack trace if the current debug level permits it, otherwise does nothing. This message will be tagged with the PNC string in the logs. + +=head2 EXPORT + +None by default. +The :constants tag will export the debug constants which define the various levels of debug +The :variables tag will export variables containing the current debug id and level +The :functions tag will export the debug functions. This or :all is what you would normally use. +The :all tag will export all above symbols. + + +=head1 SEE ALSO + +Carp +Sys::Syslog + +The ZoneMinder README file Troubleshooting section for an extended discussion on the use and configuration of syslog with ZoneMinder. + +http://www.zoneminder.com + +=head1 AUTHOR + +Philip Coombes, Ephilip.coombes@zoneminder.comE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2001-2008 Philip Coombes + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.3 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in index 2d3cff1b9..537c6af61 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in @@ -95,7 +95,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # ========================================================================== use ZoneMinder::Config qw(:all); -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use constant STATE_IDLE => 0; use constant STATE_PREALARM => 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm index a3f037e08..b8745d835 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm @@ -64,7 +64,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # ========================================================================== use ZoneMinder::Config qw(:all); -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Sys::Mmap; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm index 8562b49c2..c04e4f413 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm @@ -65,7 +65,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # ========================================================================== use ZoneMinder::Config qw(:all); -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); sub zmMemKey( $ ) { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm index b2435e43b..0344e6d94 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm @@ -38,7 +38,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Carp; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm index 41f6e9a97..234dae3d7 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Carp; use Fcntl; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm index c8a1494e2..356bb5aea 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use POSIX; sub new diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm index 330fffa9c..68df0980f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Carp; use Socket; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm index df5067eec..7e4ad4730 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Device::SerialPort; sub new diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm index 82c0009c3..ff726ac38 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); sub new { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm index f6d2812ad..a671ccd66 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm @@ -41,7 +41,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Carp; use Socket; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm index 20cccc46a..41b332d46 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm @@ -38,7 +38,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use Carp; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm index 8404ffc18..3bed2b351 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm @@ -40,7 +40,7 @@ our $VERSION = $ZoneMinder::Base::VERSION; # # ========================================================================== -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); sub new { diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index c126cfa92..8546b50cd 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -43,9 +43,6 @@ use constant MAX_AGED_DIRS => 10; # Number of event dirs to check age on use constant RECOVER_TAG => "(r)"; # Tag to append to event name when recovered use constant RECOVER_TEXT => "Recovered."; # Text to append to event notes when recovered -use constant DBG_ID => "zmaudit"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - # ========================================================================== # # You shouldn't need to change anything from here downwards @@ -75,32 +72,32 @@ my $continuous = 0; sub usage { - print( " + print( " Usage: zmaudit.pl [-r,-report|-i,-interactive] Parameters are :- -r, --report - Just report don't actually do anything -i, --interactive - Ask before applying any changes -c, --continuous - Run continuously "); - exit( -1 ); + exit( -1 ); } sub aud_print( $ ); sub confirm( ;$$ ); sub deleteSwapImage(); -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); -zmDbgSetSignal(); +logInit(); +logSetSignal(); if ( !GetOptions( 'report'=>\$report, 'interactive'=>\$interactive, 'continuous'=>\$continuous ) ) { - usage(); + usage(); } if ( ($report + $interactive + $continuous) > 1 ) { - print( STDERR "Error, only option may be specified\n" ); - usage(); + print( STDERR "Error, only option may be specified\n" ); + usage(); } my $dbh = zmDbConnect(); @@ -116,40 +113,40 @@ my $loop = 1; my $cleaned = 0; MAIN: while( $loop ) { - my $db_monitors; - my $monitorSelectSql = "select Id from Monitors order by Id"; - my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() ); - my $eventSelectSql = "select Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age from Events where MonitorId = ? order by Id"; - my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() ); + my $db_monitors; + my $monitorSelectSql = "select Id from Monitors order by Id"; + my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() ); + my $eventSelectSql = "select Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age from Events where MonitorId = ? order by Id"; + my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() ); - my $res = $monitorSelectSth->execute() or Fatal( "Can't execute: ".$monitorSelectSth->errstr() ); - while( my $monitor = $monitorSelectSth->fetchrow_hashref() ) - { - Debug( "Found database monitor '$monitor->{Id}'" ); - my $db_events = $db_monitors->{$monitor->{Id}} = {}; - my $res = $eventSelectSth->execute( $monitor->{Id} ) or Fatal( "Can't execute: ".$eventSelectSth->errstr() ); - while ( my $event = $eventSelectSth->fetchrow_hashref() ) - { - $db_events->{$event->{Id}} = $event->{Age}; - } - Debug( "Got ".int(keys(%$db_events))." events\n" ); - $eventSelectSth->finish(); - } - $monitorSelectSth->finish(); + my $res = $monitorSelectSth->execute() or Fatal( "Can't execute: ".$monitorSelectSth->errstr() ); + while( my $monitor = $monitorSelectSth->fetchrow_hashref() ) + { + Debug( "Found database monitor '$monitor->{Id}'" ); + my $db_events = $db_monitors->{$monitor->{Id}} = {}; + my $res = $eventSelectSth->execute( $monitor->{Id} ) or Fatal( "Can't execute: ".$eventSelectSth->errstr() ); + while ( my $event = $eventSelectSth->fetchrow_hashref() ) + { + $db_events->{$event->{Id}} = $event->{Age}; + } + Debug( "Got ".int(keys(%$db_events))." events\n" ); + $eventSelectSth->finish(); + } + $monitorSelectSth->finish(); - my $fs_monitors; - foreach my $monitor ( <[0-9]*> ) - { - Debug( "Found filesystem monitor '$monitor'" ); - my $fs_events = $fs_monitors->{$monitor} = {}; - ( my $monitor_dir ) = ( $monitor =~ /^(.*)$/ ); # De-taint + my $fs_monitors; + foreach my $monitor ( <[0-9]*> ) + { + Debug( "Found filesystem monitor '$monitor'" ); + my $fs_events = $fs_monitors->{$monitor} = {}; + ( my $monitor_dir ) = ( $monitor =~ /^(.*)$/ ); # De-taint if ( ZM_USE_DEEP_STORAGE ) { foreach my $day_dir ( <$monitor_dir/*/*/*> ) { Debug( "Checking $day_dir" ); - ( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint + ( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint chdir( $day_dir ); opendir( DIR, "." ) or Fatal( "Can't open directory '$day_dir': $!" ); my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR ); @@ -169,7 +166,7 @@ MAIN: while( $loop ) $fs_events->{$event} = (time() - ($^T - ((-M $event_path) * 24*60*60))); } } - chdir( EVENT_PATH ); + chdir( EVENT_PATH ); } } else @@ -190,54 +187,54 @@ MAIN: while( $loop ) $fs_events->{$event} = (time() - ($^T - ((-M $event) * 24*60*60))); } } - chdir( EVENT_PATH ); + chdir( EVENT_PATH ); } - Debug( "Got ".int(keys(%$fs_events))." events\n" ); - } + Debug( "Got ".int(keys(%$fs_events))." events\n" ); + } $cleaned = 0; - while ( my ( $fs_monitor, $fs_events ) = each(%$fs_monitors) ) - { - if ( my $db_events = $db_monitors->{$fs_monitor} ) - { - if ( $fs_events ) - { - while ( my ( $fs_event, $age ) = each(%$fs_events ) ) - { - if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > MIN_AGE)) ) - { - aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" ); - if ( confirm() ) - { + while ( my ( $fs_monitor, $fs_events ) = each(%$fs_monitors) ) + { + if ( my $db_events = $db_monitors->{$fs_monitor} ) + { + if ( $fs_events ) + { + while ( my ( $fs_event, $age ) = each(%$fs_events ) ) + { + if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > MIN_AGE)) ) + { + aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" ); + if ( confirm() ) + { deleteEventFiles( $fs_event, $fs_monitor ); $cleaned = 1; - } - } - } - } - } - else - { - aud_print( "Filesystem monitor '$fs_monitor' does not exist in database" ); - if ( confirm() ) - { - my $command = "rm -rf $fs_monitor"; - executeShellCommand( $command ); + } + } + } + } + } + else + { + aud_print( "Filesystem monitor '$fs_monitor' does not exist in database" ); + if ( confirm() ) + { + my $command = "rm -rf $fs_monitor"; + executeShellCommand( $command ); $cleaned = 1; - } - } - } + } + } + } - my $monitor_links; - foreach my $link ( <*> ) - { + my $monitor_links; + foreach my $link ( <*> ) + { next if ( !-l $link ); next if ( -e $link ); aud_print( "Filesystem monitor link '$link' does not point to valid monitor directory" ); if ( confirm() ) { - ( $link ) = ( $link =~ /^(.*)$/ ); # De-taint + ( $link ) = ( $link =~ /^(.*)$/ ); # De-taint my $command = "rm $link"; executeShellCommand( $command ); $cleaned = 1; @@ -246,204 +243,233 @@ MAIN: while( $loop ) redo MAIN if ( $cleaned ); $cleaned = 0; - my $deleteMonitorSql = "delete from Monitors where Id = ?"; - my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() ); - my $deleteEventSql = "delete from Events where Id = ?"; - my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() ); - my $deleteFramesSql = "delete from Frames where EventId = ?"; - my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() ); - my $deleteStatsSql = "delete from Stats where EventId = ?"; - my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql ) or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() ); - while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) ) - { - if ( my $fs_events = $fs_monitors->{$db_monitor} ) - { - if ( $db_events ) - { - while ( my ( $db_event, $age ) = each(%$db_events ) ) - { - if ( !defined($fs_events->{$db_event}) && ($age > MIN_AGE) ) - { - aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" ); - if ( confirm() ) - { - my $res = $deleteEventSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); - $res = $deleteFramesSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); - $res = $deleteStatsSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); + my $deleteMonitorSql = "delete from Monitors where Id = ?"; + my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() ); + my $deleteEventSql = "delete from Events where Id = ?"; + my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() ); + my $deleteFramesSql = "delete from Frames where EventId = ?"; + my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() ); + my $deleteStatsSql = "delete from Stats where EventId = ?"; + my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql ) or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() ); + while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) ) + { + if ( my $fs_events = $fs_monitors->{$db_monitor} ) + { + if ( $db_events ) + { + while ( my ( $db_event, $age ) = each(%$db_events ) ) + { + if ( !defined($fs_events->{$db_event}) && ($age > MIN_AGE) ) + { + aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" ); + if ( confirm() ) + { + my $res = $deleteEventSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); + $res = $deleteFramesSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); + $res = $deleteStatsSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); $cleaned = 1; - } - } - } - } - } - else - { - #aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); - #if ( confirm() ) - #{ - # We don't actually do this in case it's new - #my $res = $deleteMonitorSth->execute( $db_monitor ) or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() ); + } + } + } + } + } + else + { + #aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); + #if ( confirm() ) + #{ + # We don't actually do this in case it's new + #my $res = $deleteMonitorSth->execute( $db_monitor ) or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() ); #$cleaned = 1; - #} - } - } + #} + } + } redo MAIN if ( $cleaned ); # Remove orphaned events (with no monitor) $cleaned = 0; - my $selectOrphanedEventsSql = "select Events.Id, Events.Name from Events left join Monitors on (Events.MonitorId = Monitors.Id) where isnull(Monitors.Id)"; - my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql ) or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() ); - $res = $selectOrphanedEventsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() ); - while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) - { - aud_print( "Found orphaned event with no monitor '$event->{Id}'" ); - if ( confirm() ) - { - $res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); + my $selectOrphanedEventsSql = "select Events.Id, Events.Name from Events left join Monitors on (Events.MonitorId = Monitors.Id) where isnull(Monitors.Id)"; + my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql ) or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() ); + $res = $selectOrphanedEventsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() ); + while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) + { + aud_print( "Found orphaned event with no monitor '$event->{Id}'" ); + if ( confirm() ) + { + $res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); $cleaned = 1; - } - } + } + } $selectOrphanedEventsSth->finish(); redo MAIN if ( $cleaned ); # Remove empty events (with no frames) $cleaned = 0; - my $selectEmptyEventsSql = "select * from Events as E left join Frames as F on (E.Id = F.EventId) where isnull(F.EventId) and now() - interval ".MIN_AGE." second > E.StartTime"; - my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); - $res = $selectEmptyEventsSth->execute() or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() ); - while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) - { - aud_print( "Found empty event with no frame records '$event->{Id}'" ); - if ( confirm() ) - { - $res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); + my $selectEmptyEventsSql = "select * from Events as E left join Frames as F on (E.Id = F.EventId) where isnull(F.EventId) and now() - interval ".MIN_AGE." second > E.StartTime"; + my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); + $res = $selectEmptyEventsSth->execute() or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() ); + while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) + { + aud_print( "Found empty event with no frame records '$event->{Id}'" ); + if ( confirm() ) + { + $res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); $cleaned = 1; - } - } + } + } $selectEmptyEventsSth->finish(); redo MAIN if ( $cleaned ); # Remove orphaned frame records $cleaned = 0; - my $selectOrphanedFramesSql = "select distinct EventId from Frames where EventId not in (select Id from Events)"; - my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() ); - $res = $selectOrphanedFramesSth->execute() or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() ); - while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() ) - { - aud_print( "Found orphaned frame records for event '$frame->{EventId}'" ); - if ( confirm() ) - { - $res = $deleteFramesSth->execute( $frame->{EventId} ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); + my $selectOrphanedFramesSql = "select distinct EventId from Frames where EventId not in (select Id from Events)"; + my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() ); + $res = $selectOrphanedFramesSth->execute() or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() ); + while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() ) + { + aud_print( "Found orphaned frame records for event '$frame->{EventId}'" ); + if ( confirm() ) + { + $res = $deleteFramesSth->execute( $frame->{EventId} ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); $cleaned = 1; - } - } + } + } $selectOrphanedFramesSth->finish(); redo MAIN if ( $cleaned ); # Remove orphaned stats records $cleaned = 0; - my $selectOrphanedStatsSql = "select distinct EventId from Stats where EventId not in (select Id from Events)"; - my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql ) or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() ); - $res = $selectOrphanedStatsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() ); - while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() ) - { - aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" ); - if ( confirm() ) - { - $res = $deleteStatsSth->execute( $stat->{EventId} ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); + my $selectOrphanedStatsSql = "select distinct EventId from Stats where EventId not in (select Id from Events)"; + my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql ) or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() ); + $res = $selectOrphanedStatsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() ); + while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() ) + { + aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" ); + if ( confirm() ) + { + $res = $deleteStatsSth->execute( $stat->{EventId} ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); $cleaned = 1; - } - } + } + } $selectOrphanedStatsSth->finish(); redo MAIN if ( $cleaned ); - # New audit to close any events that were left open for longer than MIN_AGE seconds - my $selectUnclosedEventsSql = "select E.Id, max(F.TimeStamp) as EndTime, unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, max(F.FrameId) as Frames, count(if(F.Score>0,1,NULL)) as AlarmFrames, sum(F.Score) as TotScore, max(F.Score) as MaxScore, M.EventPrefix as Prefix from Events as E left join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where isnull(E.Frames) or isnull(E.EndTime) group by E.Id having EndTime < (now() - interval ".MIN_AGE." second)"; - my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); - my $updateUnclosedEventsSql = "update Events set Name = ?, EndTime = ?, Length = ?, Frames = ?, AlarmFrames = ?, TotScore = ?, AvgScore = ?, MaxScore = ?, Notes = concat_ws( ' ', Notes, ? ) where Id = ?"; - my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql ) or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() ); - $res = $selectUnclosedEventsSth->execute() or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() ); - while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) - { - aud_print( "Found open event '$event->{Id}'" ); - if ( confirm( 'close', 'closing' ) ) - { - $res = $updateUnclosedEventsSth->execute( sprintf( "%s%d%s", $event->{Prefix}, $event->{Id}, RECOVER_TAG ), $event->{EndTime}, $event->{Length}, $event->{Frames}, $event->{AlarmFrames}, $event->{TotScore}, $event->{AlarmFrames}?int($event->{TotScore}/$event->{AlarmFrames}):0, $event->{MaxScore}, RECOVER_TEXT, $event->{Id} ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() ); - } - } + # New audit to close any events that were left open for longer than MIN_AGE seconds + my $selectUnclosedEventsSql = "select E.Id, max(F.TimeStamp) as EndTime, unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, max(F.FrameId) as Frames, count(if(F.Score>0,1,NULL)) as AlarmFrames, sum(F.Score) as TotScore, max(F.Score) as MaxScore, M.EventPrefix as Prefix from Events as E left join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where isnull(E.Frames) or isnull(E.EndTime) group by E.Id having EndTime < (now() - interval ".MIN_AGE." second)"; + my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); + my $updateUnclosedEventsSql = "update Events set Name = ?, EndTime = ?, Length = ?, Frames = ?, AlarmFrames = ?, TotScore = ?, AvgScore = ?, MaxScore = ?, Notes = concat_ws( ' ', Notes, ? ) where Id = ?"; + my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql ) or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() ); + $res = $selectUnclosedEventsSth->execute() or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() ); + while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) + { + aud_print( "Found open event '$event->{Id}'" ); + if ( confirm( 'close', 'closing' ) ) + { + $res = $updateUnclosedEventsSth->execute( sprintf( "%s%d%s", $event->{Prefix}, $event->{Id}, RECOVER_TAG ), $event->{EndTime}, $event->{Length}, $event->{Frames}, $event->{AlarmFrames}, $event->{TotScore}, $event->{AlarmFrames}?int($event->{TotScore}/$event->{AlarmFrames}):0, $event->{MaxScore}, RECOVER_TEXT, $event->{Id} ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() ); + } + } $selectUnclosedEventsSth->finish(); - # Now delete any old image files - if ( my @old_files = grep { -M > $max_image_age } <$image_path/*.{jpg,gif,wbmp}> ) - { - aud_print( "Deleting ".int(@old_files)." old images\n" ); - my $untainted_old_files = join( ";", @old_files ); - ( $untainted_old_files ) = ( $untainted_old_files =~ /^(.*)$/ ); - unlink( split( ";", $untainted_old_files ) ); - } + # Now delete any old image files + if ( my @old_files = grep { -M > $max_image_age } <$image_path/*.{jpg,gif,wbmp}> ) + { + aud_print( "Deleting ".int(@old_files)." old images\n" ); + my $untainted_old_files = join( ";", @old_files ); + ( $untainted_old_files ) = ( $untainted_old_files =~ /^(.*)$/ ); + unlink( split( ";", $untainted_old_files ) ); + } - # Now delete any old swap files - ( my $swap_image_root ) = ( $swap_image_path =~ /^(.*)$/ ); # De-taint + # Now delete any old swap files + ( my $swap_image_root ) = ( $swap_image_path =~ /^(.*)$/ ); # De-taint File::Find::find( { wanted=>\&deleteSwapImage, untaint=>1 }, $swap_image_root ); + # Prune the Logs table if required + if ( ZM_LOG_DATABASE_LIMIT ) + { + if ( ZM_LOG_DATABASE_LIMIT =~ /^\d+$/ ) + { + # Number of rows + my $selectLogRowCountSql = "select count(*) as Rows from Logs"; + my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql ) or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() ); + $res = $selectLogRowCountSth->execute() or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() ); + my $row = $selectLogRowCountSth->fetchrow_hashref(); + my $logRows = $row->{Rows}; + $selectLogRowCountSth->finish(); + if ( $logRows > ZM_LOG_DATABASE_LIMIT ) + { + my $deleteLogByRowsSql = "delete from Logs order by TimeKey asc limit ?"; + my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql ) or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() ); + $res = $deleteLogByRowsSth->execute( $logRows - ZM_LOG_DATABASE_LIMIT ) or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() ); + aud_print( "Deleted ".$deleteLogByRowsSth->rows()." log table entries by count\n" ) if ( $deleteLogByRowsSth->rows() ); + } + } + else + { + # Time of record + my $deleteLogByTimeSql = "delete from Logs where TimeKey < unix_timestamp(now() - interval ".ZM_LOG_DATABASE_LIMIT.")"; + my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql ) or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() ); + $res = $deleteLogByTimeSth->execute() or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() ); + aud_print( "Deleted ".$deleteLogByTimeSth->rows()." log table entries by time\n" ) if ( $deleteLogByTimeSth->rows() ); + } + } $loop = $continuous; - sleep( ZM_AUDIT_CHECK_INTERVAL ) if ( $continuous ); + sleep( ZM_AUDIT_CHECK_INTERVAL ) if ( $continuous ); }; exit( 0 ); sub aud_print( $ ) { - my $string = shift; - if ( !$continuous ) - { - print( $string ); - } - else - { - Info( $string ); - } + my $string = shift; + if ( !$continuous ) + { + print( $string ); + } + else + { + Info( $string ); + } } sub confirm( ;$$ ) { - my $prompt = shift || "delete"; - my $action = shift || "deleting"; + my $prompt = shift || "delete"; + my $action = shift || "deleting"; - my $yesno = 0; - if ( $report ) - { - print( "\n" ); - } - elsif ( $interactive ) - { - print( ", $prompt y/n: " ); - my $char = <>; - chomp( $char ); - if ( $char eq 'q' ) - { - exit( 0 ); - } - if ( !$char ) - { - $char = 'y'; - } - $yesno = ( $char =~ /[yY]/ ); - } - else - { - if ( !$continuous ) - { - print( ", $action\n" ); - } - else - { - Info( $action ); - } - $yesno = 1; - } - return( $yesno ); + my $yesno = 0; + if ( $report ) + { + print( "\n" ); + } + elsif ( $interactive ) + { + print( ", $prompt y/n: " ); + my $char = <>; + chomp( $char ); + if ( $char eq 'q' ) + { + exit( 0 ); + } + if ( !$char ) + { + $char = 'y'; + } + $yesno = ( $char =~ /[yY]/ ); + } + else + { + if ( !$continuous ) + { + print( ", $action\n" ); + } + else + { + Info( $action ); + } + $yesno = 1; + } + return( $yesno ); } sub deleteSwapImage() diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index 49c021627..8598e08e3 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -27,17 +27,6 @@ # use strict; -# ========================================================================== -# -# These are the elements you can edit to suit your installation -# -# ========================================================================== - -use constant DBG_ID => "zmcontrol"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - -# ========================================================================== - @EXTRA_PERL_LIB@ use ZoneMinder; use Getopt::Long; @@ -63,7 +52,7 @@ Usage: zmcontrol.pl --id --command= exit( -1 ); } -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); +logInit(); my $arg_string = join( " ", @ARGV ); @@ -124,7 +113,7 @@ if ( !$server_up ) my $output = qx($command); my $status = $? >> 8; - if ( $status || DBG_LEVEL > 0 ) + if ( $status || logDebugging() ) { chomp( $output ); Debug( "Output: $output\n" ); @@ -142,7 +131,7 @@ if ( !$server_up ) if ( my $cpid = fork() ) { - zmDbgInit( DBG_ID, level=>DBG_LEVEL ); + logInit(); # Parent process just sleep and fall through socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" ); @@ -161,7 +150,7 @@ if ( !$server_up ) setpgrp(); - zmDbgInit( DBG_ID, level=>DBG_LEVEL ); + logInit(); Info( "Control server $id/$protocol starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) ); diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index f0109c3db..c6c6d9aec 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -36,9 +36,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmdc"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant MAX_CONNECT_DELAY => 10; # ========================================================================== @@ -63,16 +60,16 @@ $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my @daemons = ( - 'zmc', - 'zma', - 'zmf', - 'zmfilter.pl', - 'zmaudit.pl', - 'zmtrigger.pl', - 'zmx10.pl', - 'zmwatch.pl', - 'zmupdate.pl', - 'zmtrack.pl' + 'zmc', + 'zma', + 'zmf', + 'zmfilter.pl', + 'zmaudit.pl', + 'zmtrigger.pl', + 'zmx10.pl', + 'zmwatch.pl', + 'zmupdate.pl', + 'zmtrack.pl' ); sub Usage @@ -105,30 +102,30 @@ my @args; my $daemon_patt = '('.join( '|', @daemons ).')'; if ( $needs_daemon ) { - if ( $daemon =~ /^${daemon_patt}$/ ) - { - $daemon = $1; - } - else - { - print( STDERR "Invalid daemon '$daemon' specified" ); + if ( $daemon =~ /^${daemon_patt}$/ ) + { + $daemon = $1; + } + else + { + print( STDERR "Invalid daemon '$daemon' specified" ); Usage(); - } + } } foreach my $arg ( @ARGV ) { - # Detaint arguments, if they look ok - #if ( $arg =~ /^(-{0,2}[\w]+)/ ) - if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) - { - push( @args, $1 ); - } - else - { - print( STDERR "Bogus argument '$arg' found" ); + # Detaint arguments, if they look ok + #if ( $arg =~ /^(-{0,2}[\w]+)/ ) + if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) + { + push( @args, $1 ); + } + else + { + print( STDERR "Bogus argument '$arg' found" ); exit( -1 ); - } + } } socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); @@ -137,56 +134,56 @@ my $saddr = sockaddr_un( SOCK_FILE ); my $server_up = connect( CLIENT, $saddr ); if ( !$server_up ) { - if ( $command eq "logrot" ) + if ( $command eq "logrot" ) { exit(); } - if ( $command eq "check" ) - { - print( "stopped\n" ); - exit(); - } - elsif ( $command ne "startup" ) - { - print( "Unable to connect to server\n" ); - exit( -1 ); - } - # The server isn't there - print( "Starting server\n" ); - close( CLIENT ); + if ( $command eq "check" ) + { + print( "stopped\n" ); + exit(); + } + elsif ( $command ne "startup" ) + { + print( "Unable to connect to server\n" ); + exit( -1 ); + } + # The server isn't there + print( "Starting server\n" ); + close( CLIENT ); - if ( my $cpid = fork() ) - { - zmDbgInit( DBG_ID, level=>DBG_LEVEL ); + if ( my $cpid = fork() ) + { + logInit(); - # Parent process just sleep and fall through - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - my $attempts = 0; - while (!connect( CLIENT, $saddr )) - { - $attempts++; - Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY); - sleep(1); - } - } - elsif ( defined($cpid) ) - { + # Parent process just sleep and fall through + socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); + my $attempts = 0; + while (!connect( CLIENT, $saddr )) + { + $attempts++; + Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY); + sleep(1); + } + } + elsif ( defined($cpid) ) + { ZMServer::run(); - } - else - { - Fatal( "Can't fork: $!" ); - } + } + else + { + Fatal( "Can't fork: $!" ); + } } if ( $command eq "check" && !$daemon ) { - print( "running\n" ); - exit(); + print( "running\n" ); + exit(); } elsif ( $command eq "startup" ) { - # Our work here is done - exit() if ( !$server_up ); + # Our work here is done + exit() if ( !$server_up ); } # The server is there, connect to it #print( "Writing commands\n" ); @@ -198,8 +195,8 @@ print( CLIENT $message ); shutdown( CLIENT, 1 ); while ( my $line = ) { - chomp( $line ); - print( "$line\n" ); + chomp( $line ); + print( "$line\n" ); } # And we're done! close( CLIENT ); @@ -232,9 +229,9 @@ sub run setpgrp(); - zmDbgInit( main::DBG_ID, level=>main::DBG_LEVEL ); + logInit(); - dPrint( DBG_INFO, "Server starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Server starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); if ( open( PID, ">".ZM_PID ) ) { @@ -293,7 +290,7 @@ sub run elsif ( $command eq 'startup' ) { # Do nothing, this is all we're here for - dPrint( DBG_WARNING, "Already running, ignoring command '$command'\n" ); + dPrint( ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n" ); } elsif ( $command eq 'shutdown' ) { @@ -320,7 +317,7 @@ sub run } else { - dPrint( DBG_ERROR, "Invalid command '$command'\n" ); + dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); } close( CLIENT ); } @@ -353,7 +350,7 @@ sub run restartPending(); } } - dPrint( DBG_INFO, "Server exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Server exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); unlink( main::SOCK_FILE ); unlink( ZM_PID ); exit(); @@ -369,28 +366,28 @@ sub cPrint sub dPrint { - my $dbg_level = shift; + my $logLevel = shift; if ( fileno(CLIENT) ) { print CLIENT @_ } - if ( $dbg_level == DBG_DEBUG ) + if ( $logLevel == ZoneMinder::Logger::DEBUG ) { Debug( @_ ); } - elsif ( $dbg_level == DBG_INFO ) + elsif ( $logLevel == ZoneMinder::Logger::INFO ) { Info( @_ ); } - elsif ( $dbg_level == DBG_WARNING ) + elsif ( $logLevel == ZoneMinder::Logger::WARNING ) { Warning( @_ ); } - elsif ( $dbg_level == DBG_ERROR ) + elsif ( $logLevel == ZoneMinder::Logger::ERROR ) { Error( @_ ); } - elsif ( $dbg_level == DBG_FATAL ) + elsif ( $logLevel == ZoneMinder::Logger::FATAL ) { Fatal( @_ ); } @@ -412,38 +409,31 @@ sub start } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { - dPrint( DBG_INFO, "'$process->{command}' already running at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" ); + dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" ); return(); } + my $sigset = POSIX::SigSet->new; + my $blockset = POSIX::SigSet->new( SIGCHLD ); + sigprocmask( SIG_BLOCK, $blockset, $sigset ) or Fatal( "Can't block SIGCHLD: $!" ); if ( my $cpid = fork() ) { - my $sigset = POSIX::SigSet->new; - my $blockset = POSIX::SigSet->new( SIGCHLD ); - sigprocmask( SIG_BLOCK, $blockset, $sigset ) or Fatal( "Can't block SIGCHLD: $!" ); + logReinit(); + $process->{pid} = $cpid; $process->{started} = time(); delete( $process->{pending} ); - dPrint( DBG_INFO, "'$command' starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" ); + dPrint( ZoneMinder::Logger::INFO, "'$command' starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" ); $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" ); } elsif ( defined($cpid ) ) { - my $fd = 0; - while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) - { - POSIX::close( $fd++ ); - } + logReinit(); - # Child process - $SIG{CHLD} = 'DEFAULT'; - $SIG{INT} = 'DEFAULT'; - $SIG{TERM} = 'DEFAULT'; - $SIG{ABRT} = 'DEFAULT'; - dPrint( DBG_INFO, "'".join( ' ', ( $daemon, @args ) )."' started at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) )."' started at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); if ( $daemon =~ /^${daemon_patt}$/ ) { @@ -468,6 +458,20 @@ sub start } } + logTerm(); + + my $fd = 0; + while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) + { + POSIX::close( $fd++ ); + } + + # Child process + $SIG{CHLD} = 'DEFAULT'; + $SIG{INT} = 'DEFAULT'; + $SIG{TERM} = 'DEFAULT'; + $SIG{ABRT} = 'DEFAULT'; + exec( $daemon, @good_args ) or Fatal( "Can't exec: $!" ); } else @@ -487,24 +491,24 @@ sub _stop my $process = $cmd_hash{$command}; if ( !$process ) { - dPrint( DBG_WARNING, "Can't find process with command of '$command'\n" ); + dPrint( ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n" ); return(); } elsif ( $process->{pending} ) { delete( $cmd_hash{$command} ); - dPrint( DBG_INFO, "Command '$command' removed from pending list at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); return(); } my $cpid = $process->{pid}; if ( !$pid_hash{$cpid} ) { - dPrint( DBG_ERROR, "No process with command of '$command' is running\n" ); + dPrint( ZoneMinder::Logger::ERROR, "No process with command of '$command' is running\n" ); return(); } - dPrint( DBG_INFO, "'$daemon ".join( ' ', @args )."' stopping at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "'$daemon ".join( ' ', @args )."' stopping at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); $process->{keepalive} = !$final; kill( 'TERM', $cpid ); delete( $cmd_hash{$command} ); @@ -568,7 +572,7 @@ sub reload sub logrot { - zmDbgReinit(); + logReinit(); foreach my $process ( values( %pid_hash ) ) { if ( $process->{pid} && $process->{command} =~ /^zm.*\.pl/ ) @@ -590,7 +594,7 @@ sub reaper if ( !$process ) { - dPrint( DBG_INFO, "Can't find child with pid of '$cpid'\n" ); + dPrint( ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n" ); next; } @@ -673,7 +677,7 @@ sub restartPending { if ( $process->{pending} && $process->{pending} <= time() ) { - dPrint( DBG_INFO, "Starting pending process, $process->{command}\n" ); + dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" ); start( $process->{daemon}, @{$process->{args}} ); } } @@ -686,7 +690,7 @@ sub shutdownAll stop( $process->{daemon}, @{$process->{args}} ); } killAll( 5 ); - dPrint( DBG_INFO, "Server shutdown at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Server shutdown at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); unlink( main::SOCK_FILE ); unlink( ZM_PID ); close( CLIENT ); @@ -736,24 +740,24 @@ sub status my $process = $cmd_hash{$command}; if ( !$process ) { - dPrint( DBG_DEBUG, "'$command' not running\n" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); return(); } if ( $process->{pending} ) { - dPrint( DBG_DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" ); } else { my $cpid = $process->{pid}; if ( !$pid_hash{$cpid} ) { - dPrint( DBG_DEBUG, "'$command' not running\n" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); return(); } } - dPrint( DBG_DEBUG, "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}" ); } else { @@ -762,13 +766,13 @@ sub status my $out_str = "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}"; $out_str .= ", valid" if ( kill( 0, $process->{pid} ) ); $out_str .= "\n"; - dPrint( DBG_DEBUG, $out_str ); + dPrint( ZoneMinder::Logger::DEBUG, $out_str ); } foreach my $process ( values( %cmd_hash ) ) { if ( $process->{pending} ) { - dPrint( DBG_DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" ); } } } @@ -776,19 +780,19 @@ sub status sub killAll { - my $delay = shift; - sleep( $delay ); - foreach my $daemon ( @daemons ) - { - my $cmd = "killall --quiet --signal TERM $daemon"; - Debug( $cmd ); - qx( $cmd ); - } - sleep( $delay ); - foreach my $daemon ( @daemons ) - { - my $cmd = "killall --quiet --signal KILL $daemon"; - Debug( $cmd ); - qx( $cmd ); - } + my $delay = shift; + sleep( $delay ); + foreach my $daemon ( @daemons ) + { + my $cmd = "killall --quiet --signal TERM $daemon"; + Debug( $cmd ); + qx( $cmd ); + } + sleep( $delay ); + foreach my $daemon ( @daemons ) + { + my $cmd = "killall --quiet --signal KILL $daemon"; + Debug( $cmd ); + qx( $cmd ); + } } diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index bc6764322..d60c5427a 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -34,9 +34,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmfilter"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant START_DELAY => 5; # How long to wait before starting # ========================================================================== @@ -56,8 +53,8 @@ use Data::Dumper; use constant EVENT_PATH => (ZM_DIR_EVENTS=~m|/|)?ZM_DIR_EVENTS:(ZM_PATH_WEB.'/'.ZM_DIR_EVENTS); -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); -zmDbgSetSignal(); +logInit(); +logSetSignal(); if ( ZM_OPT_UPLOAD ) { @@ -678,7 +675,7 @@ sub generateVideo my $output = qx($command); chomp( $output ); my $status = $? >> 8; - if ( $status || DBG_LEVEL > 0 ) + if ( $status || logDebugging() ) { Debug( "Output: $output\n" ); } @@ -1119,7 +1116,7 @@ sub executeCommand Info( "Executing '$command'\n" ); my $output = qx($command); my $status = $? >> 8; - if ( $status || DBG_LEVEL > 0 ) + if ( $status || logDebugging() ) { chomp( $output ); Debug( "Output: $output\n" ); diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 01e22eb0d..c0eab0b66 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -27,15 +27,6 @@ use strict; use bytes; -# ========================================================================== -# -# These are the elements you can edit to suit your installation -# -# ========================================================================== - -use constant DBG_ID => "zmpkg"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - # ========================================================================== # # Don't change anything below here @@ -53,7 +44,7 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); +logInit(); my $command = $ARGV[0]; diff --git a/scripts/zmtrack.pl.in b/scripts/zmtrack.pl.in index 3d852edc5..c80277005 100644 --- a/scripts/zmtrack.pl.in +++ b/scripts/zmtrack.pl.in @@ -33,9 +33,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmtrack"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant SLEEP_TIME => 10000; # In microseconds # ========================================================================== @@ -74,8 +71,8 @@ if ( !GetOptions( 'monitor=s'=>\$mid ) ) Usage(); } -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); -zmDbgSetSignal(); +logInit(); +logSetSignal(); my ( $detaint_mid ) = $mid =~ /^(\d+)$/; $mid = $detaint_mid; @@ -190,7 +187,7 @@ while( 1 ) } else { - if ( DBG_LEVEL > 0 && $alarmed ) + if ( logDebugging() && $alarmed ) { print( "Left alarm state\n" ); $alarmed = undef; diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index ea445e114..11c5c9a29 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -34,9 +34,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmtrigger"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant MAX_CONNECT_DELAY => 10; use constant MONITOR_RELOAD_INTERVAL => 300; use constant SELECT_TIMEOUT => 0.25; @@ -78,8 +75,8 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); -zmDbgSetSignal(); +logInit(); +logSetSignal(); Info( "Trigger daemon starting\n" ); diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 39ae5cc72..4ed092064 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -34,9 +34,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmupdate"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant CHECK_INTERVAL => (1*24*60*60); # Interval between version checks # ========================================================================== @@ -48,7 +45,7 @@ use constant CHECK_INTERVAL => (1*24*60*60); # Interval between version checks @EXTRA_PERL_LIB@ use ZoneMinder::Base qw(:all); use ZoneMinder::Config qw(:all); -use ZoneMinder::Debug qw(:all); +use ZoneMinder::Logger qw(:all); use ZoneMinder::General qw(:all); use ZoneMinder::Database qw(:all); use ZoneMinder::ConfigAdmin qw( :functions ); @@ -68,19 +65,19 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my $web_uid = (getpwnam( ZM_WEB_USER ))[2]; my $use_log = (($> == 0) || ($> == $web_uid)); -zmDbgInit( DBG_ID, level=>DBG_LEVEL, to_log=>$use_log ); -zmDbgSetSignal(); +logInit( toFile=>$use_log?DEBUG:NOLOG ); +logSetSignal(); my $interactive = 1; my $check = 0; my $freshen = 0; my $rename = 0; -my $zone_fix = 0; -my $migrate_events = 0; +my $zoneFix = 0; +my $migrateEvents = 0; my $version = ''; -my $db_user = ZM_DB_USER; -my $db_pass = ZM_DB_PASS; -my $update_dir = ''; +my $dbUser = ZM_DB_USER; +my $dbPass = ZM_DB_PASS; +my $updateDir = ''; sub Usage { print( " @@ -96,12 +93,12 @@ Parameters are :- exit( -1 ); } -if ( !GetOptions( 'check'=>\$check, 'freshen'=>\$freshen, 'rename'=>\$rename, 'zone-fix'=>\$zone_fix, 'migrate-events'=>\$migrate_events, 'version=s'=>\$version, 'interactive!'=>\$interactive, 'user:s'=>\$db_user, 'pass:s'=>\$db_pass, 'dir:s'=>\$update_dir ) ) +if ( !GetOptions( 'check'=>\$check, 'freshen'=>\$freshen, 'rename'=>\$rename, 'zone-fix'=>\$zoneFix, 'migrate-events'=>\$migrateEvents, 'version=s'=>\$version, 'interactive!'=>\$interactive, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'dir:s'=>\$updateDir ) ) { Usage(); } -if ( ! ($check || $freshen || $rename || $zone_fix || $migrate_events || $version) ) +if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) ) { if ( ZM_DYN_DB_VERSION ) { @@ -114,7 +111,7 @@ if ( ! ($check || $freshen || $rename || $zone_fix || $migrate_events || $versio } } -if ( ($check + $freshen + $rename + $zone_fix + $migrate_events + ($version?1:0)) > 1 ) +if ( ($check + $freshen + $rename + $zoneFix + $migrateEvents + ($version?1:0)) > 1 ) { print( STDERR "Please give only one option\n" ); Usage(); @@ -126,25 +123,27 @@ if ( $check && ZM_CHECK_FOR_UPDATES ) my $dbh = zmDbConnect(); - my $curr_version = ZM_DYN_CURR_VERSION; - my $last_version = ZM_DYN_LAST_VERSION; - my $last_check = ZM_DYN_LAST_CHECK; + my $currVersion = ZM_DYN_CURR_VERSION; + my $lastVersion = ZM_DYN_LAST_VERSION; + my $lastCheck = ZM_DYN_LAST_CHECK; - if ( !$curr_version ) + if ( !$currVersion ) { - $curr_version = ZM_VERSION; + $currVersion = ZM_VERSION; my $sql = "update Config set Value = ? where Name = 'ZM_DYN_CURR_VERSION'"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( "$curr_version" ) or die( "Can't execute: ".$sth->errstr() ); + my $res = $sth->execute( "$currVersion" ) or die( "Can't execute: ".$sth->errstr() ); } zmDbDisconnect(); while( 1 ) { my $now = time(); - if ( !$last_version || !$last_check || (($now-$last_check) > CHECK_INTERVAL) ) + if ( !$lastVersion || !$lastCheck || (($now-$lastCheck) > CHECK_INTERVAL) ) { + $dbh = zmDbConnect(); + Info( "Checking for updates\n" ); use LWP::UserAgent; @@ -164,28 +163,25 @@ if ( $check && ZM_CHECK_FOR_UPDATES ) if ( $res->is_success ) { - $last_version = $res->content; - chomp($last_version); - $last_check = $now; + $lastVersion = $res->content; + chomp($lastVersion); + $lastCheck = $now; - Info( "Got version: '".$last_version."'\n" ); - - $dbh = zmDbConnect(); + Info( "Got version: '".$lastVersion."'\n" ); my $lv_sql = "update Config set Value = ? where Name = 'ZM_DYN_LAST_VERSION'"; my $lv_sth = $dbh->prepare_cached( $lv_sql ) or die( "Can't prepare '$lv_sql': ".$dbh->errstr() ); - my $lv_res = $lv_sth->execute( $last_version ) or die( "Can't execute: ".$lv_sth->errstr() ); + my $lv_res = $lv_sth->execute( $lastVersion ) or die( "Can't execute: ".$lv_sth->errstr() ); my $lc_sql = "update Config set Value = ? where Name = 'ZM_DYN_LAST_CHECK'"; my $lc_sth = $dbh->prepare_cached( $lc_sql ) or die( "Can't prepare '$lc_sql': ".$dbh->errstr() ); - my $lc_res = $lc_sth->execute( $last_check ) or die( "Can't execute: ".$lc_sth->errstr() ); - - zmDbDisconnect(); + my $lc_res = $lc_sth->execute( $lastCheck ) or die( "Can't execute: ".$lc_sth->errstr() ); } else { Error( "Error check failed: '".$res->status_line()."'\n" ); } + zmDbDisconnect(); } sleep( 3600 ); } @@ -211,15 +207,15 @@ if ( $rename ) { return; } - my $new_file = "$2-$1$3"; + my $newFile = "$2-$1$3"; - print( "Renaming '$file' to '$new_file'\n" ); - rename( $file, $new_file ) or warn( "Can't rename '$file' to '$new_file'" ); + print( "Renaming '$file' to '$newFile'\n" ); + rename( $file, $newFile ) or warn( "Can't rename '$file' to '$newFile'" ); } File::Find::find( \&renameImage, '.' ); } -if ( $zone_fix ) +if ( $zoneFix ) { require DBI; @@ -254,7 +250,7 @@ if ( $zone_fix ) ) or die( "Can't execute: ".$sth->errstr() ); } } -if ( $migrate_events ) +if ( $migrateEvents ) { my $webUid = (getpwnam( ZM_WEB_USER ))[2]; my $webGid = (getgrnam( ZM_WEB_USER ))[2]; @@ -372,21 +368,21 @@ if ( $version ) my ( $host, $port ) = ( ZM_DB_HOST =~ /^([^:]+)(?::(.+))?$/ ); my $command = "mysqldump -h".$host; $command .= " -P".$port if defined($port); - if ( $db_user ) + if ( $dbUser ) { - $command .= " -u".$db_user; - if ( $db_pass ) + $command .= " -u".$dbUser; + if ( $dbPass ) { - $command .= " -p".$db_pass; + $command .= " -p".$dbPass; } } my $backup = "@ZM_TMPDIR@/".ZM_DB_NAME."-".$version.".dump"; $command .= " --add-drop-table --databases ".ZM_DB_NAME." > ".$backup; print( "Creating backup to $backup. This may take several minutes.\n" ); - print( "Executing '$command'\n" ) if ( DBG_LEVEL > 0 ); + print( "Executing '$command'\n" ) if ( logDebugging() ); my $output = qx($command); my $status = $? >> 8; - if ( $status || DBG_LEVEL > 0 ) + if ( $status || logDebugging() ) { chomp( $output ); print( "Output: $output\n" ); @@ -413,18 +409,18 @@ if ( $version ) my ( $host, $port ) = ( ZM_DB_HOST =~ /^([^:]+)(?::(.+))?$/ ); my $command = "mysql -h".$host; $command .= " -P".$port if defined($port); - if ( $db_user ) + if ( $dbUser ) { - $command .= " -u".$db_user; - if ( $db_pass ) + $command .= " -u".$dbUser; + if ( $dbPass ) { - $command .= " -p".$db_pass; + $command .= " -p".$dbPass; } } $command .= " ".ZM_DB_NAME." < "; - if ( $update_dir ) + if ( $updateDir ) { - $command -= $update_dir; + $command -= $updateDir; } else { @@ -432,10 +428,10 @@ if ( $version ) } $command .= "/zm_update-".$version.".sql"; - print( "Executing '$command'\n" ) if ( DBG_LEVEL > 0 ); + print( "Executing '$command'\n" ) if ( logDebugging() ); my $output = qx($command); my $status = $? >> 8; - if ( $status || DBG_LEVEL > 0 ) + if ( $status || logDebugging() ) { chomp( $output ); print( "Output: $output\n" ); @@ -603,8 +599,8 @@ if ( $version ) { if ( $filter->{Query} =~ /op\d=&/ ) { - ( my $new_query = $filter->{Query} ) =~ s/(op\d=)&/$1=&/g; - $res = $sth->execute( $new_query, $filter->{Name} ) or die( "Can't execute: ".$sth->errstr() ); + ( my $newQuery = $filter->{Query} ) =~ s/(op\d=)&/$1=&/g; + $res = $sth->execute( $newQuery, $filter->{Name} ) or die( "Can't execute: ".$sth->errstr() ); } } } @@ -643,14 +639,14 @@ if ( $version ) } else { - my $lo_x = ($zone->{LoX} * ($zone->{Width}-1) ) / 100; - my $hi_x = ($zone->{HiX} * ($zone->{Width}-1) ) / 100; - my $lo_y = ($zone->{LoY} * ($zone->{Height}-1) ) / 100; - my $hi_y = ($zone->{HiY} * ($zone->{Height}-1) ) / 100; - my $area = (($hi_x-$lo_x)+1)*(($hi_y-$lo_y)+1); + my $loX = ($zone->{LoX} * ($zone->{Width}-1) ) / 100; + my $hiX = ($zone->{HiX} * ($zone->{Width}-1) ) / 100; + my $loY = ($zone->{LoY} * ($zone->{Height}-1) ) / 100; + my $hiY = ($zone->{HiY} * ($zone->{Height}-1) ) / 100; + my $area = (($hiX-$loX)+1)*(($hiY-$loY)+1); my $sql = "update Zones set NumCoords = 4, Coords = concat( round(?),',',round(?),' ',round(?),',',round(?),' ',round(?),',',round(?),' ',round(?),',',round(?) ), Area = round(?), MinAlarmPixels = round(?), MaxAlarmPixels = round(?), MinFilterPixels = round(?), MaxFilterPixels = round(?), MinBlobPixels = round(?), MaxBlobPixels = round(?) where Id = ?"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $lo_x, $lo_y, $hi_x, $lo_y, $hi_x, $hi_y, $lo_x, $hi_y, $area, ($zone->{MinAlarmPixels}*$area)/100, ($zone->{MaxAlarmPixels}*$area)/100, ($zone->{MinFilterPixels}*$area)/100, ($zone->{MaxFilterPixels}*$area)/100, ($zone->{MinBlobPixels}*$area)/100, ($zone->{MaxBlobPixels}*$area)/100, $zone->{Id} ) or die( "Can't execute: ".$sth->errstr() ); + my $res = $sth->execute( $loX, $loY, $hiX, $loY, $hiX, $hiY, $loX, $hiY, $area, ($zone->{MinAlarmPixels}*$area)/100, ($zone->{MaxAlarmPixels}*$area)/100, ($zone->{MinFilterPixels}*$area)/100, ($zone->{MaxFilterPixels}*$area)/100, ($zone->{MinBlobPixels}*$area)/100, ($zone->{MaxBlobPixels}*$area)/100, $zone->{Id} ) or die( "Can't execute: ".$sth->errstr() ); } } } @@ -780,16 +776,16 @@ if ( $version ) my $sql = "select * from Filters"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); - my @db_filters; - while( my $db_filter = $sth->fetchrow_hashref() ) + my @dbFilters; + while( my $dbFilter = $sth->fetchrow_hashref() ) { - push( @db_filters, $db_filter ); + push( @dbFilters, $dbFilter ); } $sth->finish(); - foreach my $db_filter ( @db_filters ) + foreach my $dbFilter ( @dbFilters ) { my %filter_terms; - foreach my $filter_parm ( split( '&', $db_filter->{Query} ) ) + foreach my $filter_parm ( split( '&', $dbFilter->{Query} ) ) { my( $key, $value ) = split( '=', $filter_parm, 2 ); if ( $key ) @@ -820,33 +816,33 @@ if ( $version ) $filter->{sort_asc} = $filter_terms{sort_asc} if ( $filter_terms{sort_asc} ); $filter->{limit} = $filter_terms{limit} if ( $filter_terms{limit} ); - my $new_query = 'a:'.int(keys(%$filter)).':{s:5:"terms";a:'.int(@{$filter->{terms}}).':{'; + my $newQuery = 'a:'.int(keys(%$filter)).':{s:5:"terms";a:'.int(@{$filter->{terms}}).':{'; my $i = 0; foreach my $term ( @{$filter->{terms}} ) { - $new_query .= 'i:'.$i.';a:'.int(keys(%$term)).':{'; + $newQuery .= 'i:'.$i.';a:'.int(keys(%$term)).':{'; while ( my ( $key, $val ) = each( %$term ) ) { - $new_query .= 's:'.length($key).':"'.$key.'";'; - $new_query .= 's:'.length($val).':"'.$val.'";'; + $newQuery .= 's:'.length($key).':"'.$key.'";'; + $newQuery .= 's:'.length($val).':"'.$val.'";'; } - $new_query .= '}'; + $newQuery .= '}'; $i++; } - $new_query .= '}'; + $newQuery .= '}'; foreach my $field ( "sort_field", "sort_asc", "limit" ) { if ( defined($filter->{$field}) ) { - $new_query .= 's:'.length($field).':"'.$field.'";'; - $new_query .= 's:'.length($filter->{$field}).':"'.$filter->{$field}.'";'; + $newQuery .= 's:'.length($field).':"'.$field.'";'; + $newQuery .= 's:'.length($filter->{$field}).':"'.$filter->{$field}.'";'; } } - $new_query .= '}'; + $newQuery .= '}'; my $sql = "update Filters set Query = ? where Name = ?"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $new_query, $db_filter->{Name} ) or die( "Can't execute: ".$sth->errstr() ); + my $res = $sth->execute( $newQuery, $dbFilter->{Name} ) or die( "Can't execute: ".$sth->errstr() ); } } @@ -951,6 +947,12 @@ if ( $version ) } $cascade = !undef; } + if ( $cascade || $version eq "1.24.4" ) + { + # Patch the database + patchDB( $dbh, "1.24.4" ); + $cascade = !undef; + } if ( $cascade ) { my $installed_version = ZM_VERSION; diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index 1504e97ab..73f6a6c1a 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -27,15 +27,6 @@ use strict; use bytes; -# ========================================================================== -# -# These are the elements you can edit to suit your installation -# -# ========================================================================== - -use constant DBG_ID => "zmvideo"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - # ========================================================================== # # You shouldn't need to change anything from here downwards @@ -55,7 +46,7 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); +logInit(); my $event_id; my $format = 'mpg'; diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 7df3b10b7..4d50f0496 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -34,9 +34,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmwatch"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant START_DELAY => 30; # To give everything else time to start # ========================================================================== @@ -65,8 +62,8 @@ Usage: zmwatch.pl exit( -1 ); } -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); -zmDbgSetSignal(); +logInit(); +logSetSignal(); Info( "Watchdog starting\n" ); Info( "Watchdog pausing for ".START_DELAY." seconds\n" ); diff --git a/scripts/zmx10.pl.in b/scripts/zmx10.pl.in index 7912b6e9d..aec69d193 100644 --- a/scripts/zmx10.pl.in +++ b/scripts/zmx10.pl.in @@ -33,9 +33,6 @@ use bytes; # # ========================================================================== -use constant DBG_ID => "zmx10"; # Tag that appears in debug to identify source -use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug - use constant CAUSE_STRING => "X10"; # What gets written as the cause of any events # ========================================================================== @@ -70,8 +67,8 @@ Parameters are :- exit( -1 ); } -zmDbgInit( DBG_ID, level=>DBG_LEVEL ); -zmDbgSetSignal(); +logInit(); +logSetSignal(); my $command; my $unit_code; @@ -206,7 +203,7 @@ sub runServer { if ( $unit_code < 1 || $unit_code > 16 ) { - dPrint( DBG_ERROR, "Invalid unit code '$unit_code'\n" ); + dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" ); next; } @@ -238,14 +235,14 @@ sub runServer { if ( $device ) { - dPrint( DBG_DEBUG, $unit_code." ".$device->{status}."\n" ); + dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); } else { foreach my $unit_code ( sort( keys(%device_hash) ) ) { my $device = $device_hash{$unit_code}; - dPrint( DBG_DEBUG, $unit_code." ".$device->{status}."\n" ); + dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); } } } @@ -255,19 +252,19 @@ sub runServer } else { - dPrint( DBG_ERROR, "Invalid command '$command'\n" ); + dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); } if ( defined($result) ) { if ( 1 || $result ) { $device->{status} = uc($command); - dPrint( DBG_DEBUG, $device->{appliance}->address()." $command, ok\n" ); + dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); } else { - dPrint( DBG_ERROR, $device->{appliance}->address()." $command, failed\n" ); + dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); } } close( CLIENT ); @@ -623,23 +620,23 @@ sub dPrint { print CLIENT @_ } - if ( $dbg_level == DBG_DEBUG ) + if ( $dbg_level == ZoneMinder::Logger::DEBUG ) { Debug( @_ ); } - elsif ( $dbg_level == DBG_INFO ) + elsif ( $dbg_level == ZoneMinder::Logger::INFO ) { Info( @_ ); } - elsif ( $dbg_level == DBG_WARNING ) + elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) { Warning( @_ ); } - elsif ( $dbg_level == DBG_ERROR ) + elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) { Error( @_ ); } - elsif ( $dbg_level == DBG_FATAL ) + elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) { Fatal( @_ ); } diff --git a/src/Makefile.am b/src/Makefile.am index 7cecda6f0..abf6f90a3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,13 +29,13 @@ zm_SOURCES = \ zm_coord.cpp \ zm.cpp \ zm_db.cpp \ - zm_debug.c \ + zm_logger.cpp \ zm_event.cpp \ zm_exception.cpp \ zm_file_camera.cpp \ zm_ffmpeg_camera.cpp \ zm_image.cpp \ - zm_jpeg.c \ + zm_jpeg.cpp \ zm_local_camera.cpp \ zm_monitor.cpp \ zm_ffmpeg.cpp \ @@ -66,7 +66,7 @@ zms_SOURCES = zms.cpp $(zm_SOURCES) zmu_SOURCES = zmu.cpp $(zm_SOURCES) zmf_SOURCES = zmf.cpp $(zm_SOURCES) zmstreamer_SOURCES = zmstreamer.cpp $(zm_SOURCES) -zmfix_SOURCES = zmfix.cpp zm_config.cpp zm_regexp.cpp zm_debug.c zm_db.cpp zm.cpp +zmfix_SOURCES = zmfix.cpp zm_config.cpp zm_regexp.cpp zm_logger.cpp zm_utils.cpp zm_db.cpp zm.cpp noinst_HEADERS = \ jinclude.h \ @@ -78,7 +78,7 @@ noinst_HEADERS = \ zm_config.h \ zm_coord.h \ zm_db.h \ - zm_debug.h \ + zm_logger.h \ zm_event.h \ zm_exception.h \ zmf.h \ diff --git a/src/Makefile.in b/src/Makefile.in index bb4cdf85c..b8a76ebdb 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -52,7 +52,7 @@ PROGRAMS = $(bin_PROGRAMS) am__objects_1 = zm_box.$(OBJEXT) zm_buffer.$(OBJEXT) \ zm_camera.$(OBJEXT) zm_comms.$(OBJEXT) zm_config.$(OBJEXT) \ zm_coord.$(OBJEXT) zm.$(OBJEXT) zm_db.$(OBJEXT) \ - zm_debug.$(OBJEXT) zm_event.$(OBJEXT) zm_exception.$(OBJEXT) \ + zm_logger.$(OBJEXT) zm_event.$(OBJEXT) zm_exception.$(OBJEXT) \ zm_file_camera.$(OBJEXT) zm_ffmpeg_camera.$(OBJEXT) \ zm_image.$(OBJEXT) zm_jpeg.$(OBJEXT) zm_local_camera.$(OBJEXT) \ zm_monitor.$(OBJEXT) zm_ffmpeg.$(OBJEXT) zm_mpeg.$(OBJEXT) \ @@ -74,8 +74,8 @@ am_zmf_OBJECTS = zmf.$(OBJEXT) $(am__objects_1) zmf_OBJECTS = $(am_zmf_OBJECTS) zmf_LDADD = $(LDADD) am_zmfix_OBJECTS = zmfix.$(OBJEXT) zm_config.$(OBJEXT) \ - zm_regexp.$(OBJEXT) zm_debug.$(OBJEXT) zm_db.$(OBJEXT) \ - zm.$(OBJEXT) + zm_regexp.$(OBJEXT) zm_logger.$(OBJEXT) zm_utils.$(OBJEXT) \ + zm_db.$(OBJEXT) zm.$(OBJEXT) zmfix_OBJECTS = $(am_zmfix_OBJECTS) zmfix_LDADD = $(LDADD) am_zms_OBJECTS = zms.$(OBJEXT) $(am__objects_1) @@ -91,10 +91,6 @@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) @@ -264,13 +260,13 @@ zm_SOURCES = \ zm_coord.cpp \ zm.cpp \ zm_db.cpp \ - zm_debug.c \ + zm_logger.cpp \ zm_event.cpp \ zm_exception.cpp \ zm_file_camera.cpp \ zm_ffmpeg_camera.cpp \ zm_image.cpp \ - zm_jpeg.c \ + zm_jpeg.cpp \ zm_local_camera.cpp \ zm_monitor.cpp \ zm_ffmpeg.cpp \ @@ -301,7 +297,7 @@ zms_SOURCES = zms.cpp $(zm_SOURCES) zmu_SOURCES = zmu.cpp $(zm_SOURCES) zmf_SOURCES = zmf.cpp $(zm_SOURCES) zmstreamer_SOURCES = zmstreamer.cpp $(zm_SOURCES) -zmfix_SOURCES = zmfix.cpp zm_config.cpp zm_regexp.cpp zm_debug.c zm_db.cpp zm.cpp +zmfix_SOURCES = zmfix.cpp zm_config.cpp zm_regexp.cpp zm_logger.cpp zm_utils.cpp zm_db.cpp zm.cpp noinst_HEADERS = \ jinclude.h \ zm_box.h \ @@ -312,7 +308,7 @@ noinst_HEADERS = \ zm_config.h \ zm_coord.h \ zm_db.h \ - zm_debug.h \ + zm_logger.h \ zm_event.h \ zm_exception.h \ zmf.h \ @@ -356,7 +352,7 @@ EXTRA_DIST = \ all: all-am .SUFFIXES: -.SUFFIXES: .c .cpp .o .obj +.SUFFIXES: .cpp .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -462,7 +458,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_coord.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_db.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_exception.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_ffmpeg.Po@am__quote@ @@ -471,6 +466,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_jpeg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_local_camera.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_logger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_monitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_mpeg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zm_poly.Po@am__quote@ @@ -500,20 +496,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zmstreamer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zmu.Po@am__quote@ -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po diff --git a/src/zm.h b/src/zm.h index aa87368d2..914a1aae1 100644 --- a/src/zm.h +++ b/src/zm.h @@ -20,12 +20,8 @@ #ifndef ZM_H #define ZM_H -extern "C" -{ -#include "zm_debug.h" -} - #include "zm_config.h" +#include "zm_logger.h" extern "C" { diff --git a/src/zm_comms.cpp b/src/zm_comms.cpp index 87395dd33..b30bed1d5 100644 --- a/src/zm_comms.cpp +++ b/src/zm_comms.cpp @@ -19,7 +19,7 @@ #include "zm_comms.h" -#include "zm_debug.h" +#include "zm_logger.h" #include #include diff --git a/src/zm_config.cpp b/src/zm_config.cpp index fc9dab9cc..2b54cfeb1 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -17,13 +17,14 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // -#include -#include -#include - #include "zm.h" #include "zm_db.h" +#include +#include +#include +#include + void zmLoadConfig() { FILE *cfg; @@ -31,7 +32,7 @@ void zmLoadConfig() char *val; if ( (cfg = fopen( ZM_CONFIG, "r")) == NULL ) { - Fatal("Can't open %s: %s", ZM_CONFIG, strerror(errno) ); + Fatal( "Can't open %s: %s", ZM_CONFIG, strerror(errno) ); } while ( fgets( line, sizeof(line), cfg ) != NULL ) { @@ -270,26 +271,6 @@ void Config::Load() void Config::Assign() { ZM_CFG_ASSIGN_LIST - - if ( extra_debug ) - { - static char extra_level_env[PATH_MAX] = ""; - static char extra_log_env[PATH_MAX] = ""; - - snprintf( extra_level_env, sizeof(extra_level_env), "ZM_DBG_LEVEL%s=%d", extra_debug_target, extra_debug_level ); - if ( putenv( extra_level_env ) < 0 ) - { - Error("Can't putenv %s: %s", extra_level_env, strerror(errno) ); - } - - snprintf( extra_log_env, sizeof(extra_log_env), "ZM_DBG_LOG%s=%s", extra_debug_target, extra_debug_log ); - if ( putenv( extra_log_env ) < 0 ) - { - Error("Can't putenv %s: %s", extra_log_env, strerror(errno) ); - } - - zmDbgReinit( extra_debug_target ); - } } const ConfigItem &Config::Item( int id ) diff --git a/src/zm_config.h.in b/src/zm_config.h.in index 2c9ec4d7f..a048b6e3d 100644 --- a/src/zm_config.h.in +++ b/src/zm_config.h.in @@ -17,6 +17,9 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +#ifndef ZM_CONFIG_H +#define ZM_CONFIG_H + #include "config.h" #include "zm_config_defines.h" @@ -128,3 +131,5 @@ public: }; extern Config config; + +#endif // ZM_CONFIG_H diff --git a/src/zm_config_defines.h b/src/zm_config_defines.h index 33199609f..45cb8dd04 100644 --- a/src/zm_config_defines.h +++ b/src/zm_config_defines.h @@ -45,162 +45,174 @@ #define ZM_FFMPEG_INPUT_OPTIONS 41 #define ZM_FFMPEG_OUTPUT_OPTIONS 42 #define ZM_FFMPEG_FORMATS 43 -#define ZM_RECORD_EVENT_STATS 44 -#define ZM_RECORD_DIAG_IMAGES 45 -#define ZM_EXTRA_DEBUG 46 -#define ZM_EXTRA_DEBUG_TARGET 47 -#define ZM_EXTRA_DEBUG_LEVEL 48 -#define ZM_EXTRA_DEBUG_LOG 49 -#define ZM_DUMP_CORES 50 -#define ZM_PATH_MAP 51 -#define ZM_PATH_SOCKS 52 -#define ZM_PATH_LOGS 53 -#define ZM_PATH_SWAP 54 -#define ZM_WEB_TITLE_PREFIX 55 -#define ZM_WEB_RESIZE_CONSOLE 56 -#define ZM_WEB_POPUP_ON_ALARM 57 -#define ZM_OPT_X10 58 -#define ZM_X10_DEVICE 59 -#define ZM_X10_HOUSE_CODE 60 -#define ZM_X10_DB_RELOAD_INTERVAL 61 -#define ZM_WEB_SOUND_ON_ALARM 62 -#define ZM_WEB_ALARM_SOUND 63 -#define ZM_WEB_COMPACT_MONTAGE 64 -#define ZM_OPT_FAST_DELETE 65 -#define ZM_STRICT_VIDEO_CONFIG 66 -#define ZM_V4L2_CAPTURE_FIELDS 67 -#define ZM_SIGNAL_CHECK_POINTS 68 -#define ZM_V4L_MULTI_BUFFER 69 -#define ZM_CAPTURES_PER_FRAME 70 -#define ZM_FILTER_RELOAD_DELAY 71 -#define ZM_FILTER_EXECUTE_INTERVAL 72 -#define ZM_OPT_UPLOAD 73 -#define ZM_UPLOAD_ARCH_FORMAT 74 -#define ZM_UPLOAD_ARCH_COMPRESS 75 -#define ZM_UPLOAD_ARCH_ANALYSE 76 -#define ZM_UPLOAD_FTP_HOST 77 -#define ZM_UPLOAD_FTP_USER 78 -#define ZM_UPLOAD_FTP_PASS 79 -#define ZM_UPLOAD_FTP_LOC_DIR 80 -#define ZM_UPLOAD_FTP_REM_DIR 81 -#define ZM_UPLOAD_FTP_TIMEOUT 82 -#define ZM_UPLOAD_FTP_PASSIVE 83 -#define ZM_UPLOAD_FTP_DEBUG 84 -#define ZM_OPT_EMAIL 85 -#define ZM_EMAIL_ADDRESS 86 -#define ZM_EMAIL_TEXT 87 -#define ZM_EMAIL_SUBJECT 88 -#define ZM_EMAIL_BODY 89 -#define ZM_OPT_MESSAGE 90 -#define ZM_MESSAGE_ADDRESS 91 -#define ZM_MESSAGE_TEXT 92 -#define ZM_MESSAGE_SUBJECT 93 -#define ZM_MESSAGE_BODY 94 -#define ZM_NEW_MAIL_MODULES 95 -#define ZM_EMAIL_HOST 96 -#define ZM_FROM_EMAIL 97 -#define ZM_URL 98 -#define ZM_MAX_RESTART_DELAY 99 -#define ZM_WATCH_CHECK_INTERVAL 100 -#define ZM_WATCH_MAX_DELAY 101 -#define ZM_RUN_AUDIT 102 -#define ZM_AUDIT_CHECK_INTERVAL 103 -#define ZM_FORCED_ALARM_SCORE 104 -#define ZM_BULK_FRAME_INTERVAL 105 -#define ZM_EVENT_CLOSE_MODE 106 -#define ZM_FORCE_CLOSE_EVENTS 107 -#define ZM_CREATE_ANALYSIS_IMAGES 108 -#define ZM_WEIGHTED_ALARM_CENTRES 109 -#define ZM_EVENT_IMAGE_DIGITS 110 -#define ZM_DEFAULT_ASPECT_RATIO 111 -#define ZM_USER_SELF_EDIT 112 -#define ZM_OPT_FRAME_SERVER 113 -#define ZM_FRAME_SOCKET_SIZE 114 -#define ZM_OPT_CONTROL 115 -#define ZM_OPT_TRIGGERS 116 -#define ZM_CHECK_FOR_UPDATES 117 -#define ZM_UPDATE_CHECK_PROXY 118 -#define ZM_SHM_KEY 119 -#define ZM_WEB_REFRESH_METHOD 120 -#define ZM_WEB_EVENT_SORT_FIELD 121 -#define ZM_WEB_EVENT_SORT_ORDER 122 -#define ZM_WEB_EVENTS_PER_PAGE 123 -#define ZM_WEB_LIST_THUMBS 124 -#define ZM_WEB_LIST_THUMB_WIDTH 125 -#define ZM_WEB_LIST_THUMB_HEIGHT 126 -#define ZM_WEB_USE_OBJECT_TAGS 127 -#define ZM_WEB_H_REFRESH_MAIN 128 -#define ZM_WEB_H_REFRESH_CYCLE 129 -#define ZM_WEB_H_REFRESH_IMAGE 130 -#define ZM_WEB_H_REFRESH_STATUS 131 -#define ZM_WEB_H_REFRESH_EVENTS 132 -#define ZM_WEB_H_CAN_STREAM 133 -#define ZM_WEB_H_STREAM_METHOD 134 -#define ZM_WEB_H_DEFAULT_SCALE 135 -#define ZM_WEB_H_DEFAULT_RATE 136 -#define ZM_WEB_H_VIDEO_BITRATE 137 -#define ZM_WEB_H_VIDEO_MAXFPS 138 -#define ZM_WEB_H_SCALE_THUMBS 139 -#define ZM_WEB_H_EVENTS_VIEW 140 -#define ZM_WEB_H_SHOW_PROGRESS 141 -#define ZM_WEB_H_AJAX_TIMEOUT 142 -#define ZM_WEB_M_REFRESH_MAIN 143 -#define ZM_WEB_M_REFRESH_CYCLE 144 -#define ZM_WEB_M_REFRESH_IMAGE 145 -#define ZM_WEB_M_REFRESH_STATUS 146 -#define ZM_WEB_M_REFRESH_EVENTS 147 -#define ZM_WEB_M_CAN_STREAM 148 -#define ZM_WEB_M_STREAM_METHOD 149 -#define ZM_WEB_M_DEFAULT_SCALE 150 -#define ZM_WEB_M_DEFAULT_RATE 151 -#define ZM_WEB_M_VIDEO_BITRATE 152 -#define ZM_WEB_M_VIDEO_MAXFPS 153 -#define ZM_WEB_M_SCALE_THUMBS 154 -#define ZM_WEB_M_EVENTS_VIEW 155 -#define ZM_WEB_M_SHOW_PROGRESS 156 -#define ZM_WEB_M_AJAX_TIMEOUT 157 -#define ZM_WEB_L_REFRESH_MAIN 158 -#define ZM_WEB_L_REFRESH_CYCLE 159 -#define ZM_WEB_L_REFRESH_IMAGE 160 -#define ZM_WEB_L_REFRESH_STATUS 161 -#define ZM_WEB_L_REFRESH_EVENTS 162 -#define ZM_WEB_L_CAN_STREAM 163 -#define ZM_WEB_L_STREAM_METHOD 164 -#define ZM_WEB_L_DEFAULT_SCALE 165 -#define ZM_WEB_L_DEFAULT_RATE 166 -#define ZM_WEB_L_VIDEO_BITRATE 167 -#define ZM_WEB_L_VIDEO_MAXFPS 168 -#define ZM_WEB_L_SCALE_THUMBS 169 -#define ZM_WEB_L_EVENTS_VIEW 170 -#define ZM_WEB_L_SHOW_PROGRESS 171 -#define ZM_WEB_L_AJAX_TIMEOUT 172 -#define ZM_WEB_P_CAN_STREAM 173 -#define ZM_WEB_P_STREAM_METHOD 174 -#define ZM_WEB_P_DEFAULT_SCALE 175 -#define ZM_WEB_P_DEFAULT_RATE 176 -#define ZM_WEB_P_VIDEO_BITRATE 177 -#define ZM_WEB_P_VIDEO_MAXFPS 178 -#define ZM_WEB_P_SCALE_THUMBS 179 -#define ZM_WEB_P_AJAX_TIMEOUT 180 -#define ZM_DYN_LAST_VERSION 181 -#define ZM_DYN_CURR_VERSION 182 -#define ZM_DYN_DB_VERSION 183 -#define ZM_DYN_LAST_CHECK 184 -#define ZM_DYN_NEXT_REMINDER 185 -#define ZM_DYN_DONATE_REMINDER_TIME 186 -#define ZM_DYN_SHOW_DONATE_REMINDER 187 -#define ZM_EYEZM_DEBUG 188 -#define ZM_EYEZM_LOG_TO_FILE 189 -#define ZM_EYEZM_LOG_FILE 190 -#define ZM_EYEZM_EVENT_VCODEC 191 -#define ZM_EYEZM_FEED_VCODEC 192 -#define ZM_EYEZM_H264_DEFAULT_BR 193 -#define ZM_EYEZM_H264_DEFAULT_EVBR 194 -#define ZM_EYEZM_H264_TIMEOUT 195 -#define ZM_EYEZM_SEG_DURATION 196 +#define ZM_LOG_LEVEL_SYSLOG 44 +#define ZM_LOG_LEVEL_FILE 45 +#define ZM_LOG_LEVEL_WEBLOG 46 +#define ZM_LOG_LEVEL_DATABASE 47 +#define ZM_LOG_DATABASE_LIMIT 48 +#define ZM_LOG_DEBUG 49 +#define ZM_LOG_DEBUG_TARGET 50 +#define ZM_LOG_DEBUG_LEVEL 51 +#define ZM_LOG_DEBUG_FILE 52 +#define ZM_LOG_CHECK_PERIOD 53 +#define ZM_LOG_ALERT_WAR_COUNT 54 +#define ZM_LOG_ALERT_ERR_COUNT 55 +#define ZM_LOG_ALERT_FAT_COUNT 56 +#define ZM_LOG_ALARM_WAR_COUNT 57 +#define ZM_LOG_ALARM_ERR_COUNT 58 +#define ZM_LOG_ALARM_FAT_COUNT 59 +#define ZM_RECORD_EVENT_STATS 60 +#define ZM_RECORD_DIAG_IMAGES 61 +#define ZM_DUMP_CORES 62 +#define ZM_PATH_MAP 63 +#define ZM_PATH_SOCKS 64 +#define ZM_PATH_LOGS 65 +#define ZM_PATH_SWAP 66 +#define ZM_WEB_TITLE_PREFIX 67 +#define ZM_WEB_RESIZE_CONSOLE 68 +#define ZM_WEB_POPUP_ON_ALARM 69 +#define ZM_OPT_X10 70 +#define ZM_X10_DEVICE 71 +#define ZM_X10_HOUSE_CODE 72 +#define ZM_X10_DB_RELOAD_INTERVAL 73 +#define ZM_WEB_SOUND_ON_ALARM 74 +#define ZM_WEB_ALARM_SOUND 75 +#define ZM_WEB_COMPACT_MONTAGE 76 +#define ZM_OPT_FAST_DELETE 77 +#define ZM_STRICT_VIDEO_CONFIG 78 +#define ZM_V4L2_CAPTURE_FIELDS 79 +#define ZM_SIGNAL_CHECK_POINTS 80 +#define ZM_V4L_MULTI_BUFFER 81 +#define ZM_CAPTURES_PER_FRAME 82 +#define ZM_FILTER_RELOAD_DELAY 83 +#define ZM_FILTER_EXECUTE_INTERVAL 84 +#define ZM_OPT_UPLOAD 85 +#define ZM_UPLOAD_ARCH_FORMAT 86 +#define ZM_UPLOAD_ARCH_COMPRESS 87 +#define ZM_UPLOAD_ARCH_ANALYSE 88 +#define ZM_UPLOAD_FTP_HOST 89 +#define ZM_UPLOAD_FTP_USER 90 +#define ZM_UPLOAD_FTP_PASS 91 +#define ZM_UPLOAD_FTP_LOC_DIR 92 +#define ZM_UPLOAD_FTP_REM_DIR 93 +#define ZM_UPLOAD_FTP_TIMEOUT 94 +#define ZM_UPLOAD_FTP_PASSIVE 95 +#define ZM_UPLOAD_FTP_DEBUG 96 +#define ZM_OPT_EMAIL 97 +#define ZM_EMAIL_ADDRESS 98 +#define ZM_EMAIL_TEXT 99 +#define ZM_EMAIL_SUBJECT 100 +#define ZM_EMAIL_BODY 101 +#define ZM_OPT_MESSAGE 102 +#define ZM_MESSAGE_ADDRESS 103 +#define ZM_MESSAGE_TEXT 104 +#define ZM_MESSAGE_SUBJECT 105 +#define ZM_MESSAGE_BODY 106 +#define ZM_NEW_MAIL_MODULES 107 +#define ZM_EMAIL_HOST 108 +#define ZM_FROM_EMAIL 109 +#define ZM_URL 110 +#define ZM_MAX_RESTART_DELAY 111 +#define ZM_WATCH_CHECK_INTERVAL 112 +#define ZM_WATCH_MAX_DELAY 113 +#define ZM_RUN_AUDIT 114 +#define ZM_AUDIT_CHECK_INTERVAL 115 +#define ZM_FORCED_ALARM_SCORE 116 +#define ZM_BULK_FRAME_INTERVAL 117 +#define ZM_EVENT_CLOSE_MODE 118 +#define ZM_FORCE_CLOSE_EVENTS 119 +#define ZM_CREATE_ANALYSIS_IMAGES 120 +#define ZM_WEIGHTED_ALARM_CENTRES 121 +#define ZM_EVENT_IMAGE_DIGITS 122 +#define ZM_DEFAULT_ASPECT_RATIO 123 +#define ZM_USER_SELF_EDIT 124 +#define ZM_OPT_FRAME_SERVER 125 +#define ZM_FRAME_SOCKET_SIZE 126 +#define ZM_OPT_CONTROL 127 +#define ZM_OPT_TRIGGERS 128 +#define ZM_CHECK_FOR_UPDATES 129 +#define ZM_UPDATE_CHECK_PROXY 130 +#define ZM_SHM_KEY 131 +#define ZM_WEB_REFRESH_METHOD 132 +#define ZM_WEB_EVENT_SORT_FIELD 133 +#define ZM_WEB_EVENT_SORT_ORDER 134 +#define ZM_WEB_EVENTS_PER_PAGE 135 +#define ZM_WEB_LIST_THUMBS 136 +#define ZM_WEB_LIST_THUMB_WIDTH 137 +#define ZM_WEB_LIST_THUMB_HEIGHT 138 +#define ZM_WEB_USE_OBJECT_TAGS 139 +#define ZM_WEB_H_REFRESH_MAIN 140 +#define ZM_WEB_H_REFRESH_CYCLE 141 +#define ZM_WEB_H_REFRESH_IMAGE 142 +#define ZM_WEB_H_REFRESH_STATUS 143 +#define ZM_WEB_H_REFRESH_EVENTS 144 +#define ZM_WEB_H_CAN_STREAM 145 +#define ZM_WEB_H_STREAM_METHOD 146 +#define ZM_WEB_H_DEFAULT_SCALE 147 +#define ZM_WEB_H_DEFAULT_RATE 148 +#define ZM_WEB_H_VIDEO_BITRATE 149 +#define ZM_WEB_H_VIDEO_MAXFPS 150 +#define ZM_WEB_H_SCALE_THUMBS 151 +#define ZM_WEB_H_EVENTS_VIEW 152 +#define ZM_WEB_H_SHOW_PROGRESS 153 +#define ZM_WEB_H_AJAX_TIMEOUT 154 +#define ZM_WEB_M_REFRESH_MAIN 155 +#define ZM_WEB_M_REFRESH_CYCLE 156 +#define ZM_WEB_M_REFRESH_IMAGE 157 +#define ZM_WEB_M_REFRESH_STATUS 158 +#define ZM_WEB_M_REFRESH_EVENTS 159 +#define ZM_WEB_M_CAN_STREAM 160 +#define ZM_WEB_M_STREAM_METHOD 161 +#define ZM_WEB_M_DEFAULT_SCALE 162 +#define ZM_WEB_M_DEFAULT_RATE 163 +#define ZM_WEB_M_VIDEO_BITRATE 164 +#define ZM_WEB_M_VIDEO_MAXFPS 165 +#define ZM_WEB_M_SCALE_THUMBS 166 +#define ZM_WEB_M_EVENTS_VIEW 167 +#define ZM_WEB_M_SHOW_PROGRESS 168 +#define ZM_WEB_M_AJAX_TIMEOUT 169 +#define ZM_WEB_L_REFRESH_MAIN 170 +#define ZM_WEB_L_REFRESH_CYCLE 171 +#define ZM_WEB_L_REFRESH_IMAGE 172 +#define ZM_WEB_L_REFRESH_STATUS 173 +#define ZM_WEB_L_REFRESH_EVENTS 174 +#define ZM_WEB_L_CAN_STREAM 175 +#define ZM_WEB_L_STREAM_METHOD 176 +#define ZM_WEB_L_DEFAULT_SCALE 177 +#define ZM_WEB_L_DEFAULT_RATE 178 +#define ZM_WEB_L_VIDEO_BITRATE 179 +#define ZM_WEB_L_VIDEO_MAXFPS 180 +#define ZM_WEB_L_SCALE_THUMBS 181 +#define ZM_WEB_L_EVENTS_VIEW 182 +#define ZM_WEB_L_SHOW_PROGRESS 183 +#define ZM_WEB_L_AJAX_TIMEOUT 184 +#define ZM_WEB_P_CAN_STREAM 185 +#define ZM_WEB_P_STREAM_METHOD 186 +#define ZM_WEB_P_DEFAULT_SCALE 187 +#define ZM_WEB_P_DEFAULT_RATE 188 +#define ZM_WEB_P_VIDEO_BITRATE 189 +#define ZM_WEB_P_VIDEO_MAXFPS 190 +#define ZM_WEB_P_SCALE_THUMBS 191 +#define ZM_WEB_P_AJAX_TIMEOUT 192 +#define ZM_DYN_LAST_VERSION 193 +#define ZM_DYN_CURR_VERSION 194 +#define ZM_DYN_DB_VERSION 195 +#define ZM_DYN_LAST_CHECK 196 +#define ZM_DYN_NEXT_REMINDER 197 +#define ZM_DYN_DONATE_REMINDER_TIME 198 +#define ZM_DYN_SHOW_DONATE_REMINDER 199 +#define ZM_EYEZM_DEBUG 200 +#define ZM_EYEZM_LOG_TO_FILE 201 +#define ZM_EYEZM_LOG_FILE 202 +#define ZM_EYEZM_EVENT_VCODEC 203 +#define ZM_EYEZM_FEED_VCODEC 204 +#define ZM_EYEZM_H264_DEFAULT_BR 205 +#define ZM_EYEZM_H264_DEFAULT_EVBR 206 +#define ZM_EYEZM_H264_TIMEOUT 207 +#define ZM_EYEZM_SEG_DURATION 208 -#define ZM_MAX_CFG_ID 196 +#define ZM_MAX_CFG_ID 208 #define ZM_CFG_DECLARE_LIST \ const char *lang_default;\ @@ -247,12 +259,24 @@ const char *ffmpeg_input_options;\ const char *ffmpeg_output_options;\ const char *ffmpeg_formats;\ + int log_level_syslog;\ + int log_level_file;\ + int log_level_weblog;\ + int log_level_database;\ + const char *log_database_limit;\ + bool log_debug;\ + const char *log_debug_target;\ + int log_debug_level;\ + const char *log_debug_file;\ + int log_check_period;\ + int log_alert_war_count;\ + int log_alert_err_count;\ + int log_alert_fat_count;\ + int log_alarm_war_count;\ + int log_alarm_err_count;\ + int log_alarm_fat_count;\ bool record_event_stats;\ bool record_diag_images;\ - bool extra_debug;\ - const char *extra_debug_target;\ - int extra_debug_level;\ - const char *extra_debug_log;\ bool dump_cores;\ const char *path_map;\ const char *path_socks;\ @@ -447,12 +471,24 @@ ffmpeg_input_options = (const char *)config.Item( ZM_FFMPEG_INPUT_OPTIONS );\ ffmpeg_output_options = (const char *)config.Item( ZM_FFMPEG_OUTPUT_OPTIONS );\ ffmpeg_formats = (const char *)config.Item( ZM_FFMPEG_FORMATS );\ + log_level_syslog = (int)config.Item( ZM_LOG_LEVEL_SYSLOG );\ + log_level_file = (int)config.Item( ZM_LOG_LEVEL_FILE );\ + log_level_weblog = (int)config.Item( ZM_LOG_LEVEL_WEBLOG );\ + log_level_database = (int)config.Item( ZM_LOG_LEVEL_DATABASE );\ + log_database_limit = (const char *)config.Item( ZM_LOG_DATABASE_LIMIT );\ + log_debug = (bool)config.Item( ZM_LOG_DEBUG );\ + log_debug_target = (const char *)config.Item( ZM_LOG_DEBUG_TARGET );\ + log_debug_level = (int)config.Item( ZM_LOG_DEBUG_LEVEL );\ + log_debug_file = (const char *)config.Item( ZM_LOG_DEBUG_FILE );\ + log_check_period = (int)config.Item( ZM_LOG_CHECK_PERIOD );\ + log_alert_war_count = (int)config.Item( ZM_LOG_ALERT_WAR_COUNT );\ + log_alert_err_count = (int)config.Item( ZM_LOG_ALERT_ERR_COUNT );\ + log_alert_fat_count = (int)config.Item( ZM_LOG_ALERT_FAT_COUNT );\ + log_alarm_war_count = (int)config.Item( ZM_LOG_ALARM_WAR_COUNT );\ + log_alarm_err_count = (int)config.Item( ZM_LOG_ALARM_ERR_COUNT );\ + log_alarm_fat_count = (int)config.Item( ZM_LOG_ALARM_FAT_COUNT );\ record_event_stats = (bool)config.Item( ZM_RECORD_EVENT_STATS );\ record_diag_images = (bool)config.Item( ZM_RECORD_DIAG_IMAGES );\ - extra_debug = (bool)config.Item( ZM_EXTRA_DEBUG );\ - extra_debug_target = (const char *)config.Item( ZM_EXTRA_DEBUG_TARGET );\ - extra_debug_level = (int)config.Item( ZM_EXTRA_DEBUG_LEVEL );\ - extra_debug_log = (const char *)config.Item( ZM_EXTRA_DEBUG_LOG );\ dump_cores = (bool)config.Item( ZM_DUMP_CORES );\ path_map = (const char *)config.Item( ZM_PATH_MAP );\ path_socks = (const char *)config.Item( ZM_PATH_SOCKS );\ diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 7077752fe..a9f532b8a 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -25,6 +25,8 @@ MYSQL dbconn; +int zmDbConnected = false; + void zmDbConnect() { if ( !mysql_init( &dbconn ) ) @@ -56,5 +58,6 @@ void zmDbConnect() Error( "Can't select database: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); } + zmDbConnected = true; } diff --git a/src/zm_db.h b/src/zm_db.h index 4d84687d0..dda2dd30f 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -22,10 +22,16 @@ #include -#include "zm.h" - +#ifdef __cplusplus +extern "C" { +#endif extern MYSQL dbconn; +extern int zmDbConnected; + void zmDbConnect(); +#ifdef __cplusplus +} /* extern "C" */ +#endif #endif // ZM_DB_H diff --git a/src/zm_debug.c b/src/zm_debug.c deleted file mode 100644 index 0c51ec4d5..000000000 --- a/src/zm_debug.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * ZoneMinder Debug Implementation, $Date$, $Revision$ - * Copyright (C) 2001-2008 Philip Coombes - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "zm_debug.h" - -int zmDbgLevel = 0; - -static char dbgSyslog[64]; -static char dbgName[64]; -static char dbgId[64]; - -static char dbgLog[PATH_MAX] = ""; -static FILE *dbgLogFP = (FILE *)NULL; -static int dbgPrint = FALSE; -static int dbgFlush = FALSE; -static int dbgRuntime = FALSE; -static int dbgAddLogId = FALSE; -static struct timeval dbgStart; - -static int dbgRunning = FALSE; - -const char *zmDbgName() -{ - return( dbgName ); -} - -void zmUsrHandler( int sig ) -{ - if( sig == SIGUSR1) - { - if ( zmDbgLevel < 9 ) - { - zmDbgLevel++; - } - } - else if ( sig == SIGUSR2 ) - { - if( zmDbgLevel > -3 ) - { - zmDbgLevel--; - } - } - Info( "Debug Level Changed to %d", zmDbgLevel ); -} - -int zmGetDebugEnv() -{ - char envName[128]; - char *envPtr = 0; - - envPtr = getenv( "ZM_DBG_PRINT" ); - if ( envPtr == (char *)NULL ) - { - dbgPrint = FALSE; - } - else - { - dbgPrint = atoi( envPtr ); - } - - envPtr = getenv( "ZM_DBG_FLUSH" ); - if ( envPtr == (char *)NULL ) - { - dbgFlush = FALSE; - } - else - { - dbgFlush = atoi( envPtr ); - } - - envPtr = getenv( "ZM_DBG_RUNTIME" ); - if ( envPtr == (char *)NULL ) - { - dbgRuntime = FALSE; - } - else - { - dbgRuntime = atoi( envPtr ); - } - - envPtr = NULL; - sprintf( envName, "ZM_DBG_LEVEL_%s_%s", dbgName, dbgId ); - envPtr = getenv(envName); - if ( envPtr == (char *)NULL ) - { - sprintf( envName, "ZM_DBG_LEVEL_%s", dbgName ); - envPtr = getenv(envName); - if ( envPtr == (char *)NULL ) - { - sprintf( envName, "ZM_DBG_LEVEL" ); - envPtr = getenv(envName); - } - } - if ( envPtr != (char *)NULL ) - { - zmDbgLevel = atoi(envPtr); - } - - envPtr = NULL; - sprintf( envName, "ZM_DBG_LOG_%s_%s", dbgName, dbgId ); - envPtr = getenv(envName); - if ( envPtr == (char *)NULL ) - { - sprintf( envName, "ZM_DBG_LOG_%s", dbgName ); - envPtr = getenv(envName); - if ( envPtr == (char *)NULL ) - { - sprintf( envName, "ZM_DBG_LOG" ); - envPtr = getenv(envName); - } - } - if ( envPtr != (char *)NULL ) - { - /* If we do not want to add a pid to the debug logs - * which is the default, and original method - */ - if ( envPtr[strlen(envPtr)-1] == '+' ) - { - /* remove the + character from the string */ - envPtr[strlen(envPtr)-1] = '\0'; - dbgAddLogId = TRUE; - } - if ( dbgAddLogId == FALSE ) - { - strncpy( dbgLog, envPtr, sizeof(dbgLog) ); - } - else - { - snprintf( dbgLog, sizeof(dbgLog), "%s.%05d", envPtr, getpid() ); - } - } - - return( 0 ); -} - -int zmDebugPrepareLog() -{ - FILE *tempLogFP = NULL; - - if ( dbgLogFP ) - { - fflush( dbgLogFP ); - if ( fclose(dbgLogFP) == -1 ) - { - Error( "fclose(), error = %s",strerror(errno) ); - return( -1 ); - } - dbgLogFP = (FILE *)NULL; - } - - if ( ( dbgAddLogId == FALSE && dbgLog[0] ) && ( dbgLog[strlen(dbgLog)-1] == '~' ) ) - { - dbgLog[strlen(dbgLog)-1] = '\0'; - - if ( (tempLogFP = fopen(dbgLog, "r")) != NULL ) - { - char oldLogPath[256]; - - sprintf( oldLogPath, "%s.old", dbgLog ); - rename( dbgLog, oldLogPath ); - fclose( tempLogFP ); - } - } - - if( dbgLog[0] && (dbgLogFP = fopen(dbgLog,"w")) == (FILE *)NULL ) - { - Error( "fopen() for %s, error = %s", dbgLog, strerror(errno) ); - return( -1 ); - } - return( 0 ); -} - -int zmDebugInitialise( const char *name, const char *id, int level ) -{ - int status; - - gettimeofday( &dbgStart, NULL ); - - strncpy( dbgName, name, sizeof(dbgName) ); - strncpy( dbgId, id, sizeof(dbgId) ); - zmDbgLevel = level; - - /* Now set up the syslog stuff */ - if ( dbgId[0] ) - snprintf( dbgSyslog, sizeof(dbgSyslog), "%s_%s", dbgName, dbgId ); - else - strncpy( dbgSyslog, dbgName, sizeof(dbgSyslog) ); - - (void) openlog( dbgSyslog, LOG_PID|LOG_NDELAY, LOG_LOCAL1 ); - - dbgLogFP = (FILE *)NULL; - - if( (status = zmGetDebugEnv() ) < 0) - { - Error( "Debug Environment Error, status = %d", status ); - return( -1 ); - } - - zmDebugPrepareLog(); - - Info( "Debug Level = %d, Debug Log = %s", zmDbgLevel, dbgLog[0]?dbgLog:"" ); - - { - struct sigaction action; - memset( &action, 0, sizeof(action) ); - action.sa_handler = zmUsrHandler; - action.sa_flags = SA_RESTART; - - if ( sigaction( SIGUSR1, &action, 0 ) < 0 ) - { - Error( "sigaction(), error = %s", strerror(errno) ); - return( -1 ); - } - if ( sigaction( SIGUSR2, &action, 0 ) < 0) - { - Error( "sigaction(), error = %s", strerror(errno) ); - return( -1 ); - } - } - dbgRunning = TRUE; - return( 0 ); -} - -int zmDbgInit( const char *name, const char *id, int level ) -{ - return( zmDebugInitialise( name, id, level ) ); -} - -int zmDebugReinitialise( const char *target ) -{ - int status; - int reinit = FALSE; - char buffer[64]; - - if ( target ) - { - snprintf( buffer, sizeof(buffer), "_%s_%s", dbgName, dbgId ); - if ( strcmp( target, buffer ) == 0 ) - { - reinit = TRUE; - } - else - { - snprintf( buffer, sizeof(buffer), "_%s", dbgName ); - if ( strcmp( target, buffer ) == 0 ) - { - reinit = TRUE; - } - else - { - if ( strcmp( target, "" ) == 0 ) - { - reinit = TRUE; - } - } - } - } - - if ( reinit ) - { - if ( (status = zmGetDebugEnv() ) < 0 ) - { - Error( "Debug Environment Error, status = %d", status ); - return( -1 ); - } - - zmDebugPrepareLog(); - - Info( "New Debug Level = %d, New Debug Log = %s", zmDbgLevel, dbgLog[0]?dbgLog:"" ); - } - - return( 0 ); -} - -int zmDbgReinit( const char *target ) -{ - return( zmDebugReinitialise( target ) ); -} - -int zmDebugTerminate() -{ - Debug( 1, "Terminating Debug" ); - fflush( dbgLogFP ); - if ( fclose(dbgLogFP) == -1 ) - { - Error( "fclose(), error = %s", strerror(errno) ); - return( -1 ); - } - dbgLogFP = (FILE *)NULL; - (void) closelog(); - - dbgRunning = FALSE; - return( 0 ); -} - -int zmDbgTerm() -{ - return( zmDebugTerminate() ); -} - -void zmDbgSubtractTime( struct timeval * const tp1, struct timeval * const tp2 ) -{ - tp1->tv_sec -= tp2->tv_sec; - if ( tp1->tv_usec <= tp2->tv_usec ) - { - tp1->tv_sec--; - tp1->tv_usec = 1000000 - (tp2->tv_usec - tp1->tv_usec); - } - else - { - tp1->tv_usec = tp1->tv_usec - tp2->tv_usec; - } -} - -void zmDbgOutput( int hex, const char * const file, const int line, const int level, const char *fstring, ... ) -{ - char classString[4]; - char timeString[64]; - char dbgString[8192]; - va_list argPtr; - int logCode; - struct timeval timeVal; - - switch ( level ) - { - case ZM_DBG_INF: - strncpy( classString, "INF", sizeof(classString) ); - break; - case ZM_DBG_WAR: - strncpy( classString, "WAR", sizeof(classString) ); - break; - case ZM_DBG_ERR: - strncpy( classString, "ERR", sizeof(classString) ); - break; - case ZM_DBG_FAT: - strncpy( classString, "FAT", sizeof(classString) ); - break; - case ZM_DBG_PNC: - strncpy( classString, "PNC", sizeof(classString) ); - break; - default: - if ( level > 0 && level <= 9 ) - { - snprintf( classString, sizeof(classString), "DB%d", level ); - } - else - { - Error( "Unknown Error Level %d", level ); - } - break; - } - - gettimeofday( &timeVal, NULL ); - - if ( dbgRuntime ) - { - zmDbgSubtractTime( &timeVal, &dbgStart ); - - snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 ); - } - else - { - char *timePtr = timeString; - timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) ); - snprintf( timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec ); - } - - char *dbgPtr = dbgString; - dbgPtr += snprintf( dbgPtr, sizeof(dbgString), "%s %s[%ld].%s-%s/%d [", - timeString, - dbgSyslog, - syscall(224), - classString, - file, - line - ); - char *dbgLogStart = dbgPtr; - - va_start( argPtr, fstring ); - if ( hex ) - { - unsigned char *data = va_arg( argPtr, unsigned char * ); - int len = va_arg( argPtr, int ); - int i; - dbgPtr += snprintf( dbgPtr, sizeof(dbgString)-(dbgPtr-dbgString), "%d:", len ); - for ( i = 0; i < len; i++ ) - { - dbgPtr += snprintf( dbgPtr, sizeof(dbgString)-(dbgPtr-dbgString), " %02x", data[i] ); - } - } - else - { - dbgPtr += vsnprintf( dbgPtr, sizeof(dbgString)-(dbgPtr-dbgString), fstring, argPtr ); - } - va_end(argPtr); - char *dbg_log_end = dbgPtr; - strncpy( dbgPtr, "]\n", sizeof(dbgString)-(dbgPtr-dbgString) ); - - if ( dbgPrint ) - { - printf( "%s", dbgString ); - fflush( stdout ); - } - if ( dbgLogFP != (FILE *)NULL ) - { - fprintf( dbgLogFP, "%s", dbgString ); - - if ( dbgFlush ) - { - fflush( dbgLogFP ); - } - } - /* For Info, Warning, Errors etc we want to log them */ - if ( level <= ZM_DBG_SYSLOG ) - { - switch( level ) - { - case ZM_DBG_INF: - logCode = LOG_INFO; - break; - case ZM_DBG_WAR: - logCode = LOG_WARNING; - break; - case ZM_DBG_ERR: - case ZM_DBG_FAT: - case ZM_DBG_PNC: - logCode = LOG_ERR; - break; - default: - logCode = LOG_DEBUG; - break; - } - //logCode |= LOG_DAEMON; - *dbg_log_end = '\0'; - syslog( logCode, "%s [%s]", classString, dbgLogStart ); - } - if ( level <= ZM_DBG_FAT ) - { - if ( level <= ZM_DBG_PNC ) - abort(); - exit( -1 ); - } -} diff --git a/src/zm_debug.h b/src/zm_debug.h deleted file mode 100644 index ad3ebe254..000000000 --- a/src/zm_debug.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * ZoneMinder Debug Interface, $Date$, $Revision$ - * Copyright (C) 2001-2008 Philip Coombes - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef ZM_DEBUG_H -#define ZM_DEBUG_H - -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/* Leave 0 and below for debug */ -#define ZM_DBG_INF 0 -#define ZM_DBG_WAR -1 -#define ZM_DBG_ERR -2 -#define ZM_DBG_FAT -3 -#define ZM_DBG_PNC -4 - -/* Define the level at which messages go through syslog */ -#define ZM_DBG_SYSLOG ZM_DBG_INF - -#define zmDbgPrintf(level,params...) {\ - if (level <= zmDbgLevel)\ - zmDbgOutput( 0, __FILE__, __LINE__, level, ##params );\ - } - -#define zmDbgHexdump(level,data,len) {\ - if (level <= zmDbgLevel)\ - zmDbgOutput( 1, __FILE__, __LINE__, level, "%p (%d)", data, len );\ - } - -/* Turn off debug here */ -#ifndef ZM_DBG_OFF -#define Debug(level,params...) zmDbgPrintf(level,##params) -#define Hexdump(level,data,len) zmDbgHexdump(level,data,len) -#else -#define Debug(level,params...) -#define Hexdump(level,data,len) -#endif - -#define Info(params...) zmDbgPrintf(ZM_DBG_INF,##params) -#define Warning(params...) zmDbgPrintf(ZM_DBG_WAR,##params) -#define Error(params...) zmDbgPrintf(ZM_DBG_ERR,##params) -#define Fatal(params...) zmDbgPrintf(ZM_DBG_FAT,##params) -#define Panic(params...) zmDbgPrintf(ZM_DBG_PNC,##params) -#define Mark() Info("Mark/%s/%d",__FILE__,__LINE__) -#define Log() Info("Log") -#ifdef __GNUC__ -#define Enter(level) zmDbgPrintf(level,("Entering %s",__PRETTY_FUNCTION__)) -#define Exit(level) zmDbgPrintf(level,("Exiting %s",__PRETTY_FUNCTION__)) -#else -#if 0 -#define Enter(level) zmDbgPrintf(level,("Entering ")) -#define Exit(level) zmDbgPrintf(level,("Exiting ")) -#endif -#define Enter(level) -#define Exit(level) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* function declarations */ -const char *zmDbgName(); -void zmUsrHandler( int sig ); -int zmGetDebugEnv( void ); -int zmDebugPrepareLog( void ); -int zmDebugInitialise( const char *name, const char *id, int level ); -int zmDebugReinitialise( const char *target ); -int zmDebugTerminate( void ); -void zmDbgSubtractTime( struct timeval * const tp1, struct timeval * const tp2 ); - -#if defined(__STDC__) || defined(__cplusplus) -int zmDbgInit( const char *name, const char *id, int level ); -int zmDbgReinit( const char *target ); -int zmDbgTerm(void); -void zmDbgOutput( int hex, const char * const file, const int line, const int level, const char *fstring, ... ) __attribute__ ((format(printf, 5, 6))); -#else -int zmDbgInit(); -int zmDbgReinit(); -int zmDbgTerm(); -void zmDbgOutput(); -#endif - -extern int zmDbgLevel; - -#ifndef _STDIO_INCLUDED -#include -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // ZM_DEBUG_H diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 5da5382b8..8b3bd57ef 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -74,7 +74,7 @@ void FfmpegCamera::Initialise() mBuffer.size( max_size ); - if ( zmDbgLevel > ZM_DBG_INF ) + if ( logDebugging() ) av_log_set_level( AV_LOG_DEBUG ); else av_log_set_level( AV_LOG_QUIET ); diff --git a/src/zm_file_camera.h b/src/zm_file_camera.h index 735f71d20..e8ad5142b 100644 --- a/src/zm_file_camera.h +++ b/src/zm_file_camera.h @@ -24,6 +24,8 @@ #include "zm_buffer.h" #include "zm_regexp.h" +#include + // // Class representing 'file' cameras, i.e. those which are // accessed over a network connection. diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 56ef67cb7..4c55c978d 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -1365,7 +1365,7 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) qsort( global_edges, n_global_edges, sizeof(*global_edges), Edge::CompareYX ); #ifndef ZM_DBG_OFF - if ( zmDbgLevel >= 9 ) + if ( logLevel() >= Logger::DEBUG9 ) { for ( int i = 0; i < n_global_edges; i++ ) { @@ -1400,7 +1400,7 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) } qsort( active_edges, n_active_edges, sizeof(*active_edges), Edge::CompareX ); #ifndef ZM_DBG_OFF - if ( zmDbgLevel >= 9 ) + if ( logLevel() >= Logger::DEBUG9 ) { for ( int i = 0; i < n_active_edges; i++ ) { diff --git a/src/zm_jpeg.c b/src/zm_jpeg.cpp similarity index 99% rename from src/zm_jpeg.c rename to src/zm_jpeg.cpp index a7517c5df..ed745f973 100644 --- a/src/zm_jpeg.c +++ b/src/zm_jpeg.cpp @@ -17,12 +17,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "zm_jpeg.h" +#include "zm_logger.h" + #include -#include "zm_jpeg.h" -#include "zm_debug.h" - /* Overridden error handlers, mostly for decompression */ +extern "C" +{ #define MAX_JPEG_ERRS 25 @@ -389,3 +391,5 @@ void zm_jpeg_mem_src( j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuff src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ } + +} diff --git a/src/zm_jpeg.h b/src/zm_jpeg.h index 4d32498d4..85df4c491 100644 --- a/src/zm_jpeg.h +++ b/src/zm_jpeg.h @@ -23,6 +23,12 @@ #include "jpeglib.h" #include "jerror.h" +// Stop complaints about deuplicate definitions +#undef HAVE_STDLIB_H +#undef HAVE_STDDEF_H + +extern "C" +{ /* Stuff for overriden error handlers */ struct zm_error_mgr { @@ -38,3 +44,4 @@ void zm_jpeg_emit_message( j_common_ptr cinfo, int msg_level ); // Prototypes for memory compress/decompression object */ void zm_jpeg_mem_src(j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size ); void zm_jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size ); +} diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index e17fac4d6..cf7ca0fcf 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -337,7 +337,7 @@ LocalCamera::~LocalCamera() void LocalCamera::Initialise() { #if HAVE_LIBSWSCALE - if ( zmDbgLevel > ZM_DBG_INF ) + if ( logDebugging() ) av_log_set_level( AV_LOG_DEBUG ); else av_log_set_level( AV_LOG_QUIET ); diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp new file mode 100644 index 000000000..855ed7df5 --- /dev/null +++ b/src/zm_logger.cpp @@ -0,0 +1,569 @@ +/* + * ZoneMinder Logger Implementation, $Date$, $Revision$ + * Copyright (C) 2001-2008 Philip Coombes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "zm_logger.h" + +#include "zm_config.h" +#include "zm_utils.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_SYSCALL_H +#include +#endif // HAVE_SYSCALL_H +#include +#include +#include + +bool Logger::smInitialised = false; +Logger *Logger::smInstance = 0; + +Logger::StringMap Logger::smCodes; +Logger::IntMap Logger::smSyslogPriorities; + +static void subtractTime( struct timeval * const tp1, struct timeval * const tp2 ) +{ + tp1->tv_sec -= tp2->tv_sec; + if ( tp1->tv_usec <= tp2->tv_usec ) + { + tp1->tv_sec--; + tp1->tv_usec = 1000000 - (tp2->tv_usec - tp1->tv_usec); + } + else + { + tp1->tv_usec = tp1->tv_usec - tp2->tv_usec; + } +} + +void Logger::usrHandler( int sig ) +{ + Logger *logger = fetch(); + if ( sig == SIGUSR1 ) + logger->level( logger->level()+1 ); + else if ( sig == SIGUSR2 ) + logger->level( logger->level()-1 ); + Info( "Logger - Level changed to %d", logger->level() ); +} + +Logger::Logger() : + mLevel( INFO ), + mTermLevel( NOLOG ), + mDatabaseLevel( NOLOG ), + mFileLevel( NOLOG ), + mSyslogLevel( NOLOG ), + mEffectiveLevel( NOLOG ), + //mLogPath( config.path_logs ), + //mLogFile( mLogPath+"/"+mId+".log" ), + mLogFileFP( NULL ), + mHasTerm( false ), + mFlush( false ) +{ + if ( smInstance ) + { + Panic( "Attempt to create second instance of Logger class" ); + } + + if ( !smInitialised ) + { + smCodes[INFO] = "INF"; + smCodes[WARNING] = "WAR"; + smCodes[ERROR] = "ERR"; + smCodes[FATAL] = "FAT"; + smCodes[PANIC] = "PNC"; + smCodes[NOLOG] = "OFF"; + + smSyslogPriorities[INFO] = LOG_INFO; + smSyslogPriorities[WARNING] = LOG_WARNING; + smSyslogPriorities[ERROR] = LOG_ERR; + smSyslogPriorities[FATAL] = LOG_ERR; + smSyslogPriorities[PANIC] = LOG_ERR; + + char code[4] = ""; + for ( int i = DEBUG1; i <= DEBUG9; i++ ) + { + snprintf( code, sizeof(code), "DB%d", i ); + smCodes[i] = code; + smSyslogPriorities[i] = LOG_DEBUG; + } + + smInitialised = true; + } + + if ( fileno(stderr) && isatty(fileno(stderr)) ) + mHasTerm = true; +} + +Logger::~Logger() +{ + terminate(); +} + +void Logger::initialise( const std::string &id, const Options &options ) +{ + char *envPtr; + + if ( !id.empty() ) + this->id( id ); + + std::string tempLogFile; + if ( options.mLogPath.size() ) + { + mLogPath = options.mLogPath; + tempLogFile = mLogPath+"/"+mId+".log"; + } + if ( options.mLogFile.size() ) + tempLogFile = options.mLogFile; + else + tempLogFile = mLogPath+"/"+mId+".log"; + if ( (envPtr = getTargettedEnv( "LOG_FILE" )) ) + tempLogFile = envPtr; + + Level tempLevel = INFO; + Level tempTermLevel = mTermLevel; + Level tempDatabaseLevel = mDatabaseLevel; + Level tempFileLevel = mFileLevel; + Level tempSyslogLevel = mSyslogLevel; + + if ( options.mTermLevel != NOOPT ) + tempTermLevel = options.mTermLevel; + if ( options.mDatabaseLevel != NOOPT ) + tempDatabaseLevel = options.mDatabaseLevel; + else + tempDatabaseLevel = config.log_level_database >= DEBUG1 ? DEBUG9 : config.log_level_database; + if ( options.mFileLevel != NOOPT ) + tempFileLevel = options.mFileLevel; + else + tempFileLevel = config.log_level_file >= DEBUG1 ? DEBUG9 : config.log_level_file; + if ( options.mSyslogLevel != NOOPT ) + tempSyslogLevel = options.mSyslogLevel; + else + tempSyslogLevel = config.log_level_syslog >= DEBUG1 ? DEBUG9 : config.log_level_syslog; + + // Legacy + if ( (envPtr = getenv( "LOG_PRINT" )) ) + tempTermLevel = atoi(envPtr) ? DEBUG9 : NOLOG; + + if ( (envPtr = getTargettedEnv( "LOG_LEVEL" )) ) + tempLevel = atoi(envPtr); + + if ( (envPtr = getTargettedEnv( "LOG_LEVEL_TERM" )) ) + tempTermLevel = atoi(envPtr); + if ( (envPtr = getTargettedEnv( "LOG_LEVEL_DATABASE" )) ) + tempDatabaseLevel = atoi(envPtr); + if ( (envPtr = getTargettedEnv( "LOG_LEVEL_FILE" )) ) + tempFileLevel = atoi(envPtr); + if ( (envPtr = getTargettedEnv( "LOG_LEVEL_SYSLOG" )) ) + tempSyslogLevel = atoi(envPtr); + + if ( config.log_debug ) + { + StringVector targets = split( config.log_debug_target, "|" ); + for ( int i = 0; i < targets.size(); i++ ) + { + const std::string &target = targets[i]; + if ( target == mId || target == "_"+mId || target == "_"+mIdRoot || target == "_"+mIdRoot || target == "" ) + { + if ( config.log_debug_level > NOLOG ) + { + tempLevel = config.log_debug_level; + if ( config.log_debug_file[0] ) + { + tempLogFile = config.log_debug_file; + tempFileLevel = tempLevel; + } + } + } + } + } + + logFile( tempLogFile ); + + termLevel( tempTermLevel ); + databaseLevel( tempDatabaseLevel ); + fileLevel( tempFileLevel ); + syslogLevel( tempSyslogLevel ); + + level( tempLevel ); + + mFlush = (envPtr = getenv( "LOG_FLUSH")) ? atoi( envPtr ) : false; + + //mRuntime = (envPtr = getenv( "LOG_RUNTIME")) ? atoi( envPtr ) : false; + + { + struct sigaction action; + memset( &action, 0, sizeof(action) ); + action.sa_handler = usrHandler; + action.sa_flags = SA_RESTART; + + if ( sigaction( SIGUSR1, &action, 0 ) < 0 ) + { + Fatal( "sigaction(), error = %s", strerror(errno) ); + } + if ( sigaction( SIGUSR2, &action, 0 ) < 0) + { + Fatal( "sigaction(), error = %s", strerror(errno) ); + } + } + + mInitialised = true; + + Debug( 1, "LogOpts: level=%s/%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s", smCodes[mLevel].c_str(), smCodes[mEffectiveLevel].c_str(), smCodes[mTermLevel].c_str(), smCodes[mDatabaseLevel].c_str(), smCodes[mFileLevel].c_str(), mLogFile.c_str(), smCodes[mSyslogLevel].c_str() ); +} + +void Logger::terminate() +{ + Info( "Terminating Logger" ); + + if ( mFileLevel > NOLOG ) + closeFile(); + + if ( mSyslogLevel > NOLOG ) + closeSyslog(); +} + +bool Logger::boolEnv( const std::string &name, bool defaultValue ) +{ + const char *envPtr = getenv( name.c_str() ); + return( envPtr ? atoi( envPtr ) : defaultValue ); +} + +int Logger::intEnv( const std::string &name, bool defaultValue ) +{ + const char *envPtr = getenv( name.c_str() ); + return( envPtr ? atoi( envPtr ) : defaultValue ); +} + +std::string Logger::strEnv( const std::string &name, const std::string defaultValue ) +{ + const char *envPtr = getenv( name.c_str() ); + return( envPtr ? envPtr : defaultValue ); +} + +char *Logger::getTargettedEnv( const std::string &name ) +{ + char *envPtr = NULL; + std::string envName; + + envName = name+"_"+mId; + envPtr = getenv( envName.c_str() ); + if ( !envPtr && mId != mIdRoot ) + { + envName = name+"_"+mIdRoot; + envPtr = getenv( envName.c_str() ); + } + if ( !envPtr ) + envPtr = getenv( name.c_str() ); + return( envPtr ); +} + +const std::string &Logger::id( const std::string &id ) +{ + std::string tempId = id; + + size_t pos; + // Remove whitespace + while ( (pos = tempId.find_first_of( " \t" )) != std::string::npos ) + { + tempId.replace( pos, 1, "" ); + } + // Replace non-alphanum with underscore + while ( (pos = tempId.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" )) != std::string::npos ) + { + tempId.replace( pos, 1, "_" ); + } + if ( mId != tempId ) + { + mId = tempId; + pos = mId.find( '_' ); + if ( pos != std::string::npos ) + { + mIdRoot = mId.substr( 0, pos ); + if ( ++pos < mId.size() ) + mIdArgs = mId.substr( pos ); + } + } + return( mId ); +} + +Logger::Level Logger::level( Logger::Level level ) +{ + if ( level > NOOPT ) + { + level = limit(level); + if ( mLevel != level ) + mLevel = level; + + mEffectiveLevel = NOLOG; + if ( mTermLevel > mEffectiveLevel ) + mEffectiveLevel = mTermLevel; + if ( mDatabaseLevel > mEffectiveLevel ) + mEffectiveLevel = mDatabaseLevel; + if ( mFileLevel > mEffectiveLevel ) + mEffectiveLevel = mFileLevel; + if ( mSyslogLevel > mEffectiveLevel ) + mEffectiveLevel = mSyslogLevel; + if ( mEffectiveLevel > mLevel) + mEffectiveLevel = mLevel; + } + return( mLevel ); +} + +Logger::Level Logger::termLevel( Logger::Level termLevel ) +{ + if ( termLevel > NOOPT ) + { + if ( !mHasTerm ) + termLevel = NOLOG; + termLevel = limit(termLevel); + if ( mTermLevel != termLevel ) + mTermLevel = termLevel; + } + return( mTermLevel ); +} + +Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) +{ + if ( databaseLevel > NOOPT ) + { + databaseLevel = limit(databaseLevel); + if ( mDatabaseLevel != databaseLevel ) + { + if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG ) + { + if ( zmDbConnected ) + zmDbConnect(); + } + mDatabaseLevel = databaseLevel; + } + } + return( mDatabaseLevel ); +} + +Logger::Level Logger::fileLevel( Logger::Level fileLevel ) +{ + if ( fileLevel > NOOPT ) + { + fileLevel = limit(fileLevel); + if ( mFileLevel != fileLevel ) + { + if ( mFileLevel > NOLOG ) + closeFile(); + mFileLevel = fileLevel; + if ( mFileLevel > NOLOG ) + openFile(); + } + } + return( mFileLevel ); +} + +Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) +{ + if ( syslogLevel > NOOPT ) + { + syslogLevel = limit(syslogLevel); + if ( mSyslogLevel != syslogLevel ) + { + if ( mSyslogLevel > NOLOG ) + closeSyslog(); + mSyslogLevel = syslogLevel; + if ( mSyslogLevel > NOLOG ) + openSyslog(); + } + } + return( mSyslogLevel ); +} + +void Logger::logFile( const std::string &logFile ) +{ + bool addLogPid = false; + std::string tempLogFile = logFile; + if ( tempLogFile[tempLogFile.length()-1] == '+' ) + { + tempLogFile.resize(tempLogFile.length()-1); + addLogPid = true; + } + if ( addLogPid ) + mLogFile = stringtf( "%s.%05d", tempLogFile.c_str(), getpid() ); + else + mLogFile = tempLogFile; +} + +void Logger::openFile() +{ + if ( mLogFile.size() && (mLogFileFP = fopen( mLogFile.c_str() ,"w" )) == (FILE *)NULL ) + { + mFileLevel = NOLOG; + Fatal( "fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno) ); + } +} + +void Logger::closeFile() +{ + if ( mLogFileFP ) + { + fflush( mLogFileFP ); + if ( fclose( mLogFileFP ) < 0 ) + { + Fatal( "fclose(), error = %s",strerror(errno) ); + } + mLogFileFP = (FILE *)NULL; + } +} + +void Logger::openSyslog() +{ + (void) openlog( mId.c_str(), LOG_PID|LOG_NDELAY, LOG_LOCAL1 ); +} + +void Logger::closeSyslog() +{ + (void) closelog(); +} + +void Logger::logPrint( bool hex, const char * const file, const int line, const int level, const char *fstring, ... ) +{ + if ( level <= mEffectiveLevel ) + { + char classString[4]; + char timeString[64]; + char logString[8192]; + va_list argPtr; + struct timeval timeVal; + + if ( level < PANIC || level > DEBUG9 ) + Panic( "Invalid logger level %d", level ); + + strncpy( classString, smCodes[level].c_str(), sizeof(classString) ); + + gettimeofday( &timeVal, NULL ); + + #if 0 + if ( logRuntime ) + { + static struct timeval logStart; + + subtractTime( &timeVal, &logStart ); + + snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 ); + } + else + { + #endif + char *timePtr = timeString; + timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) ); + snprintf( timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec ); + #if 0 + } + #endif + + pid_t tid; +#ifdef HAVE_SYSCALL + if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id +#endif // HAVE_SYSCALL + tid = getpid(); // Process id + + char *logPtr = logString; + logPtr += snprintf( logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [", + timeString, + mId.c_str(), + tid, + classString, + file, + line + ); + char *syslogStart = logPtr; + + va_start( argPtr, fstring ); + if ( hex ) + { + unsigned char *data = va_arg( argPtr, unsigned char * ); + int len = va_arg( argPtr, int ); + int i; + logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), "%d:", len ); + for ( i = 0; i < len; i++ ) + { + logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), " %02x", data[i] ); + } + } + else + { + logPtr += vsnprintf( logPtr, sizeof(logString)-(logPtr-logString), fstring, argPtr ); + } + va_end(argPtr); + char *syslogEnd = logPtr; + strncpy( logPtr, "]\n", sizeof(logString)-(logPtr-logString) ); + + if ( level <= mTermLevel ) + { + printf( "%s", logString ); + fflush( stdout ); + } + if ( level <= mFileLevel ) + { + fprintf( mLogFileFP, "%s", logString ); + if ( mFlush ) + fflush( mLogFileFP ); + } + *syslogEnd = '\0'; + if ( level <= mDatabaseLevel ) + { + char sql[ZM_SQL_MED_BUFSIZ]; + char escapedString[(strlen(syslogStart)*2)+1]; + + mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); + snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), tid, level, classString, escapedString, file, line ); + if ( mysql_query( &dbconn, sql ) ) + { + databaseLevel( NOLOG ); + Fatal( "Can't insert log entry: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } + } + if ( level <= mSyslogLevel ) + { + int priority = smSyslogPriorities[level]; + //priority |= LOG_DAEMON; + syslog( priority, "%s [%s]", classString, syslogStart ); + } + + if ( level <= FATAL ) + { + if ( level <= PANIC ) + abort(); + exit( -1 ); + } + } +} + +void logInit( const char *name, const Logger::Options &options ) +{ + if ( !Logger::smInstance ) + Logger::smInstance = new Logger(); + Logger::Options tempOptions = options; + tempOptions.mLogPath = config.path_logs; + Logger::smInstance->initialise( name, tempOptions ); +} + +void logTerm() +{ + Logger::fetch()->terminate(); +} diff --git a/src/zm_logger.h b/src/zm_logger.h new file mode 100644 index 000000000..77d23e195 --- /dev/null +++ b/src/zm_logger.h @@ -0,0 +1,237 @@ +/* + * ZoneMinder Logger Interface, $Date$, $Revision$ + * Copyright (C) 2001-2008 Philip Coombes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef ZM_LOGGER_H +#define ZM_LOGGER_H + +#include "zm_db.h" + +#include +#include + +class Logger +{ +public: + enum { + NOOPT=-6, + NOLOG, + PANIC, + FATAL, + ERROR, + WARNING, + INFO, + DEBUG1, + DEBUG2, + DEBUG3, + DEBUG4, + DEBUG5, + DEBUG6, + DEBUG7, + DEBUG8, + DEBUG9 + }; + + typedef int Level; + + typedef std::map StringMap; + typedef std::map IntMap; + + class Options + { + public: + int mTermLevel; + int mDatabaseLevel; + int mFileLevel; + int mSyslogLevel; + + std::string mLogPath; + std::string mLogFile; + + public: + Options( Level termLevel=NOOPT, Level databaseLevel=NOOPT, Level fileLevel=NOOPT, Level syslogLevel=NOOPT, const std::string &logPath=".", const std::string &logFile="" ) : + mTermLevel( termLevel ), + mDatabaseLevel( databaseLevel ), + mFileLevel( fileLevel ), + mSyslogLevel( syslogLevel ), + mLogPath( logPath ), + mLogFile( logFile ) + { + } + }; + +private: + static bool smInitialised; + static Logger *smInstance; + + static StringMap smCodes; + static IntMap smSyslogPriorities; + +private: + bool mInitialised; + + std::string mId; + std::string mIdRoot; + std::string mIdArgs; + + Level mLevel; // Level that is currently in operation + Level mTermLevel; // Maximum level output via terminal + Level mDatabaseLevel; // Maximum level output via database + Level mFileLevel; // Maximum level output via file + Level mSyslogLevel; // Maximum level output via syslog + Level mEffectiveLevel; // Level optimised to take account of maxima + + std::string mLogPath; + std::string mLogFile; + FILE *mLogFileFP; + + bool mHasTerm; + bool mFlush; + +private: + static void usrHandler( int sig ); + +public: + friend void logInit( const char *name, const Options &options ); + + static Logger *fetch() + { + if ( !smInstance ) + { + smInstance = new Logger(); + Options options; + smInstance->initialise( "undef", options ); + } + return( smInstance ); + } + +private: + Logger(); + ~Logger(); + +public: + void initialise( const std::string &id, const Options &options ); + void terminate(); + +private: + int limit( int level ) + { + if ( level > DEBUG9 ) + return( DEBUG9 ); + if ( level < NOLOG ) + return( NOLOG ); + return( level ); + } + + bool boolEnv( const std::string &name, bool defaultValue=false ); + int intEnv( const std::string &name, bool defaultValue=0 ); + std::string strEnv( const std::string &name, const std::string defaultValue="" ); + char *getTargettedEnv( const std::string &name ); + + void loadEnv(); + +public: + const std::string &id() const + { + return( mId ); + } + + const std::string &id( const std::string &id ); + + Level level() const + { + return( mLevel ); + } + Level level( Level=NOOPT ); + + bool debugOn() + { + return( mEffectiveLevel >= DEBUG1 ); + } + + Level termLevel( Level=NOOPT ); + Level databaseLevel( Level=NOOPT ); + Level fileLevel( Level=NOOPT ); + Level syslogLevel( Level=NOOPT ); + +private: + void logFile( const std::string &logFile ); + void openFile(); + void closeFile(); + void openSyslog(); + void closeSyslog(); + +public: + void logPrint( bool hex, const char * const file, const int line, const int level, const char *fstring, ... ); +}; + +void logInit( const char *name, const Logger::Options &options=Logger::Options() ); +void logTerm(); +inline const std::string &logId() +{ + return( Logger::fetch()->id() ); +} +inline Logger::Level logLevel() +{ + return( Logger::fetch()->level() ); +} +inline void logCapLevel( Logger::Level level ) +{ + Logger::fetch()->level( level ); +} +inline Logger::Level logDebugging() +{ + return( Logger::fetch()->debugOn() ); +} + +#define logPrintf(logLevel,params...) {\ + if ( logLevel <= Logger::fetch()->level() )\ + Logger::fetch()->logPrint( false, __FILE__, __LINE__, logLevel, ##params );\ + } + +#define logHexdump(logLevel,data,len) {\ + if ( logLevel <= Logger::fetch()->level() )\ + Logger::fetch()->logPrint( true, __FILE__, __LINE__, logLevel, "%p (%d)", data, len );\ + } + +/* Debug compiled out */ +#ifndef DBG_OFF +#define Debug(level,params...) logPrintf(level,##params) +#define Hexdump(level,data,len) logHexdump(level,data,len) +#else +#define Debug(level,params...) +#define Hexdump(level,data,len) +#endif + +/* Standard debug calls */ +#define Info(params...) logPrintf(Logger::INFO,##params) +#define Warning(params...) logPrintf(Logger::WARNING,##params) +#define Error(params...) logPrintf(Logger::ERROR,##params) +#define Fatal(params...) logPrintf(Logger::FATAL,##params) +#define Panic(params...) logPrintf(Logger::PANIC,##params) +#define Mark() Info("Mark/%s/%d",__FILE__,__LINE__) +#define Log() Info("Log") +#ifdef __GNUC__ +#define Enter(level) logPrintf(level,("Entering %s",__PRETTY_FUNCTION__)) +#define Exit(level) logPrintf(level,("Exiting %s",__PRETTY_FUNCTION__)) +#else +#define Enter(level) +#define Exit(level) +#endif + +#endif // ZM_LOGGER_H diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 77cc9d669..56618aa64 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -65,7 +65,7 @@ void RemoteCameraRtsp::Initialise() buffer.size( max_size ); - if ( zmDbgLevel > ZM_DBG_INF ) + if ( logDebugging() ) av_log_set_level( AV_LOG_DEBUG ); else av_log_set_level( AV_LOG_QUIET ); @@ -222,7 +222,7 @@ int RemoteCameraRtsp::Capture( Image &image ) return( 0 ); } Error( "Error while decoding frame %d", frameCount ); - Hexdump( ZM_DBG_ERR, buffer.head(), buffer.size()>256?256:buffer.size() ); + Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() ); buffer.clear(); continue; //return( -1 ); diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index fdfceec2a..b28e379a3 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -83,7 +83,7 @@ bool RtspThread::recvResponse( std::string &response ) { Error( "Response parse failure, %zd bytes follow", response.size() ); if ( response.size() ) - Hexdump( ZM_DBG_ERR, response.data(), min(response.size(),16) ); + Hexdump( Logger::ERROR, response.data(), min(response.size(),16) ); } return( false ); } @@ -257,7 +257,7 @@ int RtspThread::run() { Error( "Response parse failure, %zd bytes follow", response.size() ); if ( response.size() ) - Hexdump( ZM_DBG_ERR, response.data(), min(response.size(),16) ); + Hexdump( Logger::ERROR, response.data(), min(response.size(),16) ); } return( -1 ); } diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index 8e1b6c9ae..5bb000f0b 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -17,12 +17,13 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // -#include -#include - #include "zm.h" #include "zm_signal.h" +#include +#include +#include + bool zm_reload = false; RETSIGTYPE zm_hup_handler( int signal ) @@ -114,7 +115,7 @@ RETSIGTYPE zm_die_handler( int signal ) } else { - cmd_ptr += snprintf( cmd_ptr, sizeof(cmd)-(cmd_ptr-cmd), "/path/to/%s", zmDbgName() ); + cmd_ptr += snprintf( cmd_ptr, sizeof(cmd)-(cmd_ptr-cmd), "/path/to/%s", logId().c_str() ); } // skip first stack frame (points here) for ( int i=1; i < trace_size; i++ ) diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index c9c19d1fd..8ad372e78 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -19,7 +19,7 @@ #include "zm_thread.h" -#include "zm_debug.h" +#include "zm_logger.h" #include "zm_utils.h" #include diff --git a/src/zm_timer.cpp b/src/zm_timer.cpp index 6b5cabf11..fbac45435 100644 --- a/src/zm_timer.cpp +++ b/src/zm_timer.cpp @@ -19,7 +19,7 @@ #include "zm_timer.h" -#include "zm_debug.h" +#include "zm_logger.h" int Timer::TimerThread::mNextTimerId = 0; diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 0da7324df..afdc444d4 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -17,16 +17,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include - #include "zm.h" #include "zm_db.h" #include "zm_user.h" +#include + User::User() { username[0] = password[0] = 0; diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index 6d82332d0..e4bb53162 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -17,7 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // -//#include "zm_debug.h" +//#include "zm_logger.h" #include "zm_utils.h" #include diff --git a/src/zma.cpp b/src/zma.cpp index 722582c97..4a8fb1778 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -87,13 +87,13 @@ int main( int argc, char *argv[] ) exit( 0 ); } - char dbg_id_string[16]; - snprintf( dbg_id_string, sizeof(dbg_id_string), "m%d", id ); - - zmDbgInit( "zma", dbg_id_string, 0 ); + char log_id_string[16]; + snprintf( log_id_string, sizeof(log_id_string), "zma_m%d", id ); zmLoadConfig(); + logInit( log_id_string ); + Monitor *monitor = Monitor::Load( id, true, Monitor::ANALYSIS ); if ( monitor ) diff --git a/src/zmc.cpp b/src/zmc.cpp index 7e368b80c..17f40c4b0 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -128,30 +128,30 @@ int main( int argc, char *argv[] ) exit( 0 ); } - char dbg_id_string[16]; + char log_id_string[32] = ""; if ( device[0] ) { const char *slash_ptr = strrchr( device, '/' ); - snprintf( dbg_id_string, sizeof(dbg_id_string), "d%s", slash_ptr?slash_ptr+1:device ); + snprintf( log_id_string, sizeof(log_id_string), "zmc_d%s", slash_ptr?slash_ptr+1:device ); } else if ( host[0] ) { - snprintf( dbg_id_string, sizeof(dbg_id_string), "h%s", host ); + snprintf( log_id_string, sizeof(log_id_string), "zmc_h%s", host ); } else if ( file[0] ) { const char *slash_ptr = strrchr( file, '/' ); - snprintf( dbg_id_string, sizeof(dbg_id_string), "f%s", slash_ptr?slash_ptr+1:file ); + snprintf( log_id_string, sizeof(log_id_string), "zmc_f%s", slash_ptr?slash_ptr+1:file ); } else { - snprintf( dbg_id_string, sizeof(dbg_id_string), "m%d", monitor_id ); + snprintf( log_id_string, sizeof(log_id_string), "zmc_m%d", monitor_id ); } - zmDbgInit( "zmc", dbg_id_string, 0 ); - zmLoadConfig(); + logInit( log_id_string ); + Monitor **monitors = 0; int n_monitors = 0; #if ZM_HAS_V4L diff --git a/src/zmf.cpp b/src/zmf.cpp index 7e890951e..2f789fe98 100644 --- a/src/zmf.cpp +++ b/src/zmf.cpp @@ -155,13 +155,13 @@ int main( int argc, char *argv[] ) exit( 0 ); } - char dbg_id_string[16]; - snprintf( dbg_id_string, sizeof(dbg_id_string), "m%d", id ); - - zmDbgInit( "zmf", dbg_id_string, 0 ); + char log_id_string[16]; + snprintf( log_id_string, sizeof(log_id_string), "m%d", id ); zmLoadConfig(); + logInit( "zmf" ); + Monitor *monitor = Monitor::Load( id, false, Monitor::QUERY ); if ( !monitor ) diff --git a/src/zmfix.cpp b/src/zmfix.cpp index 7af91e464..2d3be8756 100644 --- a/src/zmfix.cpp +++ b/src/zmfix.cpp @@ -132,10 +132,11 @@ bool fixDevice( const char *device_path ) int main( int argc, char *argv[] ) { - zmDbgInit( "zmfix", "", -1 ); - zmLoadConfig(); + logInit( "zmfix" ); + logCapLevel( Logger::ERROR ); + // Only do registered devices static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "select distinct Device from Monitors where not isnull(Device) and Type = 'Local'" ); diff --git a/src/zms.cpp b/src/zms.cpp index 93934efbd..98e7e45b7 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -85,10 +85,10 @@ int main( int argc, const char *argv[] ) nph = true; } - zmDbgInit( "zms", "", 0 ); - zmLoadConfig(); + logInit( "zms" ); + zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); diff --git a/src/zmstreamer.cpp b/src/zmstreamer.cpp index c30329df8..b528947f7 100644 --- a/src/zmstreamer.cpp +++ b/src/zmstreamer.cpp @@ -140,12 +140,12 @@ int main(int argc, char** argv) { setenv("ZM_DBG_PRINT", "1", 1); printf("Done.\n"); } - zmDbgInit("zmstreamer", "", 0); // Loading ZM configurations printf("Loading ZoneMinder configurations..."); zmLoadConfig(); printf("Done.\n"); + logInit("zmstreamer"); // Setting stream parameters MonitorStream stream; diff --git a/src/zmu.cpp b/src/zmu.cpp index 923a93b24..49efafd05 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -349,10 +349,10 @@ int main( int argc, char *argv[] ) } //printf( "Monitor %d, Function %d\n", mon_id, function ); - zmDbgInit( "zmu", "", -1 ); - zmLoadConfig(); + logInit( "zmu" ); + zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); diff --git a/web/ajax/Makefile.am b/web/ajax/Makefile.am index aaddcb56b..ef79e6cae 100644 --- a/web/ajax/Makefile.am +++ b/web/ajax/Makefile.am @@ -6,6 +6,7 @@ dist_web_DATA = \ alarm.php \ control.php \ event.php \ + log.php \ status.php \ stream.php \ zone.php diff --git a/web/ajax/Makefile.in b/web/ajax/Makefile.in index 8030a287e..7bbb478b7 100644 --- a/web/ajax/Makefile.in +++ b/web/ajax/Makefile.in @@ -211,6 +211,7 @@ dist_web_DATA = \ alarm.php \ control.php \ event.php \ + log.php \ status.php \ stream.php \ zone.php diff --git a/web/ajax/log.php b/web/ajax/log.php new file mode 100644 index 000000000..030fc3cb6 --- /dev/null +++ b/web/ajax/log.php @@ -0,0 +1,357 @@ + "web_js" ) ); + + $string = $_REQUEST['message']; + $file = preg_replace( '/\w+:\/\/\w+\//', '', $_REQUEST['file'] ); + if ( !empty( $_REQUEST['line'] ) ) + $line = $_REQUEST['line']; + else + $line = NULL; + + $levels = array_flip(Logger::$codes); + if ( !isset($levels[$_REQUEST['level']]) ) + Panic( "Unexpected logger level '".$_REQUEST['level']."'" ); + $level = $levels[$_REQUEST['level']]; + Logger::fetch()->logPrint( $level, $string, $file, $line ); + ajaxResponse(); + break; + } + case 'query' : + { + if ( !canView( 'System' ) ) + ajaxError( 'Insufficient permissions to view log entries' ); + + $minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL; + $maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL; + $limit = isset($_REQUEST['limit'])?$_REQUEST['limit']:1000; + $filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array(); + $sortField = isset($_REQUEST['sortField'])?$_REQUEST['sortField']:'TimeKey'; + $sortOrder = isset($_REQUEST['sortOrder'])?$_REQUEST['sortOrder']:'desc'; + + $filterFields = array( 'Component', 'Pid', 'Level', 'File', 'Line' ); + + //$filterSql = $filter?' where + $countSql = "select count(*) as Total from Logs"; + $total = dbFetchOne( $countSql, 'Total' ); + $sql = "select * from Logs"; + $where = array(); + if ( $minTime ) + $where[] = "TimeKey > ".dbEscape($minTime); + elseif ( $maxTime ) + $where[] = "TimeKey < ".dbEscape($maxTime); + foreach ( $filter as $field=>$value ) + if ( $field == 'Level' ) + $where[] = dbEscape($field)." <= ".dbEscape($value); + else + $where[] = dbEscape($field)." = '".dbEscape($value)."'"; + if ( count($where) ) + $sql.= " where ".join( " and ", $where ); + $sql .= " order by ".dbEscape($sortField)." ".dbEscape($sortOrder)." limit ".dbEscape($limit); + $logs = array(); + foreach ( dbFetchAll( $sql ) as $log ) + { + $log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] ); + $logs[] = $log; + } + $options = array(); + $where = array(); + foreach( $filter as $field=>$value ) + $where[] = "$field = '".dbEscape($value)."'"; + foreach( $filterFields as $field ) + { + $sql = "select distinct $field from Logs where not isnull($field)"; + if ( count($where) ) + $sql.= " and ".join( " and ", $where ); + $sql.= " order by $field asc"; + if ( $field == 'Level' ) + { + foreach( dbFetchAll( $sql, $field ) as $value ) + if ( $value <= Logger::INFO ) + $options[$field][$value] = Logger::$codes[$value]; + else + $options[$field][$value] = "DB".$value; + } + else + { + foreach( dbFetchAll( $sql, $field ) as $value ) + if ( $value != '' ) + $options[$field][] = $value; + } + } + if ( count($filter) ) + { + $sql = "select count(*) as Available from Logs where ".join( " and ", $where ); + $available = dbFetchOne( $sql, 'Available' ); + } + ajaxResponse( array( + 'updated' => preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG ), + 'total' => $total, + 'available' => isset($available)?$available:$total, + 'logs' => $logs, + 'state' => logState(), + 'options' => $options + ) ); + break; + } + case 'export' : + { + if ( !canView( 'System' ) ) + ajaxError( 'Insufficient permissions to export logs' ); + + $minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL; + $maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL; + if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime ) + { + $tempTime = $minTime; + $minTime = $maxTime; + $maxTime = $tempTime; + } + //$limit = isset($_REQUEST['limit'])?$_REQUEST['limit']:1000; + $filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array(); + $sortField = isset($_REQUEST['sortField'])?$_REQUEST['sortField']:'TimeKey'; + $sortOrder = isset($_REQUEST['sortOrder'])?$_REQUEST['sortOrder']:'asc'; + + $sql = "select * from Logs"; + $where = array(); + if ( $minTime ) + { + preg_match( '/(.+)(\.\d+)/', $minTime, $matches ); + $minTime = strtotime($matches[1]).$matches[2]; + $where[] = "TimeKey >= ".$minTime; + } + if ( $maxTime ) + { + preg_match( '/(.+)(\.\d+)/', $maxTime, $matches ); + $maxTime = strtotime($matches[1]).$matches[2]; + $where[] = "TimeKey <= ".$maxTime; + } + foreach ( $filter as $field=>$value ) + if ( $value != '' ) + if ( $field == 'Level' ) + $where[] = dbEscape($field)." <= ".dbEscape($value); + else + $where[] = dbEscape($field)." = '".dbEscape($value)."'"; + if ( count($where) ) + $sql.= " where ".join( " and ", $where ); + $sql .= " order by ".dbEscape($sortField)." ".dbEscape($sortOrder); + //$sql .= " limit ".dbEscape($limit); + $format = isset($_REQUEST['format'])?$_REQUEST['format']:'text'; + switch( $format ) + { + case 'text' : + $exportExt = "txt"; + break; + case 'tsv' : + $exportExt = "tsv"; + break; + case 'html' : + $exportExt = "html"; + break; + case 'xml' : + $exportExt = "xml"; + break; + default : + Fatal( "Unrecognised log export format '$format'" ); + } + $exportKey = substr(md5(rand()),0,8); + $exportFile = "zm-log.$exportExt"; + $exportPath = "temp/zm-log-$exportKey.$exportExt"; + if ( !($exportFP = fopen( $exportPath, "w" )) ) + Fatal( "Unable to open log export file $exportFile" ); + $logs = array(); + foreach ( dbFetchAll( $sql ) as $log ) + { + $log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] ); + $logs[] = $log; + } + switch( $format ) + { + case 'text' : + { + foreach ( $logs as $log ) + { + if ( $log['Line'] ) + fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] ); + else + fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] ); + } + break; + } + case 'tsv' : + { + fprintf( $exportFP, $SLANG['DateTime']."\t".$SLANG['Component']."\t".$SLANG['Pid']."\t".$SLANG['Level']."\t".$SLANG['Message']."\t".$SLANG['File']."\t".$SLANG['Line']."\n" ); + foreach ( $logs as $log ) + { + fprintf( $exportFP, "%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + } + break; + } + case 'html' : + { + fwrite( $exportFP, +' + + + '.$SLANG['ZoneMinderLog'].' + + + +

'.$SLANG['ZoneMinderLog'].'

+

'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'

+

'.count($logs).' '.$SLANG['Logs'].'

+ + + +' ); + foreach ( $logs as $log ) + { + $classLevel = $log['Level']; + if ( $classLevel < Logger::FATAL ) + $classLevel = Logger::FATAL; + elseif ( $classLevel > Logger::DEBUG ) + $classLevel = Logger::DEBUG; + $logClass = 'log-'.strtolower(Logger::$codes[$classLevel]); + fprintf( $exportFP, " \n", $logClass, $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + } + fwrite( $exportFP, +' +
'.$SLANG['DateTime'].''.$SLANG['Component'].''.$SLANG['Pid'].''.$SLANG['Level'].''.$SLANG['Message'].''.$SLANG['File'].''.$SLANG['Line'].'
%s%s%d%s%s%s%s
+ +' ); + break; + } + case 'xml' : + { + fwrite( $exportFP, +' + + '.$_POST['selector'].'' ); + foreach ( $filter as $field=>$value ) + if ( $value != '' ) + fwrite( $exportFP, +' + <'.strtolower($field).'>'.htmlspecialchars($value).' + ' ); + fwrite( $exportFP, +' + '.$SLANG['DateTime'].''.$SLANG['Component'].''.$SLANG['Pid'].''.$SLANG['Level'].''.$SLANG['Message'].''.$SLANG['File'].''.$SLANG['Line'].' + + +' ); + foreach ( $logs as $log ) + { + fprintf( $exportFP, +" + %s + %s + %d + %s + + %s + %d + \n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); + } + fwrite( $exportFP, +' +' ); + break; + } + $exportExt = "xml"; + break; + } + fclose( $exportFP ); + ajaxResponse( array( + 'key' => $exportKey, + 'format' => $format, + ) ); + break; + } + case 'download' : + { + if ( !canView( 'System' ) ) + ajaxError( 'Insufficient permissions to download logs' ); + + if ( empty($_REQUEST['key']) ) + Fatal( "No log export key given" ); + $exportKey = $_REQUEST['key']; + if ( empty($_REQUEST['format']) ) + Fatal( "No log export format given" ); + $format = $_REQUEST['format']; + + switch( $format ) + { + case 'text' : + $exportExt = "txt"; + break; + case 'tsv' : + $exportExt = "tsv"; + break; + case 'html' : + $exportExt = "html"; + break; + case 'xml' : + $exportExt = "xml"; + break; + default : + Fatal( "Unrecognised log export format '$format'" ); + } + + $exportFile = "zm-log.$exportExt"; + $exportPath = "temp/zm-log-$exportKey.$exportExt"; + + header( "Pragma: public" ); + header( "Expires: 0" ); + header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); + header( "Cache-Control: private", false ); // required by certain browsers + header( "Content-Description: File Transfer" ); + header( 'Content-Disposition: attachment; filename="'.$exportFile.'"' ); + header( "Content-Transfer-Encoding: binary" ); + header( "Content-Type: application/force-download" ); + header( "Content-Length: ".filesize($exportPath) ); + readfile( $exportPath ); + exit( 0 ); + break; + } +} + +ajaxError( 'Unrecognised action or insufficient permissions' ); + +?> diff --git a/web/ajax/stream.php b/web/ajax/stream.php index e9546c76b..b869aea9b 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -21,23 +21,23 @@ if ( !@socket_bind( $socket, $locSockFile ) ) switch ( $_REQUEST['command'] ) { case CMD_VARPLAY : - //error_log( "Varplaying to ".$_REQUEST['rate'] ); + Debug( "Varplaying to ".$_REQUEST['rate'] ); $msg = pack( "lcn", MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768 ); break; case CMD_ZOOMIN : - //error_log( "Zooming to ".$_REQUEST['x'].",".$_REQUEST['y'] ); + Debug( "Zooming to ".$_REQUEST['x'].",".$_REQUEST['y'] ); $msg = pack( "lcnn", MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] ); break; case CMD_PAN : - //error_log( "Panning to ".$_REQUEST['x'].",".$_REQUEST['y'] ); + Debug( "Panning to ".$_REQUEST['x'].",".$_REQUEST['y'] ); $msg = pack( "lcnn", MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] ); break; case CMD_SCALE : - //error_log( "Scaling to ".$_REQUEST['scale'] ); + Debug( "Scaling to ".$_REQUEST['scale'] ); $msg = pack( "lcn", MSG_CMD, $_REQUEST['command'], $_REQUEST['scale'] ); break; case CMD_SEEK : - //error_log( "Seeking to ".$_REQUEST['offset'] ); + Debug( "Seeking to ".$_REQUEST['offset'] ); $msg = pack( "lcN", MSG_CMD, $_REQUEST['command'], $_REQUEST['offset'] ); break; default : diff --git a/web/css/Makefile.am b/web/css/Makefile.am index d1c7b5582..917b8f389 100644 --- a/web/css/Makefile.am +++ b/web/css/Makefile.am @@ -3,4 +3,6 @@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/css dist_web_DATA = \ - reset.css + reset.css \ + spinner.css \ + overlay.css diff --git a/web/css/Makefile.in b/web/css/Makefile.in index 9d5b9107f..e3c58b2af 100644 --- a/web/css/Makefile.in +++ b/web/css/Makefile.in @@ -208,7 +208,9 @@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/css dist_web_DATA = \ - reset.css + reset.css \ + spinner.css \ + overlay.css all: all-am diff --git a/web/css/overlay.css b/web/css/overlay.css new file mode 100644 index 000000000..de7ed5ecb --- /dev/null +++ b/web/css/overlay.css @@ -0,0 +1,49 @@ +.overlayMask { + position: absolute; + opacity: 0.6; + filter: alpha(opacity=60); + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=60); + z-index: 999; + background: #aaaaaa; +} + +.overlay { + display: none; + position: absolute; + background-color: #f0f0f0; + border: 2px solid #555555; + -moz-border-radius: 4px; + z-index: 1000; + overflow: hidden; +} + +.overlayHeader { + float: left; + background-color: #dddddd; + width: 100%; + border-bottom: 1px solid #666666; + color: black; +} + +.overlayTitle { + float: left; + padding: 10px 6px; + font-weight: bold; + width: auto; +} + +.overlayToolbar { + float: right; + font-weight: bold; + padding: 6px 4px; + width: auto; +} + +.overlayBody { + float: left; + width: 100%; +} + +.overlayContent { + padding: 4px 4px 6px; +} diff --git a/web/css/spinner.css b/web/css/spinner.css new file mode 100644 index 000000000..835d4e665 --- /dev/null +++ b/web/css/spinner.css @@ -0,0 +1,19 @@ +.spinner { + position: absolute; + opacity: 0.9; + filter: alpha(opacity=90); + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=90); + z-index: 1001; + background: #fff; +} +.spinner-msg { + text-align: center; + font-weight: bold; +} + +.spinner-img { + background: url(/graphics/spinner.gif) no-repeat; + width: 24px; + height: 24px; + margin: 0 auto; +} diff --git a/web/graphics/Makefile.am b/web/graphics/Makefile.am index 6e28cab0f..ec252c82e 100644 --- a/web/graphics/Makefile.am +++ b/web/graphics/Makefile.am @@ -4,4 +4,5 @@ webdir = @WEB_PREFIX@/graphics dist_web_DATA = \ favicon.ico \ + spinner.gif \ transparent.gif diff --git a/web/graphics/Makefile.in b/web/graphics/Makefile.in index f05c6819c..b31d1e11e 100644 --- a/web/graphics/Makefile.in +++ b/web/graphics/Makefile.in @@ -209,6 +209,7 @@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/graphics dist_web_DATA = \ favicon.ico \ + spinner.gif \ transparent.gif all: all-am diff --git a/web/graphics/spinner.gif b/web/graphics/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..53dd589fa194f5db985e4301c7a73ed4f1b9ad99 GIT binary patch literal 2545 zcma*pX;2hr8VB%~zPqQp=@B)`y1PS96NXtx1_oS2g;AJ+5se@Q;|&UOs2qwM!p4Ca zhJiUal?ExBdstaT~?f3m?cZgNh{frmzMrfcJ8)3 z;P)BJevgQNtw(cfF&90SnBnnr_M&xm@O%6 zzG;!w8(-4o!w_SKEsx_t8i2dHA{$xug+5j_t}~5!rEMsQGpY^uf8#e!ez!6*c<$`# z%2he_t-h<5RT`BLN|GpKWC}6HY^k+5Dom~L=dCyXf!71bXd=Do;)LbM zv+gGZ*&l+=TYuPh^HJ+{Um3v9W8Dqi zZsIDi!j*rKg;1w`oCOc;={#&)!ZF-E-<0u^i2Q3W!xltD%v-T4#;x)CfF(1Ouv)`p z>uUosDu9aCbKX*^H)pSF(Clw+wK}`3LC8Vd5wn~@j##n&8u(Or9|$_$-*q^|8tR^Ze!v`8XRU12fiFxN&Z^HeB_6{>ZFruBWn5U6U_WQI--B zG~o}Ys+mlEb+PC3o7FVVvN+9%m7%O}Y_c3WoYls|wT3|PzzV{wM+0F|$H`%9CT0Y^ za*mZIUl3}$c$+|-?~lU1Lc0B}sn(uvcimZ5#)MR#za@NWsrn^X=yb^$k3_>|w9gkR z>#sW<_Ea0KR$g0dg}fy7K69z6?%wR47d!o@ zGKEctobW(W=VY|Az1{V$NH$hYU5!_r3z~t<1_3#$IhT`+-0m8Lu3WANjbGvNg1vn1 z=E&h$lM^*FtCrg64J+q9{~$Yc&oK@)FJ9|wdu`CBEMKgD->DcQRuxrUW36azX6kqE z(WAIz&9a^4uqfQXZ?4*+k}M^TI=80q9GA}G8+>bb(fyeR`Q-S93>Q-=OX7E#U^f4~jWk3u>uE&r}55)J9D8+*U}{&~xy z+xheT3lqZ$_0RMat&nbp<_ki!f?+E=jik2kBu@#UnX z0AcCVU-1x`*#iFAGPG4?H)8U+YtUJCS?At3FP6 zWjMo76`C~5oga!z%d+xx$x-ljIYP1$9YjNGd0H&jsWL7XsM^)8O;wB>PVnYYXxtSh|$ifidD)RGQ}R zwHJrNIdVjTqdEklY&;>>dZRxDK`F>#B8Ki@pp8f7rwM2mppszvcw{I`Q1%>g09l6Ekr2-S;;<|g2awum zsj!Q?)Pbyi5x+M!F@WFk6jsdhHiry`x0GIzjy;Yj%rtk*Y|Rg9EEqf3wBpTM<@>(0 zk0}s;bd@I0{9$O~|I{qUIC4vLX&EGrCS`%OyAe_n3}9mSiO7}(QE&#Jdx176W`mkS qJBjK|(6Aas*VCO0)PD%QJkkj;=v4CXc=>?~L(zU 0 ) +{ + if ( php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']) ) + print( "Warning, overriding installed $localConfigFile file with local copy\n" ); + else + error_log( "Warning, overriding installed $localConfigFile file with local copy" ); + $configFile = $localConfigFile; +} + +$cfg = fopen( $configFile, "r") or die("Could not open config file."); while ( !feof($cfg) ) { $str = fgets( $cfg, 256 ); diff --git a/web/includes/database.php b/web/includes/database.php index 19fa57cbe..314029b20 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -69,16 +69,13 @@ function dbLog( $sql, $update=false ) global $dbLogLevel; $noExecute = $update && ($dbLogLevel >= DB_LOG_DEBUG); if ( $dbLogLevel > DB_LOG_OFF ) - error_log( "SQL-LOG: $sql".($noExecute?" (not executed)":"") ); + Debug( "SQL-LOG: $sql".($noExecute?" (not executed)":"") ); return( $noExecute ); } function dbError( $sql ) { - $err_ref = sprintf( "%X", rand( 0x100000, 0xffffff ) ); - error_log( "SQL-ERROR($err_ref): ".$sql ); - error_log( "SQL-ERROR($err_ref): ".mysql_error() ); - die( "An error has occurred and this operation cannot continue.
For full details check your web logs for the code '$err_ref'" ); + Fatal( "SQL-ERR '".mysql_error()."', statement was '".$sql."'" ); } function dbEscape( $string ) @@ -249,7 +246,7 @@ function getTableDescription( $table, $asString=1 ) //$desc['minLength'] = -128; break; default : - error_log( "Unexpected text qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); + Error( "Unexpected text qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); break; } } @@ -286,7 +283,7 @@ function getTableDescription( $table, $asString=1 ) //$desc['maxValue'] = 127; break; default : - error_log( "Unexpected integer qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); + Error( "Unexpected integer qualifier '".$matches[1]."' found for field '".$row['Field']."' in table '".$table."'" ); break; } if ( !empty($matches[1]) ) @@ -329,7 +326,7 @@ function getTableDescription( $table, $asString=1 ) } else { - error_log( "Can't parse database type '".$row['Type']."' found for field '".$row['Field']."' in table '".$table."'" ); + Error( "Can't parse database type '".$row['Type']."' found for field '".$row['Field']."' in table '".$table."'" ); } if ( $asString ) diff --git a/web/includes/functions.php b/web/includes/functions.php index 50b2bba6e..41ac8e549 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -103,7 +103,7 @@ function getAuthUser( $auth ) $remoteAddr = $_SERVER['REMOTE_ADDR']; if ( !$remoteAddr ) { - error_log( "Can't determine remote address for authentication, using empty string" ); + Error( "Can't determine remote address for authentication, using empty string" ); $remoteAddr = ""; } } @@ -125,7 +125,7 @@ function getAuthUser( $auth ) } } } - error_log( "Unable to authenticate user from auth hash '$auth'" ); + Error( "Unable to authenticate user from auth hash '$auth'" ); return( false ); } @@ -611,7 +611,7 @@ function buildSelect( $name, $contents, $behaviours=false ) $value = $_REQUEST[$arr]; if ( !preg_match_all( "/\[\s*['\"]?(\w+)[\"']?\s*\]/", $matches[2], $matches ) ) { - die( "Can't parse selector '$name'" ); + Fatal( "Can't parse selector '$name'" ); } for ( $i = 0; $i < count($matches[1]); $i++ ) { @@ -1158,7 +1158,7 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov imagecopyresampled( $thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight ); if ( !imagejpeg( $thumbImage, $thumbFile ) ) - error_log( "Can't create thumbnail '$thumbPath'" ); + Error( "Can't create thumbnail '$thumbPath'" ); } } @@ -1214,7 +1214,7 @@ function createListThumbnail( $event, $overwrite=false ) } else { - die( "No thumbnail width or height specified, please check in Options->Web" ); + Fatal( "No thumbnail width or height specified, please check in Options->Web" ); } $imageData = getImageSrc( $event, $frame, $scale, false, $overwrite ); @@ -1601,6 +1601,7 @@ function sortTag( $field ) return( "(v)" ); return( false ); } + function getLoad() { $uptime = shell_exec( 'uptime' ); @@ -2075,7 +2076,7 @@ function initX10Status() $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 ); if ( $socket < 0 ) { - die( "socket_create() failed: ".socket_strerror($socket) ); + Fatal( "socket_create() failed: ".socket_strerror($socket) ); } $sock_file = ZM_PATH_SOCKS.'/zmx10.sock'; if ( @socket_connect( $socket, $sock_file ) ) @@ -2083,7 +2084,7 @@ function initX10Status() $command = "status"; if ( !socket_write( $socket, $command ) ) { - die( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); + Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); } socket_shutdown( $socket, 1 ); $x10Output = ""; @@ -2127,7 +2128,7 @@ function setDeviceStatusX10( $key, $status ) $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 ); if ( $socket < 0 ) { - die( "socket_create() failed: ".socket_strerror($socket) ); + Fatal( "socket_create() failed: ".socket_strerror($socket) ); } $sock_file = ZM_PATH_SOCKS.'/zmx10.sock'; if ( @socket_connect( $socket, $sock_file ) ) @@ -2135,7 +2136,7 @@ function setDeviceStatusX10( $key, $status ) $command = "$status;$key"; if ( !socket_write( $socket, $command ) ) { - die( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); + Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); } socket_shutdown( $socket, 1 ); $x10Response = socket_read( $socket, 256 ); @@ -2155,6 +2156,41 @@ function setDeviceStatusX10( $key, $status ) return( $status ); } +function logState() +{ + $state = 'ok'; + + $levelCounts = array( + Logger::FATAL => array( ZM_LOG_ALERT_FAT_COUNT, ZM_LOG_ALARM_FAT_COUNT ), + Logger::ERROR => array( ZM_LOG_ALERT_ERR_COUNT, ZM_LOG_ALARM_ERR_COUNT ), + Logger::WARNING => array( ZM_LOG_ALERT_WAR_COUNT, ZM_LOG_ALARM_WAR_COUNT ), + ); + + $sql = "select Level, count(Level) as LevelCount from Logs where Level < ".Logger::INFO." and from_unixtime(TimeKey) + interval ".ZM_LOG_CHECK_PERIOD." second > now() group by Level order by Level asc"; + $counts = dbFetchAll( $sql ); + + foreach ( $counts as $count ) + { + if ( $count['Level'] <= Logger::PANIC ) + $count['Level'] = Logger::FATAL; + if ( !($levelCount = $levelCounts[$count['Level']]) ) + { + Error( "Unexpected Log level ".$count['Level'] ); + next; + } + if ( $levelCount[1] && $count['LevelCount'] >= $levelCount[1] ) + { + $state = 'alarm'; + break; + } + elseif ( $levelCount[0] && $count['LevelCount'] >= $levelCount[0] ) + { + $state = 'alert'; + } + } + return( $state ); +} + function isVector ( &$array ) { $next_key = 0; @@ -2173,15 +2209,15 @@ function checkJsonError() switch( json_last_error() ) { case JSON_ERROR_DEPTH : - die( "Unable to decode JSON string '$value', maximum stack depth exceeded" ); + Fatal( "Unable to decode JSON string '$value', maximum stack depth exceeded" ); case JSON_ERROR_CTRL_CHAR : - die( "Unable to decode JSON string '$value', unexpected control character found" ); + Fatal( "Unable to decode JSON string '$value', unexpected control character found" ); case JSON_ERROR_STATE_MISMATCH : - die( "Unable to decode JSON string '$value', invalid or malformed JSON" ); + Fatal( "Unable to decode JSON string '$value', invalid or malformed JSON" ); case JSON_ERROR_SYNTAX : - die( "Unable to decode JSON string '$value', syntax error" ); + Fatal( "Unable to decode JSON string '$value', syntax error" ); default : - die( "Unable to decode JSON string '$value', unexpected error ".json_last_error() ); + Fatal( "Unable to decode JSON string '$value', unexpected error ".json_last_error() ); case JSON_ERROR_NONE: break; } @@ -2280,9 +2316,7 @@ define( 'HTTP_STATUS_FORBIDDEN', 403 ); function ajaxError( $message, $code=HTTP_STATUS_OK ) { - error_log( $message ); - if ( function_exists( 'debug_backtrace' ) ) - error_log( var_export( debug_backtrace(), true ) ); + Error( $message ); if ( function_exists( 'ajaxCleanup' ) ) ajaxCleanup(); if ( $code == HTTP_STATUS_OK ) @@ -2304,7 +2338,6 @@ function ajaxResponse( $result=false ) $response = array_merge( $response, $result ); elseif ( !empty($result) ) $response['message'] = $result; - //error_log( var_export( $response, true ) ); header( "Content-type: text/plain" ); exit( jsonEncode( $response ) ); } diff --git a/web/includes/logger.php b/web/includes/logger.php new file mode 100644 index 000000000..71c8149e9 --- /dev/null +++ b/web/includes/logger.php @@ -0,0 +1,594 @@ + "DBG", + self::INFO => "INF", + self::WARNING => "WAR", + self::ERROR => "ERR", + self::FATAL => "FAT", + self::PANIC => "PNC", + self::NOLOG => "OFF", + ); + private static $syslogPriorities = array( + self::DEBUG => LOG_DEBUG, + self::INFO => LOG_INFO, + self::WARNING => LOG_WARNING, + self::ERROR => LOG_ERR, + self::FATAL => LOG_ERR, + self::PANIC => LOG_ERR, + ); + private static $phpErrorLevels = array( + self::DEBUG => E_USER_NOTICE, + self::INFO => E_USER_NOTICE, + self::WARNING => E_USER_WARNING, + self::ERROR => E_USER_WARNING, + self::FATAL => E_USER_ERROR, + self::PANIC => E_USER_ERROR, + ); + + private function __construct() + { + $this->hasTerm = (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])); + $this->logFile = $this->logPath."/".$this->id.".log"; + } + + public function __destruct() + { + $this->terminate(); + } + + public function initialise( $options=array() ) + { + if ( !empty($options['id']) ) + $this->id = $options['id']; + + //if ( isset($options['useErrorLog']) ) + //$this->useErrorLog = $options['useErrorLog']; + if ( isset($options['logPath']) ) + { + $this->logPath = $options['logPath']; + $tempLogFile = $this->logPath."/".$this->id.".log"; + } + if ( isset($options['logFile']) ) + $tempLogFile = $options['logFile']; + else + $tempLogFile = $this->logPath."/".$this->id.".log"; + if ( !is_null($logFile = $this->getTargettedEnv('LOG_FILE')) ) + $tempLogFile = $logFile; + + $tempLevel = self::INFO; + $tempTermLevel = $this->termLevel; + $tempDatabaseLevel = $this->databaseLevel; + $tempFileLevel = $this->fileLevel; + $tempSyslogLevel = $this->syslogLevel; + $tempWeblogLevel = $this->weblogLevel; + + if ( isset($options['termLevel']) ) + $tempTermLevel = $options['termLevel']; + if ( isset($options['databaseLevel']) ) + $tempDatabaseLevel = $options['databaseLevel']; + else + $tempDatabaseLevel = ZM_LOG_LEVEL_DATABASE; + if ( isset($options['fileLevel']) ) + $tempFileLevel = $options['fileLevel']; + else + $tempFileLevel = ZM_LOG_LEVEL_FILE; + if ( isset($options['weblogLevel']) ) + $tempWeblogLevel = $options['weblogLevel']; + else + $tempWeblogLevel = ZM_LOG_LEVEL_WEBLOG; + if ( isset($options['syslogLevel']) ) + $tempSyslogLevel = $options['syslogLevel']; + else + $tempSyslogLevel = ZM_LOG_LEVEL_SYSLOG; + + if ( isset($_ENV['LOG_PRINT']) ) + $tempTermLevel = $_ENV['LOG_PRINT']? self::DEBUG : self::NOLOG; + + if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL')) ) + $tempLevel = $level; + + if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_TERM')) ) + $tempTermLevel = $level; + if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_DATABASE')) ) + $tempDatabaseLevel = $level; + if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_FILE')) ) + $tempFileLevel = $level; + if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_SYSLOG')) ) + $tempSyslogLevel = $level; + if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_WEBLOG')) ) + $tempWeblogLevel = $level; + + if ( ZM_LOG_DEBUG ) + { + foreach ( explode( '|', ZM_LOG_DEBUG_TARGET ) as $target ) + { + if ( $target == $this->id || $target == "_".$this->id || $target == $this->idRoot || $target == "_".$this->idRoot || $target == "" ) + { + if ( ZM_LOG_DEBUG_LEVEL > self::NOLOG ) + { + $tempLevel = $this->limit( ZM_LOG_DEBUG_LEVEL ); + if ( ZM_LOG_DEBUG_FILE != "" ) + { + $tempLogFile = ZM_LOG_DEBUG_FILE; + $tempFileLevel = $tempLevel; + } + } + } + } + } + + $this->logFile( $tempLogFile ); + + $this->termLevel( $tempTermLevel ); + $this->databaseLevel( $tempDatabaseLevel ); + $this->fileLevel( $tempFileLevel ); + $this->syslogLevel( $tempSyslogLevel ); + $this->weblogLevel( $tempWeblogLevel ); + + $this->level( $tempLevel ); + + $this->initialised = true; + + Debug( "LogOpts: level=".self::$codes[$this->level]."/".self::$codes[$this->effectiveLevel].", screen=".self::$codes[$this->termLevel].", database=".self::$codes[$this->databaseLevel].", logfile=".self::$codes[$this->fileLevel]."->".$this->logFile.", weblog=".self::$codes[$this->weblogLevel].", syslog=".self::$codes[$this->syslogLevel] ); + } + + private function terminate() + { + if ( $this->initialised ) + { + if ( $this->fileLevel > self::NOLOG ) + $this->closeFile(); + if ( $this->syslogLevel > self::NOLOG ) + $this->closeSyslog(); + } + $this->initialised = false; + } + + private function limit( $level ) + { + if ( $level > self::DEBUG ) + return( self::DEBUG ); + if ( $level < self::NOLOG ) + return( self::NOLOG ); + return( $level ); + } + + private function getTargettedEnv( $name ) + { + $envName = $name."_".$this->id; + if ( isset($ENV[$envName]) ) + $value = $ENV[$envName]; + if ( empty($value) && $this->id != $this->idRoot ) + { + $envName = $name."_".$this->idRoot; + if ( isset($ENV[$envName]) ) + $value = $ENV[$envName]; + } + if ( empty($value) ) + { + if ( isset($ENV[$name]) ) + $value = $ENV[$name]; + } + return( isset($value)?$value:NULL ); + } + + public static function fetch( $initialise=true ) + { + if ( !isset(self::$instance) ) + { + $class = __CLASS__; + self::$instance = new $class; + if ( $initialise ) + self::$instance->initialise( array( 'id'=>'web_php', 'syslogLevel'=>self::INFO, 'weblogLevel'=>self::INFO ) ); + } + return self::$instance; + } + + public function id( $id=NULL ) + { + if ( isset($id) && $this->id != $id ) + { + // Remove whitespace + $id = preg_replace( '/\S/', '', $id ); + // Replace non-alphanum with underscore + $id = preg_replace( '/[^a-zA-Z_]/', '_', $id ); + + if ( $this->id != $id ) + { + $this->id = $this->idRoot = $id; + if ( preg_match( '/^([^_]+)_(.+)$/', $id, $matches ) ) + { + $this->idRoot = $matches[1]; + $this->idArgs = $matches[2]; + } + } + } + return( $this->id ); + } + + public function level( $level ) + { + if ( isset($level) ) + { + $lastLevel = $this->level; + $this->level = $this->limit($level); + $this->effectiveLevel = self::NOLOG; + if ( $this->termLevel > $this->effectiveLevel ) + $this->effectiveLevel = $this->termLevel; + if ( $this->databaseLevel > $this->effectiveLevel ) + $this->effectiveLevel = $this->databaseLevel; + if ( $this->fileLevel > $this->effectiveLevel ) + $this->effectiveLevel = $this->fileLevel; + if ( $this->weblogLevel > $this->effectiveLevel ) + $this->effectiveLevel = $this->weblogLevel; + if ( $this->syslogLevel > $this->effectiveLevel ) + $this->effectiveLevel = $this->syslogLevel; + if ( $this->effectiveLevel > $this->level ) + $this->effectiveLevel = $this->level; + if ( !$this->hasTerm ) + { + if ( $lastLevel < self::DEBUG && $this->level >= self::DEBUG ) + { + $this->savedErrorReporting = error_reporting( E_ALL ); + $this->savedDisplayErrors = ini_set( 'display_errors', true ); + } + elseif ( $lastLevel >= self::DEBUG && $this->level < self::DEBUG ) + { + error_reporting( $this->savedErrorReporting ); + ini_set( 'display_errors', $this->savedDisplayErrors ); + } + } + } + return( $this->level ); + } + + public function debugOn() + { + return( $this->effectiveLevel >= self::DEBUG ); + } + + public function termLevel( $termLevel ) + { + if ( isset($termLevel) ) + { + $termLevel = $this->limit($termLevel); + if ( $this->termLevel != $termLevel ) + $this->termLevel = $termLevel; + } + return( $this->termLevel ); + } + + public function databaseLevel( $databaseLevel=NULL ) + { + if ( !is_null($databaseLevel) ) + { + $databaseLevel = $this->limit($databaseLevel); + if ( $this->databaseLevel != $databaseLevel ) + { + $this->databaseLevel = $databaseLevel; + if ( $this->databaseLevel > self::NOLOG ) + { + if ( (include_once 'database.php') === FALSE ) + { + $this->databaseLevel = self::NOLOG; + Warning( "Unable to write log entries to DB, database.php not found" ); + } + } + } + } + return( $this->databaseLevel ); + } + + public function fileLevel( $fileLevel ) + { + if ( isset($fileLevel) ) + { + $fileLevel = $this->limit($fileLevel); + if ( $this->fileLevel != $fileLevel ) + { + if ( $this->fileLevel > self::NOLOG ) + $this->closeFile(); + $this->fileLevel = $fileLevel; + if ( $this->fileLevel > self::NOLOG ) + $this->openFile(); + } + } + return( $this->fileLevel ); + } + + public function weblogLevel( $weblogLevel ) + { + if ( isset($weblogLevel) ) + { + $weblogLevel = $this->limit($weblogLevel); + if ( $this->weblogLevel != $weblogLevel ) + { + if ( $weblogLevel > self::NOLOG && $this->weblogLevel <= self::NOLOG ) + { + $this->savedLogErrors = ini_set( 'log_errors', true ); + } + elseif ( $weblogLevel <= self::NOLOG && $this->weblogLevel > self::NOLOG ) + { + ini_set( 'log_errors', $this->savedLogErrors ); + } + $this->weblogLevel = $weblogLevel; + } + } + return( $this->weblogLevel ); + } + + public function syslogLevel( $syslogLevel ) + { + if ( isset($syslogLevel) ) + { + $syslogLevel = $this->limit($syslogLevel); + if ( $this->syslogLevel != $syslogLevel ) + { + if ( $this->syslogLevel > self::NOLOG ) + $this->closeSyslog(); + $this->syslogLevel = $syslogLevel; + if ( $this->syslogLevel > self::NOLOG ) + $this->openSyslog(); + } + } + return( $this->syslogLevel ); + } + + private function openSyslog() + { + openlog( $this->id, LOG_PID|LOG_NDELAY, LOG_LOCAL1 ); + } + + private function closeSyslog() + { + closelog(); + } + + private function logFile( $logFile ) + { + if ( preg_match( '/^(.+)\+$/', $logFile, $matches ) ) + $this->logFile = $matches[1].'.'.getmypid(); + else + $this->logFile = $logFile; + } + + private function openFile() + { + if ( !$this->useErrorLog ) + { + if ( $this->logFd = fopen( $this->logFile, "a+" ) ) + { + if ( strnatcmp( phpversion(), '5.2.0' ) >= 0 ) + { + $error = error_get_last(); + trigger_error( "Can't open log file '$logFile': ".$error['message']." @ ".$error['file']."/".$error['line'], E_USER_ERROR ); + } + $this->fileLevel = self::NOLOG; + } + } + } + + private function closeFile() + { + if ( $this->logFd ) + fclose( $this->logFd ); + } + + public function logPrint( $level, $string, $file=NULL, $line=NULL ) + { + if ( $level <= $this->effectiveLevel ) + { + $string = preg_replace( '/[\r\n]+$/', '', $string ); + $code = self::$codes[$level]; + + $time = gettimeofday(); + $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", $time['sec'] ), $time['usec'], $this->id, getmypid(), $code, $string ); + + if ( is_null( $file) ) + { + if ( $this->useErrorLog || $this->databaseLevel > self::NOLOG ) + { + $backTrace = debug_backtrace(); + $file = $backTrace[1]['file']; + $line = $backTrace[1]['line']; + if ( $this->hasTerm ) + $rootPath = getcwd(); + else + $rootPath = $_SERVER['DOCUMENT_ROOT']; + $file = preg_replace( '/^'.addcslashes($rootPath,'/').'\/?/', '', $file ); + } + } + + if ( $this->useErrorLog ) + $message .= " at ".$file." line ".$line; + else + $message = $message; + + if ( $level <= $this->termLevel ) + if ( $this->hasTerm ) + print( $message."\n" ); + else + print( preg_replace( "/\n/", '
', htmlspecialchars($message) )."
" ); + + if ( $level <= $this->fileLevel ) + if ( $this->useErrorLog ) + { + if ( !error_log( $message."\n", 3, $this->logFile ) ) + { + if ( strnatcmp(phpversion(),'5.2.0') >= 0 ) + { + $error = error_get_last(); + trigger_error( "Can't write to log file '$logFile': ".$error['message']." @ ".$error['file']."/".$error['line'], E_USER_ERROR ); + } + } + } + elseif ( $this->logFd ) + fprintf( $this->logFd, $message."\n" ); + + $message = $code." [".$string."]"; + if ( $level <= $this->syslogLevel ) + syslog( self::$syslogPriorities[$level], $message ); + if ( $level <= $this->databaseLevel ) + { + $dbFile = is_null($file)?'NULL':"'".dbEscape($file)."'"; + $dbLine = is_null($line)?'NULL':dbEscape($line); + $sql = "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ".sprintf( "%d.%06d", $time['sec'], $time['usec'] ).", '".dbEscape($this->id)."', ".getmypid().", ".dbEscape($level).", '".dbEscape($code)."', '".dbEscape($string)."', ".$dbFile.", ".$dbLine." )"; + if (!($result = mysql_query( $sql ))) + { + $this->databaseLevel = self::NOLOG; + Fatal( "Can't write log entry '$sql': ".mysql_error() ); + } + } + // This has to be last as trigger_error can be fatal + if ( $level <= $this->weblogLevel ) + { + if ( $this->useErrorLog ) + error_log( $message, 0 ); + else + trigger_error( $message, self::$phpErrorLevels[$level] ); + } + } + } +}; + +function logInit( $options=array() ) +{ + $logger = Logger::fetch(); + $logger->initialise( $options ); + set_error_handler( 'ErrorHandler' ); +} + +function logToDatabase( $level=NULL ) +{ + return( Logger::fetch()->databaseLevel( $level ) ); +} + +function Mark( $level=Logger::DEBUG, $tag="Mark" ) +{ + Logger::fetch()->logPrint( $level, $tag ); +} + +function Dump( &$var, $label="VAR" ) +{ + ob_start(); + print( $label." => " ); + print_r( $var ); + Logger::fetch()->logPrint( Logger::DEBUG, ob_get_clean() ); +} + +function Debug( $string ) +{ + Logger::fetch()->logPrint( Logger::DEBUG, $string ); +} + +function Info( $string ) +{ + Logger::fetch()->logPrint( Logger::INFO, $string ); +} + +function Warning( $string ) +{ + Logger::fetch()->logPrint( Logger::WARNING, $string ); +} + +function Error( $string ) +{ + Logger::fetch()->logPrint( Logger::ERROR, $string ); +} + +function Fatal( $string ) +{ + Logger::fetch()->logPrint( Logger::FATAL, $string ); + die( $string ); +} + +function Panic( $string ) +{ + if ( true ) + { + // Use builtin function + ob_start(); + debug_print_backtrace(); + $backtrace = "\n".ob_get_clean(); + } + else + { + // Roll your own + $backtrace = ''; + $frames = debug_backtrace(); + for ( $i = 0; $i < count($frames); $i++ ) + { + $frame = $frames[$i]; + $backtrace .= sprintf( "\n#%d %s() at %s/%d", $i, $frame['function'], $frame['file'], $frame['line'] ); + } + } + Logger::fetch()->logPrint( Logger::PANIC, $string.$backtrace ); + die( $string ); +} + +function ErrorHandler( $error, $string, $file, $line ) +{ + if ( ! (error_reporting() & $error) ) + { + // This error code is not included in error_reporting + return( false ); + } + + switch ( $error ) + { + case E_USER_ERROR: + Logger::fetch()->logPrint( Logger::FATAL, $string, $file, $line ); + break; + + case E_USER_WARNING: + Logger::fetch()->logPrint( Logger::ERROR, $string, $file, $line ); + break; + + case E_USER_NOTICE: + Logger::fetch()->logPrint( Logger::WARNING, $string, $file, $line ); + break; + + default: + Panic( "Unknown error type: [$error] $string" ); + break; + } + return( true ); +} + +?> diff --git a/web/index.php b/web/index.php index 50350349a..76f07e19e 100644 --- a/web/index.php +++ b/web/index.php @@ -68,7 +68,7 @@ define( "ZM_SKIN_PATH", "skins/$skin" ); $skinBase = array(); // To allow for inheritance of skins if ( !file_exists( ZM_SKIN_PATH ) ) - die( "Invalid skin '$skin'" ); + Fatal( "Invalid skin '$skin'" ); require_once( ZM_SKIN_PATH.'/includes/init.php' ); $skinBase[] = $skin; @@ -83,6 +83,7 @@ if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) ) } require_once( 'includes/config.php' ); +require_once( 'includes/logger.php' ); if ( ZM_OPT_USE_AUTH ) if ( isset( $_SESSION['user'] ) ) @@ -113,8 +114,7 @@ if ( isset( $_REQUEST['request'] ) ) { if ( !file_exists( $includeFile ) ) { - error_log( "Request '$request' does not exist" ); - die( "Request '$request' does not exist" ); + Fatal( "Request '$request' does not exist" ); } require_once $includeFile; } @@ -128,8 +128,7 @@ else { if ( !file_exists( $includeFile ) ) { - error_log( "View '$view' does not exist" ); - die( "View '$view' does not exist" ); + Fatal( "View '$view' does not exist" ); } require_once $includeFile; } diff --git a/web/js/Makefile.am b/web/js/Makefile.am index 984a12490..21c10613e 100644 --- a/web/js/Makefile.am +++ b/web/js/Makefile.am @@ -3,4 +3,6 @@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/js dist_web_DATA = \ - mootools.ext.js + logger.js \ + overlay.js \ + mootools.ext.js diff --git a/web/js/Makefile.in b/web/js/Makefile.in index cd66cc999..2fb8c630a 100644 --- a/web/js/Makefile.in +++ b/web/js/Makefile.in @@ -208,7 +208,9 @@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/js dist_web_DATA = \ - mootools.ext.js + logger.js \ + overlay.js \ + mootools.ext.js all: all-am diff --git a/web/js/logger.js b/web/js/logger.js new file mode 100644 index 000000000..e7f98c301 --- /dev/null +++ b/web/js/logger.js @@ -0,0 +1,116 @@ +// +// ZoneMinder logger javascript file, $Date: 2011-05-27 22:24:17 +0100 (Fri, 27 May 2011) $, $Revision: 3374 $ +// Copyright (C) 2001-2008 Philip Coombes +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// + +if ( !window.console ) +{ + window.console = + { + init:function() {}, + log:function() {}, + debug:function() {}, + info:function() {}, + warn:function() {}, + error:function() {} + }; +} +if ( !console.debug )//IE8 has console but doesn't have console.debug so lets alias it. + console.debug = console.log; + +var reportLogs = true; + +var debugParms; +var debugReq; + +function logReport( level, message, file, line ) +{ + if ( !reportLogs ) + return; + + if ( typeof(MooTools) == "undefined" ) + return; + + if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.name ) + message += ' - '+arguments.callee.caller.caller.name+'()'; + + if ( !debugReq ) + { + debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+Browser.Platform.name; + debugReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain' } ); + } + var requestParms = debugParms; + requestParms += "&level="+level+"&message="+encodeURIComponent(message); + if ( file ) + requestParms += "&file="+file; + else + requestParms += "&file="+location.search; + if ( line ) + requestParms += "&line="+line; + debugReq.send( requestParms ); +} + +function Panic( message ) +{ + console.error( message ); + logReport( "PNC", message ); + alert( "PANIC: "+message ); +} + +function Fatal( message ) +{ + console.error( message ); + logReport( "FAT", message ); + alert( "FATAL: "+message ); +} + +function Error( message ) +{ + console.error( message ); + logReport( "ERR", message ); +} + +function Warning( message ) +{ + console.warn( message ); + logReport( "WAR", message ); +} + +function Info( message ) +{ + console.info( message ); + logReport( "INF", message ); +} + +function Debug( message ) +{ + console.debug( message ); + //logReport( "DBG", message ); +} + +function Dump( value, label ) +{ + if ( label ) + console.debug( label+" => " ); + console.debug( value ); +} + +window.onerror = + function( message, url, line ) + { + logReport( "ERR", message, url, line ); + } diff --git a/web/js/mootools.ext.js b/web/js/mootools.ext.js index 78b5ab99d..bc2f276e3 100644 --- a/web/js/mootools.ext.js +++ b/web/js/mootools.ext.js @@ -1,22 +1,20 @@ /* * MooTools Extension script to support custom extensions to mootools */ -var zmMooToolsVersion = '1.2.5'; +var zmMooToolsVersion = '1.3.2'; /* * Firstly, lets check that mootools has been included and thus is present */ if ( typeof(MooTools) == "undefined" ) { - alert( "MooTools not found! Please download from\nhttp://mootools.net and install in ZoneMinder web root." ); + alert( "MooTools not found! Please check that it was installed correctly in ZoneMinder web root." ); } else { - //console.log( "Got MooTools version "+MooTools.version ); - /* Version check */ if ( MooTools.version < zmMooToolsVersion ) { - alert( "MooTools version "+MooTools.version+" found.\nVersion "+zmMooToolsVersion+" required, please upgrade." ); + alert( "MooTools version "+MooTools.version+" found.\nVersion "+zmMooToolsVersion+" required, please check that it was installed correctly in ZoneMinder web root." ); } } diff --git a/web/js/overlay.js b/web/js/overlay.js new file mode 100644 index 000000000..3c03c82bb --- /dev/null +++ b/web/js/overlay.js @@ -0,0 +1,141 @@ +var Overlay = new Class({ + Implements: [Options, Events], + initialize: function( id, options ) + { + this.setOptions( options ); + + this.loadingImagePath = '/images/loading.gif'; + this.loadingImageSize = { width: 208 , height: 13 }; + + //this.loadingImage = new Asset.image( this.loadingImagePath ); + //this.loadingImage.setStyles( { 'height': this.loadingImageSize.height, 'width': this.loadingImageSize.width } ); + + this.styles = new Asset.css( "/css/overlay.css" ); + + this.mask = new Mask( document.body, { 'maskMargins': false, 'class': 'overlayMask' } ); + + this.id = id?id:'overlay'; + if ( typeOf(this.id) == 'string' ) + { + if ( $(this.id) ) + this.element = $(this.id); + } + else + { + this.element = this.id; + this.id = this.element.get('id'); + } + if ( !this.element ) + { + this.element = new Element( 'div', { 'id': this.id, 'class': 'overlay', 'styles': { 'display': 'none' } } ); + if ( this.options.title || this.options.buttons ) + { + var overlayHeader = new Element( 'div', { 'class': 'overlayHeader' } ); + if ( this.options.title ) + { + var overlayTitle = new Element( 'div', { 'class': 'overlayTitle', 'text': this.options.title } ); + overlayHeader.grab( overlayTitle ); + } + if ( this.options.buttons ) + { + var overlayToolbar = new Element( 'div', { 'class': 'overlayToolbar' } ); + this.options.buttons.each( + function( button ) + { + var overlayButton = new Element( 'button', { 'text': button.text } ); + if ( button.id ) + overlayButton.setProperty( 'id', button.id ); + if ( button.events ) + overlayButton.set( 'events', events ); + overlayToolbar.grab( overlayButton ); + } + ); + overlayHeader.grab( overlayTitle ); + } + this.element.grab( overlayHeader ); + var overlayBody = new Element( 'div', { 'class': 'overlayBody' } ); + var overlayContent = new Element( 'div', { 'class': 'overlayContent' } ); + overlayContent.grab( this.options.content ); + overlayBody.grab( overlayContent ); + this.element.grab( overlayBody ); + } + this.target = document.id(this.options.target) || document.id(document.body); + this.element.inject( this.target ); + } + }, + show: function() + { + this.mask.show(); + $(window).addEvent( 'resize', this.update.bind(this) ); + $(window).addEvent( 'scroll', this.update.bind(this) ); + this.element.tween( 'opacity', [0, 1.0] ); + this.element.show(); + this.element.position(); + this.mask.position(); + }, + hideComplete: function() + { + $(window).removeEvent( 'resize', this.update.bind(this) ); + $(window).removeEvent( 'scroll', this.update.bind(this) ); + this.element.hide(); + this.mask.hide(); + }, + hide: function() + { + new Fx.Tween( this.element, { duration: 400, transition: Fx.Transitions.Sine, onComplete: this.hideComplete.bind(this) } ).start( 'opacity', 1.0, 0 ); + }, + update: function() + { + this.element.position(); + this.mask.position(); + }, + showAnimation:function() + { + showOverlay(); + + //console.log( "Showing overlay loading" ); + if ( !this.loading ) + { + this.loading = new Element( 'div', { 'id': 'loading'+this.key, 'styles': { 'display':'none' } } ); + this.loading.grab( this.loadingImage ); + document.body.grab( this.loading ); + } + updateOverlayLoading(); + this.loading.setStyle( 'display', 'block' ); + $(window).addEvent( 'resize', this.update.bind(this) ); + $(window).addEvent( 'scroll', this.update.bind(this) ); + }, + hideAnimation:function() + { + $(window).removeEvent( 'resize', this.update.bind(this) ); + $(window).removeEvent( 'scroll', this.update.bind(this) ); + if ( this.loading ) + this.loading.setStyle( 'display', 'none' ); + } +}); + +function setupOverlays() +{ + try { + $$('.overlay').each( + function( overlay ) + { + overlay.element = new Overlay( overlay.get('id') ); + overlay.getElements('.overlayCloser').each( + function( closer ) + { + closer.addEvent( 'click', function() { overlay.element.hide(); } ) + } + ); + overlay.overlayShow = function() { overlay.element.show(); }; + overlay.overlayHide = function() { overlay.element.hide(); }; + } + ); + } + catch ( e ) + { + alert( e ); + } +} + +window.addEvent( 'domready', setupOverlays ); diff --git a/web/lang/big5_big5.php b/web/lang/big5_big5.php index 474d893fb..a295ed1c4 100644 --- a/web/lang/big5_big5.php +++ b/web/lang/big5_big5.php @@ -207,10 +207,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Method', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Choose Filter', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => '關閉', 'Colour' => 'Colour', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'é…置為', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -230,6 +234,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => '分å€è¼ªæµæª¢è¦–', 'CycleWatch' => '分å€è¼ªæµæª¢è¦–', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'æ—¥', 'Debug' => 'debug', 'DefaultRate' => 'é è¨­é€ŸçŽ‡', @@ -251,6 +256,7 @@ $SLANG = array( 'DisableAlarms' => 'å–消警報', 'Disk' => 'ç£ç¢Ÿ', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -288,6 +294,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => '輸出框架細項', 'ExportImageFiles' => '輸出圖片檔', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => '輸出其他檔(若有)', 'ExportOptions' => '輸出é¸é …', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -363,16 +370,21 @@ $SLANG = array( 'Language' => '語言', 'Last' => 'Last', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'results only;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => '列出', 'Load' => '載入', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => '登入å稱', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => '登入中... è«‹ç¨å¾Œ...', 'Login' => '登入', 'Logout' => '登出', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => '低', 'LowBW' => 'Low B/W', 'Main' => 'Main', @@ -406,6 +418,7 @@ $SLANG = array( 'MaximumFPS' => '最大æ¯ç§’框架數 fps', 'Medium' => '中', 'MediumBW' => 'Medium B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum blob area should be less than maximum', @@ -449,6 +462,7 @@ $SLANG = array( 'Monitors' => '監視', 'Montage' => '全部顯示', 'Month' => '月', + 'More' => 'More', // Added - 2011-06-16 'Move' => '移動', 'MustBeGe' => '需大於或等於', 'MustBeLe' => '需å°æ–¼æˆ–等於', @@ -509,6 +523,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Phone B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -564,6 +579,8 @@ $SLANG = array( 'Secs' => 'Secs', 'Sectionlength' => '片段長度', 'Select' => 'é¸å–', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -606,6 +623,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'å°åœ–檢視', 'Tilt' => 'Tilt', @@ -619,6 +637,7 @@ $SLANG = array( 'TimestampLabelY' => '時間標示 Y', 'Today' => 'Today', 'Tools' => 'Tools', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => '全部
分數', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -633,6 +652,7 @@ $SLANG = array( 'Update' => 'Update', // Added - 2009-02-08 'UpdateAvailable' => 'An update to ZoneMinder is available.', 'UpdateNotNecessary' => 'No update is necessary.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Use Filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -684,6 +704,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => '監視å€', 'Zoom' => 'Zoom', diff --git a/web/lang/cn_zh.php b/web/lang/cn_zh.php index c4e22af03..23d428da1 100644 --- a/web/lang/cn_zh.php +++ b/web/lang/cn_zh.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => '报警检查方å¼', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => '选择筛选器', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => '选择预置', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => '关闭', 'Colour' => '彩色', 'Command' => '命令', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'é…ç½®', 'ConfiguredFor' => 'é…置标的', 'ConfirmDeleteEvents' => '确认希望删除所选事件?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'å¯æŽ§', 'Cycle' => '循环', 'CycleWatch' => '循环监视', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'æ—¥', 'Debug' => '调试', 'DefaultRate' => '缺çœé€ŸçŽ‡', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => '关闭警报', 'Disk' => 'ç£ç¢Ÿ', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => '请æ款', 'DonateAlready' => 'ä¸ï¼Œæˆ‘å·²ç»æ赠过了', 'DonateEnticement' => '迄今,您已ç»è¿è¡ŒZoneMinder有一阵å­äº†ï¼Œå¸Œæœ›å®ƒèƒ½å¤Ÿæœ‰åŠ©äºŽå¢žå¼ºæ‚¨å®¶æˆ–者办公区域的安全。尽管ZoneMinder是,并将ä¿æŒå…费和开æºï¼Œè¯¥é¡¹ç›®ä¾ç„¶åœ¨ç ”å‘和支æŒä¸­æŠ•å…¥äº†èµ„金和精力。如果您愿æ„支æŒä»ŠåŽçš„å¼€å‘和新功能,那么请考虑为该项目æ款。æ款ä¸æ˜¯å¿…须的,任何数é‡çš„æ赠,我们都很感谢。

如果您愿æ„æ款,请选择下列选项,或者访问 http://www.zoneminder.com/donate.html æ赠主页。

感谢您使用ZoneMinder,并且ä¸è¦å¿˜è®°è®¿é—®è®¿é—®ZoneMinder.com的论å›ä»¥èŽ·å¾—支æŒæˆ–建议,这å¯ä»¥æå‡æ‚¨çš„ZoneMinder的体验。', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => '导出帧详情', 'ExportImageFiles' => '导出影åƒæ–‡ä»¶', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => '导出其他文件 (如果存在)', 'ExportOptions' => '导出选项', 'ExportSucceeded' => '导出æˆåŠŸ', @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => '语言', 'Last' => '最åŽ', 'Layout' => '布局', + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => '个结果', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'ä»…é™äºŽå¼€å§‹', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => '管ç†ç›‘视器', 'List' => '列表', 'Load' => '加载', 'Local' => '本地', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => '登录为', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => '登录', 'Login' => '登入', 'Logout' => '登出', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => '低', 'LowBW' => '低 B/W', 'Main' => '主è¦', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => '最大帧率 FPS', 'Medium' => '中等', 'MediumBW' => '中等 B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => '最å°æŠ¥è­¦åŒºåŸŸåº”该å°äºŽæœ€å¤§åŒºåŸŸ', 'MinAlarmAreaUnset' => '您必须指定最å°æŠ¥è­¦åƒç´ æ•°é‡', 'MinBlobAreaLtMax' => '最å°blob区必须å°æ•°æœ€å¤§åŒºåŸŸ', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => '监视器', 'Montage' => '镜头组接', 'Month' => '月', + 'More' => 'More', // Added - 2011-06-16 'Move' => '移动', 'MustBeGe' => '必须大于等于', 'MustBeLe' => 'å¿…é¡»å°äºŽç­‰äºŽ', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'æš‚åœ', 'Phone' => '电è¯', 'PhoneBW' => '电诠B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'åƒç´ å·®åˆ«', 'Pixels' => 'åƒç´ ', 'Play' => '播放', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => '秒', 'Sectionlength' => '段长度', 'Select' => '选择', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => '选择监视器', 'SelfIntersecting' => '多边形边线ä¸å¾—交å‰', 'Set' => '设置', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'æµé‡æ”¾å½±åƒç¼“冲', 'Submit' => 'å‘é€', 'System' => '系统', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => '缩略图', 'Tilt' => '倾斜', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => '时间戳标签 Y', 'Today' => '今天', 'Tools' => '工具', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => '总
分数', 'TrackDelay' => '轨迹延时', 'TrackMotion' => '轨迹è¿åŠ¨', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'æ›´æ–°', 'UpdateAvailable' => '有新版本的ZoneMinder.', 'UpdateNotNecessary' => '无须更新', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => '使用筛选器', 'UseFilterExprsPost' => ' ç­›é€‰å™¨ è¡¨è¾¾å¼', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => '使用 ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => '最å°/最大污æ¸åŒºæ•° Blobs', 'ZoneMinMaxFiltArea' => '最å°/最大过滤区域', 'ZoneMinMaxPixelThres' => '最å°/最大åƒç´ é˜ˆå€¼(0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => '忽略过载帪数', 'Zones' => '区域', 'Zoom' => '缩放', diff --git a/web/lang/cs_cz.php b/web/lang/cs_cz.php index 4a1cc171a..d4bc81bdc 100644 --- a/web/lang/cs_cz.php +++ b/web/lang/cs_cz.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Metoda znaèkování alarmem', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Vybrat filtr', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Zavøít', 'Colour' => 'Barva', 'Command' => 'Pøíkaz', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Nastavení', 'ConfiguredFor' => 'Nastaveno pro', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Øíditelná', 'Cycle' => 'Cyklus', 'CycleWatch' => 'Cyklické prohlí¾ení', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Den', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Zakázat alarmy', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Prosím podpoøte', 'DonateAlready' => 'Ne, u¾ jsem podpoøil', 'DonateEnticement' => 'Ji¾ nìjakou dobu pou¾íváte software ZoneMinder k ochranì svého majetku a pøedpokládám, ¾e jej shledáváte u¾iteèným. Pøesto¾e je ZoneMinder, znovu pøipomínám, zdarma a volnì ¹íøený software, stojí jeho vývoj a podpora nìjaké peníze. Pokud byste chtìl/a podpoøit budoucí vývoj a nové mo¾nosti softwaru, prosím zva¾te darování finanèní pomoci. Darování je, samozøejmì, dobrovolné, ale zato velmi cenìné mù¾ete pøispìt jakou èástkou chcete.

Pokud máte zájem podpoøit ná¹ tým, prosím, vyberte ní¾e uvedenou mo¾nost, nebo nav¹tivte http://www.zoneminder.com/donate.html.

Dìkuji Vám ¾e jste si vybral/a software ZoneMinder a nezapomeòte nav¹tívit fórum na ZoneMinder.com pro podporu a návrhy jak udìlat ZoneMinder je¹tì lep¹ím ne¾ je dnes.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Exportovat detaily snímku', 'ExportImageFiles' => 'Exportovat obrazové soubory', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Exportovat ostatní soubory (jestli existují)', 'ExportOptions' => 'Mo¾nosti exportu', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Jazyk', 'Last' => 'Poslední', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'výsledkù', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Zobrazit pouze prvních', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'Seznam', 'Load' => 'Load', 'Local' => 'Lokální', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Pøihlá¹en jako', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Pøihla¹uji', 'Login' => 'Pøihlásit', 'Logout' => 'Odhlásit', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Pomalá', 'LowBW' => 'Pomalá B/W', 'Main' => 'Hlavní', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximum FPS', 'Medium' => 'Støední', 'MediumBW' => 'Støední B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum znaèkované oblasti by mìlo být men¹í ne¾ maximum', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'Kamery', 'Montage' => 'Sestøih', 'Month' => 'Mìsíc', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Pohyb', 'MustBeGe' => 'musí být vìt¹í nebo rovno ne¾', 'MustBeLe' => 'musí být men¹í nebo rovno ne¾', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Modem', 'PhoneBW' => 'Modem B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixely', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'Délka(s)', 'Sectionlength' => 'Délka sekce', 'Select' => 'Vybrat', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Nastavit', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Potvrdit', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Pøiblí¾it', 'Thumbnail' => 'Miniatura', 'Tilt' => 'Náklon', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Èasové razítko Y', 'Today' => 'Dnes', 'Tools' => 'Nástroje', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Celkové
skóre', 'TrackDelay' => 'Prodleva dráhy', 'TrackMotion' => 'Pohyb po dráze', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'Je dostupný nový update ZoneMinder.', 'UpdateNotNecessary' => 'Update není potøeba.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Pou¾ít filtr', 'UseFilterExprsPost' => ' výrazù', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Pou¾ít ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zóny', 'Zoom' => 'Zoom', diff --git a/web/lang/de_de.php b/web/lang/de_de.php index 835a1eb5c..d15326ef9 100644 --- a/web/lang/de_de.php +++ b/web/lang/de_de.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm-Prüfmethode', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Filterauswahl', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Voreinstellung auswählen', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Schließen', 'Colour' => 'Farbe', 'Command' => 'Kommando', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Konfig.', 'ConfiguredFor' => 'Konfiguriert für', 'ConfirmDeleteEvents' => 'Sind Sie sicher, dass Sie die ausgewählten Ereignisse löschen wollen?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Kontrollierbar', 'Cycle' => 'Zyklus', 'CycleWatch' => 'Zeitzyklus', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Tag', 'Debug' => 'Debug', 'DefaultRate' => 'Standardrate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Alarme abschalten', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Bitte spenden Sie.', 'DonateAlready' => 'Nein, ich habe schon gespendet', 'DonateEnticement' => 'Sie benutzen ZoneMinder nun schon eine Weile und es ist hoffentlich eine nützliche Applikation zur Verbesserung Ihrer Heim- oder Arbeitssicherheit. Obwohl ZoneMinder eine freie Open-Source-Software ist und bleiben wird, entstehen Kosten bei der Entwicklung und dem Support.

Falls Sie ZoneMinder für Weiterentwicklung in der Zukunft unterstützen möchten, denken Sie bitte über eine Spende für das Projekt unter der Webadresse http://www.zoneminder.com/donate.html oder über nachfolgend stehende Option nach. Spenden sind, wie der Name schon sagt, immer freiwillig. Dem Projekt helfen kleine genauso wie größere Spenden sehr weiter und ein herzlicher Dank ist jedem Spender sicher.

Vielen Dank dafür, dass sie ZoneMinder benutzen. Vergessen Sie nicht die Foren unter ZoneMinder.com, um Support zu erhalten und Ihre Erfahrung mit ZoneMinder zu verbessern!', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'ZIP (Komprimiert)', 'ExportFrames' => 'Exportiere Bilddetails', 'ExportImageFiles' => 'Exportiere Bilddateien', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Exportiere andere Dateien (falls vorhanden)', 'ExportOptions' => 'Exportierungsoptionen', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Sprache', 'Last' => 'Letztes', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'Ergebnisse;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Begrenze nur auf die ersten', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Verbundene Monitore', 'List' => 'Liste', 'Load' => 'Last', 'Local' => 'Lokal', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Angemeldet als', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Anmelden', 'Login' => 'Anmeldung', 'Logout' => 'Abmelden', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'niedrige', 'LowBW' => 'Niedrige B/W', 'Main' => 'Haupt', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximale FPS', 'Medium' => 'mittlere', 'MediumBW' => 'Mittlere B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Der minimale Alarmbereich sollte kleiner sein als der maximale', 'MinAlarmAreaUnset' => 'Sie müssen einen Minimumwert an Alarmflächenpixeln angeben', 'MinBlobAreaLtMax' => 'Die minimale Blob-Fläche muss kleiner sein als die maximale', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'Monitore', 'Montage' => 'Montage', 'Month' => 'Monat', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Bewegung', 'MustBeGe' => 'muss groesser oder gleich sein wie', 'MustBeLe' => 'muss kleiner oder gleich sein wie', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Telefon', 'PhoneBW' => 'Tel. B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel-Differenz', 'Pixels' => 'Pixel', 'Play' => 'Abspielen', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'Sekunden', 'Sectionlength' => 'Sektionslänge', 'Select' => 'Auswahl', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Wähle Monitore', 'SelfIntersecting' => 'Die Polygonränder dürfen sich nicht überschneiden.', 'Set' => 'Setze', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream-Wiedergabe-Bildpuffer', 'Submit' => 'Absenden', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Miniatur', 'Tilt' => 'Neigung', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Zeitstempel-Y', 'Today' => 'Heute', 'Tools' => 'Werkzeuge', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Totale
Punktzahl', 'TrackDelay' => 'Nachführungsverzögerung', 'TrackMotion' => 'Bewegungs-Nachführung', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Aktualisieren', 'UpdateAvailable' => 'Eine Aktualisierung für ZoneMinder ist verfügbar.', 'UpdateNotNecessary' => 'Es ist keine Aktualisierung verfügbar.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Benutze Filter', 'UseFilterExprsPost' => ' Filter Ausdrücke', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Benutze ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min./max. Blobs', 'ZoneMinMaxFiltArea' => 'Min./max. Filterfläche', 'ZoneMinMaxPixelThres' => 'Min./max. Pixelschwellwert', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Bildauslassrate bei Systemüberlastung', 'Zones' => 'Zonen', 'Zoom' => 'Zoom', diff --git a/web/lang/dk_dk.php b/web/lang/dk_dk.php index 466499318..a941d0cb1 100644 --- a/web/lang/dk_dk.php +++ b/web/lang/dk_dk.php @@ -204,10 +204,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Methode', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Vælg Filter', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Luk', 'Colour' => 'Farve', 'Command' => 'Kommando', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'konfig', 'ConfiguredFor' => 'Konfigureret for', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -227,6 +231,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Dag', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -248,6 +253,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -285,6 +291,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -360,16 +367,21 @@ $SLANG = array( 'Language' => 'Sprog', 'Last' => 'Sidste', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'results only;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'Lokal', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Logget Ind Som', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Logger Ind', 'Login' => 'Logind', 'Logout' => 'Logud', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Lav', 'LowBW' => 'Lav B/B', 'Main' => 'Main', @@ -403,6 +415,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximale FPS', 'Medium' => 'Medium', 'MediumBW' => 'Medium B/B', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum blob område bør være mindre end maximum', @@ -446,6 +459,7 @@ $SLANG = array( 'Monitors' => 'Monitore', 'Montage' => 'Montage', 'Month' => 'Måned', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Flyt', 'MustBeGe' => 'skal være støre end eller ligmed', 'MustBeLe' => 'Skal være mindre end eller ligmed', @@ -506,6 +520,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Telefon', 'PhoneBW' => 'Telefon B/B', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -561,6 +576,8 @@ $SLANG = array( 'Secs' => 'Sekunder', 'Sectionlength' => 'Sektion længde', 'Select' => 'Vælg', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Sæt', @@ -603,6 +620,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -616,6 +634,7 @@ $SLANG = array( 'TimestampLabelY' => 'Tidsstempel Mærkning Y', 'Today' => 'Idag', 'Tools' => 'Tools', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Total
Skore', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -630,6 +649,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'En updatering til ZoneMinder er tilstede.', 'UpdateNotNecessary' => 'Ingen updatering er nødvendig.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Brug Filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Brug ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -681,6 +701,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zoner', 'Zoom' => 'Zoom', diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 6d1b593f2..bbd0c7997 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -71,6 +71,15 @@ // Simple String Replacements $SLANG = array( + 'SystemLog' => 'System Log', + 'DateTime' => 'Date/Time', + 'Component' => 'Component', + 'Pid' => 'PID', + 'Level' => 'Level', + 'Message' => 'Message', + 'Line' => 'Line', + 'More' => 'More', + 'Clear' => 'Clear', '24BitColour' => '24 bit colour', '8BitGrey' => '8 bit greyscale', 'Action' => 'Action', @@ -119,6 +128,7 @@ $SLANG = array( 'AttrWeekday' => 'Weekday', 'Auto' => 'Auto', 'AutoStopTimeout' => 'Auto Stop Timeout', + 'Available' => 'Available', 'AvgBrScore' => 'Avg.
Score', 'Available' => 'Available', 'Background' => 'Background', @@ -200,10 +210,11 @@ $SLANG = array( 'CapturePalette' => 'Capture Palette', 'CaptureWidth' => 'Capture Width', 'Cause' => 'Cause', - 'Layout' => 'Layout', 'CheckMethod' => 'Alarm Check Method', 'ChooseDetectedCamera' => 'Choose Detected Camera', 'ChooseFilter' => 'Choose Filter', + 'ChooseLogFormat' => 'Choose a log format', + 'ChooseLogSelection' => 'Choose a log selection', 'ChoosePreset' => 'Choose Preset', 'Close' => 'Close', 'Colour' => 'Colour', @@ -248,6 +259,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disk', 'Display' => 'Display', + 'Displaying' => 'Displaying', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'Donate' => 'Please Donate', @@ -285,6 +297,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', 'Exporting' => 'Exporting', 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', @@ -359,12 +372,16 @@ $SLANG = array( 'Label' => 'Label', 'Language' => 'Language', 'Last' => 'Last', + 'Layout' => 'Layout', 'LimitResultsPost' => 'results only', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'Local', + 'Log' => 'Log', + 'Logs' => 'Logs', + 'Logging' => 'Logging', 'LoggedInAs' => 'Logged in as', 'LoggingIn' => 'Logging In', 'Login' => 'Login', @@ -561,6 +578,8 @@ $SLANG = array( 'Sectionlength' => 'Section length', 'SelectMonitors' => 'Select Monitors', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', + 'SelectLog' => 'Select Log', 'SelfIntersecting' => 'Polygon edges must not intersect', 'SetNewBandwidth' => 'Set New Bandwidth', 'SetPreset' => 'Set Preset', @@ -615,6 +634,7 @@ $SLANG = array( 'Time' => 'Time', 'Today' => 'Today', 'Tools' => 'Tools', + 'Total' => 'Total', 'TotalBrScore' => 'Total
Score', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +649,7 @@ $SLANG = array( 'UpdateAvailable' => 'An update to ZoneMinder is available.', 'UpdateNotNecessary' => 'No update is necessary.', 'Update' => 'Update', + 'Updated' => 'Updated', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' 'UseFilter' => 'Use Filter', @@ -674,6 +695,7 @@ $SLANG = array( 'ZoneAlarmColour' => 'Alarm Colour (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', + 'ZoneMinderLog' => 'ZoneMinder Log', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', 'ZoneMinMaxBlobs' => 'Min/Max Blobs', diff --git a/web/lang/es_ar.php b/web/lang/es_ar.php index 56cedeefb..470e76d27 100644 --- a/web/lang/es_ar.php +++ b/web/lang/es_ar.php @@ -154,10 +154,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Method', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Elegir Filtro', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Cerrar', 'Colour' => 'Color', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config.', 'ConfiguredFor' => 'Configurado Para', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -177,6 +181,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Día', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -198,6 +203,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disco', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -235,6 +241,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -310,16 +317,21 @@ $SLANG = array( 'Language' => 'Lenguaje', 'Last' => 'Ultimo', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'Resultados;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Solo los primeros', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Carga', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Registrado Como', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Ingresando', 'Login' => 'Ingresar', 'Logout' => 'Salir', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Baja', 'LowBW' => 'Baja B/W', 'Main' => 'Main', @@ -353,6 +365,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximos FPS', 'Medium' => 'Media', 'MediumBW' => 'Media B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum blob area should be less than maximum', @@ -396,6 +409,7 @@ $SLANG = array( 'Monitors' => 'Monitores', 'Montage' => 'Cámara Múltiple', 'Month' => 'Mes', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'Debe ser mayor o igual que', 'MustBeLe' => 'Debe ser menor o igual que', @@ -456,6 +470,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Tel. B/N', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', // Added - 2009-02-08 'Pixels' => 'pixels', 'Play' => 'Play', @@ -511,6 +526,8 @@ $SLANG = array( 'Secs' => 'Seg', 'Sectionlength' => 'Longitud Sección', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -553,6 +570,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'Sistema', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -566,6 +584,7 @@ $SLANG = array( 'TimestampLabelY' => 'Eje Y Etiqueta Hora', 'Today' => 'Today', 'Tools' => 'Herra.', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Total
puntuación', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -580,6 +599,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'Una Actualización a ZoneMinder esta disponible', 'UpdateNotNecessary' => 'No se requiere Actualización', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Usar Filtro', 'UseFilterExprsPost' => ' filtrar sentencias', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Utilizar ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -631,6 +651,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zonas', 'Zoom' => 'Zoom', diff --git a/web/lang/es_es.php b/web/lang/es_es.php index 24b07b31f..7654da688 100644 --- a/web/lang/es_es.php +++ b/web/lang/es_es.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Método de Comprobación de Alarma', 'ChooseDetectedCamera' => 'Elegir Cámara Detectada', 'ChooseFilter' => 'Elegir Filtro', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Elegir Preprogramación', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Cerrar', 'Colour' => 'Color', 'Command' => 'Comando', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Configurado para', 'ConfirmDeleteEvents' => '¿Seguro que desea borrar los eventos seleccionados?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controlable', 'Cycle' => 'Ciclo', 'CycleWatch' => 'Visión Ciclo', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Día', 'Debug' => 'Debug', 'DefaultRate' => 'Tasa por Defecto', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Deshabilitar Alarmas', 'Disk' => 'Disco', 'Display' => 'Display', // Added - 2011-03-02 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Por favor Done', 'DonateAlready' => 'No, Ya he donado', 'DonateEnticement' => 'Haestado ejecutando ZoneMinder por un tiempo y cn suerte le resultará un útil complemento para su seguridad en hogar y trabajo. Aunque ZoneMinder es, y será, libre y de código abierto, cuesta dinero desarrollarlo y mantenerlo. Si quiere ayudar a mantener un futuro desarrollo y nuevas funciones entonces considere hacer un donativo por favor. Donar es, por supuesto, opcional pero muy apreciado y puede donar tanto como desee sin importar la cantidad.

Si desea hacer una donación por favor seleccione la opción de debajo o vaya a http://www.zoneminder.com/donate.html en su navegador.

Muchas gracias por usar ZoneMinder y no se olvide de vistar los foros en ZoneMinder.com para obtener soporte o hacer sugerencias sobre cómo mejorar su experiencia con ZoneMinder aún más.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Exportar Detalles Cuadro', 'ExportImageFiles' => 'Exportar Archivos Imagen', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Exportar Otros Archivos (si hay)', 'ExportOptions' => 'Opciones Exportación', 'ExportSucceeded' => 'Éxito al Exportar', @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Idioma', 'Last' => 'Último', 'Layout' => 'Diseño', + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'Sólo resultados', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limitar al primero', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Monitores Enlazados', 'List' => 'Lista', 'Load' => 'Carga', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Identificado como', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Iniciando sesión', 'Login' => 'Iniciar sesión', 'Logout' => 'Cerrar sesión', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Bajo', 'LowBW' => 'Bajo B/B', 'Main' => 'Principal', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'CPS Máximos', 'Medium' => 'Medio', 'MediumBW' => 'Medio B/B', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'El área mínima de alarma debe ser menor que la máxima', 'MinAlarmAreaUnset' => 'Debe especificar la mínima cantidad de píxeles de alarma', 'MinBlobAreaLtMax' => 'El área mínima de goteo debe ser menor que la máxima', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'Monitores', 'Montage' => 'Montaje', 'Month' => 'Mes', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Mover', 'MustBeGe' => 'debe ser mayor o igual que', 'MustBeLe' => 'debe ser menor o igual que', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pausar', 'Phone' => 'Teléfono', 'PhoneBW' => 'B/B Teléfono', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Dif Píxel', 'Pixels' => 'píxeles', 'Play' => 'Reproducir', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'Segs', 'Sectionlength' => 'Duración de Sección', 'Select' => 'Seleccionar', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Seleccionar Monitores', 'SelfIntersecting' => 'Arístas de polígonos no deben intersectar', 'Set' => 'Establecer', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Secuencia de Búfer de Reproducción', 'Submit' => 'Enviar', 'System' => 'Sistema', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Inclinar', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Etiqueta de Tiempo Y', 'Today' => 'Hoy', 'Tools' => 'Herramientas', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Cuenta
Total', 'TrackDelay' => 'Retraso de Pista', 'TrackMotion' => 'Movimiento de Pista', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Actualizar', 'UpdateAvailable' => 'Hay una actualización disponible para ZoneMinder.', 'UpdateNotNecessary' => 'No es necesario actualizar.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Usar Filtro', 'UseFilterExprsPost' => ' filtros de expresiones', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usar ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Mín/Máx Goteos', 'ZoneMinMaxFiltArea' => 'Mín/Máx Ãrea Filtrada', 'ZoneMinMaxPixelThres' => 'Mín/Máx Umbral de Píxeles (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Ignorar Cuenta de Sobrecarga de Cuadros', 'Zones' => 'Zonas', 'Zoom' => 'Zoom', diff --git a/web/lang/et_ee.php b/web/lang/et_ee.php index 0863a7f69..28eeb15cd 100644 --- a/web/lang/et_ee.php +++ b/web/lang/et_ee.php @@ -199,10 +199,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Method', 'ChooseDetectedCamera' => 'Vali tuvastatud kaamera', 'ChooseFilter' => 'Vali Filter', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Sule', 'Colour' => 'Colour', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Seadistatud', 'ConfirmDeleteEvents' => 'Oled sa kindel kustamaks valitud sündmused?', @@ -222,6 +226,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Päevas', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -243,6 +248,7 @@ $SLANG = array( 'DisableAlarms' => 'Keela alarmid', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-03-02 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -280,6 +286,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', @@ -355,16 +362,21 @@ $SLANG = array( 'Language' => 'Keel', 'Last' => 'Viimane', 'Layout' => 'Layout', + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'results only', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Lingitud monitorid', 'List' => 'List', 'Load' => 'Koormus', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Sisse logitud', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Login sisse', 'Login' => 'Login', 'Logout' => 'Logi välja', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Madal', 'LowBW' => 'Low B/W', 'Main' => 'Main', @@ -398,6 +410,7 @@ $SLANG = array( 'MaximumFPS' => 'Maksimaalne FPS', 'Medium' => 'Keskmine', 'MediumBW' => 'Medium B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum blob area should be less than maximum', @@ -441,6 +454,7 @@ $SLANG = array( 'Monitors' => 'Monitors', 'Montage' => 'Montage', 'Month' => 'Kuus', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'must be greater than or equal to', 'MustBeLe' => 'must be less than or equal to', @@ -501,6 +515,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Phone B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -556,6 +571,8 @@ $SLANG = array( 'Secs' => 'Secs', 'Sectionlength' => 'Section length', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -598,6 +615,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -611,6 +629,7 @@ $SLANG = array( 'TimestampLabelY' => 'Timestamp Label Y', 'Today' => 'Today', 'Tools' => 'Tools', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Total
Score', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -625,6 +644,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'An update to ZoneMinder is available.', 'UpdateNotNecessary' => 'No update is necessary.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Use Filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -676,6 +696,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Tsoone', 'Zoom' => 'Zoom', diff --git a/web/lang/fr_fr.php b/web/lang/fr_fr.php index ea8a0d98b..4efbb828f 100644 --- a/web/lang/fr_fr.php +++ b/web/lang/fr_fr.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Méthode vérif. alarme', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Choisir filtre', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Fermer', 'Colour' => 'Couleur', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Configuré pour', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle vision', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Jour', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Langue', 'Last' => 'Dernier', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'results only;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Connecté cô', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Connexion', 'Login' => 'Login', 'Logout' => 'Déconnexion', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Bas', 'LowBW' => 'Basse N/B', 'Main' => 'Main', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'i/s maximum', 'Medium' => 'Medium', 'MediumBW' => 'Moy. N/B', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Aire blob min. doit ê < aire blob maximum', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'Ecrans', 'Montage' => 'Montage', 'Month' => 'Mois', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'doit être sup. ou égal à', 'MustBeLe' => 'doit être inf. ou égal à', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Phone B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'Secs', 'Sectionlength' => 'Longueur section', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'Système', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Timestamp Label Y', 'Today' => 'Today', 'Tools' => 'Outils', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Score
total', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'Mise à jour de ZM dispo.', 'UpdateNotNecessary' => 'Pas de mise à jour dispo.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Util. Filtre', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Util. ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zones', 'Zoom' => 'Zoom', diff --git a/web/lang/he_il.php b/web/lang/he_il.php index cb0b7c049..268b90b4e 100755 --- a/web/lang/he_il.php +++ b/web/lang/he_il.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Method', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'áçø îñðï', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'ñâåø', 'Colour' => 'öáò', 'Command' => 'ô÷åãä', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'úöåøä', 'ConfiguredFor' => 'úöåøä òáåø', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'îçæåøé', 'CycleWatch' => 'öôééä îçæåøéú', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'éåí', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'ðèøì àæò÷åú', 'Disk' => 'ãéñ÷', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'úøåí áá÷ùä', 'DonateAlready' => 'ìà, úøîúé ëáø', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'éöà ÷áöé úîåðä', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'éöà ÷áöéí àçøéí (àí éùðí)', 'ExportOptions' => 'éöà àôùøåéåú', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'ùôä', 'Last' => 'àçøåï', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'úåöàåú áìáã;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'äâáì ìøàùåï', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'îåðéèåøéí î÷åùøéí', 'List' => 'øùéîä', 'Load' => 'èòï', 'Local' => 'î÷åîé', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'äúçáø ë', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'îúçáø', 'Login' => 'äúçáø', 'Logout' => 'äúðú÷', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'ðîåê', 'LowBW' => 'ðîåê ø/ô', 'Main' => 'îøëæé', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximum FPS', 'Medium' => 'áéðåðé', 'MediumBW' => 'Medium B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum blob area should be less than maximum', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'îåðéèåøéí', 'Montage' => 'Montage', 'Month' => 'çåãù', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'äææ', 'MustBeGe' => 'must be greater than or equal to', 'MustBeLe' => 'must be less than or equal to', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'èìôåï', 'PhoneBW' => 'ø/ô èìôåï', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'ôé÷ñìéí', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'ùðéåú', 'Sectionlength' => 'àåøê ÷èò', 'Select' => 'áçø', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'áçø îåðéèåøéí', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => '÷áò', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'îòøëú', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'èì', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Timestamp Label Y', 'Today' => 'äéåí', 'Tools' => 'ëìéí', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'ñê
ðé÷åã', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'òãëåï', 'UpdateAvailable' => 'òãëåï ìæåï-îéðãø àôùøé.', 'UpdateNotNecessary' => 'òãëåï àéðå äëøçé.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'ùéîåù áîñðï', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'ùéîåù ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'àæåøéí', 'Zoom' => 'æåí', diff --git a/web/lang/hu_hu.php b/web/lang/hu_hu.php index b44dee1ca..126ee9fd3 100644 --- a/web/lang/hu_hu.php +++ b/web/lang/hu_hu.php @@ -212,10 +212,14 @@ $SLANG = array( 'CheckMethod' => 'A riasztás figyelésének módja', 'ChooseDetectedCamera' => 'Válasszon érzékelt kamerát', 'ChooseFilter' => 'Válassz szûrõt', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Válassz profilt', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Bezár', 'Colour' => 'Szín', 'Command' => 'Parancs', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Beállítás', 'ConfiguredFor' => 'Beállítva', 'ConfirmDeleteEvents' => 'Biztos benne, hogy törli a kiválasztott eseményeket?', @@ -235,6 +239,7 @@ $SLANG = array( 'Controllable' => 'Vezérelhetõ', 'Cycle' => 'Körbekapcsolás', 'CycleWatch' => 'Körbekapcsolás', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Napon', 'Debug' => 'Nyomon
követés', 'DefaultRate' => 'Alapértelmezett sebesség', @@ -256,6 +261,7 @@ $SLANG = array( 'DisableAlarms' => 'Riasztás tiltása', 'Disk' => 'Tárhely', 'Display' => 'Megjelenés', + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Kérem támogasson', 'DonateAlready' => 'Nem, én már támogattam', 'DonateEnticement' => 'Ön már jó ideje használja a ZoneMindert remélhetõleg hasznos kiegészítésnek tartja háza vagy munkahelye biztosításában. Bár ZoneMinder szabad, nyílt forráskódú, és az is marad; a fejlesztése pénzbe kerül. Ha támogatni szeretné a jövõbeni fejlesztéseket és az új funkciókat kérem támogasson. A támogatás teljesen önkéntes, de nagyon megbecsült és annyival tud támogatni amennyivel kíván.

Ha támogatni szertne kérem válasszon az alábbi lehetõségekbõl vagy látogassa meg a http://www.zoneminder.com/donate.html oldalt.

Köszönöm, hogy használja a ZoneMinder-t és ne felejtse el meglátogatni a fórumokat a ZoneMinder.com oldalon támogatásért és ötletekért, hogy tudja még jobban használni a ZoneMinder-t.', @@ -293,6 +299,7 @@ $SLANG = array( 'ExportFormatZip' => 'ZIP', 'ExportFrames' => 'Képek adatainak exportálása', 'ExportImageFiles' => 'Képek exportálása', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Egyéb fájlok exportálása (ha vannak)', 'ExportOptions' => 'Exportálás beállításai', 'ExportSucceeded' => 'Az exportálás sikerült', @@ -368,16 +375,21 @@ $SLANG = array( 'Language' => 'Nyelv', 'Last' => 'Utolsó', 'Layout' => 'Elrendezés', + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'találatig korlátoz', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Az elsõ', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Összefüggõ monitorok', 'List' => 'Lista', 'Load' => 'Terhelés', 'Local' => 'Helyi', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Bejelentkezve mint', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Bejelentkezés folyamatban', 'Login' => 'Bejelentkezés', 'Logout' => 'Kilépés', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Alacsony', 'LowBW' => 'Alacsony
sávsz.', 'Main' => 'Fõ', @@ -411,6 +423,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximum FPS', 'Medium' => 'Közepes', 'MediumBW' => 'Közepes
sávsz.', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'A minimum riasztott területnek kisebbnek kell lennie mint a maximumnak', 'MinAlarmAreaUnset' => 'Meg kell adnod a minimum riasztott képpontok számát', 'MinBlobAreaLtMax' => 'A minimum blob területnek kisebbnek kell lennie mint a maximumnak', @@ -454,6 +467,7 @@ $SLANG = array( 'Monitors' => 'Monitorok', 'Montage' => 'Többkamerás nézet', 'Month' => 'Hónapban', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Mozgás', 'MustBeGe' => 'nagyobbnak vagy egyenlõnek kell lennie', 'MustBeLe' => 'kisebbnek vagy egyenlõnek kell lennie', @@ -514,6 +528,7 @@ $SLANG = array( 'Pause' => 'Szünet', 'Phone' => 'Telefonon betárcsázva', 'PhoneBW' => 'Betárcsázó
sávsz.', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Képpont eltérés', 'Pixels' => 'képpont', 'Play' => 'Lejátszás', @@ -569,6 +584,8 @@ $SLANG = array( 'Secs' => 'mp.', 'Sectionlength' => 'Rész hossz', 'Select' => 'Kiválasztás', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Monitorok kiválasztása', 'SelfIntersecting' => 'A sokszög szélei nem keresztezõdhetnek', 'Set' => 'Beállít', @@ -611,6 +628,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Folyam visszajátszó képpuffer', 'Submit' => 'Elküld', 'System' => 'Rendszer', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Táv', 'Thumbnail' => 'Elõnézet', 'Tilt' => 'Fel-le mozgás', @@ -624,6 +642,7 @@ $SLANG = array( 'TimestampLabelY' => 'Elhelyezés Y pozició', 'Today' => 'Ma', 'Tools' => 'Eszközök', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Össz.
pontszám', 'TrackDelay' => 'Késleltetés követése', 'TrackMotion' => 'Mozgás követése', @@ -638,6 +657,7 @@ $SLANG = array( 'Update' => 'Frissítés', 'UpdateAvailable' => 'Elérhetõ ZoneMinder frissítés.', 'UpdateNotNecessary' => 'Nem szükséges a frissítés.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Szûrõt használ', 'UseFilterExprsPost' => ' szürõ kifejezés használata', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => ' ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -689,6 +709,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobok', 'ZoneMinMaxFiltArea' => 'Min/Max szûrt terület', 'ZoneMinMaxPixelThres' => 'Min/Max képpont eltérési
küszöb (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Túlterhelés esetén
ennyi képkocka hagyható ki', 'Zones' => 'Zónák', 'Zoom' => 'Zoom', diff --git a/web/lang/it_it.php b/web/lang/it_it.php index eeb4f1c90..63556e748 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -208,10 +208,14 @@ $SLANG = array( 'CheckMethod' => 'Metodo di Controllo Allarme', 'ChooseDetectedCamera' => 'Scegli telecamera rilevata', // Added - 2009-03-31 'ChooseFilter' => 'Scegli Filtro', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Scegli Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Chiudi', 'Colour' => 'Colori', 'Command' => 'Comando', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Configura', 'ConfiguredFor' => 'Configurato per', 'ConfirmDeleteEvents' => 'Sei sicuro di voler cancellare gli eventi selezionati', @@ -231,6 +235,7 @@ $SLANG = array( 'Controllable' => 'Controllabile', 'Cycle' => 'Cicla', 'CycleWatch' => 'Vista Ciclica', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Giorno', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -252,6 +257,7 @@ $SLANG = array( 'DisableAlarms' => 'Disabil Allarme', 'Disk' => 'Utilizzo Disco', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Donate,per favore', 'DonateAlready' => 'No, ho gia donato... ', 'DonateEnticement' => 'Stai usando ZoneMinder da un po\' di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.

Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a http://www.zoneminder.com/donate.html .

Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', @@ -289,6 +295,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Dettagli frame espo.', 'ExportImageFiles' => 'Esporta le immagini', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Esporto Altri file (se presenti)', 'ExportOptions' => 'Opzioni Esportazione', 'ExportSucceeded' => 'Export completata con successo', // Added - 2009-02-08 @@ -364,16 +371,21 @@ $SLANG = array( 'Language' => 'Linguaggio', 'Last' => 'Ultimo', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'risultati;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limita ai primi', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Monitor Collegati', 'List' => 'Lista', 'Load' => 'Carico Sistema', 'Local' => 'Locale', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Collegato come:', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Mi Sto Collegando', 'Login' => 'Login', 'Logout' => 'Logout', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Bassa', 'LowBW' => 'Banda Bassa', 'Main' => 'Principale', @@ -407,6 +419,7 @@ $SLANG = array( 'MaximumFPS' => 'Massimi FPS', 'Medium' => 'Media', 'MediumBW' => 'Banda Media', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'L\'area minima dell\'allarme deve essere minore di quella massima', 'MinAlarmAreaUnset' => 'Devi specificare il numero minimo di pixel per l\'allarme', 'MinBlobAreaLtMax' => 'L\'area di blob minima deve essere minore dell\'area di blob massima', @@ -450,6 +463,7 @@ $SLANG = array( 'Monitors' => 'Monitors', 'Montage' => 'Montaggio', 'Month' => 'Mese', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Sposta', 'MustBeGe' => 'deve essere superiore a', 'MustBeLe' => 'deve essere inferiore o pari a', @@ -510,6 +524,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Telefono', 'PhoneBW' => 'Banda Tel', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -565,6 +580,8 @@ $SLANG = array( 'Secs' => 'Secs', 'Sectionlength' => 'Lunghezza Sezione', 'Select' => 'Seleziona', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Monitor Selezionati', 'SelfIntersecting' => 'I vertici del poligono non devono intersecarsi', 'Set' => 'Imposta', @@ -607,6 +624,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Accetta', 'System' => 'Sistema', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Anteprima', 'Tilt' => 'Tilt', @@ -620,6 +638,7 @@ $SLANG = array( 'TimestampLabelY' => 'coordinata Y etichetta', 'Today' => 'Oggi ', 'Tools' => 'Strumenti', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Punteggio
Totale', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -634,6 +653,7 @@ $SLANG = array( 'Update' => 'Aggiorna', 'UpdateAvailable' => 'Un aggiornamento di ZoneMinder è disponibilie.', 'UpdateNotNecessary' => 'Nessun aggiornamento necessario.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Usa Filtro', 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usa ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -685,6 +705,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Area Filtrata', 'ZoneMinMaxPixelThres' => 'Min/Max Soglia Pixel (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zone', 'Zoom' => 'Zoom', diff --git a/web/lang/ja_jp.php b/web/lang/ja_jp.php index 5f2fcd5b6..f9fc83bed 100644 --- a/web/lang/ja_jp.php +++ b/web/lang/ja_jp.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => '±×°Ñ Áª¯¸•û–@', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => '̨ÙÀ°‚Ì‘I‘ð', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => '•Â‚¶‚é', 'Colour' => 'F', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Ý’è:', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => '»²¸ÙŠÏŽ@', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => '—j“ú', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Œ¾Œê', 'Last' => 'ÅI', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'results only;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'Û°¶Ù', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Û¸Þ²ÝÏ‚Ý:', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => '۸޲ݒ†', 'Login' => 'Û¸Þ²Ý', 'Logout' => 'Û¸Þ±³Ä', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => '’á', 'LowBW' => '’á‘шæ', 'Main' => 'Main', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'Å‚ FPS', 'Medium' => '’†', 'MediumBW' => '’†‘шæ', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Å’áÌÞÛ¯Ìޔ͈͂ÍÅ‚’l‚æ‚èˆÈ‰º‚Å‚È‚¯‚ê‚΂¢‚¯‚È‚¢', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'ÓÆÀ°', 'Montage' => 'ÓÝÀ°¼Þ­', 'Month' => 'ŒŽ', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => '“¯“™‚©ˆÈã‚Å‚È‚¯‚ê‚΂¢‚¯‚È‚¢', 'MustBeLe' => '“¯“™‚©ˆÈ‰º‚Å‚È‚¯‚ê‚΂¢‚¯‚È‚¢', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Œg‘Ñ—p', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'Ë߸¾Ù', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => '•b', 'Sectionlength' => '’·‚³', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => '¼½ÃÑ', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'À²Ñ½ÀÝÌß ×ÍÞÙ Y', 'Today' => 'Today', 'Tools' => '°Ù', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => '‡Œv
½º±°', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'ZoneMinder‚̱¯ÌßÃÞ°Ä‚ª‚ ‚è‚Ü‚·', 'UpdateNotNecessary' => '±¯ÌßÃÞ°Ä‚Ì•K—v‚Í‚ ‚è‚Ü‚¹‚ñ', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => '̨ÙÀ°‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢', 'UseFilterExprsPost' => ' Ì¨ÙÀ°ŒÂ”', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Žw’肵‚Ä‚­‚¾‚³‚¢: ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => '¿Þ°Ý', 'Zoom' => 'Zoom', diff --git a/web/lang/nl_nl.php b/web/lang/nl_nl.php index 03716d6ad..09bf5d4b2 100644 --- a/web/lang/nl_nl.php +++ b/web/lang/nl_nl.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Methode', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Kies filter', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Sluit', 'Colour' => 'Kleur', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Geconfigureerd voor', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Observeer cyclus', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Dag', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Taal', 'Last' => 'Laatste', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'resultaten;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'beperk tot eerste', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'Lokaal', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Ingelogd als', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'In loggen', 'Login' => 'Login', 'Logout' => 'Logout', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Laag', 'LowBW' => 'Laag B/W', 'Main' => 'Main', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximum FPS', 'Medium' => 'Medium', 'MediumBW' => 'Medium B/W', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'minimum blob gebied moet kleiner zijn dan maximum blob gebied', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'Monitoren', 'Montage' => 'Montage', 'Month' => 'Maand', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'Moet groter zijn of gelijk aan', 'MustBeLe' => 'Moet kleiner zijn of gelijk aan', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Telefoon B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'Secs', 'Sectionlength' => 'Sectie lengte', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'Systeem', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Tijdstempel Label Y', 'Today' => 'Today', 'Tools' => 'Gereedschappen', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Totaal
Score', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'een update voor ZoneMinder is beschikbaar', 'UpdateNotNecessary' => 'geen update noodzakelijk', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Gebruik Filter', 'UseFilterExprsPost' => ' filter expressies', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Gebruik ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zones', 'Zoom' => 'Zoom', diff --git a/web/lang/pl_pl.php b/web/lang/pl_pl.php index 2d429ec14..a85d221be 100644 --- a/web/lang/pl_pl.php +++ b/web/lang/pl_pl.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'Metoda sprawdzenia alarmu', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Wybierz filtr', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Zamknij', 'Colour' => 'Nasycenie', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Konfiguracja', 'ConfiguredFor' => 'Ustawiona', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Cykl podgl±du', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Dzieñ', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Dysk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'Jêzyk', 'Last' => 'Ostatni', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'wyników;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Ogranicz do pocz±tkowych', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Obc.', 'Local' => 'Lokalny', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Zalogowany jako', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Logowanie', 'Login' => 'Login', 'Logout' => 'Wyloguj', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'niska', 'LowBW' => 'Nis. prz.', 'Main' => 'Main', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'Maks. FPS', 'Medium' => '¶rednia', 'MediumBW' => '¦red. prz.', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimalny obszar plamki powinien byæ mniejszy od maksymalnego obszaru plamki', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'Monitory', 'Montage' => 'Monta¿', 'Month' => 'Miesi±c', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'musi byæ wiêksze lub równe od', 'MustBeLe' => 'musi byæ mniejsze lub równe od', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Tel. prz.', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pikseli', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'Sekund', 'Sectionlength' => 'D³ugo¶æ sekcji', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Wsp. Y etykiety czasu', 'Today' => 'Today', 'Tools' => 'Narzêdzia', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Ca³kowity
wynik', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'Jest dostêpne uaktualnienie ZoneMinder ', 'UpdateNotNecessary' => 'Nie jest wymagane uaktualnienie', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'U¿yj filtru', 'UseFilterExprsPost' => ' wyra¿enie filtru', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'U¿yj ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Strefy', 'Zoom' => 'Zoom', diff --git a/web/lang/pt_br.php b/web/lang/pt_br.php index b4ccf0199..4dcb32b4a 100644 --- a/web/lang/pt_br.php +++ b/web/lang/pt_br.php @@ -143,10 +143,14 @@ $SLANG = array( 'CheckMethod' => 'Metodo marcar por alarme', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Escolher Filtro', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Fechar', 'Colour' => 'Cor', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Configurado para', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -166,6 +170,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'Ciclo Monitor', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Dia', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -187,6 +192,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disco', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -224,6 +230,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -299,16 +306,21 @@ $SLANG = array( 'Language' => 'Linguagem', 'Last' => 'Último', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'resultados somente;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limitar aos primeiros', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Carga', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Conectado como', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Conectando', 'Login' => 'Conectar', 'Logout' => 'Sair', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Baixa', 'LowBW' => 'Baixa L/B', 'Main' => 'Main', @@ -342,6 +354,7 @@ $SLANG = array( 'MaximumFPS' => 'Maximo FPS', 'Medium' => 'Media', 'MediumBW' => 'Media L/B', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'A area minima de blob deve ser menor do que a area máxima de blob', @@ -385,6 +398,7 @@ $SLANG = array( 'Monitors' => 'Monitores', 'Montage' => 'Montagem', 'Month' => 'Mês', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'deve ser maior ou igual a', 'MustBeLe' => 'deve ser menor ou igual a', @@ -445,6 +459,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Discada L/B', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', 'Play' => 'Play', @@ -500,6 +515,8 @@ $SLANG = array( 'Secs' => 'Segs', 'Sectionlength' => 'Tamanho de evento Fixo', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -542,6 +559,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'Sistema', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -555,6 +573,7 @@ $SLANG = array( 'TimestampLabelY' => 'posição de etiqueta Y', 'Today' => 'Today', 'Tools' => 'Ferramentas', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Score
Total', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -569,6 +588,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'Um update ao zoneminder está disponível.', 'UpdateNotNecessary' => 'Não é necessário update.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Use Filtro', 'UseFilterExprsPost' => ' expressões de filtragem', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -620,6 +640,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zonas', 'Zoom' => 'Zoom', diff --git a/web/lang/ro_ro.php b/web/lang/ro_ro.php index 77ce51a9a..0de867743 100755 --- a/web/lang/ro_ro.php +++ b/web/lang/ro_ro.php @@ -174,10 +174,14 @@ $SLANG = array( 'CheckMethod' => 'Alarm Check Method', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Alege filtru', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Închide', 'Colour' => 'Culoare', 'Command' => 'Comanda', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Configurat pentru', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -197,6 +201,7 @@ $SLANG = array( 'Controllable' => 'Controlabil', 'Cycle' => 'Ciclu', 'CycleWatch' => 'Vizual. ciclu', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Zi', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -218,6 +223,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disc', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -255,6 +261,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -330,16 +337,21 @@ $SLANG = array( 'Language' => 'Limbă', 'Last' => 'Ultim', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'rezultate', 'LimitResultsPre' => 'Limitează la primele', + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'Local', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Eşti conectat ca', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Logare', 'Login' => 'Login', 'Logout' => 'Ieşire', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Redusa', 'LowBW' => 'B/W redus', 'Main' => 'Main', @@ -373,6 +385,7 @@ $SLANG = array( 'MaximumFPS' => 'FPS max', 'Medium' => 'Medie', 'MediumBW' => 'B/W mediu', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'Minimum blob area should be less than maximum', @@ -416,6 +429,7 @@ $SLANG = array( 'Monitors' => 'Monitoare', 'Montage' => 'Montage', 'Month' => 'Luna', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Mişcare', 'MustBeGe' => 'trebuie sa fie mai mare sau egal cu', 'MustBeLe' => 'trebuie sa fie mai mic sau egal cu', @@ -476,6 +490,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'Phone B/W', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'Pixeli', 'Play' => 'Play', @@ -531,6 +546,8 @@ $SLANG = array( 'Secs' => 'Sec', 'Sectionlength' => 'Lungime secţiune', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -573,6 +590,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Trimite', 'System' => 'Sistem', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Miniatură', 'Tilt' => 'Înclinare', @@ -586,6 +604,7 @@ $SLANG = array( 'TimestampLabelY' => 'Format timp eticheta Y', 'Today' => 'Azi', 'Tools' => 'Unelte', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Cota
total', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -600,6 +619,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'Sunt disponibile actualizări ZoneMinder.', 'UpdateNotNecessary' => 'Actulizarea nu este necesară.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Foloseşte filtru', 'UseFilterExprsPost' => ' expresii de filtrare ', 'UseFilterExprsPre' => 'Foloseşte ', @@ -651,6 +671,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zona', 'Zoom' => 'Zoom', diff --git a/web/lang/ru_ru.php b/web/lang/ru_ru.php index 5ead8c048..e0bd2a062 100644 --- a/web/lang/ru_ru.php +++ b/web/lang/ru_ru.php @@ -203,10 +203,14 @@ $SLANG = array( 'CheckMethod' => 'íÅÔÏÄ ÐÒÏ×ÅÒËÉ ÔÒÅ×ÏÇÉ', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => '÷ÙÂÒÁÔØ ÆÉÌØÔÒ', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'úÁËÒÙÔØ', 'Colour' => 'ã×ÅÔ', 'Command' => 'Command', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'îÁÓÔÒÏÅÎ ÎÁ', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', @@ -226,6 +230,7 @@ $SLANG = array( 'Controllable' => 'Controllable', 'Cycle' => 'Cycle', 'CycleWatch' => 'ãÉËÌÉÞÅÓËÉÊ ÐÒÏÓÍÏÔÒ', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'äÅÎØ', 'Debug' => 'Debug', 'DefaultRate' => 'Default Rate', @@ -247,6 +252,7 @@ $SLANG = array( 'DisableAlarms' => 'Disable Alarms', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -284,6 +290,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Export Frame Details', 'ExportImageFiles' => 'Export Image Files', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Export Other Files (if present)', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -359,16 +366,21 @@ $SLANG = array( 'Language' => 'ñÚÙË', 'Last' => 'ðÏÓÌÅÄÎÉÊ', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'results only;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Linked Monitors', 'List' => 'List', 'Load' => 'Load', 'Local' => 'ìÏËÁÌØÎÙÊ', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'ðÏÌØÚÏ×ÁÔÅÌØ', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => '÷ÈÏÄ × ÓÉÓÔÅÍÕ', 'Login' => '÷ÏÊÔÉ', 'Logout' => '÷ÙÊÔÉ', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'ÕÚËÉÊ', 'LowBW' => 'õÚËÉÊ ËÁÎÁÌ', 'Main' => 'Main', @@ -402,6 +414,7 @@ $SLANG = array( 'MaximumFPS' => 'ïÇÒÁÎÉÞÅÎÉÅ ÓËÏÒÏÓÔÉ ÚÁÐÉÓÉ (Ë/Ó)', 'Medium' => 'ÓÒÅÄÎÉÊ', 'MediumBW' => 'ïÂÙÞÎÙÊ ËÁÎÁÌ', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', 'MinBlobAreaLtMax' => 'íÉÎÉÍÁÌØÎÁÑ ÐÌÏÝÁÄØ ÏÂßÅËÔÁ ÄÏÌÖÎÁ ÂÙÔØ ÍÅÎØÛÅ ÞÅÍ ÍÁËÓÉÍÁÌØÎÁÑ ÐÌÏÝÁÄØ ÏÂßÅËÔÁ', @@ -445,6 +458,7 @@ $SLANG = array( 'Monitors' => 'íÏÎÉÔÏÒÙ', 'Montage' => 'Montage', 'Month' => 'íÅÓÑÃ', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Move', 'MustBeGe' => 'ÄÏÌÖÎÏ ÂÙÔØ ÂÏÌØÛÅ ÉÌÉ ÒÁ×ÎÏ', 'MustBeLe' => 'ÄÏÌÖÎÏ ÂÙÔØ ÍÅÎØÛÅ ÉÌÉ ÒÁ×ÎÏ', @@ -505,6 +519,7 @@ $SLANG = array( 'Pause' => 'Pause', 'Phone' => 'Phone', 'PhoneBW' => 'ôÅÌÅÆÏÎÎÁÑ ÌÉÎÉÑ', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => '× ÐÉËÓÅÌÑÈ', 'Play' => 'Play', @@ -560,6 +575,8 @@ $SLANG = array( 'Secs' => 'óÅË.', 'Sectionlength' => 'äÌÉÎÁ ÓÅËÃÉÉ (× ËÁÄÒÁÈ)', 'Select' => 'Select', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Select Monitors', 'SelfIntersecting' => 'Polygon edges must not intersect', 'Set' => 'Set', @@ -602,6 +619,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'Submit' => 'Submit', 'System' => 'óÉÓÔÅÍÁ', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -615,6 +633,7 @@ $SLANG = array( 'TimestampLabelY' => 'Y-ËÏÏÒÄÉÎÁÔÁ ÍÅÔËÉ', 'Today' => 'Today', 'Tools' => 'éÎÓÔÒÕÍÅÎÔÙ', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'óÕÍÍ.
ÏÃÅÎËÁ', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', @@ -629,6 +648,7 @@ $SLANG = array( 'Update' => 'Update', 'UpdateAvailable' => 'äÏÓÔÕÐÎÏ ÏÂÎÏ×ÌÅÎÉÅ ZoneMinder', 'UpdateNotNecessary' => 'ïÂÎÏ×ÌÅÎÉÅ ÎÅ ÔÒÅÂÕÅÔÓÑ', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'éÓÐÏÌØÚÏ×ÁÔØ ÆÉÌØÔÒ', 'UseFilterExprsPost' => ' ×ÙÒÁÖÅÎÉÊ ÄÌÑ ÆÉÌØÔÒÁ', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'éÓÐÏÌ. ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -680,6 +700,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max Blobs', 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'úÏÎÙ', 'Zoom' => 'Zoom', diff --git a/web/lang/se_se.php b/web/lang/se_se.php index f956b9564..fb4346cc7 100644 --- a/web/lang/se_se.php +++ b/web/lang/se_se.php @@ -204,10 +204,14 @@ $SLANG = array( 'CheckMethod' => 'Larmkontrollmetod', 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 'ChooseFilter' => 'Välj filter', + 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Välj standard', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Stäng', 'Colour' => 'Färg', 'Command' => 'Kommando', + 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Konfigurera', 'ConfiguredFor' => 'Konfigurerad för', 'ConfirmDeleteEvents' => 'Är du säker på att du vill ta bort dom valda händelserna?', @@ -227,6 +231,7 @@ $SLANG = array( 'Controllable' => 'Kontrollerbar', 'Cycle' => 'Period', 'CycleWatch' => 'Cycle Watch', + 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Dag', 'Debug' => 'Avlusa', 'DefaultRate' => 'Standardhastighet', @@ -248,6 +253,7 @@ $SLANG = array( 'DisableAlarms' => 'Avaktivera larm', 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 + 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Var vänlig och donera', 'DonateAlready' => 'Nej, Jag har redan donerat', 'DonateEnticement' => 'Du har kört ZoneMinder ett tag nu och förhoppningsvis har du sett att det fungerar bra hemma eller på ditt företag. Även om ZoneMinder är, och kommer att vara, fri programvara och öppen kallkod, så kostar det pengar att utveckla och underhålla. Om du vill hjälpa till med framtida utveckling och nya funktioner så var vanlig och bidrag med en slant. Bidragen är naturligtvis en option men mycket uppskattade och du kan bidra med precis hur mycket du vill.

Om du vill ge ett bidrag väljer du nedan eller surfar till http://www.zoneminder.com/donate.html.

Tack för att du använder ZoneMinder, glöm inte att besöka forumen på ZoneMinder.com för support och förslag om hur du får din ZoneMinder att fungera lite bättre.', @@ -285,6 +291,7 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => 'Exportera ramdetaljer', 'ExportImageFiles' => 'Exportera bildfiler', + 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Exportera andra filer (om dom finns)', 'ExportOptions' => 'Konfiguera export', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 @@ -360,16 +367,21 @@ $SLANG = array( 'Language' => 'Språk', 'Last' => 'Sist', 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'LimitResultsPost' => 'resultaten;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Begränsa till första', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Line', // Added - 2011-06-16 'LinkedMonitors' => 'Länkade övervakare', 'List' => 'Lista', 'Load' => 'Belastning', 'Local' => 'Lokal', + 'Log' => 'Log', // Added - 2011-06-16 'LoggedInAs' => 'Inloggad som', + 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Loggar in', 'Login' => 'Logga in', 'Logout' => 'Logga ut', + 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Låg', 'LowBW' => 'Låg bandbredd', 'Main' => 'Huvudmeny', @@ -403,6 +415,7 @@ $SLANG = array( 'MaximumFPS' => 'Max ramar/s', 'Medium' => 'Mellan', 'MediumBW' => 'Mellan bandbredd', + 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minsta larmarean skall vara mindre än största', 'MinAlarmAreaUnset' => 'Du måste ange minsta antal larmbildpunkter', 'MinBlobAreaLtMax' => 'Minsta blobarean skall vara mindre än högsta', @@ -446,6 +459,7 @@ $SLANG = array( 'Monitors' => 'Bevakare', 'Montage' => 'Montera', 'Month' => 'Månad', + 'More' => 'More', // Added - 2011-06-16 'Move' => 'Flytta', 'MustBeGe' => 'måste vara större än eller lika med', 'MustBeLe' => 'måste vara mindre än eller lika med', @@ -506,6 +520,7 @@ $SLANG = array( 'Pause' => 'Paus', 'Phone' => 'Mobil', 'PhoneBW' => 'Mobil bandbredd', + 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Skillnad i bildpunkter', 'Pixels' => 'bildpunkter', 'Play' => 'Spela', @@ -561,6 +576,8 @@ $SLANG = array( 'Secs' => 'Sek', 'Sectionlength' => 'Sektionslängd', 'Select' => 'Välj', + 'SelectFormat' => 'Select Format', // Added - 2011-06-17 + 'SelectLog' => 'Select Log', // Added - 2011-06-17 'SelectMonitors' => 'Välj bevakare', 'SelfIntersecting' => 'Polygonändarna får inte överlappa', 'Set' => 'Ställ in', @@ -603,6 +620,7 @@ $SLANG = array( 'StreamReplayBuffer' => 'Buffert för strömmande uppspelning', 'Submit' => 'Skicka', 'System' => 'System', + 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', 'Thumbnail' => 'Miniatyrer', 'Tilt' => 'Tilt', @@ -616,6 +634,7 @@ $SLANG = array( 'TimestampLabelY' => 'Värde på tidsstämpel Y', 'Today' => 'Idag', 'Tools' => 'Verktyg', + 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Total
Score', 'TrackDelay' => 'Spårfördröjning', 'TrackMotion' => 'Spåra rörelse', @@ -630,6 +649,7 @@ $SLANG = array( 'Update' => 'Uppdatera', 'UpdateAvailable' => 'En uppdatering till ZoneMinder finns tillgänglig.', 'UpdateNotNecessary' => 'Ingen uppdatering behövs.', + 'Updated' => 'Updated', // Added - 2011-06-16 'UseFilter' => 'Använd filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Använd ', // This is used at the beginning of the phrase 'use N filter expressions' @@ -681,6 +701,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Min/Max blobbar', 'ZoneMinMaxFiltArea' => 'Min/Max filterarea', 'ZoneMinMaxPixelThres' => 'Min/Max pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'Zones' => 'Zoner', 'Zoom' => 'Zoom', diff --git a/web/skins/classic/css/skin.css b/web/skins/classic/css/skin.css index a4ccdad4e..e59827fc3 100644 --- a/web/skins/classic/css/skin.css +++ b/web/skins/classic/css/skin.css @@ -88,7 +88,7 @@ label { margin-right: 4px; } -input,textarea,select { +input,textarea,select,button { border: 1px #7f7fb2 solid; font-family: inherit; font-size: 100%; @@ -242,23 +242,55 @@ ul.tabList li.active a { font-size: 120%; } -/* - * Behavior classes - */ -.errorText { +.overlay { + font-size: 11px; +} + +.overlay fieldset { + background-color: #f8f8f8; +} + +.validation-advice { + padding: 4px; color: #dc143c; } -.warnText { +fieldset { + border: 1px solid black; + padding: 4px; + margin-bottom: 8px; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +fieldset > legend { + padding: 0 2px; +} + +/* + * Behavior classes + */ +.alarm, .errorText { + color: #dc143c; +} + +.alert, .warnText { color: #ff8c00; } -.infoText { +.ok, .infoText { color: #688e23; } -.disabledText { - font-style: italic; +.fakelink { + color: #7f7fb2; + cursor: pointer; +} + +.fakelink:hover { + color: #336699; + text-decoration: none; } /* @@ -281,6 +313,36 @@ div.clear { clear: both; } +.table-th-sort { + font-style:italic; +} + +td.table-td-sort { + font-style:italic; +} + +th.table-th-sort { + margin-right: 12px; +} + +th.table-th-sort span.table-th-sort-span { + float: right; + width: 12px; + height: 12px; + background: url("../graphics/arrow-s-u.gif") no-repeat 0 0; +} + +th.table-th-sort-rev span.table-th-sort-span { + float: right; + width: 12px; + height: 12px; + background: url("../graphics/arrow-s-d.gif") no-repeat 0 0; +} + +.table-tr-odd { + background-color: #f8f8f8; +} + /* * Primary layout styles */ @@ -300,6 +362,10 @@ div.clear { left: 0; } +#header h2.floating { + float: left; +} + #headerControl { width: 50%; text-align: center; @@ -314,6 +380,10 @@ div.clear { margin-left: 8px; } +#headerButtons input { + margin-left: 4px; +} + #content { width: 96%; margin: 8px auto; @@ -342,11 +412,11 @@ div.clear { } */ -#content > input[type=submit], #content > input[type=button] { +#content > input[type=submit], #content > input[type=button], #content > button { margin-top: 8px; } -#content table input[type=submit], #content table input[type=button] { +#content table input[type=submit], #content table input[type=button], #content table button { margin-top: 0; } diff --git a/web/skins/classic/graphics/Makefile.am b/web/skins/classic/graphics/Makefile.am index 06e7e15ed..c5c7b6bba 100644 --- a/web/skins/classic/graphics/Makefile.am +++ b/web/skins/classic/graphics/Makefile.am @@ -10,6 +10,8 @@ dist_web_DATA = \ arrow-l.gif \ arrow-l-u.gif \ arrow-r.gif \ + arrow-s-d.gif \ + arrow-s-u.gif \ arrow-u.gif \ arrow-ul.gif \ arrow-ur.gif \ diff --git a/web/skins/classic/graphics/Makefile.in b/web/skins/classic/graphics/Makefile.in index 111c6d521..bdeeb7cc3 100644 --- a/web/skins/classic/graphics/Makefile.in +++ b/web/skins/classic/graphics/Makefile.in @@ -215,6 +215,8 @@ dist_web_DATA = \ arrow-l.gif \ arrow-l-u.gif \ arrow-r.gif \ + arrow-s-d.gif \ + arrow-s-u.gif \ arrow-u.gif \ arrow-ul.gif \ arrow-ur.gif \ diff --git a/web/skins/classic/graphics/arrow-s-d.gif b/web/skins/classic/graphics/arrow-s-d.gif new file mode 100644 index 0000000000000000000000000000000000000000..bb45dd0848408d32464f30c6301e3dc82217c4a6 GIT binary patch literal 206 zcmZ?wbhEHb=XZrz0KA5;8mu50Z|sGV}9%sF>)$$j0PR<#Ry6p<#-gB8$a`2`WdMxpS1xy!`m= Q01Hc#P{V?a4h{^~04mHuEdT%j literal 0 HcmV?d00001 diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 557d24206..7123cbf6f 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -961,7 +961,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp $file = "zmEventDetail.html"; if ( !($fp = fopen( $eventPath."/".$file, "w" )) ) { - die( "Can't open event detail export file '$file'" ); + Fatal( "Can't open event detail export file '$file'" ); } fwrite( $fp, exportEventDetail( $event, $exportFrames, $exportImages ) ); fclose( $fp ); @@ -972,7 +972,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp $file = "zmEventFrames.html"; if ( !($fp = fopen( $eventPath."/".$file, "w" )) ) { - die( "Can't open event frames export file '$file'" ); + Fatal( "Can't open event frames export file '$file'" ); } fwrite( $fp, exportEventFrames( $event, $exportDetail, $exportImages ) ); fclose( $fp ); @@ -1001,7 +1001,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp // create an image slider if(!empty($myfilelist)) { $file = "zmEventImages.html"; - if ( !($fp = fopen( $eventPath."/".$file, "w" )) ) die( "Can't open event images export file '$file'" ); + if ( !($fp = fopen( $eventPath."/".$file, "w" )) ) Fatal( "Can't open event images export file '$file'" ); fwrite( $fp, exportEventImages( $event, $exportDetail, $exportFrames, $myfilelist ) ); fclose( $fp ); $exportFileList[$file] = $eventPath."/".$file; @@ -1072,7 +1072,7 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo } $monitorPath = 'events/'; $html_eventMaster = 'zmEventImagesMaster_'.date('Ymd_His'). '.html'; - if ( !($fp = fopen( $monitorPath."/".$html_eventMaster, "w" )) ) die( "Can't open event images export file '$html_eventMaster'" ); + if ( !($fp = fopen( $monitorPath."/".$html_eventMaster, "w" )) ) Fatal( "Can't open event images export file '$html_eventMaster'" ); fwrite( $fp, exportEventImagesMaster( $eids ) ); fclose( $fp ); $exportFileList[] = $monitorPath."/".$html_eventMaster; @@ -1081,7 +1081,7 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo $listFile = "temp/".$export_listFile; if ( !($fp = fopen( $listFile, "w" )) ) { - die( "Can't open event export list file '$listFile'" ); + Fatal( "Can't open event export list file '$listFile'" ); } foreach ( $exportFileList as $exportFile ) { @@ -1097,9 +1097,9 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo exec( escapeshellcmd( $command ), $output, $status ); if ( $status ) { - error_log( "Command '$command' returned with status $status" ); + Error( "Command '$command' returned with status $status" ); if ( $output[0] ) - error_log( "First line of output is '".$output[0]."'" ); + Error( "First line of output is '".$output[0]."'" ); return( false ); } } @@ -1115,9 +1115,9 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo exec( $command, $output, $status ); if ( $status ) { - error_log( "Command '$command' returned with status $status" ); + Error( "Command '$command' returned with status $status" ); if ( $output[0] ) - error_log( "First line of output is '".$output[0]."'" ); + Error( "First line of output is '".$output[0]."'" ); return( false ); } } diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index a354675f8..5e5d54e15 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -64,6 +64,8 @@ function xhtmlHeaders( $file, $title ) + + - var AJAX_TIMEOUT = ; +var AJAX_TIMEOUT = ; - var currentView = ''; - var thisUrl = ""; - var skinPath = ""; +var currentView = ''; +var thisUrl = ""; +var skinPath = ""; - var canEditSystem = ; - var canViewSystem = ; +var canEditSystem = ; +var canViewSystem = ; - var refreshParent = ; +var refreshParent = ; - var focusWindow = ; +var focusWindow = ; - var imagePrefix = ""; +var imagePrefix = ""; diff --git a/web/skins/classic/views/Makefile.am b/web/skins/classic/views/Makefile.am index c2697941b..58c72b78f 100644 --- a/web/skins/classic/views/Makefile.am +++ b/web/skins/classic/views/Makefile.am @@ -30,6 +30,7 @@ dist_web_DATA = \ function.php \ group.php \ groups.php \ + log.php \ login.php \ logout.php \ Makefile.am \ diff --git a/web/skins/classic/views/Makefile.in b/web/skins/classic/views/Makefile.in index b331e2b69..1cde4efba 100644 --- a/web/skins/classic/views/Makefile.in +++ b/web/skins/classic/views/Makefile.in @@ -275,6 +275,7 @@ dist_web_DATA = \ function.php \ group.php \ groups.php \ + log.php \ login.php \ logout.php \ Makefile.am \ diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 09628026d..bc00e4da4 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -198,7 +198,7 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) if ( canView( 'System' ) ) { ?> -
+
Logger::NOLOG ) { ?> / '.$SLANG['Log'].'' ) ?>
1 ) diff --git a/web/skins/classic/views/css/Makefile.am b/web/skins/classic/views/css/Makefile.am index ffe08350b..39c270cf7 100644 --- a/web/skins/classic/views/css/Makefile.am +++ b/web/skins/classic/views/css/Makefile.am @@ -14,6 +14,7 @@ dist_web_DATA = \ frame.css \ frames.css \ groups.css \ + log.css \ monitor.css \ montage_2wide.css \ montage_3wide50enlarge.css \ diff --git a/web/skins/classic/views/css/Makefile.in b/web/skins/classic/views/css/Makefile.in index b0f906285..bfbf9e4a0 100644 --- a/web/skins/classic/views/css/Makefile.in +++ b/web/skins/classic/views/css/Makefile.in @@ -219,6 +219,7 @@ dist_web_DATA = \ frame.css \ frames.css \ groups.css \ + log.css \ monitor.css \ montage_2wide.css \ montage_3wide50enlarge.css \ diff --git a/web/skins/classic/views/css/log.css b/web/skins/classic/views/css/log.css new file mode 100644 index 000000000..60361339e --- /dev/null +++ b/web/skins/classic/views/css/log.css @@ -0,0 +1,44 @@ +#logSummary { + margin: 4px auto 0; + border-collapse: collapse; +} + +#logSummary tr { + margin: 0; + padding: 0; +} + +#logSummary td { + border: 1px solid #7f7fb2; + padding: 0 6px; + text-align: center; + font-size: 10px; + line-height: 15px; +} + +tr.log-fat td { + background-color:#ffcccc; + font-weight: bold; + font-style: italics; +} + +tr.log-err td { + background-color:#ffcccc; +} + +tr.log-war td { + background-color: #ffe4b5; +} + +tr.log-dbg td { + font-style: italics; +} + +#exportLog label { + vertical-align: middle; +} + +#exportLog input[type=radio] { + margin-right: 4px; + vertical-align: middle; +} diff --git a/web/skins/classic/views/js/Makefile.am b/web/skins/classic/views/js/Makefile.am index 992a55f57..ba1845e0c 100644 --- a/web/skins/classic/views/js/Makefile.am +++ b/web/skins/classic/views/js/Makefile.am @@ -23,6 +23,7 @@ dist_web_DATA = \ filter.js.php \ group.js \ groups.js \ + log.js \ login.js \ Makefile.am \ monitor.js \ diff --git a/web/skins/classic/views/js/Makefile.in b/web/skins/classic/views/js/Makefile.in index 445968e50..c476c5adc 100644 --- a/web/skins/classic/views/js/Makefile.in +++ b/web/skins/classic/views/js/Makefile.in @@ -228,6 +228,7 @@ dist_web_DATA = \ filter.js.php \ group.js \ groups.js \ + log.js \ login.js \ Makefile.am \ monitor.js \ diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 0ce488020..a1b2a2e55 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -41,7 +41,7 @@ function getCmdResponse( respObj, respText ) return; if ( streamCmdTimer ) - streamCmdTimer = $clear( streamCmdTimer ); + streamCmdTimer = clearTimeout( streamCmdTimer ); streamStatus = respObj.status; @@ -434,7 +434,7 @@ function getFrameResponse( respObj, respText ) } if ( !eventData['frames'] ) - eventData['frames'] = new Hash(); + eventData['frames'] = new Object(); eventData['frames'][frame.FrameId] = frame; @@ -460,7 +460,7 @@ function checkFrames( eventId, frameId, loadImage ) } if ( !eventData['frames'] ) - eventData['frames'] = new Hash(); + eventData['frames'] = new Object(); currFrameId = frameId; @@ -482,7 +482,7 @@ function checkFrames( eventId, frameId, loadImage ) var injected = false; if ( fid < imgs.length ) { - img.injectBefore( imgs[fid-1] ); + img.inject( imgs[fid-1], 'before' ); injected = true; } else @@ -492,7 +492,7 @@ function checkFrames( eventId, frameId, loadImage ) { if ( parseInt(img.getProperty( 'alt' )) < parseInt(thumbImg.getProperty( 'alt' )) ) { - img.injectBefore( thumbImg ); + img.inject( thumbImg, 'before' ); return( true ); } return( false ); @@ -501,7 +501,7 @@ function checkFrames( eventId, frameId, loadImage ) } if ( !injected ) { - img.injectInside( $('eventThumbs') ); + img.inject( $('eventThumbs') ); } var scale = parseInt(img.getStyle('height')); img.setStyles( { @@ -589,7 +589,7 @@ function actQuery( action, parms ) { var actParms = "view=request&request=event&id="+eventData.Id+"&action="+action; if ( parms != null ) - actParms += "&"+Hash.toQueryString( parms ); + actParms += "&"+Object.toQueryString( parms ); actReq.send( actParms ); } @@ -746,7 +746,7 @@ function initPage() var streamImg = $('imageFeed').getElement('img'); if ( !streamImg ) streamImg = $('imageFeed').getElement('object'); - $(streamImg).addEvent( 'click', handleClick.bindWithEvent( $(streamImg) ) ); + $(streamImg).addEvent( 'click', function( event ) { handleClick( event ); } ); } } diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js new file mode 100644 index 000000000..73f40d661 --- /dev/null +++ b/web/skins/classic/views/js/log.js @@ -0,0 +1,304 @@ +var logParms = "view=request&request=log&task=query"; +var logReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: logResponse } ); +var logTimer = undefined; +var logTable = undefined; + +var logCodes = new Object({ + '0': 'INF', + '-1': 'WAR', + '-2': 'ERR', + '-3': 'FAT', + '-4': 'PNC', +}); + +var minSampleTime = 1000; +var maxSampleTime = 16000; +var minLogTime = 0; +var maxLogTime = 0; +var logCount = 0; +var maxLogFetch = 100; +var filter = {}; +var logTimeout = maxSampleTime; +var firstLoad = true; +var initialDisplayLimit = 200; +var sortReversed = false; +var filterFields = [ 'Component', 'Pid', 'Level', 'File', 'Line']; +var options = {}; + +function buildFetchParms( parms ) +{ + var fetchParms = logParms+'&limit='+maxLogFetch; + if ( parms ) + fetchParms += '&'+parms; + Object.each(filter, + function( value, key ) + { + fetchParms += '&filter['+key+']='+value; + } + ); + return( fetchParms ); +} + +function fetchNextLogs() +{ + logReq.send( buildFetchParms( 'minTime='+maxLogTime ) ); +} + +function fetchPrevLogs() +{ + logReq.send( buildFetchParms( 'maxTime='+minLogTime ) ); +} + +function logResponse( respObj ) +{ + if ( logTimer ) + logTimer = clearTimeout( logTimer ); + + if ( respObj.result == 'Ok' ) + { + if ( respObj.logs.length > 0 ) + { + logTimeout = minSampleTime; + logCount += respObj.logs.length; + try { + respObj.logs.each( + function( log ) + { + if ( !maxLogTime || log.TimeKey > maxLogTime ) + maxLogTime = log.TimeKey; + if ( !minLogTime || log.TimeKey < minLogTime ) + minLogTime = log.TimeKey; + var row = logTable.push( [ { content: log.DateTime, properties: { style: 'white-space: nowrap' }}, log.Component, log.Pid, log.Code, log.Message, log.File, log.Line ] ); + delete log.Message; + row.tr.store( 'log', log ); + if ( log.Level <= -3 ) + row.tr.addClass( 'log-fat' ); + else if ( log.Level <= -2 ) + row.tr.addClass( 'log-err' ); + else if ( log.Level <= -1 ) + row.tr.addClass( 'log-war' ); + else if ( log.Level > 0 ) + row.tr.addClass( 'log-dbg' ); + if ( !firstLoad ) + { + new Fx.Tween( row.tr, { duration: 10000, transition: Fx.Transitions.Sine } ).start( 'color', '#6495ED', '#000000' ); + } + } + ); + options = respObj.options; + updateFilterSelectors(); + $('lastUpdate').set('text',respObj.updated); + $('logState').set('text',respObj.state); + $('logState').removeClass('ok'); + $('logState').removeClass('alert'); + $('logState').removeClass('alarm'); + $('logState').addClass(respObj.state); + $('totalLogs').set('text',respObj.total); + $('availLogs').set('text',respObj.available); + $('displayLogs').set('text',logCount); + if ( firstLoad ) + { + if ( logCount < displayLimit ) + fetchPrevLogs(); + } + logTable.reSort(); + } + catch( e ) + { + console.error( e ); + } + logTimeout /= 2; + if ( logTimeout < minSampleTime ) + logTimeout = minSampleTime; + } + else + { + firstLoad = false; + logTimeout *= 2; + if ( logTimeout > maxSampleTime ) + logTimeout = maxSampleTime; + } + } + logTimer = fetchNextLogs.delay( logTimeout ); +} + +function refreshLog() +{ + options = {}; + logTable.empty(); + firstLoad = true; + maxLogTime = 0; + minLogTime = 0; + logCount = 0; + logTimeout = maxSampleTime; + displayLimit = initialDisplayLimit; + fetchNextLogs(); +} + +function expandLog() +{ + displayLimit += maxLogFetch; + fetchPrevLogs(); +} + +function clearLog() +{ + logReq.cancel(); + minLogTime = 0; + logCount = 0; + logTimeout = maxSampleTime; + displayLimit = initialDisplayLimit; + $('displayLogs').set('text',logCount); + options = {}; + logTable.empty(); +} + +function filterLog() +{ + filter = {}; + filterFields.each( + function( field ) + { + var selector = $('filter['+field+']'); + var value = selector.get('value'); + if ( value ) + filter[field] = value; + } + ); + refreshLog(); +} + +function resetLog() +{ + filter = {}; + refreshLog(); +} + +var exportFormValidator; + +function exportLog() +{ + exportFormValidator.reset(); + $('exportLog').overlayShow(); +} + +function exportResponse( response ) +{ + $('exportLog').unspin(); + if ( response.result == 'Ok' ) + { + window.location.replace( thisUrl+'?view=request&request=log&task=download&key='+response.key+'&format='+response.format ); + } +} + +function exportRequest() +{ + var form = $('exportForm'); + if ( form.validate() ) + { + var exportParms = "view=request&request=log&task=export"; + var exportReq = new Request.JSON( { url: thisUrl, method: 'post', link: 'cancel', onSuccess: exportResponse } ); + var selection = form.getElement('input[name=selector]:checked').get('value'); + if ( selection == 'filter' || selection == 'current' ) + { + $$('#filters select').each( + function( select ) + { + exportParms += "&"+select.get('id')+"="+select.get('value'); + } + ); + } + if ( selection == 'current' ) + { + var tbody = $(logTable).getElement( 'tbody' ); + var rows = tbody.getElements( 'tr' ); + if ( rows ) + { + var minTime = rows[0].getElement('td').get('text'); + exportParms += "&minTime="+encodeURIComponent(minTime); + var maxTime = rows[rows.length-1].getElement('td').get('text'); + exportParms += "&maxTime="+encodeURIComponent(maxTime); + } + } + exportReq.send( exportParms+"&"+form.toQueryString() ); + $('exportLog').spin(); + } +} + +function updateFilterSelectors() +{ + Object.each(options, + function( values, key ) + { + var selector = $('filter['+key+']'); + selector.options.length = 1; + if ( key == 'Level' ) + { + Object.each(values, + function( value, label ) + { + selector.options[selector.options.length] = new Option( value, label ); + } + ); + } + else + { + values.each( + function( value ) + { + selector.options[selector.options.length] = new Option( value ); + } + ); + } + if ( filter[key] ) + selector.set('value',filter[key]); + } + ); +} + +function initPage() +{ + displayLimit = initialDisplayLimit; + for ( var i = 1; i <= 9; i++ ) + logCodes[''+i] = 'DB'+i; + logTable = new HtmlTable( $('contentTable'), + { + zebra: true, + sortable: true, + sortReverse: true + } + ); + logTable.addEvent( 'sort', function( tbody, index ) + { + var header = tbody.getParent( 'table' ).getElement( 'thead' ); + var columns = header.getElement( 'tr' ).getElements( 'th' ); + var column = columns[index]; + sortReversed = column.hasClass( 'table-th-sort-rev' ); + if ( logCount > displayLimit ) + { + var rows = tbody.getElements( 'tr' ); + var startIndex; + if ( sortReversed ) + startIndex = displayLimit; + else + startIndex = 0;; + for ( var i = startIndex; logCount > displayLimit; i++ ) + { + rows[i].destroy(); + logCount--; + } + $('displayLogs').set('text',logCount); + } + } + ); + exportFormValidator = new Form.Validator.Inline($('exportForm'), { + useTitles: true, + warningPrefix: "", + errorPrefix: "" + }); + new Asset.css( "/css/spinner.css" ); + fetchNextLogs(); +} + +// Kick everything off +window.addEvent( 'domready', initPage ); diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 92e5bde96..c0ba63a0e 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -5,7 +5,7 @@ var defaultAspectRatio = ''; if ( ZM_OPT_CONTROL ) { ?> -var controlOptions = new Hash(); +var controlOptions = new Object(); $SLANG['None'] ); @@ -42,7 +42,7 @@ controlOptions[][] = ''; if ( empty($_REQUEST['mid']) ) { ?> -var monitorNames = new Hash(); +var monitorNames = new Object(); 0 ) eventHtml.addClass( 'archived' ); - new Element( 'p' ).injectInside( eventHtml ).set( 'text', monitorNames[event.MonitorId] ); - new Element( 'p' ).injectInside( eventHtml ).set( 'text', event.Name+(frame?("("+frame.FrameId+")"):"") ); - new Element( 'p' ).injectInside( eventHtml ).set( 'text', event.StartTime+" - "+event.Length+"s" ); - new Element( 'p' ).injectInside( eventHtml ).set( 'text', event.Cause ); + new Element( 'p' ).inject( eventHtml ).set( 'text', monitorNames[event.MonitorId] ); + new Element( 'p' ).inject( eventHtml ).set( 'text', event.Name+(frame?("("+frame.FrameId+")"):"") ); + new Element( 'p' ).inject( eventHtml ).set( 'text', event.StartTime+" - "+event.Length+"s" ); + new Element( 'p' ).inject( eventHtml ).set( 'text', event.Cause ); if ( event.Notes ) - new Element( 'p' ).injectInside( eventHtml ).set( 'text', event.Notes ); + new Element( 'p' ).inject( eventHtml ).set( 'text', event.Notes ); if ( event.Archived > 0 ) - new Element( 'p' ).injectInside( eventHtml ).set( 'text', archivedString ); + new Element( 'p' ).inject( eventHtml ).set( 'text', archivedString ); return( eventHtml ); } @@ -67,7 +67,7 @@ function frameDataResponse( respObj, respText ) } if ( !event['frames'] ) - event['frames'] = new Hash(); + event['frames'] = new Object(); event['frames'][frame.FrameId] = frame; event['frames'][frame.FrameId]['html'] = createEventHtml( event, frame ); diff --git a/web/skins/classic/views/js/timeline.js.php b/web/skins/classic/views/js/timeline.js.php index aad33ff6a..cbda779bd 100644 --- a/web/skins/classic/views/js/timeline.js.php +++ b/web/skins/classic/views/js/timeline.js.php @@ -1,6 +1,6 @@ var filterQuery = ''; -var monitorNames = new Hash(); +var monitorNames = new Object(); ; var canEditMonitors = ; var canStreamNative = ; -var canPlayPauseAudio = Browser.Engine.trident; +var canPlayPauseAudio = Browser.ie; var imageControlMode = "moveMap"; diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index 6b09a93dd..ed2024e26 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -438,7 +438,7 @@ function drawZonePoints() var div = new Element( 'div', { 'id': 'point'+i, 'class': 'zonePoint', 'title': 'Point '+(i+1), 'styles': { 'left': zone['Points'][i].x, 'top': zone['Points'][i].y } } ); div.addEvent( 'mouseover', highlightOn.pass( i ) ); div.addEvent( 'mouseout', highlightOff.pass( i ) ); - div.injectInside( $('imageFrame') ); + div.inject( $('imageFrame') ); div.makeDraggable( { 'container': $('imageFrame'), 'onStart': setActivePoint.pass( i ), 'onComplete': fixActivePoint.pass( i ), 'onDrag': updateActivePoint.pass( i ) } ); } @@ -450,27 +450,27 @@ function drawZonePoints() row.addEvents( { 'mouseover': highlightOn.pass( i ), 'mouseout': highlightOff.pass( i ) } ); var cell = new Element( 'td' ); cell.set( 'text', i+1 ); - cell.injectInside( row ); + cell.inject( row ); cell = new Element( 'td' ); var input = new Element( 'input', { 'id': 'newZone[Points]['+i+'][x]', 'name': 'newZone[Points]['+i+'][x]', 'value': zone['Points'][i].x, 'size': 5 } ); input.addEvent( 'change', updateX.pass( i ) ); - input.injectInside( cell ); - cell.injectInside( row ); + input.inject( cell ); + cell.inject( row ); cell = new Element( 'td' ); input = new Element( 'input', { 'id': 'newZone[Points]['+i+'][y]', 'name': 'newZone[Points]['+i+'][y]', 'value': zone['Points'][i].y, 'size': 5 } ); input.addEvent( 'change', updateY.pass( i ) ); - input.injectInside( cell ); - cell.injectInside( row ); + input.inject( cell ); + cell.inject( row ); cell = new Element( 'td' ); - new Element( 'a', { 'href': '#', 'events': { 'click': addPoint.pass( i ) } } ).set( 'text', '+' ).injectInside( cell ); + new Element( 'a', { 'href': '#', 'events': { 'click': addPoint.pass( i ) } } ).set( 'text', '+' ).inject( cell ); if ( zone['Points'].length > 3 ) - new Element( 'a', { 'id': 'delete'+i, 'href': '#', 'events': { 'click': delPoint.pass( i ) } } ).set( 'text', '-' ).injectInside( cell ); - cell.injectInside( row ); + new Element( 'a', { 'id': 'delete'+i, 'href': '#', 'events': { 'click': delPoint.pass( i ) } } ).set( 'text', '-' ).inject( cell ); + cell.inject( row ); - row.injectInside( tables[i%tables.length].getElement( 'tbody' ) ); + row.inject( tables[i%tables.length].getElement( 'tbody' ) ); } } diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php index c96527ce3..715fff40f 100644 --- a/web/skins/classic/views/js/zone.js.php +++ b/web/skins/classic/views/js/zone.js.php @@ -1,4 +1,4 @@ -var presets = new Hash(); +var presets = new Object(); + +
+ +
+
Filter log - + Component + PID + Level + File + Line + +
+
+ + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + +
+
+ + + + + +
+ + + +
+
+
+
+ + diff --git a/web/skins/classic/views/monitorprobe.php b/web/skins/classic/views/monitorprobe.php index b6cb06b93..bb94b5f2f 100644 --- a/web/skins/classic/views/monitorprobe.php +++ b/web/skins/classic/views/monitorprobe.php @@ -37,7 +37,7 @@ if ( ZM_V4L2 ) $result = exec( escapeshellcmd($command), $output, $status ); if ( $status ) - die( "Unable to probe local cameras, status is '$status'" ); + Fatal( "Unable to probe local cameras, status is '$status'" ); $monitors = array(); foreach ( dbFetchAll( "select Id, Name, Device,Channel from Monitors where Type = 'Local' order by Device, Channel" ) as $monitor ) @@ -49,7 +49,7 @@ if ( ZM_V4L2 ) foreach ( $output as $line ) { if ( !preg_match( '/^d:([^|]+).*S:([^|]*).*F:([^|]+).*I:(\d+)\|(.+)$/', $line, $deviceMatches ) ) - die( "Can't parse command output '$line'" ); + Fatal( "Can't parse command output '$line'" ); $standards = explode('/',$deviceMatches[2]); $preferredStandard = false; foreach ( $preferredStandards as $standard ) @@ -75,7 +75,7 @@ if ( ZM_V4L2 ) for ( $i = 0; $i < $deviceMatches[4]; $i++ ) { if ( !preg_match( '/i'.$i.':([^|]+)\|i'.$i.'T:([^|]+)\|/', $deviceMatches[5], $inputMatches ) ) - die( "Can't parse input '".$deviceMatches[5]."'" ); + Fatal( "Can't parse input '".$deviceMatches[5]."'" ); if ( $inputMatches[2] == 'Camera' ) { $input = array( 'index'=>$i, 'id'=>$deviceMatches[1].':'.$i, 'name'=>$inputMatches[1], 'free'=>empty($monitors[$deviceMatches[1].':'.$i]) ); @@ -264,12 +264,11 @@ unset($output); $command = "arp -a"; $result = exec( escapeshellcmd($command), $output, $status ); if ( $status ) - die( "Unable to probe network cameras, status is '$status'" ); + Fatal( "Unable to probe network cameras, status is '$status'" ); foreach ( $output as $line ) { if ( !preg_match( '/^(\S+) \(([\d.]+)\) at ([0-9a-f:]+)/', $line, $matches ) ) continue; - //die( "Can't parse command output '$line'" ); $host = $matches[1]; $ip = $matches[2]; if ( !$host || $host == '?' ) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 6d1ef0389..10a3ed03c 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -33,7 +33,7 @@ $tabs['config'] = $SLANG['Config']; $tabs['paths'] = $SLANG['Paths']; $tabs['web'] = $SLANG['Web']; $tabs['images'] = $SLANG['Images']; -$tabs['debug'] = $SLANG['Debug']; +$tabs['logging'] = $SLANG['Logging']; $tabs['network'] = $SLANG['Network']; $tabs['mail'] = $SLANG['Email']; $tabs['ftp'] = $SLANG['FTP']; @@ -231,12 +231,21 @@ else if ( count( $options ) > 3 ) { ?> - > - + @@ -247,8 +256,17 @@ else { foreach ( $options as $option ) { + if ( preg_match( '/^([^=]+)=(.+)$/', $option ) ) + { + $optionLabel = $matches[1]; + $optionValue = $matches[2]; + } + else + { + $optionLabel = $optionValue = $option; + } ?> - checked="checked"/>  + checked="checked"/>  -1 : this.indexOf(string) > -1; - }, - - trim: function(){ - return this.replace(/^\s+|\s+$/g, ''); - }, - - clean: function(){ - return this.replace(/\s+/g, ' ').trim(); - }, - - camelCase: function(){ - return this.replace(/-\D/g, function(match){ - return match.charAt(1).toUpperCase(); - }); - }, - - hyphenate: function(){ - return this.replace(/[A-Z]/g, function(match){ - return ('-' + match.charAt(0).toLowerCase()); - }); - }, - - capitalize: function(){ - return this.replace(/\b[a-z]/g, function(match){ - return match.toUpperCase(); - }); - }, - - escapeRegExp: function(){ - return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); - }, - - toInt: function(base){ - return parseInt(this, base || 10); - }, - - toFloat: function(){ - return parseFloat(this); - }, - - hexToRgb: function(array){ - var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - return (hex) ? hex.slice(1).hexToRgb(array) : null; - }, - - rgbToHex: function(array){ - var rgb = this.match(/\d{1,3}/g); - return (rgb) ? rgb.rgbToHex(array) : null; - }, - - stripScripts: function(option){ - var scripts = ''; - var text = this.replace(/]*>([\s\S]*?)<\/script>/gi, function(){ - scripts += arguments[1] + '\n'; - return ''; - }); - if (option === true) $exec(scripts); - else if ($type(option) == 'function') option(scripts, text); - return text; - }, - - substitute: function(object, regexp){ - return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ - if (match.charAt(0) == '\\') return match.slice(1); - return (object[name] != undefined) ? object[name] : ''; - }); - } - -}); - - -/* ---- - -name: Function - -description: Contains Function Prototypes like create, bind, pass, and delay. - -license: MIT-style license. - -requires: [Native, $util] - -provides: Function - -... -*/ - -try { - delete Function.prototype.bind; -} catch(e){} - -Function.implement({ - - extend: function(properties){ - for (var property in properties) this[property] = properties[property]; - return this; - }, - - create: function(options){ - var self = this; - options = options || {}; - return function(event){ - var args = options.arguments; - args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); - if (options.event) args = [event || window.event].extend(args); - var returns = function(){ - return self.apply(options.bind || null, args); - }; - if (options.delay) return setTimeout(returns, options.delay); - if (options.periodical) return setInterval(returns, options.periodical); - if (options.attempt) return $try(returns); - return returns(); - }; - }, - - run: function(args, bind){ - return this.apply(bind, $splat(args)); - }, - - pass: function(args, bind){ - return this.create({bind: bind, arguments: args}); - }, - - bind: function(bind, args){ - return this.create({bind: bind, arguments: args}); - }, - - bindWithEvent: function(bind, args){ - return this.create({bind: bind, arguments: args, event: true}); - }, - - attempt: function(args, bind){ - return this.create({bind: bind, arguments: args, attempt: true})(); - }, - - delay: function(delay, bind, args){ - return this.create({bind: bind, arguments: args, delay: delay})(); - }, - - periodical: function(periodical, bind, args){ - return this.create({bind: bind, arguments: args, periodical: periodical})(); - } - -}); - - -/* ---- - -name: Number - -description: Contains Number Prototypes like limit, round, times, and ceil. - -license: MIT-style license. - -requires: [Native, $util] - -provides: Number - -... -*/ - -Number.implement({ - - limit: function(min, max){ - return Math.min(max, Math.max(min, this)); - }, - - round: function(precision){ - precision = Math.pow(10, precision || 0); - return Math.round(this * precision) / precision; - }, - - times: function(fn, bind){ - for (var i = 0; i < this; i++) fn.call(bind, i, this); - }, - - toFloat: function(){ - return parseFloat(this); - }, - - toInt: function(base){ - return parseInt(this, base || 10); - } - -}); - -Number.alias('times', 'each'); - -(function(math){ - var methods = {}; - math.each(function(name){ - if (!Number[name]) methods[name] = function(){ - return Math[name].apply(null, [this].concat($A(arguments))); - }; - }); - Number.implement(methods); -})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); - - -/* ---- - -name: Hash - -description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. - -license: MIT-style license. - -requires: Hash.base - -provides: Hash - -... -*/ - -Hash.implement({ - - has: Object.prototype.hasOwnProperty, - - keyOf: function(value){ - for (var key in this){ - if (this.hasOwnProperty(key) && this[key] === value) return key; - } - return null; - }, - - hasValue: function(value){ - return (Hash.keyOf(this, value) !== null); - }, - - extend: function(properties){ - Hash.each(properties || {}, function(value, key){ - Hash.set(this, key, value); - }, this); - return this; - }, - - combine: function(properties){ - Hash.each(properties || {}, function(value, key){ - Hash.include(this, key, value); - }, this); - return this; - }, - - erase: function(key){ - if (this.hasOwnProperty(key)) delete this[key]; - return this; - }, - - get: function(key){ - return (this.hasOwnProperty(key)) ? this[key] : null; - }, - - set: function(key, value){ - if (!this[key] || this.hasOwnProperty(key)) this[key] = value; - return this; - }, - - empty: function(){ - Hash.each(this, function(value, key){ - delete this[key]; - }, this); - return this; - }, - - include: function(key, value){ - if (this[key] == undefined) this[key] = value; - return this; - }, - - map: function(fn, bind){ - var results = new Hash; - Hash.each(this, function(value, key){ - results.set(key, fn.call(bind, value, key, this)); - }, this); - return results; - }, - - filter: function(fn, bind){ - var results = new Hash; - Hash.each(this, function(value, key){ - if (fn.call(bind, value, key, this)) results.set(key, value); - }, this); - return results; - }, - - every: function(fn, bind){ - for (var key in this){ - if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; - } - return true; - }, - - some: function(fn, bind){ - for (var key in this){ - if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; - } - return false; - }, - - getKeys: function(){ - var keys = []; - Hash.each(this, function(value, key){ - keys.push(key); - }); - return keys; - }, - - getValues: function(){ - var values = []; - Hash.each(this, function(value){ - values.push(value); - }); - return values; - }, - - toQueryString: function(base){ - var queryString = []; - Hash.each(this, function(value, key){ - if (base) key = base + '[' + key + ']'; - var result; - switch ($type(value)){ - case 'object': result = Hash.toQueryString(value, key); break; - case 'array': - var qs = {}; - value.each(function(val, i){ - qs[i] = val; - }); - result = Hash.toQueryString(qs, key); - break; - default: result = key + '=' + encodeURIComponent(value); - } - if (value != undefined) queryString.push(result); - }); - - return queryString.join('&'); - } - -}); - -Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); - - -/* ---- - -name: Class - -description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. - -license: MIT-style license. - -requires: [$util, Native, Array, String, Function, Number, Hash] - -provides: Class - -... -*/ - -function Class(params){ - - if (params instanceof Function) params = {initialize: params}; - - var newClass = function(){ - Object.reset(this); - if (newClass._prototyping) return this; - this._current = $empty; - var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; - delete this._current; delete this.caller; - return value; - }.extend(this); - - newClass.implement(params); - - newClass.constructor = Class; - newClass.prototype.constructor = newClass; - - return newClass; - -}; - -Function.prototype.protect = function(){ - this._protected = true; - return this; -}; - -Object.reset = function(object, key){ - - if (key == null){ - for (var p in object) Object.reset(object, p); - return object; - } - - delete object[key]; - - switch ($type(object[key])){ - case 'object': - var F = function(){}; - F.prototype = object[key]; - var i = new F; - object[key] = Object.reset(i); - break; - case 'array': object[key] = $unlink(object[key]); break; - } - - return object; - -}; - -new Native({name: 'Class', initialize: Class}).extend({ - - instantiate: function(F){ - F._prototyping = true; - var proto = new F; - delete F._prototyping; - return proto; - }, - - wrap: function(self, key, method){ - if (method._origin) method = method._origin; - - return function(){ - if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); - var caller = this.caller, current = this._current; - this.caller = current; this._current = arguments.callee; - var result = method.apply(this, arguments); - this._current = current; this.caller = caller; - return result; - }.extend({_owner: self, _origin: method, _name: key}); - - } - -}); - -Class.implement({ - - implement: function(key, value){ - - if ($type(key) == 'object'){ - for (var p in key) this.implement(p, key[p]); - return this; - } - - var mutator = Class.Mutators[key]; - - if (mutator){ - value = mutator.call(this, value); - if (value == null) return this; - } - - var proto = this.prototype; - - switch ($type(value)){ - - case 'function': - if (value._hidden) return this; - proto[key] = Class.wrap(this, key, value); - break; - - case 'object': - var previous = proto[key]; - if ($type(previous) == 'object') $mixin(previous, value); - else proto[key] = $unlink(value); - break; - - case 'array': - proto[key] = $unlink(value); - break; - - default: proto[key] = value; - - } - - return this; - - } - -}); - -Class.Mutators = { - - Extends: function(parent){ - - this.parent = parent; - this.prototype = Class.instantiate(parent); - - this.implement('parent', function(){ - var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; - if (!previous) throw new Error('The method "' + name + '" has no parent.'); - return previous.apply(this, arguments); - }.protect()); - - }, - - Implements: function(items){ - $splat(items).each(function(item){ - if (item instanceof Function) item = Class.instantiate(item); - this.implement(item); - }, this); - - } - -}; - - -/* ---- - -name: Class.Extras - -description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. - -license: MIT-style license. - -requires: Class - -provides: [Chain, Events, Options, Class.Extras] - -... -*/ - -var Chain = new Class({ - - $chain: [], - - chain: function(){ - this.$chain.extend(Array.flatten(arguments)); - return this; - }, - - callChain: function(){ - return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; - }, - - clearChain: function(){ - this.$chain.empty(); - return this; - } - -}); - -var Events = new Class({ - - $events: {}, - - addEvent: function(type, fn, internal){ - type = Events.removeOn(type); - if (fn != $empty){ - this.$events[type] = this.$events[type] || []; - this.$events[type].include(fn); - if (internal) fn.internal = true; - } - return this; - }, - - addEvents: function(events){ - for (var type in events) this.addEvent(type, events[type]); - return this; - }, - - fireEvent: function(type, args, delay){ - type = Events.removeOn(type); - if (!this.$events || !this.$events[type]) return this; - this.$events[type].each(function(fn){ - fn.create({'bind': this, 'delay': delay, 'arguments': args})(); - }, this); - return this; - }, - - removeEvent: function(type, fn){ - type = Events.removeOn(type); - if (!this.$events[type]) return this; - if (!fn.internal) this.$events[type].erase(fn); - return this; - }, - - removeEvents: function(events){ - var type; - if ($type(events) == 'object'){ - for (type in events) this.removeEvent(type, events[type]); - return this; - } - if (events) events = Events.removeOn(events); - for (type in this.$events){ - if (events && events != type) continue; - var fns = this.$events[type]; - for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); - } - return this; - } - -}); - -Events.removeOn = function(string){ - return string.replace(/^on([A-Z])/, function(full, first){ - return first.toLowerCase(); - }); -}; - -var Options = new Class({ - - setOptions: function(){ - this.options = $merge.run([this.options].extend(arguments)); - if (!this.addEvent) return this; - for (var option in this.options){ - if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; - this.addEvent(option, this.options[option]); - delete this.options[option]; - } - return this; - } - -}); - - -/* ---- - -name: Browser - -description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. - -license: MIT-style license. - -requires: [Native, $util] - -provides: [Browser, Window, Document, $exec] - -... -*/ - -var Browser = $merge({ - - Engine: {name: 'unknown', version: 0}, - - Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, - - Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, - - Plugins: {}, - - Engines: { - - presto: function(){ - return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); - }, - - trident: function(){ - return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); - }, - - webkit: function(){ - return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); - }, - - gecko: function(){ - return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); - } - - } - -}, Browser || {}); - -Browser.Platform[Browser.Platform.name] = true; - -Browser.detect = function(){ - - for (var engine in this.Engines){ - var version = this.Engines[engine](); - if (version){ - this.Engine = {name: engine, version: version}; - this.Engine[engine] = this.Engine[engine + version] = true; - break; - } - } - - return {name: engine, version: version}; - -}; - -Browser.detect(); - -Browser.Request = function(){ - return $try(function(){ - return new XMLHttpRequest(); - }, function(){ - return new ActiveXObject('MSXML2.XMLHTTP'); - }, function(){ - return new ActiveXObject('Microsoft.XMLHTTP'); - }); -}; - -Browser.Features.xhr = !!(Browser.Request()); - -Browser.Plugins.Flash = (function(){ - var version = ($try(function(){ - return navigator.plugins['Shockwave Flash'].description; - }, function(){ - return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); - }) || '0 r0').match(/\d+/g); - return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; -})(); - -function $exec(text){ - if (!text) return text; - if (window.execScript){ - window.execScript(text); - } else { - var script = document.createElement('script'); - script.setAttribute('type', 'text/javascript'); - script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; - document.head.appendChild(script); - document.head.removeChild(script); - } - return text; -}; - -Native.UID = 1; - -var $uid = (Browser.Engine.trident) ? function(item){ - return (item.uid || (item.uid = [Native.UID++]))[0]; -} : function(item){ - return item.uid || (item.uid = Native.UID++); -}; - -var Window = new Native({ - - name: 'Window', - - legacy: (Browser.Engine.trident) ? null: window.Window, - - initialize: function(win){ - $uid(win); - if (!win.Element){ - win.Element = $empty; - if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 - win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; - } - win.document.window = win; - return $extend(win, Window.Prototype); - }, - - afterImplement: function(property, value){ - window[property] = Window.Prototype[property] = value; - } - -}); - -Window.Prototype = {$family: {name: 'window'}}; - -new Window(window); - -var Document = new Native({ - - name: 'Document', - - legacy: (Browser.Engine.trident) ? null: window.Document, - - initialize: function(doc){ - $uid(doc); - doc.head = doc.getElementsByTagName('head')[0]; - doc.html = doc.getElementsByTagName('html')[0]; - if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ - doc.execCommand("BackgroundImageCache", false, true); - }); - if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){ - doc.window.detachEvent('onunload', arguments.callee); - doc.head = doc.html = doc.window = null; - }); - return $extend(doc, Document.Prototype); - }, - - afterImplement: function(property, value){ - document[property] = Document.Prototype[property] = value; - } - -}); - -Document.Prototype = {$family: {name: 'document'}}; - -new Document(document); - - -/* ---- - -name: Element - -description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. - -license: MIT-style license. - -requires: [Window, Document, Array, String, Function, Number, Hash] - -provides: [Element, Elements, $, $$, Iframe] - -... -*/ - -var Element = new Native({ - - name: 'Element', - - legacy: window.Element, - - initialize: function(tag, props){ - var konstructor = Element.Constructors.get(tag); - if (konstructor) return konstructor(props); - if (typeof tag == 'string') return document.newElement(tag, props); - return document.id(tag).set(props); - }, - - afterImplement: function(key, value){ - Element.Prototype[key] = value; - if (Array[key]) return; - Elements.implement(key, function(){ - var items = [], elements = true; - for (var i = 0, j = this.length; i < j; i++){ - var returns = this[i][key].apply(this[i], arguments); - items.push(returns); - if (elements) elements = ($type(returns) == 'element'); - } - return (elements) ? new Elements(items) : items; - }); - } - -}); - -Element.Prototype = {$family: {name: 'element'}}; - -Element.Constructors = new Hash; - -var IFrame = new Native({ - - name: 'IFrame', - - generics: false, - - initialize: function(){ - var params = Array.link(arguments, {properties: Object.type, iframe: $defined}); - var props = params.properties || {}; - var iframe = document.id(params.iframe); - var onload = props.onload || $empty; - delete props.onload; - props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time()); - iframe = new Element(iframe || 'iframe', props); - var onFrameLoad = function(){ - var host = $try(function(){ - return iframe.contentWindow.location.host; - }); - if (!host || host == window.location.host){ - var win = new Window(iframe.contentWindow); - new Document(iframe.contentWindow.document); - $extend(win.Element.prototype, Element.Prototype); - } - onload.call(iframe.contentWindow, iframe.contentWindow.document); - }; - var contentWindow = $try(function(){ - return iframe.contentWindow; - }); - ((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad); - return iframe; - } - -}); - -var Elements = new Native({ - - initialize: function(elements, options){ - options = $extend({ddup: true, cash: true}, options); - elements = elements || []; - if (options.ddup || options.cash){ - var uniques = {}, returned = []; - for (var i = 0, l = elements.length; i < l; i++){ - var el = document.id(elements[i], !options.cash); - if (options.ddup){ - if (uniques[el.uid]) continue; - uniques[el.uid] = true; - } - if (el) returned.push(el); - } - elements = returned; - } - return (options.cash) ? $extend(elements, this) : elements; - } - -}); - -Elements.implement({ - - filter: function(filter, bind){ - if (!filter) return this; - return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){ - return item.match(filter); - } : filter, bind)); - } - -}); - -(function(){ - -/**/ -var createElementAcceptsHTML; -try { - var x = document.createElement(''); - createElementAcceptsHTML = (x.name == 'x'); -} catch(e){} - -var escapeQuotes = function(html){ - return ('' + html).replace(/&/g,'&').replace(/"/g,'"'); -}; -/**/ - -Document.implement({ - - newElement: function(tag, props){ - if (props && props.checked != null) props.defaultChecked = props.checked; - /**/// Fix for readonly name and type properties in IE < 8 - if (createElementAcceptsHTML && props){ - tag = '<' + tag; - if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"'; - if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"'; - tag += '>'; - delete props.name; - delete props.type; - } - /**/ - return this.id(this.createElement(tag)).set(props); - }, - - newTextNode: function(text){ - return this.createTextNode(text); - }, - - getDocument: function(){ - return this; - }, - - getWindow: function(){ - return this.window; - }, - - id: (function(){ - - var types = { - - string: function(id, nocash, doc){ - id = doc.getElementById(id); - return (id) ? types.element(id, nocash) : null; - }, - - element: function(el, nocash){ - $uid(el); - if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){ - var proto = Element.Prototype; - for (var p in proto) el[p] = proto[p]; - }; - return el; - }, - - object: function(obj, nocash, doc){ - if (obj.toElement) return types.element(obj.toElement(doc), nocash); - return null; - } - - }; - - types.textnode = types.whitespace = types.window = types.document = $arguments(0); - - return function(el, nocash, doc){ - if (el && el.$family && el.uid) return el; - var type = $type(el); - return (types[type]) ? types[type](el, nocash, doc || document) : null; - }; - - })() - -}); - -})(); - -if (window.$ == null) Window.implement({ - $: function(el, nc){ - return document.id(el, nc, this.document); - } -}); - -Window.implement({ - - $$: function(selector){ - if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector); - var elements = []; - var args = Array.flatten(arguments); - for (var i = 0, l = args.length; i < l; i++){ - var item = args[i]; - switch ($type(item)){ - case 'element': elements.push(item); break; - case 'string': elements.extend(this.document.getElements(item, true)); - } - } - return new Elements(elements); - }, - - getDocument: function(){ - return this.document; - }, - - getWindow: function(){ - return this; - } - -}); - -Native.implement([Element, Document], { - - getElement: function(selector, nocash){ - return document.id(this.getElements(selector, true)[0] || null, nocash); - }, - - getElements: function(tags, nocash){ - tags = tags.split(','); - var elements = []; - var ddup = (tags.length > 1); - tags.each(function(tag){ - var partial = this.getElementsByTagName(tag.trim()); - (ddup) ? elements.extend(partial) : elements = partial; - }, this); - return new Elements(elements, {ddup: ddup, cash: !nocash}); - } - -}); - -(function(){ - -var collected = {}, storage = {}; -var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'}; - -var get = function(uid){ - return (storage[uid] || (storage[uid] = {})); -}; - -var clean = function(item, retain){ - if (!item) return; - var uid = item.uid; - if (retain !== true) retain = false; - if (Browser.Engine.trident){ - if (item.clearAttributes){ - var clone = retain && item.cloneNode(false); - item.clearAttributes(); - if (clone) item.mergeAttributes(clone); - } else if (item.removeEvents){ - item.removeEvents(); - } - if ((/object/i).test(item.tagName)){ - for (var p in item){ - if (typeof item[p] == 'function') item[p] = $empty; - } - Element.dispose(item); - } - } - if (!uid) return; - collected[uid] = storage[uid] = null; -}; - -var purge = function(){ - Hash.each(collected, clean); - if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean); - if (window.CollectGarbage) CollectGarbage(); - collected = storage = null; -}; - -var walk = function(element, walk, start, match, all, nocash){ - var el = element[start || walk]; - var elements = []; - while (el){ - if (el.nodeType == 1 && (!match || Element.match(el, match))){ - if (!all) return document.id(el, nocash); - elements.push(el); - } - el = el[walk]; - } - return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null; -}; - -var attributes = { - 'html': 'innerHTML', - 'class': 'className', - 'for': 'htmlFor', - 'defaultValue': 'defaultValue', - 'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent' -}; -var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer']; -var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']; - -bools = bools.associate(bools); - -Hash.extend(attributes, bools); -Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase))); - -var inserters = { - - before: function(context, element){ - if (element.parentNode) element.parentNode.insertBefore(context, element); - }, - - after: function(context, element){ - if (!element.parentNode) return; - var next = element.nextSibling; - (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context); - }, - - bottom: function(context, element){ - element.appendChild(context); - }, - - top: function(context, element){ - var first = element.firstChild; - (first) ? element.insertBefore(context, first) : element.appendChild(context); - } - -}; - -inserters.inside = inserters.bottom; - -Hash.each(inserters, function(inserter, where){ - - where = where.capitalize(); - - Element.implement('inject' + where, function(el){ - inserter(this, document.id(el, true)); - return this; - }); - - Element.implement('grab' + where, function(el){ - inserter(document.id(el, true), this); - return this; - }); - -}); - -Element.implement({ - - set: function(prop, value){ - switch ($type(prop)){ - case 'object': - for (var p in prop) this.set(p, prop[p]); - break; - case 'string': - var property = Element.Properties.get(prop); - (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value); - } - return this; - }, - - get: function(prop){ - var property = Element.Properties.get(prop); - return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop); - }, - - erase: function(prop){ - var property = Element.Properties.get(prop); - (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); - return this; - }, - - setProperty: function(attribute, value){ - var key = attributes[attribute]; - if (value == undefined) return this.removeProperty(attribute); - if (key && bools[attribute]) value = !!value; - (key) ? this[key] = value : this.setAttribute(attribute, '' + value); - return this; - }, - - setProperties: function(attributes){ - for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); - return this; - }, - - getProperty: function(attribute){ - var key = attributes[attribute]; - var value = (key) ? this[key] : this.getAttribute(attribute, 2); - return (bools[attribute]) ? !!value : (key) ? value : value || null; - }, - - getProperties: function(){ - var args = $A(arguments); - return args.map(this.getProperty, this).associate(args); - }, - - removeProperty: function(attribute){ - var key = attributes[attribute]; - (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute); - return this; - }, - - removeProperties: function(){ - Array.each(arguments, this.removeProperty, this); - return this; - }, - - hasClass: function(className){ - return this.className.contains(className, ' '); - }, - - addClass: function(className){ - if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); - return this; - }, - - removeClass: function(className){ - this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); - return this; - }, - - toggleClass: function(className){ - return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); - }, - - adopt: function(){ - Array.flatten(arguments).each(function(element){ - element = document.id(element, true); - if (element) this.appendChild(element); - }, this); - return this; - }, - - appendText: function(text, where){ - return this.grab(this.getDocument().newTextNode(text), where); - }, - - grab: function(el, where){ - inserters[where || 'bottom'](document.id(el, true), this); - return this; - }, - - inject: function(el, where){ - inserters[where || 'bottom'](this, document.id(el, true)); - return this; - }, - - replaces: function(el){ - el = document.id(el, true); - el.parentNode.replaceChild(this, el); - return this; - }, - - wraps: function(el, where){ - el = document.id(el, true); - return this.replaces(el).grab(el, where); - }, - - getPrevious: function(match, nocash){ - return walk(this, 'previousSibling', null, match, false, nocash); - }, - - getAllPrevious: function(match, nocash){ - return walk(this, 'previousSibling', null, match, true, nocash); - }, - - getNext: function(match, nocash){ - return walk(this, 'nextSibling', null, match, false, nocash); - }, - - getAllNext: function(match, nocash){ - return walk(this, 'nextSibling', null, match, true, nocash); - }, - - getFirst: function(match, nocash){ - return walk(this, 'nextSibling', 'firstChild', match, false, nocash); - }, - - getLast: function(match, nocash){ - return walk(this, 'previousSibling', 'lastChild', match, false, nocash); - }, - - getParent: function(match, nocash){ - return walk(this, 'parentNode', null, match, false, nocash); - }, - - getParents: function(match, nocash){ - return walk(this, 'parentNode', null, match, true, nocash); - }, - - getSiblings: function(match, nocash){ - return this.getParent().getChildren(match, nocash).erase(this); - }, - - getChildren: function(match, nocash){ - return walk(this, 'nextSibling', 'firstChild', match, true, nocash); - }, - - getWindow: function(){ - return this.ownerDocument.window; - }, - - getDocument: function(){ - return this.ownerDocument; - }, - - getElementById: function(id, nocash){ - var el = this.ownerDocument.getElementById(id); - if (!el) return null; - for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ - if (!parent) return null; - } - return document.id(el, nocash); - }, - - getSelected: function(){ - return new Elements($A(this.options).filter(function(option){ - return option.selected; - })); - }, - - getComputedStyle: function(property){ - if (this.currentStyle) return this.currentStyle[property.camelCase()]; - var computed = this.getDocument().defaultView.getComputedStyle(this, null); - return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; - }, - - toQueryString: function(){ - var queryString = []; - this.getElements('input, select, textarea', true).each(function(el){ - if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return; - var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){ - return opt.value; - }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; - $splat(value).each(function(val){ - if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val)); - }); - }); - return queryString.join('&'); - }, - - clone: function(contents, keepid){ - contents = contents !== false; - var clone = this.cloneNode(contents); - var clean = function(node, element){ - if (!keepid) node.removeAttribute('id'); - if (Browser.Engine.trident){ - node.clearAttributes(); - node.mergeAttributes(element); - node.removeAttribute('uid'); - if (node.options){ - var no = node.options, eo = element.options; - for (var j = no.length; j--;) no[j].selected = eo[j].selected; - } - } - var prop = props[element.tagName.toLowerCase()]; - if (prop && element[prop]) node[prop] = element[prop]; - }; - - if (contents){ - var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); - for (var i = ce.length; i--;) clean(ce[i], te[i]); - } - - clean(clone, this); - return document.id(clone); - }, - - destroy: function(){ - Element.empty(this); - Element.dispose(this); - clean(this, true); - return null; - }, - - empty: function(){ - $A(this.childNodes).each(function(node){ - Element.destroy(node); - }); - return this; - }, - - dispose: function(){ - return (this.parentNode) ? this.parentNode.removeChild(this) : this; - }, - - hasChild: function(el){ - el = document.id(el, true); - if (!el) return false; - if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el); - return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16); - }, - - match: function(tag){ - return (!tag || (tag == this) || (Element.get(this, 'tag') == tag)); - } - -}); - -Native.implement([Element, Window, Document], { - - addListener: function(type, fn){ - if (type == 'unload'){ - var old = fn, self = this; - fn = function(){ - self.removeListener('unload', fn); - old(); - }; - } else { - collected[this.uid] = this; - } - if (this.addEventListener) this.addEventListener(type, fn, false); - else this.attachEvent('on' + type, fn); - return this; - }, - - removeListener: function(type, fn){ - if (this.removeEventListener) this.removeEventListener(type, fn, false); - else this.detachEvent('on' + type, fn); - return this; - }, - - retrieve: function(property, dflt){ - var storage = get(this.uid), prop = storage[property]; - if (dflt != undefined && prop == undefined) prop = storage[property] = dflt; - return $pick(prop); - }, - - store: function(property, value){ - var storage = get(this.uid); - storage[property] = value; - return this; - }, - - eliminate: function(property){ - var storage = get(this.uid); - delete storage[property]; - return this; - } - -}); - -window.addListener('unload', purge); - -})(); - -Element.Properties = new Hash; - -Element.Properties.style = { - - set: function(style){ - this.style.cssText = style; - }, - - get: function(){ - return this.style.cssText; - }, - - erase: function(){ - this.style.cssText = ''; - } - -}; - -Element.Properties.tag = { - - get: function(){ - return this.tagName.toLowerCase(); - } - -}; - -Element.Properties.html = (function(){ - var wrapper = document.createElement('div'); - - var translations = { - table: [1, '', '
'], - select: [1, ''], - tbody: [2, '', '
'], - tr: [3, '', '
'] - }; - translations.thead = translations.tfoot = translations.tbody; - - var html = { - set: function(){ - var html = Array.flatten(arguments).join(''); - var wrap = Browser.Engine.trident && translations[this.get('tag')]; - if (wrap){ - var first = wrapper; - first.innerHTML = wrap[1] + html + wrap[2]; - for (var i = wrap[0]; i--;) first = first.firstChild; - this.empty().adopt(first.childNodes); - } else { - this.innerHTML = html; - } - } - }; - - html.erase = html.set; - - return html; -})(); - -if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = { - get: function(){ - if (this.innerText) return this.innerText; - var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body); - var text = temp.innerText; - temp.destroy(); - return text; - } -}; - - -/* ---- - -name: Element.Dimensions - -description: Contains methods to work with size, scroll, or positioning of Elements and the window object. - -license: MIT-style license. - -credits: - - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). - - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). - -requires: Element - -provides: Element.Dimensions - -... -*/ - -(function(){ - -Element.implement({ - - scrollTo: function(x, y){ - if (isBody(this)){ - this.getWindow().scrollTo(x, y); - } else { - this.scrollLeft = x; - this.scrollTop = y; - } - return this; - }, - - getSize: function(){ - if (isBody(this)) return this.getWindow().getSize(); - return {x: this.offsetWidth, y: this.offsetHeight}; - }, - - getScrollSize: function(){ - if (isBody(this)) return this.getWindow().getScrollSize(); - return {x: this.scrollWidth, y: this.scrollHeight}; - }, - - getScroll: function(){ - if (isBody(this)) return this.getWindow().getScroll(); - return {x: this.scrollLeft, y: this.scrollTop}; - }, - - getScrolls: function(){ - var element = this, position = {x: 0, y: 0}; - while (element && !isBody(element)){ - position.x += element.scrollLeft; - position.y += element.scrollTop; - element = element.parentNode; - } - return position; - }, - - getOffsetParent: function(){ - var element = this; - if (isBody(element)) return null; - if (!Browser.Engine.trident) return element.offsetParent; - while ((element = element.parentNode) && !isBody(element)){ - if (styleString(element, 'position') != 'static') return element; - } - return null; - }, - - getOffsets: function(){ - if (this.getBoundingClientRect){ - var bound = this.getBoundingClientRect(), - html = document.id(this.getDocument().documentElement), - htmlScroll = html.getScroll(), - elemScrolls = this.getScrolls(), - elemScroll = this.getScroll(), - isFixed = (styleString(this, 'position') == 'fixed'); - - return { - x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, - y: bound.top.toInt() + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop - }; - } - - var element = this, position = {x: 0, y: 0}; - if (isBody(this)) return position; - - while (element && !isBody(element)){ - position.x += element.offsetLeft; - position.y += element.offsetTop; - - if (Browser.Engine.gecko){ - if (!borderBox(element)){ - position.x += leftBorder(element); - position.y += topBorder(element); - } - var parent = element.parentNode; - if (parent && styleString(parent, 'overflow') != 'visible'){ - position.x += leftBorder(parent); - position.y += topBorder(parent); - } - } else if (element != this && Browser.Engine.webkit){ - position.x += leftBorder(element); - position.y += topBorder(element); - } - - element = element.offsetParent; - } - if (Browser.Engine.gecko && !borderBox(this)){ - position.x -= leftBorder(this); - position.y -= topBorder(this); - } - return position; - }, - - getPosition: function(relative){ - if (isBody(this)) return {x: 0, y: 0}; - var offset = this.getOffsets(), - scroll = this.getScrolls(); - var position = { - x: offset.x - scroll.x, - y: offset.y - scroll.y - }; - var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0}; - return {x: position.x - relativePosition.x, y: position.y - relativePosition.y}; - }, - - getCoordinates: function(element){ - if (isBody(this)) return this.getWindow().getCoordinates(); - var position = this.getPosition(element), - size = this.getSize(); - var obj = { - left: position.x, - top: position.y, - width: size.x, - height: size.y - }; - obj.right = obj.left + obj.width; - obj.bottom = obj.top + obj.height; - return obj; - }, - - computePosition: function(obj){ - return { - left: obj.x - styleNumber(this, 'margin-left'), - top: obj.y - styleNumber(this, 'margin-top') - }; - }, - - setPosition: function(obj){ - return this.setStyles(this.computePosition(obj)); - } - -}); - - -Native.implement([Document, Window], { - - getSize: function(){ - if (Browser.Engine.presto || Browser.Engine.webkit){ - var win = this.getWindow(); - return {x: win.innerWidth, y: win.innerHeight}; - } - var doc = getCompatElement(this); - return {x: doc.clientWidth, y: doc.clientHeight}; - }, - - getScroll: function(){ - var win = this.getWindow(), doc = getCompatElement(this); - return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; - }, - - getScrollSize: function(){ - var doc = getCompatElement(this), min = this.getSize(); - return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)}; - }, - - getPosition: function(){ - return {x: 0, y: 0}; - }, - - getCoordinates: function(){ - var size = this.getSize(); - return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; - } - -}); - -// private methods - -var styleString = Element.getComputedStyle; - -function styleNumber(element, style){ - return styleString(element, style).toInt() || 0; -}; - -function borderBox(element){ - return styleString(element, '-moz-box-sizing') == 'border-box'; -}; - -function topBorder(element){ - return styleNumber(element, 'border-top-width'); -}; - -function leftBorder(element){ - return styleNumber(element, 'border-left-width'); -}; - -function isBody(element){ - return (/^(?:body|html)$/i).test(element.tagName); -}; - -function getCompatElement(element){ - var doc = element.getDocument(); - return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; -}; - -})(); - -//aliases -Element.alias('setPosition', 'position'); //compatability - -Native.implement([Window, Document, Element], { - - getHeight: function(){ - return this.getSize().y; - }, - - getWidth: function(){ - return this.getSize().x; - }, - - getScrollTop: function(){ - return this.getScroll().y; - }, - - getScrollLeft: function(){ - return this.getScroll().x; - }, - - getScrollHeight: function(){ - return this.getScrollSize().y; - }, - - getScrollWidth: function(){ - return this.getScrollSize().x; - }, - - getTop: function(){ - return this.getPosition().y; - }, - - getLeft: function(){ - return this.getPosition().x; - } - -}); - - -/* ---- - -name: Event - -description: Contains the Event Class, to make the event object cross-browser. - -license: MIT-style license. - -requires: [Window, Document, Hash, Array, Function, String] - -provides: Event - -... -*/ - -var Event = new Native({ - - name: 'Event', - - initialize: function(event, win){ - win = win || window; - var doc = win.document; - event = event || win.event; - if (event.$extended) return event; - this.$extended = true; - var type = event.type; - var target = event.target || event.srcElement; - while (target && target.nodeType == 3) target = target.parentNode; - - if (type.test(/key/)){ - var code = event.which || event.keyCode; - var key = Event.Keys.keyOf(code); - if (type == 'keydown'){ - var fKey = code - 111; - if (fKey > 0 && fKey < 13) key = 'f' + fKey; - } - key = key || String.fromCharCode(code).toLowerCase(); - } else if (type.match(/(click|mouse|menu)/i)){ - doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; - var page = { - x: event.pageX || event.clientX + doc.scrollLeft, - y: event.pageY || event.clientY + doc.scrollTop - }; - var client = { - x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, - y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY - }; - if (type.match(/DOMMouseScroll|mousewheel/)){ - var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; - } - var rightClick = (event.which == 3) || (event.button == 2); - var related = null; - if (type.match(/over|out/)){ - switch (type){ - case 'mouseover': related = event.relatedTarget || event.fromElement; break; - case 'mouseout': related = event.relatedTarget || event.toElement; - } - if (!(function(){ - while (related && related.nodeType == 3) related = related.parentNode; - return true; - }).create({attempt: Browser.Engine.gecko})()) related = false; - } - } - - return $extend(this, { - event: event, - type: type, - - page: page, - client: client, - rightClick: rightClick, - - wheel: wheel, - - relatedTarget: related, - target: target, - - code: code, - key: key, - - shift: event.shiftKey, - control: event.ctrlKey, - alt: event.altKey, - meta: event.metaKey - }); - } - -}); - -Event.Keys = new Hash({ - 'enter': 13, - 'up': 38, - 'down': 40, - 'left': 37, - 'right': 39, - 'esc': 27, - 'space': 32, - 'backspace': 8, - 'tab': 9, - 'delete': 46 -}); - -Event.implement({ - - stop: function(){ - return this.stopPropagation().preventDefault(); - }, - - stopPropagation: function(){ - if (this.event.stopPropagation) this.event.stopPropagation(); - else this.event.cancelBubble = true; - return this; - }, - - preventDefault: function(){ - if (this.event.preventDefault) this.event.preventDefault(); - else this.event.returnValue = false; - return this; - } - -}); - - -/* ---- - -name: Element.Event - -description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. - -license: MIT-style license. - -requires: [Element, Event] - -provides: Element.Event - -... -*/ - -Element.Properties.events = {set: function(events){ - this.addEvents(events); -}}; - -Native.implement([Element, Window, Document], { - - addEvent: function(type, fn){ - var events = this.retrieve('events', {}); - events[type] = events[type] || {'keys': [], 'values': []}; - if (events[type].keys.contains(fn)) return this; - events[type].keys.push(fn); - var realType = type, custom = Element.Events.get(type), condition = fn, self = this; - if (custom){ - if (custom.onAdd) custom.onAdd.call(this, fn); - if (custom.condition){ - condition = function(event){ - if (custom.condition.call(this, event)) return fn.call(this, event); - return true; - }; - } - realType = custom.base || realType; - } - var defn = function(){ - return fn.call(self); - }; - var nativeEvent = Element.NativeEvents[realType]; - if (nativeEvent){ - if (nativeEvent == 2){ - defn = function(event){ - event = new Event(event, self.getWindow()); - if (condition.call(self, event) === false) event.stop(); - }; - } - this.addListener(realType, defn); - } - events[type].values.push(defn); - return this; - }, - - removeEvent: function(type, fn){ - var events = this.retrieve('events'); - if (!events || !events[type]) return this; - var pos = events[type].keys.indexOf(fn); - if (pos == -1) return this; - events[type].keys.splice(pos, 1); - var value = events[type].values.splice(pos, 1)[0]; - var custom = Element.Events.get(type); - if (custom){ - if (custom.onRemove) custom.onRemove.call(this, fn); - type = custom.base || type; - } - return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this; - }, - - addEvents: function(events){ - for (var event in events) this.addEvent(event, events[event]); - return this; - }, - - removeEvents: function(events){ - var type; - if ($type(events) == 'object'){ - for (type in events) this.removeEvent(type, events[type]); - return this; - } - var attached = this.retrieve('events'); - if (!attached) return this; - if (!events){ - for (type in attached) this.removeEvents(type); - this.eliminate('events'); - } else if (attached[events]){ - while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]); - attached[events] = null; - } - return this; - }, - - fireEvent: function(type, args, delay){ - var events = this.retrieve('events'); - if (!events || !events[type]) return this; - events[type].keys.each(function(fn){ - fn.create({'bind': this, 'delay': delay, 'arguments': args})(); - }, this); - return this; - }, - - cloneEvents: function(from, type){ - from = document.id(from); - var fevents = from.retrieve('events'); - if (!fevents) return this; - if (!type){ - for (var evType in fevents) this.cloneEvents(from, evType); - } else if (fevents[type]){ - fevents[type].keys.each(function(fn){ - this.addEvent(type, fn); - }, this); - } - return this; - } - -}); - -// IE9 -try { - if (typeof HTMLElement != 'undefined') - HTMLElement.prototype.fireEvent = Element.prototype.fireEvent; -} catch(e){} - -Element.NativeEvents = { - click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons - mousewheel: 2, DOMMouseScroll: 2, //mouse wheel - mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement - keydown: 2, keypress: 2, keyup: 2, //keyboard - focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements - load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window - error: 1, abort: 1, scroll: 1 //misc -}; - -(function(){ - -var $check = function(event){ - var related = event.relatedTarget; - if (related == undefined) return true; - if (related === false) return false; - return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related)); -}; - -Element.Events = new Hash({ - - mouseenter: { - base: 'mouseover', - condition: $check - }, - - mouseleave: { - base: 'mouseout', - condition: $check - }, - - mousewheel: { - base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel' - } - -}); - -})(); - - -/* ---- - -name: Element.Style - -description: Contains methods for interacting with the styles of Elements in a fashionable way. - -license: MIT-style license. - -requires: Element - -provides: Element.Style - -... -*/ - -Element.Properties.styles = {set: function(styles){ - this.setStyles(styles); -}}; - -Element.Properties.opacity = { - - set: function(opacity, novisibility){ - if (!novisibility){ - if (opacity == 0){ - if (this.style.visibility != 'hidden') this.style.visibility = 'hidden'; - } else { - if (this.style.visibility != 'visible') this.style.visibility = 'visible'; - } - } - if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; - if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; - this.style.opacity = opacity; - this.store('opacity', opacity); - }, - - get: function(){ - return this.retrieve('opacity', 1); - } - -}; - -Element.implement({ - - setOpacity: function(value){ - return this.set('opacity', value, true); - }, - - getOpacity: function(){ - return this.get('opacity'); - }, - - setStyle: function(property, value){ - switch (property){ - case 'opacity': return this.set('opacity', parseFloat(value)); - case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; - } - property = property.camelCase(); - if ($type(value) != 'string'){ - var map = (Element.Styles.get(property) || '@').split(' '); - value = $splat(value).map(function(val, i){ - if (!map[i]) return ''; - return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; - }).join(' '); - } else if (value == String(Number(value))){ - value = Math.round(value); - } - this.style[property] = value; - return this; - }, - - getStyle: function(property){ - switch (property){ - case 'opacity': return this.get('opacity'); - case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; - } - property = property.camelCase(); - var result = this.style[property]; - if (!$chk(result)){ - result = []; - for (var style in Element.ShortStyles){ - if (property != style) continue; - for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); - return result.join(' '); - } - result = this.getComputedStyle(property); - } - if (result){ - result = String(result); - var color = result.match(/rgba?\([\d\s,]+\)/); - if (color) result = result.replace(color[0], color[0].rgbToHex()); - } - if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){ - if (property.test(/^(height|width)$/)){ - var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; - values.each(function(value){ - size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); - }, this); - return this['offset' + property.capitalize()] - size + 'px'; - } - if ((Browser.Engine.presto) && String(result).test('px')) return result; - if (property.test(/(border(.+)Width|margin|padding)/)) return '0px'; - } - return result; - }, - - setStyles: function(styles){ - for (var style in styles) this.setStyle(style, styles[style]); - return this; - }, - - getStyles: function(){ - var result = {}; - Array.flatten(arguments).each(function(key){ - result[key] = this.getStyle(key); - }, this); - return result; - } - -}); - -Element.Styles = new Hash({ - left: '@px', top: '@px', bottom: '@px', right: '@px', - width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', - backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', - fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', - margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', - borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', - zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' -}); - -Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; - -['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ - var Short = Element.ShortStyles; - var All = Element.Styles; - ['margin', 'padding'].each(function(style){ - var sd = style + direction; - Short[style][sd] = All[sd] = '@px'; - }); - var bd = 'border' + direction; - Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; - var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; - Short[bd] = {}; - Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; - Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; - Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; -}); - - -/* ---- - -name: Fx - -description: Contains the basic animation logic to be extended by all other Fx Classes. - -license: MIT-style license. - -requires: [Chain, Events, Options] - -provides: Fx - -... -*/ - -var Fx = new Class({ - - Implements: [Chain, Events, Options], - - options: { - /* - onStart: $empty, - onCancel: $empty, - onComplete: $empty, - */ - fps: 50, - unit: false, - duration: 500, - link: 'ignore' - }, - - initialize: function(options){ - this.subject = this.subject || this; - this.setOptions(options); - this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt(); - var wait = this.options.wait; - if (wait === false) this.options.link = 'cancel'; - }, - - getTransition: function(){ - return function(p){ - return -(Math.cos(Math.PI * p) - 1) / 2; - }; - }, - - step: function(){ - var time = $time(); - if (time < this.time + this.options.duration){ - var delta = this.transition((time - this.time) / this.options.duration); - this.set(this.compute(this.from, this.to, delta)); - } else { - this.set(this.compute(this.from, this.to, 1)); - this.complete(); - } - }, - - set: function(now){ - return now; - }, - - compute: function(from, to, delta){ - return Fx.compute(from, to, delta); - }, - - check: function(){ - if (!this.timer) return true; - switch (this.options.link){ - case 'cancel': this.cancel(); return true; - case 'chain': this.chain(this.caller.bind(this, arguments)); return false; - } - return false; - }, - - start: function(from, to){ - if (!this.check(from, to)) return this; - this.from = from; - this.to = to; - this.time = 0; - this.transition = this.getTransition(); - this.startTimer(); - this.onStart(); - return this; - }, - - complete: function(){ - if (this.stopTimer()) this.onComplete(); - return this; - }, - - cancel: function(){ - if (this.stopTimer()) this.onCancel(); - return this; - }, - - onStart: function(){ - this.fireEvent('start', this.subject); - }, - - onComplete: function(){ - this.fireEvent('complete', this.subject); - if (!this.callChain()) this.fireEvent('chainComplete', this.subject); - }, - - onCancel: function(){ - this.fireEvent('cancel', this.subject).clearChain(); - }, - - pause: function(){ - this.stopTimer(); - return this; - }, - - resume: function(){ - this.startTimer(); - return this; - }, - - stopTimer: function(){ - if (!this.timer) return false; - this.time = $time() - this.time; - this.timer = $clear(this.timer); - return true; - }, - - startTimer: function(){ - if (this.timer) return false; - this.time = $time() - this.time; - this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); - return true; - } - -}); - -Fx.compute = function(from, to, delta){ - return (to - from) * delta + from; -}; - -Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; - - -/* ---- - -name: Fx.CSS - -description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. - -license: MIT-style license. - -requires: [Fx, Element.Style] - -provides: Fx.CSS - -... -*/ - -Fx.CSS = new Class({ - - Extends: Fx, - - //prepares the base from/to object - - prepare: function(element, property, values){ - values = $splat(values); - var values1 = values[1]; - if (!$chk(values1)){ - values[1] = values[0]; - values[0] = element.getStyle(property); - } - var parsed = values.map(this.parse); - return {from: parsed[0], to: parsed[1]}; - }, - - //parses a value into an array - - parse: function(value){ - value = $lambda(value)(); - value = (typeof value == 'string') ? value.split(' ') : $splat(value); - return value.map(function(val){ - val = String(val); - var found = false; - Fx.CSS.Parsers.each(function(parser, key){ - if (found) return; - var parsed = parser.parse(val); - if ($chk(parsed)) found = {value: parsed, parser: parser}; - }); - found = found || {value: val, parser: Fx.CSS.Parsers.String}; - return found; - }); - }, - - //computes by a from and to prepared objects, using their parsers. - - compute: function(from, to, delta){ - var computed = []; - (Math.min(from.length, to.length)).times(function(i){ - computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); - }); - computed.$family = {name: 'fx:css:value'}; - return computed; - }, - - //serves the value as settable - - serve: function(value, unit){ - if ($type(value) != 'fx:css:value') value = this.parse(value); - var returned = []; - value.each(function(bit){ - returned = returned.concat(bit.parser.serve(bit.value, unit)); - }); - return returned; - }, - - //renders the change to an element - - render: function(element, property, value, unit){ - element.setStyle(property, this.serve(value, unit)); - }, - - //searches inside the page css to find the values for a selector - - search: function(selector){ - if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; - var to = {}; - Array.each(document.styleSheets, function(sheet, j){ - var href = sheet.href; - if (href && href.contains('://') && !href.contains(document.domain)) return; - var rules = sheet.rules || sheet.cssRules; - Array.each(rules, function(rule, i){ - if (!rule.style) return; - var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ - return m.toLowerCase(); - }) : null; - if (!selectorText || !selectorText.test('^' + selector + '$')) return; - Element.Styles.each(function(value, style){ - if (!rule.style[style] || Element.ShortStyles[style]) return; - value = String(rule.style[style]); - to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value; - }); - }); - }); - return Fx.CSS.Cache[selector] = to; - } - -}); - -Fx.CSS.Cache = {}; - -Fx.CSS.Parsers = new Hash({ - - Color: { - parse: function(value){ - if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); - return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; - }, - compute: function(from, to, delta){ - return from.map(function(value, i){ - return Math.round(Fx.compute(from[i], to[i], delta)); - }); - }, - serve: function(value){ - return value.map(Number); - } - }, - - Number: { - parse: parseFloat, - compute: Fx.compute, - serve: function(value, unit){ - return (unit) ? value + unit : value; - } - }, - - String: { - parse: $lambda(false), - compute: $arguments(1), - serve: $arguments(0) - } - -}); - - -/* ---- - -name: Fx.Morph - -description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. - -license: MIT-style license. - -requires: Fx.CSS - -provides: Fx.Morph - -... -*/ - -Fx.Morph = new Class({ - - Extends: Fx.CSS, - - initialize: function(element, options){ - this.element = this.subject = document.id(element); - this.parent(options); - }, - - set: function(now){ - if (typeof now == 'string') now = this.search(now); - for (var p in now) this.render(this.element, p, now[p], this.options.unit); - return this; - }, - - compute: function(from, to, delta){ - var now = {}; - for (var p in from) now[p] = this.parent(from[p], to[p], delta); - return now; - }, - - start: function(properties){ - if (!this.check(properties)) return this; - if (typeof properties == 'string') properties = this.search(properties); - var from = {}, to = {}; - for (var p in properties){ - var parsed = this.prepare(this.element, p, properties[p]); - from[p] = parsed.from; - to[p] = parsed.to; - } - return this.parent(from, to); - } - -}); - -Element.Properties.morph = { - - set: function(options){ - var morph = this.retrieve('morph'); - if (morph) morph.cancel(); - return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options)); - }, - - get: function(options){ - if (options || !this.retrieve('morph')){ - if (options || !this.retrieve('morph:options')) this.set('morph', options); - this.store('morph', new Fx.Morph(this, this.retrieve('morph:options'))); - } - return this.retrieve('morph'); - } - -}; - -Element.implement({ - - morph: function(props){ - this.get('morph').start(props); - return this; - } - -}); - - -/* ---- - -name: Fx.Transitions - -description: Contains a set of advanced transitions to be used with any of the Fx Classes. - -license: MIT-style license. - -credits: Easing Equations by Robert Penner, , modified and optimized to be used with MooTools. - -requires: Fx - -provides: Fx.Transitions - -... -*/ - -Fx.implement({ - - getTransition: function(){ - var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; - if (typeof trans == 'string'){ - var data = trans.split(':'); - trans = Fx.Transitions; - trans = trans[data[0]] || trans[data[0].capitalize()]; - if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; - } - return trans; - } - -}); - -Fx.Transition = function(transition, params){ - params = $splat(params); - return $extend(transition, { - easeIn: function(pos){ - return transition(pos, params); - }, - easeOut: function(pos){ - return 1 - transition(1 - pos, params); - }, - easeInOut: function(pos){ - return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; - } - }); -}; - -Fx.Transitions = new Hash({ - - linear: $arguments(0) - -}); - -Fx.Transitions.extend = function(transitions){ - for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); -}; - -Fx.Transitions.extend({ - - Pow: function(p, x){ - return Math.pow(p, x[0] || 6); - }, - - Expo: function(p){ - return Math.pow(2, 8 * (p - 1)); - }, - - Circ: function(p){ - return 1 - Math.sin(Math.acos(p)); - }, - - Sine: function(p){ - return 1 - Math.sin((1 - p) * Math.PI / 2); - }, - - Back: function(p, x){ - x = x[0] || 1.618; - return Math.pow(p, 2) * ((x + 1) * p - x); - }, - - Bounce: function(p){ - var value; - for (var a = 0, b = 1; 1; a += b, b /= 2){ - if (p >= (7 - 4 * a) / 11){ - value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); - break; - } - } - return value; - }, - - Elastic: function(p, x){ - return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); - } - -}); - -['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ - Fx.Transitions[transition] = new Fx.Transition(function(p){ - return Math.pow(p, [i + 2]); - }); -}); - - -/* ---- - -name: Fx.Tween - -description: Formerly Fx.Style, effect to transition any CSS property for an element. - -license: MIT-style license. - -requires: Fx.CSS - -provides: [Fx.Tween, Element.fade, Element.highlight] - -... -*/ - -Fx.Tween = new Class({ - - Extends: Fx.CSS, - - initialize: function(element, options){ - this.element = this.subject = document.id(element); - this.parent(options); - }, - - set: function(property, now){ - if (arguments.length == 1){ - now = property; - property = this.property || this.options.property; - } - this.render(this.element, property, now, this.options.unit); - return this; - }, - - start: function(property, from, to){ - if (!this.check(property, from, to)) return this; - var args = Array.flatten(arguments); - this.property = this.options.property || args.shift(); - var parsed = this.prepare(this.element, this.property, args); - return this.parent(parsed.from, parsed.to); - } - -}); - -Element.Properties.tween = { - - set: function(options){ - var tween = this.retrieve('tween'); - if (tween) tween.cancel(); - return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options)); - }, - - get: function(options){ - if (options || !this.retrieve('tween')){ - if (options || !this.retrieve('tween:options')) this.set('tween', options); - this.store('tween', new Fx.Tween(this, this.retrieve('tween:options'))); - } - return this.retrieve('tween'); - } - -}; - -Element.implement({ - - tween: function(property, from, to){ - this.get('tween').start(arguments); - return this; - }, - - fade: function(how){ - var fade = this.get('tween'), o = 'opacity', toggle; - how = $pick(how, 'toggle'); - switch (how){ - case 'in': fade.start(o, 1); break; - case 'out': fade.start(o, 0); break; - case 'show': fade.set(o, 1); break; - case 'hide': fade.set(o, 0); break; - case 'toggle': - var flag = this.retrieve('fade:flag', this.get('opacity') == 1); - fade.start(o, (flag) ? 0 : 1); - this.store('fade:flag', !flag); - toggle = true; - break; - default: fade.start(o, arguments); - } - if (!toggle) this.eliminate('fade:flag'); - return this; - }, - - highlight: function(start, end){ - if (!end){ - end = this.retrieve('highlight:original', this.getStyle('background-color')); - end = (end == 'transparent') ? '#fff' : end; - } - var tween = this.get('tween'); - tween.start('background-color', start || '#ffff88', end).chain(function(){ - this.setStyle('background-color', this.retrieve('highlight:original')); - tween.callChain(); - }.bind(this)); - return this; - } - -}); - - -/* ---- - -name: Request - -description: Powerful all purpose Request Class. Uses XMLHTTPRequest. - -license: MIT-style license. - -requires: [Element, Chain, Events, Options, Browser] - -provides: Request - -... -*/ - -var Request = new Class({ - - Implements: [Chain, Events, Options], - - options: {/* - onRequest: $empty, - onComplete: $empty, - onCancel: $empty, - onSuccess: $empty, - onFailure: $empty, - onException: $empty,*/ - url: '', - data: '', - headers: { - 'X-Requested-With': 'XMLHttpRequest', - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }, - async: true, - format: false, - method: 'post', - link: 'ignore', - isSuccess: null, - emulation: true, - urlEncoded: true, - encoding: 'utf-8', - evalScripts: false, - evalResponse: false, - noCache: false - }, - - initialize: function(options){ - this.xhr = new Browser.Request(); - this.setOptions(options); - this.options.isSuccess = this.options.isSuccess || this.isSuccess; - this.headers = new Hash(this.options.headers); - }, - - onStateChange: function(){ - if (this.xhr.readyState != 4 || !this.running) return; - this.running = false; - this.status = 0; - $try(function(){ - this.status = this.xhr.status; - }.bind(this)); - this.xhr.onreadystatechange = $empty; - if (this.options.isSuccess.call(this, this.status)){ - this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML}; - this.success(this.response.text, this.response.xml); - } else { - this.response = {text: null, xml: null}; - this.failure(); - } - }, - - isSuccess: function(){ - return ((this.status >= 200) && (this.status < 300)); - }, - - processScripts: function(text){ - if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text); - return text.stripScripts(this.options.evalScripts); - }, - - success: function(text, xml){ - this.onSuccess(this.processScripts(text), xml); - }, - - onSuccess: function(){ - this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); - }, - - failure: function(){ - this.onFailure(); - }, - - onFailure: function(){ - this.fireEvent('complete').fireEvent('failure', this.xhr); - }, - - setHeader: function(name, value){ - this.headers.set(name, value); - return this; - }, - - getHeader: function(name){ - return $try(function(){ - return this.xhr.getResponseHeader(name); - }.bind(this)); - }, - - check: function(){ - if (!this.running) return true; - switch (this.options.link){ - case 'cancel': this.cancel(); return true; - case 'chain': this.chain(this.caller.bind(this, arguments)); return false; - } - return false; - }, - - send: function(options){ - if (!this.check(options)) return this; - this.running = true; - - var type = $type(options); - if (type == 'string' || type == 'element') options = {data: options}; - - var old = this.options; - options = $extend({data: old.data, url: old.url, method: old.method}, options); - var data = options.data, url = String(options.url), method = options.method.toLowerCase(); - - switch ($type(data)){ - case 'element': data = document.id(data).toQueryString(); break; - case 'object': case 'hash': data = Hash.toQueryString(data); - } - - if (this.options.format){ - var format = 'format=' + this.options.format; - data = (data) ? format + '&' + data : format; - } - - if (this.options.emulation && !['get', 'post'].contains(method)){ - var _method = '_method=' + method; - data = (data) ? _method + '&' + data : _method; - method = 'post'; - } - - if (this.options.urlEncoded && method == 'post'){ - var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; - this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding); - } - - if (this.options.noCache){ - var noCache = 'noCache=' + new Date().getTime(); - data = (data) ? noCache + '&' + data : noCache; - } - - var trimPosition = url.lastIndexOf('/'); - if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); - - if (data && method == 'get'){ - url = url + (url.contains('?') ? '&' : '?') + data; - data = null; - } - - this.xhr.open(method.toUpperCase(), url, this.options.async); - - this.xhr.onreadystatechange = this.onStateChange.bind(this); - - this.headers.each(function(value, key){ - try { - this.xhr.setRequestHeader(key, value); - } catch (e){ - this.fireEvent('exception', [key, value]); - } - }, this); - - this.fireEvent('request'); - this.xhr.send(data); - if (!this.options.async) this.onStateChange(); - return this; - }, - - cancel: function(){ - if (!this.running) return this; - this.running = false; - this.xhr.abort(); - this.xhr.onreadystatechange = $empty; - this.xhr = new Browser.Request(); - this.fireEvent('cancel'); - return this; - } - -}); - -(function(){ - -var methods = {}; -['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ - methods[method] = function(){ - var params = Array.link(arguments, {url: String.type, data: $defined}); - return this.send($extend(params, {method: method})); - }; -}); - -Request.implement(methods); - -})(); - -Element.Properties.send = { - - set: function(options){ - var send = this.retrieve('send'); - if (send) send.cancel(); - return this.eliminate('send').store('send:options', $extend({ - data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') - }, options)); - }, - - get: function(options){ - if (options || !this.retrieve('send')){ - if (options || !this.retrieve('send:options')) this.set('send', options); - this.store('send', new Request(this.retrieve('send:options'))); - } - return this.retrieve('send'); - } - -}; - -Element.implement({ - - send: function(url){ - var sender = this.get('send'); - sender.send({data: this, url: url || sender.options.url}); - return this; - } - -}); - - -/* ---- - -name: Request.HTML - -description: Extends the basic Request Class with additional methods for interacting with HTML responses. - -license: MIT-style license. - -requires: [Request, Element] - -provides: Request.HTML - -... -*/ - -Request.HTML = new Class({ - - Extends: Request, - - options: { - update: false, - append: false, - evalScripts: true, - filter: false - }, - - processHTML: function(text){ - var match = text.match(/]*>([\s\S]*?)<\/body>/i); - text = (match) ? match[1] : text; - - var container = new Element('div'); - - return $try(function(){ - var root = '' + text + '', doc; - if (Browser.Engine.trident){ - doc = new ActiveXObject('Microsoft.XMLDOM'); - doc.async = false; - doc.loadXML(root); - } else { - doc = new DOMParser().parseFromString(root, 'text/xml'); - } - root = doc.getElementsByTagName('root')[0]; - if (!root) return null; - for (var i = 0, k = root.childNodes.length; i < k; i++){ - var child = Element.clone(root.childNodes[i], true, true); - if (child) container.grab(child); - } - return container; - }) || container.set('html', text); - }, - - success: function(text){ - var options = this.options, response = this.response; - - response.html = text.stripScripts(function(script){ - response.javascript = script; - }); - - var temp = this.processHTML(response.html); - - response.tree = temp.childNodes; - response.elements = temp.getElements('*'); - - if (options.filter) response.tree = response.elements.filter(options.filter); - if (options.update) document.id(options.update).empty().set('html', response.html); - else if (options.append) document.id(options.append).adopt(temp.getChildren()); - if (options.evalScripts) $exec(response.javascript); - - this.onSuccess(response.tree, response.elements, response.html, response.javascript); - } - -}); - -Element.Properties.load = { - - set: function(options){ - var load = this.retrieve('load'); - if (load) load.cancel(); - return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options)); - }, - - get: function(options){ - if (options || ! this.retrieve('load')){ - if (options || !this.retrieve('load:options')) this.set('load', options); - this.store('load', new Request.HTML(this.retrieve('load:options'))); - } - return this.retrieve('load'); - } - -}; - -Element.implement({ - - load: function(){ - this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type})); - return this; - } - -}); - - -/* ---- - -name: JSON - -description: JSON encoder and decoder. - -license: MIT-style license. - -see: - -requires: [Array, String, Number, Function, Hash] - -provides: JSON - -... -*/ - -var JSON = new Hash(this.JSON && { - stringify: JSON.stringify, - parse: JSON.parse -}).extend({ - - $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}, - - $replaceChars: function(chr){ - return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16); - }, - - encode: function(obj){ - switch ($type(obj)){ - case 'string': - return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; - case 'array': - return '[' + String(obj.map(JSON.encode).clean()) + ']'; - case 'object': case 'hash': - var string = []; - Hash.each(obj, function(value, key){ - var json = JSON.encode(value); - if (json) string.push(JSON.encode(key) + ':' + json); - }); - return '{' + string + '}'; - case 'number': case 'boolean': return String(obj); - case false: return 'null'; - } - return null; - }, - - decode: function(string, secure){ - if ($type(string) != 'string' || !string.length) return null; - if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null; - return eval('(' + string + ')'); - } - -}); - - -/* ---- - -name: Request.JSON - -description: Extends the basic Request Class with additional methods for sending and receiving JSON data. - -license: MIT-style license. - -requires: [Request, JSON] - -provides: [Request.JSON] - -... -*/ - -Request.JSON = new Class({ - - Extends: Request, - - options: { - secure: true - }, - - initialize: function(options){ - this.parent(options); - this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'}); - }, - - success: function(text){ - this.response.json = JSON.decode(text, this.options.secure); - this.onSuccess(this.response.json, text); - } - -}); - - -/* ---- - -name: Cookie - -description: Class for creating, reading, and deleting browser Cookies. - -license: MIT-style license. - -credits: Based on the functions by Peter-Paul Koch (http://quirksmode.org). - -requires: Options - -provides: Cookie - -... -*/ - -var Cookie = new Class({ - - Implements: Options, - - options: { - path: false, - domain: false, - duration: false, - secure: false, - document: document - }, - - initialize: function(key, options){ - this.key = key; - this.setOptions(options); - }, - - write: function(value){ - value = encodeURIComponent(value); - if (this.options.domain) value += '; domain=' + this.options.domain; - if (this.options.path) value += '; path=' + this.options.path; - if (this.options.duration){ - var date = new Date(); - date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); - value += '; expires=' + date.toGMTString(); - } - if (this.options.secure) value += '; secure'; - this.options.document.cookie = this.key + '=' + value; - return this; - }, - - read: function(){ - var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); - return (value) ? decodeURIComponent(value[1]) : null; - }, - - dispose: function(){ - new Cookie(this.key, $merge(this.options, {duration: -1})).write(''); - return this; - } - -}); - -Cookie.write = function(key, value, options){ - return new Cookie(key, options).write(value); -}; - -Cookie.read = function(key){ - return new Cookie(key).read(); -}; - -Cookie.dispose = function(key, options){ - return new Cookie(key, options).dispose(); -}; - - -/* ---- - -name: DomReady - -description: Contains the custom event domready. - -license: MIT-style license. - -requires: Element.Event - -provides: DomReady - -... -*/ - -Element.Events.domready = { - - onAdd: function(fn){ - if (Browser.loaded) fn.call(this); - } - -}; - -(function(){ - - var domready = function(){ - if (Browser.loaded) return; - Browser.loaded = true; - window.fireEvent('domready'); - document.fireEvent('domready'); - }; - - window.addEvent('load', domready); - - if (Browser.Engine.trident){ - var temp = document.createElement('div'); - (function(){ - ($try(function(){ - temp.doScroll(); // Technique by Diego Perini - return document.id(temp).inject(document.body).set('html', 'temp').dispose(); - })) ? domready() : arguments.callee.delay(50); - })(); - } else if (Browser.Engine.webkit && Browser.Engine.version < 525){ - (function(){ - (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); - })(); - } else { - document.addEvent('DOMContentLoaded', domready); - } - -})(); - - -/* ---- - -name: Selectors - -description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors. - -license: MIT-style license. - -requires: Element - -provides: Selectors - -... -*/ - -Native.implement([Document, Element], { - - getElements: function(expression, nocash){ - expression = expression.split(','); - var items, local = {}; - for (var i = 0, l = expression.length; i < l; i++){ - var selector = expression[i], elements = Selectors.Utils.search(this, selector, local); - if (i != 0 && elements.item) elements = $A(elements); - items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements); - } - return new Elements(items, {ddup: (expression.length > 1), cash: !nocash}); - } - -}); - -Element.implement({ - - match: function(selector){ - if (!selector || (selector == this)) return true; - var tagid = Selectors.Utils.parseTagAndID(selector); - var tag = tagid[0], id = tagid[1]; - if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false; - var parsed = Selectors.Utils.parseSelector(selector); - return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true; - } - -}); - -var Selectors = {Cache: {nth: {}, parsed: {}}}; - -Selectors.RegExps = { - id: (/#([\w-]+)/), - tag: (/^(\w+|\*)/), - quick: (/^(\w+|\*)$/), - splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g), - combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g) -}; - -Selectors.Utils = { - - chk: function(item, uniques){ - if (!uniques) return true; - var uid = $uid(item); - if (!uniques[uid]) return uniques[uid] = true; - return false; - }, - - parseNthArgument: function(argument){ - if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument]; - var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/); - if (!parsed) return false; - var inta = parseInt(parsed[1], 10); - var a = (inta || inta === 0) ? inta : 1; - var special = parsed[2] || false; - var b = parseInt(parsed[3], 10) || 0; - if (a != 0){ - b--; - while (b < 1) b += a; - while (b >= a) b -= a; - } else { - a = b; - special = 'index'; - } - switch (special){ - case 'n': parsed = {a: a, b: b, special: 'n'}; break; - case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break; - case 'even': parsed = {a: 2, b: 1, special: 'n'}; break; - case 'first': parsed = {a: 0, special: 'index'}; break; - case 'last': parsed = {special: 'last-child'}; break; - case 'only': parsed = {special: 'only-child'}; break; - default: parsed = {a: (a - 1), special: 'index'}; - } - - return Selectors.Cache.nth[argument] = parsed; - }, - - parseSelector: function(selector){ - if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector]; - var m, parsed = {classes: [], pseudos: [], attributes: []}; - while ((m = Selectors.RegExps.combined.exec(selector))){ - var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7]; - if (cn){ - parsed.classes.push(cn); - } else if (pn){ - var parser = Selectors.Pseudo.get(pn); - if (parser) parsed.pseudos.push({parser: parser, argument: pa}); - else parsed.attributes.push({name: pn, operator: '=', value: pa}); - } else if (an){ - parsed.attributes.push({name: an, operator: ao, value: av}); - } - } - if (!parsed.classes.length) delete parsed.classes; - if (!parsed.attributes.length) delete parsed.attributes; - if (!parsed.pseudos.length) delete parsed.pseudos; - if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null; - return Selectors.Cache.parsed[selector] = parsed; - }, - - parseTagAndID: function(selector){ - var tag = selector.match(Selectors.RegExps.tag); - var id = selector.match(Selectors.RegExps.id); - return [(tag) ? tag[1] : '*', (id) ? id[1] : false]; - }, - - filter: function(item, parsed, local){ - var i; - if (parsed.classes){ - for (i = parsed.classes.length; i--; i){ - var cn = parsed.classes[i]; - if (!Selectors.Filters.byClass(item, cn)) return false; - } - } - if (parsed.attributes){ - for (i = parsed.attributes.length; i--; i){ - var att = parsed.attributes[i]; - if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false; - } - } - if (parsed.pseudos){ - for (i = parsed.pseudos.length; i--; i){ - var psd = parsed.pseudos[i]; - if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false; - } - } - return true; - }, - - getByTagAndID: function(ctx, tag, id){ - if (id){ - var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true); - return (item && Selectors.Filters.byTag(item, tag)) ? [item] : []; - } else { - return ctx.getElementsByTagName(tag); - } - }, - - search: function(self, expression, local){ - var splitters = []; - - var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){ - splitters.push(m1); - return ':)' + m2; - }).split(':)'); - - var items, filtered, item; - - for (var i = 0, l = selectors.length; i < l; i++){ - - var selector = selectors[i]; - - if (i == 0 && Selectors.RegExps.quick.test(selector)){ - items = self.getElementsByTagName(selector); - continue; - } - - var splitter = splitters[i - 1]; - - var tagid = Selectors.Utils.parseTagAndID(selector); - var tag = tagid[0], id = tagid[1]; - - if (i == 0){ - items = Selectors.Utils.getByTagAndID(self, tag, id); - } else { - var uniques = {}, found = []; - for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques); - items = found; - } - - var parsed = Selectors.Utils.parseSelector(selector); - - if (parsed){ - filtered = []; - for (var m = 0, n = items.length; m < n; m++){ - item = items[m]; - if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item); - } - items = filtered; - } - - } - - return items; - - } - -}; - -Selectors.Getters = { - - ' ': function(found, self, tag, id, uniques){ - var items = Selectors.Utils.getByTagAndID(self, tag, id); - for (var i = 0, l = items.length; i < l; i++){ - var item = items[i]; - if (Selectors.Utils.chk(item, uniques)) found.push(item); - } - return found; - }, - - '>': function(found, self, tag, id, uniques){ - var children = Selectors.Utils.getByTagAndID(self, tag, id); - for (var i = 0, l = children.length; i < l; i++){ - var child = children[i]; - if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child); - } - return found; - }, - - '+': function(found, self, tag, id, uniques){ - while ((self = self.nextSibling)){ - if (self.nodeType == 1){ - if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); - break; - } - } - return found; - }, - - '~': function(found, self, tag, id, uniques){ - while ((self = self.nextSibling)){ - if (self.nodeType == 1){ - if (!Selectors.Utils.chk(self, uniques)) break; - if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); - } - } - return found; - } - -}; - -Selectors.Filters = { - - byTag: function(self, tag){ - return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag)); - }, - - byID: function(self, id){ - return (!id || (self.id && self.id == id)); - }, - - byClass: function(self, klass){ - return (self.className && self.className.contains && self.className.contains(klass, ' ')); - }, - - byPseudo: function(self, parser, argument, local){ - return parser.call(self, argument, local); - }, - - byAttribute: function(self, name, operator, value){ - var result = Element.prototype.getProperty.call(self, name); - if (!result) return (operator == '!='); - if (!operator || value == undefined) return true; - switch (operator){ - case '=': return (result == value); - case '*=': return (result.contains(value)); - case '^=': return (result.substr(0, value.length) == value); - case '$=': return (result.substr(result.length - value.length) == value); - case '!=': return (result != value); - case '~=': return result.contains(value, ' '); - case '|=': return result.contains(value, '-'); - } - return false; - } - -}; - -Selectors.Pseudo = new Hash({ - - // w3c pseudo selectors - - checked: function(){ - return this.checked; - }, - - empty: function(){ - return !(this.innerText || this.textContent || '').length; - }, - - not: function(selector){ - return !Element.match(this, selector); - }, - - contains: function(text){ - return (this.innerText || this.textContent || '').contains(text); - }, - - 'first-child': function(){ - return Selectors.Pseudo.index.call(this, 0); - }, - - 'last-child': function(){ - var element = this; - while ((element = element.nextSibling)){ - if (element.nodeType == 1) return false; - } - return true; - }, - - 'only-child': function(){ - var prev = this; - while ((prev = prev.previousSibling)){ - if (prev.nodeType == 1) return false; - } - var next = this; - while ((next = next.nextSibling)){ - if (next.nodeType == 1) return false; - } - return true; - }, - - 'nth-child': function(argument, local){ - argument = (argument == undefined) ? 'n' : argument; - var parsed = Selectors.Utils.parseNthArgument(argument); - if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local); - var count = 0; - local.positions = local.positions || {}; - var uid = $uid(this); - if (!local.positions[uid]){ - var self = this; - while ((self = self.previousSibling)){ - if (self.nodeType != 1) continue; - count ++; - var position = local.positions[$uid(self)]; - if (position != undefined){ - count = position + count; - break; - } - } - local.positions[uid] = count; - } - return (local.positions[uid] % parsed.a == parsed.b); - }, - - // custom pseudo selectors - - index: function(index){ - var element = this, count = 0; - while ((element = element.previousSibling)){ - if (element.nodeType == 1 && ++count > index) return false; - } - return (count == index); - }, - - even: function(argument, local){ - return Selectors.Pseudo['nth-child'].call(this, '2n+1', local); - }, - - odd: function(argument, local){ - return Selectors.Pseudo['nth-child'].call(this, '2n', local); - }, - - selected: function(){ - return this.selected; - }, - - enabled: function(){ - return (this.disabled === false); - } - -}); - - -/* ---- - -name: Swiff - -description: Wrapper for embedding SWF movies. Supports External Interface Communication. - -license: MIT-style license. - -credits: Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. - -requires: [Options, $util] - -provides: Swiff - -... -*/ - -var Swiff = new Class({ - - Implements: [Options], - - options: { - id: null, - height: 1, - width: 1, - container: null, - properties: {}, - params: { - quality: 'high', - allowScriptAccess: 'always', - wMode: 'transparent', - swLiveConnect: true - }, - callBacks: {}, - vars: {} - }, - - toElement: function(){ - return this.object; - }, - - initialize: function(path, options){ - this.instance = 'Swiff_' + $time(); - - this.setOptions(options); - options = this.options; - var id = this.id = options.id || this.instance; - var container = document.id(options.container); - - Swiff.CallBacks[this.instance] = {}; - - var params = options.params, vars = options.vars, callBacks = options.callBacks; - var properties = $extend({height: options.height, width: options.width}, options.properties); - - var self = this; - - for (var callBack in callBacks){ - Swiff.CallBacks[this.instance][callBack] = (function(option){ - return function(){ - return option.apply(self.object, arguments); - }; - })(callBacks[callBack]); - vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; - } - - params.flashVars = Hash.toQueryString(vars); - if (Browser.Engine.trident){ - properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; - params.movie = path; - } else { - properties.type = 'application/x-shockwave-flash'; - properties.data = path; - } - var build = ''; - } - build += ''; - this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; - }, - - replaces: function(element){ - element = document.id(element, true); - element.parentNode.replaceChild(this.toElement(), element); - return this; - }, - - inject: function(element){ - document.id(element, true).appendChild(this.toElement()); - return this; - }, - - remote: function(){ - return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments)); - } - -}); - -Swiff.CallBacks = {}; - -Swiff.remote = function(obj, fn){ - var rs = obj.CallFunction('' + __flash__argumentsToXML(arguments, 2) + ''); - return eval(rs); -}; - diff --git a/web/tools/mootools/mootools-1.2.5-core-yc.js b/web/tools/mootools/mootools-1.2.5-core-yc.js deleted file mode 100644 index 21ef4f027..000000000 --- a/web/tools/mootools/mootools-1.2.5-core-yc.js +++ /dev/null @@ -1,3 +0,0 @@ -//MooTools, , My Object Oriented (JavaScript) Tools. Copyright (c) 2006-2009 Valerio Proietti, , MIT Style License. - -var MooTools={version:"1.2.5",build:"008d8f0f2fcc2044e54fdd3635341aaab274e757"};var Native=function(l){l=l||{};var a=l.name;var j=l.legacy;var b=l.protect;var c=l.implement;var i=l.generics;var g=l.initialize;var h=l.afterImplement||function(){};var d=g||j;i=i!==false;d.constructor=Native;d.$family={name:"native"};if(j&&g){d.prototype=j.prototype;}d.prototype.constructor=d;if(a){var f=a.toLowerCase();d.prototype.$family={name:f};Native.typize(d,f);}var k=function(o,m,p,n){if(!b||n||!o.prototype[m]){o.prototype[m]=p;}if(i){Native.genericize(o,m,b);}h.call(o,m,p);return o;};d.alias=function(o,m,q){if(typeof o=="string"){var p=this.prototype[o];if((o=p)){return k(this,m,o,q);}}for(var n in o){this.alias(n,o[n],m);}return this;};d.implement=function(n,m,q){if(typeof n=="string"){return k(this,n,m,q);}for(var o in n){k(this,o,n[o],m);}return this;};if(c){d.implement(c);}return d;};Native.genericize=function(b,c,a){if((!a||!b[c])&&typeof b.prototype[c]=="function"){b[c]=function(){var d=Array.prototype.slice.call(arguments);return b.prototype[c].apply(d.shift(),d);};}};Native.implement=function(d,c){for(var b=0,a=d.length;b-1:this.indexOf(a)>-1;},trim:function(){return this.replace(/^\s+|\s+$/g,"");},clean:function(){return this.replace(/\s+/g," ").trim();},camelCase:function(){return this.replace(/-\D/g,function(a){return a.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/[A-Z]/g,function(a){return("-"+a.charAt(0).toLowerCase());});},capitalize:function(){return this.replace(/\b[a-z]/g,function(a){return a.toUpperCase();});},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1");},toInt:function(a){return parseInt(this,a||10);},toFloat:function(){return parseFloat(this);},hexToRgb:function(b){var a=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);return(a)?a.slice(1).hexToRgb(b):null;},rgbToHex:function(b){var a=this.match(/\d{1,3}/g);return(a)?a.rgbToHex(b):null;},stripScripts:function(b){var a="";var c=this.replace(/]*>([\s\S]*?)<\/script>/gi,function(){a+=arguments[1]+"\n";return"";});if(b===true){$exec(a);}else{if($type(b)=="function"){b(a,c);}}return c;},substitute:function(a,b){return this.replace(b||(/\\?\{([^{}]+)\}/g),function(d,c){if(d.charAt(0)=="\\"){return d.slice(1);}return(a[c]!=undefined)?a[c]:"";});}});try{delete Function.prototype.bind;}catch(e){}Function.implement({extend:function(a){for(var b in a){this[b]=a[b];}return this;},create:function(b){var a=this;b=b||{};return function(d){var c=b.arguments;c=(c!=undefined)?$splat(c):Array.slice(arguments,(b.event)?1:0);if(b.event){c=[d||window.event].extend(c);}var f=function(){return a.apply(b.bind||null,c);};if(b.delay){return setTimeout(f,b.delay);}if(b.periodical){return setInterval(f,b.periodical);}if(b.attempt){return $try(f);}return f();};},run:function(a,b){return this.apply(b,$splat(a));},pass:function(a,b){return this.create({bind:b,arguments:a});},bind:function(b,a){return this.create({bind:b,arguments:a});},bindWithEvent:function(b,a){return this.create({bind:b,arguments:a,event:true});},attempt:function(a,b){return this.create({bind:b,arguments:a,attempt:true})();},delay:function(b,c,a){return this.create({bind:c,arguments:a,delay:b})();},periodical:function(c,b,a){return this.create({bind:b,arguments:a,periodical:c})();}});Number.implement({limit:function(b,a){return Math.min(a,Math.max(b,this));},round:function(a){a=Math.pow(10,a||0);return Math.round(this*a)/a;},times:function(b,c){for(var a=0;a");d=(a.name=="x");}catch(b){}var c=function(f){return(""+f).replace(/&/g,"&").replace(/"/g,""");};Document.implement({newElement:function(f,g){if(g&&g.checked!=null){g.defaultChecked=g.checked;}if(d&&g){f="<"+f;if(g.name){f+=' name="'+c(g.name)+'"';}if(g.type){f+=' type="'+c(g.type)+'"';}f+=">";delete g.name;delete g.type;}return this.id(this.createElement(f)).set(g);},newTextNode:function(f){return this.createTextNode(f);},getDocument:function(){return this;},getWindow:function(){return this.window;},id:(function(){var f={string:function(i,h,g){i=g.getElementById(i);return(i)?f.element(i,h):null;},element:function(g,j){$uid(g);if(!j&&!g.$family&&!(/^object|embed$/i).test(g.tagName)){var h=Element.Prototype;for(var i in h){g[i]=h[i];}}return g;},object:function(h,i,g){if(h.toElement){return f.element(h.toElement(g),i);}return null;}};f.textnode=f.whitespace=f.window=f.document=$arguments(0);return function(h,j,i){if(h&&h.$family&&h.uid){return h;}var g=$type(h);return(f[g])?f[g](h,j,i||document):null;};})()});})();if(window.$==null){Window.implement({$:function(a,b){return document.id(a,b,this.document);}});}Window.implement({$$:function(a){if(arguments.length==1&&typeof a=="string"){return this.document.getElements(a);}var g=[];var c=Array.flatten(arguments);for(var d=0,b=c.length;d1);a.each(function(f){var g=this.getElementsByTagName(f.trim());(b)?c.extend(g):c=g;},this);return new Elements(c,{ddup:b,cash:!d});}});(function(){var i={},g={};var j={input:"checked",option:"selected",textarea:(Browser.Engine.webkit&&Browser.Engine.version<420)?"innerHTML":"value"};var c=function(m){return(g[m]||(g[m]={}));};var h=function(o,m){if(!o){return;}var n=o.uid;if(m!==true){m=false;}if(Browser.Engine.trident){if(o.clearAttributes){var r=m&&o.cloneNode(false);o.clearAttributes();if(r){o.mergeAttributes(r);}}else{if(o.removeEvents){o.removeEvents();}}if((/object/i).test(o.tagName)){for(var q in o){if(typeof o[q]=="function"){o[q]=$empty;}}Element.dispose(o);}}if(!n){return;}i[n]=g[n]=null;};var d=function(){Hash.each(i,h);if(Browser.Engine.trident){$A(document.getElementsByTagName("object")).each(h);}if(window.CollectGarbage){CollectGarbage();}i=g=null;};var k=function(o,m,t,n,q,s){var p=o[t||m];var r=[];while(p){if(p.nodeType==1&&(!n||Element.match(p,n))){if(!q){return document.id(p,s);}r.push(p);}p=p[m];}return(q)?new Elements(r,{ddup:false,cash:!s}):null;};var f={html:"innerHTML","class":"className","for":"htmlFor",defaultValue:"defaultValue",text:(Browser.Engine.trident||(Browser.Engine.webkit&&Browser.Engine.version<420))?"innerText":"textContent"};var b=["compact","nowrap","ismap","declare","noshade","checked","disabled","readonly","multiple","selected","noresize","defer"];var l=["value","type","defaultValue","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","maxLength","readOnly","rowSpan","tabIndex","useMap"];b=b.associate(b);Hash.extend(f,b);Hash.extend(f,l.associate(l.map(String.toLowerCase)));var a={before:function(n,m){if(m.parentNode){m.parentNode.insertBefore(n,m);}},after:function(n,m){if(!m.parentNode){return;}var o=m.nextSibling;(o)?m.parentNode.insertBefore(n,o):m.parentNode.appendChild(n);},bottom:function(n,m){m.appendChild(n);},top:function(n,m){var o=m.firstChild;(o)?m.insertBefore(n,o):m.appendChild(n);}};a.inside=a.bottom;Hash.each(a,function(m,n){n=n.capitalize();Element.implement("inject"+n,function(o){m(this,document.id(o,true));return this;});Element.implement("grab"+n,function(o){m(document.id(o,true),this);return this;});});Element.implement({set:function(q,n){switch($type(q)){case"object":for(var o in q){this.set(o,q[o]);}break;case"string":var m=Element.Properties.get(q);(m&&m.set)?m.set.apply(this,Array.slice(arguments,1)):this.setProperty(q,n);}return this;},get:function(n){var m=Element.Properties.get(n);return(m&&m.get)?m.get.apply(this,Array.slice(arguments,1)):this.getProperty(n);},erase:function(n){var m=Element.Properties.get(n);(m&&m.erase)?m.erase.apply(this):this.removeProperty(n);return this;},setProperty:function(n,o){var m=f[n];if(o==undefined){return this.removeProperty(n);}if(m&&b[n]){o=!!o;}(m)?this[m]=o:this.setAttribute(n,""+o);return this;},setProperties:function(m){for(var n in m){this.setProperty(n,m[n]);}return this;},getProperty:function(n){var m=f[n];var o=(m)?this[m]:this.getAttribute(n,2);return(b[n])?!!o:(m)?o:o||null;},getProperties:function(){var m=$A(arguments);return m.map(this.getProperty,this).associate(m);},removeProperty:function(n){var m=f[n];(m)?this[m]=(m&&b[n])?false:"":this.removeAttribute(n);return this;},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this;},hasClass:function(m){return this.className.contains(m," ");},addClass:function(m){if(!this.hasClass(m)){this.className=(this.className+" "+m).clean();}return this;},removeClass:function(m){this.className=this.className.replace(new RegExp("(^|\\s)"+m+"(?:\\s|$)"),"$1");return this;},toggleClass:function(m){return this.hasClass(m)?this.removeClass(m):this.addClass(m);},adopt:function(){Array.flatten(arguments).each(function(m){m=document.id(m,true);if(m){this.appendChild(m);}},this);return this;},appendText:function(n,m){return this.grab(this.getDocument().newTextNode(n),m);},grab:function(n,m){a[m||"bottom"](document.id(n,true),this);return this;},inject:function(n,m){a[m||"bottom"](this,document.id(n,true));return this;},replaces:function(m){m=document.id(m,true);m.parentNode.replaceChild(this,m);return this;},wraps:function(n,m){n=document.id(n,true);return this.replaces(n).grab(n,m);},getPrevious:function(m,n){return k(this,"previousSibling",null,m,false,n);},getAllPrevious:function(m,n){return k(this,"previousSibling",null,m,true,n);},getNext:function(m,n){return k(this,"nextSibling",null,m,false,n);},getAllNext:function(m,n){return k(this,"nextSibling",null,m,true,n);},getFirst:function(m,n){return k(this,"nextSibling","firstChild",m,false,n);},getLast:function(m,n){return k(this,"previousSibling","lastChild",m,false,n);},getParent:function(m,n){return k(this,"parentNode",null,m,false,n);},getParents:function(m,n){return k(this,"parentNode",null,m,true,n);},getSiblings:function(m,n){return this.getParent().getChildren(m,n).erase(this);},getChildren:function(m,n){return k(this,"nextSibling","firstChild",m,true,n);},getWindow:function(){return this.ownerDocument.window;},getDocument:function(){return this.ownerDocument;},getElementById:function(p,o){var n=this.ownerDocument.getElementById(p);if(!n){return null;}for(var m=n.parentNode;m!=this;m=m.parentNode){if(!m){return null;}}return document.id(n,o);},getSelected:function(){return new Elements($A(this.options).filter(function(m){return m.selected;}));},getComputedStyle:function(n){if(this.currentStyle){return this.currentStyle[n.camelCase()];}var m=this.getDocument().defaultView.getComputedStyle(this,null);return(m)?m.getPropertyValue([n.hyphenate()]):null;},toQueryString:function(){var m=[];this.getElements("input, select, textarea",true).each(function(n){if(!n.name||n.disabled||n.type=="submit"||n.type=="reset"||n.type=="file"){return;}var o=(n.tagName.toLowerCase()=="select")?Element.getSelected(n).map(function(p){return p.value;}):((n.type=="radio"||n.type=="checkbox")&&!n.checked)?null:n.value;$splat(o).each(function(p){if(typeof p!="undefined"){m.push(n.name+"="+encodeURIComponent(p));}});});return m.join("&");},clone:function(p,m){p=p!==false;var s=this.cloneNode(p);var o=function(w,v){if(!m){w.removeAttribute("id");}if(Browser.Engine.trident){w.clearAttributes();w.mergeAttributes(v);w.removeAttribute("uid");if(w.options){var x=w.options,t=v.options;for(var u=x.length;u--;){x[u].selected=t[u].selected;}}}var y=j[v.tagName.toLowerCase()];if(y&&v[y]){w[y]=v[y];}};if(p){var q=s.getElementsByTagName("*"),r=this.getElementsByTagName("*");for(var n=q.length;n--;){o(q[n],r[n]);}}o(s,this);return document.id(s);},destroy:function(){Element.empty(this);Element.dispose(this);h(this,true);return null;},empty:function(){$A(this.childNodes).each(function(m){Element.destroy(m);});return this;},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this;},hasChild:function(m){m=document.id(m,true);if(!m){return false;}if(Browser.Engine.webkit&&Browser.Engine.version<420){return $A(this.getElementsByTagName(m.tagName)).contains(m);}return(this.contains)?(this!=m&&this.contains(m)):!!(this.compareDocumentPosition(m)&16);},match:function(m){return(!m||(m==this)||(Element.get(this,"tag")==m));}});Native.implement([Element,Window,Document],{addListener:function(p,o){if(p=="unload"){var m=o,n=this;o=function(){n.removeListener("unload",o);m();};}else{i[this.uid]=this;}if(this.addEventListener){this.addEventListener(p,o,false);}else{this.attachEvent("on"+p,o);}return this;},removeListener:function(n,m){if(this.removeEventListener){this.removeEventListener(n,m,false);}else{this.detachEvent("on"+n,m);}return this;},retrieve:function(n,m){var p=c(this.uid),o=p[n];if(m!=undefined&&o==undefined){o=p[n]=m;}return $pick(o);},store:function(n,m){var o=c(this.uid);o[n]=m;return this;},eliminate:function(m){var n=c(this.uid);delete n[m];return this;}});window.addListener("unload",d);})();Element.Properties=new Hash;Element.Properties.style={set:function(a){this.style.cssText=a;},get:function(){return this.style.cssText;},erase:function(){this.style.cssText="";}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase();}};Element.Properties.html=(function(){var c=document.createElement("div");var a={table:[1,"","
"],select:[1,""],tbody:[2,"","
"],tr:[3,"","
"]};a.thead=a.tfoot=a.tbody;var b={set:function(){var f=Array.flatten(arguments).join("");var g=Browser.Engine.trident&&a[this.get("tag")];if(g){var h=c;h.innerHTML=g[1]+f+g[2];for(var d=g[0];d--;){h=h.firstChild;}this.empty().adopt(h.childNodes);}else{this.innerHTML=f;}}};b.erase=b.set;return b;})();if(Browser.Engine.webkit&&Browser.Engine.version<420){Element.Properties.text={get:function(){if(this.innerText){return this.innerText;}var a=this.ownerDocument.newElement("div",{html:this.innerHTML}).inject(this.ownerDocument.body);var b=a.innerText;a.destroy();return b;}};}(function(){Element.implement({scrollTo:function(i,j){if(b(this)){this.getWindow().scrollTo(i,j);}else{this.scrollLeft=i;this.scrollTop=j;}return this;},getSize:function(){if(b(this)){return this.getWindow().getSize();}return{x:this.offsetWidth,y:this.offsetHeight};},getScrollSize:function(){if(b(this)){return this.getWindow().getScrollSize();}return{x:this.scrollWidth,y:this.scrollHeight};},getScroll:function(){if(b(this)){return this.getWindow().getScroll();}return{x:this.scrollLeft,y:this.scrollTop};},getScrolls:function(){var j=this,i={x:0,y:0};while(j&&!b(j)){i.x+=j.scrollLeft;i.y+=j.scrollTop;j=j.parentNode;}return i;},getOffsetParent:function(){var i=this;if(b(i)){return null;}if(!Browser.Engine.trident){return i.offsetParent;}while((i=i.parentNode)&&!b(i)){if(d(i,"position")!="static"){return i;}}return null;},getOffsets:function(){if(this.getBoundingClientRect){var k=this.getBoundingClientRect(),n=document.id(this.getDocument().documentElement),q=n.getScroll(),l=this.getScrolls(),j=this.getScroll(),i=(d(this,"position")=="fixed");return{x:k.left.toInt()+l.x-j.x+((i)?0:q.x)-n.clientLeft,y:k.top.toInt()+l.y-j.y+((i)?0:q.y)-n.clientTop};}var m=this,o={x:0,y:0};if(b(this)){return o;}while(m&&!b(m)){o.x+=m.offsetLeft;o.y+=m.offsetTop;if(Browser.Engine.gecko){if(!g(m)){o.x+=c(m);o.y+=h(m);}var p=m.parentNode;if(p&&d(p,"overflow")!="visible"){o.x+=c(p);o.y+=h(p);}}else{if(m!=this&&Browser.Engine.webkit){o.x+=c(m);o.y+=h(m);}}m=m.offsetParent;}if(Browser.Engine.gecko&&!g(this)){o.x-=c(this);o.y-=h(this);}return o;},getPosition:function(l){if(b(this)){return{x:0,y:0};}var m=this.getOffsets(),j=this.getScrolls();var i={x:m.x-j.x,y:m.y-j.y};var k=(l&&(l=document.id(l)))?l.getPosition():{x:0,y:0};return{x:i.x-k.x,y:i.y-k.y};},getCoordinates:function(k){if(b(this)){return this.getWindow().getCoordinates();}var i=this.getPosition(k),j=this.getSize();var l={left:i.x,top:i.y,width:j.x,height:j.y};l.right=l.left+l.width;l.bottom=l.top+l.height;return l;},computePosition:function(i){return{left:i.x-f(this,"margin-left"),top:i.y-f(this,"margin-top")};},setPosition:function(i){return this.setStyles(this.computePosition(i));}});Native.implement([Document,Window],{getSize:function(){if(Browser.Engine.presto||Browser.Engine.webkit){var j=this.getWindow();return{x:j.innerWidth,y:j.innerHeight};}var i=a(this);return{x:i.clientWidth,y:i.clientHeight};},getScroll:function(){var j=this.getWindow(),i=a(this);return{x:j.pageXOffset||i.scrollLeft,y:j.pageYOffset||i.scrollTop};},getScrollSize:function(){var j=a(this),i=this.getSize();return{x:Math.max(j.scrollWidth,i.x),y:Math.max(j.scrollHeight,i.y)};},getPosition:function(){return{x:0,y:0};},getCoordinates:function(){var i=this.getSize();return{top:0,left:0,bottom:i.y,right:i.x,height:i.y,width:i.x};}});var d=Element.getComputedStyle;function f(i,j){return d(i,j).toInt()||0;}function g(i){return d(i,"-moz-box-sizing")=="border-box";}function h(i){return f(i,"border-top-width");}function c(i){return f(i,"border-left-width");}function b(i){return(/^(?:body|html)$/i).test(i.tagName);}function a(i){var j=i.getDocument();return(!j.compatMode||j.compatMode=="CSS1Compat")?j.html:j.body;}})();Element.alias("setPosition","position");Native.implement([Window,Document,Element],{getHeight:function(){return this.getSize().y;},getWidth:function(){return this.getSize().x;},getScrollTop:function(){return this.getScroll().y;},getScrollLeft:function(){return this.getScroll().x;},getScrollHeight:function(){return this.getScrollSize().y;},getScrollWidth:function(){return this.getScrollSize().x;},getTop:function(){return this.getPosition().y;},getLeft:function(){return this.getPosition().x;}});var Event=new Native({name:"Event",initialize:function(a,g){g=g||window;var l=g.document;a=a||g.event;if(a.$extended){return a;}this.$extended=true;var k=a.type;var h=a.target||a.srcElement;while(h&&h.nodeType==3){h=h.parentNode;}if(k.test(/key/)){var b=a.which||a.keyCode;var n=Event.Keys.keyOf(b);if(k=="keydown"){var d=b-111;if(d>0&&d<13){n="f"+d;}}n=n||String.fromCharCode(b).toLowerCase();}else{if(k.match(/(click|mouse|menu)/i)){l=(!l.compatMode||l.compatMode=="CSS1Compat")?l.html:l.body;var j={x:a.pageX||a.clientX+l.scrollLeft,y:a.pageY||a.clientY+l.scrollTop};var c={x:(a.pageX)?a.pageX-g.pageXOffset:a.clientX,y:(a.pageY)?a.pageY-g.pageYOffset:a.clientY};if(k.match(/DOMMouseScroll|mousewheel/)){var i=(a.wheelDelta)?a.wheelDelta/120:-(a.detail||0)/3;}var f=(a.which==3)||(a.button==2);var m=null;if(k.match(/over|out/)){switch(k){case"mouseover":m=a.relatedTarget||a.fromElement;break;case"mouseout":m=a.relatedTarget||a.toElement;}if(!(function(){while(m&&m.nodeType==3){m=m.parentNode;}return true;}).create({attempt:Browser.Engine.gecko})()){m=false;}}}}return $extend(this,{event:a,type:k,page:j,client:c,rightClick:f,wheel:i,relatedTarget:m,target:h,code:b,key:n,shift:a.shiftKey,control:a.ctrlKey,alt:a.altKey,meta:a.metaKey});}});Event.Keys=new Hash({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46});Event.implement({stop:function(){return this.stopPropagation().preventDefault();},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation();}else{this.event.cancelBubble=true;}return this;},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault();}else{this.event.returnValue=false;}return this;}});Element.Properties.events={set:function(a){this.addEvents(a);}};Native.implement([Element,Window,Document],{addEvent:function(f,h){var i=this.retrieve("events",{});i[f]=i[f]||{keys:[],values:[]};if(i[f].keys.contains(h)){return this;}i[f].keys.push(h);var g=f,a=Element.Events.get(f),c=h,j=this;if(a){if(a.onAdd){a.onAdd.call(this,h);}if(a.condition){c=function(k){if(a.condition.call(this,k)){return h.call(this,k);}return true;};}g=a.base||g;}var d=function(){return h.call(j);};var b=Element.NativeEvents[g];if(b){if(b==2){d=function(k){k=new Event(k,j.getWindow());if(c.call(j,k)===false){k.stop();}};}this.addListener(g,d);}i[f].values.push(d);return this;},removeEvent:function(c,b){var a=this.retrieve("events");if(!a||!a[c]){return this;}var g=a[c].keys.indexOf(b);if(g==-1){return this;}a[c].keys.splice(g,1);var f=a[c].values.splice(g,1)[0];var d=Element.Events.get(c);if(d){if(d.onRemove){d.onRemove.call(this,b);}c=d.base||c;}return(Element.NativeEvents[c])?this.removeListener(c,f):this;},addEvents:function(a){for(var b in a){this.addEvent(b,a[b]);}return this;},removeEvents:function(a){var c;if($type(a)=="object"){for(c in a){this.removeEvent(c,a[c]);}return this;}var b=this.retrieve("events");if(!b){return this;}if(!a){for(c in b){this.removeEvents(c);}this.eliminate("events");}else{if(b[a]){while(b[a].keys[0]){this.removeEvent(a,b[a].keys[0]);}b[a]=null;}}return this;},fireEvent:function(d,b,a){var c=this.retrieve("events");if(!c||!c[d]){return this;}c[d].keys.each(function(f){f.create({bind:this,delay:a,"arguments":b})();},this);return this;},cloneEvents:function(d,a){d=document.id(d);var c=d.retrieve("events");if(!c){return this;}if(!a){for(var b in c){this.cloneEvents(d,b);}}else{if(c[a]){c[a].keys.each(function(f){this.addEvent(a,f);},this);}}return this;}});try{if(typeof HTMLElement!="undefined"){HTMLElement.prototype.fireEvent=Element.prototype.fireEvent;}}catch(e){}Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:1,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1};(function(){var a=function(b){var c=b.relatedTarget;if(c==undefined){return true;}if(c===false){return false;}return($type(this)!="document"&&c!=this&&c.prefix!="xul"&&!this.hasChild(c));};Element.Events=new Hash({mouseenter:{base:"mouseover",condition:a},mouseleave:{base:"mouseout",condition:a},mousewheel:{base:(Browser.Engine.gecko)?"DOMMouseScroll":"mousewheel"}});})();Element.Properties.styles={set:function(a){this.setStyles(a);}};Element.Properties.opacity={set:function(a,b){if(!b){if(a==0){if(this.style.visibility!="hidden"){this.style.visibility="hidden";}}else{if(this.style.visibility!="visible"){this.style.visibility="visible";}}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1;}if(Browser.Engine.trident){this.style.filter=(a==1)?"":"alpha(opacity="+a*100+")";}this.style.opacity=a;this.store("opacity",a);},get:function(){return this.retrieve("opacity",1);}};Element.implement({setOpacity:function(a){return this.set("opacity",a,true);},getOpacity:function(){return this.get("opacity");},setStyle:function(b,a){switch(b){case"opacity":return this.set("opacity",parseFloat(a));case"float":b=(Browser.Engine.trident)?"styleFloat":"cssFloat";}b=b.camelCase();if($type(a)!="string"){var c=(Element.Styles.get(b)||"@").split(" ");a=$splat(a).map(function(f,d){if(!c[d]){return"";}return($type(f)=="number")?c[d].replace("@",Math.round(f)):f;}).join(" ");}else{if(a==String(Number(a))){a=Math.round(a);}}this.style[b]=a;return this;},getStyle:function(h){switch(h){case"opacity":return this.get("opacity");case"float":h=(Browser.Engine.trident)?"styleFloat":"cssFloat";}h=h.camelCase();var a=this.style[h];if(!$chk(a)){a=[];for(var g in Element.ShortStyles){if(h!=g){continue;}for(var f in Element.ShortStyles[g]){a.push(this.getStyle(f));}return a.join(" ");}a=this.getComputedStyle(h);}if(a){a=String(a);var c=a.match(/rgba?\([\d\s,]+\)/);if(c){a=a.replace(c[0],c[0].rgbToHex());}}if(Browser.Engine.presto||(Browser.Engine.trident&&!$chk(parseInt(a,10)))){if(h.test(/^(height|width)$/)){var b=(h=="width")?["left","right"]:["top","bottom"],d=0;b.each(function(i){d+=this.getStyle("border-"+i+"-width").toInt()+this.getStyle("padding-"+i).toInt();},this);return this["offset"+h.capitalize()]-d+"px";}if((Browser.Engine.presto)&&String(a).test("px")){return a;}if(h.test(/(border(.+)Width|margin|padding)/)){return"0px";}}return a;},setStyles:function(b){for(var a in b){this.setStyle(a,b[a]);}return this;},getStyles:function(){var a={};Array.flatten(arguments).each(function(b){a[b]=this.getStyle(b);},this);return a;}});Element.Styles=new Hash({left:"@px",top:"@px",bottom:"@px",right:"@px",width:"@px",height:"@px",maxWidth:"@px",maxHeight:"@px",minWidth:"@px",minHeight:"@px",backgroundColor:"rgb(@, @, @)",backgroundPosition:"@px @px",color:"rgb(@, @, @)",fontSize:"@px",letterSpacing:"@px",lineHeight:"@px",clip:"rect(@px @px @px @px)",margin:"@px @px @px @px",padding:"@px @px @px @px",border:"@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)",borderWidth:"@px @px @px @px",borderStyle:"@ @ @ @",borderColor:"rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)",zIndex:"@",zoom:"@",fontWeight:"@",textIndent:"@px",opacity:"@"});Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};["Top","Right","Bottom","Left"].each(function(h){var g=Element.ShortStyles;var b=Element.Styles;["margin","padding"].each(function(i){var j=i+h;g[i][j]=b[j]="@px";});var f="border"+h;g.border[f]=b[f]="@px @ rgb(@, @, @)";var d=f+"Width",a=f+"Style",c=f+"Color";g[f]={};g.borderWidth[d]=g[f][d]=b[d]="@px";g.borderStyle[a]=g[f][a]=b[a]="@";g.borderColor[c]=g[f][c]=b[c]="rgb(@, @, @)";});var Fx=new Class({Implements:[Chain,Events,Options],options:{fps:50,unit:false,duration:500,link:"ignore"},initialize:function(a){this.subject=this.subject||this;this.setOptions(a);this.options.duration=Fx.Durations[this.options.duration]||this.options.duration.toInt();var b=this.options.wait;if(b===false){this.options.link="cancel";}},getTransition:function(){return function(a){return -(Math.cos(Math.PI*a)-1)/2;};},step:function(){var a=$time();if(a=(7-4*d)/11){f=c*c-Math.pow((11-6*d-11*g)/4,2);break;}}return f;},Elastic:function(b,a){return Math.pow(2,10*--b)*Math.cos(20*b*Math.PI*(a[0]||1)/3);}});["Quad","Cubic","Quart","Quint"].each(function(b,a){Fx.Transitions[b]=new Fx.Transition(function(c){return Math.pow(c,[a+2]);});});Fx.Tween=new Class({Extends:Fx.CSS,initialize:function(b,a){this.element=this.subject=document.id(b);this.parent(a);},set:function(b,a){if(arguments.length==1){a=b;b=this.property||this.options.property;}this.render(this.element,b,a,this.options.unit);return this;},start:function(c,f,d){if(!this.check(c,f,d)){return this;}var b=Array.flatten(arguments);this.property=this.options.property||b.shift();var a=this.prepare(this.element,this.property,b);return this.parent(a.from,a.to);}});Element.Properties.tween={set:function(a){var b=this.retrieve("tween");if(b){b.cancel();}return this.eliminate("tween").store("tween:options",$extend({link:"cancel"},a));},get:function(a){if(a||!this.retrieve("tween")){if(a||!this.retrieve("tween:options")){this.set("tween",a);}this.store("tween",new Fx.Tween(this,this.retrieve("tween:options")));}return this.retrieve("tween");}};Element.implement({tween:function(a,c,b){this.get("tween").start(arguments);return this;},fade:function(c){var f=this.get("tween"),d="opacity",a;c=$pick(c,"toggle");switch(c){case"in":f.start(d,1);break;case"out":f.start(d,0);break;case"show":f.set(d,1);break;case"hide":f.set(d,0);break;case"toggle":var b=this.retrieve("fade:flag",this.get("opacity")==1);f.start(d,(b)?0:1);this.store("fade:flag",!b);a=true;break;default:f.start(d,arguments);}if(!a){this.eliminate("fade:flag");}return this;},highlight:function(c,a){if(!a){a=this.retrieve("highlight:original",this.getStyle("background-color"));a=(a=="transparent")?"#fff":a;}var b=this.get("tween");b.start("background-color",c||"#ffff88",a).chain(function(){this.setStyle("background-color",this.retrieve("highlight:original"));b.callChain();}.bind(this));return this;}});var Request=new Class({Implements:[Chain,Events,Options],options:{url:"",data:"",headers:{"X-Requested-With":"XMLHttpRequest",Accept:"text/javascript, text/html, application/xml, text/xml, */*"},async:true,format:false,method:"post",link:"ignore",isSuccess:null,emulation:true,urlEncoded:true,encoding:"utf-8",evalScripts:false,evalResponse:false,noCache:false},initialize:function(a){this.xhr=new Browser.Request();this.setOptions(a);this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.headers=new Hash(this.options.headers);},onStateChange:function(){if(this.xhr.readyState!=4||!this.running){return;}this.running=false;this.status=0;$try(function(){this.status=this.xhr.status;}.bind(this));this.xhr.onreadystatechange=$empty;if(this.options.isSuccess.call(this,this.status)){this.response={text:this.xhr.responseText,xml:this.xhr.responseXML};this.success(this.response.text,this.response.xml);}else{this.response={text:null,xml:null};this.failure();}},isSuccess:function(){return((this.status>=200)&&(this.status<300));},processScripts:function(a){if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader("Content-type"))){return $exec(a);}return a.stripScripts(this.options.evalScripts);},success:function(b,a){this.onSuccess(this.processScripts(b),a);},onSuccess:function(){this.fireEvent("complete",arguments).fireEvent("success",arguments).callChain();},failure:function(){this.onFailure();},onFailure:function(){this.fireEvent("complete").fireEvent("failure",this.xhr);},setHeader:function(a,b){this.headers.set(a,b);return this;},getHeader:function(a){return $try(function(){return this.xhr.getResponseHeader(a);}.bind(this));},check:function(){if(!this.running){return true;}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(this.caller.bind(this,arguments));return false;}return false;},send:function(l){if(!this.check(l)){return this;}this.running=true;var j=$type(l);if(j=="string"||j=="element"){l={data:l};}var d=this.options;l=$extend({data:d.data,url:d.url,method:d.method},l);var h=l.data,b=String(l.url),a=l.method.toLowerCase();switch($type(h)){case"element":h=document.id(h).toQueryString();break;case"object":case"hash":h=Hash.toQueryString(h);}if(this.options.format){var k="format="+this.options.format;h=(h)?k+"&"+h:k;}if(this.options.emulation&&!["get","post"].contains(a)){var i="_method="+a;h=(h)?i+"&"+h:i;a="post";}if(this.options.urlEncoded&&a=="post"){var c=(this.options.encoding)?"; charset="+this.options.encoding:"";this.headers.set("Content-type","application/x-www-form-urlencoded"+c);}if(this.options.noCache){var g="noCache="+new Date().getTime();h=(h)?g+"&"+h:g;}var f=b.lastIndexOf("/");if(f>-1&&(f=b.indexOf("#"))>-1){b=b.substr(0,f);}if(h&&a=="get"){b=b+(b.contains("?")?"&":"?")+h;h=null;}this.xhr.open(a.toUpperCase(),b,this.options.async);this.xhr.onreadystatechange=this.onStateChange.bind(this);this.headers.each(function(n,m){try{this.xhr.setRequestHeader(m,n);}catch(o){this.fireEvent("exception",[m,n]);}},this);this.fireEvent("request");this.xhr.send(h);if(!this.options.async){this.onStateChange();}return this;},cancel:function(){if(!this.running){return this;}this.running=false;this.xhr.abort();this.xhr.onreadystatechange=$empty;this.xhr=new Browser.Request();this.fireEvent("cancel");return this;}});(function(){var a={};["get","post","put","delete","GET","POST","PUT","DELETE"].each(function(b){a[b]=function(){var c=Array.link(arguments,{url:String.type,data:$defined});return this.send($extend(c,{method:b}));};});Request.implement(a);})();Element.Properties.send={set:function(a){var b=this.retrieve("send");if(b){b.cancel();}return this.eliminate("send").store("send:options",$extend({data:this,link:"cancel",method:this.get("method")||"post",url:this.get("action")},a));},get:function(a){if(a||!this.retrieve("send")){if(a||!this.retrieve("send:options")){this.set("send",a);}this.store("send",new Request(this.retrieve("send:options")));}return this.retrieve("send");}};Element.implement({send:function(a){var b=this.get("send");b.send({data:this,url:a||b.options.url});return this;}});Request.HTML=new Class({Extends:Request,options:{update:false,append:false,evalScripts:true,filter:false},processHTML:function(c){var b=c.match(/]*>([\s\S]*?)<\/body>/i);c=(b)?b[1]:c;var a=new Element("div");return $try(function(){var d=""+c+"",h;if(Browser.Engine.trident){h=new ActiveXObject("Microsoft.XMLDOM");h.async=false;h.loadXML(d);}else{h=new DOMParser().parseFromString(d,"text/xml");}d=h.getElementsByTagName("root")[0];if(!d){return null;}for(var g=0,f=d.childNodes.length;g1),cash:!h});}});Element.implement({match:function(b){if(!b||(b==this)){return true;}var d=Selectors.Utils.parseTagAndID(b);var a=d[0],f=d[1];if(!Selectors.Filters.byID(this,f)||!Selectors.Filters.byTag(this,a)){return false;}var c=Selectors.Utils.parseSelector(b);return(c)?Selectors.Utils.filter(this,c,{}):true;}});var Selectors={Cache:{nth:{},parsed:{}}};Selectors.RegExps={id:(/#([\w-]+)/),tag:(/^(\w+|\*)/),quick:(/^(\w+|\*)$/),splitter:(/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),combined:(/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)};Selectors.Utils={chk:function(b,c){if(!c){return true;}var a=$uid(b);if(!c[a]){return c[a]=true;}return false;},parseNthArgument:function(i){if(Selectors.Cache.nth[i]){return Selectors.Cache.nth[i];}var f=i.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);if(!f){return false;}var h=parseInt(f[1],10);var d=(h||h===0)?h:1;var g=f[2]||false;var c=parseInt(f[3],10)||0;if(d!=0){c--;while(c<1){c+=d;}while(c>=d){c-=d;}}else{d=c;g="index";}switch(g){case"n":f={a:d,b:c,special:"n"};break;case"odd":f={a:2,b:0,special:"n"};break;case"even":f={a:2,b:1,special:"n"};break;case"first":f={a:0,special:"index"};break;case"last":f={special:"last-child"};break;case"only":f={special:"only-child"};break;default:f={a:(d-1),special:"index"};}return Selectors.Cache.nth[i]=f;},parseSelector:function(f){if(Selectors.Cache.parsed[f]){return Selectors.Cache.parsed[f];}var d,i={classes:[],pseudos:[],attributes:[]};while((d=Selectors.RegExps.combined.exec(f))){var j=d[1],h=d[2],g=d[3],b=d[5],c=d[6],k=d[7];if(j){i.classes.push(j);}else{if(c){var a=Selectors.Pseudo.get(c);if(a){i.pseudos.push({parser:a,argument:k});}else{i.attributes.push({name:c,operator:"=",value:k});}}else{if(h){i.attributes.push({name:h,operator:g,value:b});}}}}if(!i.classes.length){delete i.classes;}if(!i.attributes.length){delete i.attributes;}if(!i.pseudos.length){delete i.pseudos;}if(!i.classes&&!i.attributes&&!i.pseudos){i=null;}return Selectors.Cache.parsed[f]=i;},parseTagAndID:function(b){var a=b.match(Selectors.RegExps.tag);var c=b.match(Selectors.RegExps.id);return[(a)?a[1]:"*",(c)?c[1]:false];},filter:function(g,c,f){var d;if(c.classes){for(d=c.classes.length;d--;d){var h=c.classes[d];if(!Selectors.Filters.byClass(g,h)){return false;}}}if(c.attributes){for(d=c.attributes.length;d--;d){var b=c.attributes[d];if(!Selectors.Filters.byAttribute(g,b.name,b.operator,b.value)){return false;}}}if(c.pseudos){for(d=c.pseudos.length;d--;d){var a=c.pseudos[d];if(!Selectors.Filters.byPseudo(g,a.parser,a.argument,f)){return false;}}}return true;},getByTagAndID:function(b,a,d){if(d){var c=(b.getElementById)?b.getElementById(d,true):Element.getElementById(b,d,true);return(c&&Selectors.Filters.byTag(c,a))?[c]:[];}else{return b.getElementsByTagName(a);}},search:function(p,o,u){var b=[];var c=o.trim().replace(Selectors.RegExps.splitter,function(k,j,i){b.push(j);return":)"+i;}).split(":)");var q,f,B;for(var A=0,w=c.length;A":function(j,h,k,a,g){var c=Selectors.Utils.getByTagAndID(h,k,a);for(var f=0,d=c.length;fa){return false;}}return(c==a);},even:function(b,a){return Selectors.Pseudo["nth-child"].call(this,"2n+1",a);},odd:function(b,a){return Selectors.Pseudo["nth-child"].call(this,"2n",a);},selected:function(){return this.selected;},enabled:function(){return(this.disabled===false);}});var Swiff=new Class({Implements:[Options],options:{id:null,height:1,width:1,container:null,properties:{},params:{quality:"high",allowScriptAccess:"always",wMode:"transparent",swLiveConnect:true},callBacks:{},vars:{}},toElement:function(){return this.object;},initialize:function(m,n){this.instance="Swiff_"+$time();this.setOptions(n);n=this.options;var b=this.id=n.id||this.instance;var a=document.id(n.container);Swiff.CallBacks[this.instance]={};var f=n.params,h=n.vars,g=n.callBacks;var i=$extend({height:n.height,width:n.width},n.properties);var l=this;for(var d in g){Swiff.CallBacks[this.instance][d]=(function(o){return function(){return o.apply(l.object,arguments);};})(g[d]);h[d]="Swiff.CallBacks."+this.instance+"."+d;}f.flashVars=Hash.toQueryString(h);if(Browser.Engine.trident){i.classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";f.movie=m;}else{i.type="application/x-shockwave-flash";i.data=m;}var k='';}}k+="";this.object=((a)?a.empty():new Element("div")).set("html",k).firstChild;},replaces:function(a){a=document.id(a,true);a.parentNode.replaceChild(this.toElement(),a);return this;},inject:function(a){document.id(a,true).appendChild(this.toElement());return this;},remote:function(){return Swiff.remote.apply(Swiff,[this.toElement()].extend(arguments));}});Swiff.CallBacks={};Swiff.remote=function(obj,fn){var rs=obj.CallFunction(''+__flash__argumentsToXML(arguments,2)+"");return eval(rs);}; \ No newline at end of file diff --git a/web/tools/mootools/mootools-1.2.5.1-more-yc.js b/web/tools/mootools/mootools-1.2.5.1-more-yc.js deleted file mode 100644 index 489332e3d..000000000 --- a/web/tools/mootools/mootools-1.2.5.1-more-yc.js +++ /dev/null @@ -1,683 +0,0 @@ -//MooTools More, . Copyright (c) 2006-2009 Aaron Newton , Valerio Proietti & the MooTools team , MIT Style License. - -MooTools.More={version:"1.2.5.1",build:"254884f2b83651bf95260eed5c6cceb838e22d8e"};(function(){var a={language:"en-US",languages:{"en-US":{}},cascades:["en-US"]}; -var b;MooTools.lang=new Events();$extend(MooTools.lang,{setLanguage:function(c){if(!a.languages[c]){return this;}a.language=c;this.load();this.fireEvent("langChange",c); -return this;},load:function(){var c=this.cascade(this.getCurrentLanguage());b={};$each(c,function(f,d){b[d]=this.lambda(f);},this);},getCurrentLanguage:function(){return a.language; -},addLanguage:function(c){a.languages[c]=a.languages[c]||{};return this;},cascade:function(f){var c=(a.languages[f]||{}).cascades||[];c.combine(a.cascades); -c.erase(f).push(f);var d=c.map(function(g){return a.languages[g];},this);return $merge.apply(this,d);},lambda:function(c){(c||{}).get=function(f,d){return $lambda(c[f]).apply(this,$splat(d)); -};return c;},get:function(f,d,c){if(b&&b[f]){return(d?b[f].get(d,c):b[f]);}},set:function(d,f,c){this.addLanguage(d);langData=a.languages[d];if(!langData[f]){langData[f]={}; -}$extend(langData[f],c);if(d==this.getCurrentLanguage()){this.load();this.fireEvent("langChange",d);}return this;},list:function(){return Hash.getKeys(a.languages); -}});})();(function(){var c=this;var b=function(){if(c.console&&console.log){try{console.log.apply(console,arguments);}catch(d){console.log(Array.slice(arguments)); -}}else{Log.logged.push(arguments);}return this;};var a=function(){this.logged.push(arguments);return this;};this.Log=new Class({logged:[],log:a,resetLog:function(){this.logged.empty(); -return this;},enableLog:function(){this.log=b;this.logged.each(function(d){this.log.apply(this,d);},this);return this.resetLog();},disableLog:function(){this.log=a; -return this;}});Log.extend(new Log).enableLog();Log.logger=function(){return this.log.apply(this,arguments);};})();Class.refactor=function(b,a){$each(a,function(f,d){var c=b.prototype[d]; -if(c&&(c=c._origin?c._origin:c)&&typeof f=="function"){b.implement(d,function(){var g=this.previous;this.previous=c;var h=f.apply(this,arguments);this.previous=g; -return h;});}else{b.implement(d,f);}});return b;};Class.Mutators.Binds=function(a){return a;};Class.Mutators.initialize=function(a){return function(){$splat(this.Binds).each(function(b){var c=this[b]; -if(c){this[b]=c.bind(this);}},this);return a.apply(this,arguments);};};Class.Occlude=new Class({occlude:function(c,b){b=document.id(b||this.element);var a=b.retrieve(c||this.property); -if(a&&!$defined(this.occluded)){return this.occluded=a;}this.occluded=false;b.store(c||this.property,this);return this.occluded;}});(function(){var a={wait:function(b){return this.chain(function(){this.callChain.delay($pick(b,500),this); -}.bind(this));}};Chain.implement(a);if(window.Fx){Fx.implement(a);["Css","Tween","Elements"].each(function(b){if(Fx[b]){Fx[b].implement(a);}});}Element.implement({chains:function(b){$splat($pick(b,["tween","morph","reveal"])).each(function(c){c=this.get(c); -if(!c){return;}c.setOptions({link:"chain"});},this);return this;},pauseFx:function(c,b){this.chains(b).get($pick(b,"tween")).wait(c);return this;}});})(); -Array.implement({min:function(){return Math.min.apply(null,this);},max:function(){return Math.max.apply(null,this);},average:function(){return this.length?this.sum()/this.length:0; -},sum:function(){var a=0,b=this.length;if(b){do{a+=this[--b];}while(b);}return a;},unique:function(){return[].combine(this);},shuffle:function(){for(var b=this.length; -b&&--b;){var a=this[b],c=Math.floor(Math.random()*(b+1));this[b]=this[c];this[c]=a;}return this;}});(function(){var j=this.Date;if(!j.now){j.now=$time; -}j.Methods={ms:"Milliseconds",year:"FullYear",min:"Minutes",mo:"Month",sec:"Seconds",hr:"Hours"};["Date","Day","FullYear","Hours","Milliseconds","Minutes","Month","Seconds","Time","TimezoneOffset","Week","Timezone","GMTOffset","DayOfYear","LastMonth","LastDayOfMonth","UTCDate","UTCDay","UTCFullYear","AMPM","Ordinal","UTCHours","UTCMilliseconds","UTCMinutes","UTCMonth","UTCSeconds","UTCMilliseconds"].each(function(q){j.Methods[q.toLowerCase()]=q; -});var d=function(r,q){return new Array(q-String(r).length+1).join("0")+r;};j.implement({set:function(t,r){switch($type(t)){case"object":for(var s in t){this.set(s,t[s]); -}break;case"string":t=t.toLowerCase();var q=j.Methods;if(q[t]){this["set"+q[t]](r);}}return this;},get:function(r){r=r.toLowerCase();var q=j.Methods;if(q[r]){return this["get"+q[r]](); -}return null;},clone:function(){return new j(this.get("time"));},increment:function(q,s){q=q||"day";s=$pick(s,1);switch(q){case"year":return this.increment("month",s*12); -case"month":var r=this.get("date");this.set("date",1).set("mo",this.get("mo")+s);return this.set("date",r.min(this.get("lastdayofmonth")));case"week":return this.increment("day",s*7); -case"day":return this.set("date",this.get("date")+s);}if(!j.units[q]){throw new Error(q+" is not a supported interval");}return this.set("time",this.get("time")+s*j.units[q]()); -},decrement:function(q,r){return this.increment(q,-1*$pick(r,1));},isLeapYear:function(){return j.isLeapYear(this.get("year"));},clearTime:function(){return this.set({hr:0,min:0,sec:0,ms:0}); -},diff:function(r,q){if($type(r)=="string"){r=j.parse(r);}return((r-this)/j.units[q||"day"](3,3)).round();},getLastDayOfMonth:function(){return j.daysInMonth(this.get("mo"),this.get("year")); -},getDayOfYear:function(){return(j.UTC(this.get("year"),this.get("mo"),this.get("date")+1)-j.UTC(this.get("year"),0,1))/j.units.day();},getWeek:function(){return(this.get("dayofyear")/7).ceil(); -},getOrdinal:function(q){return j.getMsg("ordinal",q||this.get("date"));},getTimezone:function(){return this.toString().replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3"); -},getGMTOffset:function(){var q=this.get("timezoneOffset");return((q>0)?"-":"+")+d((q.abs()/60).floor(),2)+d(q%60,2);},setAMPM:function(q){q=q.toUpperCase(); -var r=this.get("hr");if(r>11&&q=="AM"){return this.decrement("hour",12);}else{if(r<12&&q=="PM"){return this.increment("hour",12);}}return this;},getAMPM:function(){return(this.get("hr")<12)?"AM":"PM"; -},parse:function(q){this.set("time",j.parse(q));return this;},isValid:function(q){return !isNaN((q||this).valueOf());},format:function(q){if(!this.isValid()){return"invalid date"; -}q=q||"%x %X";q=l[q.toLowerCase()]||q;var r=this;return q.replace(/%([a-z%])/gi,function(t,s){switch(s){case"a":return j.getMsg("days")[r.get("day")].substr(0,3); -case"A":return j.getMsg("days")[r.get("day")];case"b":return j.getMsg("months")[r.get("month")].substr(0,3);case"B":return j.getMsg("months")[r.get("month")]; -case"c":return r.toString();case"d":return d(r.get("date"),2);case"D":return r.get("date");case"e":return r.get("date");case"H":return d(r.get("hr"),2); -case"I":return((r.get("hr")%12)||12);case"j":return d(r.get("dayofyear"),3);case"m":return d((r.get("mo")+1),2);case"M":return d(r.get("min"),2);case"o":return r.get("ordinal"); -case"p":return j.getMsg(r.get("ampm"));case"s":return Math.round(r/1000);case"S":return d(r.get("seconds"),2);case"U":return d(r.get("week"),2);case"w":return r.get("day"); -case"x":return r.format(j.getMsg("shortDate"));case"X":return r.format(j.getMsg("shortTime"));case"y":return r.get("year").toString().substr(2);case"Y":return r.get("year"); -case"T":return r.get("GMTOffset");case"Z":return r.get("Timezone");case"z":return d(r.get("ms"),3);}return s;});},toISOString:function(){return this.format("iso8601"); -}});j.alias("toISOString","toJSON");j.alias("diff","compare");j.alias("format","strftime");var l={db:"%Y-%m-%d %H:%M:%S",compact:"%Y%m%dT%H%M%S",iso8601:"%Y-%m-%dT%H:%M:%S%T",rfc822:"%a, %d %b %Y %H:%M:%S %Z","short":"%d %b %H:%M","long":"%B %d, %Y %H:%M"}; -var h=[];var f=j.parse;var o=function(t,v,s){var r=-1;var u=j.getMsg(t+"s");switch($type(v)){case"object":r=u[v.get(t)];break;case"number":r=u[v];if(!r){throw new Error("Invalid "+t+" index: "+v); -}break;case"string":var q=u.filter(function(w){return this.test(w);},new RegExp("^"+v,"i"));if(!q.length){throw new Error("Invalid "+t+" string");}if(q.length>1){throw new Error("Ambiguous "+t); -}r=q[0];}return(s)?u.indexOf(r):r;};j.extend({getMsg:function(r,q){return MooTools.lang.get("Date",r,q);},units:{ms:$lambda(1),second:$lambda(1000),minute:$lambda(60000),hour:$lambda(3600000),day:$lambda(86400000),week:$lambda(608400000),month:function(r,q){var s=new j; -return j.daysInMonth($pick(r,s.get("mo")),$pick(q,s.get("year")))*86400000;},year:function(q){q=q||new j().get("year");return j.isLeapYear(q)?31622400000:31536000000; -}},daysInMonth:function(r,q){return[31,j.isLeapYear(q)?29:28,31,30,31,30,31,31,30,31,30,31][r];},isLeapYear:function(q){return((q%4===0)&&(q%100!==0))||(q%400===0); -},parse:function(s){var r=$type(s);if(r=="number"){return new j(s);}if(r!="string"){return s;}s=s.clean();if(!s.length){return null;}var q;h.some(function(u){var t=u.re.exec(s); -return(t)?(q=u.handler(t)):false;});return q||new j(f(s));},parseDay:function(q,r){return o("day",q,r);},parseMonth:function(r,q){return o("month",r,q); -},parseUTC:function(r){var q=new j(r);var s=j.UTC(q.get("year"),q.get("mo"),q.get("date"),q.get("hr"),q.get("min"),q.get("sec"),q.get("ms"));return new j(s); -},orderIndex:function(q){return j.getMsg("dateOrder").indexOf(q)+1;},defineFormat:function(q,r){l[q]=r;},defineFormats:function(q){for(var r in q){j.defineFormat(r,q[r]); -}},parsePatterns:h,defineParser:function(q){h.push((q.re&&q.handler)?q:m(q));},defineParsers:function(){Array.flatten(arguments).each(j.defineParser);},define2DigitYearStart:function(q){i=q%100; -n=q-i;}});var n=1900;var i=70;var k=function(q){return new RegExp("(?:"+j.getMsg(q).map(function(r){return r.substr(0,3);}).join("|")+")[a-z]*");};var a=function(q){switch(q){case"x":return((j.orderIndex("month")==1)?"%m[-./]%d":"%d[-./]%m")+"([-./]%y)?"; -case"X":return"%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%T?";}return null;};var p={d:/[0-2]?[0-9]|3[01]/,H:/[01]?[0-9]|2[0-3]/,I:/0?[1-9]|1[0-2]/,M:/[0-5]?\d/,s:/\d+/,o:/[a-z]*/,p:/[ap]\.?m\.?/,y:/\d{2}|\d{4}/,Y:/\d{4}/,T:/Z|[+-]\d{2}(?::?\d{2})?/}; -p.m=p.I;p.S=p.M;var c;var b=function(q){c=q;p.a=p.A=k("days");p.b=p.B=k("months");h.each(function(s,r){if(s.format){h[r]=m(s.format);}});};var m=function(s){if(!c){return{format:s}; -}var q=[];var r=(s.source||s).replace(/%([a-z])/gi,function(u,t){return a(t)||u;}).replace(/\((?!\?)/g,"(?:").replace(/ (?!\?|\*)/g,",? ").replace(/%([a-z%])/gi,function(u,t){var v=p[t]; -if(!v){return t;}q.push(t);return"("+v.source+")";}).replace(/\[a-z\]/gi,"[a-z\\u00c0-\\uffff]");return{format:s,re:new RegExp("^"+r+"$","i"),handler:function(w){w=w.slice(1).associate(q); -var t=new j().clearTime(),v=w.y||w.Y;if(v!=null){g.call(t,"y",v);}if("d" in w){g.call(t,"d",1);}if("m" in w||"b" in w||"B" in w){g.call(t,"m",1);}for(var u in w){g.call(t,u,w[u]); -}return t;}};};var g=function(q,r){if(!r){return this;}switch(q){case"a":case"A":return this.set("day",j.parseDay(r,true));case"b":case"B":return this.set("mo",j.parseMonth(r,true)); -case"d":return this.set("date",r);case"H":case"I":return this.set("hr",r);case"m":return this.set("mo",r-1);case"M":return this.set("min",r);case"p":return this.set("ampm",r.replace(/\./g,"")); -case"S":return this.set("sec",r);case"s":return this.set("ms",("0."+r)*1000);case"w":return this.set("day",r);case"Y":return this.set("year",r);case"y":r=+r; -if(r<100){r+=n+(r0.75*a){f=c;}break;}g/=a;f=c+"s";}return Date.getMsg(f+d,g).substitute({delta:g.round()});}});Date.defineParsers({re:/^(?:tod|tom|yes)/i,handler:function(a){var b=new Date().clearTime(); -switch(a[0]){case"tom":return b.increment();case"yes":return b.decrement();default:return b;}}},{re:/^(next|last) ([a-z]+)$/i,handler:function(f){var g=new Date().clearTime(); -var b=g.getDay();var c=Date.parseDay(f[2],true);var a=c-b;if(c<=b){a+=7;}if(f[1]=="last"){a-=7;}return g.set("date",g.getDate()+a);}});Hash.implement({getFromPath:function(a){var b=this.getClean(); -a.replace(/\[([^\]]+)\]|\.([^.[]+)|[^[.]+/g,function(c){if(!b){return null;}var d=arguments[2]||arguments[1]||arguments[0];b=(d in b)?b[d]:null;return c; -});return b;},cleanValues:function(a){a=a||$defined;this.each(function(c,b){if(!a(c)){this.erase(b);}},this);return this;},run:function(){var a=arguments; -this.each(function(c,b){if($type(c)=="function"){c.run(a);}});}});(function(){var c={a:"[àáâãäåăą]",A:"[ÀÃÂÃÄÅĂĄ]",c:"[ćÄç]",C:"[ĆČÇ]",d:"[ÄÄ‘]",D:"[ÄŽÃ]",e:"[èéêëěę]",E:"[ÈÉÊËĚĘ]",g:"[ÄŸ]",G:"[Äž]",i:"[ìíîï]",I:"[ÃŒÃÃŽÃ]",l:"[ĺľł]",L:"[ĹĽÅ]",n:"[ñňń]",N:"[ÑŇŃ]",o:"[òóôõöøő]",O:"[ÒÓÔÕÖØ]",r:"[řŕ]",R:"[ŘŔ]",s:"[Å¡Å¡ÅŸ]",S:"[ŠŞŚ]",t:"[ťţ]",T:"[ŤŢ]",ue:"[ü]",UE:"[Ãœ]",u:"[ùúûůµ]",U:"[ÙÚÛŮ]",y:"[ÿý]",Y:"[ŸÃ]",z:"[žźż]",Z:"[ŽŹŻ]",th:"[þ]",TH:"[Þ]",dh:"[ð]",DH:"[Ã]",ss:"[ß]",oe:"[Å“]",OE:"[Å’]",ae:"[æ]",AE:"[Æ]"},b={" ":"[\xa0\u2002\u2003\u2009]","*":"[\xb7]","'":"[\u2018\u2019]",'"':"[\u201c\u201d]","...":"[\u2026]","-":"[\u2013]","--":"[\u2014]","»":"[\uFFFD]"}; -function a(g,h){var f=g;for(key in h){f=f.replace(new RegExp(h[key],"g"),key);}return f;}function d(f,g){f=f||"";var h=g?"<"+f+"(?!\\w)[^>]*>([\\s\\S]*?)":"]+)?>"; -reg=new RegExp(h,"gi");return reg;}String.implement({standardize:function(){return a(this,c);},repeat:function(f){return new Array(f+1).join(this);},pad:function(g,i,f){if(this.length>=g){return this; -}var h=(i==null?" ":""+i).repeat(g-this.length).substr(0,g-this.length);if(!f||f=="right"){return this+h;}if(f=="left"){return h+this;}return h.substr(0,(h.length/2).floor())+this+h.substr(0,(h.length/2).ceil()); -},getTags:function(f,g){return this.match(d(f,g))||[];},stripTags:function(f,g){return this.replace(d(f,g),"");},tidy:function(){return a(this,b);}});})(); -String.implement({parseQueryString:function(d,a){if(d==null){d=true;}if(a==null){a=true;}var c=this.split(/[&;]/),b={};if(c.length){c.each(function(j){var f=j.indexOf("="),g=f<0?[""]:j.substr(0,f).match(/([^\]\[]+|(\B)(?=\]))/g),h=a?decodeURIComponent(j.substr(f+1)):j.substr(f+1),i=b; -g.each(function(l,k){if(d){l=decodeURIComponent(l);}var m=i[l];if(k0){a.pop(); -}else{if(d!="."){a.push(d);}}});return a.join("/")+"/";},combine:function(a){return a.value||a.scheme+"://"+(a.user?a.user+(a.password?":"+a.password:"")+"@":"")+(a.host||"")+(a.port&&a.port!=this.schemes[a.scheme]?":"+a.port:"")+(a.directory||"/")+(a.file||"")+(a.query?"?"+a.query:"")+(a.fragment?"#"+a.fragment:""); -},set:function(b,d,c){if(b=="value"){var a=d.match(URI.regs.scheme);if(a){a=a[1];}if(a&&!$defined(this.schemes[a.toLowerCase()])){this.parsed={scheme:a,value:d}; -}else{this.parsed=this.parse(d,(c||this).parsed)||(a?{scheme:a,value:d}:{value:d});}}else{if(b=="data"){this.setData(d);}else{this.parsed[b]=d;}}return this; -},get:function(a,b){switch(a){case"value":return this.combine(this.parsed,b?b.parsed:false);case"data":return this.getData();}return this.parsed[a]||""; -},go:function(){document.location.href=this.toString();},toURI:function(){return this;},getData:function(c,b){var a=this.get(b||"query");if(!$chk(a)){return c?null:{}; -}var d=a.parseQueryString();return c?d[c]:d;},setData:function(a,c,b){if(typeof a=="string"){data=this.getData();data[arguments[0]]=arguments[1];a=data; -}else{if(c){a=$merge(this.getData(),a);}}return this.set(b||"query",Hash.toQueryString(a));},clearData:function(a){return this.set(a||"query","");}});URI.prototype.toString=URI.prototype.valueOf=function(){return this.get("value"); -};URI.regs={endSlash:/\/$/,scheme:/^(\w+):/,directoryDot:/\.\/|\.$/};URI.base=new URI(document.getElements("base[href]",true).getLast(),{base:document.location}); -String.implement({toURI:function(a){return new URI(this,a);}});URI=Class.refactor(URI,{combine:function(g,f){if(!f||g.scheme!=f.scheme||g.host!=f.host||g.port!=f.port){return this.previous.apply(this,arguments); -}var a=g.file+(g.query?"?"+g.query:"")+(g.fragment?"#"+g.fragment:"");if(!f.directory){return(g.directory||(g.file?"":"./"))+a;}var d=f.directory.split("/"),c=g.directory.split("/"),h="",j; -var b=0;for(j=0;j~\s]/,g=function(h){var i=h.match(c); -return !i?{event:h}:{event:i[1],selector:i[2]};},a=function(n,h){var l=n.target;if(b.test(h=h.trim())){var k=this.getElements(h);for(var j=k.length;j--; -){var m=k[j];if(l==m||m.hasChild(l)){return m;}}}else{for(;l&&l!=this;l=l.parentNode){if(Element.match(l,h)){return document.id(l);}}}return null;};Element.implement({addEvent:function(l,k){var j=g(l); -if(j.selector){var i=this.retrieve("delegation:_delegateMonitors",{});if(!i[l]){var h=function(n){var m=a.call(this,n,j.selector);if(m){this.fireEvent(l,[n,m],0,m); -}}.bind(this);i[l]=h;d.call(this,j.event,h);}}return d.apply(this,arguments);},removeEvent:function(l,k){var j=g(l);if(j.selector){var i=this.retrieve("events"); -if(!i||!i[l]||(k&&!i[l].keys.contains(k))){return this;}if(k){f.apply(this,[l,k]);}else{f.apply(this,l);}i=this.retrieve("events");if(i&&i[l]&&i[l].keys.length==0){var h=this.retrieve("delegation:_delegateMonitors",{}); -f.apply(this,[j.event,h[l]]);delete h[l];}return this;}return f.apply(this,arguments);},fireEvent:function(l,i,h,n){var j=this.retrieve("events");var m,k; -if(i){m=i[0];k=i[1];}if(!j||!j[l]){return this;}j[l].keys.each(function(o){o.create({bind:n||this,delay:h,arguments:i})();},this);return this;}});})(Element.prototype.addEvent,Element.prototype.removeEvent); -try{if(typeof HTMLElement!="undefined"){HTMLElement.prototype.fireEvent=Element.prototype.fireEvent;}}catch(e){}Element.implement({measure:function(f){var h=function(i){return !!(!i||i.offsetHeight||i.offsetWidth); -};if(h(this)){return f.apply(this);}var d=this.getParent(),g=[],b=[];while(!h(d)&&d!=document.body){b.push(d.expose());d=d.getParent();}var c=this.expose(); -var a=f.apply(this);c();b.each(function(i){i();});return a;},expose:function(){if(this.getStyle("display")!="none"){return $empty;}var a=this.style.cssText; -this.setStyles({display:"block",position:"absolute",visibility:"hidden"});return function(){this.style.cssText=a;}.bind(this);},getDimensions:function(a){a=$merge({computeSize:false},a); -var f={};var d=function(h,g){return(g.computeSize)?h.getComputedSize(g):h.getSize();};var b=this.getParent("body");if(b&&this.getStyle("display")=="none"){f=this.measure(function(){return d(this,a); -});}else{if(b){try{f=d(this,a);}catch(c){}}else{f={x:0,y:0};}}return $chk(f.x)?$extend(f,{width:f.x,height:f.y}):$extend(f,{x:f.width,y:f.height});},getComputedSize:function(a){if(a&&a.plains){a.planes=a.plains; -}a=$merge({styles:["padding","border"],planes:{height:["top","bottom"],width:["left","right"]},mode:"both"},a);var c={width:0,height:0};switch(a.mode){case"vertical":delete c.width; -delete a.planes.width;break;case"horizontal":delete c.height;delete a.planes.height;break;}var b=[];$each(a.planes,function(g,h){g.each(function(i){a.styles.each(function(j){b.push((j=="border")?j+"-"+i+"-width":j+"-"+i); -});});});var f={};b.each(function(g){f[g]=this.getComputedStyle(g);},this);var d=[];$each(a.planes,function(g,h){var i=h.capitalize();c["total"+i]=c["computed"+i]=0; -g.each(function(j){c["computed"+j.capitalize()]=0;b.each(function(l,k){if(l.test(j)){f[l]=f[l].toInt()||0;c["total"+i]=c["total"+i]+f[l];c["computed"+j.capitalize()]=c["computed"+j.capitalize()]+f[l]; -}if(l.test(j)&&h!=l&&(l.test("border")||l.test("padding"))&&!d.contains(l)){d.push(l);c["computed"+i]=c["computed"+i]-f[l];}});});});["Width","Height"].each(function(h){var g=h.toLowerCase(); -if(!$chk(c[g])){return;}c[g]=c[g]+this["offset"+h]+c["computed"+h];c["total"+h]=c[g]+c["total"+h];delete c["computed"+h];},this);return $extend(f,c);}}); -(function(){var a=false,b=false;var c=function(){var d=new Element("div").setStyles({position:"fixed",top:0,right:0}).inject(document.body);a=(d.offsetTop===0); -d.dispose();b=true;};Element.implement({pin:function(i,g){if(!b){c();}if(this.getStyle("display")=="none"){return this;}var k,l=window.getScroll();if(i!==false){k=this.getPosition(a?document.body:this.getOffsetParent()); -if(!this.retrieve("pin:_pinned")){var h={top:k.y-l.y,left:k.x-l.x};if(a&&!g){this.setStyle("position","fixed").setStyles(h);}else{var m=this.getOffsetParent(),j=this.getPosition(m),n=this.getStyles("left","top"); -if(m&&n.left=="auto"||n.top=="auto"){this.setPosition(j);}if(this.getStyle("position")=="static"){this.setStyle("position","absolute");}j={x:n.left.toInt()-l.x,y:n.top.toInt()-l.y}; -var f=function(){if(!this.retrieve("pin:_pinned")){return;}var o=window.getScroll();this.setStyles({left:j.x+o.x,top:j.y+o.y});}.bind(this);this.store("pin:_scrollFixer",f); -window.addEvent("scroll",f);}this.store("pin:_pinned",true);}}else{if(!this.retrieve("pin:_pinned")){return this;}var m=this.getParent(),d=(m.getComputedStyle("position")!="static"?m:m.getOffsetParent()); -k=this.getPosition(d);this.store("pin:_pinned",false);var f=this.retrieve("pin:_scrollFixer");if(!f){this.setStyles({position:"absolute",top:k.y+l.y,left:k.x+l.x}); -}else{this.store("pin:_scrollFixer",null);window.removeEvent("scroll",f);}this.removeClass("isPinned");}return this;},unpin:function(){return this.pin(false); -},togglepin:function(){return this.pin(!this.retrieve("pin:_pinned"));}});})();(function(){var a=Element.prototype.position;Element.implement({position:function(h){if(h&&($defined(h.x)||$defined(h.y))){return a?a.apply(this,arguments):this; -}$each(h||{},function(w,u){if(!$defined(w)){delete h[u];}});h=$merge({relativeTo:document.body,position:{x:"center",y:"center"},edge:false,offset:{x:0,y:0},returnPos:false,relFixedPosition:false,ignoreMargins:false,ignoreScroll:false,allowNegative:false},h); -var s={x:0,y:0},f=false;var c=this.measure(function(){return document.id(this.getOffsetParent());});if(c&&c!=this.getDocument().body){s=c.measure(function(){return this.getPosition(); -});f=c!=document.id(h.relativeTo);h.offset.x=h.offset.x-s.x;h.offset.y=h.offset.y-s.y;}var t=function(u){if($type(u)!="string"){return u;}u=u.toLowerCase(); -var v={};if(u.test("left")){v.x="left";}else{if(u.test("right")){v.x="right";}else{v.x="center";}}if(u.test("upper")||u.test("top")){v.y="top";}else{if(u.test("bottom")){v.y="bottom"; -}else{v.y="center";}}return v;};h.edge=t(h.edge);h.position=t(h.position);if(!h.edge){if(h.position.x=="center"&&h.position.y=="center"){h.edge={x:"center",y:"center"}; -}else{h.edge={x:"left",y:"top"};}}this.setStyle("position","absolute");var g=document.id(h.relativeTo)||document.body,d=g==document.body?window.getScroll():g.getPosition(),m=d.y,i=d.x; -var o=this.getDimensions({computeSize:true,styles:["padding","border","margin"]});var k={},p=h.offset.y,r=h.offset.x,l=window.getSize();switch(h.position.x){case"left":k.x=i+r; -break;case"right":k.x=i+r+g.offsetWidth;break;default:k.x=i+((g==document.body?l.x:g.offsetWidth)/2)+r;break;}switch(h.position.y){case"top":k.y=m+p;break; -case"bottom":k.y=m+p+g.offsetHeight;break;default:k.y=m+((g==document.body?l.y:g.offsetHeight)/2)+p;break;}if(h.edge){var b={};switch(h.edge.x){case"left":b.x=0; -break;case"right":b.x=-o.x-o.computedRight-o.computedLeft;break;default:b.x=-(o.totalWidth/2);break;}switch(h.edge.y){case"top":b.y=0;break;case"bottom":b.y=-o.y-o.computedTop-o.computedBottom; -break;default:b.y=-(o.totalHeight/2);break;}k.x+=b.x;k.y+=b.y;}k={left:((k.x>=0||f||h.allowNegative)?k.x:0).toInt(),top:((k.y>=0||f||h.allowNegative)?k.y:0).toInt()}; -var j={left:"x",top:"y"};["minimum","maximum"].each(function(u){["left","top"].each(function(v){var w=h[u]?h[u][j[v]]:null;if(w!=null&&((u=="minimum")?k[v]w)){k[v]=w; -}});});if(g.getStyle("position")=="fixed"||h.relFixedPosition){var n=window.getScroll();k.top+=n.y;k.left+=n.x;}var q=g.getScroll();if(h.ignoreScroll){k.top-=q.y; -k.left-=q.x;}else{k.top+=q.y;k.left+=q.x;}if(h.ignoreMargins){k.left+=(h.edge.x=="right"?o["margin-right"]:h.edge.x=="center"?-o["margin-left"]+((o["margin-right"]+o["margin-left"])/2):-o["margin-left"]); -k.top+=(h.edge.y=="bottom"?o["margin-bottom"]:h.edge.y=="center"?-o["margin-top"]+((o["margin-bottom"]+o["margin-top"])/2):-o["margin-top"]);}k.left=Math.ceil(k.left); -k.top=Math.ceil(k.top);if(h.returnPos){return k;}else{this.setStyles(k);}return this;}});})();Element.implement({isDisplayed:function(){return this.getStyle("display")!="none"; -},isVisible:function(){var a=this.offsetWidth,b=this.offsetHeight;return(a==0&&b==0)?false:(a>0&&b>0)?true:this.style.display!="none";},toggle:function(){return this[this.isDisplayed()?"hide":"show"](); -},hide:function(){var b;try{b=this.getStyle("display");}catch(a){}if(b=="none"){return this;}return this.store("element:_originalDisplay",b||"").setStyle("display","none"); -},show:function(a){if(!a&&this.isDisplayed()){return this;}a=a||this.retrieve("element:_originalDisplay")||"block";return this.setStyle("display",(a=="none")?"block":a); -},swapClass:function(a,b){return this.removeClass(a).addClass(b);}});Document.implement({clearSelection:function(){if(document.selection&&document.selection.empty){document.selection.empty(); -}else{if(window.getSelection){var a=window.getSelection();if(a&&a.removeAllRanges){a.removeAllRanges();}}}}});if(!window.Form){window.Form={};}(function(){Form.Request=new Class({Binds:["onSubmit","onFormValidate"],Implements:[Options,Events,Class.Occlude],options:{requestOptions:{evalScripts:true,useSpinner:true,emulation:false,link:"ignore"},sendButtonClicked:true,extraData:{},resetForm:true},property:"form.request",initialize:function(b,c,a){this.element=document.id(b); -if(this.occlude()){return this.occluded;}this.update=document.id(c);this.setOptions(a);this.makeRequest();if(this.options.resetForm){this.request.addEvent("success",function(){$try(function(){this.element.reset(); -}.bind(this));if(window.OverText){OverText.update();}}.bind(this));}this.attach();},toElement:function(){return this.element;},makeRequest:function(){this.request=new Request.HTML($merge({update:this.update,emulation:false,spinnerTarget:this.element,method:this.element.get("method")||"post"},this.options.requestOptions)).addEvents({success:function(b,d,c,a){["complete","success"].each(function(f){this.fireEvent(f,[this.update,b,d,c,a]); -},this);}.bind(this),failure:function(){this.fireEvent("complete",arguments).fireEvent("failure",arguments);}.bind(this),exception:function(){this.fireEvent("failure",arguments); -}.bind(this)});},attach:function(a){a=$pick(a,true);method=a?"addEvent":"removeEvent";this.element[method]("click:relay(button, input[type=submit])",this.saveClickedButton.bind(this)); -var b=this.element.retrieve("validator");if(b){b[method]("onFormValidate",this.onFormValidate);}else{this.element[method]("submit",this.onSubmit);}},detach:function(){this.attach(false); -return this;},enable:function(){this.attach();return this;},disable:function(){this.detach();return this;},onFormValidate:function(b,a,d){if(!d){return; -}var c=this.element.retrieve("validator");if(b||(c&&!c.options.stopOnFailure)){if(d&&d.stop){d.stop();}this.send();}},onSubmit:function(b){var a=this.element.retrieve("validator"); -if(a){this.element.removeEvent("submit",this.onSubmit);a.addEvent("onFormValidate",this.onFormValidate);this.element.validate();return;}if(b){b.stop(); -}this.send();},saveClickedButton:function(a,b){if(!this.options.sendButtonClicked){return;}if(!b.get("name")){return;}this.options.extraData[b.get("name")]=b.get("value")||true; -this.clickedCleaner=function(){delete this.options.extraData[b.get("name")];this.clickedCleaner=$empty;}.bind(this);},clickedCleaner:$empty,send:function(){var b=this.element.toQueryString().trim(); -var a=$H(this.options.extraData).toQueryString();if(b){b+="&"+a;}else{b=a;}this.fireEvent("send",[this.element,b.parseQueryString()]);this.request.send({data:b,url:this.element.get("action")}); -this.clickedCleaner();return this;}});Element.Properties.formRequest={set:function(){var a=Array.link(arguments,{options:Object.type,update:Element.type,updateId:String.type}); -var c=a.update||a.updateId;var b=this.retrieve("form.request");if(c){if(b){b.update=document.id(c);}this.store("form.request:update",c);}if(a.options){if(b){b.setOptions(a.options); -}this.store("form.request:options",a.options);}return this;},get:function(){var a=Array.link(arguments,{options:Object.type,update:Element.type,updateId:String.type}); -var b=a.update||a.updateId;if(a.options||b||!this.retrieve("form.request")){if(a.options||!this.retrieve("form.request:options")){this.set("form.request",a.options); -}if(b){this.set("form.request",b);}this.store("form.request",new Form.Request(this,this.retrieve("form.request:update"),this.retrieve("form.request:options"))); -}return this.retrieve("form.request");}};Element.implement({formUpdate:function(b,a){this.get("formRequest",b,a).send();return this;}});})();Form.Request.Append=new Class({Extends:Form.Request,options:{useReveal:true,revealOptions:{},inject:"bottom"},makeRequest:function(){this.request=new Request.HTML($merge({url:this.element.get("action"),method:this.element.get("method")||"post",spinnerTarget:this.element},this.options.requestOptions,{evalScripts:false})).addEvents({success:function(b,h,g,a){var c; -var d=Elements.from(g);if(d.length==1){c=d[0];}else{c=new Element("div",{styles:{display:"none"}}).adopt(d);}c.inject(this.update,this.options.inject); -if(this.options.requestOptions.evalScripts){$exec(a);}this.fireEvent("beforeEffect",c);var f=function(){this.fireEvent("success",[c,this.update,b,h,g,a]); -}.bind(this);if(this.options.useReveal){c.get("reveal",this.options.revealOptions).chain(f);c.reveal();}else{f();}}.bind(this),failure:function(a){this.fireEvent("failure",a); -}.bind(this)});}});if(!window.Form){window.Form={};}var InputValidator=new Class({Implements:[Options],options:{errorMsg:"Validation failed.",test:function(a){return true; -}},initialize:function(b,a){this.setOptions(a);this.className=b;},test:function(b,a){if(document.id(b)){return this.options.test(document.id(b),a||this.getProps(b)); -}else{return false;}},getError:function(c,a){var b=this.options.errorMsg;if($type(b)=="function"){b=b(document.id(c),a||this.getProps(c));}return b;},getProps:function(a){if(!document.id(a)){return{}; -}return a.get("validatorProps");}});Element.Properties.validatorProps={set:function(a){return this.eliminate("validatorProps").store("validatorProps",a); -},get:function(a){if(a){this.set(a);}if(this.retrieve("validatorProps")){return this.retrieve("validatorProps");}if(this.getProperty("validatorProps")){try{this.store("validatorProps",JSON.decode(this.getProperty("validatorProps"))); -}catch(c){return{};}}else{var b=this.get("class").split(" ").filter(function(d){return d.test(":");});if(!b.length){this.store("validatorProps",{});}else{a={}; -b.each(function(d){var f=d.split(":");if(f[1]){try{a[f[0]]=JSON.decode(f[1]);}catch(g){}}});this.store("validatorProps",a);}}return this.retrieve("validatorProps"); -}};Form.Validator=new Class({Implements:[Options,Events],Binds:["onSubmit"],options:{fieldSelectors:"input, select, textarea",ignoreHidden:true,ignoreDisabled:true,useTitles:false,evaluateOnSubmit:true,evaluateFieldsOnBlur:true,evaluateFieldsOnChange:true,serial:true,stopOnFailure:true,warningPrefix:function(){return Form.Validator.getMsg("warningPrefix")||"Warning: "; -},errorPrefix:function(){return Form.Validator.getMsg("errorPrefix")||"Error: ";}},initialize:function(b,a){this.setOptions(a);this.element=document.id(b); -this.element.store("validator",this);this.warningPrefix=$lambda(this.options.warningPrefix)();this.errorPrefix=$lambda(this.options.errorPrefix)();if(this.options.evaluateOnSubmit){this.element.addEvent("submit",this.onSubmit); -}if(this.options.evaluateFieldsOnBlur||this.options.evaluateFieldsOnChange){this.watchFields(this.getFields());}},toElement:function(){return this.element; -},getFields:function(){return(this.fields=this.element.getElements(this.options.fieldSelectors));},watchFields:function(a){a.each(function(b){if(this.options.evaluateFieldsOnBlur){b.addEvent("blur",this.validationMonitor.pass([b,false],this)); -}if(this.options.evaluateFieldsOnChange){b.addEvent("change",this.validationMonitor.pass([b,true],this));}},this);},validationMonitor:function(){$clear(this.timer); -this.timer=this.validateField.delay(50,this,arguments);},onSubmit:function(a){if(!this.validate(a)&&a){a.preventDefault();}else{this.reset();}},reset:function(){this.getFields().each(this.resetField,this); -return this;},validate:function(b){var a=this.getFields().map(function(c){return this.validateField(c,true);},this).every(function(c){return c;});this.fireEvent("formValidate",[a,this.element,b]); -if(this.options.stopOnFailure&&!a&&b){b.preventDefault();}return a;},validateField:function(j,a){if(this.paused){return true;}j=document.id(j);var d=!j.hasClass("validation-failed"); -var g,i;if(this.options.serial&&!a){g=this.element.getElement(".validation-failed");i=this.element.getElement(".warning");}if(j&&(!g||a||j.hasClass("validation-failed")||(g&&!this.options.serial))){var c=j.className.split(" ").some(function(k){return this.getValidator(k); -},this);var h=[];j.className.split(" ").each(function(k){if(k&&!this.test(k,j)){h.include(k);}},this);d=h.length===0;if(c&&!j.hasClass("warnOnly")){if(d){j.addClass("validation-passed").removeClass("validation-failed"); -this.fireEvent("elementPass",j);}else{j.addClass("validation-failed").removeClass("validation-passed");this.fireEvent("elementFail",[j,h]);}}if(!i){var f=j.className.split(" ").some(function(k){if(k.test("^warn-")||j.hasClass("warnOnly")){return this.getValidator(k.replace(/^warn-/,"")); -}else{return null;}},this);j.removeClass("warning");var b=j.className.split(" ").map(function(k){if(k.test("^warn-")||j.hasClass("warnOnly")){return this.test(k.replace(/^warn-/,""),j,true); -}else{return null;}},this);}}return d;},test:function(b,d,f){d=document.id(d);if((this.options.ignoreHidden&&!d.isVisible())||(this.options.ignoreDisabled&&d.get("disabled"))){return true; -}var a=this.getValidator(b);f=$pick(f,false);if(d.hasClass("warnOnly")){f=true;}var c=d.hasClass("ignoreValidation")||(a?a.test(d):true);if(a&&d.isVisible()){this.fireEvent("elementValidate",[c,d,b,f]); -}if(f){return true;}return c;},resetField:function(a){a=document.id(a);if(a){a.className.split(" ").each(function(b){if(b.test("^warn-")){b=b.replace(/^warn-/,""); -}a.removeClass("validation-failed");a.removeClass("warning");a.removeClass("validation-passed");},this);}return this;},stop:function(){this.paused=true; -return this;},start:function(){this.paused=false;return this;},ignoreField:function(a,b){a=document.id(a);if(a){this.enforceField(a);if(b){a.addClass("warnOnly"); -}else{a.addClass("ignoreValidation");}}return this;},enforceField:function(a){a=document.id(a);if(a){a.removeClass("warnOnly").removeClass("ignoreValidation"); -}return this;}});Form.Validator.getMsg=function(a){return MooTools.lang.get("Form.Validator",a);};Form.Validator.adders={validators:{},add:function(b,a){this.validators[b]=new InputValidator(b,a); -if(!this.initialize){this.implement({validators:this.validators});}},addAllThese:function(a){$A(a).each(function(b){this.add(b[0],b[1]);},this);},getValidator:function(a){return this.validators[a.split(":")[0]]; -}};$extend(Form.Validator,Form.Validator.adders);Form.Validator.implement(Form.Validator.adders);Form.Validator.add("IsEmpty",{errorMsg:false,test:function(a){if(a.type=="select-one"||a.type=="select"){return !(a.selectedIndex>=0&&a.options[a.selectedIndex].value!=""); -}else{return((a.get("value")==null)||(a.get("value").length==0));}}});Form.Validator.addAllThese([["required",{errorMsg:function(){return Form.Validator.getMsg("required"); -},test:function(a){return !Form.Validator.getValidator("IsEmpty").test(a);}}],["minLength",{errorMsg:function(a,b){if($type(b.minLength)){return Form.Validator.getMsg("minLength").substitute({minLength:b.minLength,length:a.get("value").length}); -}else{return"";}},test:function(a,b){if($type(b.minLength)){return(a.get("value").length>=$pick(b.minLength,0));}else{return true;}}}],["maxLength",{errorMsg:function(a,b){if($type(b.maxLength)){return Form.Validator.getMsg("maxLength").substitute({maxLength:b.maxLength,length:a.get("value").length}); -}else{return"";}},test:function(a,b){return(a.get("value").length<=$pick(b.maxLength,10000));}}],["validate-integer",{errorMsg:Form.Validator.getMsg.pass("integer"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^(-?[1-9]\d*|0)$/).test(a.get("value")); -}}],["validate-numeric",{errorMsg:Form.Validator.getMsg.pass("numeric"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(a.get("value")); -}}],["validate-digits",{errorMsg:Form.Validator.getMsg.pass("digits"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^[\d() .:\-\+#]+$/.test(a.get("value"))); -}}],["validate-alpha",{errorMsg:Form.Validator.getMsg.pass("alpha"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^[a-zA-Z]+$/).test(a.get("value")); -}}],["validate-alphanum",{errorMsg:Form.Validator.getMsg.pass("alphanum"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||!(/\W/).test(a.get("value")); -}}],["validate-date",{errorMsg:function(a,b){if(Date.parse){var c=b.dateFormat||"%x";return Form.Validator.getMsg("dateSuchAs").substitute({date:new Date().format(c)}); -}else{return Form.Validator.getMsg("dateInFormatMDY");}},test:function(a,b){if(Form.Validator.getValidator("IsEmpty").test(a)){return true;}var h;if(Date.parse){var g=b.dateFormat||"%x"; -h=Date.parse(a.get("value"));var f=h.format(g);if(f!="invalid date"){a.set("value",f);}return !isNaN(h);}else{var c=/^(\d{2})\/(\d{2})\/(\d{4})$/;if(!c.test(a.get("value"))){return false; -}h=new Date(a.get("value").replace(c,"$1/$2/$3"));return(parseInt(RegExp.$1,10)==(1+h.getMonth()))&&(parseInt(RegExp.$2,10)==h.getDate())&&(parseInt(RegExp.$3,10)==h.getFullYear()); -}}}],["validate-email",{errorMsg:Form.Validator.getMsg.pass("email"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).test(a.get("value")); -}}],["validate-url",{errorMsg:Form.Validator.getMsg.pass("url"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i).test(a.get("value")); -}}],["validate-currency-dollar",{errorMsg:Form.Validator.getMsg.pass("currencyDollar"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(a.get("value")); -}}],["validate-one-required",{errorMsg:Form.Validator.getMsg.pass("oneRequired"),test:function(a,b){var c=document.id(b["validate-one-required"])||a.getParent(b["validate-one-required"]); -return c.getElements("input").some(function(d){if(["checkbox","radio"].contains(d.get("type"))){return d.get("checked");}return d.get("value");});}}]]); -Element.Properties.validator={set:function(a){var b=this.retrieve("validator");if(b){b.setOptions(a);}return this.store("validator:options",a);},get:function(a){if(a||!this.retrieve("validator")){if(a||!this.retrieve("validator:options")){this.set("validator",a); -}this.store("validator",new Form.Validator(this,this.retrieve("validator:options")));}return this.retrieve("validator");}};Element.implement({validate:function(a){if(a){this.set("validator",a); -}return this.get("validator",a).validate();}});var FormValidator=Form.Validator;Form.Validator.Inline=new Class({Extends:Form.Validator,options:{showError:function(a){if(a.reveal){a.reveal(); -}else{a.setStyle("display","block");}},hideError:function(a){if(a.dissolve){a.dissolve();}else{a.setStyle("display","none");}},scrollToErrorsOnSubmit:true,scrollToErrorsOnBlur:false,scrollToErrorsOnChange:false,scrollFxOptions:{transition:"quad:out",offset:{y:-20}}},initialize:function(b,a){this.parent(b,a); -this.addEvent("onElementValidate",function(h,g,f,i){var d=this.getValidator(f);if(!h&&d.getError(g)){if(i){g.addClass("warning");}var c=this.makeAdvice(f,g,d.getError(g),i); -this.insertAdvice(c,g);this.showAdvice(f,g);}else{this.hideAdvice(f,g);}});},makeAdvice:function(d,g,c,h){var f=(h)?this.warningPrefix:this.errorPrefix; -f+=(this.options.useTitles)?g.title||c:c;var a=(h)?"warning-advice":"validation-advice";var b=this.getAdvice(d,g);if(b){b=b.set("html",f);}else{b=new Element("div",{html:f,styles:{display:"none"},id:"advice-"+d.split(":")[0]+"-"+this.getFieldId(g)}).addClass(a); -}g.store("advice-"+d,b);return b;},getFieldId:function(a){return a.id?a.id:a.id="input_"+a.name;},showAdvice:function(b,c){var a=this.getAdvice(b,c);if(a&&!c.retrieve(this.getPropName(b))&&(a.getStyle("display")=="none"||a.getStyle("visiblity")=="hidden"||a.getStyle("opacity")==0)){c.store(this.getPropName(b),true); -this.options.showError(a);this.fireEvent("showAdvice",[c,a,b]);}},hideAdvice:function(b,c){var a=this.getAdvice(b,c);if(a&&c.retrieve(this.getPropName(b))){c.store(this.getPropName(b),false); -this.options.hideError(a);this.fireEvent("hideAdvice",[c,a,b]);}},getPropName:function(a){return"advice"+a;},resetField:function(a){a=document.id(a);if(!a){return this; -}this.parent(a);a.className.split(" ").each(function(b){this.hideAdvice(b,a);},this);return this;},getAllAdviceMessages:function(d,c){var b=[];if(d.hasClass("ignoreValidation")&&!c){return b; -}var a=d.className.split(" ").some(function(h){var f=h.test("^warn-")||d.hasClass("warnOnly");if(f){h=h.replace(/^warn-/,"");}var g=this.getValidator(h); -if(!g){return;}b.push({message:g.getError(d),warnOnly:f,passed:g.test(),validator:g});},this);return b;},getAdvice:function(a,b){return b.retrieve("advice-"+a); -},insertAdvice:function(a,c){var b=c.get("validatorProps");if(!b.msgPos||!document.id(b.msgPos)){if(c.type.toLowerCase()=="radio"){c.getParent().adopt(a); -}else{a.inject(document.id(c),"after");}}else{document.id(b.msgPos).grab(a);}},validateField:function(h,g,b){var a=this.parent(h,g);if(((this.options.scrollToErrorsOnSubmit&&b===undefined)||b)&&!a){var c=document.id(this).getElement(".validation-failed"); -var d=document.id(this).getParent();while(d!=document.body&&d.getScrollSize().y==d.getSize().y){d=d.getParent();}var f=d.retrieve("fvScroller");if(!f&&window.Fx&&Fx.Scroll){f=new Fx.Scroll(d,this.options.scrollFxOptions); -d.store("fvScroller",f);}if(c){if(f){f.toElement(c);}else{d.scrollTo(d.getScroll().x,c.getPosition(d).y-20);}}}return a;},watchFields:function(a){a.each(function(b){if(this.options.evaluateFieldsOnBlur){b.addEvent("blur",this.validationMonitor.pass([b,false,this.options.scrollToErrorsOnBlur],this)); -}if(this.options.evaluateFieldsOnChange){b.addEvent("change",this.validationMonitor.pass([b,true,this.options.scrollToErrorsOnChange],this));}},this);}}); -Form.Validator.addAllThese([["validate-enforce-oncheck",{test:function(a,b){var c=a.getParent("form").retrieve("validator");if(!c){return true;}(b.toEnforce||document.id(b.enforceChildrenOf).getElements("input, select, textarea")).map(function(d){if(a.checked){c.enforceField(d); -}else{c.ignoreField(d);c.resetField(d);}});return true;}}],["validate-ignore-oncheck",{test:function(a,b){var c=a.getParent("form").retrieve("validator"); -if(!c){return true;}(b.toIgnore||document.id(b.ignoreChildrenOf).getElements("input, select, textarea")).each(function(d){if(a.checked){c.ignoreField(d); -c.resetField(d);}else{c.enforceField(d);}});return true;}}],["validate-nospace",{errorMsg:function(){return Form.Validator.getMsg("noSpace");},test:function(a,b){return !a.get("value").test(/\s/); -}}],["validate-toggle-oncheck",{test:function(b,c){var d=b.getParent("form").retrieve("validator");if(!d){return true;}var a=c.toToggle||document.id(c.toToggleChildrenOf).getElements("input, select, textarea"); -if(!b.checked){a.each(function(f){d.ignoreField(f);d.resetField(f);});}else{a.each(function(f){d.enforceField(f);});}return true;}}],["validate-reqchk-bynode",{errorMsg:function(){return Form.Validator.getMsg("reqChkByNode"); -},test:function(a,b){return(document.id(b.nodeId).getElements(b.selector||"input[type=checkbox], input[type=radio]")).some(function(c){return c.checked; -});}}],["validate-required-check",{errorMsg:function(a,b){return b.useTitle?a.get("title"):Form.Validator.getMsg("requiredChk");},test:function(a,b){return !!a.checked; -}}],["validate-reqchk-byname",{errorMsg:function(a,b){return Form.Validator.getMsg("reqChkByName").substitute({label:b.label||a.get("type")});},test:function(b,d){var c=d.groupName||b.get("name"); -var a=$$(document.getElementsByName(c)).some(function(h,g){return h.checked;});var f=b.getParent("form").retrieve("validator");if(a&&f){f.resetField(b); -}return a;}}],["validate-match",{errorMsg:function(a,b){return Form.Validator.getMsg("match").substitute({matchName:b.matchName||document.id(b.matchInput).get("name")}); -},test:function(b,c){var d=b.get("value");var a=document.id(c.matchInput)&&document.id(c.matchInput).get("value");return d&&a?d==a:true;}}],["validate-after-date",{errorMsg:function(a,b){return Form.Validator.getMsg("afterDate").substitute({label:b.afterLabel||(b.afterElement?Form.Validator.getMsg("startDate"):Form.Validator.getMsg("currentDate"))}); -},test:function(b,c){var d=document.id(c.afterElement)?Date.parse(document.id(c.afterElement).get("value")):new Date();var a=Date.parse(b.get("value")); -return a&&d?a>=d:true;}}],["validate-before-date",{errorMsg:function(a,b){return Form.Validator.getMsg("beforeDate").substitute({label:b.beforeLabel||(b.beforeElement?Form.Validator.getMsg("endDate"):Form.Validator.getMsg("currentDate"))}); -},test:function(b,c){var d=Date.parse(b.get("value"));var a=document.id(c.beforeElement)?Date.parse(document.id(c.beforeElement).get("value")):new Date(); -return a&&d?a>=d:true;}}],["validate-custom-required",{errorMsg:function(){return Form.Validator.getMsg("required");},test:function(a,b){return a.get("value")!=b.emptyValue; -}}],["validate-same-month",{errorMsg:function(a,b){var c=document.id(b.sameMonthAs)&&document.id(b.sameMonthAs).get("value");var d=a.get("value");if(d!=""){return Form.Validator.getMsg(c?"sameMonth":"startMonth"); -}},test:function(a,b){var d=Date.parse(a.get("value"));var c=Date.parse(document.id(b.sameMonthAs)&&document.id(b.sameMonthAs).get("value"));return d&&c?d.format("%B")==c.format("%B"):true; -}}],["validate-cc-num",{errorMsg:function(a){var b=a.get("value").replace(/[^0-9]/g,"");return Form.Validator.getMsg("creditcard").substitute({length:b.length}); -},test:function(c){if(Form.Validator.getValidator("IsEmpty").test(c)){return true;}var h=c.get("value");h=h.replace(/[^0-9]/g,"");var a=false;if(h.test(/^4[0-9]{12}([0-9]{3})?$/)){a="Visa"; -}else{if(h.test(/^5[1-5]([0-9]{14})$/)){a="Master Card";}else{if(h.test(/^3[47][0-9]{13}$/)){a="American Express";}else{if(h.test(/^6011[0-9]{12}$/)){a="Discover"; -}}}}if(a){var d=0;var f=0;for(var b=h.length-1;b>=0;--b){f=h.charAt(b).toInt();if(f==0){continue;}if((h.length-b)%2==0){f+=f;}if(f>9){f=f.toString().charAt(0).toInt()+f.toString().charAt(1).toInt(); -}d+=f;}if((d%10)==0){return true;}}var g="";while(h!=""){g+=" "+h.substr(0,4);h=h.substr(4);}c.getParent("form").retrieve("validator").ignoreField(c);c.set("value",g.clean()); -c.getParent("form").retrieve("validator").enforceField(c);return false;}}]]);var OverText=new Class({Implements:[Options,Events,Class.Occlude],Binds:["reposition","assert","focus","hide"],options:{element:"label",positionOptions:{position:"upperLeft",edge:"upperLeft",offset:{x:4,y:2}},poll:false,pollInterval:250,wrap:false},property:"OverText",initialize:function(b,a){this.element=document.id(b); -if(this.occlude()){return this.occluded;}this.setOptions(a);this.attach(this.element);OverText.instances.push(this);if(this.options.poll){this.poll();}return this; -},toElement:function(){return this.element;},attach:function(){var a=this.options.textOverride||this.element.get("alt")||this.element.get("title");if(!a){return; -}this.text=new Element(this.options.element,{"class":"overTxtLabel",styles:{lineHeight:"normal",position:"absolute",cursor:"text"},html:a,events:{click:this.hide.pass(this.options.element=="label",this)}}).inject(this.element,"after"); -if(this.options.element=="label"){if(!this.element.get("id")){this.element.set("id","input_"+new Date().getTime());}this.text.set("for",this.element.get("id")); -}if(this.options.wrap){this.textHolder=new Element("div",{styles:{lineHeight:"normal",position:"relative"},"class":"overTxtWrapper"}).adopt(this.text).inject(this.element,"before"); -}return this.enable();},destroy:function(){this.element.eliminate("OverTextDiv").eliminate("OverText");this.disable();if(this.text){this.text.destroy(); -}if(this.textHolder){this.textHolder.destroy();}return this;},disable:function(){this.element.removeEvents({focus:this.focus,blur:this.assert,change:this.assert}); -window.removeEvent("resize",this.reposition);this.hide(true,true);return this;},enable:function(){this.element.addEvents({focus:this.focus,blur:this.assert,change:this.assert}); -window.addEvent("resize",this.reposition);this.assert(true);this.reposition();return this;},wrap:function(){if(this.options.element=="label"){if(!this.element.get("id")){this.element.set("id","input_"+new Date().getTime()); -}this.text.set("for",this.element.get("id"));}},startPolling:function(){this.pollingPaused=false;return this.poll();},poll:function(a){if(this.poller&&!a){return this; -}var b=function(){if(!this.pollingPaused){this.assert(true);}}.bind(this);if(a){$clear(this.poller);}else{this.poller=b.periodical(this.options.pollInterval,this); -}return this;},stopPolling:function(){this.pollingPaused=true;return this.poll(true);},focus:function(){if(this.text&&(!this.text.isDisplayed()||this.element.get("disabled"))){return; -}this.hide();},hide:function(c,a){if(this.text&&(this.text.isDisplayed()&&(!this.element.get("disabled")||a))){this.text.hide();this.fireEvent("textHide",[this.text,this.element]); -this.pollingPaused=true;if(!c){try{this.element.fireEvent("focus");this.element.focus();}catch(b){}}}return this;},show:function(){if(this.text&&!this.text.isDisplayed()){this.text.show(); -this.reposition();this.fireEvent("textShow",[this.text,this.element]);this.pollingPaused=false;}return this;},assert:function(a){this[this.test()?"show":"hide"](a); -},test:function(){var a=this.element.get("value");return !a;},reposition:function(){this.assert(true);if(!this.element.isVisible()){return this.stopPolling().hide(); -}if(this.text&&this.test()){this.text.position($merge(this.options.positionOptions,{relativeTo:this.element}));}return this;}});OverText.instances=[];$extend(OverText,{each:function(a){return OverText.instances.map(function(c,b){if(c.element&&c.text){return a.apply(OverText,[c,b]); -}return null;});},update:function(){return OverText.each(function(a){return a.reposition();});},hideAll:function(){return OverText.each(function(a){return a.hide(true,true); -});},showAll:function(){return OverText.each(function(a){return a.show();});}});if(window.Fx&&Fx.Reveal){Fx.Reveal.implement({hideInputs:Browser.Engine.trident?"select, input, textarea, object, embed, .overTxtLabel":false}); -}Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(b,a){this.elements=this.subject=$$(b);this.parent(a);},compute:function(h,j,k){var c={};for(var d in h){var a=h[d],f=j[d],g=c[d]={}; -for(var b in a){g[b]=this.parent(a[b],f[b],k);}}return c;},set:function(b){for(var c in b){if(!this.elements[c]){continue;}var a=b[c];for(var d in a){this.render(this.elements[c],d,a[d],this.options.unit); -}}return this;},start:function(c){if(!this.check(c)){return this;}var j={},k={};for(var d in c){if(!this.elements[d]){continue;}var g=c[d],a=j[d]={},h=k[d]={}; -for(var b in g){var f=this.prepare(this.elements[d],b,g[b]);a[b]=f.from;h[b]=f.to;}}return this.parent(j,k);}});Fx.Accordion=new Class({Extends:Fx.Elements,options:{fixedHeight:false,fixedWidth:false,display:0,show:false,height:true,width:false,opacity:true,alwaysHide:false,trigger:"click",initialDisplayFx:true,returnHeightToAuto:true},initialize:function(){var c=Array.link(arguments,{container:Element.type,options:Object.type,togglers:$defined,elements:$defined}); -this.parent(c.elements,c.options);this.togglers=$$(c.togglers);this.previous=-1;this.internalChain=new Chain();if(this.options.alwaysHide){this.options.wait=true; -}if($chk(this.options.show)){this.options.display=false;this.previous=this.options.show;}if(this.options.start){this.options.display=false;this.options.show=false; -}this.effects={};if(this.options.opacity){this.effects.opacity="fullOpacity";}if(this.options.width){this.effects.width=this.options.fixedWidth?"fullWidth":"offsetWidth"; -}if(this.options.height){this.effects.height=this.options.fixedHeight?"fullHeight":"scrollHeight";}for(var b=0,a=this.togglers.length;b=0?a-1:0)).chain(d);}else{d();}return this;},detach:function(b){var a=function(c){c.removeEvent(this.options.trigger,c.retrieve("accordion:display")); -}.bind(this);if(!b){this.togglers.each(a);}else{a(b);}return this;},display:function(a,b){if(!this.check(a,b)){return this;}b=$pick(b,true);a=($type(a)=="element")?this.elements.indexOf(a):a; -if(a==this.previous&&!this.options.alwaysHide){return this;}if(this.options.returnHeightToAuto){var d=this.elements[this.previous];if(d&&!this.selfHidden){for(var c in this.effects){d.setStyle(c,d[this.effects[c]]); -}}}if((this.timer&&this.options.wait)||(a===this.previous&&!this.options.alwaysHide)){return this;}this.previous=a;var f={};this.elements.each(function(j,h){f[h]={}; -var g;if(h!=a){g=true;}else{if(this.options.alwaysHide&&((j.offsetHeight>0&&this.options.height)||j.offsetWidth>0&&this.options.width)){g=true;this.selfHidden=true; -}}this.fireEvent(g?"background":"active",[this.togglers[h],j]);for(var k in this.effects){f[h][k]=g?0:j[this.effects[k]];}},this);this.internalChain.clearChain(); -this.internalChain.chain(function(){if(this.options.returnHeightToAuto&&!this.selfHidden){var g=this.elements[a];if(g){g.setStyle("height","auto");}}}.bind(this)); -return b?this.start(f):this.set(f);}});var Accordion=new Class({Extends:Fx.Accordion,initialize:function(){this.parent.apply(this,arguments);var a=Array.link(arguments,{container:Element.type}); -this.container=a.container;},addSection:function(c,b,f){c=document.id(c);b=document.id(b);var d=this.togglers.contains(c);var a=this.togglers.length;if(a&&(!d||f)){f=$pick(f,a-1); -c.inject(this.togglers[f],"before");b.inject(c,"after");}else{if(this.container&&!d){c.inject(this.container);b.inject(this.container);}}return this.parent.apply(this,arguments); -}});Fx.Move=new Class({Extends:Fx.Morph,options:{relativeTo:document.body,position:"center",edge:false,offset:{x:0,y:0}},start:function(a){var b=this.element,c=b.getStyles("top","left"); -if(c.top=="auto"||c.left=="auto"){b.setPosition(b.getPosition(b.getOffsetParent()));}return this.parent(b.position($merge(this.options,a,{returnPos:true}))); -}});Element.Properties.move={set:function(a){var b=this.retrieve("move");if(b){b.cancel();}return this.eliminate("move").store("move:options",$extend({link:"cancel"},a)); -},get:function(a){if(a||!this.retrieve("move")){if(a||!this.retrieve("move:options")){this.set("move",a);}this.store("move",new Fx.Move(this,this.retrieve("move:options"))); -}return this.retrieve("move");}};Element.implement({move:function(a){this.get("move").start(a);return this;}});Fx.Reveal=new Class({Extends:Fx.Morph,options:{link:"cancel",styles:["padding","border","margin"],transitionOpacity:!Browser.Engine.trident4,mode:"vertical",display:function(){return this.element.get("tag")!="tr"?"block":"table-row"; -},hideInputs:Browser.Engine.trident?"select, input, textarea, object, embed":false,opacity:1},dissolve:function(){try{if(!this.hiding&&!this.showing){if(this.element.getStyle("display")!="none"){this.hiding=true; -this.showing=false;this.hidden=true;this.cssText=this.element.style.cssText;var d=this.element.getComputedSize({styles:this.options.styles,mode:this.options.mode}); -this.element.setStyle("display",$lambda(this.options.display).apply(this));if(this.options.transitionOpacity){d.opacity=this.options.opacity;}var b={}; -$each(d,function(g,f){b[f]=[g,0];},this);this.element.setStyle("overflow","hidden");var a=this.options.hideInputs?this.element.getElements(this.options.hideInputs):null; -this.$chain.unshift(function(){if(this.hidden){this.hiding=false;$each(d,function(g,f){d[f]=g;},this);this.element.style.cssText=this.cssText;this.element.setStyle("display","none"); -if(a){a.setStyle("visibility","visible");}}this.fireEvent("hide",this.element);this.callChain();}.bind(this));if(a){a.setStyle("visibility","hidden");}this.start(b); -}else{this.callChain.delay(10,this);this.fireEvent("complete",this.element);this.fireEvent("hide",this.element);}}else{if(this.options.link=="chain"){this.chain(this.dissolve.bind(this)); -}else{if(this.options.link=="cancel"&&!this.hiding){this.cancel();this.dissolve();}}}}catch(c){this.hiding=false;this.element.setStyle("display","none"); -this.callChain.delay(10,this);this.fireEvent("complete",this.element);this.fireEvent("hide",this.element);}return this;},reveal:function(){try{if(!this.showing&&!this.hiding){if(this.element.getStyle("display")=="none"){this.showing=true; -this.hiding=this.hidden=false;var d;this.cssText=this.element.style.cssText;this.element.measure(function(){d=this.element.getComputedSize({styles:this.options.styles,mode:this.options.mode}); -}.bind(this));$each(d,function(g,f){d[f]=g;});if($chk(this.options.heightOverride)){d.height=this.options.heightOverride.toInt();}if($chk(this.options.widthOverride)){d.width=this.options.widthOverride.toInt(); -}if(this.options.transitionOpacity){this.element.setStyle("opacity",0);d.opacity=this.options.opacity;}var b={height:0,display:$lambda(this.options.display).apply(this)}; -$each(d,function(g,f){b[f]=0;});this.element.setStyles($merge(b,{overflow:"hidden"}));var a=this.options.hideInputs?this.element.getElements(this.options.hideInputs):null; -if(a){a.setStyle("visibility","hidden");}this.start(d);this.$chain.unshift(function(){this.element.style.cssText=this.cssText;this.element.setStyle("display",$lambda(this.options.display).apply(this)); -if(!this.hidden){this.showing=false;}if(a){a.setStyle("visibility","visible");}this.callChain();this.fireEvent("show",this.element);}.bind(this));}else{this.callChain(); -this.fireEvent("complete",this.element);this.fireEvent("show",this.element);}}else{if(this.options.link=="chain"){this.chain(this.reveal.bind(this));}else{if(this.options.link=="cancel"&&!this.showing){this.cancel(); -this.reveal();}}}}catch(c){this.element.setStyles({display:$lambda(this.options.display).apply(this),visiblity:"visible",opacity:this.options.opacity}); -this.showing=false;this.callChain.delay(10,this);this.fireEvent("complete",this.element);this.fireEvent("show",this.element);}return this;},toggle:function(){if(this.element.getStyle("display")=="none"){this.reveal(); -}else{this.dissolve();}return this;},cancel:function(){this.parent.apply(this,arguments);this.element.style.cssText=this.cssText;this.hiding=false;this.showing=false; -return this;}});Element.Properties.reveal={set:function(a){var b=this.retrieve("reveal");if(b){b.cancel();}return this.eliminate("reveal").store("reveal:options",a); -},get:function(a){if(a||!this.retrieve("reveal")){if(a||!this.retrieve("reveal:options")){this.set("reveal",a);}this.store("reveal",new Fx.Reveal(this,this.retrieve("reveal:options"))); -}return this.retrieve("reveal");}};Element.Properties.dissolve=Element.Properties.reveal;Element.implement({reveal:function(a){this.get("reveal",a).reveal(); -return this;},dissolve:function(a){this.get("reveal",a).dissolve();return this;},nix:function(){var a=Array.link(arguments,{destroy:Boolean.type,options:Object.type}); -this.get("reveal",a.options).dissolve().chain(function(){this[a.destroy?"destroy":"dispose"]();}.bind(this));return this;},wink:function(){var b=Array.link(arguments,{duration:Number.type,options:Object.type}); -var a=this.get("reveal",b.options);a.reveal().chain(function(){(function(){a.dissolve();}).delay(b.duration||2000);});}});Fx.Scroll=new Class({Extends:Fx,options:{offset:{x:0,y:0},wheelStops:true},initialize:function(b,a){this.element=this.subject=document.id(b); -this.parent(a);var d=this.cancel.bind(this,false);if($type(this.element)!="element"){this.element=document.id(this.element.getDocument().body);}var c=this.element; -if(this.options.wheelStops){this.addEvent("start",function(){c.addEvent("mousewheel",d);},true);this.addEvent("complete",function(){c.removeEvent("mousewheel",d); -},true);}},set:function(){var a=Array.flatten(arguments);if(Browser.Engine.gecko){a=[Math.round(a[0]),Math.round(a[1])];}this.element.scrollTo(a[0]+this.options.offset.x,a[1]+this.options.offset.y); -},compute:function(c,b,a){return[0,1].map(function(d){return Fx.compute(c[d],b[d],a);});},start:function(c,h){if(!this.check(c,h)){return this;}var f=this.element.getScrollSize(),b=this.element.getScroll(),d={x:c,y:h}; -for(var g in d){var a=f[g];if($chk(d[g])){d[g]=($type(d[g])=="number")?d[g]:a;}else{d[g]=b[g];}d[g]+=this.options.offset[g];}return this.parent([b.x,b.y],[d.x,d.y]); -},toTop:function(){return this.start(false,0);},toLeft:function(){return this.start(0,false);},toRight:function(){return this.start("right",false);},toBottom:function(){return this.start(false,"bottom"); -},toElement:function(b){var a=document.id(b).getPosition(this.element);return this.start(a.x,a.y);},scrollIntoView:function(c,f,d){f=f?$splat(f):["x","y"]; -var i={};c=document.id(c);var g=c.getPosition(this.element);var j=c.getSize();var h=this.element.getScroll();var a=this.element.getSize();var b={x:g.x+j.x,y:g.y+j.y}; -["x","y"].each(function(k){if(f.contains(k)){if(b[k]>h[k]+a[k]){i[k]=b[k]-a[k];}if(g[k]this.elements.length){f.splice(this.elements.length-1,f.length-this.elements.length); -}}var b=j=a=0;f.each(function(m,k){var l={};if(d){l.top=j-g[m].top-b;j+=g[m].height;}else{l.left=a-g[m].left;a+=g[m].width;}b=b+g[m].margin;c[m]=l;},this); -var h={};$A(f).sort().each(function(k){h[k]=c[k];});this.start(h);this.currentOrder=f;return this;},rearrangeDOM:function(a){a=a||this.currentOrder;var b=this.elements[0].getParent(); -var c=[];this.elements.setStyle("opacity",0);a.each(function(d){c.push(this.elements[d].inject(b).setStyles({top:0,left:0}));},this);this.elements.setStyle("opacity",1); -this.elements=$$(c);this.setDefaultOrder();return this;},getDefaultOrder:function(){return this.elements.map(function(b,a){return a;});},forward:function(){return this.sort(this.getDefaultOrder()); -},backward:function(){return this.sort(this.getDefaultOrder().reverse());},reverse:function(){return this.sort(this.currentOrder.reverse());},sortByElements:function(a){return this.sort(a.map(function(b){return this.elements.indexOf(b); -},this));},swap:function(c,b){if($type(c)=="element"){c=this.elements.indexOf(c);}if($type(b)=="element"){b=this.elements.indexOf(b);}var a=$A(this.currentOrder); -a[this.currentOrder.indexOf(c)]=b;a[this.currentOrder.indexOf(b)]=c;return this.sort(a);}});var Drag=new Class({Implements:[Events,Options],options:{snap:6,unit:"px",grid:false,style:true,limit:false,handle:false,invert:false,preventDefault:false,stopPropagation:false,modifiers:{x:"left",y:"top"}},initialize:function(){var b=Array.link(arguments,{options:Object.type,element:$defined}); -this.element=document.id(b.element);this.document=this.element.getDocument();this.setOptions(b.options||{});var a=$type(this.options.handle);this.handles=((a=="array"||a=="collection")?$$(this.options.handle):document.id(this.options.handle))||this.element; -this.mouse={now:{},pos:{}};this.value={start:{},now:{}};this.selection=(Browser.Engine.trident)?"selectstart":"mousedown";this.bound={start:this.start.bind(this),check:this.check.bind(this),drag:this.drag.bind(this),stop:this.stop.bind(this),cancel:this.cancel.bind(this),eventStop:$lambda(false)}; -this.attach();},attach:function(){this.handles.addEvent("mousedown",this.bound.start);return this;},detach:function(){this.handles.removeEvent("mousedown",this.bound.start); -return this;},start:function(f){if(f.rightClick){return;}if(this.options.preventDefault){f.preventDefault();}if(this.options.stopPropagation){f.stopPropagation(); -}this.mouse.start=f.page;this.fireEvent("beforeStart",this.element);var a=this.options.limit;this.limit={x:[],y:[]};var d=this.element.getStyles("left","right","top","bottom"); -this._invert={x:this.options.modifiers.x=="left"&&d.left=="auto"&&!isNaN(d.right.toInt())&&(this.options.modifiers.x="right"),y:this.options.modifiers.y=="top"&&d.top=="auto"&&!isNaN(d.bottom.toInt())&&(this.options.modifiers.y="bottom")}; -var h,g;for(h in this.options.modifiers){if(!this.options.modifiers[h]){continue;}var c=this.element.getStyle(this.options.modifiers[h]);if(c&&!c.match(/px$/)){if(!g){g=this.element.getCoordinates(this.element.getOffsetParent()); -}c=g[this.options.modifiers[h]];}if(this.options.style){this.value.now[h]=(c||0).toInt();}else{this.value.now[h]=this.element[this.options.modifiers[h]]; -}if(this.options.invert){this.value.now[h]*=-1;}if(this._invert[h]){this.value.now[h]*=-1;}this.mouse.pos[h]=f.page[h]-this.value.now[h];if(a&&a[h]){for(var b=2; -b--;b){if($chk(a[h][b])){this.limit[h][b]=$lambda(a[h][b])();}}}}if($type(this.options.grid)=="number"){this.options.grid={x:this.options.grid,y:this.options.grid}; -}this.document.addEvents({mousemove:this.bound.check,mouseup:this.bound.cancel});this.document.addEvent(this.selection,this.bound.eventStop);},check:function(a){if(this.options.preventDefault){a.preventDefault(); -}var b=Math.round(Math.sqrt(Math.pow(a.page.x-this.mouse.start.x,2)+Math.pow(a.page.y-this.mouse.start.y,2)));if(b>this.options.snap){this.cancel();this.document.addEvents({mousemove:this.bound.drag,mouseup:this.bound.stop}); -this.fireEvent("start",[this.element,a]).fireEvent("snap",this.element);}},drag:function(a){if(this.options.preventDefault){a.preventDefault();}this.mouse.now=a.page; -for(var b in this.options.modifiers){if(!this.options.modifiers[b]){continue;}this.value.now[b]=this.mouse.now[b]-this.mouse.pos[b];if(this.options.invert){this.value.now[b]*=-1; -}if(this._invert[b]){this.value.now[b]*=-1;}if(this.options.limit&&this.limit[b]){if($chk(this.limit[b][1])&&(this.value.now[b]>this.limit[b][1])){this.value.now[b]=this.limit[b][1]; -}else{if($chk(this.limit[b][0])&&(this.value.now[b]c.left&&a.xc.top);},checkDroppables:function(){var a=this.droppables.filter(this.checkAgainst,this).getLast(); -if(this.overed!=a){if(this.overed){this.fireEvent("leave",[this.element,this.overed]);}if(a){this.fireEvent("enter",[this.element,a]);}this.overed=a;}},drag:function(a){this.parent(a); -if(this.options.checkDroppables&&this.droppables.length){this.checkDroppables();}},stop:function(a){this.checkDroppables();this.fireEvent("drop",[this.element,this.overed,a]); -this.overed=null;return this.parent(a);}});Element.implement({makeDraggable:function(a){var b=new Drag.Move(this,a);this.store("dragger",b);return b;}}); -var Slider=new Class({Implements:[Events,Options],Binds:["clickedElement","draggedKnob","scrolledElement"],options:{onTick:function(a){if(this.options.snap){a=this.toPosition(this.step); -}this.knob.setStyle(this.property,a);},initialStep:0,snap:false,offset:0,range:false,wheel:false,steps:100,mode:"horizontal"},initialize:function(g,a,f){this.setOptions(f); -this.element=document.id(g);this.knob=document.id(a);this.previousChange=this.previousEnd=this.step=-1;var h,b={},d={x:false,y:false};switch(this.options.mode){case"vertical":this.axis="y"; -this.property="top";h="offsetHeight";break;case"horizontal":this.axis="x";this.property="left";h="offsetWidth";}this.full=this.element.measure(function(){this.half=this.knob[h]/2; -return this.element[h]-this.knob[h]+(this.options.offset*2);}.bind(this));this.setRange(this.options.range);this.knob.setStyle("position","relative").setStyle(this.property,-this.options.offset); -d[this.axis]=this.property;b[this.axis]=[-this.options.offset,this.full-this.options.offset];var c={snap:0,limit:b,modifiers:d,onDrag:this.draggedKnob,onStart:this.draggedKnob,onBeforeStart:(function(){this.isDragging=true; -}).bind(this),onCancel:function(){this.isDragging=false;}.bind(this),onComplete:function(){this.isDragging=false;this.draggedKnob();this.end();}.bind(this)}; -if(this.options.snap){c.grid=Math.ceil(this.stepWidth);c.limit[this.axis][1]=this.full;}this.drag=new Drag(this.knob,c);this.attach();if(this.options.initialStep!=null){this.set(this.options.initialStep); -}},attach:function(){this.element.addEvent("mousedown",this.clickedElement);if(this.options.wheel){this.element.addEvent("mousewheel",this.scrolledElement); -}this.drag.attach();return this;},detach:function(){this.element.removeEvent("mousedown",this.clickedElement);this.element.removeEvent("mousewheel",this.scrolledElement); -this.drag.detach();return this;},set:function(a){if(!((this.range>0)^(a0)^(a>this.max))){a=this.max;}this.step=Math.round(a); -this.checkStep();this.fireEvent("tick",this.toPosition(this.step));this.end();return this;},setRange:function(a,b){this.min=$pick(a[0],0);this.max=$pick(a[1],this.options.steps); -this.range=this.max-this.min;this.steps=this.options.steps||this.full;this.stepSize=Math.abs(this.range)/this.steps;this.stepWidth=this.stepSize*this.full/Math.abs(this.range); -this.set($pick(b,this.step).floor(this.min).max(this.max));return this;},clickedElement:function(c){if(this.isDragging||c.target==this.knob){return;}var b=this.range<0?-1:1; -var a=c.page[this.axis]-this.element.getPosition()[this.axis]-this.half;a=a.limit(-this.options.offset,this.full-this.options.offset);this.step=Math.round(this.min+b*this.toStep(a)); -this.checkStep();this.fireEvent("tick",a);this.end();},scrolledElement:function(a){var b=(this.options.mode=="horizontal")?(a.wheel<0):(a.wheel>0);this.set(b?this.step-this.stepSize:this.step+this.stepSize); -a.stop();},draggedKnob:function(){var b=this.range<0?-1:1;var a=this.drag.value.now[this.axis];a=a.limit(-this.options.offset,this.full-this.options.offset); -this.step=Math.round(this.min+b*this.toStep(a));this.checkStep();},checkStep:function(){if(this.previousChange!=this.step){this.previousChange=this.step; -this.fireEvent("change",this.step);}},end:function(){if(this.previousEnd!==this.step){this.previousEnd=this.step;this.fireEvent("complete",this.step+""); -}},toStep:function(a){var b=(a+this.options.offset)*this.stepSize/this.full*this.steps;return this.options.steps?Math.round(b-=b%this.stepSize):b;},toPosition:function(a){return(this.full*Math.abs(this.min-a))/(this.steps*this.stepSize)-this.options.offset; -}});var Sortables=new Class({Implements:[Events,Options],options:{snap:4,opacity:1,clone:false,revert:false,handle:false,constrain:false,preventDefault:false},initialize:function(a,b){this.setOptions(b); -this.elements=[];this.lists=[];this.idle=true;this.addLists($$(document.id(a)||a));if(!this.options.clone){this.options.revert=false;}if(this.options.revert){this.effect=new Fx.Morph(null,$merge({duration:250,link:"cancel"},this.options.revert)); -}},attach:function(){this.addLists(this.lists);return this;},detach:function(){this.lists=this.removeLists(this.lists);return this;},addItems:function(){Array.flatten(arguments).each(function(a){this.elements.push(a); -var b=a.retrieve("sortables:start",this.start.bindWithEvent(this,a));(this.options.handle?a.getElement(this.options.handle)||a:a).addEvent("mousedown",b); -},this);return this;},addLists:function(){Array.flatten(arguments).each(function(a){this.lists.push(a);this.addItems(a.getChildren());},this);return this; -},removeItems:function(){return $$(Array.flatten(arguments).map(function(a){this.elements.erase(a);var b=a.retrieve("sortables:start");(this.options.handle?a.getElement(this.options.handle)||a:a).removeEvent("mousedown",b); -return a;},this));},removeLists:function(){return $$(Array.flatten(arguments).map(function(a){this.lists.erase(a);this.removeItems(a.getChildren());return a; -},this));},getClone:function(b,a){if(!this.options.clone){return new Element(a.tagName).inject(document.body);}if($type(this.options.clone)=="function"){return this.options.clone.call(this,b,a,this.list); -}var c=a.clone(true).setStyles({margin:"0px",position:"absolute",visibility:"hidden",width:a.getStyle("width")});if(c.get("html").test("radio")){c.getElements("input[type=radio]").each(function(d,f){d.set("name","clone_"+f); -if(d.get("checked")){a.getElements("input[type=radio]")[f].set("checked",true);}});}return c.inject(this.list).setPosition(a.getPosition(a.getOffsetParent())); -},getDroppables:function(){var a=this.list.getChildren();if(!this.options.constrain){a=this.lists.concat(a).erase(this.list);}return a.erase(this.clone).erase(this.element); -},insert:function(c,b){var a="inside";if(this.lists.contains(b)){this.list=b;this.drag.droppables=this.getDroppables();}else{a=this.element.getAllPrevious().contains(b)?"before":"after"; -}this.element.inject(b,a);this.fireEvent("sort",[this.element,this.clone]);},start:function(b,a){if(!this.idle||b.rightClick||["button","input"].contains(document.id(b.target).get("tag"))){return; -}this.idle=false;this.element=a;this.opacity=a.get("opacity");this.list=a.getParent();this.clone=this.getClone(b,a);this.drag=new Drag.Move(this.clone,{preventDefault:this.options.preventDefault,snap:this.options.snap,container:this.options.constrain&&this.element.getParent(),droppables:this.getDroppables(),onSnap:function(){b.stop(); -this.clone.setStyle("visibility","visible");this.element.set("opacity",this.options.opacity||0);this.fireEvent("start",[this.element,this.clone]);}.bind(this),onEnter:this.insert.bind(this),onCancel:this.reset.bind(this),onComplete:this.end.bind(this)}); -this.clone.inject(this.element,"before");this.drag.start(b);},end:function(){this.drag.detach();this.element.set("opacity",this.opacity);if(this.effect){var a=this.element.getStyles("width","height"); -var b=this.clone.computePosition(this.element.getPosition(this.clone.getOffsetParent()));this.effect.element=this.clone;this.effect.start({top:b.top,left:b.left,width:a.width,height:a.height,opacity:0.25}).chain(this.reset.bind(this)); -}else{this.reset();}},reset:function(){this.idle=true;this.clone.destroy();this.fireEvent("complete",this.element);},serialize:function(){var c=Array.link(arguments,{modifier:Function.type,index:$defined}); -var b=this.lists.map(function(d){return d.getChildren().map(c.modifier||function(f){return f.get("id");},this);},this);var a=c.index;if(this.lists.length==1){a=0; -}return $chk(a)&&a>=0&&a2083){this.log("JSONP "+f+" will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs"); -}var a=new Element("script",{type:"text/javascript",src:f});Request.JSONP.request_map["request_"+b]=function(){this.success(arguments,a);}.bind(this);return a.inject(this.options.injectScript); -},success:function(b,a){if(!this.running){return false;}if(a){a.destroy();}this.running=false;this.log("JSONP successfully retrieved: ",b);this.fireEvent("complete",b).fireEvent("success",b).callChain(); -}});Request.JSONP.counter=0;Request.JSONP.request_map={};Request.Queue=new Class({Implements:[Options,Events],Binds:["attach","request","complete","cancel","success","failure","exception"],options:{stopOnFailure:true,autoAdvance:true,concurrent:1,requests:{}},initialize:function(a){if(a){var b=a.requests; -delete a.requests;}this.setOptions(a);this.requests=new Hash;this.queue=[];this.reqBinders={};if(b){this.addRequests(b);}},addRequest:function(a,b){this.requests.set(a,b); -this.attach(a,b);return this;},addRequests:function(a){$each(a,function(c,b){this.addRequest(b,c);},this);return this;},getName:function(a){return this.requests.keyOf(a); -},attach:function(a,b){if(b._groupSend){return this;}["request","complete","cancel","success","failure","exception"].each(function(c){if(!this.reqBinders[a]){this.reqBinders[a]={}; -}this.reqBinders[a][c]=function(){this["on"+c.capitalize()].apply(this,[a,b].extend(arguments));}.bind(this);b.addEvent(c,this.reqBinders[a][c]);},this); -b._groupSend=b.send;b.send=function(c){this.send(a,c);return b;}.bind(this);return this;},removeRequest:function(b){var a=$type(b)=="object"?this.getName(b):b; -if(!a&&$type(a)!="string"){return this;}b=this.requests.get(a);if(!b){return this;}["request","complete","cancel","success","failure","exception"].each(function(c){b.removeEvent(c,this.reqBinders[a][c]); -},this);b.send=b._groupSend;delete b._groupSend;return this;},getRunning:function(){return this.requests.filter(function(a){return a.running;});},isRunning:function(){return !!(this.getRunning().getKeys().length); -},send:function(b,a){var c=function(){this.requests.get(b)._groupSend(a);this.queue.erase(c);}.bind(this);c.name=b;if(this.getRunning().getKeys().length>=this.options.concurrent||(this.error&&this.options.stopOnFailure)){this.queue.push(c); -}else{c();}return this;},hasNext:function(a){return(!a)?!!this.queue.length:!!this.queue.filter(function(b){return b.name==a;}).length;},resume:function(){this.error=false; -(this.options.concurrent-this.getRunning().getKeys().length).times(this.runNext,this);return this;},runNext:function(a){if(!this.queue.length){return this; -}if(!a){this.queue[0]();}else{var b;this.queue.each(function(c){if(!b&&c.name==a){b=true;c();}});}return this;},runAll:function(){this.queue.each(function(a){a(); -});return this;},clear:function(a){if(!a){this.queue.empty();}else{this.queue=this.queue.map(function(b){if(b.name!=a){return b;}else{return false;}}).filter(function(b){return b; -});}return this;},cancel:function(a){this.requests.get(a).cancel();return this;},onRequest:function(){this.fireEvent("request",arguments);},onComplete:function(){this.fireEvent("complete",arguments); -if(!this.queue.length){this.fireEvent("end");}},onCancel:function(){if(this.options.autoAdvance&&!this.error){this.runNext();}this.fireEvent("cancel",arguments); -},onSuccess:function(){if(this.options.autoAdvance&&!this.error){this.runNext();}this.fireEvent("success",arguments);},onFailure:function(){this.error=true; -if(!this.options.stopOnFailure&&this.options.autoAdvance){this.runNext();}this.fireEvent("failure",arguments);},onException:function(){this.error=true; -if(!this.options.stopOnFailure&&this.options.autoAdvance){this.runNext();}this.fireEvent("exception",arguments);}});Request.implement({options:{initialDelay:5000,delay:5000,limit:60000},startTimer:function(b){var a=function(){if(!this.running){this.send({data:b}); -}};this.timer=a.delay(this.options.initialDelay,this);this.lastDelay=this.options.initialDelay;this.completeCheck=function(c){$clear(this.timer);this.lastDelay=(c)?this.options.delay:(this.lastDelay+this.options.delay).min(this.options.limit); -this.timer=a.delay(this.lastDelay,this);};return this.addEvent("complete",this.completeCheck);},stopTimer:function(){$clear(this.timer);return this.removeEvent("complete",this.completeCheck); -}});var Asset={javascript:function(g,d){d=$extend({onload:$empty,document:document,check:$lambda(true)},d);if(d.onLoad){d.onload=d.onLoad;delete d.onLoad; -}var b=new Element("script",{src:g,type:"text/javascript"});var f=d.onload.bind(b),a=d.check,h=d.document;delete d.onload;delete d.check;delete d.document; -b.addEvents({load:f,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){f();}}}).set(d);if(Browser.Engine.webkit419){var c=(function(){if(!$try(a)){return; -}$clear(c);f();}).periodical(50);}return b.inject(h.head);},css:function(b,a){a=a||{};var c=a.onload||a.onLoad;if(c){a.events=a.events||{};a.events.load=c; -delete a.onload;delete a.onLoad;}return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:b},a)).inject(document.head);},image:function(c,b){b=$merge({onload:$empty,onabort:$empty,onerror:$empty},b); -var d=new Image();var a=document.id(d)||new Element("img");["load","abort","error"].each(function(f){var h="on"+f;var g=f.capitalize();if(b["on"+g]){b[h]=b["on"+g]; -delete b["on"+g];}var i=b[h];delete b[h];d[h]=function(){if(!d){return;}if(!a.parentNode){a.width=d.width;a.height=d.height;}d=d.onload=d.onabort=d.onerror=null; -i.delay(1,a,a);a.fireEvent(f,a,1);};});d.src=a.src=c;if(d&&d.complete){d.onload.delay(1);}return a.set(b);},images:function(d,c){c=$merge({onComplete:$empty,onProgress:$empty,onError:$empty,properties:{}},c); -d=$splat(d);var a=[];var b=0;return new Elements(d.map(function(g,f){return Asset.image(g,$extend(c.properties,{onload:function(){c.onProgress.call(this,b,f); -b++;if(b==d.length){c.onComplete();}},onerror:function(){c.onError.call(this,b,f);b++;if(b==d.length){c.onComplete();}}}));}));}};var Color=new Native({initialize:function(b,c){if(arguments.length>=3){c="rgb"; -b=Array.slice(arguments,0,3);}else{if(typeof b=="string"){if(b.match(/rgb/)){b=b.rgbToHex().hexToRgb(true);}else{if(b.match(/hsb/)){b=b.hsbToRgb();}else{b=b.hexToRgb(true); -}}}}c=c||"rgb";switch(c){case"hsb":var a=b;b=b.hsbToRgb();b.hsb=a;break;case"hex":b=b.hexToRgb(true);break;}b.rgb=b.slice(0,3);b.hsb=b.hsb||b.rgbToHsb(); -b.hex=b.rgbToHex();return $extend(b,this);}});Color.implement({mix:function(){var a=Array.slice(arguments);var c=($type(a.getLast())=="number")?a.pop():50; -var b=this.slice();a.each(function(d){d=new Color(d);for(var f=0;f<3;f++){b[f]=Math.round((b[f]/100*(100-c))+(d[f]/100*c));}});return new Color(b,"rgb"); -},invert:function(){return new Color(this.map(function(a){return 255-a;}));},setHue:function(a){return new Color([a,this.hsb[1],this.hsb[2]],"hsb");},setSaturation:function(a){return new Color([this.hsb[0],a,this.hsb[2]],"hsb"); -},setBrightness:function(a){return new Color([this.hsb[0],this.hsb[1],a],"hsb");}});var $RGB=function(d,c,a){return new Color([d,c,a],"rgb");};var $HSB=function(d,c,a){return new Color([d,c,a],"hsb"); -};var $HEX=function(a){return new Color(a,"hex");};Array.implement({rgbToHsb:function(){var b=this[0],c=this[1],k=this[2],h=0;var j=Math.max(b,c,k),f=Math.min(b,c,k); -var l=j-f;var i=j/255,g=(j!=0)?l/j:0;if(g!=0){var d=(j-b)/l;var a=(j-c)/l;var m=(j-k)/l;if(b==j){h=m-a;}else{if(c==j){h=2+d-m;}else{h=4+a-d;}}h/=6;if(h<0){h++; -}}return[Math.round(h*360),Math.round(g*100),Math.round(i*100)];},hsbToRgb:function(){var c=Math.round(this[2]/100*255);if(this[1]==0){return[c,c,c];}else{var a=this[0]%360; -var g=a%60;var h=Math.round((this[2]*(100-this[1]))/10000*255);var d=Math.round((this[2]*(6000-this[1]*g))/600000*255);var b=Math.round((this[2]*(6000-this[1]*(60-g)))/600000*255); -switch(Math.floor(a/60)){case 0:return[c,b,h];case 1:return[d,c,h];case 2:return[h,c,b];case 3:return[h,d,c];case 4:return[b,h,c];case 5:return[c,h,d]; -}}return false;}});String.implement({rgbToHsb:function(){var a=this.match(/\d{1,3}/g);return(a)?a.rgbToHsb():null;},hsbToRgb:function(){var a=this.match(/\d{1,3}/g); -return(a)?a.hsbToRgb():null;}});var Group=new Class({initialize:function(){this.instances=Array.flatten(arguments);this.events={};this.checker={};},addEvent:function(b,a){this.checker[b]=this.checker[b]||{}; -this.events[b]=this.events[b]||[];if(this.events[b].contains(a)){return false;}else{this.events[b].push(a);}this.instances.each(function(c,d){c.addEvent(b,this.check.bind(this,[b,c,d])); -},this);return this;},check:function(c,a,b){this.checker[c][b]=true;var d=this.instances.every(function(g,f){return this.checker[c][f]||false;},this);if(!d){return; -}this.checker[c]={};this.events[c].each(function(f){f.call(this,this.instances,a);},this);}});Hash.Cookie=new Class({Extends:Cookie,options:{autoSave:true},initialize:function(b,a){this.parent(b,a); -this.load();},save:function(){var a=JSON.encode(this.hash);if(!a||a.length>4096){return false;}if(a=="{}"){this.dispose();}else{this.write(a);}return true; -},load:function(){this.hash=new Hash(JSON.decode(this.read(),true));return this;}});Hash.each(Hash.prototype,function(b,a){if(typeof b=="function"){Hash.Cookie.implement(a,function(){var c=b.apply(this.hash,arguments); -if(this.options.autoSave){this.save();}return c;});}});var IframeShim=new Class({Implements:[Options,Events,Class.Occlude],options:{className:"iframeShim",src:'javascript:false;document.write("");',display:false,zIndex:null,margin:0,offset:{x:0,y:0},browsers:(Browser.Engine.trident4||(Browser.Engine.gecko&&!Browser.Engine.gecko19&&Browser.Platform.mac))},property:"IframeShim",initialize:function(b,a){this.element=document.id(b); -if(this.occlude()){return this.occluded;}this.setOptions(a);this.makeShim();return this;},makeShim:function(){if(this.options.browsers){var c=this.element.getStyle("zIndex").toInt(); -if(!c){c=1;var b=this.element.getStyle("position");if(b=="static"||!b){this.element.setStyle("position","relative");}this.element.setStyle("zIndex",c); -}c=($chk(this.options.zIndex)&&c>this.options.zIndex)?this.options.zIndex:c-1;if(c<0){c=1;}this.shim=new Element("iframe",{src:this.options.src,scrolling:"no",frameborder:0,styles:{zIndex:c,position:"absolute",border:"none",filter:"progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"},"class":this.options.className}).store("IframeShim",this); -var a=(function(){this.shim.inject(this.element,"after");this[this.options.display?"show":"hide"]();this.fireEvent("inject");}).bind(this);if(!IframeShim.ready){window.addEvent("load",a); -}else{a();}}else{this.position=this.hide=this.show=this.dispose=$lambda(this);}},position:function(){if(!IframeShim.ready||!this.shim){return this;}var a=this.element.measure(function(){return this.getSize(); -});if(this.options.margin!=undefined){a.x=a.x-(this.options.margin*2);a.y=a.y-(this.options.margin*2);this.options.offset.x+=this.options.margin;this.options.offset.y+=this.options.margin; -}this.shim.set({width:a.x,height:a.y}).position({relativeTo:this.element,offset:this.options.offset});return this;},hide:function(){if(this.shim){this.shim.setStyle("display","none"); -}return this;},show:function(){if(this.shim){this.shim.setStyle("display","block");}return this.position();},dispose:function(){if(this.shim){this.shim.dispose(); -}return this;},destroy:function(){if(this.shim){this.shim.destroy();}return this;}});window.addEvent("load",function(){IframeShim.ready=true;});var HtmlTable=new Class({Implements:[Options,Events,Class.Occlude],options:{properties:{cellpadding:0,cellspacing:0,border:0},rows:[],headers:[],footers:[]},property:"HtmlTable",initialize:function(){var a=Array.link(arguments,{options:Object.type,table:Element.type}); -this.setOptions(a.options);this.element=a.table||new Element("table",this.options.properties);if(this.occlude()){return this.occluded;}this.build();},build:function(){this.element.store("HtmlTable",this); -this.body=document.id(this.element.tBodies[0])||new Element("tbody").inject(this.element);$$(this.body.rows);if(this.options.headers.length){this.setHeaders(this.options.headers); -}else{this.thead=document.id(this.element.tHead);}if(this.thead){this.head=document.id(this.thead.rows[0]);}if(this.options.footers.length){this.setFooters(this.options.footers); -}this.tfoot=document.id(this.element.tFoot);if(this.tfoot){this.foot=document.id(this.tfoot.rows[0]);}this.options.rows.each(function(a){this.push(a);},this); -["adopt","inject","wraps","grab","replaces","dispose"].each(function(a){this[a]=this.element[a].bind(this.element);},this);},toElement:function(){return this.element; -},empty:function(){this.body.empty();return this;},set:function(d,a){var c=(d=="headers")?"tHead":"tFoot";this[c.toLowerCase()]=(document.id(this.element[c])||new Element(c.toLowerCase()).inject(this.element,"top")).empty(); -var b=this.push(a,{},this[c.toLowerCase()],d=="headers"?"th":"td");if(d=="headers"){this.head=document.id(this.thead.rows[0]);}else{this.foot=document.id(this.thead.rows[0]); -}return b;},setHeaders:function(a){this.set("headers",a);return this;},setFooters:function(a){this.set("footers",a);return this;},push:function(f,b,d,a){if($type(f)=="element"&&f.get("tag")=="tr"){f.inject(d||this.body); -return{tr:f,tds:f.getChildren("td")};}var c=f.map(function(i){var j=new Element(a||"td",i?i.properties:{}),h=(i?i.content:"")||i,g=document.id(h);if($type(h)!="string"&&g){j.adopt(g); -}else{j.set("html",h);}return j;});return{tr:new Element("tr",b).inject(d||this.body).adopt(c),tds:c};}});HtmlTable=Class.refactor(HtmlTable,{options:{classZebra:"table-tr-odd",zebra:true},initialize:function(){this.previous.apply(this,arguments); -if(this.occluded){return this.occluded;}if(this.options.zebra){this.updateZebras();}},updateZebras:function(){Array.each(this.body.rows,this.zebra,this); -},zebra:function(b,a){return b[((a%2)?"remove":"add")+"Class"](this.options.classZebra);},push:function(){var a=this.previous.apply(this,arguments);if(this.options.zebra){this.updateZebras(); -}return a;}});HtmlTable=Class.refactor(HtmlTable,{options:{sortIndex:0,sortReverse:false,parsers:[],defaultParser:"string",classSortable:"table-sortable",classHeadSort:"table-th-sort",classHeadSortRev:"table-th-sort-rev",classNoSort:"table-th-nosort",classGroupHead:"table-tr-group-head",classGroup:"table-tr-group",classCellSort:"table-td-sort",classSortSpan:"table-th-sort-span",sortable:false},initialize:function(){this.previous.apply(this,arguments); -if(this.occluded){return this.occluded;}this.sorted={index:null,dir:1};this.bound={headClick:this.headClick.bind(this)};this.sortSpans=new Elements();if(this.options.sortable){this.enableSort(); -if(this.options.sortIndex!=null){this.sort(this.options.sortIndex,this.options.sortReverse);}}},attachSorts:function(a){this.element.removeEvents("click:relay(th)"); -this.element[$pick(a,true)?"addEvent":"removeEvent"]("click:relay(th)",this.bound.headClick);},setHeaders:function(){this.previous.apply(this,arguments); -if(this.sortEnabled){this.detectParsers();}},detectParsers:function(c){if(!this.head){return;}var a=this.options.parsers,b=this.body.rows;this.parsers=$$(this.head.cells).map(function(d,f){if(!c&&(d.hasClass(this.options.classNoSort)||d.retrieve("htmltable-parser"))){return d.retrieve("htmltable-parser"); -}var g=new Element("div");$each(d.childNodes,function(k){g.adopt(k);});g.inject(d);var i=new Element("span",{html:" ","class":this.options.classSortSpan}).inject(g,"top"); -this.sortSpans.push(i);var j=a[f],h;switch($type(j)){case"function":j={convert:j};h=true;break;case"string":j=j;h=true;break;}if(!h){HtmlTable.Parsers.some(function(o){var m=o.match; -if(!m){return false;}for(var n=0,l=b.length;ni.value?1:-1; -});if(!this.sorted.reverse){t.reverse(true);}var q=t.length,l=this.body;var o,s,a,h;while(q){var r=t[--q];s=r.position;var f=l.rows[s];if(f.disabled){continue; -}if(!n){if(h===r.value){f.removeClass(u).addClass(p);}else{h=r.value;f.removeClass(p).addClass(u);}if(this.options.zebra){this.zebra(f,q);}f.cells[g].addClass(m); -}l.appendChild(f);for(o=0;os){t[o].position--;}}}t=null;if(b){b.grab(l);}return this.fireEvent("sort",[l,g]);},reSort:function(){if(this.sortEnabled){this.sort.call(this,this.sorted.index,this.sorted.reverse); -}return this;},enableSort:function(){this.element.addClass(this.options.classSortable);this.attachSorts(true);this.detectParsers();this.sortEnabled=true; -return this;},disableSort:function(){this.element.removeClass(this.options.classSortable);this.attachSorts(false);this.sortSpans.each(function(a){a.destroy(); -});this.sortSpans.empty();this.sortEnabled=false;return this;}});HtmlTable.Parsers=new Hash({date:{match:/^\d{2}[-\/ ]\d{2}[-\/ ]\d{2,4}$/,convert:function(){var a=Date.parse(this.get("text").stripTags()); -return $type(a)=="date"?a.format("db"):"";},type:"date"},"input-checked":{match:/ type="(radio|checkbox)" /,convert:function(){return this.getElement("input").checked; -}},"input-value":{match:/=this.body.rows.length){a=null;}return a;},_attachSelects:function(d){d=$pick(d,true); -var h=d?"addEvents":"removeEvents";this.element[h]({mouseleave:this._bound.mouseleave});this.body[h]({"click:relay(tr)":this._bound.clickRow,"contextmenu:relay(tr)":this._bound.clickRow}); -if(this.options.useKeyboard||this.keyboard){if(!this.keyboard){var g,f;var c=function(j){var i=function(k){$clear(g);k.preventDefault();var l=this.body.rows[this._getRowByOffset(j)]; -if(k.shift&&l&&this.isSelected(l)){this.deselectRow(this._focused);this._focused=l;}else{if(l&&(!this.options.allowMultiSelect||!k.shift)){this.selectNone(); -}this._shiftFocus(j,k);}if(f){g=i.delay(100,this,k);}else{g=(function(){f=true;i(k);}).delay(400);}}.bind(this);return i;}.bind(this);var b=function(){$clear(g); -f=false;};this.keyboard=new Keyboard({events:{"keydown:shift+up":c(-1),"keydown:shift+down":c(1),"keyup:shift+up":b,"keyup:shift+down":b,"keyup:up":b,"keyup:down":b},active:true}); -var a="";if(this.options.allowMultiSelect&&this.options.shiftForMultiSelect&&this.options.useKeyboard){a=" (Shift multi-selects).";}this.keyboard.addShortcuts({"Select Previous Row":{keys:"up",shortcut:"up arrow",handler:c(-1),description:"Select the previous row in the table."+a},"Select Next Row":{keys:"down",shortcut:"down arrow",handler:c(1),description:"Select the next row in the table."+a}}); -}this.keyboard[d?"activate":"deactivate"]();}this._updateSelects();},_mouseleave:function(){if(this._hovered){this._leaveRow(this._hovered);}}});(function(){var a=this.Keyboard=new Class({Extends:Events,Implements:[Options,Log],options:{defaultEventType:"keydown",active:false,manager:null,events:{},nonParsedEvents:["activate","deactivate","onactivate","ondeactivate","changed","onchanged"]},initialize:function(g){if(g&&g.manager){this.manager=g.manager; -delete g.manager;}this.setOptions(g);this.setup();},setup:function(){this.addEvents(this.options.events);if(a.manager&&!this.manager){a.manager.manage(this); -}if(this.options.active){this.activate();}},handle:function(i,h){if(i.preventKeyboardPropagation){return;}var g=!!this.manager;if(g&&this.activeKB){this.activeKB.handle(i,h); -if(i.preventKeyboardPropagation){return;}}this.fireEvent(h,i);if(!g&&this.activeKB){this.activeKB.handle(i,h);}},addEvent:function(i,h,g){return this.parent(a.parse(i,this.options.defaultEventType,this.options.nonParsedEvents),h,g); -},removeEvent:function(h,g){return this.parent(a.parse(h,this.options.defaultEventType,this.options.nonParsedEvents),g);},toggleActive:function(){return this[this.active?"deactivate":"activate"](); -},activate:function(g){if(g){if(g.isActive()){return this;}if(this.activeKB&&g!=this.activeKB){this.previous=this.activeKB;this.previous.fireEvent("deactivate"); -}this.activeKB=g.fireEvent("activate");a.manager.fireEvent("changed");}else{if(this.manager){this.manager.activate(this);}}return this;},isActive:function(){return this.manager?this.manager.activeKB==this:a.manager==this; -},deactivate:function(g){if(g){if(g===this.activeKB){this.activeKB=null;g.fireEvent("deactivate");a.manager.fireEvent("changed");}}else{if(this.manager){this.manager.deactivate(this); -}}return this;},relinquish:function(){if(this.isActive()&&this.manager&&this.manager.previous){this.manager.activate(this.manager.previous);}},manage:function(g){if(g.manager&&g.manager!=a.manager&&this!=a.manager){g.manager.drop(g); -}this.instances.push(g);g.manager=this;if(!this.activeKB){this.activate(g);}},_disable:function(g){if(this.activeKB==g){this.activeKB=null;}},drop:function(g){this._disable(g); -this.instances.erase(g);a.manager.manage(g);if(this.activeKB==g&&this.previous&&this.instances.contains(this.previous)){this.activate(this.previous);}},instances:[],trace:function(){a.trace(this); -},each:function(g){a.each(this,g);}});var b={};var c=["shift","control","alt","meta"];var f=/^(?:shift|control|ctrl|alt|meta)$/;a.parse=function(i,h,l){if(l&&l.contains(i.toLowerCase())){return i; -}i=i.toLowerCase().replace(/^(keyup|keydown):/,function(n,m){h=m;return"";});if(!b[i]){var g,k={};i.split("+").each(function(m){if(f.test(m)){k[m]=true; -}else{g=m;}});k.control=k.control||k.ctrl;var j=[];c.each(function(m){if(k[m]){j.push(m);}});if(g){j.push(g);}b[i]=j.join("+");}return h+":"+b[i];};a.each=function(g,h){var i=g||a.manager; -while(i){h.run(i);i=i.activeKB;}};a.stop=function(g){g.preventKeyboardPropagation=true;};a.manager=new a({active:true});a.trace=function(g){g=g||a.manager; -g.enableLog();g.log("the following items have focus: ");a.each(g,function(h){g.log(document.id(h.widget)||h.wiget||h);});};var d=function(h){var g=[];c.each(function(i){if(h[i]){g.push(i); -}});if(!f.test(h.key)){g.push(h.key);}a.manager.handle(h,h.type+":"+g.join("+"));};document.addEvents({keyup:d,keydown:d});Event.Keys.extend({shift:16,control:17,alt:18,capslock:20,pageup:33,pagedown:34,end:35,home:36,numlock:144,scrolllock:145,";":186,"=":187,",":188,"-":Browser.Engine.gecko?109:189,".":190,"/":191,"`":192,"[":219,"\\":220,"]":221,"'":222}); -})();Keyboard.prototype.options.nonParsedEvents.combine(["rebound","onrebound"]);Keyboard.implement({addShortcut:function(b,a){this.shortcuts=this.shortcuts||[]; -this.shortcutIndex=this.shortcutIndex||{};a.getKeyboard=$lambda(this);a.name=b;this.shortcutIndex[b]=a;this.shortcuts.push(a);if(a.keys){this.addEvent(a.keys,a.handler); -}return this;},addShortcuts:function(b){for(var a in b){this.addShortcut(a,b[a]);}return this;},removeShortcut:function(b){var a=this.getShortcut(b);if(a&&a.keys){this.removeEvent(a.keys,a.handler); -delete this.shortcutIndex[b];this.shortcuts.erase(a);}return this;},removeShortcuts:function(a){a.each(this.removeShortcut,this);return this;},getShortcuts:function(){return this.shortcuts||[]; -},getShortcut:function(a){return(this.shortcutIndex||{})[a];}});Keyboard.rebind=function(b,a){$splat(a).each(function(c){c.getKeyboard().removeEvent(c.keys,c.handler); -c.getKeyboard().addEvent(b,c.handler);c.keys=b;c.getKeyboard().fireEvent("rebound");});};Keyboard.getActiveShortcuts=function(b){var a=[],c=[];Keyboard.each(b,[].push.bind(a)); -a.each(function(d){c.extend(d.getShortcuts());});return c;};Keyboard.getShortcut=function(c,b,d){d=d||{};var a=d.many?[]:null,f=d.many?function(h){var g=h.getShortcut(c); -if(g){a.push(g);}}:function(g){if(!a){a=g.getShortcut(c);}};Keyboard.each(b,f);return a;};Keyboard.getShortcuts=function(b,a){return Keyboard.getShortcut(b,a,{many:true}); -};var Mask=new Class({Implements:[Options,Events],Binds:["position"],options:{style:{},"class":"mask",maskMargins:false,useIframeShim:true,iframeShimOptions:{}},initialize:function(b,a){this.target=document.id(b)||document.id(document.body); -this.target.store("Mask",this);this.setOptions(a);this.render();this.inject();},render:function(){this.element=new Element("div",{"class":this.options["class"],id:this.options.id||"mask-"+$time(),styles:$merge(this.options.style,{display:"none"}),events:{click:function(){this.fireEvent("click"); -if(this.options.hideOnClick){this.hide();}}.bind(this)}});this.hidden=true;},toElement:function(){return this.element;},inject:function(b,a){a=a||this.options.inject?this.options.inject.where:""||this.target==document.body?"inside":"after"; -b=b||this.options.inject?this.options.inject.target:""||this.target;this.element.inject(b,a);if(this.options.useIframeShim){this.shim=new IframeShim(this.element,this.options.iframeShimOptions); -this.addEvents({show:this.shim.show.bind(this.shim),hide:this.shim.hide.bind(this.shim),destroy:this.shim.destroy.bind(this.shim)});}},position:function(){this.resize(this.options.width,this.options.height); -this.element.position({relativeTo:this.target,position:"topLeft",ignoreMargins:!this.options.maskMargins,ignoreScroll:this.target==document.body});return this; -},resize:function(a,f){var b={styles:["padding","border"]};if(this.options.maskMargins){b.styles.push("margin");}var d=this.target.getComputedSize(b);if(this.target==document.body){var c=window.getScrollSize(); -if(d.totalHeight(c[g]+i[g])&&a[g]+c[g]!=d[g]){h[g]=(this.page[g]-c[g]+b-i[g])*this.options.velocity; -}}h[g]=h[g].round();}if(h.y||h.x){this.fireEvent("change",[a.x+h.x,a.y+h.y]);}}});(function(){var a=function(c,b){return(c)?($type(c)=="function"?c(b):b.get(c)):""; -};this.Tips=new Class({Implements:[Events,Options],options:{onShow:function(){this.tip.setStyle("display","block");},onHide:function(){this.tip.setStyle("display","none"); -},title:"title",text:function(b){return b.get("rel")||b.get("href");},showDelay:100,hideDelay:100,className:"tip-wrap",offset:{x:16,y:16},windowPadding:{x:0,y:0},fixed:false},initialize:function(){var b=Array.link(arguments,{options:Object.type,elements:$defined}); -this.setOptions(b.options);if(b.elements){this.attach(b.elements);}this.container=new Element("div",{"class":"tip"});},toElement:function(){if(this.tip){return this.tip; -}return this.tip=new Element("div",{"class":this.options.className,styles:{position:"absolute",top:0,left:0}}).adopt(new Element("div",{"class":"tip-top"}),this.container,new Element("div",{"class":"tip-bottom"})); -},attach:function(b){$$(b).each(function(d){var g=a(this.options.title,d),f=a(this.options.text,d);d.erase("title").store("tip:native",g).retrieve("tip:title",g); -d.retrieve("tip:text",f);this.fireEvent("attach",[d]);var c=["enter","leave"];if(!this.options.fixed){c.push("move");}c.each(function(i){var h=d.retrieve("tip:"+i); -if(!h){h=this["element"+i.capitalize()].bindWithEvent(this,d);}d.store("tip:"+i,h).addEvent("mouse"+i,h);},this);},this);return this;},detach:function(b){$$(b).each(function(d){["enter","leave","move"].each(function(f){d.removeEvent("mouse"+f,d.retrieve("tip:"+f)).eliminate("tip:"+f); -});this.fireEvent("detach",[d]);if(this.options.title=="title"){var c=d.retrieve("tip:native");if(c){d.set("title",c);}}},this);return this;},elementEnter:function(c,b){this.container.empty(); -["title","text"].each(function(f){var d=b.retrieve("tip:"+f);if(d){this.fill(new Element("div",{"class":"tip-"+f}).inject(this.container),d);}},this);$clear(this.timer); -this.timer=(function(){this.show(b);this.position((this.options.fixed)?{page:b.getPosition()}:c);}).delay(this.options.showDelay,this);},elementLeave:function(c,b){$clear(this.timer); -this.timer=this.hide.delay(this.options.hideDelay,this,b);this.fireForParent(c,b);},fireForParent:function(c,b){b=b.getParent();if(!b||b==document.body){return; -}if(b.retrieve("tip:enter")){b.fireEvent("mouseenter",c);}else{this.fireForParent(c,b);}},elementMove:function(c,b){this.position(c);},position:function(f){if(!this.tip){document.id(this); -}var c=window.getSize(),b=window.getScroll(),g={x:this.tip.offsetWidth,y:this.tip.offsetHeight},d={x:"left",y:"top"},h={};for(var i in d){h[d[i]]=f.page[i]+this.options.offset[i]; -if((h[d[i]]+g[i]-b[i])>c[i]-this.options.windowPadding[i]){h[d[i]]=f.page[i]-this.options.offset[i]-g[i];}}this.tip.setStyles(h);},fill:function(b,c){if(typeof c=="string"){b.set("html",c); -}else{b.adopt(c);}},show:function(b){if(!this.tip){document.id(this);}if(!this.tip.getParent()){this.tip.inject(document.body);}this.fireEvent("show",[this.tip,b]); -},hide:function(b){if(!this.tip){document.id(this);}this.fireEvent("hide",[this.tip,b]);}});})();var Spinner=new Class({Extends:Mask,options:{"class":"spinner",containerPosition:{},content:{"class":"spinner-content"},messageContainer:{"class":"spinner-msg"},img:{"class":"spinner-img"},fxOptions:{link:"chain"}},initialize:function(){this.parent.apply(this,arguments); -this.target.store("spinner",this);var a=function(){this.active=false;}.bind(this);this.addEvents({hide:a,show:a});},render:function(){this.parent();this.element.set("id",this.options.id||"spinner-"+$time()); -this.content=document.id(this.options.content)||new Element("div",this.options.content);this.content.inject(this.element);if(this.options.message){this.msg=document.id(this.options.message)||new Element("p",this.options.messageContainer).appendText(this.options.message); -this.msg.inject(this.content);}if(this.options.img){this.img=document.id(this.options.img)||new Element("div",this.options.img);this.img.inject(this.content); -}this.element.set("tween",this.options.fxOptions);},show:function(a){if(this.active){return this.chain(this.show.bind(this));}if(!this.hidden){this.callChain.delay(20,this); -return this;}this.active=true;return this.parent(a);},showMask:function(a){var b=function(){this.content.position($merge({relativeTo:this.element},this.options.containerPosition)); -}.bind(this);if(a){this.parent();b();}else{this.element.setStyles({display:"block",opacity:0}).tween("opacity",this.options.style.opacity||0.9);b();this.hidden=false; -this.fireEvent("show");this.callChain();}},hide:function(a){if(this.active){return this.chain(this.hide.bind(this));}if(this.hidden){this.callChain.delay(20,this); -return this;}this.active=true;return this.parent(a);},hideMask:function(a){if(a){return this.parent();}this.element.tween("opacity",0).get("tween").chain(function(){this.element.setStyle("display","none"); -this.hidden=true;this.fireEvent("hide");this.callChain();}.bind(this));},destroy:function(){this.content.destroy();this.parent();this.target.eliminate("spinner"); -}});Spinner.implement(new Chain);Request=Class.refactor(Request,{options:{useSpinner:false,spinnerOptions:{},spinnerTarget:false},initialize:function(a){this._send=this.send; -this.send=function(b){var c=this.getSpinner();if(c){c.chain(this._send.bind(this,b)).show();}else{this._send(b);}return this;};this.previous(a);},getSpinner:function(){if(!this.spinner){var a=document.id(this.options.spinnerTarget)||document.id(this.options.update); -if(this.options.useSpinner&&a){this.spinner=a.get("spinner",this.options.spinnerOptions);["onComplete","onException","onCancel"].each(function(b){this.addEvent(b,this.spinner.hide.bind(this.spinner)); -},this);}}return this.spinner;}});Element.Properties.spinner={set:function(a){var b=this.retrieve("spinner");return this.eliminate("spinner").store("spinner:options",a); -},get:function(a){if(a||!this.retrieve("spinner")){if(this.retrieve("spinner")){this.retrieve("spinner").destroy();}if(a||!this.retrieve("spinner:options")){this.set("spinner",a); -}new Spinner(this,this.retrieve("spinner:options"));}return this.retrieve("spinner");}};Element.implement({spin:function(a){this.get("spinner",a).show(); -return this;},unspin:function(){var a=Array.link(arguments,{options:Object.type,callback:Function.type});this.get("spinner",a.options).hide(a.callback); -return this;}});MooTools.lang.set("en-US","Date",{months:["January","February","March","April","May","June","July","August","September","October","November","December"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dateOrder:["month","date","year"],shortDate:"%m/%d/%Y",shortTime:"%I:%M%p",AM:"AM",PM:"PM",ordinal:function(a){return(a>3&&a<21)?"th":["th","st","nd","rd","th"][Math.min(a%10,4)]; -},lessThanMinuteAgo:"less than a minute ago",minuteAgo:"about a minute ago",minutesAgo:"{delta} minutes ago",hourAgo:"about an hour ago",hoursAgo:"about {delta} hours ago",dayAgo:"1 day ago",daysAgo:"{delta} days ago",weekAgo:"1 week ago",weeksAgo:"{delta} weeks ago",monthAgo:"1 month ago",monthsAgo:"{delta} months ago",yearAgo:"1 year ago",yearsAgo:"{delta} years ago",lessThanMinuteUntil:"less than a minute from now",minuteUntil:"about a minute from now",minutesUntil:"{delta} minutes from now",hourUntil:"about an hour from now",hoursUntil:"about {delta} hours from now",dayUntil:"1 day from now",daysUntil:"{delta} days from now",weekUntil:"1 week from now",weeksUntil:"{delta} weeks from now",monthUntil:"1 month from now",monthsUntil:"{delta} months from now",yearUntil:"1 year from now",yearsUntil:"{delta} years from now"}); -MooTools.lang.set("en-US","Form.Validator",{required:"This field is required.",minLength:"Please enter at least {minLength} characters (you entered {length} characters).",maxLength:"Please enter no more than {maxLength} characters (you entered {length} characters).",integer:"Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.",numeric:'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").',digits:"Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).",alpha:"Please use only letters (a-z) within this field. No spaces or other characters are allowed.",alphanum:"Please use only letters (a-z) or numbers (0-9) in this field. No spaces or other characters are allowed.",dateSuchAs:"Please enter a valid date such as {date}",dateInFormatMDY:'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")',email:'Please enter a valid email address. For example "fred@domain.com".',url:"Please enter a valid URL such as http://www.google.com.",currencyDollar:"Please enter a valid $ amount. For example $100.00 .",oneRequired:"Please enter something for at least one of these inputs.",errorPrefix:"Error: ",warningPrefix:"Warning: ",noSpace:"There can be no spaces in this input.",reqChkByNode:"No items are selected.",requiredChk:"This field is required.",reqChkByName:"Please select a {label}.",match:"This field needs to match the {matchName} field",startDate:"the start date",endDate:"the end date",currendDate:"the current date",afterDate:"The date should be the same or after {label}.",beforeDate:"The date should be the same or before {label}.",startMonth:"Please select a start month",sameMonth:"These two dates must be in the same month - you must change one or the other.",creditcard:"The credit card number entered is invalid. Please check the number and try again. {length} digits entered."}); diff --git a/web/tools/mootools/mootools-core-1.3.2-nc.js b/web/tools/mootools/mootools-core-1.3.2-nc.js new file mode 100644 index 000000000..cba97ef7f --- /dev/null +++ b/web/tools/mootools/mootools-core-1.3.2-nc.js @@ -0,0 +1,5515 @@ +/* +--- +MooTools: the javascript framework + +web build: + - http://mootools.net/core/7c56cfef9dddcf170a5d68e3fb61cfd7 + +packager build: + - packager build Core/Core Core/Array Core/String Core/Number Core/Function Core/Object Core/Event Core/Browser Core/Class Core/Class.Extras Core/Slick.Parser Core/Slick.Finder Core/Element Core/Element.Style Core/Element.Event Core/Element.Dimensions Core/Fx Core/Fx.CSS Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/Request Core/Request.HTML Core/Request.JSON Core/Cookie Core/JSON Core/DOMReady Core/Swiff + +/* +--- + +name: Core + +description: The heart of MooTools. + +license: MIT-style license. + +copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). + +authors: The MooTools production team (http://mootools.net/developers/) + +inspiration: + - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) + - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) + +provides: [Core, MooTools, Type, typeOf, instanceOf, Native] + +... +*/ + +(function(){ + +this.MooTools = { + version: '1.3.2', + build: 'c9f1ff10e9e7facb65e9481049ed1b450959d587' +}; + +// typeOf, instanceOf + +var typeOf = this.typeOf = function(item){ + if (item == null) return 'null'; + if (item.$family) return item.$family(); + + if (item.nodeName){ + if (item.nodeType == 1) return 'element'; + if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace'; + } else if (typeof item.length == 'number'){ + if (item.callee) return 'arguments'; + if ('item' in item) return 'collection'; + } + + return typeof item; +}; + +var instanceOf = this.instanceOf = function(item, object){ + if (item == null) return false; + var constructor = item.$constructor || item.constructor; + while (constructor){ + if (constructor === object) return true; + constructor = constructor.parent; + } + return item instanceof object; +}; + +// Function overloading + +var Function = this.Function; + +var enumerables = true; +for (var i in {toString: 1}) enumerables = null; +if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; + +Function.prototype.overloadSetter = function(usePlural){ + var self = this; + return function(a, b){ + if (a == null) return this; + if (usePlural || typeof a != 'string'){ + for (var k in a) self.call(this, k, a[k]); + if (enumerables) for (var i = enumerables.length; i--;){ + k = enumerables[i]; + if (a.hasOwnProperty(k)) self.call(this, k, a[k]); + } + } else { + self.call(this, a, b); + } + return this; + }; +}; + +Function.prototype.overloadGetter = function(usePlural){ + var self = this; + return function(a){ + var args, result; + if (usePlural || typeof a != 'string') args = a; + else if (arguments.length > 1) args = arguments; + if (args){ + result = {}; + for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]); + } else { + result = self.call(this, a); + } + return result; + }; +}; + +Function.prototype.extend = function(key, value){ + this[key] = value; +}.overloadSetter(); + +Function.prototype.implement = function(key, value){ + this.prototype[key] = value; +}.overloadSetter(); + +// From + +var slice = Array.prototype.slice; + +Function.from = function(item){ + return (typeOf(item) == 'function') ? item : function(){ + return item; + }; +}; + +Array.from = function(item){ + if (item == null) return []; + return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item]; +}; + +Number.from = function(item){ + var number = parseFloat(item); + return isFinite(number) ? number : null; +}; + +String.from = function(item){ + return item + ''; +}; + +// hide, protect + +Function.implement({ + + hide: function(){ + this.$hidden = true; + return this; + }, + + protect: function(){ + this.$protected = true; + return this; + } + +}); + +// Type + +var Type = this.Type = function(name, object){ + if (name){ + var lower = name.toLowerCase(); + var typeCheck = function(item){ + return (typeOf(item) == lower); + }; + + Type['is' + name] = typeCheck; + if (object != null){ + object.prototype.$family = (function(){ + return lower; + }).hide(); + + } + } + + if (object == null) return null; + + object.extend(this); + object.$constructor = Type; + object.prototype.$constructor = object; + + return object; +}; + +var toString = Object.prototype.toString; + +Type.isEnumerable = function(item){ + return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' ); +}; + +var hooks = {}; + +var hooksOf = function(object){ + var type = typeOf(object.prototype); + return hooks[type] || (hooks[type] = []); +}; + +var implement = function(name, method){ + if (method && method.$hidden) return; + + var hooks = hooksOf(this); + + for (var i = 0; i < hooks.length; i++){ + var hook = hooks[i]; + if (typeOf(hook) == 'type') implement.call(hook, name, method); + else hook.call(this, name, method); + } + + var previous = this.prototype[name]; + if (previous == null || !previous.$protected) this.prototype[name] = method; + + if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){ + return method.apply(item, slice.call(arguments, 1)); + }); +}; + +var extend = function(name, method){ + if (method && method.$hidden) return; + var previous = this[name]; + if (previous == null || !previous.$protected) this[name] = method; +}; + +Type.implement({ + + implement: implement.overloadSetter(), + + extend: extend.overloadSetter(), + + alias: function(name, existing){ + implement.call(this, name, this.prototype[existing]); + }.overloadSetter(), + + mirror: function(hook){ + hooksOf(this).push(hook); + return this; + } + +}); + +new Type('Type', Type); + +// Default Types + +var force = function(name, object, methods){ + var isType = (object != Object), + prototype = object.prototype; + + if (isType) object = new Type(name, object); + + for (var i = 0, l = methods.length; i < l; i++){ + var key = methods[i], + generic = object[key], + proto = prototype[key]; + + if (generic) generic.protect(); + + if (isType && proto){ + delete prototype[key]; + prototype[key] = proto.protect(); + } + } + + if (isType) object.implement(prototype); + + return force; +}; + +force('String', String, [ + 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', + 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase' +])('Array', Array, [ + 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', + 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight' +])('Number', Number, [ + 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision' +])('Function', Function, [ + 'apply', 'call', 'bind' +])('RegExp', RegExp, [ + 'exec', 'test' +])('Object', Object, [ + 'create', 'defineProperty', 'defineProperties', 'keys', + 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', + 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen' +])('Date', Date, ['now']); + +Object.extend = extend.overloadSetter(); + +Date.extend('now', function(){ + return +(new Date); +}); + +new Type('Boolean', Boolean); + +// fixes NaN returning as Number + +Number.prototype.$family = function(){ + return isFinite(this) ? 'number' : 'null'; +}.hide(); + +// Number.random + +Number.extend('random', function(min, max){ + return Math.floor(Math.random() * (max - min + 1) + min); +}); + +// forEach, each + +var hasOwnProperty = Object.prototype.hasOwnProperty; +Object.extend('forEach', function(object, fn, bind){ + for (var key in object){ + if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object); + } +}); + +Object.each = Object.forEach; + +Array.implement({ + + forEach: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (i in this) fn.call(bind, this[i], i, this); + } + }, + + each: function(fn, bind){ + Array.forEach(this, fn, bind); + return this; + } + +}); + +// Array & Object cloning, Object merging and appending + +var cloneOf = function(item){ + switch (typeOf(item)){ + case 'array': return item.clone(); + case 'object': return Object.clone(item); + default: return item; + } +}; + +Array.implement('clone', function(){ + var i = this.length, clone = new Array(i); + while (i--) clone[i] = cloneOf(this[i]); + return clone; +}); + +var mergeOne = function(source, key, current){ + switch (typeOf(current)){ + case 'object': + if (typeOf(source[key]) == 'object') Object.merge(source[key], current); + else source[key] = Object.clone(current); + break; + case 'array': source[key] = current.clone(); break; + default: source[key] = current; + } + return source; +}; + +Object.extend({ + + merge: function(source, k, v){ + if (typeOf(k) == 'string') return mergeOne(source, k, v); + for (var i = 1, l = arguments.length; i < l; i++){ + var object = arguments[i]; + for (var key in object) mergeOne(source, key, object[key]); + } + return source; + }, + + clone: function(object){ + var clone = {}; + for (var key in object) clone[key] = cloneOf(object[key]); + return clone; + }, + + append: function(original){ + for (var i = 1, l = arguments.length; i < l; i++){ + var extended = arguments[i] || {}; + for (var key in extended) original[key] = extended[key]; + } + return original; + } + +}); + +// Object-less types + +['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){ + new Type(name); +}); + +// Unique ID + +var UID = Date.now(); + +String.extend('uniqueID', function(){ + return (UID++).toString(36); +}); + + + +})(); + + +/* +--- + +name: Array + +description: Contains Array Prototypes like each, contains, and erase. + +license: MIT-style license. + +requires: Type + +provides: Array + +... +*/ + +Array.implement({ + + /**/ + every: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if ((i in this) && !fn.call(bind, this[i], i, this)) return false; + } + return true; + }, + + filter: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++){ + if ((i in this) && fn.call(bind, this[i], i, this)) results.push(this[i]); + } + return results; + }, + + indexOf: function(item, from){ + var len = this.length; + for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ + if (this[i] === item) return i; + } + return -1; + }, + + map: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++){ + if (i in this) results[i] = fn.call(bind, this[i], i, this); + } + return results; + }, + + some: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if ((i in this) && fn.call(bind, this[i], i, this)) return true; + } + return false; + }, + /**/ + + clean: function(){ + return this.filter(function(item){ + return item != null; + }); + }, + + invoke: function(methodName){ + var args = Array.slice(arguments, 1); + return this.map(function(item){ + return item[methodName].apply(item, args); + }); + }, + + associate: function(keys){ + var obj = {}, length = Math.min(this.length, keys.length); + for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; + return obj; + }, + + link: function(object){ + var result = {}; + for (var i = 0, l = this.length; i < l; i++){ + for (var key in object){ + if (object[key](this[i])){ + result[key] = this[i]; + delete object[key]; + break; + } + } + } + return result; + }, + + contains: function(item, from){ + return this.indexOf(item, from) != -1; + }, + + append: function(array){ + this.push.apply(this, array); + return this; + }, + + getLast: function(){ + return (this.length) ? this[this.length - 1] : null; + }, + + getRandom: function(){ + return (this.length) ? this[Number.random(0, this.length - 1)] : null; + }, + + include: function(item){ + if (!this.contains(item)) this.push(item); + return this; + }, + + combine: function(array){ + for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); + return this; + }, + + erase: function(item){ + for (var i = this.length; i--;){ + if (this[i] === item) this.splice(i, 1); + } + return this; + }, + + empty: function(){ + this.length = 0; + return this; + }, + + flatten: function(){ + var array = []; + for (var i = 0, l = this.length; i < l; i++){ + var type = typeOf(this[i]); + if (type == 'null') continue; + array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]); + } + return array; + }, + + pick: function(){ + for (var i = 0, l = this.length; i < l; i++){ + if (this[i] != null) return this[i]; + } + return null; + }, + + hexToRgb: function(array){ + if (this.length != 3) return null; + var rgb = this.map(function(value){ + if (value.length == 1) value += value; + return value.toInt(16); + }); + return (array) ? rgb : 'rgb(' + rgb + ')'; + }, + + rgbToHex: function(array){ + if (this.length < 3) return null; + if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (this[i] - 0).toString(16); + hex.push((bit.length == 1) ? '0' + bit : bit); + } + return (array) ? hex : '#' + hex.join(''); + } + +}); + + + + +/* +--- + +name: String + +description: Contains String Prototypes like camelCase, capitalize, test, and toInt. + +license: MIT-style license. + +requires: Type + +provides: String + +... +*/ + +String.implement({ + + test: function(regex, params){ + return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this); + }, + + contains: function(string, separator){ + return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; + }, + + trim: function(){ + return this.replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return this.replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return this.replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return this.replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return this.replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = this.match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + substitute: function(object, regexp){ + return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + if (match.charAt(0) == '\\') return match.slice(1); + return (object[name] != null) ? object[name] : ''; + }); + } + +}); + + +/* +--- + +name: Number + +description: Contains Number Prototypes like limit, round, times, and ceil. + +license: MIT-style license. + +requires: Type + +provides: Number + +... +*/ + +Number.implement({ + + limit: function(min, max){ + return Math.min(max, Math.max(min, this)); + }, + + round: function(precision){ + precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0); + return Math.round(this * precision) / precision; + }, + + times: function(fn, bind){ + for (var i = 0; i < this; i++) fn.call(bind, i, this); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + } + +}); + +Number.alias('each', 'times'); + +(function(math){ + var methods = {}; + math.each(function(name){ + if (!Number[name]) methods[name] = function(){ + return Math[name].apply(null, [this].concat(Array.from(arguments))); + }; + }); + Number.implement(methods); +})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); + + +/* +--- + +name: Function + +description: Contains Function Prototypes like create, bind, pass, and delay. + +license: MIT-style license. + +requires: Type + +provides: Function + +... +*/ + +Function.extend({ + + attempt: function(){ + for (var i = 0, l = arguments.length; i < l; i++){ + try { + return arguments[i](); + } catch (e){} + } + return null; + } + +}); + +Function.implement({ + + attempt: function(args, bind){ + try { + return this.apply(bind, Array.from(args)); + } catch (e){} + + return null; + }, + + /**/ + bind: function(bind){ + var self = this, + args = (arguments.length > 1) ? Array.slice(arguments, 1) : null; + + return function(){ + if (!args && !arguments.length) return self.call(bind); + if (args && arguments.length) return self.apply(bind, args.concat(Array.from(arguments))); + return self.apply(bind, args || arguments); + }; + }, + /**/ + + pass: function(args, bind){ + var self = this; + if (args != null) args = Array.from(args); + return function(){ + return self.apply(bind, args || arguments); + }; + }, + + delay: function(delay, bind, args){ + return setTimeout(this.pass((args == null ? [] : args), bind), delay); + }, + + periodical: function(periodical, bind, args){ + return setInterval(this.pass((args == null ? [] : args), bind), periodical); + } + +}); + + + + +/* +--- + +name: Object + +description: Object generic methods + +license: MIT-style license. + +requires: Type + +provides: [Object, Hash] + +... +*/ + +(function(){ + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +Object.extend({ + + subset: function(object, keys){ + var results = {}; + for (var i = 0, l = keys.length; i < l; i++){ + var k = keys[i]; + if (k in object) results[k] = object[k]; + } + return results; + }, + + map: function(object, fn, bind){ + var results = {}; + for (var key in object){ + if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object); + } + return results; + }, + + filter: function(object, fn, bind){ + var results = {}; + for (var key in object){ + var value = object[key]; + if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value; + } + return results; + }, + + every: function(object, fn, bind){ + for (var key in object){ + if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false; + } + return true; + }, + + some: function(object, fn, bind){ + for (var key in object){ + if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true; + } + return false; + }, + + keys: function(object){ + var keys = []; + for (var key in object){ + if (hasOwnProperty.call(object, key)) keys.push(key); + } + return keys; + }, + + values: function(object){ + var values = []; + for (var key in object){ + if (hasOwnProperty.call(object, key)) values.push(object[key]); + } + return values; + }, + + getLength: function(object){ + return Object.keys(object).length; + }, + + keyOf: function(object, value){ + for (var key in object){ + if (hasOwnProperty.call(object, key) && object[key] === value) return key; + } + return null; + }, + + contains: function(object, value){ + return Object.keyOf(object, value) != null; + }, + + toQueryString: function(object, base){ + var queryString = []; + + Object.each(object, function(value, key){ + if (base) key = base + '[' + key + ']'; + var result; + switch (typeOf(value)){ + case 'object': result = Object.toQueryString(value, key); break; + case 'array': + var qs = {}; + value.each(function(val, i){ + qs[i] = val; + }); + result = Object.toQueryString(qs, key); + break; + default: result = key + '=' + encodeURIComponent(value); + } + if (value != null) queryString.push(result); + }); + + return queryString.join('&'); + } + +}); + +})(); + + + + +/* +--- + +name: Browser + +description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash. + +license: MIT-style license. + +requires: [Array, Function, Number, String] + +provides: [Browser, Window, Document] + +... +*/ + +(function(){ + +var document = this.document; +var window = document.window = this; + +var UID = 1; + +this.$uid = (window.ActiveXObject) ? function(item){ + return (item.uid || (item.uid = [UID++]))[0]; +} : function(item){ + return item.uid || (item.uid = UID++); +}; + +$uid(window); +$uid(document); + +var ua = navigator.userAgent.toLowerCase(), + platform = navigator.platform.toLowerCase(), + UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0], + mode = UA[1] == 'ie' && document.documentMode; + +var Browser = this.Browser = { + + extend: Function.prototype.extend, + + name: (UA[1] == 'version') ? UA[3] : UA[1], + + version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]), + + Platform: { + name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0] + }, + + Features: { + xpath: !!(document.evaluate), + air: !!(window.runtime), + query: !!(document.querySelector), + json: !!(window.JSON) + }, + + Plugins: {} + +}; + +Browser[Browser.name] = true; +Browser[Browser.name + parseInt(Browser.version, 10)] = true; +Browser.Platform[Browser.Platform.name] = true; + +// Request + +Browser.Request = (function(){ + + var XMLHTTP = function(){ + return new XMLHttpRequest(); + }; + + var MSXML2 = function(){ + return new ActiveXObject('MSXML2.XMLHTTP'); + }; + + var MSXML = function(){ + return new ActiveXObject('Microsoft.XMLHTTP'); + }; + + return Function.attempt(function(){ + XMLHTTP(); + return XMLHTTP; + }, function(){ + MSXML2(); + return MSXML2; + }, function(){ + MSXML(); + return MSXML; + }); + +})(); + +Browser.Features.xhr = !!(Browser.Request); + +// Flash detection + +var version = (Function.attempt(function(){ + return navigator.plugins['Shockwave Flash'].description; +}, function(){ + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); +}) || '0 r0').match(/\d+/g); + +Browser.Plugins.Flash = { + version: Number(version[0] || '0.' + version[1]) || 0, + build: Number(version[2]) || 0 +}; + +// String scripts + +Browser.exec = function(text){ + if (!text) return text; + if (window.execScript){ + window.execScript(text); + } else { + var script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script.text = text; + document.head.appendChild(script); + document.head.removeChild(script); + } + return text; +}; + +String.implement('stripScripts', function(exec){ + var scripts = ''; + var text = this.replace(/]*>([\s\S]*?)<\/script>/gi, function(all, code){ + scripts += code + '\n'; + return ''; + }); + if (exec === true) Browser.exec(scripts); + else if (typeOf(exec) == 'function') exec(scripts, text); + return text; +}); + +// Window, Document + +Browser.extend({ + Document: this.Document, + Window: this.Window, + Element: this.Element, + Event: this.Event +}); + +this.Window = this.$constructor = new Type('Window', function(){}); + +this.$family = Function.from('window').hide(); + +Window.mirror(function(name, method){ + window[name] = method; +}); + +this.Document = document.$constructor = new Type('Document', function(){}); + +document.$family = Function.from('document').hide(); + +Document.mirror(function(name, method){ + document[name] = method; +}); + +document.html = document.documentElement; +if (!document.head) document.head = document.getElementsByTagName('head')[0]; + +if (document.execCommand) try { + document.execCommand("BackgroundImageCache", false, true); +} catch (e){} + +/**/ +if (this.attachEvent && !this.addEventListener){ + var unloadEvent = function(){ + this.detachEvent('onunload', unloadEvent); + document.head = document.html = document.window = null; + }; + this.attachEvent('onunload', unloadEvent); +} + +// IE fails on collections and ) +var arrayFrom = Array.from; +try { + arrayFrom(document.html.childNodes); +} catch(e){ + Array.from = function(item){ + if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){ + var i = item.length, array = new Array(i); + while (i--) array[i] = item[i]; + return array; + } + return arrayFrom(item); + }; + + var prototype = Array.prototype, + slice = prototype.slice; + ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){ + var method = prototype[name]; + Array[name] = function(item){ + return method.apply(Array.from(item), slice.call(arguments, 1)); + }; + }); +} +/**/ + + + +})(); + + +/* +--- + +name: Event + +description: Contains the Event Class, to make the event object cross-browser. + +license: MIT-style license. + +requires: [Window, Document, Array, Function, String, Object] + +provides: Event + +... +*/ + +var Event = new Type('Event', function(event, win){ + if (!win) win = window; + var doc = win.document; + event = event || win.event; + if (event.$extended) return event; + this.$extended = true; + var type = event.type, + target = event.target || event.srcElement, + page = {}, + client = {}, + related = null, + rightClick, wheel, code, key; + while (target && target.nodeType == 3) target = target.parentNode; + + if (type.indexOf('key') != -1){ + code = event.which || event.keyCode; + key = Object.keyOf(Event.Keys, code); + if (type == 'keydown'){ + var fKey = code - 111; + if (fKey > 0 && fKey < 13) key = 'f' + fKey; + } + if (!key) key = String.fromCharCode(code).toLowerCase(); + } else if ((/click|mouse|menu/i).test(type)){ + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + page = { + x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, + y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop + }; + client = { + x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY + }; + if ((/DOMMouseScroll|mousewheel/).test(type)){ + wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + } + rightClick = (event.which == 3) || (event.button == 2); + if ((/over|out/).test(type)){ + related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; + var testRelated = function(){ + while (related && related.nodeType == 3) related = related.parentNode; + return true; + }; + var hasRelated = (Browser.firefox2) ? testRelated.attempt() : testRelated(); + related = (hasRelated) ? related : null; + } + } else if ((/gesture|touch/i).test(type)){ + this.rotation = event.rotation; + this.scale = event.scale; + this.targetTouches = event.targetTouches; + this.changedTouches = event.changedTouches; + var touches = this.touches = event.touches; + if (touches && touches[0]){ + var touch = touches[0]; + page = {x: touch.pageX, y: touch.pageY}; + client = {x: touch.clientX, y: touch.clientY}; + } + } + + return Object.append(this, { + event: event, + type: type, + + page: page, + client: client, + rightClick: rightClick, + + wheel: wheel, + + relatedTarget: document.id(related), + target: document.id(target), + + code: code, + key: key, + + shift: event.shiftKey, + control: event.ctrlKey, + alt: event.altKey, + meta: event.metaKey + }); +}); + +Event.Keys = { + 'enter': 13, + 'up': 38, + 'down': 40, + 'left': 37, + 'right': 39, + 'esc': 27, + 'space': 32, + 'backspace': 8, + 'tab': 9, + 'delete': 46 +}; + + + +Event.implement({ + + stop: function(){ + return this.stopPropagation().preventDefault(); + }, + + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + return this; + }, + + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + } + +}); + + +/* +--- + +name: Class + +description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. + +license: MIT-style license. + +requires: [Array, String, Function, Number] + +provides: Class + +... +*/ + +(function(){ + +var Class = this.Class = new Type('Class', function(params){ + if (instanceOf(params, Function)) params = {initialize: params}; + + var newClass = function(){ + reset(this); + if (newClass.$prototyping) return this; + this.$caller = null; + var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; + this.$caller = this.caller = null; + return value; + }.extend(this).implement(params); + + newClass.$constructor = Class; + newClass.prototype.$constructor = newClass; + newClass.prototype.parent = parent; + + return newClass; +}); + +var parent = function(){ + if (!this.$caller) throw new Error('The method "parent" cannot be called.'); + var name = this.$caller.$name, + parent = this.$caller.$owner.parent, + previous = (parent) ? parent.prototype[name] : null; + if (!previous) throw new Error('The method "' + name + '" has no parent.'); + return previous.apply(this, arguments); +}; + +var reset = function(object){ + for (var key in object){ + var value = object[key]; + switch (typeOf(value)){ + case 'object': + var F = function(){}; + F.prototype = value; + object[key] = reset(new F); + break; + case 'array': object[key] = value.clone(); break; + } + } + return object; +}; + +var wrap = function(self, key, method){ + if (method.$origin) method = method.$origin; + var wrapper = function(){ + if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.'); + var caller = this.caller, current = this.$caller; + this.caller = current; this.$caller = wrapper; + var result = method.apply(this, arguments); + this.$caller = current; this.caller = caller; + return result; + }.extend({$owner: self, $origin: method, $name: key}); + return wrapper; +}; + +var implement = function(key, value, retain){ + if (Class.Mutators.hasOwnProperty(key)){ + value = Class.Mutators[key].call(this, value); + if (value == null) return this; + } + + if (typeOf(value) == 'function'){ + if (value.$hidden) return this; + this.prototype[key] = (retain) ? value : wrap(this, key, value); + } else { + Object.merge(this.prototype, key, value); + } + + return this; +}; + +var getInstance = function(klass){ + klass.$prototyping = true; + var proto = new klass; + delete klass.$prototyping; + return proto; +}; + +Class.implement('implement', implement.overloadSetter()); + +Class.Mutators = { + + Extends: function(parent){ + this.parent = parent; + this.prototype = getInstance(parent); + }, + + Implements: function(items){ + Array.from(items).each(function(item){ + var instance = new item; + for (var key in instance) implement.call(this, key, instance[key], true); + }, this); + } +}; + +})(); + + +/* +--- + +name: Class.Extras + +description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. + +license: MIT-style license. + +requires: Class + +provides: [Class.Extras, Chain, Events, Options] + +... +*/ + +(function(){ + +this.Chain = new Class({ + + $chain: [], + + chain: function(){ + this.$chain.append(Array.flatten(arguments)); + return this; + }, + + callChain: function(){ + return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; + }, + + clearChain: function(){ + this.$chain.empty(); + return this; + } + +}); + +var removeOn = function(string){ + return string.replace(/^on([A-Z])/, function(full, first){ + return first.toLowerCase(); + }); +}; + +this.Events = new Class({ + + $events: {}, + + addEvent: function(type, fn, internal){ + type = removeOn(type); + + + + this.$events[type] = (this.$events[type] || []).include(fn); + if (internal) fn.internal = true; + return this; + }, + + addEvents: function(events){ + for (var type in events) this.addEvent(type, events[type]); + return this; + }, + + fireEvent: function(type, args, delay){ + type = removeOn(type); + var events = this.$events[type]; + if (!events) return this; + args = Array.from(args); + events.each(function(fn){ + if (delay) fn.delay(delay, this, args); + else fn.apply(this, args); + }, this); + return this; + }, + + removeEvent: function(type, fn){ + type = removeOn(type); + var events = this.$events[type]; + if (events && !fn.internal){ + var index = events.indexOf(fn); + if (index != -1) delete events[index]; + } + return this; + }, + + removeEvents: function(events){ + var type; + if (typeOf(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + if (events) events = removeOn(events); + for (type in this.$events){ + if (events && events != type) continue; + var fns = this.$events[type]; + for (var i = fns.length; i--;) if (i in fns){ + this.removeEvent(type, fns[i]); + } + } + return this; + } + +}); + +this.Options = new Class({ + + setOptions: function(){ + var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments)); + if (this.addEvent) for (var option in options){ + if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; + this.addEvent(option, options[option]); + delete options[option]; + } + return this; + } + +}); + +})(); + + +/* +--- +name: Slick.Parser +description: Standalone CSS3 Selector parser +provides: Slick.Parser +... +*/ + +;(function(){ + +var parsed, + separatorIndex, + combinatorIndex, + reversed, + cache = {}, + reverseCache = {}, + reUnescape = /\\/g; + +var parse = function(expression, isReversed){ + if (expression == null) return null; + if (expression.Slick === true) return expression; + expression = ('' + expression).replace(/^\s+|\s+$/g, ''); + reversed = !!isReversed; + var currentCache = (reversed) ? reverseCache : cache; + if (currentCache[expression]) return currentCache[expression]; + parsed = { + Slick: true, + expressions: [], + raw: expression, + reverse: function(){ + return parse(this.raw, true); + } + }; + separatorIndex = -1; + while (expression != (expression = expression.replace(regexp, parser))); + parsed.length = parsed.expressions.length; + return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed; +}; + +var reverseCombinator = function(combinator){ + if (combinator === '!') return ' '; + else if (combinator === ' ') return '!'; + else if ((/^!/).test(combinator)) return combinator.replace(/^!/, ''); + else return '!' + combinator; +}; + +var reverse = function(expression){ + var expressions = expression.expressions; + for (var i = 0; i < expressions.length; i++){ + var exp = expressions[i]; + var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)}; + + for (var j = 0; j < exp.length; j++){ + var cexp = exp[j]; + if (!cexp.reverseCombinator) cexp.reverseCombinator = ' '; + cexp.combinator = cexp.reverseCombinator; + delete cexp.reverseCombinator; + } + + exp.reverse().push(last); + } + return expression; +}; + +var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan MIT License + return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){ + return '\\' + match; + }); +}; + +var regexp = new RegExp( +/* +#!/usr/bin/env ruby +puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'') +__END__ + "(?x)^(?:\ + \\s* ( , ) \\s* # Separator \n\ + | \\s* ( + ) \\s* # Combinator \n\ + | ( \\s+ ) # CombinatorChildren \n\ + | ( + | \\* ) # Tag \n\ + | \\# ( + ) # ID \n\ + | \\. ( + ) # ClassName \n\ + | # Attribute \n\ + \\[ \ + \\s* (+) (?: \ + \\s* ([*^$!~|]?=) (?: \ + \\s* (?:\ + ([\"']?)(.*?)\\9 \ + )\ + ) \ + )? \\s* \ + \\](?!\\]) \n\ + | :+ ( + )(?:\ + \\( (?:\ + (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\ + ) \\)\ + )?\ + )" +*/ + "^(?:\\s*(,)\\s*|\\s*(+)\\s*|(\\s+)|(+|\\*)|\\#(+)|\\.(+)|\\[\\s*(+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)" + .replace(//, '[' + escapeRegExp(">+~`!@$%^&={}\\;/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') + .replace(//g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') +); + +function parser( + rawMatch, + + separator, + combinator, + combinatorChildren, + + tagName, + id, + className, + + attributeKey, + attributeOperator, + attributeQuote, + attributeValue, + + pseudoMarker, + pseudoClass, + pseudoQuote, + pseudoClassQuotedValue, + pseudoClassValue +){ + if (separator || separatorIndex === -1){ + parsed.expressions[++separatorIndex] = []; + combinatorIndex = -1; + if (separator) return ''; + } + + if (combinator || combinatorChildren || combinatorIndex === -1){ + combinator = combinator || ' '; + var currentSeparator = parsed.expressions[separatorIndex]; + if (reversed && currentSeparator[combinatorIndex]) + currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator); + currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'}; + } + + var currentParsed = parsed.expressions[separatorIndex][combinatorIndex]; + + if (tagName){ + currentParsed.tag = tagName.replace(reUnescape, ''); + + } else if (id){ + currentParsed.id = id.replace(reUnescape, ''); + + } else if (className){ + className = className.replace(reUnescape, ''); + + if (!currentParsed.classList) currentParsed.classList = []; + if (!currentParsed.classes) currentParsed.classes = []; + currentParsed.classList.push(className); + currentParsed.classes.push({ + value: className, + regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)') + }); + + } else if (pseudoClass){ + pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue; + pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null; + + if (!currentParsed.pseudos) currentParsed.pseudos = []; + currentParsed.pseudos.push({ + key: pseudoClass.replace(reUnescape, ''), + value: pseudoClassValue, + type: pseudoMarker.length == 1 ? 'class' : 'element' + }); + + } else if (attributeKey){ + attributeKey = attributeKey.replace(reUnescape, ''); + attributeValue = (attributeValue || '').replace(reUnescape, ''); + + var test, regexp; + + switch (attributeOperator){ + case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break; + case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break; + case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break; + case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break; + case '=' : test = function(value){ + return attributeValue == value; + }; break; + case '*=' : test = function(value){ + return value && value.indexOf(attributeValue) > -1; + }; break; + case '!=' : test = function(value){ + return attributeValue != value; + }; break; + default : test = function(value){ + return !!value; + }; + } + + if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){ + return false; + }; + + if (!test) test = function(value){ + return value && regexp.test(value); + }; + + if (!currentParsed.attributes) currentParsed.attributes = []; + currentParsed.attributes.push({ + key: attributeKey, + operator: attributeOperator, + value: attributeValue, + test: test + }); + + } + + return ''; +}; + +// Slick NS + +var Slick = (this.Slick || {}); + +Slick.parse = function(expression){ + return parse(expression); +}; + +Slick.escapeRegExp = escapeRegExp; + +if (!this.Slick) this.Slick = Slick; + +}).apply(/**/(typeof exports != 'undefined') ? exports : /**/this); + + +/* +--- +name: Slick.Finder +description: The new, superfast css selector engine. +provides: Slick.Finder +requires: Slick.Parser +... +*/ + +;(function(){ + +var local = {}, + featuresCache = {}, + toString = Object.prototype.toString; + +// Feature / Bug detection + +local.isNativeCode = function(fn){ + return (/\{\s*\[native code\]\s*\}/).test('' + fn); +}; + +local.isXML = function(document){ + return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') || + (document.nodeType == 9 && document.documentElement.nodeName != 'HTML'); +}; + +local.setDocument = function(document){ + + // convert elements / window arguments to document. if document cannot be extrapolated, the function returns. + var nodeType = document.nodeType; + if (nodeType == 9); // document + else if (nodeType) document = document.ownerDocument; // node + else if (document.navigator) document = document.document; // window + else return; + + // check if it's the old document + + if (this.document === document) return; + this.document = document; + + // check if we have done feature detection on this document before + + var root = document.documentElement, + rootUid = this.getUIDXML(root), + features = featuresCache[rootUid], + feature; + + if (features){ + for (feature in features){ + this[feature] = features[feature]; + } + return; + } + + features = featuresCache[rootUid] = {}; + + features.root = root; + features.isXMLDocument = this.isXML(document); + + features.brokenStarGEBTN + = features.starSelectsClosedQSA + = features.idGetsName + = features.brokenMixedCaseQSA + = features.brokenGEBCN + = features.brokenCheckedQSA + = features.brokenEmptyAttributeQSA + = features.isHTMLDocument + = features.nativeMatchesSelector + = false; + + var starSelectsClosed, starSelectsComments, + brokenSecondClassNameGEBCN, cachedGetElementsByClassName, + brokenFormAttributeGetter; + + var selected, id = 'slick_uniqueid'; + var testNode = document.createElement('div'); + + var testRoot = document.body || document.getElementsByTagName('body')[0] || root; + testRoot.appendChild(testNode); + + // on non-HTML documents innerHTML and getElementsById doesnt work properly + try { + testNode.innerHTML = ''; + features.isHTMLDocument = !!document.getElementById(id); + } catch(e){}; + + if (features.isHTMLDocument){ + + testNode.style.display = 'none'; + + // IE returns comment nodes for getElementsByTagName('*') for some documents + testNode.appendChild(document.createComment('')); + starSelectsComments = (testNode.getElementsByTagName('*').length > 1); + + // IE returns closed nodes (EG:"") for getElementsByTagName('*') for some documents + try { + testNode.innerHTML = 'foo'; + selected = testNode.getElementsByTagName('*'); + starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/'); + } catch(e){}; + + features.brokenStarGEBTN = starSelectsComments || starSelectsClosed; + + // IE returns elements with the name instead of just id for getElementsById for some documents + try { + testNode.innerHTML = ''; + features.idGetsName = document.getElementById(id) === testNode.firstChild; + } catch(e){}; + + if (testNode.getElementsByClassName){ + + // Safari 3.2 getElementsByClassName caches results + try { + testNode.innerHTML = ''; + testNode.getElementsByClassName('b').length; + testNode.firstChild.className = 'b'; + cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2); + } catch(e){}; + + // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one + try { + testNode.innerHTML = ''; + brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2); + } catch(e){}; + + features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN; + } + + if (testNode.querySelectorAll){ + // IE 8 returns closed nodes (EG:"") for querySelectorAll('*') for some documents + try { + testNode.innerHTML = 'foo'; + selected = testNode.querySelectorAll('*'); + features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/'); + } catch(e){}; + + // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode + try { + testNode.innerHTML = ''; + features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length; + } catch(e){}; + + // Webkit and Opera dont return selected options on querySelectorAll + try { + testNode.innerHTML = ''; + features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0); + } catch(e){}; + + // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll + try { + testNode.innerHTML = ''; + features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0); + } catch(e){}; + + } + + // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input + try { + testNode.innerHTML = '
'; + brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's'); + } catch(e){}; + + // native matchesSelector function + + features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector; + if (features.nativeMatchesSelector) try { + // if matchesSelector trows errors on incorrect sintaxes we can use it + features.nativeMatchesSelector.call(root, ':slick'); + features.nativeMatchesSelector = null; + } catch(e){}; + + } + + try { + root.slick_expando = 1; + delete root.slick_expando; + features.getUID = this.getUIDHTML; + } catch(e) { + features.getUID = this.getUIDXML; + } + + testRoot.removeChild(testNode); + testNode = selected = testRoot = null; + + // getAttribute + + features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){ + var method = this.attributeGetters[name]; + if (method) return method.call(node); + var attributeNode = node.getAttributeNode(name); + return (attributeNode) ? attributeNode.nodeValue : null; + } : function(node, name){ + var method = this.attributeGetters[name]; + return (method) ? method.call(node) : node.getAttribute(name); + }; + + // hasAttribute + + features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) { + return node.hasAttribute(attribute); + } : function(node, attribute) { + node = node.getAttributeNode(attribute); + return !!(node && (node.specified || node.nodeValue)); + }; + + // contains + // FIXME: Add specs: local.contains should be different for xml and html documents? + features.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){ + return context.contains(node); + } : (root && root.compareDocumentPosition) ? function(context, node){ + return context === node || !!(context.compareDocumentPosition(node) & 16); + } : function(context, node){ + if (node) do { + if (node === context) return true; + } while ((node = node.parentNode)); + return false; + }; + + // document order sorting + // credits to Sizzle (http://sizzlejs.com/) + + features.documentSorter = (root.compareDocumentPosition) ? function(a, b){ + if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0; + return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + } : ('sourceIndex' in root) ? function(a, b){ + if (!a.sourceIndex || !b.sourceIndex) return 0; + return a.sourceIndex - b.sourceIndex; + } : (document.createRange) ? function(a, b){ + if (!a.ownerDocument || !b.ownerDocument) return 0; + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + return aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + } : null ; + + root = null; + + for (feature in features){ + this[feature] = features[feature]; + } +}; + +// Main Method + +var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/, + reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/, + qsaFailExpCache = {}; + +local.search = function(context, expression, append, first){ + + var found = this.found = (first) ? null : (append || []); + + if (!context) return found; + else if (context.navigator) context = context.document; // Convert the node from a window to a document + else if (!context.nodeType) return found; + + // setup + + var parsed, i, + uniques = this.uniques = {}, + hasOthers = !!(append && append.length), + contextIsDocument = (context.nodeType == 9); + + if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context); + + // avoid duplicating items already in the append array + if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true; + + // expression checks + + if (typeof expression == 'string'){ // expression is a string + + /**/ + var simpleSelector = expression.match(reSimpleSelector); + simpleSelectors: if (simpleSelector) { + + var symbol = simpleSelector[1], + name = simpleSelector[2], + node, nodes; + + if (!symbol){ + + if (name == '*' && this.brokenStarGEBTN) break simpleSelectors; + nodes = context.getElementsByTagName(name); + if (first) return nodes[0] || null; + for (i = 0; node = nodes[i++];){ + if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); + } + + } else if (symbol == '#'){ + + if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors; + node = context.getElementById(name); + if (!node) return found; + if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors; + if (first) return node || null; + if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); + + } else if (symbol == '.'){ + + if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors; + if (context.getElementsByClassName && !this.brokenGEBCN){ + nodes = context.getElementsByClassName(name); + if (first) return nodes[0] || null; + for (i = 0; node = nodes[i++];){ + if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); + } + } else { + var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)'); + nodes = context.getElementsByTagName('*'); + for (i = 0; node = nodes[i++];){ + className = node.className; + if (!(className && matchClass.test(className))) continue; + if (first) return node; + if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); + } + } + + } + + if (hasOthers) this.sort(found); + return (first) ? null : found; + + } + /**/ + + /**/ + querySelector: if (context.querySelectorAll) { + + if (!this.isHTMLDocument + || qsaFailExpCache[expression] + //TODO: only skip when expression is actually mixed case + || this.brokenMixedCaseQSA + || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1) + || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) + || (!contextIsDocument //Abort when !contextIsDocument and... + // there are multiple expressions in the selector + // since we currently only fix non-document rooted QSA for single expression selectors + && expression.indexOf(',') > -1 + ) + || Slick.disableQSA + ) break querySelector; + + var _expression = expression, _context = context; + if (!contextIsDocument){ + // non-document rooted QSA + // credits to Andrew Dupont + var currentId = _context.getAttribute('id'), slickid = 'slickid__'; + _context.setAttribute('id', slickid); + _expression = '#' + slickid + ' ' + _expression; + context = _context.parentNode; + } + + try { + if (first) return context.querySelector(_expression) || null; + else nodes = context.querySelectorAll(_expression); + } catch(e) { + qsaFailExpCache[expression] = 1; + break querySelector; + } finally { + if (!contextIsDocument){ + if (currentId) _context.setAttribute('id', currentId); + else _context.removeAttribute('id'); + context = _context; + } + } + + if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){ + if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node); + } else for (i = 0; node = nodes[i++];){ + if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); + } + + if (hasOthers) this.sort(found); + return found; + + } + /**/ + + parsed = this.Slick.parse(expression); + if (!parsed.length) return found; + } else if (expression == null){ // there is no expression + return found; + } else if (expression.Slick){ // expression is a parsed Slick object + parsed = expression; + } else if (this.contains(context.documentElement || context, expression)){ // expression is a node + (found) ? found.push(expression) : found = expression; + return found; + } else { // other junk + return found; + } + + /**//**/ + + // cache elements for the nth selectors + + this.posNTH = {}; + this.posNTHLast = {}; + this.posNTHType = {}; + this.posNTHTypeLast = {}; + + /**//**/ + + // if append is null and there is only a single selector with one expression use pushArray, else use pushUID + this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID; + + if (found == null) found = []; + + // default engine + + var j, m, n; + var combinator, tag, id, classList, classes, attributes, pseudos; + var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions; + + search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){ + + combinator = 'combinator:' + currentBit.combinator; + if (!this[combinator]) continue search; + + tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase(); + id = currentBit.id; + classList = currentBit.classList; + classes = currentBit.classes; + attributes = currentBit.attributes; + pseudos = currentBit.pseudos; + lastBit = (j === (currentExpression.length - 1)); + + this.bitUniques = {}; + + if (lastBit){ + this.uniques = uniques; + this.found = found; + } else { + this.uniques = {}; + this.found = []; + } + + if (j === 0){ + this[combinator](context, tag, id, classes, attributes, pseudos, classList); + if (first && lastBit && found.length) break search; + } else { + if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){ + this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); + if (found.length) break search; + } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); + } + + currentItems = this.found; + } + + // should sort if there are nodes in append and if you pass multiple expressions. + if (hasOthers || (parsed.expressions.length > 1)) this.sort(found); + + return (first) ? (found[0] || null) : found; +}; + +// Utils + +local.uidx = 1; +local.uidk = 'slick-uniqueid'; + +local.getUIDXML = function(node){ + var uid = node.getAttribute(this.uidk); + if (!uid){ + uid = this.uidx++; + node.setAttribute(this.uidk, uid); + } + return uid; +}; + +local.getUIDHTML = function(node){ + return node.uniqueNumber || (node.uniqueNumber = this.uidx++); +}; + +// sort based on the setDocument documentSorter method. + +local.sort = function(results){ + if (!this.documentSorter) return results; + results.sort(this.documentSorter); + return results; +}; + +/**//**/ + +local.cacheNTH = {}; + +local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/; + +local.parseNTHArgument = function(argument){ + var parsed = argument.match(this.matchNTH); + if (!parsed) return false; + var special = parsed[2] || false; + var a = parsed[1] || 1; + if (a == '-') a = -1; + var b = +parsed[3] || 0; + parsed = + (special == 'n') ? {a: a, b: b} : + (special == 'odd') ? {a: 2, b: 1} : + (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a}; + + return (this.cacheNTH[argument] = parsed); +}; + +local.createNTHPseudo = function(child, sibling, positions, ofType){ + return function(node, argument){ + var uid = this.getUID(node); + if (!this[positions][uid]){ + var parent = node.parentNode; + if (!parent) return false; + var el = parent[child], count = 1; + if (ofType){ + var nodeName = node.nodeName; + do { + if (el.nodeName != nodeName) continue; + this[positions][this.getUID(el)] = count++; + } while ((el = el[sibling])); + } else { + do { + if (el.nodeType != 1) continue; + this[positions][this.getUID(el)] = count++; + } while ((el = el[sibling])); + } + } + argument = argument || 'n'; + var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument); + if (!parsed) return false; + var a = parsed.a, b = parsed.b, pos = this[positions][uid]; + if (a == 0) return b == pos; + if (a > 0){ + if (pos < b) return false; + } else { + if (b < pos) return false; + } + return ((pos - b) % a) == 0; + }; +}; + +/**//**/ + +local.pushArray = function(node, tag, id, classes, attributes, pseudos){ + if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node); +}; + +local.pushUID = function(node, tag, id, classes, attributes, pseudos){ + var uid = this.getUID(node); + if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){ + this.uniques[uid] = true; + this.found.push(node); + } +}; + +local.matchNode = function(node, selector){ + if (this.isHTMLDocument && this.nativeMatchesSelector){ + try { + return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]')); + } catch(matchError) {} + } + + var parsed = this.Slick.parse(selector); + if (!parsed) return true; + + // simple (single) selectors + var expressions = parsed.expressions, reversedExpressions, simpleExpCounter = 0, i; + for (i = 0; (currentExpression = expressions[i]); i++){ + if (currentExpression.length == 1){ + var exp = currentExpression[0]; + if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true; + simpleExpCounter++; + } + } + + if (simpleExpCounter == parsed.length) return false; + + var nodes = this.search(this.document, parsed), item; + for (i = 0; item = nodes[i++];){ + if (item === node) return true; + } + return false; +}; + +local.matchPseudo = function(node, name, argument){ + var pseudoName = 'pseudo:' + name; + if (this[pseudoName]) return this[pseudoName](node, argument); + var attribute = this.getAttribute(node, name); + return (argument) ? argument == attribute : !!attribute; +}; + +local.matchSelector = function(node, tag, id, classes, attributes, pseudos){ + if (tag){ + var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase(); + if (tag == '*'){ + if (nodeName < '@') return false; // Fix for comment nodes and closed nodes + } else { + if (nodeName != tag) return false; + } + } + + if (id && node.getAttribute('id') != id) return false; + + var i, part, cls; + if (classes) for (i = classes.length; i--;){ + cls = node.getAttribute('class') || node.className; + if (!(cls && classes[i].regexp.test(cls))) return false; + } + if (attributes) for (i = attributes.length; i--;){ + part = attributes[i]; + if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false; + } + if (pseudos) for (i = pseudos.length; i--;){ + part = pseudos[i]; + if (!this.matchPseudo(node, part.key, part.value)) return false; + } + return true; +}; + +var combinators = { + + ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level + + var i, item, children; + + if (this.isHTMLDocument){ + getById: if (id){ + item = this.document.getElementById(id); + if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){ + // all[id] returns all the elements with that name or id inside node + // if theres just one it will return the element, else it will be a collection + children = node.all[id]; + if (!children) return; + if (!children[0]) children = [children]; + for (i = 0; item = children[i++];){ + var idNode = item.getAttributeNode('id'); + if (idNode && idNode.nodeValue == id){ + this.push(item, tag, null, classes, attributes, pseudos); + break; + } + } + return; + } + if (!item){ + // if the context is in the dom we return, else we will try GEBTN, breaking the getById label + if (this.contains(this.root, node)) return; + else break getById; + } else if (this.document !== node && !this.contains(node, item)) return; + this.push(item, tag, null, classes, attributes, pseudos); + return; + } + getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){ + children = node.getElementsByClassName(classList.join(' ')); + if (!(children && children.length)) break getByClass; + for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos); + return; + } + } + getByTag: { + children = node.getElementsByTagName(tag); + if (!(children && children.length)) break getByTag; + if (!this.brokenStarGEBTN) tag = null; + for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos); + } + }, + + '>': function(node, tag, id, classes, attributes, pseudos){ // direct children + if ((node = node.firstChild)) do { + if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); + } while ((node = node.nextSibling)); + }, + + '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling + while ((node = node.nextSibling)) if (node.nodeType == 1){ + this.push(node, tag, id, classes, attributes, pseudos); + break; + } + }, + + '^': function(node, tag, id, classes, attributes, pseudos){ // first child + node = node.firstChild; + if (node){ + if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); + else this['combinator:+'](node, tag, id, classes, attributes, pseudos); + } + }, + + '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings + while ((node = node.nextSibling)){ + if (node.nodeType != 1) continue; + var uid = this.getUID(node); + if (this.bitUniques[uid]) break; + this.bitUniques[uid] = true; + this.push(node, tag, id, classes, attributes, pseudos); + } + }, + + '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling + this['combinator:+'](node, tag, id, classes, attributes, pseudos); + this['combinator:!+'](node, tag, id, classes, attributes, pseudos); + }, + + '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings + this['combinator:~'](node, tag, id, classes, attributes, pseudos); + this['combinator:!~'](node, tag, id, classes, attributes, pseudos); + }, + + '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document + while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); + }, + + '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level) + node = node.parentNode; + if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); + }, + + '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling + while ((node = node.previousSibling)) if (node.nodeType == 1){ + this.push(node, tag, id, classes, attributes, pseudos); + break; + } + }, + + '!^': function(node, tag, id, classes, attributes, pseudos){ // last child + node = node.lastChild; + if (node){ + if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); + else this['combinator:!+'](node, tag, id, classes, attributes, pseudos); + } + }, + + '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings + while ((node = node.previousSibling)){ + if (node.nodeType != 1) continue; + var uid = this.getUID(node); + if (this.bitUniques[uid]) break; + this.bitUniques[uid] = true; + this.push(node, tag, id, classes, attributes, pseudos); + } + } + +}; + +for (var c in combinators) local['combinator:' + c] = combinators[c]; + +var pseudos = { + + /**/ + + 'empty': function(node){ + var child = node.firstChild; + return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length; + }, + + 'not': function(node, expression){ + return !this.matchNode(node, expression); + }, + + 'contains': function(node, text){ + return (node.innerText || node.textContent || '').indexOf(text) > -1; + }, + + 'first-child': function(node){ + while ((node = node.previousSibling)) if (node.nodeType == 1) return false; + return true; + }, + + 'last-child': function(node){ + while ((node = node.nextSibling)) if (node.nodeType == 1) return false; + return true; + }, + + 'only-child': function(node){ + var prev = node; + while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false; + var next = node; + while ((next = next.nextSibling)) if (next.nodeType == 1) return false; + return true; + }, + + /**/ + + 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'), + + 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'), + + 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true), + + 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true), + + 'index': function(node, index){ + return this['pseudo:nth-child'](node, '' + index + 1); + }, + + 'even': function(node){ + return this['pseudo:nth-child'](node, '2n'); + }, + + 'odd': function(node){ + return this['pseudo:nth-child'](node, '2n+1'); + }, + + /**/ + + /**/ + + 'first-of-type': function(node){ + var nodeName = node.nodeName; + while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false; + return true; + }, + + 'last-of-type': function(node){ + var nodeName = node.nodeName; + while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false; + return true; + }, + + 'only-of-type': function(node){ + var prev = node, nodeName = node.nodeName; + while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false; + var next = node; + while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false; + return true; + }, + + /**/ + + // custom pseudos + + 'enabled': function(node){ + return !node.disabled; + }, + + 'disabled': function(node){ + return node.disabled; + }, + + 'checked': function(node){ + return node.checked || node.selected; + }, + + 'focus': function(node){ + return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex')); + }, + + 'root': function(node){ + return (node === this.root); + }, + + 'selected': function(node){ + return node.selected; + } + + /**/ +}; + +for (var p in pseudos) local['pseudo:' + p] = pseudos[p]; + +// attributes methods + +local.attributeGetters = { + + 'class': function(){ + return this.getAttribute('class') || this.className; + }, + + 'for': function(){ + return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for'); + }, + + 'href': function(){ + return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href'); + }, + + 'style': function(){ + return (this.style) ? this.style.cssText : this.getAttribute('style'); + }, + + 'tabindex': function(){ + var attributeNode = this.getAttributeNode('tabindex'); + return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; + }, + + 'type': function(){ + return this.getAttribute('type'); + } + +}; + +// Slick + +var Slick = local.Slick = (this.Slick || {}); + +Slick.version = '1.1.5'; + +// Slick finder + +Slick.search = function(context, expression, append){ + return local.search(context, expression, append); +}; + +Slick.find = function(context, expression){ + return local.search(context, expression, null, true); +}; + +// Slick containment checker + +Slick.contains = function(container, node){ + local.setDocument(container); + return local.contains(container, node); +}; + +// Slick attribute getter + +Slick.getAttribute = function(node, name){ + return local.getAttribute(node, name); +}; + +// Slick matcher + +Slick.match = function(node, selector){ + if (!(node && selector)) return false; + if (!selector || selector === node) return true; + local.setDocument(node); + return local.matchNode(node, selector); +}; + +// Slick attribute accessor + +Slick.defineAttributeGetter = function(name, fn){ + local.attributeGetters[name] = fn; + return this; +}; + +Slick.lookupAttributeGetter = function(name){ + return local.attributeGetters[name]; +}; + +// Slick pseudo accessor + +Slick.definePseudo = function(name, fn){ + local['pseudo:' + name] = function(node, argument){ + return fn.call(node, argument); + }; + return this; +}; + +Slick.lookupPseudo = function(name){ + var pseudo = local['pseudo:' + name]; + if (pseudo) return function(argument){ + return pseudo.call(this, argument); + }; + return null; +}; + +// Slick overrides accessor + +Slick.override = function(regexp, fn){ + local.override(regexp, fn); + return this; +}; + +Slick.isXML = local.isXML; + +Slick.uidOf = function(node){ + return local.getUIDHTML(node); +}; + +if (!this.Slick) this.Slick = Slick; + +}).apply(/**/(typeof exports != 'undefined') ? exports : /**/this); + + +/* +--- + +name: Element + +description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. + +license: MIT-style license. + +requires: [Window, Document, Array, String, Function, Number, Slick.Parser, Slick.Finder] + +provides: [Element, Elements, $, $$, Iframe, Selectors] + +... +*/ + +var Element = function(tag, props){ + var konstructor = Element.Constructors[tag]; + if (konstructor) return konstructor(props); + if (typeof tag != 'string') return document.id(tag).set(props); + + if (!props) props = {}; + + if (!(/^[\w-]+$/).test(tag)){ + var parsed = Slick.parse(tag).expressions[0][0]; + tag = (parsed.tag == '*') ? 'div' : parsed.tag; + if (parsed.id && props.id == null) props.id = parsed.id; + + var attributes = parsed.attributes; + if (attributes) for (var i = 0, l = attributes.length; i < l; i++){ + var attr = attributes[i]; + if (props[attr.key] != null) continue; + + if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value; + else if (!attr.value && !attr.operator) props[attr.key] = true; + } + + if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' '); + } + + return document.newElement(tag, props); +}; + +if (Browser.Element) Element.prototype = Browser.Element.prototype; + +new Type('Element', Element).mirror(function(name){ + if (Array.prototype[name]) return; + + var obj = {}; + obj[name] = function(){ + var results = [], args = arguments, elements = true; + for (var i = 0, l = this.length; i < l; i++){ + var element = this[i], result = results[i] = element[name].apply(element, args); + elements = (elements && typeOf(result) == 'element'); + } + return (elements) ? new Elements(results) : results; + }; + + Elements.implement(obj); +}); + +if (!Browser.Element){ + Element.parent = Object; + + Element.Prototype = {'$family': Function.from('element').hide()}; + + Element.mirror(function(name, method){ + Element.Prototype[name] = method; + }); +} + +Element.Constructors = {}; + + + +var IFrame = new Type('IFrame', function(){ + var params = Array.link(arguments, { + properties: Type.isObject, + iframe: function(obj){ + return (obj != null); + } + }); + + var props = params.properties || {}, iframe; + if (params.iframe) iframe = document.id(params.iframe); + var onload = props.onload || function(){}; + delete props.onload; + props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick(); + iframe = new Element(iframe || 'iframe', props); + + var onLoad = function(){ + onload.call(iframe.contentWindow); + }; + + if (window.frames[props.id]) onLoad(); + else iframe.addListener('load', onLoad); + return iframe; +}); + +var Elements = this.Elements = function(nodes){ + if (nodes && nodes.length){ + var uniques = {}, node; + for (var i = 0; node = nodes[i++];){ + var uid = Slick.uidOf(node); + if (!uniques[uid]){ + uniques[uid] = true; + this.push(node); + } + } + } +}; + +Elements.prototype = {length: 0}; +Elements.parent = Array; + +new Type('Elements', Elements).implement({ + + filter: function(filter, bind){ + if (!filter) return this; + return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){ + return item.match(filter); + } : filter, bind)); + }.protect(), + + push: function(){ + var length = this.length; + for (var i = 0, l = arguments.length; i < l; i++){ + var item = document.id(arguments[i]); + if (item) this[length++] = item; + } + return (this.length = length); + }.protect(), + + unshift: function(){ + var items = []; + for (var i = 0, l = arguments.length; i < l; i++){ + var item = document.id(arguments[i]); + if (item) items.push(item); + } + return Array.prototype.unshift.apply(this, items); + }.protect(), + + concat: function(){ + var newElements = new Elements(this); + for (var i = 0, l = arguments.length; i < l; i++){ + var item = arguments[i]; + if (Type.isEnumerable(item)) newElements.append(item); + else newElements.push(item); + } + return newElements; + }.protect(), + + append: function(collection){ + for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]); + return this; + }.protect(), + + empty: function(){ + while (this.length) delete this[--this.length]; + return this; + }.protect() + +}); + + + +(function(){ + +// FF, IE +var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2}; + +splice.call(object, 1, 1); +if (object[1] == 1) Elements.implement('splice', function(){ + var length = this.length; + splice.apply(this, arguments); + while (length >= this.length) delete this[length--]; + return this; +}.protect()); + +Elements.implement(Array.prototype); + +Array.mirror(Elements); + +/**/ +var createElementAcceptsHTML; +try { + var x = document.createElement(''); + createElementAcceptsHTML = (x.name == 'x'); +} catch(e){} + +var escapeQuotes = function(html){ + return ('' + html).replace(/&/g, '&').replace(/"/g, '"'); +}; +/**/ + +Document.implement({ + + newElement: function(tag, props){ + if (props && props.checked != null) props.defaultChecked = props.checked; + /**/// Fix for readonly name and type properties in IE < 8 + if (createElementAcceptsHTML && props){ + tag = '<' + tag; + if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"'; + if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"'; + tag += '>'; + delete props.name; + delete props.type; + } + /**/ + return this.id(this.createElement(tag)).set(props); + } + +}); + +})(); + +Document.implement({ + + newTextNode: function(text){ + return this.createTextNode(text); + }, + + getDocument: function(){ + return this; + }, + + getWindow: function(){ + return this.window; + }, + + id: (function(){ + + var types = { + + string: function(id, nocash, doc){ + id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1')); + return (id) ? types.element(id, nocash) : null; + }, + + element: function(el, nocash){ + $uid(el); + if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){ + Object.append(el, Element.Prototype); + } + return el; + }, + + object: function(obj, nocash, doc){ + if (obj.toElement) return types.element(obj.toElement(doc), nocash); + return null; + } + + }; + + types.textnode = types.whitespace = types.window = types.document = function(zero){ + return zero; + }; + + return function(el, nocash, doc){ + if (el && el.$family && el.uid) return el; + var type = typeOf(el); + return (types[type]) ? types[type](el, nocash, doc || document) : null; + }; + + })() + +}); + +if (window.$ == null) Window.implement('$', function(el, nc){ + return document.id(el, nc, this.document); +}); + +Window.implement({ + + getDocument: function(){ + return this.document; + }, + + getWindow: function(){ + return this; + } + +}); + +[Document, Element].invoke('implement', { + + getElements: function(expression){ + return Slick.search(this, expression, new Elements); + }, + + getElement: function(expression){ + return document.id(Slick.find(this, expression)); + } + +}); + + + +if (window.$$ == null) Window.implement('$$', function(selector){ + if (arguments.length == 1){ + if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements); + else if (Type.isEnumerable(selector)) return new Elements(selector); + } + return new Elements(arguments); +}); + +(function(){ + +var collected = {}, storage = {}; +var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; + +var get = function(uid){ + return (storage[uid] || (storage[uid] = {})); +}; + +var clean = function(item){ + var uid = item.uid; + if (item.removeEvents) item.removeEvents(); + if (item.clearAttributes) item.clearAttributes(); + if (uid != null){ + delete collected[uid]; + delete storage[uid]; + } + return item; +}; + +var camels = ['defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', + 'rowSpan', 'tabIndex', 'useMap' +]; +var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected', + 'noresize', 'defer', 'defaultChecked' +]; + var attributes = { + 'html': 'innerHTML', + 'class': 'className', + 'for': 'htmlFor', + 'text': (function(){ + var temp = document.createElement('div'); + return (temp.textContent == null) ? 'innerText' : 'textContent'; + })() +}; +var readOnly = ['type']; +var expandos = ['value', 'defaultValue']; +var uriAttrs = /^(?:href|src|usemap)$/i; + +bools = bools.associate(bools); +camels = camels.associate(camels.map(String.toLowerCase)); +readOnly = readOnly.associate(readOnly); + +Object.append(attributes, expandos.associate(expandos)); + +var inserters = { + + before: function(context, element){ + var parent = element.parentNode; + if (parent) parent.insertBefore(context, element); + }, + + after: function(context, element){ + var parent = element.parentNode; + if (parent) parent.insertBefore(context, element.nextSibling); + }, + + bottom: function(context, element){ + element.appendChild(context); + }, + + top: function(context, element){ + element.insertBefore(context, element.firstChild); + } + +}; + +inserters.inside = inserters.bottom; + + + +var injectCombinator = function(expression, combinator){ + if (!expression) return combinator; + + expression = Object.clone(Slick.parse(expression)); + + var expressions = expression.expressions; + for (var i = expressions.length; i--;) + expressions[i][0].combinator = combinator; + + return expression; +}; + +Element.implement({ + + set: function(prop, value){ + var property = Element.Properties[prop]; + (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value); + }.overloadSetter(), + + get: function(prop){ + var property = Element.Properties[prop]; + return (property && property.get) ? property.get.apply(this) : this.getProperty(prop); + }.overloadGetter(), + + erase: function(prop){ + var property = Element.Properties[prop]; + (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); + return this; + }, + + setProperty: function(attribute, value){ + attribute = camels[attribute] || attribute; + if (value == null) return this.removeProperty(attribute); + var key = attributes[attribute]; + (key) ? this[key] = value : + (bools[attribute]) ? this[attribute] = !!value : this.setAttribute(attribute, '' + value); + return this; + }, + + setProperties: function(attributes){ + for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); + return this; + }, + + getProperty: function(attribute){ + attribute = camels[attribute] || attribute; + var key = attributes[attribute] || readOnly[attribute]; + return (key) ? this[key] : + (bools[attribute]) ? !!this[attribute] : + (uriAttrs.test(attribute) ? this.getAttribute(attribute, 2) : + (key = this.getAttributeNode(attribute)) ? key.nodeValue : null) || null; + }, + + getProperties: function(){ + var args = Array.from(arguments); + return args.map(this.getProperty, this).associate(args); + }, + + removeProperty: function(attribute){ + attribute = camels[attribute] || attribute; + var key = attributes[attribute]; + (key) ? this[key] = '' : + (bools[attribute]) ? this[attribute] = false : this.removeAttribute(attribute); + return this; + }, + + removeProperties: function(){ + Array.each(arguments, this.removeProperty, this); + return this; + }, + + hasClass: function(className){ + return this.className.clean().contains(className, ' '); + }, + + addClass: function(className){ + if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); + return this; + }, + + removeClass: function(className){ + this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); + return this; + }, + + toggleClass: function(className, force){ + if (force == null) force = !this.hasClass(className); + return (force) ? this.addClass(className) : this.removeClass(className); + }, + + adopt: function(){ + var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length; + if (length > 1) parent = fragment = document.createDocumentFragment(); + + for (var i = 0; i < length; i++){ + var element = document.id(elements[i], true); + if (element) parent.appendChild(element); + } + + if (fragment) this.appendChild(fragment); + + return this; + }, + + appendText: function(text, where){ + return this.grab(this.getDocument().newTextNode(text), where); + }, + + grab: function(el, where){ + inserters[where || 'bottom'](document.id(el, true), this); + return this; + }, + + inject: function(el, where){ + inserters[where || 'bottom'](this, document.id(el, true)); + return this; + }, + + replaces: function(el){ + el = document.id(el, true); + el.parentNode.replaceChild(this, el); + return this; + }, + + wraps: function(el, where){ + el = document.id(el, true); + return this.replaces(el).grab(el, where); + }, + + getPrevious: function(expression){ + return document.id(Slick.find(this, injectCombinator(expression, '!~'))); + }, + + getAllPrevious: function(expression){ + return Slick.search(this, injectCombinator(expression, '!~'), new Elements); + }, + + getNext: function(expression){ + return document.id(Slick.find(this, injectCombinator(expression, '~'))); + }, + + getAllNext: function(expression){ + return Slick.search(this, injectCombinator(expression, '~'), new Elements); + }, + + getFirst: function(expression){ + return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]); + }, + + getLast: function(expression){ + return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast()); + }, + + getParent: function(expression){ + return document.id(Slick.find(this, injectCombinator(expression, '!'))); + }, + + getParents: function(expression){ + return Slick.search(this, injectCombinator(expression, '!'), new Elements); + }, + + getSiblings: function(expression){ + return Slick.search(this, injectCombinator(expression, '~~'), new Elements); + }, + + getChildren: function(expression){ + return Slick.search(this, injectCombinator(expression, '>'), new Elements); + }, + + getWindow: function(){ + return this.ownerDocument.window; + }, + + getDocument: function(){ + return this.ownerDocument; + }, + + getElementById: function(id){ + return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); + }, + + getSelected: function(){ + this.selectedIndex; // Safari 3.2.1 + return new Elements(Array.from(this.options).filter(function(option){ + return option.selected; + })); + }, + + toQueryString: function(){ + var queryString = []; + this.getElements('input, select, textarea').each(function(el){ + var type = el.type; + if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return; + + var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){ + // IE + return document.id(opt).get('value'); + }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value'); + + Array.from(value).each(function(val){ + if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val)); + }); + }); + return queryString.join('&'); + }, + + destroy: function(){ + var children = clean(this).getElementsByTagName('*'); + Array.each(children, clean); + Element.dispose(this); + return null; + }, + + empty: function(){ + Array.from(this.childNodes).each(Element.dispose); + return this; + }, + + dispose: function(){ + return (this.parentNode) ? this.parentNode.removeChild(this) : this; + }, + + match: function(expression){ + return !expression || Slick.match(this, expression); + } + +}); + +var cleanClone = function(node, element, keepid){ + if (!keepid) node.setAttributeNode(document.createAttribute('id')); + if (node.clearAttributes){ + node.clearAttributes(); + node.mergeAttributes(element); + node.removeAttribute('uid'); + if (node.options){ + var no = node.options, eo = element.options; + for (var i = no.length; i--;) no[i].selected = eo[i].selected; + } + } + + var prop = formProps[element.tagName.toLowerCase()]; + if (prop && element[prop]) node[prop] = element[prop]; +}; + +Element.implement('clone', function(contents, keepid){ + contents = contents !== false; + var clone = this.cloneNode(contents), i; + + if (contents){ + var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); + for (i = ce.length; i--;) cleanClone(ce[i], te[i], keepid); + } + + cleanClone(clone, this, keepid); + + if (Browser.ie){ + var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object'); + for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; + } + return document.id(clone); +}); + +var contains = {contains: function(element){ + return Slick.contains(this, element); +}}; + +if (!document.contains) Document.implement(contains); +if (!document.createElement('div').contains) Element.implement(contains); + + + +[Element, Window, Document].invoke('implement', { + + addListener: function(type, fn){ + if (type == 'unload'){ + var old = fn, self = this; + fn = function(){ + self.removeListener('unload', fn); + old(); + }; + } else { + collected[$uid(this)] = this; + } + if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]); + else this.attachEvent('on' + type, fn); + return this; + }, + + removeListener: function(type, fn){ + if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]); + else this.detachEvent('on' + type, fn); + return this; + }, + + retrieve: function(property, dflt){ + var storage = get($uid(this)), prop = storage[property]; + if (dflt != null && prop == null) prop = storage[property] = dflt; + return prop != null ? prop : null; + }, + + store: function(property, value){ + var storage = get($uid(this)); + storage[property] = value; + return this; + }, + + eliminate: function(property){ + var storage = get($uid(this)); + delete storage[property]; + return this; + } + +}); + +/**/ +if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){ + Object.each(collected, clean); + if (window.CollectGarbage) CollectGarbage(); +}); +/**/ + +})(); + +Element.Properties = {}; + + + +Element.Properties.style = { + + set: function(style){ + this.style.cssText = style; + }, + + get: function(){ + return this.style.cssText; + }, + + erase: function(){ + this.style.cssText = ''; + } + +}; + +Element.Properties.tag = { + + get: function(){ + return this.tagName.toLowerCase(); + } + +}; + +/**/ +(function(maxLength){ + if (maxLength != null) Element.Properties.maxlength = Element.Properties.maxLength = { + get: function(){ + var maxlength = this.getAttribute('maxLength'); + return maxlength == maxLength ? null : maxlength; + } + }; +})(document.createElement('input').getAttribute('maxLength')); +/**/ + +/**/ +Element.Properties.html = (function(){ + + var tableTest = Function.attempt(function(){ + var table = document.createElement('table'); + table.innerHTML = ''; + }); + + var wrapper = document.createElement('div'); + + var translations = { + table: [1, '', '
'], + select: [1, ''], + tbody: [2, '', '
'], + tr: [3, '', '
'] + }; + translations.thead = translations.tfoot = translations.tbody; + + var html = { + set: function(){ + var html = Array.flatten(arguments).join(''); + var wrap = (!tableTest && translations[this.get('tag')]); + if (wrap){ + var first = wrapper; + first.innerHTML = wrap[1] + html + wrap[2]; + for (var i = wrap[0]; i--;) first = first.firstChild; + this.empty().adopt(first.childNodes); + } else { + this.innerHTML = html; + } + } + }; + + html.erase = html.set; + + return html; +})(); +/**/ + + +/* +--- + +name: Element.Style + +description: Contains methods for interacting with the styles of Elements in a fashionable way. + +license: MIT-style license. + +requires: Element + +provides: Element.Style + +... +*/ + +(function(){ + +var html = document.html; + +Element.Properties.styles = {set: function(styles){ + this.setStyles(styles); +}}; + +var hasOpacity = (html.style.opacity != null); +var reAlpha = /alpha\(opacity=([\d.]+)\)/i; + +var setOpacity = function(element, opacity){ + if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; + if (hasOpacity){ + element.style.opacity = opacity; + } else { + opacity = (opacity * 100).limit(0, 100).round(); + opacity = (opacity == 100) ? '' : 'alpha(opacity=' + opacity + ')'; + var filter = element.style.filter || element.getComputedStyle('filter') || ''; + element.style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity; + } +}; + +Element.Properties.opacity = { + + set: function(opacity){ + var visibility = this.style.visibility; + if (opacity == 0 && visibility != 'hidden') this.style.visibility = 'hidden'; + else if (opacity != 0 && visibility != 'visible') this.style.visibility = 'visible'; + + setOpacity(this, opacity); + }, + + get: (hasOpacity) ? function(){ + var opacity = this.style.opacity || this.getComputedStyle('opacity'); + return (opacity == '') ? 1 : opacity; + } : function(){ + var opacity, filter = (this.style.filter || this.getComputedStyle('filter')); + if (filter) opacity = filter.match(reAlpha); + return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); + } + +}; + +var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat'; + +Element.implement({ + + getComputedStyle: function(property){ + if (this.currentStyle) return this.currentStyle[property.camelCase()]; + var defaultView = Element.getDocument(this).defaultView, + computed = defaultView ? defaultView.getComputedStyle(this, null) : null; + return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : null; + }, + + setOpacity: function(value){ + setOpacity(this, value); + return this; + }, + + getOpacity: function(){ + return this.get('opacity'); + }, + + setStyle: function(property, value){ + switch (property){ + case 'opacity': return this.set('opacity', parseFloat(value)); + case 'float': property = floatName; + } + property = property.camelCase(); + if (typeOf(value) != 'string'){ + var map = (Element.Styles[property] || '@').split(' '); + value = Array.from(value).map(function(val, i){ + if (!map[i]) return ''; + return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; + }).join(' '); + } else if (value == String(Number(value))){ + value = Math.round(value); + } + this.style[property] = value; + return this; + }, + + getStyle: function(property){ + switch (property){ + case 'opacity': return this.get('opacity'); + case 'float': property = floatName; + } + property = property.camelCase(); + var result = this.style[property]; + if (!result || property == 'zIndex'){ + result = []; + for (var style in Element.ShortStyles){ + if (property != style) continue; + for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); + return result.join(' '); + } + result = this.getComputedStyle(property); + } + if (result){ + result = String(result); + var color = result.match(/rgba?\([\d\s,]+\)/); + if (color) result = result.replace(color[0], color[0].rgbToHex()); + } + if (Browser.opera || (Browser.ie && isNaN(parseFloat(result)))){ + if ((/^(height|width)$/).test(property)){ + var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; + values.each(function(value){ + size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); + }, this); + return this['offset' + property.capitalize()] - size + 'px'; + } + if (Browser.opera && String(result).indexOf('px') != -1) return result; + if ((/^border(.+)Width|margin|padding/).test(property)) return '0px'; + } + return result; + }, + + setStyles: function(styles){ + for (var style in styles) this.setStyle(style, styles[style]); + return this; + }, + + getStyles: function(){ + var result = {}; + Array.flatten(arguments).each(function(key){ + result[key] = this.getStyle(key); + }, this); + return result; + } + +}); + +Element.Styles = { + left: '@px', top: '@px', bottom: '@px', right: '@px', + width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', + backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', + fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', + margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', + borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', + zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' +}; + + + +Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; + +['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ + var Short = Element.ShortStyles; + var All = Element.Styles; + ['margin', 'padding'].each(function(style){ + var sd = style + direction; + Short[style][sd] = All[sd] = '@px'; + }); + var bd = 'border' + direction; + Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; + var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; + Short[bd] = {}; + Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; + Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; + Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; +}); + +})(); + + +/* +--- + +name: Element.Event + +description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. + +license: MIT-style license. + +requires: [Element, Event] + +provides: Element.Event + +... +*/ + +(function(){ + +Element.Properties.events = {set: function(events){ + this.addEvents(events); +}}; + +[Element, Window, Document].invoke('implement', { + + addEvent: function(type, fn){ + var events = this.retrieve('events', {}); + if (!events[type]) events[type] = {keys: [], values: []}; + if (events[type].keys.contains(fn)) return this; + events[type].keys.push(fn); + var realType = type, + custom = Element.Events[type], + condition = fn, + self = this; + if (custom){ + if (custom.onAdd) custom.onAdd.call(this, fn); + if (custom.condition){ + condition = function(event){ + if (custom.condition.call(this, event)) return fn.call(this, event); + return true; + }; + } + realType = custom.base || realType; + } + var defn = function(){ + return fn.call(self); + }; + var nativeEvent = Element.NativeEvents[realType]; + if (nativeEvent){ + if (nativeEvent == 2){ + defn = function(event){ + event = new Event(event, self.getWindow()); + if (condition.call(self, event) === false) event.stop(); + }; + } + this.addListener(realType, defn, arguments[2]); + } + events[type].values.push(defn); + return this; + }, + + removeEvent: function(type, fn){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + var list = events[type]; + var index = list.keys.indexOf(fn); + if (index == -1) return this; + var value = list.values[index]; + delete list.keys[index]; + delete list.values[index]; + var custom = Element.Events[type]; + if (custom){ + if (custom.onRemove) custom.onRemove.call(this, fn); + type = custom.base || type; + } + return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this; + }, + + addEvents: function(events){ + for (var event in events) this.addEvent(event, events[event]); + return this; + }, + + removeEvents: function(events){ + var type; + if (typeOf(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + var attached = this.retrieve('events'); + if (!attached) return this; + if (!events){ + for (type in attached) this.removeEvents(type); + this.eliminate('events'); + } else if (attached[events]){ + attached[events].keys.each(function(fn){ + this.removeEvent(events, fn); + }, this); + delete attached[events]; + } + return this; + }, + + fireEvent: function(type, args, delay){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + args = Array.from(args); + + events[type].keys.each(function(fn){ + if (delay) fn.delay(delay, this, args); + else fn.apply(this, args); + }, this); + return this; + }, + + cloneEvents: function(from, type){ + from = document.id(from); + var events = from.retrieve('events'); + if (!events) return this; + if (!type){ + for (var eventType in events) this.cloneEvents(from, eventType); + } else if (events[type]){ + events[type].keys.each(function(fn){ + this.addEvent(type, fn); + }, this); + } + return this; + } + +}); + +Element.NativeEvents = { + click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons + mousewheel: 2, DOMMouseScroll: 2, //mouse wheel + mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement + keydown: 2, keypress: 2, keyup: 2, //keyboard + orientationchange: 2, // mobile + touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch + gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements + load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window + error: 1, abort: 1, scroll: 1 //misc +}; + +var check = function(event){ + var related = event.relatedTarget; + if (related == null) return true; + if (!related) return false; + return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related)); +}; + +Element.Events = { + + mouseenter: { + base: 'mouseover', + condition: check + }, + + mouseleave: { + base: 'mouseout', + condition: check + }, + + mousewheel: { + base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel' + } + +}; + + + +})(); + + +/* +--- + +name: Element.Dimensions + +description: Contains methods to work with size, scroll, or positioning of Elements and the window object. + +license: MIT-style license. + +credits: + - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). + - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). + +requires: [Element, Element.Style] + +provides: [Element.Dimensions] + +... +*/ + +(function(){ + +var element = document.createElement('div'), + child = document.createElement('div'); +element.style.height = '0'; +element.appendChild(child); +var brokenOffsetParent = (child.offsetParent === element); +element = child = null; + +var isOffset = function(el){ + return styleString(el, 'position') != 'static' || isBody(el); +}; + +var isOffsetStatic = function(el){ + return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName); +}; + +Element.implement({ + + scrollTo: function(x, y){ + if (isBody(this)){ + this.getWindow().scrollTo(x, y); + } else { + this.scrollLeft = x; + this.scrollTop = y; + } + return this; + }, + + getSize: function(){ + if (isBody(this)) return this.getWindow().getSize(); + return {x: this.offsetWidth, y: this.offsetHeight}; + }, + + getScrollSize: function(){ + if (isBody(this)) return this.getWindow().getScrollSize(); + return {x: this.scrollWidth, y: this.scrollHeight}; + }, + + getScroll: function(){ + if (isBody(this)) return this.getWindow().getScroll(); + return {x: this.scrollLeft, y: this.scrollTop}; + }, + + getScrolls: function(){ + var element = this.parentNode, position = {x: 0, y: 0}; + while (element && !isBody(element)){ + position.x += element.scrollLeft; + position.y += element.scrollTop; + element = element.parentNode; + } + return position; + }, + + getOffsetParent: brokenOffsetParent ? function(){ + var element = this; + if (isBody(element) || styleString(element, 'position') == 'fixed') return null; + + var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset; + while ((element = element.parentNode)){ + if (isOffsetCheck(element)) return element; + } + return null; + } : function(){ + var element = this; + if (isBody(element) || styleString(element, 'position') == 'fixed') return null; + + try { + return element.offsetParent; + } catch(e) {} + return null; + }, + + getOffsets: function(){ + if (this.getBoundingClientRect && !Browser.Platform.ios){ + var bound = this.getBoundingClientRect(), + html = document.id(this.getDocument().documentElement), + htmlScroll = html.getScroll(), + elemScrolls = this.getScrolls(), + isFixed = (styleString(this, 'position') == 'fixed'); + + return { + x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, + y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop + }; + } + + var element = this, position = {x: 0, y: 0}; + if (isBody(this)) return position; + + while (element && !isBody(element)){ + position.x += element.offsetLeft; + position.y += element.offsetTop; + + if (Browser.firefox){ + if (!borderBox(element)){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + var parent = element.parentNode; + if (parent && styleString(parent, 'overflow') != 'visible'){ + position.x += leftBorder(parent); + position.y += topBorder(parent); + } + } else if (element != this && Browser.safari){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + + element = element.offsetParent; + } + if (Browser.firefox && !borderBox(this)){ + position.x -= leftBorder(this); + position.y -= topBorder(this); + } + return position; + }, + + getPosition: function(relative){ + if (isBody(this)) return {x: 0, y: 0}; + var offset = this.getOffsets(), + scroll = this.getScrolls(); + var position = { + x: offset.x - scroll.x, + y: offset.y - scroll.y + }; + + if (relative && (relative = document.id(relative))){ + var relativePosition = relative.getPosition(); + return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)}; + } + return position; + }, + + getCoordinates: function(element){ + if (isBody(this)) return this.getWindow().getCoordinates(); + var position = this.getPosition(element), + size = this.getSize(); + var obj = { + left: position.x, + top: position.y, + width: size.x, + height: size.y + }; + obj.right = obj.left + obj.width; + obj.bottom = obj.top + obj.height; + return obj; + }, + + computePosition: function(obj){ + return { + left: obj.x - styleNumber(this, 'margin-left'), + top: obj.y - styleNumber(this, 'margin-top') + }; + }, + + setPosition: function(obj){ + return this.setStyles(this.computePosition(obj)); + } + +}); + + +[Document, Window].invoke('implement', { + + getSize: function(){ + var doc = getCompatElement(this); + return {x: doc.clientWidth, y: doc.clientHeight}; + }, + + getScroll: function(){ + var win = this.getWindow(), doc = getCompatElement(this); + return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; + }, + + getScrollSize: function(){ + var doc = getCompatElement(this), + min = this.getSize(), + body = this.getDocument().body; + + return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)}; + }, + + getPosition: function(){ + return {x: 0, y: 0}; + }, + + getCoordinates: function(){ + var size = this.getSize(); + return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; + } + +}); + +// private methods + +var styleString = Element.getComputedStyle; + +function styleNumber(element, style){ + return styleString(element, style).toInt() || 0; +} + +function borderBox(element){ + return styleString(element, '-moz-box-sizing') == 'border-box'; +} + +function topBorder(element){ + return styleNumber(element, 'border-top-width'); +} + +function leftBorder(element){ + return styleNumber(element, 'border-left-width'); +} + +function isBody(element){ + return (/^(?:body|html)$/i).test(element.tagName); +} + +function getCompatElement(element){ + var doc = element.getDocument(); + return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; +} + +})(); + +//aliases +Element.alias({position: 'setPosition'}); //compatability + +[Window, Document, Element].invoke('implement', { + + getHeight: function(){ + return this.getSize().y; + }, + + getWidth: function(){ + return this.getSize().x; + }, + + getScrollTop: function(){ + return this.getScroll().y; + }, + + getScrollLeft: function(){ + return this.getScroll().x; + }, + + getScrollHeight: function(){ + return this.getScrollSize().y; + }, + + getScrollWidth: function(){ + return this.getScrollSize().x; + }, + + getTop: function(){ + return this.getPosition().y; + }, + + getLeft: function(){ + return this.getPosition().x; + } + +}); + + +/* +--- + +name: Fx + +description: Contains the basic animation logic to be extended by all other Fx Classes. + +license: MIT-style license. + +requires: [Chain, Events, Options] + +provides: Fx + +... +*/ + +(function(){ + +var Fx = this.Fx = new Class({ + + Implements: [Chain, Events, Options], + + options: { + /* + onStart: nil, + onCancel: nil, + onComplete: nil, + */ + fps: 60, + unit: false, + duration: 500, + frames: null, + frameSkip: true, + link: 'ignore' + }, + + initialize: function(options){ + this.subject = this.subject || this; + this.setOptions(options); + }, + + getTransition: function(){ + return function(p){ + return -(Math.cos(Math.PI * p) - 1) / 2; + }; + }, + + step: function(now){ + if (this.options.frameSkip){ + var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval; + this.time = now; + this.frame += frames; + } else { + this.frame++; + } + + if (this.frame < this.frames){ + var delta = this.transition(this.frame / this.frames); + this.set(this.compute(this.from, this.to, delta)); + } else { + this.frame = this.frames; + this.set(this.compute(this.from, this.to, 1)); + this.stop(); + } + }, + + set: function(now){ + return now; + }, + + compute: function(from, to, delta){ + return Fx.compute(from, to, delta); + }, + + check: function(){ + if (!this.isRunning()) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.pass(arguments, this)); return false; + } + return false; + }, + + start: function(from, to){ + if (!this.check(from, to)) return this; + this.from = from; + this.to = to; + this.frame = (this.options.frameSkip) ? 0 : -1; + this.time = null; + this.transition = this.getTransition(); + var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration; + this.duration = Fx.Durations[duration] || duration.toInt(); + this.frameInterval = 1000 / fps; + this.frames = frames || Math.round(this.duration / this.frameInterval); + this.fireEvent('start', this.subject); + pushInstance.call(this, fps); + return this; + }, + + stop: function(){ + if (this.isRunning()){ + this.time = null; + pullInstance.call(this, this.options.fps); + if (this.frames == this.frame){ + this.fireEvent('complete', this.subject); + if (!this.callChain()) this.fireEvent('chainComplete', this.subject); + } else { + this.fireEvent('stop', this.subject); + } + } + return this; + }, + + cancel: function(){ + if (this.isRunning()){ + this.time = null; + pullInstance.call(this, this.options.fps); + this.frame = this.frames; + this.fireEvent('cancel', this.subject).clearChain(); + } + return this; + }, + + pause: function(){ + if (this.isRunning()){ + this.time = null; + pullInstance.call(this, this.options.fps); + } + return this; + }, + + resume: function(){ + if ((this.frame < this.frames) && !this.isRunning()) pushInstance.call(this, this.options.fps); + return this; + }, + + isRunning: function(){ + var list = instances[this.options.fps]; + return list && list.contains(this); + } + +}); + +Fx.compute = function(from, to, delta){ + return (to - from) * delta + from; +}; + +Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; + +// global timers + +var instances = {}, timers = {}; + +var loop = function(){ + var now = Date.now(); + for (var i = this.length; i--;){ + var instance = this[i]; + if (instance) instance.step(now); + } +}; + +var pushInstance = function(fps){ + var list = instances[fps] || (instances[fps] = []); + list.push(this); + if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list); +}; + +var pullInstance = function(fps){ + var list = instances[fps]; + if (list){ + list.erase(this); + if (!list.length && timers[fps]){ + delete instances[fps]; + timers[fps] = clearInterval(timers[fps]); + } + } +}; + +})(); + + +/* +--- + +name: Fx.CSS + +description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. + +license: MIT-style license. + +requires: [Fx, Element.Style] + +provides: Fx.CSS + +... +*/ + +Fx.CSS = new Class({ + + Extends: Fx, + + //prepares the base from/to object + + prepare: function(element, property, values){ + values = Array.from(values); + if (values[1] == null){ + values[1] = values[0]; + values[0] = element.getStyle(property); + } + var parsed = values.map(this.parse); + return {from: parsed[0], to: parsed[1]}; + }, + + //parses a value into an array + + parse: function(value){ + value = Function.from(value)(); + value = (typeof value == 'string') ? value.split(' ') : Array.from(value); + return value.map(function(val){ + val = String(val); + var found = false; + Object.each(Fx.CSS.Parsers, function(parser, key){ + if (found) return; + var parsed = parser.parse(val); + if (parsed || parsed === 0) found = {value: parsed, parser: parser}; + }); + found = found || {value: val, parser: Fx.CSS.Parsers.String}; + return found; + }); + }, + + //computes by a from and to prepared objects, using their parsers. + + compute: function(from, to, delta){ + var computed = []; + (Math.min(from.length, to.length)).times(function(i){ + computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); + }); + computed.$family = Function.from('fx:css:value'); + return computed; + }, + + //serves the value as settable + + serve: function(value, unit){ + if (typeOf(value) != 'fx:css:value') value = this.parse(value); + var returned = []; + value.each(function(bit){ + returned = returned.concat(bit.parser.serve(bit.value, unit)); + }); + return returned; + }, + + //renders the change to an element + + render: function(element, property, value, unit){ + element.setStyle(property, this.serve(value, unit)); + }, + + //searches inside the page css to find the values for a selector + + search: function(selector){ + if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; + var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$'); + Array.each(document.styleSheets, function(sheet, j){ + var href = sheet.href; + if (href && href.contains('://') && !href.contains(document.domain)) return; + var rules = sheet.rules || sheet.cssRules; + Array.each(rules, function(rule, i){ + if (!rule.style) return; + var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ + return m.toLowerCase(); + }) : null; + if (!selectorText || !selectorTest.test(selectorText)) return; + Object.each(Element.Styles, function(value, style){ + if (!rule.style[style] || Element.ShortStyles[style]) return; + value = String(rule.style[style]); + to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value; + }); + }); + }); + return Fx.CSS.Cache[selector] = to; + } + +}); + +Fx.CSS.Cache = {}; + +Fx.CSS.Parsers = { + + Color: { + parse: function(value){ + if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); + return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; + }, + compute: function(from, to, delta){ + return from.map(function(value, i){ + return Math.round(Fx.compute(from[i], to[i], delta)); + }); + }, + serve: function(value){ + return value.map(Number); + } + }, + + Number: { + parse: parseFloat, + compute: Fx.compute, + serve: function(value, unit){ + return (unit) ? value + unit : value; + } + }, + + String: { + parse: Function.from(false), + compute: function(zero, one){ + return one; + }, + serve: function(zero){ + return zero; + } + } + +}; + + + + +/* +--- + +name: Fx.Tween + +description: Formerly Fx.Style, effect to transition any CSS property for an element. + +license: MIT-style license. + +requires: Fx.CSS + +provides: [Fx.Tween, Element.fade, Element.highlight] + +... +*/ + +Fx.Tween = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(property, now){ + if (arguments.length == 1){ + now = property; + property = this.property || this.options.property; + } + this.render(this.element, property, now, this.options.unit); + return this; + }, + + start: function(property, from, to){ + if (!this.check(property, from, to)) return this; + var args = Array.flatten(arguments); + this.property = this.options.property || args.shift(); + var parsed = this.prepare(this.element, this.property, args); + return this.parent(parsed.from, parsed.to); + } + +}); + +Element.Properties.tween = { + + set: function(options){ + this.get('tween').cancel().setOptions(options); + return this; + }, + + get: function(){ + var tween = this.retrieve('tween'); + if (!tween){ + tween = new Fx.Tween(this, {link: 'cancel'}); + this.store('tween', tween); + } + return tween; + } + +}; + +Element.implement({ + + tween: function(property, from, to){ + this.get('tween').start(arguments); + return this; + }, + + fade: function(how){ + var fade = this.get('tween'), o = 'opacity', toggle; + how = [how, 'toggle'].pick(); + switch (how){ + case 'in': fade.start(o, 1); break; + case 'out': fade.start(o, 0); break; + case 'show': fade.set(o, 1); break; + case 'hide': fade.set(o, 0); break; + case 'toggle': + var flag = this.retrieve('fade:flag', this.get('opacity') == 1); + fade.start(o, (flag) ? 0 : 1); + this.store('fade:flag', !flag); + toggle = true; + break; + default: fade.start(o, arguments); + } + if (!toggle) this.eliminate('fade:flag'); + return this; + }, + + highlight: function(start, end){ + if (!end){ + end = this.retrieve('highlight:original', this.getStyle('background-color')); + end = (end == 'transparent') ? '#fff' : end; + } + var tween = this.get('tween'); + tween.start('background-color', start || '#ffff88', end).chain(function(){ + this.setStyle('background-color', this.retrieve('highlight:original')); + tween.callChain(); + }.bind(this)); + return this; + } + +}); + + +/* +--- + +name: Fx.Morph + +description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. + +license: MIT-style license. + +requires: Fx.CSS + +provides: Fx.Morph + +... +*/ + +Fx.Morph = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(now){ + if (typeof now == 'string') now = this.search(now); + for (var p in now) this.render(this.element, p, now[p], this.options.unit); + return this; + }, + + compute: function(from, to, delta){ + var now = {}; + for (var p in from) now[p] = this.parent(from[p], to[p], delta); + return now; + }, + + start: function(properties){ + if (!this.check(properties)) return this; + if (typeof properties == 'string') properties = this.search(properties); + var from = {}, to = {}; + for (var p in properties){ + var parsed = this.prepare(this.element, p, properties[p]); + from[p] = parsed.from; + to[p] = parsed.to; + } + return this.parent(from, to); + } + +}); + +Element.Properties.morph = { + + set: function(options){ + this.get('morph').cancel().setOptions(options); + return this; + }, + + get: function(){ + var morph = this.retrieve('morph'); + if (!morph){ + morph = new Fx.Morph(this, {link: 'cancel'}); + this.store('morph', morph); + } + return morph; + } + +}; + +Element.implement({ + + morph: function(props){ + this.get('morph').start(props); + return this; + } + +}); + + +/* +--- + +name: Fx.Transitions + +description: Contains a set of advanced transitions to be used with any of the Fx Classes. + +license: MIT-style license. + +credits: + - Easing Equations by Robert Penner, , modified and optimized to be used with MooTools. + +requires: Fx + +provides: Fx.Transitions + +... +*/ + +Fx.implement({ + + getTransition: function(){ + var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; + if (typeof trans == 'string'){ + var data = trans.split(':'); + trans = Fx.Transitions; + trans = trans[data[0]] || trans[data[0].capitalize()]; + if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; + } + return trans; + } + +}); + +Fx.Transition = function(transition, params){ + params = Array.from(params); + var easeIn = function(pos){ + return transition(pos, params); + }; + return Object.append(easeIn, { + easeIn: easeIn, + easeOut: function(pos){ + return 1 - transition(1 - pos, params); + }, + easeInOut: function(pos){ + return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2; + } + }); +}; + +Fx.Transitions = { + + linear: function(zero){ + return zero; + } + +}; + + + +Fx.Transitions.extend = function(transitions){ + for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); +}; + +Fx.Transitions.extend({ + + Pow: function(p, x){ + return Math.pow(p, x && x[0] || 6); + }, + + Expo: function(p){ + return Math.pow(2, 8 * (p - 1)); + }, + + Circ: function(p){ + return 1 - Math.sin(Math.acos(p)); + }, + + Sine: function(p){ + return 1 - Math.cos(p * Math.PI / 2); + }, + + Back: function(p, x){ + x = x && x[0] || 1.618; + return Math.pow(p, 2) * ((x + 1) * p - x); + }, + + Bounce: function(p){ + var value; + for (var a = 0, b = 1; 1; a += b, b /= 2){ + if (p >= (7 - 4 * a) / 11){ + value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); + break; + } + } + return value; + }, + + Elastic: function(p, x){ + return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3); + } + +}); + +['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ + Fx.Transitions[transition] = new Fx.Transition(function(p){ + return Math.pow(p, i + 2); + }); +}); + + +/* +--- + +name: Request + +description: Powerful all purpose Request Class. Uses XMLHTTPRequest. + +license: MIT-style license. + +requires: [Object, Element, Chain, Events, Options, Browser] + +provides: Request + +... +*/ + +(function(){ + +var empty = function(){}, + progressSupport = ('onprogress' in new Browser.Request); + +var Request = this.Request = new Class({ + + Implements: [Chain, Events, Options], + + options: {/* + onRequest: function(){}, + onLoadstart: function(event, xhr){}, + onProgress: function(event, xhr){}, + onComplete: function(){}, + onCancel: function(){}, + onSuccess: function(responseText, responseXML){}, + onFailure: function(xhr){}, + onException: function(headerName, value){}, + onTimeout: function(){}, + user: '', + password: '',*/ + url: '', + data: '', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }, + async: true, + format: false, + method: 'post', + link: 'ignore', + isSuccess: null, + emulation: true, + urlEncoded: true, + encoding: 'utf-8', + evalScripts: false, + evalResponse: false, + timeout: 0, + noCache: false + }, + + initialize: function(options){ + this.xhr = new Browser.Request(); + this.setOptions(options); + this.headers = this.options.headers; + }, + + onStateChange: function(){ + var xhr = this.xhr; + if (xhr.readyState != 4 || !this.running) return; + this.running = false; + this.status = 0; + Function.attempt(function(){ + var status = xhr.status; + this.status = (status == 1223) ? 204 : status; + }.bind(this)); + xhr.onreadystatechange = empty; + if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; + clearTimeout(this.timer); + + this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML}; + if (this.options.isSuccess.call(this, this.status)) + this.success(this.response.text, this.response.xml); + else + this.failure(); + }, + + isSuccess: function(){ + var status = this.status; + return (status >= 200 && status < 300); + }, + + isRunning: function(){ + return !!this.running; + }, + + processScripts: function(text){ + if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text); + return text.stripScripts(this.options.evalScripts); + }, + + success: function(text, xml){ + this.onSuccess(this.processScripts(text), xml); + }, + + onSuccess: function(){ + this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); + }, + + failure: function(){ + this.onFailure(); + }, + + onFailure: function(){ + this.fireEvent('complete').fireEvent('failure', this.xhr); + }, + + loadstart: function(event){ + this.fireEvent('loadstart', [event, this.xhr]); + }, + + progress: function(event){ + this.fireEvent('progress', [event, this.xhr]); + }, + + timeout: function(){ + this.fireEvent('timeout', this.xhr); + }, + + setHeader: function(name, value){ + this.headers[name] = value; + return this; + }, + + getHeader: function(name){ + return Function.attempt(function(){ + return this.xhr.getResponseHeader(name); + }.bind(this)); + }, + + check: function(){ + if (!this.running) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.pass(arguments, this)); return false; + } + return false; + }, + + send: function(options){ + if (!this.check(options)) return this; + + this.options.isSuccess = this.options.isSuccess || this.isSuccess; + this.running = true; + + var type = typeOf(options); + if (type == 'string' || type == 'element') options = {data: options}; + + var old = this.options; + options = Object.append({data: old.data, url: old.url, method: old.method}, options); + var data = options.data, url = String(options.url), method = options.method.toLowerCase(); + + switch (typeOf(data)){ + case 'element': data = document.id(data).toQueryString(); break; + case 'object': case 'hash': data = Object.toQueryString(data); + } + + if (this.options.format){ + var format = 'format=' + this.options.format; + data = (data) ? format + '&' + data : format; + } + + if (this.options.emulation && !['get', 'post'].contains(method)){ + var _method = '_method=' + method; + data = (data) ? _method + '&' + data : _method; + method = 'post'; + } + + if (this.options.urlEncoded && ['post', 'put'].contains(method)){ + var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; + this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding; + } + + if (!url) url = document.location.pathname; + + var trimPosition = url.lastIndexOf('/'); + if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); + + if (this.options.noCache) + url += (url.contains('?') ? '&' : '?') + String.uniqueID(); + + if (data && method == 'get'){ + url += (url.contains('?') ? '&' : '?') + data; + data = null; + } + + var xhr = this.xhr; + if (progressSupport){ + xhr.onloadstart = this.loadstart.bind(this); + xhr.onprogress = this.progress.bind(this); + } + + xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password); + if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true; + + xhr.onreadystatechange = this.onStateChange.bind(this); + + Object.each(this.headers, function(value, key){ + try { + xhr.setRequestHeader(key, value); + } catch (e){ + this.fireEvent('exception', [key, value]); + } + }, this); + + this.fireEvent('request'); + xhr.send(data); + if (!this.options.async) this.onStateChange(); + if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this); + return this; + }, + + cancel: function(){ + if (!this.running) return this; + this.running = false; + var xhr = this.xhr; + xhr.abort(); + clearTimeout(this.timer); + xhr.onreadystatechange = empty; + if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; + this.xhr = new Browser.Request(); + this.fireEvent('cancel'); + return this; + } + +}); + +var methods = {}; +['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ + methods[method] = function(data){ + var object = { + method: method + }; + if (data != null) object.data = data; + return this.send(object); + }; +}); + +Request.implement(methods); + +Element.Properties.send = { + + set: function(options){ + var send = this.get('send').cancel(); + send.setOptions(options); + return this; + }, + + get: function(){ + var send = this.retrieve('send'); + if (!send){ + send = new Request({ + data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') + }); + this.store('send', send); + } + return send; + } + +}; + +Element.implement({ + + send: function(url){ + var sender = this.get('send'); + sender.send({data: this, url: url || sender.options.url}); + return this; + } + +}); + +})(); + +/* +--- + +name: Request.HTML + +description: Extends the basic Request Class with additional methods for interacting with HTML responses. + +license: MIT-style license. + +requires: [Element, Request] + +provides: Request.HTML + +... +*/ + +Request.HTML = new Class({ + + Extends: Request, + + options: { + update: false, + append: false, + evalScripts: true, + filter: false, + headers: { + Accept: 'text/html, application/xml, text/xml, */*' + } + }, + + success: function(text){ + var options = this.options, response = this.response; + + response.html = text.stripScripts(function(script){ + response.javascript = script; + }); + + var match = response.html.match(/]*>([\s\S]*?)<\/body>/i); + if (match) response.html = match[1]; + var temp = new Element('div').set('html', response.html); + + response.tree = temp.childNodes; + response.elements = temp.getElements('*'); + + if (options.filter) response.tree = response.elements.filter(options.filter); + if (options.update) document.id(options.update).empty().set('html', response.html); + else if (options.append) document.id(options.append).adopt(temp.getChildren()); + if (options.evalScripts) Browser.exec(response.javascript); + + this.onSuccess(response.tree, response.elements, response.html, response.javascript); + } + +}); + +Element.Properties.load = { + + set: function(options){ + var load = this.get('load').cancel(); + load.setOptions(options); + return this; + }, + + get: function(){ + var load = this.retrieve('load'); + if (!load){ + load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'}); + this.store('load', load); + } + return load; + } + +}; + +Element.implement({ + + load: function(){ + this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString})); + return this; + } + +}); + + +/* +--- + +name: JSON + +description: JSON encoder and decoder. + +license: MIT-style license. + +See Also: + +requires: [Array, String, Number, Function] + +provides: JSON + +... +*/ + +if (typeof JSON == 'undefined') this.JSON = {}; + + + +(function(){ + +var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}; + +var escape = function(chr){ + return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4); +}; + +JSON.validate = function(string){ + string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). + replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). + replace(/(?:^|:|,)(?:\s*\[)+/g, ''); + + return (/^[\],:{}\s]*$/).test(string); +}; + +JSON.encode = JSON.stringify ? function(obj){ + return JSON.stringify(obj); +} : function(obj){ + if (obj && obj.toJSON) obj = obj.toJSON(); + + switch (typeOf(obj)){ + case 'string': + return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"'; + case 'array': + return '[' + obj.map(JSON.encode).clean() + ']'; + case 'object': case 'hash': + var string = []; + Object.each(obj, function(value, key){ + var json = JSON.encode(value); + if (json) string.push(JSON.encode(key) + ':' + json); + }); + return '{' + string + '}'; + case 'number': case 'boolean': return '' + obj; + case 'null': return 'null'; + } + + return null; +}; + +JSON.decode = function(string, secure){ + if (!string || typeOf(string) != 'string') return null; + + if (secure || JSON.secure){ + if (JSON.parse) return JSON.parse(string); + if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.'); + } + + return eval('(' + string + ')'); +}; + +})(); + + +/* +--- + +name: Request.JSON + +description: Extends the basic Request Class with additional methods for sending and receiving JSON data. + +license: MIT-style license. + +requires: [Request, JSON] + +provides: Request.JSON + +... +*/ + +Request.JSON = new Class({ + + Extends: Request, + + options: { + /*onError: function(text, error){},*/ + secure: true + }, + + initialize: function(options){ + this.parent(options); + Object.append(this.headers, { + 'Accept': 'application/json', + 'X-Request': 'JSON' + }); + }, + + success: function(text){ + var json; + try { + json = this.response.json = JSON.decode(text, this.options.secure); + } catch (error){ + this.fireEvent('error', [text, error]); + return; + } + if (json == null) this.onFailure(); + else this.onSuccess(json, text); + } + +}); + + +/* +--- + +name: Cookie + +description: Class for creating, reading, and deleting browser Cookies. + +license: MIT-style license. + +credits: + - Based on the functions by Peter-Paul Koch (http://quirksmode.org). + +requires: [Options, Browser] + +provides: Cookie + +... +*/ + +var Cookie = new Class({ + + Implements: Options, + + options: { + path: '/', + domain: false, + duration: false, + secure: false, + document: document, + encode: true + }, + + initialize: function(key, options){ + this.key = key; + this.setOptions(options); + }, + + write: function(value){ + if (this.options.encode) value = encodeURIComponent(value); + if (this.options.domain) value += '; domain=' + this.options.domain; + if (this.options.path) value += '; path=' + this.options.path; + if (this.options.duration){ + var date = new Date(); + date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); + value += '; expires=' + date.toGMTString(); + } + if (this.options.secure) value += '; secure'; + this.options.document.cookie = this.key + '=' + value; + return this; + }, + + read: function(){ + var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); + return (value) ? decodeURIComponent(value[1]) : null; + }, + + dispose: function(){ + new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write(''); + return this; + } + +}); + +Cookie.write = function(key, value, options){ + return new Cookie(key, options).write(value); +}; + +Cookie.read = function(key){ + return new Cookie(key).read(); +}; + +Cookie.dispose = function(key, options){ + return new Cookie(key, options).dispose(); +}; + + +/* +--- + +name: DOMReady + +description: Contains the custom event domready. + +license: MIT-style license. + +requires: [Browser, Element, Element.Event] + +provides: [DOMReady, DomReady] + +... +*/ + +(function(window, document){ + +var ready, + loaded, + checks = [], + shouldPoll, + timer, + testElement = document.createElement('div'); + +var domready = function(){ + clearTimeout(timer); + if (ready) return; + Browser.loaded = ready = true; + document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check); + + document.fireEvent('domready'); + window.fireEvent('domready'); +}; + +var check = function(){ + for (var i = checks.length; i--;) if (checks[i]()){ + domready(); + return true; + } + return false; +}; + +var poll = function(){ + clearTimeout(timer); + if (!check()) timer = setTimeout(poll, 10); +}; + +document.addListener('DOMContentLoaded', domready); + +/**/ +// doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/ +// testElement.doScroll() throws when the DOM is not ready, only in the top window +var doScrollWorks = function(){ + try { + testElement.doScroll(); + return true; + } catch (e){} + return false; +} +// If doScroll works already, it can't be used to determine domready +// e.g. in an iframe +if (testElement.doScroll && !doScrollWorks()){ + checks.push(doScrollWorks); + shouldPoll = true; +} +/**/ + +if (document.readyState) checks.push(function(){ + var state = document.readyState; + return (state == 'loaded' || state == 'complete'); +}); + +if ('onreadystatechange' in document) document.addListener('readystatechange', check); +else shouldPoll = true; + +if (shouldPoll) poll(); + +Element.Events.domready = { + onAdd: function(fn){ + if (ready) fn.call(this); + } +}; + +// Make sure that domready fires before load +Element.Events.load = { + base: 'load', + onAdd: function(fn){ + if (loaded && this == window) fn.call(this); + }, + condition: function(){ + if (this == window){ + domready(); + delete Element.Events.load; + } + return true; + } +}; + +// This is based on the custom load event +window.addEvent('load', function(){ + loaded = true; +}); + +})(window, document); + + +/* +--- + +name: Swiff + +description: Wrapper for embedding SWF movies. Supports External Interface Communication. + +license: MIT-style license. + +credits: + - Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. + +requires: [Options, Object, Element] + +provides: Swiff + +... +*/ + +(function(){ + +var Swiff = this.Swiff = new Class({ + + Implements: Options, + + options: { + id: null, + height: 1, + width: 1, + container: null, + properties: {}, + params: { + quality: 'high', + allowScriptAccess: 'always', + wMode: 'window', + swLiveConnect: true + }, + callBacks: {}, + vars: {} + }, + + toElement: function(){ + return this.object; + }, + + initialize: function(path, options){ + this.instance = 'Swiff_' + String.uniqueID(); + + this.setOptions(options); + options = this.options; + var id = this.id = options.id || this.instance; + var container = document.id(options.container); + + Swiff.CallBacks[this.instance] = {}; + + var params = options.params, vars = options.vars, callBacks = options.callBacks; + var properties = Object.append({height: options.height, width: options.width}, options.properties); + + var self = this; + + for (var callBack in callBacks){ + Swiff.CallBacks[this.instance][callBack] = (function(option){ + return function(){ + return option.apply(self.object, arguments); + }; + })(callBacks[callBack]); + vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; + } + + params.flashVars = Object.toQueryString(vars); + if (Browser.ie){ + properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; + params.movie = path; + } else { + properties.type = 'application/x-shockwave-flash'; + } + properties.data = path; + + var build = ''; + } + build += ''; + this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; + }, + + replaces: function(element){ + element = document.id(element, true); + element.parentNode.replaceChild(this.toElement(), element); + return this; + }, + + inject: function(element){ + document.id(element, true).appendChild(this.toElement()); + return this; + }, + + remote: function(){ + return Swiff.remote.apply(Swiff, [this.toElement()].append(arguments)); + } + +}); + +Swiff.CallBacks = {}; + +Swiff.remote = function(obj, fn){ + var rs = obj.CallFunction('' + __flash__argumentsToXML(arguments, 2) + ''); + return eval(rs); +}; + +})(); + diff --git a/web/tools/mootools/mootools-core-1.3.2-yc.js b/web/tools/mootools/mootools-core-1.3.2-yc.js new file mode 100644 index 000000000..71a263b81 --- /dev/null +++ b/web/tools/mootools/mootools-core-1.3.2-yc.js @@ -0,0 +1,450 @@ +/* +--- +MooTools: the javascript framework + +web build: + - http://mootools.net/core/7c56cfef9dddcf170a5d68e3fb61cfd7 + +packager build: + - packager build Core/Core Core/Array Core/String Core/Number Core/Function Core/Object Core/Event Core/Browser Core/Class Core/Class.Extras Core/Slick.Parser Core/Slick.Finder Core/Element Core/Element.Style Core/Element.Event Core/Element.Dimensions Core/Fx Core/Fx.CSS Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/Request Core/Request.HTML Core/Request.JSON Core/Cookie Core/JSON Core/DOMReady Core/Swiff + +copyrights: + - [MooTools](http://mootools.net) + +licenses: + - [MIT License](http://mootools.net/license.txt) +... +*/ +(function(){this.MooTools={version:"1.3.2",build:"c9f1ff10e9e7facb65e9481049ed1b450959d587"};var o=this.typeOf=function(i){if(i==null){return"null";}if(i.$family){return i.$family(); +}if(i.nodeName){if(i.nodeType==1){return"element";}if(i.nodeType==3){return(/\S/).test(i.nodeValue)?"textnode":"whitespace";}}else{if(typeof i.length=="number"){if(i.callee){return"arguments"; +}if("item" in i){return"collection";}}}return typeof i;};var j=this.instanceOf=function(t,i){if(t==null){return false;}var s=t.$constructor||t.constructor; +while(s){if(s===i){return true;}s=s.parent;}return t instanceof i;};var f=this.Function;var p=true;for(var k in {toString:1}){p=null;}if(p){p=["hasOwnProperty","valueOf","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","constructor"]; +}f.prototype.overloadSetter=function(s){var i=this;return function(u,t){if(u==null){return this;}if(s||typeof u!="string"){for(var v in u){i.call(this,v,u[v]); +}if(p){for(var w=p.length;w--;){v=p[w];if(u.hasOwnProperty(v)){i.call(this,v,u[v]);}}}}else{i.call(this,u,t);}return this;};};f.prototype.overloadGetter=function(s){var i=this; +return function(u){var v,t;if(s||typeof u!="string"){v=u;}else{if(arguments.length>1){v=arguments;}}if(v){t={};for(var w=0;w-1:this.indexOf(a)>-1;},trim:function(){return this.replace(/^\s+|\s+$/g,"");},clean:function(){return this.replace(/\s+/g," ").trim(); +},camelCase:function(){return this.replace(/-\D/g,function(a){return a.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/[A-Z]/g,function(a){return("-"+a.charAt(0).toLowerCase()); +});},capitalize:function(){return this.replace(/\b[a-z]/g,function(a){return a.toUpperCase();});},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1"); +},toInt:function(a){return parseInt(this,a||10);},toFloat:function(){return parseFloat(this);},hexToRgb:function(b){var a=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); +return(a)?a.slice(1).hexToRgb(b):null;},rgbToHex:function(b){var a=this.match(/\d{1,3}/g);return(a)?a.rgbToHex(b):null;},substitute:function(a,b){return this.replace(b||(/\\?\{([^{}]+)\}/g),function(d,c){if(d.charAt(0)=="\\"){return d.slice(1); +}return(a[c]!=null)?a[c]:"";});}});Number.implement({limit:function(b,a){return Math.min(a,Math.max(b,this));},round:function(a){a=Math.pow(10,a||0).toFixed(a<0?-a:0); +return Math.round(this*a)/a;},times:function(b,c){for(var a=0;a1)?Array.slice(arguments,1):null;return function(){if(!b&&!arguments.length){return a.call(c);}if(b&&arguments.length){return a.apply(c,b.concat(Array.from(arguments))); +}return a.apply(c,b||arguments);};},pass:function(b,c){var a=this;if(b!=null){b=Array.from(b);}return function(){return a.apply(c,b||arguments);};},delay:function(b,c,a){return setTimeout(this.pass((a==null?[]:a),c),b); +},periodical:function(c,b,a){return setInterval(this.pass((a==null?[]:a),b),c);}});(function(){var a=Object.prototype.hasOwnProperty;Object.extend({subset:function(d,g){var f={}; +for(var e=0,b=g.length;e]*>([\s\S]*?)<\/script>/gi,function(r,s){e+=s+"\n"; +return"";});if(p===true){o.exec(e);}else{if(typeOf(p)=="function"){p(e,q);}}return q;});o.extend({Document:this.Document,Window:this.Window,Element:this.Element,Event:this.Event}); +this.Window=this.$constructor=new Type("Window",function(){});this.$family=Function.from("window").hide();Window.mirror(function(e,p){i[e]=p;});this.Document=k.$constructor=new Type("Document",function(){}); +k.$family=Function.from("document").hide();Document.mirror(function(e,p){k[e]=p;});k.html=k.documentElement;if(!k.head){k.head=k.getElementsByTagName("head")[0]; +}if(k.execCommand){try{k.execCommand("BackgroundImageCache",false,true);}catch(g){}}if(this.attachEvent&&!this.addEventListener){var d=function(){this.detachEvent("onunload",d); +k.head=k.html=k.window=null;};this.attachEvent("onunload",d);}var m=Array.from;try{m(k.html.childNodes);}catch(g){Array.from=function(p){if(typeof p!="string"&&Type.isEnumerable(p)&&typeOf(p)!="array"){var e=p.length,q=new Array(e); +while(e--){q[e]=p[e];}return q;}return m(p);};var l=Array.prototype,n=l.slice;["pop","push","reverse","shift","sort","splice","unshift","concat","join","slice"].each(function(e){var p=l[e]; +Array[e]=function(q){return p.apply(Array.from(q),n.call(arguments,1));};});}})();var Event=new Type("Event",function(a,i){if(!i){i=window;}var o=i.document; +a=a||i.event;if(a.$extended){return a;}this.$extended=true;var n=a.type,k=a.target||a.srcElement,m={},c={},q=null,h,l,b,p;while(k&&k.nodeType==3){k=k.parentNode; +}if(n.indexOf("key")!=-1){b=a.which||a.keyCode;p=Object.keyOf(Event.Keys,b);if(n=="keydown"){var d=b-111;if(d>0&&d<13){p="f"+d;}}if(!p){p=String.fromCharCode(b).toLowerCase(); +}}else{if((/click|mouse|menu/i).test(n)){o=(!o.compatMode||o.compatMode=="CSS1Compat")?o.html:o.body;m={x:(a.pageX!=null)?a.pageX:a.clientX+o.scrollLeft,y:(a.pageY!=null)?a.pageY:a.clientY+o.scrollTop}; +c={x:(a.pageX!=null)?a.pageX-i.pageXOffset:a.clientX,y:(a.pageY!=null)?a.pageY-i.pageYOffset:a.clientY};if((/DOMMouseScroll|mousewheel/).test(n)){l=(a.wheelDelta)?a.wheelDelta/120:-(a.detail||0)/3; +}h=(a.which==3)||(a.button==2);if((/over|out/).test(n)){q=a.relatedTarget||a[(n=="mouseover"?"from":"to")+"Element"];var j=function(){while(q&&q.nodeType==3){q=q.parentNode; +}return true;};var g=(Browser.firefox2)?j.attempt():j();q=(g)?q:null;}}else{if((/gesture|touch/i).test(n)){this.rotation=a.rotation;this.scale=a.scale; +this.targetTouches=a.targetTouches;this.changedTouches=a.changedTouches;var f=this.touches=a.touches;if(f&&f[0]){var e=f[0];m={x:e.pageX,y:e.pageY};c={x:e.clientX,y:e.clientY}; +}}}}return Object.append(this,{event:a,type:n,page:m,client:c,rightClick:h,wheel:l,relatedTarget:document.id(q),target:document.id(k),code:b,key:p,shift:a.shiftKey,control:a.ctrlKey,alt:a.altKey,meta:a.metaKey}); +});Event.Keys={enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46};Event.implement({stop:function(){return this.stopPropagation().preventDefault(); +},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation();}else{this.event.cancelBubble=true;}return this;},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault(); +}else{this.event.returnValue=false;}return this;}});(function(){var a=this.Class=new Type("Class",function(h){if(instanceOf(h,Function)){h={initialize:h}; +}var g=function(){e(this);if(g.$prototyping){return this;}this.$caller=null;var i=(this.initialize)?this.initialize.apply(this,arguments):this;this.$caller=this.caller=null; +return i;}.extend(this).implement(h);g.$constructor=a;g.prototype.$constructor=g;g.prototype.parent=c;return g;});var c=function(){if(!this.$caller){throw new Error('The method "parent" cannot be called.'); +}var g=this.$caller.$name,h=this.$caller.$owner.parent,i=(h)?h.prototype[g]:null;if(!i){throw new Error('The method "'+g+'" has no parent.');}return i.apply(this,arguments); +};var e=function(g){for(var h in g){var j=g[h];switch(typeOf(j)){case"object":var i=function(){};i.prototype=j;g[h]=e(new i);break;case"array":g[h]=j.clone(); +break;}}return g;};var b=function(g,h,j){if(j.$origin){j=j.$origin;}var i=function(){if(j.$protected&&this.$caller==null){throw new Error('The method "'+h+'" cannot be called.'); +}var l=this.caller,m=this.$caller;this.caller=m;this.$caller=i;var k=j.apply(this,arguments);this.$caller=m;this.caller=l;return k;}.extend({$owner:g,$origin:j,$name:h}); +return i;};var f=function(h,i,g){if(a.Mutators.hasOwnProperty(h)){i=a.Mutators[h].call(this,i);if(i==null){return this;}}if(typeOf(i)=="function"){if(i.$hidden){return this; +}this.prototype[h]=(g)?i:b(this,h,i);}else{Object.merge(this.prototype,h,i);}return this;};var d=function(g){g.$prototyping=true;var h=new g;delete g.$prototyping; +return h;};a.implement("implement",f.overloadSetter());a.Mutators={Extends:function(g){this.parent=g;this.prototype=d(g);},Implements:function(g){Array.from(g).each(function(j){var h=new j; +for(var i in h){f.call(this,i,h[i],true);}},this);}};})();(function(){this.Chain=new Class({$chain:[],chain:function(){this.$chain.append(Array.flatten(arguments)); +return this;},callChain:function(){return(this.$chain.length)?this.$chain.shift().apply(this,arguments):false;},clearChain:function(){this.$chain.empty(); +return this;}});var a=function(b){return b.replace(/^on([A-Z])/,function(c,d){return d.toLowerCase();});};this.Events=new Class({$events:{},addEvent:function(d,c,b){d=a(d); +this.$events[d]=(this.$events[d]||[]).include(c);if(b){c.internal=true;}return this;},addEvents:function(b){for(var c in b){this.addEvent(c,b[c]);}return this; +},fireEvent:function(e,c,b){e=a(e);var d=this.$events[e];if(!d){return this;}c=Array.from(c);d.each(function(f){if(b){f.delay(b,this,c);}else{f.apply(this,c); +}},this);return this;},removeEvent:function(e,d){e=a(e);var c=this.$events[e];if(c&&!d.internal){var b=c.indexOf(d);if(b!=-1){delete c[b];}}return this; +},removeEvents:function(d){var e;if(typeOf(d)=="object"){for(e in d){this.removeEvent(e,d[e]);}return this;}if(d){d=a(d);}for(e in this.$events){if(d&&d!=e){continue; +}var c=this.$events[e];for(var b=c.length;b--;){if(b in c){this.removeEvent(e,c[b]);}}}return this;}});this.Options=new Class({setOptions:function(){var b=this.options=Object.merge.apply(null,[{},this.options].append(arguments)); +if(this.addEvent){for(var c in b){if(typeOf(b[c])!="function"||!(/^on[A-Z]/).test(c)){continue;}this.addEvent(c,b[c]);delete b[c];}}return this;}});})(); +(function(){var k,n,l,g,a={},c={},m=/\\/g;var e=function(q,p){if(q==null){return null;}if(q.Slick===true){return q;}q=(""+q).replace(/^\s+|\s+$/g,"");g=!!p; +var o=(g)?c:a;if(o[q]){return o[q];}k={Slick:true,expressions:[],raw:q,reverse:function(){return e(this.raw,true);}};n=-1;while(q!=(q=q.replace(j,b))){}k.length=k.expressions.length; +return o[k.raw]=(g)?h(k):k;};var i=function(o){if(o==="!"){return" ";}else{if(o===" "){return"!";}else{if((/^!/).test(o)){return o.replace(/^!/,"");}else{return"!"+o; +}}}};var h=function(u){var r=u.expressions;for(var p=0;p+)\\s*|(\\s+)|(+|\\*)|\\#(+)|\\.(+)|\\[\\s*(+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)".replace(//,"["+f(">+~`!@$%^&={}\\;/g,"(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])").replace(//g,"(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])")); +function b(x,s,D,z,r,C,q,B,A,y,u,F,G,v,p,w){if(s||n===-1){k.expressions[++n]=[];l=-1;if(s){return"";}}if(D||z||l===-1){D=D||" ";var t=k.expressions[n]; +if(g&&t[l]){t[l].reverseCombinator=i(D);}t[++l]={combinator:D,tag:"*"};}var o=k.expressions[n][l];if(r){o.tag=r.replace(m,"");}else{if(C){o.id=C.replace(m,""); +}else{if(q){q=q.replace(m,"");if(!o.classList){o.classList=[];}if(!o.classes){o.classes=[];}o.classList.push(q);o.classes.push({value:q,regexp:new RegExp("(^|\\s)"+f(q)+"(\\s|$)")}); +}else{if(G){w=w||p;w=w?w.replace(m,""):null;if(!o.pseudos){o.pseudos=[];}o.pseudos.push({key:G.replace(m,""),value:w,type:F.length==1?"class":"element"}); +}else{if(B){B=B.replace(m,"");u=(u||"").replace(m,"");var E,H;switch(A){case"^=":H=new RegExp("^"+f(u));break;case"$=":H=new RegExp(f(u)+"$");break;case"~=":H=new RegExp("(^|\\s)"+f(u)+"(\\s|$)"); +break;case"|=":H=new RegExp("^"+f(u)+"(-|$)");break;case"=":E=function(I){return u==I;};break;case"*=":E=function(I){return I&&I.indexOf(u)>-1;};break; +case"!=":E=function(I){return u!=I;};break;default:E=function(I){return !!I;};}if(u==""&&(/^[*$^]=$/).test(A)){E=function(){return false;};}if(!E){E=function(I){return I&&H.test(I); +};}if(!o.attributes){o.attributes=[];}o.attributes.push({key:B,operator:A,value:u,test:E});}}}}}return"";}var d=(this.Slick||{});d.parse=function(o){return e(o); +};d.escapeRegExp=f;if(!this.Slick){this.Slick=d;}}).apply((typeof exports!="undefined")?exports:this);(function(){var j={},l={},b=Object.prototype.toString; +j.isNativeCode=function(c){return(/\{\s*\[native code\]\s*\}/).test(""+c);};j.isXML=function(c){return(!!c.xmlVersion)||(!!c.xml)||(b.call(c)=="[object XMLDocument]")||(c.nodeType==9&&c.documentElement.nodeName!="HTML"); +};j.setDocument=function(w){var t=w.nodeType;if(t==9){}else{if(t){w=w.ownerDocument;}else{if(w.navigator){w=w.document;}else{return;}}}if(this.document===w){return; +}this.document=w;var y=w.documentElement,u=this.getUIDXML(y),o=l[u],A;if(o){for(A in o){this[A]=o[A];}return;}o=l[u]={};o.root=y;o.isXMLDocument=this.isXML(w); +o.brokenStarGEBTN=o.starSelectsClosedQSA=o.idGetsName=o.brokenMixedCaseQSA=o.brokenGEBCN=o.brokenCheckedQSA=o.brokenEmptyAttributeQSA=o.isHTMLDocument=o.nativeMatchesSelector=false; +var m,n,x,q,r;var s,c="slick_uniqueid";var z=w.createElement("div");var p=w.body||w.getElementsByTagName("body")[0]||y;p.appendChild(z);try{z.innerHTML=''; +o.isHTMLDocument=!!w.getElementById(c);}catch(v){}if(o.isHTMLDocument){z.style.display="none";z.appendChild(w.createComment(""));n=(z.getElementsByTagName("*").length>1); +try{z.innerHTML="foo";s=z.getElementsByTagName("*");m=(s&&!!s.length&&s[0].nodeName.charAt(0)=="/");}catch(v){}o.brokenStarGEBTN=n||m;try{z.innerHTML=''; +o.idGetsName=w.getElementById(c)===z.firstChild;}catch(v){}if(z.getElementsByClassName){try{z.innerHTML='';z.getElementsByClassName("b").length; +z.firstChild.className="b";q=(z.getElementsByClassName("b").length!=2);}catch(v){}try{z.innerHTML='';x=(z.getElementsByClassName("a").length!=2); +}catch(v){}o.brokenGEBCN=q||x;}if(z.querySelectorAll){try{z.innerHTML="foo";s=z.querySelectorAll("*");o.starSelectsClosedQSA=(s&&!!s.length&&s[0].nodeName.charAt(0)=="/"); +}catch(v){}try{z.innerHTML='';o.brokenMixedCaseQSA=!z.querySelectorAll(".MiX").length;}catch(v){}try{z.innerHTML=''; +o.brokenCheckedQSA=(z.querySelectorAll(":checked").length==0);}catch(v){}try{z.innerHTML='';o.brokenEmptyAttributeQSA=(z.querySelectorAll('[class*=""]').length!=0); +}catch(v){}}try{z.innerHTML='
';r=(z.firstChild.getAttribute("action")!="s");}catch(v){}o.nativeMatchesSelector=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector; +if(o.nativeMatchesSelector){try{o.nativeMatchesSelector.call(y,":slick");o.nativeMatchesSelector=null;}catch(v){}}}try{y.slick_expando=1;delete y.slick_expando; +o.getUID=this.getUIDHTML;}catch(v){o.getUID=this.getUIDXML;}p.removeChild(z);z=s=p=null;o.getAttribute=(o.isHTMLDocument&&r)?function(D,B){var E=this.attributeGetters[B]; +if(E){return E.call(D);}var C=D.getAttributeNode(B);return(C)?C.nodeValue:null;}:function(C,B){var D=this.attributeGetters[B];return(D)?D.call(C):C.getAttribute(B); +};o.hasAttribute=(y&&this.isNativeCode(y.hasAttribute))?function(C,B){return C.hasAttribute(B);}:function(C,B){C=C.getAttributeNode(B);return !!(C&&(C.specified||C.nodeValue)); +};o.contains=(y&&this.isNativeCode(y.contains))?function(B,C){return B.contains(C);}:(y&&y.compareDocumentPosition)?function(B,C){return B===C||!!(B.compareDocumentPosition(C)&16); +}:function(B,C){if(C){do{if(C===B){return true;}}while((C=C.parentNode));}return false;};o.documentSorter=(y.compareDocumentPosition)?function(C,B){if(!C.compareDocumentPosition||!B.compareDocumentPosition){return 0; +}return C.compareDocumentPosition(B)&4?-1:C===B?0:1;}:("sourceIndex" in y)?function(C,B){if(!C.sourceIndex||!B.sourceIndex){return 0;}return C.sourceIndex-B.sourceIndex; +}:(w.createRange)?function(E,C){if(!E.ownerDocument||!C.ownerDocument){return 0;}var D=E.ownerDocument.createRange(),B=C.ownerDocument.createRange();D.setStart(E,0); +D.setEnd(E,0);B.setStart(C,0);B.setEnd(C,0);return D.compareBoundaryPoints(Range.START_TO_END,B);}:null;y=null;for(A in o){this[A]=o[A];}};var e=/^([#.]?)((?:[\w-]+|\*))$/,g=/\[.+[*$^]=(?:""|'')?\]/,f={}; +j.search=function(U,z,H,s){var p=this.found=(s)?null:(H||[]);if(!U){return p;}else{if(U.navigator){U=U.document;}else{if(!U.nodeType){return p;}}}var F,O,V=this.uniques={},I=!!(H&&H.length),y=(U.nodeType==9); +if(this.document!==(y?U:U.ownerDocument)){this.setDocument(U);}if(I){for(O=p.length;O--;){V[this.getUID(p[O])]=true;}}if(typeof z=="string"){var r=z.match(e); +simpleSelectors:if(r){var u=r[1],v=r[2],A,E;if(!u){if(v=="*"&&this.brokenStarGEBTN){break simpleSelectors;}E=U.getElementsByTagName(v);if(s){return E[0]||null; +}for(O=0;A=E[O++];){if(!(I&&V[this.getUID(A)])){p.push(A);}}}else{if(u=="#"){if(!this.isHTMLDocument||!y){break simpleSelectors;}A=U.getElementById(v); +if(!A){return p;}if(this.idGetsName&&A.getAttributeNode("id").nodeValue!=v){break simpleSelectors;}if(s){return A||null;}if(!(I&&V[this.getUID(A)])){p.push(A); +}}else{if(u=="."){if(!this.isHTMLDocument||((!U.getElementsByClassName||this.brokenGEBCN)&&U.querySelectorAll)){break simpleSelectors;}if(U.getElementsByClassName&&!this.brokenGEBCN){E=U.getElementsByClassName(v); +if(s){return E[0]||null;}for(O=0;A=E[O++];){if(!(I&&V[this.getUID(A)])){p.push(A);}}}else{var T=new RegExp("(^|\\s)"+d.escapeRegExp(v)+"(\\s|$)");E=U.getElementsByTagName("*"); +for(O=0;A=E[O++];){className=A.className;if(!(className&&T.test(className))){continue;}if(s){return A;}if(!(I&&V[this.getUID(A)])){p.push(A);}}}}}}if(I){this.sort(p); +}return(s)?null:p;}querySelector:if(U.querySelectorAll){if(!this.isHTMLDocument||f[z]||this.brokenMixedCaseQSA||(this.brokenCheckedQSA&&z.indexOf(":checked")>-1)||(this.brokenEmptyAttributeQSA&&g.test(z))||(!y&&z.indexOf(",")>-1)||d.disableQSA){break querySelector; +}var S=z,x=U;if(!y){var C=x.getAttribute("id"),t="slickid__";x.setAttribute("id",t);S="#"+t+" "+S;U=x.parentNode;}try{if(s){return U.querySelector(S)||null; +}else{E=U.querySelectorAll(S);}}catch(Q){f[z]=1;break querySelector;}finally{if(!y){if(C){x.setAttribute("id",C);}else{x.removeAttribute("id");}U=x;}}if(this.starSelectsClosedQSA){for(O=0; +A=E[O++];){if(A.nodeName>"@"&&!(I&&V[this.getUID(A)])){p.push(A);}}}else{for(O=0;A=E[O++];){if(!(I&&V[this.getUID(A)])){p.push(A);}}}if(I){this.sort(p); +}return p;}F=this.Slick.parse(z);if(!F.length){return p;}}else{if(z==null){return p;}else{if(z.Slick){F=z;}else{if(this.contains(U.documentElement||U,z)){(p)?p.push(z):p=z; +return p;}else{return p;}}}}this.posNTH={};this.posNTHLast={};this.posNTHType={};this.posNTHTypeLast={};this.push=(!I&&(s||(F.length==1&&F.expressions[0].length==1)))?this.pushArray:this.pushUID; +if(p==null){p=[];}var M,L,K;var B,J,D,c,q,G,W;var N,P,o,w,R=F.expressions;search:for(O=0;(P=R[O]);O++){for(M=0;(o=P[M]);M++){B="combinator:"+o.combinator; +if(!this[B]){continue search;}J=(this.isXMLDocument)?o.tag:o.tag.toUpperCase();D=o.id;c=o.classList;q=o.classes;G=o.attributes;W=o.pseudos;w=(M===(P.length-1)); +this.bitUniques={};if(w){this.uniques=V;this.found=p;}else{this.uniques={};this.found=[];}if(M===0){this[B](U,J,D,q,G,W,c);if(s&&w&&p.length){break search; +}}else{if(s&&w){for(L=0,K=N.length;L1)){this.sort(p);}return(s)?(p[0]||null):p;};j.uidx=1;j.uidk="slick-uniqueid";j.getUIDXML=function(m){var c=m.getAttribute(this.uidk); +if(!c){c=this.uidx++;m.setAttribute(this.uidk,c);}return c;};j.getUIDHTML=function(c){return c.uniqueNumber||(c.uniqueNumber=this.uidx++);};j.sort=function(c){if(!this.documentSorter){return c; +}c.sort(this.documentSorter);return c;};j.cacheNTH={};j.matchNTH=/^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;j.parseNTHArgument=function(p){var n=p.match(this.matchNTH); +if(!n){return false;}var o=n[2]||false;var m=n[1]||1;if(m=="-"){m=-1;}var c=+n[3]||0;n=(o=="n")?{a:m,b:c}:(o=="odd")?{a:2,b:1}:(o=="even")?{a:2,b:0}:{a:0,b:m}; +return(this.cacheNTH[p]=n);};j.createNTHPseudo=function(o,m,c,n){return function(r,p){var t=this.getUID(r);if(!this[c][t]){var z=r.parentNode;if(!z){return false; +}var q=z[o],s=1;if(n){var y=r.nodeName;do{if(q.nodeName!=y){continue;}this[c][this.getUID(q)]=s++;}while((q=q[m]));}else{do{if(q.nodeType!=1){continue; +}this[c][this.getUID(q)]=s++;}while((q=q[m]));}}p=p||"n";var u=this.cacheNTH[p]||this.parseNTHArgument(p);if(!u){return false;}var x=u.a,w=u.b,v=this[c][t]; +if(x==0){return w==v;}if(x>0){if(v":function(o,c,q,n,m,p){if((o=o.firstChild)){do{if(o.nodeType==1){this.push(o,c,q,n,m,p); +}}while((o=o.nextSibling));}},"+":function(o,c,q,n,m,p){while((o=o.nextSibling)){if(o.nodeType==1){this.push(o,c,q,n,m,p);break;}}},"^":function(o,c,q,n,m,p){o=o.firstChild; +if(o){if(o.nodeType==1){this.push(o,c,q,n,m,p);}else{this["combinator:+"](o,c,q,n,m,p);}}},"~":function(p,c,r,o,m,q){while((p=p.nextSibling)){if(p.nodeType!=1){continue; +}var n=this.getUID(p);if(this.bitUniques[n]){break;}this.bitUniques[n]=true;this.push(p,c,r,o,m,q);}},"++":function(o,c,q,n,m,p){this["combinator:+"](o,c,q,n,m,p); +this["combinator:!+"](o,c,q,n,m,p);},"~~":function(o,c,q,n,m,p){this["combinator:~"](o,c,q,n,m,p);this["combinator:!~"](o,c,q,n,m,p);},"!":function(o,c,q,n,m,p){while((o=o.parentNode)){if(o!==this.document){this.push(o,c,q,n,m,p); +}}},"!>":function(o,c,q,n,m,p){o=o.parentNode;if(o!==this.document){this.push(o,c,q,n,m,p);}},"!+":function(o,c,q,n,m,p){while((o=o.previousSibling)){if(o.nodeType==1){this.push(o,c,q,n,m,p); +break;}}},"!^":function(o,c,q,n,m,p){o=o.lastChild;if(o){if(o.nodeType==1){this.push(o,c,q,n,m,p);}else{this["combinator:!+"](o,c,q,n,m,p);}}},"!~":function(p,c,r,o,m,q){while((p=p.previousSibling)){if(p.nodeType!=1){continue; +}var n=this.getUID(p);if(this.bitUniques[n]){break;}this.bitUniques[n]=true;this.push(p,c,r,o,m,q);}}};for(var h in i){j["combinator:"+h]=i[h];}var k={empty:function(c){var m=c.firstChild; +return !(m&&m.nodeType==1)&&!(c.innerText||c.textContent||"").length;},not:function(c,m){return !this.matchNode(c,m);},contains:function(c,m){return(c.innerText||c.textContent||"").indexOf(m)>-1; +},"first-child":function(c){while((c=c.previousSibling)){if(c.nodeType==1){return false;}}return true;},"last-child":function(c){while((c=c.nextSibling)){if(c.nodeType==1){return false; +}}return true;},"only-child":function(n){var m=n;while((m=m.previousSibling)){if(m.nodeType==1){return false;}}var c=n;while((c=c.nextSibling)){if(c.nodeType==1){return false; +}}return true;},"nth-child":j.createNTHPseudo("firstChild","nextSibling","posNTH"),"nth-last-child":j.createNTHPseudo("lastChild","previousSibling","posNTHLast"),"nth-of-type":j.createNTHPseudo("firstChild","nextSibling","posNTHType",true),"nth-last-of-type":j.createNTHPseudo("lastChild","previousSibling","posNTHTypeLast",true),index:function(m,c){return this["pseudo:nth-child"](m,""+c+1); +},even:function(c){return this["pseudo:nth-child"](c,"2n");},odd:function(c){return this["pseudo:nth-child"](c,"2n+1");},"first-of-type":function(c){var m=c.nodeName; +while((c=c.previousSibling)){if(c.nodeName==m){return false;}}return true;},"last-of-type":function(c){var m=c.nodeName;while((c=c.nextSibling)){if(c.nodeName==m){return false; +}}return true;},"only-of-type":function(n){var m=n,o=n.nodeName;while((m=m.previousSibling)){if(m.nodeName==o){return false;}}var c=n;while((c=c.nextSibling)){if(c.nodeName==o){return false; +}}return true;},enabled:function(c){return !c.disabled;},disabled:function(c){return c.disabled;},checked:function(c){return c.checked||c.selected;},focus:function(c){return this.isHTMLDocument&&this.document.activeElement===c&&(c.href||c.type||this.hasAttribute(c,"tabindex")); +},root:function(c){return(c===this.root);},selected:function(c){return c.selected;}};for(var a in k){j["pseudo:"+a]=k[a];}j.attributeGetters={"class":function(){return this.getAttribute("class")||this.className; +},"for":function(){return("htmlFor" in this)?this.htmlFor:this.getAttribute("for");},href:function(){return("href" in this)?this.getAttribute("href",2):this.getAttribute("href"); +},style:function(){return(this.style)?this.style.cssText:this.getAttribute("style");},tabindex:function(){var c=this.getAttributeNode("tabindex");return(c&&c.specified)?c.nodeValue:null; +},type:function(){return this.getAttribute("type");}};var d=j.Slick=(this.Slick||{});d.version="1.1.5";d.search=function(m,n,c){return j.search(m,n,c); +};d.find=function(c,m){return j.search(c,m,null,true);};d.contains=function(c,m){j.setDocument(c);return j.contains(c,m);};d.getAttribute=function(m,c){return j.getAttribute(m,c); +};d.match=function(m,c){if(!(m&&c)){return false;}if(!c||c===m){return true;}j.setDocument(m);return j.matchNode(m,c);};d.defineAttributeGetter=function(c,m){j.attributeGetters[c]=m; +return this;};d.lookupAttributeGetter=function(c){return j.attributeGetters[c];};d.definePseudo=function(c,m){j["pseudo:"+c]=function(o,n){return m.call(o,n); +};return this;};d.lookupPseudo=function(c){var m=j["pseudo:"+c];if(m){return function(n){return m.call(this,n);};}return null;};d.override=function(m,c){j.override(m,c); +return this;};d.isXML=j.isXML;d.uidOf=function(c){return j.getUIDHTML(c);};if(!this.Slick){this.Slick=d;}}).apply((typeof exports!="undefined")?exports:this); +var Element=function(b,g){var h=Element.Constructors[b];if(h){return h(g);}if(typeof b!="string"){return document.id(b).set(g);}if(!g){g={};}if(!(/^[\w-]+$/).test(b)){var e=Slick.parse(b).expressions[0][0]; +b=(e.tag=="*")?"div":e.tag;if(e.id&&g.id==null){g.id=e.id;}var d=e.attributes;if(d){for(var f=0,c=d.length;f=this.length){delete this[e--];}return this; +}.protect());}Elements.implement(Array.prototype);Array.mirror(Elements);var f;try{var a=document.createElement("");f=(a.name=="x");}catch(c){}var d=function(e){return(""+e).replace(/&/g,"&").replace(/"/g,"""); +};Document.implement({newElement:function(e,h){if(h&&h.checked!=null){h.defaultChecked=h.checked;}if(f&&h){e="<"+e;if(h.name){e+=' name="'+d(h.name)+'"'; +}if(h.type){e+=' type="'+d(h.type)+'"';}e+=">";delete h.name;delete h.type;}return this.id(this.createElement(e)).set(h);}});})();Document.implement({newTextNode:function(a){return this.createTextNode(a); +},getDocument:function(){return this;},getWindow:function(){return this.window;},id:(function(){var a={string:function(d,c,b){d=Slick.find(b,"#"+d.replace(/(\W)/g,"\\$1")); +return(d)?a.element(d,c):null;},element:function(b,c){$uid(b);if(!c&&!b.$family&&!(/^(?:object|embed)$/i).test(b.tagName)){Object.append(b,Element.Prototype); +}return b;},object:function(c,d,b){if(c.toElement){return a.element(c.toElement(b),d);}return null;}};a.textnode=a.whitespace=a.window=a.document=function(b){return b; +};return function(c,e,d){if(c&&c.$family&&c.uid){return c;}var b=typeOf(c);return(a[b])?a[b](c,e,d||document):null;};})()});if(window.$==null){Window.implement("$",function(a,b){return document.id(a,b,this.document); +});}Window.implement({getDocument:function(){return this.document;},getWindow:function(){return this;}});[Document,Element].invoke("implement",{getElements:function(a){return Slick.search(this,a,new Elements); +},getElement:function(a){return document.id(Slick.find(this,a));}});if(window.$$==null){Window.implement("$$",function(a){if(arguments.length==1){if(typeof a=="string"){return Slick.search(this.document,a,new Elements); +}else{if(Type.isEnumerable(a)){return new Elements(a);}}}return new Elements(arguments);});}(function(){var k={},i={};var n={input:"checked",option:"selected",textarea:"value"}; +var e=function(p){return(i[p]||(i[p]={}));};var j=function(q){var p=q.uid;if(q.removeEvents){q.removeEvents();}if(q.clearAttributes){q.clearAttributes(); +}if(p!=null){delete k[p];delete i[p];}return q;};var o=["defaultValue","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","maxLength","readOnly","rowSpan","tabIndex","useMap"]; +var d=["compact","nowrap","ismap","declare","noshade","checked","disabled","readOnly","multiple","selected","noresize","defer","defaultChecked"];var g={html:"innerHTML","class":"className","for":"htmlFor",text:(function(){var p=document.createElement("div"); +return(p.textContent==null)?"innerText":"textContent";})()};var m=["type"];var h=["value","defaultValue"];var l=/^(?:href|src|usemap)$/i;d=d.associate(d); +o=o.associate(o.map(String.toLowerCase));m=m.associate(m);Object.append(g,h.associate(h));var c={before:function(q,p){var r=p.parentNode;if(r){r.insertBefore(q,p); +}},after:function(q,p){var r=p.parentNode;if(r){r.insertBefore(q,p.nextSibling);}},bottom:function(q,p){p.appendChild(q);},top:function(q,p){p.insertBefore(q,p.firstChild); +}};c.inside=c.bottom;var b=function(s,r){if(!s){return r;}s=Object.clone(Slick.parse(s));var q=s.expressions;for(var p=q.length;p--;){q[p][0].combinator=r; +}return s;};Element.implement({set:function(r,q){var p=Element.Properties[r];(p&&p.set)?p.set.call(this,q):this.setProperty(r,q);}.overloadSetter(),get:function(q){var p=Element.Properties[q]; +return(p&&p.get)?p.get.apply(this):this.getProperty(q);}.overloadGetter(),erase:function(q){var p=Element.Properties[q];(p&&p.erase)?p.erase.apply(this):this.removeProperty(q); +return this;},setProperty:function(q,r){q=o[q]||q;if(r==null){return this.removeProperty(q);}var p=g[q];(p)?this[p]=r:(d[q])?this[q]=!!r:this.setAttribute(q,""+r); +return this;},setProperties:function(p){for(var q in p){this.setProperty(q,p[q]);}return this;},getProperty:function(q){q=o[q]||q;var p=g[q]||m[q];return(p)?this[p]:(d[q])?!!this[q]:(l.test(q)?this.getAttribute(q,2):(p=this.getAttributeNode(q))?p.nodeValue:null)||null; +},getProperties:function(){var p=Array.from(arguments);return p.map(this.getProperty,this).associate(p);},removeProperty:function(q){q=o[q]||q;var p=g[q]; +(p)?this[p]="":(d[q])?this[q]=false:this.removeAttribute(q);return this;},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this; +},hasClass:function(p){return this.className.clean().contains(p," ");},addClass:function(p){if(!this.hasClass(p)){this.className=(this.className+" "+p).clean(); +}return this;},removeClass:function(p){this.className=this.className.replace(new RegExp("(^|\\s)"+p+"(?:\\s|$)"),"$1");return this;},toggleClass:function(p,q){if(q==null){q=!this.hasClass(p); +}return(q)?this.addClass(p):this.removeClass(p);},adopt:function(){var s=this,p,u=Array.flatten(arguments),t=u.length;if(t>1){s=p=document.createDocumentFragment(); +}for(var r=0;r"))[0]);},getLast:function(p){return document.id(Slick.search(this,b(p,">")).getLast()); +},getParent:function(p){return document.id(Slick.find(this,b(p,"!")));},getParents:function(p){return Slick.search(this,b(p,"!"),new Elements);},getSiblings:function(p){return Slick.search(this,b(p,"~~"),new Elements); +},getChildren:function(p){return Slick.search(this,b(p,">"),new Elements);},getWindow:function(){return this.ownerDocument.window;},getDocument:function(){return this.ownerDocument; +},getElementById:function(p){return document.id(Slick.find(this,"#"+(""+p).replace(/(\W)/g,"\\$1")));},getSelected:function(){this.selectedIndex;return new Elements(Array.from(this.options).filter(function(p){return p.selected; +}));},toQueryString:function(){var p=[];this.getElements("input, select, textarea").each(function(r){var q=r.type;if(!r.name||r.disabled||q=="submit"||q=="reset"||q=="file"||q=="image"){return; +}var s=(r.get("tag")=="select")?r.getSelected().map(function(t){return document.id(t).get("value");}):((q=="radio"||q=="checkbox")&&!r.checked)?null:r.get("value"); +Array.from(s).each(function(t){if(typeof t!="undefined"){p.push(encodeURIComponent(r.name)+"="+encodeURIComponent(t));}});});return p.join("&");},destroy:function(){var p=j(this).getElementsByTagName("*"); +Array.each(p,j);Element.dispose(this);return null;},empty:function(){Array.from(this.childNodes).each(Element.dispose);return this;},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this; +},match:function(p){return !p||Slick.match(this,p);}});var a=function(t,s,q){if(!q){t.setAttributeNode(document.createAttribute("id"));}if(t.clearAttributes){t.clearAttributes(); +t.mergeAttributes(s);t.removeAttribute("uid");if(t.options){var u=t.options,p=s.options;for(var r=u.length;r--;){u[r].selected=p[r].selected;}}}var v=n[s.tagName.toLowerCase()]; +if(v&&s[v]){t[v]=s[v];}};Element.implement("clone",function(r,p){r=r!==false;var w=this.cloneNode(r),q;if(r){var s=w.getElementsByTagName("*"),u=this.getElementsByTagName("*"); +for(q=s.length;q--;){a(s[q],u[q],p);}}a(w,this,p);if(Browser.ie){var t=w.getElementsByTagName("object"),v=this.getElementsByTagName("object");for(q=t.length; +q--;){t[q].outerHTML=v[q].outerHTML;}}return document.id(w);});var f={contains:function(p){return Slick.contains(this,p);}};if(!document.contains){Document.implement(f); +}if(!document.createElement("div").contains){Element.implement(f);}[Element,Window,Document].invoke("implement",{addListener:function(s,r){if(s=="unload"){var p=r,q=this; +r=function(){q.removeListener("unload",r);p();};}else{k[$uid(this)]=this;}if(this.addEventListener){this.addEventListener(s,r,!!arguments[2]);}else{this.attachEvent("on"+s,r); +}return this;},removeListener:function(q,p){if(this.removeEventListener){this.removeEventListener(q,p,!!arguments[2]);}else{this.detachEvent("on"+q,p); +}return this;},retrieve:function(q,p){var s=e($uid(this)),r=s[q];if(p!=null&&r==null){r=s[q]=p;}return r!=null?r:null;},store:function(q,p){var r=e($uid(this)); +r[q]=p;return this;},eliminate:function(p){var q=e($uid(this));delete q[p];return this;}});if(window.attachEvent&&!window.addEventListener){window.addListener("unload",function(){Object.each(k,j); +if(window.CollectGarbage){CollectGarbage();}});}})();Element.Properties={};Element.Properties.style={set:function(a){this.style.cssText=a;},get:function(){return this.style.cssText; +},erase:function(){this.style.cssText="";}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase();}};(function(a){if(a!=null){Element.Properties.maxlength=Element.Properties.maxLength={get:function(){var b=this.getAttribute("maxLength"); +return b==a?null:b;}};}})(document.createElement("input").getAttribute("maxLength"));Element.Properties.html=(function(){var c=Function.attempt(function(){var e=document.createElement("table"); +e.innerHTML="";});var d=document.createElement("div");var a={table:[1,"","
"],select:[1,""],tbody:[2,"","
"],tr:[3,"","
"]}; +a.thead=a.tfoot=a.tbody;var b={set:function(){var f=Array.flatten(arguments).join("");var g=(!c&&a[this.get("tag")]);if(g){var h=d;h.innerHTML=g[1]+f+g[2]; +for(var e=g[0];e--;){h=h.firstChild;}this.empty().adopt(h.childNodes);}else{this.innerHTML=f;}}};b.erase=b.set;return b;})();(function(){var c=document.html; +Element.Properties.styles={set:function(f){this.setStyles(f);}};var e=(c.style.opacity!=null);var d=/alpha\(opacity=([\d.]+)\)/i;var b=function(g,f){if(!g.currentStyle||!g.currentStyle.hasLayout){g.style.zoom=1; +}if(e){g.style.opacity=f;}else{f=(f*100).limit(0,100).round();f=(f==100)?"":"alpha(opacity="+f+")";var h=g.style.filter||g.getComputedStyle("filter")||""; +g.style.filter=d.test(h)?h.replace(d,f):h+f;}};Element.Properties.opacity={set:function(g){var f=this.style.visibility;if(g==0&&f!="hidden"){this.style.visibility="hidden"; +}else{if(g!=0&&f!="visible"){this.style.visibility="visible";}}b(this,g);},get:(e)?function(){var f=this.style.opacity||this.getComputedStyle("opacity"); +return(f=="")?1:f;}:function(){var f,g=(this.style.filter||this.getComputedStyle("filter"));if(g){f=g.match(d);}return(f==null||g==null)?1:(f[1]/100);}}; +var a=(c.style.cssFloat==null)?"styleFloat":"cssFloat";Element.implement({getComputedStyle:function(h){if(this.currentStyle){return this.currentStyle[h.camelCase()]; +}var g=Element.getDocument(this).defaultView,f=g?g.getComputedStyle(this,null):null;return(f)?f.getPropertyValue((h==a)?"float":h.hyphenate()):null;},setOpacity:function(f){b(this,f); +return this;},getOpacity:function(){return this.get("opacity");},setStyle:function(g,f){switch(g){case"opacity":return this.set("opacity",parseFloat(f)); +case"float":g=a;}g=g.camelCase();if(typeOf(f)!="string"){var h=(Element.Styles[g]||"@").split(" ");f=Array.from(f).map(function(k,j){if(!h[j]){return""; +}return(typeOf(k)=="number")?h[j].replace("@",Math.round(k)):k;}).join(" ");}else{if(f==String(Number(f))){f=Math.round(f);}}this.style[g]=f;return this; +},getStyle:function(l){switch(l){case"opacity":return this.get("opacity");case"float":l=a;}l=l.camelCase();var f=this.style[l];if(!f||l=="zIndex"){f=[]; +for(var k in Element.ShortStyles){if(l!=k){continue;}for(var j in Element.ShortStyles[k]){f.push(this.getStyle(j));}return f.join(" ");}f=this.getComputedStyle(l); +}if(f){f=String(f);var h=f.match(/rgba?\([\d\s,]+\)/);if(h){f=f.replace(h[0],h[0].rgbToHex());}}if(Browser.opera||(Browser.ie&&isNaN(parseFloat(f)))){if((/^(height|width)$/).test(l)){var g=(l=="width")?["left","right"]:["top","bottom"],i=0; +g.each(function(m){i+=this.getStyle("border-"+m+"-width").toInt()+this.getStyle("padding-"+m).toInt();},this);return this["offset"+l.capitalize()]-i+"px"; +}if(Browser.opera&&String(f).indexOf("px")!=-1){return f;}if((/^border(.+)Width|margin|padding/).test(l)){return"0px";}}return f;},setStyles:function(g){for(var f in g){this.setStyle(f,g[f]); +}return this;},getStyles:function(){var f={};Array.flatten(arguments).each(function(g){f[g]=this.getStyle(g);},this);return f;}});Element.Styles={left:"@px",top:"@px",bottom:"@px",right:"@px",width:"@px",height:"@px",maxWidth:"@px",maxHeight:"@px",minWidth:"@px",minHeight:"@px",backgroundColor:"rgb(@, @, @)",backgroundPosition:"@px @px",color:"rgb(@, @, @)",fontSize:"@px",letterSpacing:"@px",lineHeight:"@px",clip:"rect(@px @px @px @px)",margin:"@px @px @px @px",padding:"@px @px @px @px",border:"@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)",borderWidth:"@px @px @px @px",borderStyle:"@ @ @ @",borderColor:"rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)",zIndex:"@",zoom:"@",fontWeight:"@",textIndent:"@px",opacity:"@"}; +Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};["Top","Right","Bottom","Left"].each(function(l){var k=Element.ShortStyles; +var g=Element.Styles;["margin","padding"].each(function(m){var n=m+l;k[m][n]=g[n]="@px";});var j="border"+l;k.border[j]=g[j]="@px @ rgb(@, @, @)";var i=j+"Width",f=j+"Style",h=j+"Color"; +k[j]={};k.borderWidth[i]=k[j][i]=g[i]="@px";k.borderStyle[f]=k[j][f]=g[f]="@";k.borderColor[h]=k[j][h]=g[h]="rgb(@, @, @)";});})();(function(){Element.Properties.events={set:function(b){this.addEvents(b); +}};[Element,Window,Document].invoke("implement",{addEvent:function(f,h){var i=this.retrieve("events",{});if(!i[f]){i[f]={keys:[],values:[]};}if(i[f].keys.contains(h)){return this; +}i[f].keys.push(h);var g=f,b=Element.Events[f],d=h,j=this;if(b){if(b.onAdd){b.onAdd.call(this,h);}if(b.condition){d=function(k){if(b.condition.call(this,k)){return h.call(this,k); +}return true;};}g=b.base||g;}var e=function(){return h.call(j);};var c=Element.NativeEvents[g];if(c){if(c==2){e=function(k){k=new Event(k,j.getWindow()); +if(d.call(j,k)===false){k.stop();}};}this.addListener(g,e,arguments[2]);}i[f].values.push(e);return this;},removeEvent:function(e,d){var c=this.retrieve("events"); +if(!c||!c[e]){return this;}var h=c[e];var b=h.keys.indexOf(d);if(b==-1){return this;}var g=h.values[b];delete h.keys[b];delete h.values[b];var f=Element.Events[e]; +if(f){if(f.onRemove){f.onRemove.call(this,d);}e=f.base||e;}return(Element.NativeEvents[e])?this.removeListener(e,g,arguments[2]):this;},addEvents:function(b){for(var c in b){this.addEvent(c,b[c]); +}return this;},removeEvents:function(b){var d;if(typeOf(b)=="object"){for(d in b){this.removeEvent(d,b[d]);}return this;}var c=this.retrieve("events"); +if(!c){return this;}if(!b){for(d in c){this.removeEvents(d);}this.eliminate("events");}else{if(c[b]){c[b].keys.each(function(e){this.removeEvent(b,e);},this); +delete c[b];}}return this;},fireEvent:function(e,c,b){var d=this.retrieve("events");if(!d||!d[e]){return this;}c=Array.from(c);d[e].keys.each(function(f){if(b){f.delay(b,this,c); +}else{f.apply(this,c);}},this);return this;},cloneEvents:function(e,d){e=document.id(e);var c=e.retrieve("events");if(!c){return this;}if(!d){for(var b in c){this.cloneEvents(e,b); +}}else{if(c[d]){c[d].keys.each(function(f){this.addEvent(d,f);},this);}}return this;}});Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,orientationchange:2,touchstart:2,touchmove:2,touchend:2,touchcancel:2,gesturestart:2,gesturechange:2,gestureend:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:2,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1}; +var a=function(b){var c=b.relatedTarget;if(c==null){return true;}if(!c){return false;}return(c!=this&&c.prefix!="xul"&&typeOf(this)!="document"&&!this.contains(c)); +};Element.Events={mouseenter:{base:"mouseover",condition:a},mouseleave:{base:"mouseout",condition:a},mousewheel:{base:(Browser.firefox)?"DOMMouseScroll":"mousewheel"}}; +})();(function(){var h=document.createElement("div"),e=document.createElement("div");h.style.height="0";h.appendChild(e);var d=(e.offsetParent===h);h=e=null; +var l=function(m){return k(m,"position")!="static"||a(m);};var i=function(m){return l(m)||(/^(?:table|td|th)$/i).test(m.tagName);};Element.implement({scrollTo:function(m,n){if(a(this)){this.getWindow().scrollTo(m,n); +}else{this.scrollLeft=m;this.scrollTop=n;}return this;},getSize:function(){if(a(this)){return this.getWindow().getSize();}return{x:this.offsetWidth,y:this.offsetHeight}; +},getScrollSize:function(){if(a(this)){return this.getWindow().getScrollSize();}return{x:this.scrollWidth,y:this.scrollHeight};},getScroll:function(){if(a(this)){return this.getWindow().getScroll(); +}return{x:this.scrollLeft,y:this.scrollTop};},getScrolls:function(){var n=this.parentNode,m={x:0,y:0};while(n&&!a(n)){m.x+=n.scrollLeft;m.y+=n.scrollTop; +n=n.parentNode;}return m;},getOffsetParent:d?function(){var m=this;if(a(m)||k(m,"position")=="fixed"){return null;}var n=(k(m,"position")=="static")?i:l; +while((m=m.parentNode)){if(n(m)){return m;}}return null;}:function(){var m=this;if(a(m)||k(m,"position")=="fixed"){return null;}try{return m.offsetParent; +}catch(n){}return null;},getOffsets:function(){if(this.getBoundingClientRect&&!Browser.Platform.ios){var r=this.getBoundingClientRect(),o=document.id(this.getDocument().documentElement),q=o.getScroll(),t=this.getScrolls(),s=(k(this,"position")=="fixed"); +return{x:r.left.toInt()+t.x+((s)?0:q.x)-o.clientLeft,y:r.top.toInt()+t.y+((s)?0:q.y)-o.clientTop};}var n=this,m={x:0,y:0};if(a(this)){return m;}while(n&&!a(n)){m.x+=n.offsetLeft; +m.y+=n.offsetTop;if(Browser.firefox){if(!c(n)){m.x+=b(n);m.y+=g(n);}var p=n.parentNode;if(p&&k(p,"overflow")!="visible"){m.x+=b(p);m.y+=g(p);}}else{if(n!=this&&Browser.safari){m.x+=b(n); +m.y+=g(n);}}n=n.offsetParent;}if(Browser.firefox&&!c(this)){m.x-=b(this);m.y-=g(this);}return m;},getPosition:function(p){if(a(this)){return{x:0,y:0};}var q=this.getOffsets(),n=this.getScrolls(); +var m={x:q.x-n.x,y:q.y-n.y};if(p&&(p=document.id(p))){var o=p.getPosition();return{x:m.x-o.x-b(p),y:m.y-o.y-g(p)};}return m;},getCoordinates:function(o){if(a(this)){return this.getWindow().getCoordinates(); +}var m=this.getPosition(o),n=this.getSize();var p={left:m.x,top:m.y,width:n.x,height:n.y};p.right=p.left+p.width;p.bottom=p.top+p.height;return p;},computePosition:function(m){return{left:m.x-j(this,"margin-left"),top:m.y-j(this,"margin-top")}; +},setPosition:function(m){return this.setStyles(this.computePosition(m));}});[Document,Window].invoke("implement",{getSize:function(){var m=f(this);return{x:m.clientWidth,y:m.clientHeight}; +},getScroll:function(){var n=this.getWindow(),m=f(this);return{x:n.pageXOffset||m.scrollLeft,y:n.pageYOffset||m.scrollTop};},getScrollSize:function(){var o=f(this),n=this.getSize(),m=this.getDocument().body; +return{x:Math.max(o.scrollWidth,m.scrollWidth,n.x),y:Math.max(o.scrollHeight,m.scrollHeight,n.y)};},getPosition:function(){return{x:0,y:0};},getCoordinates:function(){var m=this.getSize(); +return{top:0,left:0,bottom:m.y,right:m.x,height:m.y,width:m.x};}});var k=Element.getComputedStyle;function j(m,n){return k(m,n).toInt()||0;}function c(m){return k(m,"-moz-box-sizing")=="border-box"; +}function g(m){return j(m,"border-top-width");}function b(m){return j(m,"border-left-width");}function a(m){return(/^(?:body|html)$/i).test(m.tagName); +}function f(m){var n=m.getDocument();return(!n.compatMode||n.compatMode=="CSS1Compat")?n.html:n.body;}})();Element.alias({position:"setPosition"});[Window,Document,Element].invoke("implement",{getHeight:function(){return this.getSize().y; +},getWidth:function(){return this.getSize().x;},getScrollTop:function(){return this.getScroll().y;},getScrollLeft:function(){return this.getScroll().x; +},getScrollHeight:function(){return this.getScrollSize().y;},getScrollWidth:function(){return this.getScrollSize().x;},getTop:function(){return this.getPosition().y; +},getLeft:function(){return this.getPosition().x;}});(function(){var f=this.Fx=new Class({Implements:[Chain,Events,Options],options:{fps:60,unit:false,duration:500,frames:null,frameSkip:true,link:"ignore"},initialize:function(g){this.subject=this.subject||this; +this.setOptions(g);},getTransition:function(){return function(g){return -(Math.cos(Math.PI*g)-1)/2;};},step:function(g){if(this.options.frameSkip){var h=(this.time!=null)?(g-this.time):0,i=h/this.frameInterval; +this.time=g;this.frame+=i;}else{this.frame++;}if(this.frame=(7-4*d)/11){e=c*c-Math.pow((11-6*d-11*f)/4,2);break;}}return e; +},Elastic:function(b,a){return Math.pow(2,10*--b)*Math.cos(20*b*Math.PI*(a&&a[0]||1)/3);}});["Quad","Cubic","Quart","Quint"].each(function(b,a){Fx.Transitions[b]=new Fx.Transition(function(c){return Math.pow(c,a+2); +});});(function(){var d=function(){},a=("onprogress" in new Browser.Request);var c=this.Request=new Class({Implements:[Chain,Events,Options],options:{url:"",data:"",headers:{"X-Requested-With":"XMLHttpRequest",Accept:"text/javascript, text/html, application/xml, text/xml, */*"},async:true,format:false,method:"post",link:"ignore",isSuccess:null,emulation:true,urlEncoded:true,encoding:"utf-8",evalScripts:false,evalResponse:false,timeout:0,noCache:false},initialize:function(e){this.xhr=new Browser.Request(); +this.setOptions(e);this.headers=this.options.headers;},onStateChange:function(){var e=this.xhr;if(e.readyState!=4||!this.running){return;}this.running=false; +this.status=0;Function.attempt(function(){var f=e.status;this.status=(f==1223)?204:f;}.bind(this));e.onreadystatechange=d;if(a){e.onprogress=e.onloadstart=d; +}clearTimeout(this.timer);this.response={text:this.xhr.responseText||"",xml:this.xhr.responseXML};if(this.options.isSuccess.call(this,this.status)){this.success(this.response.text,this.response.xml); +}else{this.failure();}},isSuccess:function(){var e=this.status;return(e>=200&&e<300);},isRunning:function(){return !!this.running;},processScripts:function(e){if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader("Content-type"))){return Browser.exec(e); +}return e.stripScripts(this.options.evalScripts);},success:function(f,e){this.onSuccess(this.processScripts(f),e);},onSuccess:function(){this.fireEvent("complete",arguments).fireEvent("success",arguments).callChain(); +},failure:function(){this.onFailure();},onFailure:function(){this.fireEvent("complete").fireEvent("failure",this.xhr);},loadstart:function(e){this.fireEvent("loadstart",[e,this.xhr]); +},progress:function(e){this.fireEvent("progress",[e,this.xhr]);},timeout:function(){this.fireEvent("timeout",this.xhr);},setHeader:function(e,f){this.headers[e]=f; +return this;},getHeader:function(e){return Function.attempt(function(){return this.xhr.getResponseHeader(e);}.bind(this));},check:function(){if(!this.running){return true; +}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(this.caller.pass(arguments,this));return false;}return false;},send:function(o){if(!this.check(o)){return this; +}this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.running=true;var l=typeOf(o);if(l=="string"||l=="element"){o={data:o};}var h=this.options; +o=Object.append({data:h.data,url:h.url,method:h.method},o);var j=o.data,f=String(o.url),e=o.method.toLowerCase();switch(typeOf(j)){case"element":j=document.id(j).toQueryString(); +break;case"object":case"hash":j=Object.toQueryString(j);}if(this.options.format){var m="format="+this.options.format;j=(j)?m+"&"+j:m;}if(this.options.emulation&&!["get","post"].contains(e)){var k="_method="+e; +j=(j)?k+"&"+j:k;e="post";}if(this.options.urlEncoded&&["post","put"].contains(e)){var g=(this.options.encoding)?"; charset="+this.options.encoding:"";this.headers["Content-type"]="application/x-www-form-urlencoded"+g; +}if(!f){f=document.location.pathname;}var i=f.lastIndexOf("/");if(i>-1&&(i=f.indexOf("#"))>-1){f=f.substr(0,i);}if(this.options.noCache){f+=(f.contains("?")?"&":"?")+String.uniqueID(); +}if(j&&e=="get"){f+=(f.contains("?")?"&":"?")+j;j=null;}var n=this.xhr;if(a){n.onloadstart=this.loadstart.bind(this);n.onprogress=this.progress.bind(this); +}n.open(e.toUpperCase(),f,this.options.async,this.options.user,this.options.password);if(this.options.user&&"withCredentials" in n){n.withCredentials=true; +}n.onreadystatechange=this.onStateChange.bind(this);Object.each(this.headers,function(q,p){try{n.setRequestHeader(p,q);}catch(r){this.fireEvent("exception",[p,q]); +}},this);this.fireEvent("request");n.send(j);if(!this.options.async){this.onStateChange();}if(this.options.timeout){this.timer=this.timeout.delay(this.options.timeout,this); +}return this;},cancel:function(){if(!this.running){return this;}this.running=false;var e=this.xhr;e.abort();clearTimeout(this.timer);e.onreadystatechange=d; +if(a){e.onprogress=e.onloadstart=d;}this.xhr=new Browser.Request();this.fireEvent("cancel");return this;}});var b={};["get","post","put","delete","GET","POST","PUT","DELETE"].each(function(e){b[e]=function(g){var f={method:e}; +if(g!=null){f.data=g;}return this.send(f);};});c.implement(b);Element.Properties.send={set:function(e){var f=this.get("send").cancel();f.setOptions(e); +return this;},get:function(){var e=this.retrieve("send");if(!e){e=new c({data:this,link:"cancel",method:this.get("method")||"post",url:this.get("action")}); +this.store("send",e);}return e;}};Element.implement({send:function(e){var f=this.get("send");f.send({data:this,url:e||f.options.url});return this;}});})(); +Request.HTML=new Class({Extends:Request,options:{update:false,append:false,evalScripts:true,filter:false,headers:{Accept:"text/html, application/xml, text/xml, */*"}},success:function(e){var d=this.options,b=this.response; +b.html=e.stripScripts(function(f){b.javascript=f;});var c=b.html.match(/]*>([\s\S]*?)<\/body>/i);if(c){b.html=c[1];}var a=new Element("div").set("html",b.html); +b.tree=a.childNodes;b.elements=a.getElements("*");if(d.filter){b.tree=b.elements.filter(d.filter);}if(d.update){document.id(d.update).empty().set("html",b.html); +}else{if(d.append){document.id(d.append).adopt(a.getChildren());}}if(d.evalScripts){Browser.exec(b.javascript);}this.onSuccess(b.tree,b.elements,b.html,b.javascript); +}});Element.Properties.load={set:function(a){var b=this.get("load").cancel();b.setOptions(a);return this;},get:function(){var a=this.retrieve("load");if(!a){a=new Request.HTML({data:this,link:"cancel",update:this,method:"get"}); +this.store("load",a);}return a;}};Element.implement({load:function(){this.get("load").send(Array.link(arguments,{data:Type.isObject,url:Type.isString})); +return this;}});if(typeof JSON=="undefined"){this.JSON={};}(function(){var special={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"}; +var escape=function(chr){return special[chr]||"\\u"+("0000"+chr.charCodeAt(0).toString(16)).slice(-4);};JSON.validate=function(string){string=string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""); +return(/^[\],:{}\s]*$/).test(string);};JSON.encode=JSON.stringify?function(obj){return JSON.stringify(obj);}:function(obj){if(obj&&obj.toJSON){obj=obj.toJSON(); +}switch(typeOf(obj)){case"string":return'"'+obj.replace(/[\x00-\x1f\\"]/g,escape)+'"';case"array":return"["+obj.map(JSON.encode).clean()+"]";case"object":case"hash":var string=[]; +Object.each(obj,function(value,key){var json=JSON.encode(value);if(json){string.push(JSON.encode(key)+":"+json);}});return"{"+string+"}";case"number":case"boolean":return""+obj; +case"null":return"null";}return null;};JSON.decode=function(string,secure){if(!string||typeOf(string)!="string"){return null;}if(secure||JSON.secure){if(JSON.parse){return JSON.parse(string); +}if(!JSON.validate(string)){throw new Error("JSON could not decode the input; security is enabled and the value is not secure.");}}return eval("("+string+")"); +};})();Request.JSON=new Class({Extends:Request,options:{secure:true},initialize:function(a){this.parent(a);Object.append(this.headers,{Accept:"application/json","X-Request":"JSON"}); +},success:function(c){var b;try{b=this.response.json=JSON.decode(c,this.options.secure);}catch(a){this.fireEvent("error",[c,a]);return;}if(b==null){this.onFailure(); +}else{this.onSuccess(b,c);}}});var Cookie=new Class({Implements:Options,options:{path:"/",domain:false,duration:false,secure:false,document:document,encode:true},initialize:function(b,a){this.key=b; +this.setOptions(a);},write:function(b){if(this.options.encode){b=encodeURIComponent(b);}if(this.options.domain){b+="; domain="+this.options.domain;}if(this.options.path){b+="; path="+this.options.path; +}if(this.options.duration){var a=new Date();a.setTime(a.getTime()+this.options.duration*24*60*60*1000);b+="; expires="+a.toGMTString();}if(this.options.secure){b+="; secure"; +}this.options.document.cookie=this.key+"="+b;return this;},read:function(){var a=this.options.document.cookie.match("(?:^|;)\\s*"+this.key.escapeRegExp()+"=([^;]*)"); +return(a)?decodeURIComponent(a[1]):null;},dispose:function(){new Cookie(this.key,Object.merge({},this.options,{duration:-1})).write("");return this;}}); +Cookie.write=function(b,c,a){return new Cookie(b,a).write(c);};Cookie.read=function(a){return new Cookie(a).read();};Cookie.dispose=function(b,a){return new Cookie(b,a).dispose(); +};(function(i,k){var l,f,e=[],c,b,d=k.createElement("div");var g=function(){clearTimeout(b);if(l){return;}Browser.loaded=l=true;k.removeListener("DOMContentLoaded",g).removeListener("readystatechange",a); +k.fireEvent("domready");i.fireEvent("domready");};var a=function(){for(var m=e.length;m--;){if(e[m]()){g();return true;}}return false;};var j=function(){clearTimeout(b); +if(!a()){b=setTimeout(j,10);}};k.addListener("DOMContentLoaded",g);var h=function(){try{d.doScroll();return true;}catch(m){}return false;};if(d.doScroll&&!h()){e.push(h); +c=true;}if(k.readyState){e.push(function(){var m=k.readyState;return(m=="loaded"||m=="complete");});}if("onreadystatechange" in k){k.addListener("readystatechange",a); +}else{c=true;}if(c){j();}Element.Events.domready={onAdd:function(m){if(l){m.call(this);}}};Element.Events.load={base:"load",onAdd:function(m){if(f&&this==i){m.call(this); +}},condition:function(){if(this==i){g();delete Element.Events.load;}return true;}};i.addEvent("load",function(){f=true;});})(window,document);(function(){var Swiff=this.Swiff=new Class({Implements:Options,options:{id:null,height:1,width:1,container:null,properties:{},params:{quality:"high",allowScriptAccess:"always",wMode:"window",swLiveConnect:true},callBacks:{},vars:{}},toElement:function(){return this.object; +},initialize:function(path,options){this.instance="Swiff_"+String.uniqueID();this.setOptions(options);options=this.options;var id=this.id=options.id||this.instance; +var container=document.id(options.container);Swiff.CallBacks[this.instance]={};var params=options.params,vars=options.vars,callBacks=options.callBacks; +var properties=Object.append({height:options.height,width:options.width},options.properties);var self=this;for(var callBack in callBacks){Swiff.CallBacks[this.instance][callBack]=(function(option){return function(){return option.apply(self.object,arguments); +};})(callBacks[callBack]);vars[callBack]="Swiff.CallBacks."+this.instance+"."+callBack;}params.flashVars=Object.toQueryString(vars);if(Browser.ie){properties.classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; +params.movie=path;}else{properties.type="application/x-shockwave-flash";}properties.data=path;var build='';}}build+="";this.object=((container)?container.empty():new Element("div")).set("html",build).firstChild; +},replaces:function(element){element=document.id(element,true);element.parentNode.replaceChild(this.toElement(),element);return this;},inject:function(element){document.id(element,true).appendChild(this.toElement()); +return this;},remote:function(){return Swiff.remote.apply(Swiff,[this.toElement()].append(arguments));}});Swiff.CallBacks={};Swiff.remote=function(obj,fn){var rs=obj.CallFunction(''+__flash__argumentsToXML(arguments,2)+""); +return eval(rs);};})(); \ No newline at end of file diff --git a/web/tools/mootools/mootools-1.2.5.1-more-nc.js b/web/tools/mootools/mootools-more-1.3.2.1-nc.js similarity index 57% rename from web/tools/mootools/mootools-1.2.5.1-more-nc.js rename to web/tools/mootools/mootools-more-1.3.2.1-nc.js index 26c4af807..4bf490e79 100644 --- a/web/tools/mootools/mootools-1.2.5.1-more-nc.js +++ b/web/tools/mootools/mootools-more-1.3.2.1-nc.js @@ -1,5 +1,6 @@ -//MooTools More, . Copyright (c) 2006-2009 Aaron Newton , Valerio Proietti & the MooTools team , MIT Style License. - +// MooTools: the javascript framework. +// Load this file's selection again by visiting: http://mootools.net/more/09f3e47813269cd5026cbf8c1f828e72 +// Or build this file again with packager using: packager build More/Chain.Wait More/Array.Extras More/Date More/Date.Extras More/Number.Format More/String.Extras More/String.QueryString More/URI More/URI.Relative More/Hash More/Hash.Extras More/Element.Forms More/Elements.From More/Element.Event.Pseudos.Keys More/Element.Pin More/Element.Position More/Element.Shortcuts More/Form.Request More/Form.Request.Append More/Form.Validator.Inline More/Form.Validator.Extras More/OverText More/Fx.Accordion More/Fx.Move More/Fx.Reveal More/Fx.Slide More/Fx.SmoothScroll More/Fx.Sort More/Drag.Move More/Slider More/Sortables More/Request.JSONP More/Request.Queue More/Request.Periodical More/Assets More/Color More/Group More/Hash.Cookie More/Table More/HtmlTable.Zebra More/HtmlTable.Sort More/HtmlTable.Select More/Keyboard.Extras More/Mask More/Scroller More/Tips More/Locale.en-GB.Date /* --- @@ -11,6 +12,16 @@ description: MooTools More license: MIT-style license +authors: + - Guillermo Rauch + - Thomas Aylott + - Scott Kyle + - Arian Stolwijk + - Tim Wienk + - Christoph Pojer + - Aaron Newton + - Jacob Thornton + requires: - Core/MooTools @@ -20,320 +31,11 @@ provides: [MooTools.More] */ MooTools.More = { - 'version': '1.2.5.1', - 'build': '254884f2b83651bf95260eed5c6cceb838e22d8e' + 'version': '1.3.2.1', + 'build': 'e586bcd2496e9b22acfde32e12f84d49ce09e59d' }; -/* ---- - -script: MooTools.Lang.js - -name: MooTools.Lang - -description: Provides methods for localization. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Events - - /MooTools.More - -provides: [Lang] - -... -*/ - -(function(){ - - var data = { - language: 'en-US', - languages: { - 'en-US': {} - }, - cascades: ['en-US'] - }; - - var cascaded; - - MooTools.lang = new Events(); - - $extend(MooTools.lang, { - - setLanguage: function(lang){ - if (!data.languages[lang]) return this; - data.language = lang; - this.load(); - this.fireEvent('langChange', lang); - return this; - }, - - load: function() { - var langs = this.cascade(this.getCurrentLanguage()); - cascaded = {}; - $each(langs, function(set, setName){ - cascaded[setName] = this.lambda(set); - }, this); - }, - - getCurrentLanguage: function(){ - return data.language; - }, - - addLanguage: function(lang){ - data.languages[lang] = data.languages[lang] || {}; - return this; - }, - - cascade: function(lang){ - var cascades = (data.languages[lang] || {}).cascades || []; - cascades.combine(data.cascades); - cascades.erase(lang).push(lang); - var langs = cascades.map(function(lng){ - return data.languages[lng]; - }, this); - return $merge.apply(this, langs); - }, - - lambda: function(set) { - (set || {}).get = function(key, args){ - return $lambda(set[key]).apply(this, $splat(args)); - }; - return set; - }, - - get: function(set, key, args){ - if (cascaded && cascaded[set]) return (key ? cascaded[set].get(key, args) : cascaded[set]); - }, - - set: function(lang, set, members){ - this.addLanguage(lang); - langData = data.languages[lang]; - if (!langData[set]) langData[set] = {}; - $extend(langData[set], members); - if (lang == this.getCurrentLanguage()){ - this.load(); - this.fireEvent('langChange', lang); - } - return this; - }, - - list: function(){ - return Hash.getKeys(data.languages); - } - - }); - -})(); - - -/* ---- - -script: Log.js - -name: Log - -description: Provides basic logging functionality for plugins to implement. - -license: MIT-style license - -authors: - - Guillermo Rauch - - Thomas Aylott - - Scott Kyle - -requires: - - Core/Class - - /MooTools.More - -provides: [Log] - -... -*/ - -(function(){ - -var global = this; - -var log = function(){ - if (global.console && console.log){ - try { - console.log.apply(console, arguments); - } catch(e) { - console.log(Array.slice(arguments)); - } - } else { - Log.logged.push(arguments); - } - return this; -}; - -var disabled = function(){ - this.logged.push(arguments); - return this; -}; - -this.Log = new Class({ - - logged: [], - - log: disabled, - - resetLog: function(){ - this.logged.empty(); - return this; - }, - - enableLog: function(){ - this.log = log; - this.logged.each(function(args){ - this.log.apply(this, args); - }, this); - return this.resetLog(); - }, - - disableLog: function(){ - this.log = disabled; - return this; - } - -}); - -Log.extend(new Log).enableLog(); - -// legacy -Log.logger = function(){ - return this.log.apply(this, arguments); -}; - -})(); - - -/* ---- - -script: Class.Refactor.js - -name: Class.Refactor - -description: Extends a class onto itself with new property, preserving any items attached to the class's namespace. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Class - - /MooTools.More - -# Some modules declare themselves dependent on Class.Refactor -provides: [Class.refactor, Class.Refactor] - -... -*/ - -Class.refactor = function(original, refactors){ - - $each(refactors, function(item, name){ - var origin = original.prototype[name]; - if (origin && (origin = origin._origin ? origin._origin: origin) && typeof item == 'function') original.implement(name, function(){ - var old = this.previous; - this.previous = origin; - var value = item.apply(this, arguments); - this.previous = old; - return value; - }); else original.implement(name, item); - }); - - return original; - -}; - - -/* ---- - -script: Class.Binds.js - -name: Class.Binds - -description: Automagically binds specified methods in a class to the instance of the class. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Class - - /MooTools.More - -provides: [Class.Binds] - -... -*/ - -Class.Mutators.Binds = function(binds){ - return binds; -}; - -Class.Mutators.initialize = function(initialize){ - return function(){ - $splat(this.Binds).each(function(name){ - var original = this[name]; - if (original) this[name] = original.bind(this); - }, this); - return initialize.apply(this, arguments); - }; -}; - - -/* ---- - -script: Class.Occlude.js - -name: Class.Occlude - -description: Prevents a class from being applied to a DOM element twice. - -license: MIT-style license. - -authors: - - Aaron Newton - -requires: - - Core/Class - - Core/Element - - /MooTools.More - -provides: [Class.Occlude] - -... -*/ - -Class.Occlude = new Class({ - - occlude: function(property, element){ - element = document.id(element || this.element); - var instance = element.retrieve(property || this.property); - if (instance && !$defined(this.occluded)) - return this.occluded = instance; - - this.occluded = false; - element.store(property || this.property, this); - return this.occluded; - } - -}); - - /* --- @@ -348,7 +50,7 @@ license: MIT-style license. authors: - Aaron Newton -requires: +requires: - Core/Chain - Core/Element - Core/Fx @@ -364,37 +66,38 @@ provides: [Chain.Wait] var wait = { wait: function(duration){ return this.chain(function(){ - this.callChain.delay($pick(duration, 500), this); + this.callChain.delay(duration == null ? 500 : duration, this); + return this; }.bind(this)); } }; Chain.implement(wait); - if (window.Fx){ - Fx.implement(wait); - ['Css', 'Tween', 'Elements'].each(function(cls){ - if (Fx[cls]) Fx[cls].implement(wait); + if (this.Fx) Fx.implement(wait); + + if (this.Element && Element.implement && this.Fx){ + Element.implement({ + + chains: function(effects){ + Array.from(effects || ['tween', 'morph', 'reveal']).each(function(effect){ + effect = this.get(effect); + if (!effect) return; + effect.setOptions({ + link:'chain' + }); + }, this); + return this; + }, + + pauseFx: function(duration, effect){ + this.chains(effect).get(effect || 'tween').wait(duration); + return this; + } + }); } - Element.implement({ - chains: function(effects){ - $splat($pick(effects, ['tween', 'morph', 'reveal'])).each(function(effect){ - effect = this.get(effect); - if (!effect) return; - effect.setOptions({ - link:'chain' - }); - }, this); - return this; - }, - pauseFx: function(duration, effect){ - this.chains(effect).get($pick(effect, 'tween')).wait(duration); - return this; - } - }); - })(); @@ -411,14 +114,19 @@ license: MIT-style license authors: - Christoph Pojer + - Sebastian MarkbÃ¥ge requires: - Core/Array + - MooTools.More provides: [Array.Extras] ... */ + +(function(nil){ + Array.implement({ min: function(){ @@ -436,9 +144,7 @@ Array.implement({ sum: function(){ var result = 0, l = this.length; if (l){ - do { - result += this[--l]; - } while (l); + while (l--) result += this[l]; } return result; }, @@ -454,10 +160,336 @@ Array.implement({ this[r] = temp; } return this; + }, + + reduce: function(fn, value){ + for (var i = 0, l = this.length; i < l; i++){ + if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this); + } + return value; + }, + + reduceRight: function(fn, value){ + var i = this.length; + while (i--){ + if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this); + } + return value; } }); +})(); + + +/* +--- + +script: Object.Extras.js + +name: Object.Extras + +description: Extra Object generics, like getFromPath which allows a path notation to child elements. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Object + - /MooTools.More + +provides: [Object.Extras] + +... +*/ + +(function(){ + +var defined = function(value){ + return value != null; +}; + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +Object.extend({ + + getFromPath: function(source, parts){ + if (typeof parts == 'string') parts = parts.split('.'); + for (var i = 0, l = parts.length; i < l; i++){ + if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]]; + else return null; + } + return source; + }, + + cleanValues: function(object, method){ + method = method || defined; + for (var key in object) if (!method(object[key])){ + delete object[key]; + } + return object; + }, + + erase: function(object, key){ + if (hasOwnProperty.call(object, key)) delete object[key]; + return object; + }, + + run: function(object){ + var args = Array.slice(arguments, 1); + for (var key in object) if (object[key].apply){ + object[key].apply(object, args); + } + return object; + } + +}); + +})(); + + +/* +--- + +script: Locale.js + +name: Locale + +description: Provides methods for localization. + +license: MIT-style license + +authors: + - Aaron Newton + - Arian Stolwijk + +requires: + - Core/Events + - /Object.Extras + - /MooTools.More + +provides: [Locale, Lang] + +... +*/ + +(function(){ + +var current = null, + locales = {}, + inherits = {}; + +var getSet = function(set){ + if (instanceOf(set, Locale.Set)) return set; + else return locales[set]; +}; + +var Locale = this.Locale = { + + define: function(locale, set, key, value){ + var name; + if (instanceOf(locale, Locale.Set)){ + name = locale.name; + if (name) locales[name] = locale; + } else { + name = locale; + if (!locales[name]) locales[name] = new Locale.Set(name); + locale = locales[name]; + } + + if (set) locale.define(set, key, value); + + + + if (!current) current = locale; + + return locale; + }, + + use: function(locale){ + locale = getSet(locale); + + if (locale){ + current = locale; + + this.fireEvent('change', locale); + + + } + + return this; + }, + + getCurrent: function(){ + return current; + }, + + get: function(key, args){ + return (current) ? current.get(key, args) : ''; + }, + + inherit: function(locale, inherits, set){ + locale = getSet(locale); + + if (locale) locale.inherit(inherits, set); + return this; + }, + + list: function(){ + return Object.keys(locales); + } + +}; + +Object.append(Locale, new Events); + +Locale.Set = new Class({ + + sets: {}, + + inherits: { + locales: [], + sets: {} + }, + + initialize: function(name){ + this.name = name || ''; + }, + + define: function(set, key, value){ + var defineData = this.sets[set]; + if (!defineData) defineData = {}; + + if (key){ + if (typeOf(key) == 'object') defineData = Object.merge(defineData, key); + else defineData[key] = value; + } + this.sets[set] = defineData; + + return this; + }, + + get: function(key, args, _base){ + var value = Object.getFromPath(this.sets, key); + if (value != null){ + var type = typeOf(value); + if (type == 'function') value = value.apply(null, Array.from(args)); + else if (type == 'object') value = Object.clone(value); + return value; + } + + // get value of inherited locales + var index = key.indexOf('.'), + set = index < 0 ? key : key.substr(0, index), + names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US'); + if (!_base) _base = []; + + for (var i = 0, l = names.length; i < l; i++){ + if (_base.contains(names[i])) continue; + _base.include(names[i]); + + var locale = locales[names[i]]; + if (!locale) continue; + + value = locale.get(key, args, _base); + if (value != null) return value; + } + + return ''; + }, + + inherit: function(names, set){ + names = Array.from(names); + + if (set && !this.inherits.sets[set]) this.inherits.sets[set] = []; + + var l = names.length; + while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]); + + return this; + } + +}); + + + +})(); + + +/* +--- + +name: Locale.en-US.Date + +description: Date messages for US English. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - /Locale + +provides: [Locale.en-US.Date] + +... +*/ + +Locale.define('en-US', 'Date', { + + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + + // Culture's date order: MM/DD/YYYY + dateOrder: ['month', 'date', 'year'], + shortDate: '%m/%d/%Y', + shortTime: '%I:%M%p', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 0, + + // Date.Extras + ordinal: function(dayOfMonth){ + // 1st, 2nd, 3rd, etc. + return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)]; + }, + + lessThanMinuteAgo: 'less than a minute ago', + minuteAgo: 'about a minute ago', + minutesAgo: '{delta} minutes ago', + hourAgo: 'about an hour ago', + hoursAgo: 'about {delta} hours ago', + dayAgo: '1 day ago', + daysAgo: '{delta} days ago', + weekAgo: '1 week ago', + weeksAgo: '{delta} weeks ago', + monthAgo: '1 month ago', + monthsAgo: '{delta} months ago', + yearAgo: '1 year ago', + yearsAgo: '{delta} years ago', + + lessThanMinuteUntil: 'less than a minute from now', + minuteUntil: 'about a minute from now', + minutesUntil: '{delta} minutes from now', + hourUntil: 'about an hour from now', + hoursUntil: 'about {delta} hours from now', + dayUntil: '1 day from now', + daysUntil: '{delta} days from now', + weekUntil: '1 week from now', + weeksUntil: '{delta} weeks from now', + monthUntil: '1 month from now', + monthsUntil: '{delta} months from now', + yearUntil: '1 year from now', + yearsUntil: '{delta} years from now' + +}); + + /* --- @@ -479,9 +511,9 @@ requires: - Core/Array - Core/String - Core/Number - - /Lang - - /Date.English.US - - /MooTools.More + - MooTools.More + - Locale + - Locale.en-US.Date provides: [Date] @@ -492,9 +524,7 @@ provides: [Date] var Date = this.Date; -if (!Date.now) Date.now = $time; - -Date.Methods = { +var DateMethods = Date.Methods = { ms: 'Milliseconds', year: 'FullYear', min: 'Minutes', @@ -509,31 +539,26 @@ Date.Methods = { Date.Methods[method.toLowerCase()] = method; }); -var pad = function(what, length){ - return new Array(length - String(what).length + 1).join('0') + what; +var pad = function(n, digits, string){ + if (digits == 1) return n; + return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n; }; Date.implement({ set: function(prop, value){ - switch ($type(prop)){ - case 'object': - for (var p in prop) this.set(p, prop[p]); - break; - case 'string': - prop = prop.toLowerCase(); - var m = Date.Methods; - if (m[prop]) this['set' + m[prop]](value); - } + prop = prop.toLowerCase(); + var method = DateMethods[prop] && 'set' + DateMethods[prop]; + if (method && this[method]) this[method](value); return this; - }, + }.overloadSetter(), get: function(prop){ prop = prop.toLowerCase(); - var m = Date.Methods; - if (m[prop]) return this['get' + m[prop]](); + var method = DateMethods[prop] && 'get' + DateMethods[prop]; + if (method && this[method]) return this[method](); return null; - }, + }.overloadGetter(), clone: function(){ return new Date(this.get('time')); @@ -541,7 +566,7 @@ Date.implement({ increment: function(interval, times){ interval = interval || 'day'; - times = $pick(times, 1); + times = times != null ? times : 1; switch (interval){ case 'year': @@ -562,7 +587,7 @@ Date.implement({ }, decrement: function(interval, times){ - return this.increment(interval, -1 * $pick(times, 1)); + return this.increment(interval, -1 * (times != null ? times : 1)); }, isLeapYear: function(){ @@ -574,8 +599,8 @@ Date.implement({ }, diff: function(date, resolution){ - if ($type(date) == 'string') date = Date.parse(date); - + if (typeOf(date) == 'string') date = Date.parse(date); + return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month }, @@ -584,14 +609,61 @@ Date.implement({ }, getDayOfYear: function(){ - return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1) + return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1) - Date.UTC(this.get('year'), 0, 1)) / Date.units.day(); }, - getWeek: function(){ - return (this.get('dayofyear') / 7).ceil(); + setDay: function(day, firstDayOfWeek){ + if (firstDayOfWeek == null){ + firstDayOfWeek = Date.getMsg('firstDayOfWeek'); + if (firstDayOfWeek === '') firstDayOfWeek = 1; + } + + day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7; + var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7; + + return this.increment('day', day - currentDay); }, - + + getWeek: function(firstDayOfWeek){ + if (firstDayOfWeek == null){ + firstDayOfWeek = Date.getMsg('firstDayOfWeek'); + if (firstDayOfWeek === '') firstDayOfWeek = 1; + } + + var date = this, + dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7, + dividend = 0, + firstDayOfYear; + + if (firstDayOfWeek == 1){ + // ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week) + var month = date.get('month'), + startOfWeek = date.get('date') - dayOfWeek; + + if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year + + if (month == 0 && startOfWeek < -2){ + // Use a date from last year to determine the week + date = new Date(date).decrement('day', dayOfWeek); + dayOfWeek = 0; + } + + firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7; + if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1 + } else { + // In other cultures the first week of the year is always week 1 and the last week always 53 or 54. + // Days in the same week can have a different weeknumber if the week spreads across two years. + firstDayOfYear = new Date(date.get('year'), 0, 1).get('day'); + } + + dividend += date.get('dayofyear'); + dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week + dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week + + return (dividend / 7); + }, + getOrdinal: function(day){ return Date.getMsg('ordinal', day || this.get('date')); }, @@ -624,44 +696,50 @@ Date.implement({ return this; }, - isValid: function(date) { + isValid: function(date){ return !isNaN((date || this).valueOf()); }, format: function(f){ if (!this.isValid()) return 'invalid date'; - f = f || '%x %X'; - f = formats[f.toLowerCase()] || f; // replace short-hand with actual format + if (!f) f = '%x %X'; + + var formatLower = f.toLowerCase(); + if (formatters[formatLower]) return formatters[formatLower](this); // it's a formatter! + f = formats[formatLower] || f; // replace short-hand with actual format + var d = this; return f.replace(/%([a-z%])/gi, function($0, $1){ switch ($1){ - case 'a': return Date.getMsg('days')[d.get('day')].substr(0, 3); + case 'a': return Date.getMsg('days_abbr')[d.get('day')]; case 'A': return Date.getMsg('days')[d.get('day')]; - case 'b': return Date.getMsg('months')[d.get('month')].substr(0, 3); + case 'b': return Date.getMsg('months_abbr')[d.get('month')]; case 'B': return Date.getMsg('months')[d.get('month')]; - case 'c': return d.toString(); + case 'c': return d.format('%a %b %d %H:%M:%S %Y'); case 'd': return pad(d.get('date'), 2); - case 'D': return d.get('date'); - case 'e': return d.get('date'); + case 'e': return pad(d.get('date'), 2, ' '); case 'H': return pad(d.get('hr'), 2); - case 'I': return ((d.get('hr') % 12) || 12); + case 'I': return pad((d.get('hr') % 12) || 12, 2); case 'j': return pad(d.get('dayofyear'), 3); + case 'k': return pad(d.get('hr'), 2, ' '); + case 'l': return pad((d.get('hr') % 12) || 12, 2, ' '); + case 'L': return pad(d.get('ms'), 3); case 'm': return pad((d.get('mo') + 1), 2); case 'M': return pad(d.get('min'), 2); case 'o': return d.get('ordinal'); case 'p': return Date.getMsg(d.get('ampm')); case 's': return Math.round(d / 1000); case 'S': return pad(d.get('seconds'), 2); + case 'T': return d.format('%H:%M:%S'); case 'U': return pad(d.get('week'), 2); case 'w': return d.get('day'); case 'x': return d.format(Date.getMsg('shortDate')); case 'X': return d.format(Date.getMsg('shortTime')); case 'y': return d.get('year').toString().substr(2); case 'Y': return d.get('year'); - case 'T': return d.get('GMTOffset'); + case 'z': return d.get('GMTOffset'); case 'Z': return d.get('Timezone'); - case 'z': return pad(d.get('ms'), 3); } return $1; } @@ -672,28 +750,51 @@ Date.implement({ return this.format('iso8601'); } +}).alias({ + toJSON: 'toISOString', + compare: 'diff', + strftime: 'format' }); -Date.alias('toISOString', 'toJSON'); -Date.alias('diff', 'compare'); -Date.alias('format', 'strftime'); - var formats = { db: '%Y-%m-%d %H:%M:%S', compact: '%Y%m%dT%H%M%S', - iso8601: '%Y-%m-%dT%H:%M:%S%T', - rfc822: '%a, %d %b %Y %H:%M:%S %Z', 'short': '%d %b %H:%M', 'long': '%B %d, %Y %H:%M' }; -var parsePatterns = []; -var nativeParse = Date.parse; +// The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized +var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + +var formatters = { + rfc822: function(date){ + return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z'); + }, + rfc2822: function(date){ + return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z'); + }, + iso8601: function(date){ + return ( + date.getUTCFullYear() + '-' + + pad(date.getUTCMonth() + 1, 2) + '-' + + pad(date.getUTCDate(), 2) + 'T' + + pad(date.getUTCHours(), 2) + ':' + + pad(date.getUTCMinutes(), 2) + ':' + + pad(date.getUTCSeconds(), 2) + '.' + + pad(date.getUTCMilliseconds(), 3) + 'Z' + ); + } +}; + + +var parsePatterns = [], + nativeParse = Date.parse; var parseWord = function(type, word, num){ - var ret = -1; - var translated = Date.getMsg(type + 's'); - switch ($type(word)){ + var ret = -1, + translated = Date.getMsg(type + 's'); + switch (typeOf(word)){ case 'object': ret = translated[word.get(type)]; break; @@ -705,7 +806,7 @@ var parseWord = function(type, word, num){ var match = translated.filter(function(name){ return this.test(name); }, new RegExp('^' + word, 'i')); - if (!match.length) throw new Error('Invalid ' + type + ' string'); + if (!match.length) throw new Error('Invalid ' + type + ' string'); if (match.length > 1) throw new Error('Ambiguous ' + type); ret = match[0]; } @@ -713,22 +814,25 @@ var parseWord = function(type, word, num){ return (num) ? translated.indexOf(ret) : ret; }; +var startCentury = 1900, + startYear = 70; + Date.extend({ - getMsg: function(key, args) { - return MooTools.lang.get('Date', key, args); + getMsg: function(key, args){ + return Locale.get('Date.' + key, args); }, units: { - ms: $lambda(1), - second: $lambda(1000), - minute: $lambda(60000), - hour: $lambda(3600000), - day: $lambda(86400000), - week: $lambda(608400000), + ms: Function.from(1), + second: Function.from(1000), + minute: Function.from(60000), + hour: Function.from(3600000), + day: Function.from(86400000), + week: Function.from(608400000), month: function(month, year){ var d = new Date; - return Date.daysInMonth($pick(month, d.get('mo')), $pick(year, d.get('year'))) * 86400000; + return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000; }, year: function(year){ year = year || new Date().get('year'); @@ -745,7 +849,7 @@ Date.extend({ }, parse: function(from){ - var t = $type(from); + var t = typeOf(from); if (t == 'number') return new Date(from); if (t != 'string') return from; from = from.clean(); @@ -757,7 +861,11 @@ Date.extend({ return (bits) ? (parsed = pattern.handler(bits)) : false; }); - return parsed || new Date(nativeParse(from)); + if (!(parsed && parsed.isValid())){ + parsed = new Date(nativeParse(from)); + if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt()); + } + return parsed; }, parseDay: function(day, num){ @@ -788,32 +896,34 @@ Date.extend({ defineFormat: function(name, format){ formats[name] = format; + return this; }, defineFormats: function(formats){ for (var name in formats) Date.defineFormat(name, formats[name]); + return this; }, - parsePatterns: parsePatterns, // this is deprecated + defineParser: function(pattern){ parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern)); + return this; }, - + defineParsers: function(){ Array.flatten(arguments).each(Date.defineParser); + return this; }, - + define2DigitYearStart: function(year){ startYear = year % 100; startCentury = year - startYear; + return this; } }); -var startCentury = 1900; -var startYear = 70; - var regexOf = function(type){ return new RegExp('(?:' + Date.getMsg(type).map(function(name){ return name.substr(0, 3); @@ -821,11 +931,13 @@ var regexOf = function(type){ }; var replacers = function(key){ - switch(key){ + switch (key){ + case 'T': + return '%H:%M:%S'; case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?'; case 'X': - return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%T?'; + return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?'; } return null; }; @@ -840,7 +952,7 @@ var keys = { p: /[ap]\.?m\.?/, y: /\d{2}|\d{4}/, Y: /\d{4}/, - T: /Z|[+-]\d{2}(?::?\d{2})?/ + z: /Z|[+-]\d{2}(?::?\d{2})?/ }; keys.m = keys.I; @@ -850,10 +962,10 @@ var currentLanguage; var recompile = function(language){ currentLanguage = language; - + keys.a = keys.A = regexOf('days'); keys.b = keys.B = regexOf('months'); - + parsePatterns.each(function(pattern, i){ if (pattern.format) parsePatterns[i] = build(pattern.format); }); @@ -861,7 +973,7 @@ var recompile = function(language){ var build = function(format){ if (!currentLanguage) return {format: format}; - + var parsed = []; var re = (format.source || format) // allow format to be regex .replace(/%([a-z])/gi, @@ -877,7 +989,7 @@ var build = function(format){ parsed.push($1); return '(' + p.source + ')'; } - ).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff]'); // handle unicode words + ).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words return { format: format, @@ -886,11 +998,11 @@ var build = function(format){ bits = bits.slice(1).associate(parsed); var date = new Date().clearTime(), year = bits.y || bits.Y; - + if (year != null) handle.call(date, 'y', year); // need to start in the right year if ('d' in bits) handle.call(date, 'd', 1); - if ('m' in bits || 'b' in bits || 'B' in bits) handle.call(date, 'm', 1); - + if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1); + for (var key in bits) handle.call(date, key, bits[key]); return date; } @@ -900,7 +1012,7 @@ var build = function(format){ var handle = function(key, value){ if (!value) return this; - switch(key){ + switch (key){ case 'a': case 'A': return this.set('day', Date.parseDay(value, true)); case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true)); case 'd': return this.set('date', value); @@ -916,7 +1028,7 @@ var handle = function(key, value){ value = +value; if (value < 100) value += startCentury + (value < startYear ? 100 : 0); return this.set('year', value); - case 'T': + case 'z': if (value == 'Z') value = '+00'; var offset = value.match(/([+-])(\d{2}):?(\d{2})?/); offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset(); @@ -933,12 +1045,14 @@ Date.defineParsers( '%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm" '%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched '%Y %b( %d%o( %X)?)?', // Same as above with year coming first - '%o %b %d %X %T %Y' // "Thu Oct 22 08:11:23 +0000 2009" + '%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009" + '%T', // %H:%M:%S + '%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05" ); -MooTools.lang.addEvent('langChange', function(language){ - if (MooTools.lang.get('Date')) recompile(language); -}).fireEvent('langChange', MooTools.lang.getCurrentLanguage()); +Locale.addEvent('change', function(language){ + if (Locale.get('Date')) recompile(language); +}).fireEvent('change', Locale.getCurrent()); })(); @@ -968,36 +1082,33 @@ provides: [Date.Extras] Date.implement({ - timeDiffInWords: function(relative_to){ - return Date.distanceOfTimeInWords(this, relative_to || new Date); + timeDiffInWords: function(to){ + return Date.distanceOfTimeInWords(this, to || new Date); }, - timeDiff: function(to, joiner){ + timeDiff: function(to, separator){ if (to == null) to = new Date; - var delta = ((to - this) / 1000).toInt(); - if (!delta) return '0s'; - - var durations = {s: 60, m: 60, h: 24, d: 365, y: 0}; - var duration, vals = []; - - for (var step in durations){ - if (!delta) break; - if ((duration = durations[step])){ - vals.unshift((delta % duration) + step); - delta = (delta / duration).toInt(); - } else { - vals.unshift(delta + step); + var delta = ((to - this) / 1000).floor().abs(); + + var vals = [], + durations = [60, 60, 24, 365, 0], + names = ['s', 'm', 'h', 'd', 'y'], + value, duration; + + for (var item = 0; item < durations.length; item++){ + if (item && !delta) break; + value = delta; + if ((duration = durations[item])){ + value = (delta % duration); + delta = (delta / duration).floor(); } + vals.unshift(value + (names[item] || '')); } - - return vals.join(joiner || ':'); + + return vals.join(separator || ':'); } -}); - -Date.alias('timeDiffInWords', 'timeAgoInWords'); - -Date.extend({ +}).extend({ distanceOfTimeInWords: function(from, to){ return Date.getTimePhrase(((to - from) / 1000).toInt()); @@ -1006,7 +1117,7 @@ Date.extend({ getTimePhrase: function(delta){ var suffix = (delta < 0) ? 'Until' : 'Ago'; if (delta < 0) delta *= -1; - + var units = { minute: 60, hour: 60, @@ -1016,9 +1127,9 @@ Date.extend({ year: 12, eon: Infinity }; - + var msg = 'lessThanMinute'; - + for (var unit in units){ var interval = units[unit]; if (delta < 1.5 * interval){ @@ -1028,24 +1139,22 @@ Date.extend({ delta /= interval; msg = unit + 's'; } - - return Date.getMsg(msg + suffix, delta).substitute({delta: delta.round()}); + + delta = delta.round(); + return Date.getMsg(msg + suffix, delta).substitute({delta: delta}); } -}); - - -Date.defineParsers( +}).defineParsers( { // "today", "tomorrow", "yesterday" re: /^(?:tod|tom|yes)/i, handler: function(bits){ var d = new Date().clearTime(); - switch(bits[0]){ + switch (bits[0]){ case 'tom': return d.increment(); case 'yes': return d.decrement(); - default: return d; + default: return d; } } }, @@ -1064,62 +1173,169 @@ Date.defineParsers( } } -); +).alias('timeAgoInWords', 'timeDiffInWords'); /* --- -script: Hash.Extras.js +name: Locale.en-US.Number -name: Hash.Extras - -description: Extends the Hash native object to include getFromPath which allows a path notation to child elements. +description: Number messages for US English. license: MIT-style license authors: - - Aaron Newton + - Arian Stolwijk requires: - - Core/Hash.base - - /MooTools.More + - /Locale -provides: [Hash.Extras] +provides: [Locale.en-US.Number] ... */ -Hash.implement({ +Locale.define('en-US', 'Number', { - getFromPath: function(notation){ - var source = this.getClean(); - notation.replace(/\[([^\]]+)\]|\.([^.[]+)|[^[.]+/g, function(match){ - if (!source) return null; - var prop = arguments[2] || arguments[1] || arguments[0]; - source = (prop in source) ? source[prop] : null; - return match; - }); - return source; + decimal: '.', + group: ',', + +/* Commented properties are the defaults for Number.format + decimals: 0, + precision: 0, + scientific: null, + + prefix: null, + suffic: null, + + // Negative/Currency/percentage will mixin Number + negative: { + prefix: '-' + },*/ + + currency: { +// decimals: 2, + prefix: '$ ' + }/*, + + percentage: { + decimals: 2, + suffix: '%' + }*/ + +}); + + + + +/* +--- +name: Number.Format +description: Extends the Number Type object to include a number formatting method. +license: MIT-style license +authors: [Arian Stolwijk] +requires: [Core/Number, Locale.en-US.Number] +# Number.Extras is for compatibility +provides: [Number.Format, Number.Extras] +... +*/ + + +Number.implement({ + + format: function(options){ + // Thanks dojo and YUI for some inspiration + var value = this; + options = options ? Object.clone(options) : {}; + var getOption = function(key){ + if (options[key] != null) return options[key]; + return Locale.get('Number.' + key); + }; + + var negative = value < 0, + decimal = getOption('decimal'), + precision = getOption('precision'), + group = getOption('group'), + decimals = getOption('decimals'); + + if (negative){ + var negativeLocale = getOption('negative') || {}; + if (negativeLocale.prefix == null && negativeLocale.suffix == null) negativeLocale.prefix = '-'; + ['prefix', 'suffix'].each(function(key){ + if (negativeLocale[key]) options[key] = getOption(key) + negativeLocale[key]; + }); + + value = -value; + } + + var prefix = getOption('prefix'), + suffix = getOption('suffix'); + + if (decimals !== '' && decimals >= 0 && decimals <= 20) value = value.toFixed(decimals); + if (precision >= 1 && precision <= 21) value = (+value).toPrecision(precision); + + value += ''; + var index; + if (getOption('scientific') === false && value.indexOf('e') > -1){ + var match = value.split('e'), + zeros = +match[1]; + value = match[0].replace('.', ''); + + if (zeros < 0){ + zeros = -zeros - 1; + index = match[0].indexOf('.'); + if (index > -1) zeros -= index - 1; + while (zeros--) value = '0' + value; + value = '0.' + value; + } else { + index = match[0].lastIndexOf('.'); + if (index > -1) zeros -= match[0].length - index - 1; + while (zeros--) value += '0'; + } + } + + if (decimal != '.') value = value.replace('.', decimal); + + if (group){ + index = value.lastIndexOf(decimal); + index = (index > -1) ? index : value.length; + var newOutput = value.substring(index), + i = index; + + while (i--){ + if ((index - i - 1) % 3 == 0 && i != (index - 1)) newOutput = group + newOutput; + newOutput = value.charAt(i) + newOutput; + } + + value = newOutput; + } + + if (prefix) value = prefix + value; + if (suffix) value += suffix; + + return value; }, - cleanValues: function(method){ - method = method || $defined; - this.each(function(v, k){ - if (!method(v)) this.erase(k); - }, this); - return this; + formatCurrency: function(){ + var locale = Locale.get('Number.currency') || {}; + if (locale.scientific == null) locale.scientific = false; + if (locale.decimals == null) locale.decimals = 2; + + return this.format(locale); }, - run: function(){ - var args = arguments; - this.each(function(v, k){ - if ($type(v) == 'function') v.run(args); - }); + formatPercentage: function(){ + var locale = Locale.get('Number.percentage') || {}; + if (locale.suffix == null) locale.suffix = '%'; + if (locale.decimals == null) locale.decimals = 2; + + return this.format(locale); } }); + /* --- @@ -1138,8 +1354,8 @@ authors: requires: - Core/String - - Core/$util - Core/Array + - MooTools.More provides: [String.Extras] @@ -1149,74 +1365,70 @@ provides: [String.Extras] (function(){ var special = { - 'a': '[àáâãäåăą]', - 'A': '[ÀÃÂÃÄÅĂĄ]', - 'c': '[ćÄç]', - 'C': '[ĆČÇ]', - 'd': '[ÄÄ‘]', - 'D': '[ÄŽÃ]', - 'e': '[èéêëěę]', - 'E': '[ÈÉÊËĚĘ]', - 'g': '[ÄŸ]', - 'G': '[Äž]', - 'i': '[ìíîï]', - 'I': '[ÃŒÃÃŽÃ]', - 'l': '[ĺľł]', - 'L': '[ĹĽÅ]', - 'n': '[ñňń]', - 'N': '[ÑŇŃ]', - 'o': '[òóôõöøő]', - 'O': '[ÒÓÔÕÖØ]', - 'r': '[řŕ]', - 'R': '[ŘŔ]', - 's': '[Å¡Å¡ÅŸ]', - 'S': '[ŠŞŚ]', - 't': '[ťţ]', - 'T': '[ŤŢ]', - 'ue': '[ü]', - 'UE': '[Ãœ]', - 'u': '[ùúûůµ]', - 'U': '[ÙÚÛŮ]', - 'y': '[ÿý]', - 'Y': '[ŸÃ]', - 'z': '[žźż]', - 'Z': '[ŽŹŻ]', - 'th': '[þ]', - 'TH': '[Þ]', - 'dh': '[ð]', - 'DH': '[Ã]', - 'ss': '[ß]', - 'oe': '[Å“]', - 'OE': '[Å’]', - 'ae': '[æ]', - 'AE': '[Æ]' + 'a': /[àáâãäåăą]/g, + 'A': /[ÀÃÂÃÄÅĂĄ]/g, + 'c': /[ćÄç]/g, + 'C': /[ĆČÇ]/g, + 'd': /[ÄÄ‘]/g, + 'D': /[ÄŽÃ]/g, + 'e': /[èéêëěę]/g, + 'E': /[ÈÉÊËĚĘ]/g, + 'g': /[ÄŸ]/g, + 'G': /[Äž]/g, + 'i': /[ìíîï]/g, + 'I': /[ÃŒÃÃŽÃ]/g, + 'l': /[ĺľł]/g, + 'L': /[ĹĽÅ]/g, + 'n': /[ñňń]/g, + 'N': /[ÑŇŃ]/g, + 'o': /[òóôõöøő]/g, + 'O': /[ÒÓÔÕÖØ]/g, + 'r': /[řŕ]/g, + 'R': /[ŘŔ]/g, + 's': /[Å¡Å¡ÅŸ]/g, + 'S': /[ŠŞŚ]/g, + 't': /[ťţ]/g, + 'T': /[ŤŢ]/g, + 'ue': /[ü]/g, + 'UE': /[Ãœ]/g, + 'u': /[ùúûůµ]/g, + 'U': /[ÙÚÛŮ]/g, + 'y': /[ÿý]/g, + 'Y': /[ŸÃ]/g, + 'z': /[žźż]/g, + 'Z': /[ŽŹŻ]/g, + 'th': /[þ]/g, + 'TH': /[Þ]/g, + 'dh': /[ð]/g, + 'DH': /[Ã]/g, + 'ss': /[ß]/g, + 'oe': /[Å“]/g, + 'OE': /[Å’]/g, + 'ae': /[æ]/g, + 'AE': /[Æ]/g }, tidy = { - ' ': '[\xa0\u2002\u2003\u2009]', - '*': '[\xb7]', - '\'': '[\u2018\u2019]', - '"': '[\u201c\u201d]', - '...': '[\u2026]', - '-': '[\u2013]', - '--': '[\u2014]', - '»': '[\uFFFD]' + ' ': /[\xa0\u2002\u2003\u2009]/g, + '*': /[\xb7]/g, + '\'': /[\u2018\u2019]/g, + '"': /[\u201c\u201d]/g, + '...': /[\u2026]/g, + '-': /[\u2013]/g, +// '--': /[\u2014]/g, + '»': /[\uFFFD]/g }; -function walk(string, replacements) { - var result = string; - - for (key in replacements) { - result = result.replace(new RegExp(replacements[key], 'g'), key); - } - +var walk = function(string, replacements){ + var result = string, key; + for (key in replacements) result = result.replace(replacements[key], key); return result; -} +}; -function getRegForTag(tag, contents) { +var getRegexForTag = function(tag, contents){ tag = tag || ''; - var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>"; - reg = new RegExp(regstr, "gi"); + var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>", + reg = new RegExp(regstr, "gi"); return reg; }; @@ -1230,24 +1442,43 @@ String.implement({ return new Array(times + 1).join(this); }, - pad: function(length, str, dir){ + pad: function(length, str, direction){ if (this.length >= length) return this; - var pad = (str == null ? ' ' : '' + str).repeat(length - this.length).substr(0, length - this.length); - if (!dir || dir == 'right') return this + pad; - if (dir == 'left') return pad + this; + + var pad = (str == null ? ' ' : '' + str) + .repeat(length - this.length) + .substr(0, length - this.length); + + if (!direction || direction == 'right') return this + pad; + if (direction == 'left') return pad + this; + return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil()); }, getTags: function(tag, contents){ - return this.match(getRegForTag(tag, contents)) || []; + return this.match(getRegexForTag(tag, contents)) || []; }, stripTags: function(tag, contents){ - return this.replace(getRegForTag(tag, contents), ''); + return this.replace(getRegexForTag(tag, contents), ''); }, tidy: function(){ return walk(this, tidy); + }, + + truncate: function(max, trail, atChar){ + var string = this; + if (trail == null && arguments.length == 1) trail = '…'; + if (string.length > max){ + string = string.substring(0, max); + if (atChar){ + var index = string.lastIndexOf(atChar); + if (index != -1) string = string.substr(0, index); + } + if (trail) string += trail; + } + return string; } }); @@ -1267,7 +1498,10 @@ description: Methods for dealing with URI query strings. license: MIT-style license authors: - - Sebastian MarkbÃ¥ge, Aaron Newton, Lennart Pilon, Valerio Proietti + - Sebastian MarkbÃ¥ge + - Aaron Newton + - Lennart Pilon + - Valerio Proietti requires: - Core/Array @@ -1284,37 +1518,44 @@ String.implement({ parseQueryString: function(decodeKeys, decodeValues){ if (decodeKeys == null) decodeKeys = true; if (decodeValues == null) decodeValues = true; - var vars = this.split(/[&;]/), res = {}; - if (vars.length) vars.each(function(val){ - var index = val.indexOf('='), - keys = index < 0 ? [''] : val.substr(0, index).match(/([^\]\[]+|(\B)(?=\]))/g), - value = decodeValues ? decodeURIComponent(val.substr(index + 1)) : val.substr(index + 1), - obj = res; + + var vars = this.split(/[&;]/), + object = {}; + if (!vars.length) return object; + + vars.each(function(val){ + var index = val.indexOf('=') + 1, + value = index ? val.substr(index) : '', + keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val], + obj = object; + if (!keys) return; + if (decodeValues) value = decodeURIComponent(value); keys.each(function(key, i){ if (decodeKeys) key = decodeURIComponent(key); var current = obj[key]; - if(i < keys.length - 1) - obj = obj[key] = current || {}; - else if($type(current) == 'array') - current.push(value); - else - obj[key] = $defined(current) ? [current, value] : value; + + if (i < keys.length - 1) obj = obj[key] = current || {}; + else if (typeOf(current) == 'array') current.push(value); + else obj[key] = current != null ? [current, value] : value; }); }); - return res; + + return object; }, cleanQueryString: function(method){ return this.split('&').filter(function(val){ var index = val.indexOf('='), - key = index < 0 ? '' : val.substr(0, index), - value = val.substr(index + 1); - return method ? method.run([key, value]) : $chk(value); + key = index < 0 ? '' : val.substr(0, index), + value = val.substr(index + 1); + + return method ? method.call(null, key, value) : (value || value === 0); }).join('&'); } }); + /* --- @@ -1331,7 +1572,10 @@ authors: - Aaron Newton requires: - - Core/Selectors + - Core/Object + - Core/Class + - Core/Class.Extras + - Core/Element - /String.QueryString provides: [URI] @@ -1339,7 +1583,13 @@ provides: [URI] ... */ -var URI = new Class({ +(function(){ + +var toString = function(){ + return this.get('value'); +}; + +var URI = this.URI = new Class({ Implements: Options, @@ -1354,9 +1604,9 @@ var URI = new Class({ initialize: function(uri, options){ this.setOptions(options); var base = this.options.base || URI.base; - if(!uri) uri = base; - - if (uri && uri.parsed) this.parsed = $unlink(uri.parsed); + if (!uri) uri = base; + + if (uri && uri.parsed) this.parsed = Object.clone(uri.parsed); else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false); }, @@ -1381,7 +1631,7 @@ var URI = new Class({ return bits; }, - parseDirectory: function(directory, baseDirectory) { + parseDirectory: function(directory, baseDirectory){ directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory; if (!directory.test(URI.regs.directoryDot)) return directory; var result = []; @@ -1405,9 +1655,9 @@ var URI = new Class({ if (part == 'value'){ var scheme = value.match(URI.regs.scheme); if (scheme) scheme = scheme[1]; - if (scheme && !$defined(this.schemes[scheme.toLowerCase()])) this.parsed = { scheme: scheme, value: value }; + if (scheme && this.schemes[scheme.toLowerCase()] == null) this.parsed = { scheme: scheme, value: value }; else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value }); - } else if (part == 'data') { + } else if (part == 'data'){ this.setData(value); } else { this.parsed[part] = value; @@ -1416,7 +1666,7 @@ var URI = new Class({ }, get: function(part, base){ - switch(part){ + switch (part){ case 'value': return this.combine(this.parsed, base ? base.parsed : false); case 'data' : return this.getData(); } @@ -1433,39 +1683,38 @@ var URI = new Class({ getData: function(key, part){ var qs = this.get(part || 'query'); - if (!$chk(qs)) return key ? null : {}; + if (!(qs || qs === 0)) return key ? null : {}; var obj = qs.parseQueryString(); return key ? obj[key] : obj; }, setData: function(values, merge, part){ if (typeof values == 'string'){ - data = this.getData(); + var data = this.getData(); data[arguments[0]] = arguments[1]; values = data; - } else if (merge) { - values = $merge(this.getData(), values); + } else if (merge){ + values = Object.merge(this.getData(), values); } - return this.set(part || 'query', Hash.toQueryString(values)); + return this.set(part || 'query', Object.toQueryString(values)); }, clearData: function(part){ return this.set(part || 'query', ''); - } + }, + + toString: toString, + valueOf: toString }); -URI.prototype.toString = URI.prototype.valueOf = function(){ - return this.get('value'); -}; - URI.regs = { endSlash: /\/$/, scheme: /^(\w+):/, directoryDot: /\.\/|\.$/ }; -URI.base = new URI(document.getElements('base[href]', true).getLast(), {base: document.location}); +URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location}); String.implement({ @@ -1475,6 +1724,51 @@ String.implement({ }); +})(); + + +/* +--- + +script: Class.Refactor.js + +name: Class.Refactor + +description: Extends a class onto itself with new property, preserving any items attached to the class's namespace. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Class + - /MooTools.More + +# Some modules declare themselves dependent on Class.Refactor +provides: [Class.refactor, Class.Refactor] + +... +*/ + +Class.refactor = function(original, refactors){ + + Object.each(refactors, function(item, name){ + var origin = original.prototype[name]; + origin = (origin && origin.$origin) || origin || function(){}; + original.implement(name, (typeof item == 'function') ? function(){ + var old = this.previous; + this.previous = origin; + var value = item.apply(this, arguments); + this.previous = old; + return value; + } : item); + }); + + return original; + +}; + /* --- @@ -1515,9 +1809,9 @@ URI = Class.refactor(URI, { offset; var i = 0; - for(offset = 0; offset < baseDir.length && offset < relDir.length && baseDir[offset] == relDir[offset]; offset++); - for(i = 0; i < baseDir.length - offset - 1; i++) path += '../'; - for(i = offset; i < relDir.length - 1; i++) path += relDir[i] + '/'; + for (offset = 0; offset < baseDir.length && offset < relDir.length && baseDir[offset] == relDir[offset]; offset++); + for (i = 0; i < baseDir.length - offset - 1; i++) path += '../'; + for (i = offset; i < relDir.length - 1; i++) path += relDir[i] + '/'; return (path || (bits.file ? '' : './')) + end; }, @@ -1535,6 +1829,193 @@ URI = Class.refactor(URI, { }); +/* +--- + +name: Hash + +description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. + +license: MIT-style license. + +requires: + - Core/Object + - /MooTools.More + +provides: [Hash] + +... +*/ + +(function(){ + +if (this.Hash) return; + +var Hash = this.Hash = new Type('Hash', function(object){ + if (typeOf(object) == 'hash') object = Object.clone(object.getClean()); + for (var key in object) this[key] = object[key]; + return this; +}); + +this.$H = function(object){ + return new Hash(object); +}; + +Hash.implement({ + + forEach: function(fn, bind){ + Object.forEach(this, fn, bind); + }, + + getClean: function(){ + var clean = {}; + for (var key in this){ + if (this.hasOwnProperty(key)) clean[key] = this[key]; + } + return clean; + }, + + getLength: function(){ + var length = 0; + for (var key in this){ + if (this.hasOwnProperty(key)) length++; + } + return length; + } + +}); + +Hash.alias('each', 'forEach'); + +Hash.implement({ + + has: Object.prototype.hasOwnProperty, + + keyOf: function(value){ + return Object.keyOf(this, value); + }, + + hasValue: function(value){ + return Object.contains(this, value); + }, + + extend: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.set(this, key, value); + }, this); + return this; + }, + + combine: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.include(this, key, value); + }, this); + return this; + }, + + erase: function(key){ + if (this.hasOwnProperty(key)) delete this[key]; + return this; + }, + + get: function(key){ + return (this.hasOwnProperty(key)) ? this[key] : null; + }, + + set: function(key, value){ + if (!this[key] || this.hasOwnProperty(key)) this[key] = value; + return this; + }, + + empty: function(){ + Hash.each(this, function(value, key){ + delete this[key]; + }, this); + return this; + }, + + include: function(key, value){ + if (this[key] == undefined) this[key] = value; + return this; + }, + + map: function(fn, bind){ + return new Hash(Object.map(this, fn, bind)); + }, + + filter: function(fn, bind){ + return new Hash(Object.filter(this, fn, bind)); + }, + + every: function(fn, bind){ + return Object.every(this, fn, bind); + }, + + some: function(fn, bind){ + return Object.some(this, fn, bind); + }, + + getKeys: function(){ + return Object.keys(this); + }, + + getValues: function(){ + return Object.values(this); + }, + + toQueryString: function(base){ + return Object.toQueryString(this, base); + } + +}); + +Hash.alias({indexOf: 'keyOf', contains: 'hasValue'}); + + +})(); + + + +/* +--- + +script: Hash.Extras.js + +name: Hash.Extras + +description: Extends the Hash Type to include getFromPath which allows a path notation to child elements. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - /Hash + - /Object.Extras + +provides: [Hash.Extras] + +... +*/ + +Hash.implement({ + + getFromPath: function(notation){ + return Object.getFromPath(this, notation); + }, + + cleanValues: function(method){ + return new Hash(Object.cleanValues(this, method)); + }, + + run: function(){ + Object.run(arguments); + } + +}); + + /* --- @@ -1551,6 +2032,7 @@ authors: requires: - Core/Element + - /String.Extras - /MooTools.More provides: [Element.Forms] @@ -1573,24 +2055,34 @@ Element.implement({ return document.selection.createRange().text; }, - getSelectedRange: function() { - if ($defined(this.selectionStart)) return {start: this.selectionStart, end: this.selectionEnd}; - var pos = {start: 0, end: 0}; + getSelectedRange: function(){ + if (this.selectionStart != null){ + return { + start: this.selectionStart, + end: this.selectionEnd + }; + } + + var pos = { + start: 0, + end: 0 + }; var range = this.getDocument().selection.createRange(); if (!range || range.parentElement() != this) return pos; - var dup = range.duplicate(); - if (this.type == 'text') { - pos.start = 0 - dup.moveStart('character', -100000); + var duplicate = range.duplicate(); + + if (this.type == 'text'){ + pos.start = 0 - duplicate.moveStart('character', -100000); pos.end = pos.start + range.text.length; } else { var value = this.get('value'); var offset = value.length; - dup.moveToElementText(this); - dup.setEndPoint('StartToEnd', range); - if(dup.text.length) offset -= value.match(/[\n\r]*$/)[0].length; - pos.end = offset - dup.text.length; - dup.setEndPoint('StartToStart', range); - pos.start = offset - dup.text.length; + duplicate.moveToElementText(this); + duplicate.setEndPoint('StartToEnd', range); + if (duplicate.text.length) offset -= value.match(/[\n\r]*$/)[0].length; + pos.end = offset - duplicate.text.length; + duplicate.setEndPoint('StartToStart', range); + pos.start = offset - duplicate.text.length; } return pos; }, @@ -1614,7 +2106,7 @@ Element.implement({ }, selectRange: function(start, end){ - if (this.setSelectionRange) { + if (this.setSelectionRange){ this.focus(); this.setSelectionRange(start, end); } else { @@ -1634,20 +2126,22 @@ Element.implement({ var pos = this.getSelectedRange(); var text = this.get('value'); this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length)); - if ($pick(select, true)) this.selectRange(pos.start, pos.start + value.length); + if (select !== false) this.selectRange(pos.start, pos.start + value.length); else this.setCaretPosition(pos.start + value.length); return this; }, insertAroundCursor: function(options, select){ - options = $extend({ + options = Object.append({ before: '', defaultMiddle: '', after: '' }, options); + var value = this.getSelectedText() || options.defaultMiddle; var pos = this.getSelectedRange(); var text = this.get('value'); + if (pos.start == pos.end){ this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length)); this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length); @@ -1655,7 +2149,7 @@ Element.implement({ var current = text.substring(pos.start, pos.end); this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length)); var selStart = pos.start + options.before.length; - if ($pick(select, true)) this.selectRange(selStart, selStart + current.length); + if (select !== false) this.selectRange(selStart, selStart + current.length); else this.setCaretPosition(selStart + text.length); } return this; @@ -1663,6 +2157,7 @@ Element.implement({ }); + /* --- @@ -1678,6 +2173,7 @@ authors: - Aaron Newton requires: + - Core/String - Core/Element - /MooTools.More @@ -1687,7 +2183,7 @@ provides: [Elements.from, Elements.From] */ Elements.from = function(text, excludeScripts){ - if ($pick(excludeScripts, true)) text = text.stripScripts(); + if (excludeScripts || excludeScripts == null) text = text.stripScripts(); var container, match = text.match(/^\s*<(t[dhr]|tbody|tfoot|thead)/i); @@ -1707,275 +2203,307 @@ Elements.from = function(text, excludeScripts){ /* --- -script: Element.Delegation.js +name: Events.Pseudos -name: Element.Delegation - -description: Extends the Element native object to include the delegate method for more efficient event management. - -credits: - - "Event checking based on the work of Daniel Steigerwald. License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" +description: Adds the functionality to add pseudo events license: MIT-style license authors: - - Aaron Newton - - Daniel Steigerwald + - Arian Stolwijk -requires: - - Core/Element.Event - - Core/Selectors - - /MooTools.More +requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More] -provides: [Element.Delegation] +provides: [Events.Pseudos] ... */ -(function(addEvent, removeEvent){ - - var match = /(.*?):relay\(((?:\(.*?\)|.)+)\)$/, - combinators = /[+>~\s]/, - splitType = function(type){ - var bits = type.match(match); - return !bits ? {event: type} : { - event: bits[1], - selector: bits[2] - }; - }, - check = function(e, selector){ - var t = e.target; - if (combinators.test(selector = selector.trim())){ - var els = this.getElements(selector); - for (var i = els.length; i--; ){ - var el = els[i]; - if (t == el || el.hasChild(t)) return el; - } - } else { - for ( ; t && t != this; t = t.parentNode){ - if (Element.match(t, selector)) return document.id(t); - } +Events.Pseudos = function(pseudos, addEvent, removeEvent){ + + var storeKey = 'monitorEvents:'; + + var storageOf = function(object){ + return { + store: object.store ? function(key, value){ + object.store(storeKey + key, value); + } : function(key, value){ + (object.$monitorEvents || (object.$monitorEvents = {}))[key] = value; + }, + retrieve: object.retrieve ? function(key, dflt){ + return object.retrieve(storeKey + key, dflt); + } : function(key, dflt){ + if (!object.$monitorEvents) return dflt; + return object.$monitorEvents[key] || dflt; } - return null; }; + }; - Element.implement({ + var splitType = function(type){ + if (type.indexOf(':') == -1 || !pseudos) return null; - addEvent: function(type, fn){ + var parsed = Slick.parse(type).expressions[0][0], + parsedPseudos = parsed.pseudos, + l = parsedPseudos.length, + splits = []; + + while (l--) if (pseudos[parsedPseudos[l].key]){ + splits.push({ + event: parsed.tag, + value: parsedPseudos[l].value, + pseudo: parsedPseudos[l].key, + original: type + }); + } + + return splits.length ? splits : null; + }; + + var mergePseudoOptions = function(split){ + return Object.merge.apply(this, split.map(function(item){ + return pseudos[item.pseudo].options || {}; + })); + }; + + return { + + addEvent: function(type, fn, internal){ var split = splitType(type); - if (split.selector){ - var monitors = this.retrieve('delegation:_delegateMonitors', {}); - if (!monitors[type]){ - var monitor = function(e){ - var el = check.call(this, e, split.selector); - if (el) this.fireEvent(type, [e, el], 0, el); - }.bind(this); - monitors[type] = monitor; - addEvent.call(this, split.event, monitor); - } - } - return addEvent.apply(this, arguments); + if (!split) return addEvent.call(this, type, fn, internal); + + var storage = storageOf(this), + events = storage.retrieve(type, []), + eventType = split[0].event, + options = mergePseudoOptions(split), + stack = fn, + eventOptions = options[eventType] || {}, + args = Array.slice(arguments, 2), + self = this, + monitor; + + if (eventOptions.args) args.append(Array.from(eventOptions.args)); + if (eventOptions.base) eventType = eventOptions.base; + if (eventOptions.onAdd) eventOptions.onAdd(this); + + split.each(function(item){ + var stackFn = stack; + stack = function(){ + (eventOptions.listener || pseudos[item.pseudo].listener).call(self, item, stackFn, arguments, monitor, options); + }; + }); + monitor = stack.bind(this); + + events.include({event: fn, monitor: monitor}); + storage.store(type, events); + + addEvent.apply(this, [type, fn].concat(args)); + return addEvent.apply(this, [eventType, monitor].concat(args)); }, removeEvent: function(type, fn){ var split = splitType(type); - if (split.selector){ - var events = this.retrieve('events'); - if (!events || !events[type] || (fn && !events[type].keys.contains(fn))) return this; + if (!split) return removeEvent.call(this, type, fn); - if (fn) removeEvent.apply(this, [type, fn]); - else removeEvent.apply(this, type); + var storage = storageOf(this), + events = storage.retrieve(type); + if (!events) return this; - events = this.retrieve('events'); - if (events && events[type] && events[type].keys.length == 0){ - var monitors = this.retrieve('delegation:_delegateMonitors', {}); - removeEvent.apply(this, [split.event, monitors[type]]); - delete monitors[type]; - } - return this; - } - return removeEvent.apply(this, arguments); - }, + var eventType = split[0].event, + options = mergePseudoOptions(split), + eventOptions = options[eventType] || {}, + args = Array.slice(arguments, 2); - fireEvent: function(type, args, delay, bind){ - var events = this.retrieve('events'); - var e, el; - if (args) { - e = args[0]; - el = args[1]; - } - if (!events || !events[type]) return this; - events[type].keys.each(function(fn){ - fn.create({bind: bind || this, delay: delay, arguments: args})(); + if (eventOptions.args) args.append(Array.from(eventOptions.args)); + if (eventOptions.base) eventType = eventOptions.base; + if (eventOptions.onRemove) eventOptions.onRemove(this); + + removeEvent.apply(this, [type, fn].concat(args)); + events.each(function(monitor, i){ + if (!fn || monitor.event == fn) removeEvent.apply(this, [eventType, monitor.monitor].concat(args)); + delete events[i]; }, this); + + storage.store(type, events); return this; } - }); + }; -})(Element.prototype.addEvent, Element.prototype.removeEvent); +}; -try { - if (typeof HTMLElement != 'undefined') - HTMLElement.prototype.fireEvent = Element.prototype.fireEvent; -} catch(e){} +(function(){ + +var pseudos = { + + once: { + listener: function(split, fn, args, monitor){ + fn.apply(this, args); + this.removeEvent(split.event, monitor) + .removeEvent(split.original, fn); + } + }, + + throttle: { + listener: function(split, fn, args){ + if (!fn._throttled){ + fn.apply(this, args); + fn._throttled = setTimeout(function(){ + fn._throttled = false; + }, split.value || 250); + } + } + }, + + pause: { + listener: function(split, fn, args){ + clearTimeout(fn._pause); + fn._pause = fn.delay(split.value || 250, this, args); + } + } + +}; + +Events.definePseudo = function(key, listener){ + pseudos[key] = Type.isFunction(listener) ? {listener: listener} : listener; + return this; +}; + +Events.lookupPseudo = function(key){ + return pseudos[key]; +}; + +var proto = Events.prototype; +Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent)); + +['Request', 'Fx'].each(function(klass){ + if (this[klass]) this[klass].implement(Events.prototype); +}); + +})(); /* --- -script: Element.Measure.js +name: Element.Event.Pseudos -name: Element.Measure - -description: Extends the Element native object to include methods useful in measuring dimensions. - -credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" +description: Adds the functionality to add pseudo events for Elements license: MIT-style license authors: - - Aaron Newton + - Arian Stolwijk -requires: - - Core/Element.Style - - Core/Element.Dimensions - - /MooTools.More +requires: [Core/Element.Event, Events.Pseudos] -provides: [Element.Measure] +provides: [Element.Event.Pseudos] ... */ -Element.implement({ +(function(){ - measure: function(fn){ - var vis = function(el) { - return !!(!el || el.offsetHeight || el.offsetWidth); +var pseudos = {}, + copyFromEvents = ['once', 'throttle', 'pause'], + count = copyFromEvents.length; + +while (count--) pseudos[copyFromEvents[count]] = Events.lookupPseudo(copyFromEvents[count]); + +Event.definePseudo = function(key, listener){ + pseudos[key] = Type.isFunction(listener) ? {listener: listener} : listener; + return this; +}; + +var proto = Element.prototype; +[Element, Window, Document].invoke('implement', Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent)); + +})(); + + +/* +--- + +name: Element.Event.Pseudos.Keys + +description: Adds functionality fire events if certain keycombinations are pressed + +license: MIT-style license + +authors: + - Arian Stolwijk + +requires: [Element.Event.Pseudos] + +provides: [Element.Event.Pseudos.Keys] + +... +*/ + +(function(){ + +var keysStoreKey = '$moo:keys-pressed', + keysKeyupStoreKey = '$moo:keys-keyup'; + + +Event.definePseudo('keys', function(split, fn, args){ + + var event = args[0], + keys = [], + pressed = this.retrieve(keysStoreKey, []); + + keys.append(split.value.replace('++', function(){ + keys.push('+'); // shift++ and shift+++a + return ''; + }).split('+')); + + pressed.include(event.key); + + if (keys.every(function(key){ + return pressed.contains(key); + })) fn.apply(this, args); + + this.store(keysStoreKey, pressed); + + if (!this.retrieve(keysKeyupStoreKey)){ + var keyup = function(event){ + (function(){ + pressed = this.retrieve(keysStoreKey, []).erase(event.key); + this.store(keysStoreKey, pressed); + }).delay(0, this); // Fix for IE }; - if (vis(this)) return fn.apply(this); - var parent = this.getParent(), - restorers = [], - toMeasure = []; - while (!vis(parent) && parent != document.body) { - toMeasure.push(parent.expose()); - parent = parent.getParent(); - } - var restore = this.expose(); - var result = fn.apply(this); - restore(); - toMeasure.each(function(restore){ - restore(); - }); - return result; - }, - - expose: function(){ - if (this.getStyle('display') != 'none') return $empty; - var before = this.style.cssText; - this.setStyles({ - display: 'block', - position: 'absolute', - visibility: 'hidden' - }); - return function(){ - this.style.cssText = before; - }.bind(this); - }, - - getDimensions: function(options){ - options = $merge({computeSize: false},options); - var dim = {}; - var getSize = function(el, options){ - return (options.computeSize)?el.getComputedSize(options):el.getSize(); - }; - var parent = this.getParent('body'); - if (parent && this.getStyle('display') == 'none'){ - dim = this.measure(function(){ - return getSize(this, options); - }); - } else if (parent){ - try { //safari sometimes crashes here, so catch it - dim = getSize(this, options); - }catch(e){} - } else { - dim = {x: 0, y: 0}; - } - return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim, {x: dim.width, y: dim.height}); - }, - - getComputedSize: function(options){ - //legacy support for my stupid spelling error - if (options && options.plains) options.planes = options.plains; - - options = $merge({ - styles: ['padding','border'], - planes: { - height: ['top','bottom'], - width: ['left','right'] - }, - mode: 'both' - }, options); - - var size = {width: 0,height: 0}; - switch (options.mode){ - case 'vertical': - delete size.width; - delete options.planes.width; - break; - case 'horizontal': - delete size.height; - delete options.planes.height; - break; - } - var getStyles = []; - //this function might be useful in other places; perhaps it should be outside this function? - $each(options.planes, function(plane, key){ - plane.each(function(edge){ - options.styles.each(function(style){ - getStyles.push((style == 'border') ? style + '-' + edge + '-' + 'width' : style + '-' + edge); - }); - }); - }); - var styles = {}; - getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); }, this); - var subtracted = []; - $each(options.planes, function(plane, key){ //keys: width, height, planes: ['left', 'right'], ['top','bottom'] - var capitalized = key.capitalize(); - size['total' + capitalized] = size['computed' + capitalized] = 0; - plane.each(function(edge){ //top, left, right, bottom - size['computed' + edge.capitalize()] = 0; - getStyles.each(function(style, i){ //padding, border, etc. - //'padding-left'.test('left') size['totalWidth'] = size['width'] + [padding-left] - if (style.test(edge)){ - styles[style] = styles[style].toInt() || 0; //styles['padding-left'] = 5; - size['total' + capitalized] = size['total' + capitalized] + styles[style]; - size['computed' + edge.capitalize()] = size['computed' + edge.capitalize()] + styles[style]; - } - //if width != width (so, padding-left, for instance), then subtract that from the total - if (style.test(edge) && key != style && - (style.test('border') || style.test('padding')) && !subtracted.contains(style)){ - subtracted.push(style); - size['computed' + capitalized] = size['computed' + capitalized]-styles[style]; - } - }); - }); - }); - - ['Width', 'Height'].each(function(value){ - var lower = value.toLowerCase(); - if(!$chk(size[lower])) return; - - size[lower] = size[lower] + this['offset' + value] + size['computed' + value]; - size['total' + value] = size[lower] + size['total' + value]; - delete size['computed' + value]; - }, this); - - return $extend(styles, size); + this.store(keysKeyupStoreKey, keyup).addEvent('keyup', keyup); } }); +Object.append(Event.Keys, { + 'shift': 16, + 'control': 17, + 'alt': 18, + 'capslock': 20, + 'pageup': 33, + 'pagedown': 34, + 'end': 35, + 'home': 36, + 'numlock': 144, + 'scrolllock': 145, + ';': 186, + '=': 187, + ',': 188, + '-': Browser.firefox ? 109 : 189, + '.': 190, + '/': 191, + '`': 192, + '[': 219, + '\\': 220, + ']': 221, + "'": 222, + '+': 107 +}); + +})(); + + /* --- @@ -2014,7 +2542,7 @@ provides: [Element.Pin] supportsPositionFixed = (test.offsetTop === 0); test.dispose(); supportTested = true; - } + }; Element.implement({ @@ -2023,7 +2551,9 @@ provides: [Element.Pin] if (this.getStyle('display') == 'none') return this; var pinnedPosition, - scroll = window.getScroll(); + scroll = window.getScroll(), + parent, + scrollFixer; if (enable !== false){ pinnedPosition = this.getPosition(supportsPositionFixed ? document.body : this.getOffsetParent()); @@ -2037,8 +2567,8 @@ provides: [Element.Pin] this.setStyle('position', 'fixed').setStyles(currentPosition); } else { - var parent = this.getOffsetParent(), - position = this.getPosition(parent), + parent = this.getOffsetParent(); + var position = this.getPosition(parent), styles = this.getStyles('left', 'top'); if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position); @@ -2049,7 +2579,7 @@ provides: [Element.Pin] y: styles.top.toInt() - scroll.y }; - var scrollFixer = function(){ + scrollFixer = function(){ if (!this.retrieve('pin:_pinned')) return; var scroll = window.getScroll(); this.setStyles({ @@ -2067,13 +2597,13 @@ provides: [Element.Pin] } else { if (!this.retrieve('pin:_pinned')) return this; - var parent = this.getParent(), - offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent()); + parent = this.getParent(); + var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent()); pinnedPosition = this.getPosition(offsetParent); this.store('pin:_pinned', false); - var scrollFixer = this.retrieve('pin:_scrollFixer'); + scrollFixer = this.retrieve('pin:_scrollFixer'); if (!scrollFixer){ this.setStyles({ position: 'absolute', @@ -2093,12 +2623,183 @@ provides: [Element.Pin] return this.pin(false); }, - togglepin: function(){ + togglePin: function(){ return this.pin(!this.retrieve('pin:_pinned')); } }); + + +})(); + + +/* +--- + +script: Element.Measure.js + +name: Element.Measure + +description: Extends the Element native object to include methods useful in measuring dimensions. + +credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Element.Style + - Core/Element.Dimensions + - /MooTools.More + +provides: [Element.Measure] + +... +*/ + +(function(){ + +var getStylesList = function(styles, planes){ + var list = []; + Object.each(planes, function(directions){ + Object.each(directions, function(edge){ + styles.each(function(style){ + list.push(style + '-' + edge + (style == 'border' ? '-width' : '')); + }); + }); + }); + return list; +}; + +var calculateEdgeSize = function(edge, styles){ + var total = 0; + Object.each(styles, function(value, style){ + if (style.test(edge)) total = total + value.toInt(); + }); + return total; +}; + +var isVisible = function(el){ + return !!(!el || el.offsetHeight || el.offsetWidth); +}; + + +Element.implement({ + + measure: function(fn){ + if (isVisible(this)) return fn.call(this); + var parent = this.getParent(), + toMeasure = []; + while (!isVisible(parent) && parent != document.body){ + toMeasure.push(parent.expose()); + parent = parent.getParent(); + } + var restore = this.expose(), + result = fn.call(this); + restore(); + toMeasure.each(function(restore){ + restore(); + }); + return result; + }, + + expose: function(){ + if (this.getStyle('display') != 'none') return function(){}; + var before = this.style.cssText; + this.setStyles({ + display: 'block', + position: 'absolute', + visibility: 'hidden' + }); + return function(){ + this.style.cssText = before; + }.bind(this); + }, + + getDimensions: function(options){ + options = Object.merge({computeSize: false}, options); + var dim = {x: 0, y: 0}; + + var getSize = function(el, options){ + return (options.computeSize) ? el.getComputedSize(options) : el.getSize(); + }; + + var parent = this.getParent('body'); + + if (parent && this.getStyle('display') == 'none'){ + dim = this.measure(function(){ + return getSize(this, options); + }); + } else if (parent){ + try { //safari sometimes crashes here, so catch it + dim = getSize(this, options); + }catch(e){} + } + + return Object.append(dim, (dim.x || dim.x === 0) ? { + width: dim.x, + height: dim.y + } : { + x: dim.width, + y: dim.height + } + ); + }, + + getComputedSize: function(options){ + + + options = Object.merge({ + styles: ['padding','border'], + planes: { + height: ['top','bottom'], + width: ['left','right'] + }, + mode: 'both' + }, options); + + var styles = {}, + size = {width: 0, height: 0}, + dimensions; + + if (options.mode == 'vertical'){ + delete size.width; + delete options.planes.width; + } else if (options.mode == 'horizontal'){ + delete size.height; + delete options.planes.height; + } + + getStylesList(options.styles, options.planes).each(function(style){ + styles[style] = this.getStyle(style).toInt(); + }, this); + + Object.each(options.planes, function(edges, plane){ + + var capitalized = plane.capitalize(), + style = this.getStyle(plane); + + if (style == 'auto' && !dimensions) dimensions = this.getDimensions(); + + style = styles[plane] = (style == 'auto') ? dimensions[plane] : style.toInt(); + size['total' + capitalized] = style; + + edges.each(function(edge){ + var edgesize = calculateEdgeSize(edge, styles); + size['computed' + edge.capitalize()] = edgesize; + size['total' + capitalized] += edgesize; + }); + + }, this); + + return Object.append(size, styles); + } + +}); + })(); @@ -2115,189 +2816,228 @@ license: MIT-style license authors: - Aaron Newton + - Jacob Thornton requires: + - Core/Options - Core/Element.Dimensions - - /Element.Measure + - Element.Measure provides: [Element.Position] ... */ -(function(){ +(function(original){ -var original = Element.prototype.position; +var local = Element.Position = { + + options: {/* + edge: false, + returnPos: false, + minimum: {x: 0, y: 0}, + maximum: {x: 0, y: 0}, + relFixedPosition: false, + ignoreMargins: false, + ignoreScroll: false, + allowNegative: false,*/ + relativeTo: document.body, + position: { + x: 'center', //left, center, right + y: 'center' //top, center, bottom + }, + offset: {x: 0, y: 0} + }, + + getOptions: function(element, options){ + options = Object.merge({}, local.options, options); + local.setPositionOption(options); + local.setEdgeOption(options); + local.setOffsetOption(element, options); + local.setDimensionsOption(element, options); + return options; + }, + + setPositionOption: function(options){ + options.position = local.getCoordinateFromValue(options.position); + }, + + setEdgeOption: function(options){ + var edgeOption = local.getCoordinateFromValue(options.edge); + options.edge = edgeOption ? edgeOption : + (options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} : + {x: 'left', y: 'top'}; + }, + + setOffsetOption: function(element, options){ + var parentOffset = {x: 0, y: 0}, + offsetParent = element.measure(function(){ + return document.id(this.getOffsetParent()); + }), + parentScroll = offsetParent.getScroll(); + + if (!offsetParent || offsetParent == element.getDocument().body) return; + parentOffset = offsetParent.measure(function(){ + var position = this.getPosition(); + if (this.getStyle('position') == 'fixed'){ + var scroll = window.getScroll(); + position.x += scroll.x; + position.y += scroll.y; + } + return position; + }); + + options.offset = { + parentPositioned: offsetParent != document.id(options.relativeTo), + x: options.offset.x - parentOffset.x + parentScroll.x, + y: options.offset.y - parentOffset.y + parentScroll.y + }; + }, + + setDimensionsOption: function(element, options){ + options.dimensions = element.getDimensions({ + computeSize: true, + styles: ['padding', 'border', 'margin'] + }); + }, + + getPosition: function(element, options){ + var position = {}; + options = local.getOptions(element, options); + var relativeTo = document.id(options.relativeTo) || document.body; + + local.setPositionCoordinates(options, position, relativeTo); + if (options.edge) local.toEdge(position, options); + + var offset = options.offset; + position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt(); + position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt(); + + local.toMinMax(position, options); + + if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position); + if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position); + if (options.ignoreMargins) local.toIgnoreMargins(position, options); + + position.left = Math.ceil(position.left); + position.top = Math.ceil(position.top); + delete position.x; + delete position.y; + + return position; + }, + + setPositionCoordinates: function(options, position, relativeTo){ + var offsetY = options.offset.y, + offsetX = options.offset.x, + calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(), + top = calc.y, + left = calc.x, + winSize = window.getSize(); + + switch(options.position.x){ + case 'left': position.x = left + offsetX; break; + case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break; + default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break; + } + + switch(options.position.y){ + case 'top': position.y = top + offsetY; break; + case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break; + default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break; + } + }, + + toMinMax: function(position, options){ + var xy = {left: 'x', top: 'y'}, value; + ['minimum', 'maximum'].each(function(minmax){ + ['left', 'top'].each(function(lr){ + value = options[minmax] ? options[minmax][xy[lr]] : null; + if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value; + }); + }); + }, + + toRelFixedPosition: function(relativeTo, position){ + var winScroll = window.getScroll(); + position.top += winScroll.y; + position.left += winScroll.x; + }, + + toIgnoreScroll: function(relativeTo, position){ + var relScroll = relativeTo.getScroll(); + position.top -= relScroll.y; + position.left -= relScroll.x; + }, + + toIgnoreMargins: function(position, options){ + position.left += options.edge.x == 'right' + ? options.dimensions['margin-right'] + : (options.edge.x != 'center' + ? -options.dimensions['margin-left'] + : -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2)); + + position.top += options.edge.y == 'bottom' + ? options.dimensions['margin-bottom'] + : (options.edge.y != 'center' + ? -options.dimensions['margin-top'] + : -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2)); + }, + + toEdge: function(position, options){ + var edgeOffset = {}, + dimensions = options.dimensions, + edge = options.edge; + + switch(edge.x){ + case 'left': edgeOffset.x = 0; break; + case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break; + // center + default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break; + } + + switch(edge.y){ + case 'top': edgeOffset.y = 0; break; + case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break; + // center + default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break; + } + + position.x += edgeOffset.x; + position.y += edgeOffset.y; + }, + + getCoordinateFromValue: function(option){ + if (typeOf(option) != 'string') return option; + option = option.toLowerCase(); + + return { + x: option.test('left') ? 'left' + : (option.test('right') ? 'right' : 'center'), + y: option.test(/upper|top/) ? 'top' + : (option.test('bottom') ? 'bottom' : 'center') + }; + } + +}; Element.implement({ position: function(options){ - //call original position if the options are x/y values - if (options && ($defined(options.x) || $defined(options.y))) return original ? original.apply(this, arguments) : this; - $each(options||{}, function(v, k){ if (!$defined(v)) delete options[k]; }); - options = $merge({ - // minimum: { x: 0, y: 0 }, - // maximum: { x: 0, y: 0}, - relativeTo: document.body, - position: { - x: 'center', //left, center, right - y: 'center' //top, center, bottom - }, - edge: false, - offset: {x: 0, y: 0}, - returnPos: false, - relFixedPosition: false, - ignoreMargins: false, - ignoreScroll: false, - allowNegative: false - }, options); - //compute the offset of the parent positioned element if this element is in one - var parentOffset = {x: 0, y: 0}, - parentPositioned = false; - /* dollar around getOffsetParent should not be necessary, but as it does not return - * a mootools extended element in IE, an error occurs on the call to expose. See: - * http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getoffsetparent-inconsistency-between-ie-and-other-browsers */ - var offsetParent = this.measure(function(){ - return document.id(this.getOffsetParent()); - }); - if (offsetParent && offsetParent != this.getDocument().body){ - parentOffset = offsetParent.measure(function(){ - return this.getPosition(); - }); - parentPositioned = offsetParent != document.id(options.relativeTo); - options.offset.x = options.offset.x - parentOffset.x; - options.offset.y = options.offset.y - parentOffset.y; - } - //upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft - //topRight, topLeft, centerTop, centerBottom, center - var fixValue = function(option){ - if ($type(option) != 'string') return option; - option = option.toLowerCase(); - var val = {}; - - if (option.test('left')) val.x = 'left'; - else if (option.test('right')) val.x = 'right'; - else val.x = 'center'; - - if (option.test('upper') || option.test('top')) val.y = 'top'; - else if (option.test('bottom')) val.y = 'bottom'; - else val.y = 'center'; - - return val; - }; - options.edge = fixValue(options.edge); - options.position = fixValue(options.position); - if (!options.edge){ - if (options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center', y:'center'}; - else options.edge = {x:'left', y:'top'}; + if (options && (options.x != null || options.y != null)) { + return (original ? original.apply(this, arguments) : this); } + var position = this.setStyle('position', 'absolute').calculatePosition(options); + return (options && options.returnPos) ? position : this.setStyles(position); + }, - this.setStyle('position', 'absolute'); - var rel = document.id(options.relativeTo) || document.body, - calc = rel == document.body ? window.getScroll() : rel.getPosition(), - top = calc.y, left = calc.x; - - var dim = this.getDimensions({computeSize: true, styles:['padding', 'border','margin']}); - var pos = {}, - prefY = options.offset.y, - prefX = options.offset.x, - winSize = window.getSize(); - switch(options.position.x){ - case 'left': - pos.x = left + prefX; - break; - case 'right': - pos.x = left + prefX + rel.offsetWidth; - break; - default: //center - pos.x = left + ((rel == document.body ? winSize.x : rel.offsetWidth)/2) + prefX; - break; - } - switch(options.position.y){ - case 'top': - pos.y = top + prefY; - break; - case 'bottom': - pos.y = top + prefY + rel.offsetHeight; - break; - default: //center - pos.y = top + ((rel == document.body ? winSize.y : rel.offsetHeight)/2) + prefY; - break; - } - if (options.edge){ - var edgeOffset = {}; - - switch(options.edge.x){ - case 'left': - edgeOffset.x = 0; - break; - case 'right': - edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft; - break; - default: //center - edgeOffset.x = -(dim.totalWidth/2); - break; - } - switch(options.edge.y){ - case 'top': - edgeOffset.y = 0; - break; - case 'bottom': - edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom; - break; - default: //center - edgeOffset.y = -(dim.totalHeight/2); - break; - } - pos.x += edgeOffset.x; - pos.y += edgeOffset.y; - } - pos = { - left: ((pos.x >= 0 || parentPositioned || options.allowNegative) ? pos.x : 0).toInt(), - top: ((pos.y >= 0 || parentPositioned || options.allowNegative) ? pos.y : 0).toInt() - }; - var xy = {left: 'x', top: 'y'}; - ['minimum', 'maximum'].each(function(minmax) { - ['left', 'top'].each(function(lr) { - var val = options[minmax] ? options[minmax][xy[lr]] : null; - if (val != null && ((minmax == 'minimum') ? pos[lr] < val: pos[lr] > val)) pos[lr] = val; - }); - }); - if (rel.getStyle('position') == 'fixed' || options.relFixedPosition){ - var winScroll = window.getScroll(); - pos.top+= winScroll.y; - pos.left+= winScroll.x; - } - var relScroll = rel.getScroll(); - if (options.ignoreScroll) { - pos.top -= relScroll.y; - pos.left -= relScroll.x; - } else { - pos.top += relScroll.y; - pos.left += relScroll.x; - } - if (options.ignoreMargins) { - pos.left += ( - options.edge.x == 'right' ? dim['margin-right'] : - options.edge.x == 'center' ? -dim['margin-left'] + ((dim['margin-right'] + dim['margin-left'])/2) : - - dim['margin-left'] - ); - pos.top += ( - options.edge.y == 'bottom' ? dim['margin-bottom'] : - options.edge.y == 'center' ? -dim['margin-top'] + ((dim['margin-bottom'] + dim['margin-top'])/2) : - - dim['margin-top'] - ); - } - pos.left = Math.ceil(pos.left); - pos.top = Math.ceil(pos.top); - if (options.returnPos) return pos; - else this.setStyles(pos); - return this; + calculatePosition: function(options){ + return local.getPosition(this, options); } }); -})(); +})(Element.prototype.position); /* @@ -2345,7 +3085,7 @@ Element.implement({ //IE fails here if the element is not in the dom d = this.getStyle('display'); } catch(e){} - if (d == "none") return this; + if (d == 'none') return this; return this.store('element:_originalDisplay', d || '').setStyle('display', 'none'); }, @@ -2358,19 +3098,810 @@ Element.implement({ swapClass: function(remove, add){ return this.removeClass(remove).addClass(add); } + }); Document.implement({ + clearSelection: function(){ - if (document.selection && document.selection.empty) { - document.selection.empty(); - } else if (window.getSelection) { + if (window.getSelection){ var selection = window.getSelection(); if (selection && selection.removeAllRanges) selection.removeAllRanges(); + } else if (document.selection && document.selection.empty){ + try { + //IE fails here if selected element is not in dom + document.selection.empty(); + } catch(e){} } } + }); + +/* +--- + +script: Class.Binds.js + +name: Class.Binds + +description: Automagically binds specified methods in a class to the instance of the class. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Class + - /MooTools.More + +provides: [Class.Binds] + +... +*/ + +Class.Mutators.Binds = function(binds){ + if (!this.prototype.initialize) this.implement('initialize', function(){}); + return Array.from(binds).concat(this.prototype.Binds || []); +}; + +Class.Mutators.initialize = function(initialize){ + return function(){ + Array.from(this.Binds).each(function(name){ + var original = this[name]; + if (original) this[name] = original.bind(this); + }, this); + return initialize.apply(this, arguments); + }; +}; + + +/* +--- + +script: Class.Occlude.js + +name: Class.Occlude + +description: Prevents a class from being applied to a DOM element twice. + +license: MIT-style license. + +authors: + - Aaron Newton + +requires: + - Core/Class + - Core/Element + - /MooTools.More + +provides: [Class.Occlude] + +... +*/ + +Class.Occlude = new Class({ + + occlude: function(property, element){ + element = document.id(element || this.element); + var instance = element.retrieve(property || this.property); + if (instance && !this.occluded) + return (this.occluded = instance); + + this.occluded = false; + element.store(property || this.property, this); + return this.occluded; + } + +}); + + +/* +--- + +script: IframeShim.js + +name: IframeShim + +description: Defines IframeShim, a class for obscuring select lists and flash objects in IE. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Element.Event + - Core/Element.Style + - Core/Options + - Core/Events + - /Element.Position + - /Class.Occlude + +provides: [IframeShim] + +... +*/ + +var IframeShim = new Class({ + + Implements: [Options, Events, Class.Occlude], + + options: { + className: 'iframeShim', + src: 'javascript:false;document.write("");', + display: false, + zIndex: null, + margin: 0, + offset: {x: 0, y: 0}, + browsers: (Browser.ie6 || (Browser.firefox && Browser.version < 3 && Browser.Platform.mac)) + }, + + property: 'IframeShim', + + initialize: function(element, options){ + this.element = document.id(element); + if (this.occlude()) return this.occluded; + this.setOptions(options); + this.makeShim(); + return this; + }, + + makeShim: function(){ + if (this.options.browsers){ + var zIndex = this.element.getStyle('zIndex').toInt(); + + if (!zIndex){ + zIndex = 1; + var pos = this.element.getStyle('position'); + if (pos == 'static' || !pos) this.element.setStyle('position', 'relative'); + this.element.setStyle('zIndex', zIndex); + } + zIndex = ((this.options.zIndex != null || this.options.zIndex === 0) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1; + if (zIndex < 0) zIndex = 1; + this.shim = new Element('iframe', { + src: this.options.src, + scrolling: 'no', + frameborder: 0, + styles: { + zIndex: zIndex, + position: 'absolute', + border: 'none', + filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)' + }, + 'class': this.options.className + }).store('IframeShim', this); + var inject = (function(){ + this.shim.inject(this.element, 'after'); + this[this.options.display ? 'show' : 'hide'](); + this.fireEvent('inject'); + }).bind(this); + if (!IframeShim.ready) window.addEvent('load', inject); + else inject(); + } else { + this.position = this.hide = this.show = this.dispose = Function.from(this); + } + }, + + position: function(){ + if (!IframeShim.ready || !this.shim) return this; + var size = this.element.measure(function(){ + return this.getSize(); + }); + if (this.options.margin != undefined){ + size.x = size.x - (this.options.margin * 2); + size.y = size.y - (this.options.margin * 2); + this.options.offset.x += this.options.margin; + this.options.offset.y += this.options.margin; + } + this.shim.set({width: size.x, height: size.y}).position({ + relativeTo: this.element, + offset: this.options.offset + }); + return this; + }, + + hide: function(){ + if (this.shim) this.shim.setStyle('display', 'none'); + return this; + }, + + show: function(){ + if (this.shim) this.shim.setStyle('display', 'block'); + return this.position(); + }, + + dispose: function(){ + if (this.shim) this.shim.dispose(); + return this; + }, + + destroy: function(){ + if (this.shim) this.shim.destroy(); + return this; + } + +}); + +window.addEvent('load', function(){ + IframeShim.ready = true; +}); + + +/* +--- + +script: Mask.js + +name: Mask + +description: Creates a mask element to cover another. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Options + - Core/Events + - Core/Element.Event + - /Class.Binds + - /Element.Position + - /IframeShim + +provides: [Mask] + +... +*/ + +var Mask = new Class({ + + Implements: [Options, Events], + + Binds: ['position'], + + options: {/* + onShow: function(){}, + onHide: function(){}, + onDestroy: function(){}, + onClick: function(event){}, + inject: { + where: 'after', + target: null, + }, + hideOnClick: false, + id: null, + destroyOnHide: false,*/ + style: {}, + 'class': 'mask', + maskMargins: false, + useIframeShim: true, + iframeShimOptions: {} + }, + + initialize: function(target, options){ + this.target = document.id(target) || document.id(document.body); + this.target.store('mask', this); + this.setOptions(options); + this.render(); + this.inject(); + }, + + render: function(){ + this.element = new Element('div', { + 'class': this.options['class'], + id: this.options.id || 'mask-' + String.uniqueID(), + styles: Object.merge({}, this.options.style, { + display: 'none' + }), + events: { + click: function(event){ + this.fireEvent('click', event); + if (this.options.hideOnClick) this.hide(); + }.bind(this) + } + }); + + this.hidden = true; + }, + + toElement: function(){ + return this.element; + }, + + inject: function(target, where){ + where = where || (this.options.inject ? this.options.inject.where : '') || this.target == document.body ? 'inside' : 'after'; + target = target || (this.options.inject && this.options.inject.target) || this.target; + + this.element.inject(target, where); + + if (this.options.useIframeShim){ + this.shim = new IframeShim(this.element, this.options.iframeShimOptions); + + this.addEvents({ + show: this.shim.show.bind(this.shim), + hide: this.shim.hide.bind(this.shim), + destroy: this.shim.destroy.bind(this.shim) + }); + } + }, + + position: function(){ + this.resize(this.options.width, this.options.height); + + this.element.position({ + relativeTo: this.target, + position: 'topLeft', + ignoreMargins: !this.options.maskMargins, + ignoreScroll: this.target == document.body + }); + + return this; + }, + + resize: function(x, y){ + var opt = { + styles: ['padding', 'border'] + }; + if (this.options.maskMargins) opt.styles.push('margin'); + + var dim = this.target.getComputedSize(opt); + if (this.target == document.body){ + this.element.setStyles({width: 0, height: 0}); + var win = window.getScrollSize(); + if (dim.totalHeight < win.y) dim.totalHeight = win.y; + if (dim.totalWidth < win.x) dim.totalWidth = win.x; + } + this.element.setStyles({ + width: Array.pick([x, dim.totalWidth, dim.x]), + height: Array.pick([y, dim.totalHeight, dim.y]) + }); + + return this; + }, + + show: function(){ + if (!this.hidden) return this; + + window.addEvent('resize', this.position); + this.position(); + this.showMask.apply(this, arguments); + + return this; + }, + + showMask: function(){ + this.element.setStyle('display', 'block'); + this.hidden = false; + this.fireEvent('show'); + }, + + hide: function(){ + if (this.hidden) return this; + + window.removeEvent('resize', this.position); + this.hideMask.apply(this, arguments); + if (this.options.destroyOnHide) return this.destroy(); + + return this; + }, + + hideMask: function(){ + this.element.setStyle('display', 'none'); + this.hidden = true; + this.fireEvent('hide'); + }, + + toggle: function(){ + this[this.hidden ? 'show' : 'hide'](); + }, + + destroy: function(){ + this.hide(); + this.element.destroy(); + this.fireEvent('destroy'); + this.target.eliminate('mask'); + } + +}); + +Element.Properties.mask = { + + set: function(options){ + var mask = this.retrieve('mask'); + if (mask) mask.destroy(); + return this.eliminate('mask').store('mask:options', options); + }, + + get: function(){ + var mask = this.retrieve('mask'); + if (!mask){ + mask = new Mask(this, this.retrieve('mask:options')); + this.store('mask', mask); + } + return mask; + } + +}; + +Element.implement({ + + mask: function(options){ + if (options) this.set('mask', options); + this.get('mask').show(); + return this; + }, + + unmask: function(){ + this.get('mask').hide(); + return this; + } + +}); + + +/* +--- + +script: Spinner.js + +name: Spinner + +description: Adds a semi-transparent overlay over a dom element with a spinnin ajax icon. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Fx.Tween + - Core/Request + - /Class.refactor + - /Mask + +provides: [Spinner] + +... +*/ + +var Spinner = new Class({ + + Extends: Mask, + + Implements: Chain, + + options: {/* + message: false,*/ + 'class': 'spinner', + containerPosition: {}, + content: { + 'class': 'spinner-content' + }, + messageContainer: { + 'class': 'spinner-msg' + }, + img: { + 'class': 'spinner-img' + }, + fxOptions: { + link: 'chain' + } + }, + + initialize: function(target, options){ + this.target = document.id(target) || document.id(document.body); + this.target.store('spinner', this); + this.setOptions(options); + this.render(); + this.inject(); + + // Add this to events for when noFx is true; parent methods handle hide/show. + var deactivate = function(){ this.active = false; }.bind(this); + this.addEvents({ + hide: deactivate, + show: deactivate + }); + }, + + render: function(){ + this.parent(); + + this.element.set('id', this.options.id || 'spinner-' + String.uniqueID()); + + this.content = document.id(this.options.content) || new Element('div', this.options.content); + this.content.inject(this.element); + + if (this.options.message){ + this.msg = document.id(this.options.message) || new Element('p', this.options.messageContainer).appendText(this.options.message); + this.msg.inject(this.content); + } + + if (this.options.img){ + this.img = document.id(this.options.img) || new Element('div', this.options.img); + this.img.inject(this.content); + } + + this.element.set('tween', this.options.fxOptions); + }, + + show: function(noFx){ + if (this.active) return this.chain(this.show.bind(this)); + if (!this.hidden){ + this.callChain.delay(20, this); + return this; + } + + this.active = true; + + return this.parent(noFx); + }, + + showMask: function(noFx){ + var pos = function(){ + this.content.position(Object.merge({ + relativeTo: this.element + }, this.options.containerPosition)); + }.bind(this); + + if (noFx){ + this.parent(); + pos(); + } else { + if (!this.options.style.opacity) this.options.style.opacity = this.element.getStyle('opacity').toFloat(); + this.element.setStyles({ + display: 'block', + opacity: 0 + }).tween('opacity', this.options.style.opacity); + pos(); + this.hidden = false; + this.fireEvent('show'); + this.callChain(); + } + }, + + hide: function(noFx){ + if (this.active) return this.chain(this.hide.bind(this)); + if (this.hidden){ + this.callChain.delay(20, this); + return this; + } + this.active = true; + return this.parent(noFx); + }, + + hideMask: function(noFx){ + if (noFx) return this.parent(); + this.element.tween('opacity', 0).get('tween').chain(function(){ + this.element.setStyle('display', 'none'); + this.hidden = true; + this.fireEvent('hide'); + this.callChain(); + }.bind(this)); + }, + + destroy: function(){ + this.content.destroy(); + this.parent(); + this.target.eliminate('spinner'); + } + +}); + +Request = Class.refactor(Request, { + + options: { + useSpinner: false, + spinnerOptions: {}, + spinnerTarget: false + }, + + initialize: function(options){ + this._send = this.send; + this.send = function(options){ + var spinner = this.getSpinner(); + if (spinner) spinner.chain(this._send.pass(options, this)).show(); + else this._send(options); + return this; + }; + this.previous(options); + }, + + getSpinner: function(){ + if (!this.spinner){ + var update = document.id(this.options.spinnerTarget) || document.id(this.options.update); + if (this.options.useSpinner && update){ + update.set('spinner', this.options.spinnerOptions); + var spinner = this.spinner = update.get('spinner'); + ['complete', 'exception', 'cancel'].each(function(event){ + this.addEvent(event, spinner.hide.bind(spinner)); + }, this); + } + } + return this.spinner; + } + +}); + +Element.Properties.spinner = { + + set: function(options){ + var spinner = this.retrieve('spinner'); + if (spinner) spinner.destroy(); + return this.eliminate('spinner').store('spinner:options', options); + }, + + get: function(){ + var spinner = this.retrieve('spinner'); + if (!spinner){ + spinner = new Spinner(this, this.retrieve('spinner:options')); + this.store('spinner', spinner); + } + return spinner; + } + +}; + +Element.implement({ + + spin: function(options){ + if (options) this.set('spinner', options); + this.get('spinner').show(); + return this; + }, + + unspin: function(){ + this.get('spinner').hide(); + return this; + } + +}); + + +/* +--- + +script: Element.Delegation.js + +name: Element.Delegation + +description: Extends the Element native object to include the delegate method for more efficient event management. + +credits: + - "Event checking based on the work of Daniel Steigerwald. License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" + +license: MIT-style license + +authors: + - Aaron Newton + - Daniel Steigerwald + +requires: [/MooTools.More, Element.Event.Pseudos] + +provides: [Element.Delegation] + +... +*/ + +(function(){ + +var eventListenerSupport = !(window.attachEvent && !window.addEventListener), + nativeEvents = Element.NativeEvents; + +nativeEvents.focusin = 2; +nativeEvents.focusout = 2; + +var check = function(split, target, event){ + var elementEvent = Element.Events[split.event], condition; + if (elementEvent) condition = elementEvent.condition; + return Slick.match(target, split.value) && (!condition || condition.call(target, event)); +}; + +var bubbleUp = function(split, event, fn){ + for (var target = event.target; target && target != this; target = document.id(target.parentNode)){ + if (target && check(split, target, event)) return fn.call(target, event, target); + } +}; + +var formObserver = function(eventName){ + + var $delegationKey = '$delegation:'; + + return { + base: 'focusin', + + onRemove: function(element){ + element.retrieve($delegationKey + 'forms', []).each(function(el){ + el.retrieve($delegationKey + 'listeners', []).each(function(listener){ + el.removeEvent(eventName, listener); + }); + el.eliminate($delegationKey + eventName + 'listeners') + .eliminate($delegationKey + eventName + 'originalFn'); + }); + }, + + listener: function(split, fn, args, monitor, options){ + var event = args[0], + forms = this.retrieve($delegationKey + 'forms', []), + target = event.target, + form = (target.get('tag') == 'form') ? target : event.target.getParent('form'); + + if (!form) return; + + var formEvents = form.retrieve($delegationKey + 'originalFn', []), + formListeners = form.retrieve($delegationKey + 'listeners', []), + self = this; + + forms.include(form); + this.store($delegationKey + 'forms', forms); + + if (!formEvents.contains(fn)){ + var formListener = function(event){ + bubbleUp.call(self, split, event, fn); + }; + form.addEvent(eventName, formListener); + + formEvents.push(fn); + formListeners.push(formListener); + + form.store($delegationKey + eventName + 'originalFn', formEvents) + .store($delegationKey + eventName + 'listeners', formListeners); + } + } + }; +}; + +var inputObserver = function(eventName){ + return { + base: 'focusin', + listener: function(split, fn, args){ + var events = {blur: function(){ + this.removeEvents(events); + }}, self = this; + events[eventName] = function(event){ + bubbleUp.call(self, split, event, fn); + }; + args[0].target.addEvents(events); + } + }; +}; + +var eventOptions = { + mouseenter: { + base: 'mouseover' + }, + mouseleave: { + base: 'mouseout' + }, + focus: { + base: 'focus' + (eventListenerSupport ? '' : 'in'), + args: [true] + }, + blur: { + base: eventListenerSupport ? 'blur' : 'focusout', + args: [true] + } +}; + +if (!eventListenerSupport) Object.append(eventOptions, { + submit: formObserver('submit'), + reset: formObserver('reset'), + change: inputObserver('change'), + select: inputObserver('select') +}); + +Event.definePseudo('relay', { + listener: function(split, fn, args){ + bubbleUp.call(this, split, args[0], fn); + }, + options: eventOptions +}); + +})(); + + /* --- @@ -2408,10 +3939,10 @@ if (!window.Form) window.Form = {}; Implements: [Options, Events, Class.Occlude], - options: { - //onFailure: $empty, - //onSuccess: #empty, //aliased to onComplete, - //onSend: $empty + options: {/* + onFailure: function(){}, + onSuccess: function(){}, // aliased to onComplete, + onSend: function(){}*/ requestOptions: { evalScripts: true, useSpinner: true, @@ -2425,163 +3956,405 @@ if (!window.Form) window.Form = {}; property: 'form.request', - initialize: function(form, update, options) { + initialize: function(form, target, options){ this.element = document.id(form); if (this.occlude()) return this.occluded; - this.update = document.id(update); - this.setOptions(options); - this.makeRequest(); - if (this.options.resetForm) { - this.request.addEvent('success', function(){ - $try(function(){ this.element.reset(); }.bind(this)); - if (window.OverText) OverText.update(); - }.bind(this)); - } - this.attach(); + this.setOptions(options) + .setTarget(target) + .attach(); }, - toElement: function() { + setTarget: function(target){ + this.target = document.id(target); + if (!this.request){ + this.makeRequest(); + } else { + this.request.setOptions({ + update: this.target + }); + } + return this; + }, + + toElement: function(){ return this.element; }, makeRequest: function(){ - this.request = new Request.HTML($merge({ - update: this.update, + var self = this; + this.request = new Request.HTML(Object.merge({ + update: this.target, emulation: false, spinnerTarget: this.element, method: this.element.get('method') || 'post' }, this.options.requestOptions)).addEvents({ success: function(tree, elements, html, javascript){ ['complete', 'success'].each(function(evt){ - this.fireEvent(evt, [this.update, tree, elements, html, javascript]); - }, this); - }.bind(this), + self.fireEvent(evt, [self.target, tree, elements, html, javascript]); + }); + }, failure: function(){ - this.fireEvent('complete', arguments).fireEvent('failure', arguments); - }.bind(this), + self.fireEvent('complete', arguments).fireEvent('failure', arguments); + }, exception: function(){ - this.fireEvent('failure', arguments); - }.bind(this) + self.fireEvent('failure', arguments); + } }); + return this.attachReset(); + }, + + attachReset: function(){ + if (!this.options.resetForm) return this; + this.request.addEvent('success', function(){ + Function.attempt(function(){ + this.element.reset(); + }.bind(this)); + if (window.OverText) OverText.update(); + }.bind(this)); + return this; }, attach: function(attach){ - attach = $pick(attach, true); - method = attach ? 'addEvent' : 'removeEvent'; - + var method = (attach != false) ? 'addEvent' : 'removeEvent'; this.element[method]('click:relay(button, input[type=submit])', this.saveClickedButton.bind(this)); - + var fv = this.element.retrieve('validator'); if (fv) fv[method]('onFormValidate', this.onFormValidate); else this.element[method]('submit', this.onSubmit); + + return this; }, detach: function(){ - this.attach(false); - return this; + return this.attach(false); }, //public method enable: function(){ - this.attach(); - return this; + return this.attach(); }, //public method disable: function(){ - this.detach(); - return this; + return this.detach(); }, - onFormValidate: function(valid, form, e) { + onFormValidate: function(valid, form, event){ //if there's no event, then this wasn't a submit event - if (!e) return; + if (!event) return; var fv = this.element.retrieve('validator'); - if (valid || (fv && !fv.options.stopOnFailure)) { - if (e && e.stop) e.stop(); + if (valid || (fv && !fv.options.stopOnFailure)){ + event.stop(); this.send(); } }, - onSubmit: function(e){ + onSubmit: function(event){ var fv = this.element.retrieve('validator'); - if (fv) { + if (fv){ //form validator was created after Form.Request this.element.removeEvent('submit', this.onSubmit); fv.addEvent('onFormValidate', this.onFormValidate); this.element.validate(); return; } - if (e) e.stop(); + if (event) event.stop(); this.send(); }, - saveClickedButton: function(event, target) { - if (!this.options.sendButtonClicked) return; - if (!target.get('name')) return; - this.options.extraData[target.get('name')] = target.get('value') || true; + saveClickedButton: function(event, target){ + var targetName = target.get('name'); + if (!targetName || !this.options.sendButtonClicked) return; + this.options.extraData[targetName] = target.get('value') || true; this.clickedCleaner = function(){ - delete this.options.extraData[target.get('name')]; - this.clickedCleaner = $empty; + delete this.options.extraData[targetName]; + this.clickedCleaner = function(){}; }.bind(this); }, - clickedCleaner: $empty, + clickedCleaner: function(){}, send: function(){ - var str = this.element.toQueryString().trim(); - var data = $H(this.options.extraData).toQueryString(); + var str = this.element.toQueryString().trim(), + data = Object.toQueryString(this.options.extraData); + if (str) str += "&" + data; else str = data; + this.fireEvent('send', [this.element, str.parseQueryString()]); - this.request.send({data: str, url: this.element.get("action")}); + this.request.send({ + data: str, + url: this.options.requestOptions.url || this.element.get('action') + }); this.clickedCleaner(); return this; } }); - Element.Properties.formRequest = { - - set: function(){ - var opt = Array.link(arguments, {options: Object.type, update: Element.type, updateId: String.type}); - var update = opt.update || opt.updateId; - var updater = this.retrieve('form.request'); - if (update) { - if (updater) updater.update = document.id(update); - this.store('form.request:update', update); - } - if (opt.options) { - if (updater) updater.setOptions(opt.options); - this.store('form.request:options', opt.options); - } - return this; - }, - - get: function(){ - var opt = Array.link(arguments, {options: Object.type, update: Element.type, updateId: String.type}); - var update = opt.update || opt.updateId; - if (opt.options || update || !this.retrieve('form.request')){ - if (opt.options || !this.retrieve('form.request:options')) this.set('form.request', opt.options); - if (update) this.set('form.request', update); - this.store('form.request', new Form.Request(this, this.retrieve('form.request:update'), this.retrieve('form.request:options'))); - } - return this.retrieve('form.request'); + Element.implement('formUpdate', function(update, options){ + var fq = this.retrieve('form.request'); + if (!fq) { + fq = new Form.Request(this, update, options); + } else { + if (update) fq.setTarget(update); + if (options) fq.setOptions(options).makeRequest(); } - - }; - - Element.implement({ - - formUpdate: function(update, options){ - this.get('formRequest', update, options).send(); - return this; - } - + fq.send(); + return this; }); })(); + +/* +--- + +script: Fx.Reveal.js + +name: Fx.Reveal + +description: Defines Fx.Reveal, a class that shows and hides elements with a transition. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Fx.Morph + - /Element.Shortcuts + - /Element.Measure + +provides: [Fx.Reveal] + +... +*/ + +(function(){ + + +var hideTheseOf = function(object){ + var hideThese = object.options.hideInputs; + if (window.OverText){ + var otClasses = [null]; + OverText.each(function(ot){ + otClasses.include('.' + ot.options.labelClass); + }); + if (otClasses) hideThese += otClasses.join(', '); + } + return (hideThese) ? object.element.getElements(hideThese) : null; +}; + + +Fx.Reveal = new Class({ + + Extends: Fx.Morph, + + options: {/* + onShow: function(thisElement){}, + onHide: function(thisElement){}, + onComplete: function(thisElement){}, + heightOverride: null, + widthOverride: null,*/ + link: 'cancel', + styles: ['padding', 'border', 'margin'], + transitionOpacity: !Browser.ie6, + mode: 'vertical', + display: function(){ + return this.element.get('tag') != 'tr' ? 'block' : 'table-row'; + }, + opacity: 1, + hideInputs: Browser.ie ? 'select, input, textarea, object, embed' : null + }, + + dissolve: function(){ + if (!this.hiding && !this.showing){ + if (this.element.getStyle('display') != 'none'){ + this.hiding = true; + this.showing = false; + this.hidden = true; + this.cssText = this.element.style.cssText; + + var startStyles = this.element.getComputedSize({ + styles: this.options.styles, + mode: this.options.mode + }); + if (this.options.transitionOpacity) startStyles.opacity = this.options.opacity; + + var zero = {}; + Object.each(startStyles, function(style, name){ + zero[name] = [style, 0]; + }); + + this.element.setStyles({ + display: Function.from(this.options.display).call(this), + overflow: 'hidden' + }); + + var hideThese = hideTheseOf(this); + if (hideThese) hideThese.setStyle('visibility', 'hidden'); + + this.$chain.unshift(function(){ + if (this.hidden){ + this.hiding = false; + this.element.style.cssText = this.cssText; + this.element.setStyle('display', 'none'); + if (hideThese) hideThese.setStyle('visibility', 'visible'); + } + this.fireEvent('hide', this.element); + this.callChain(); + }.bind(this)); + + this.start(zero); + } else { + this.callChain.delay(10, this); + this.fireEvent('complete', this.element); + this.fireEvent('hide', this.element); + } + } else if (this.options.link == 'chain'){ + this.chain(this.dissolve.bind(this)); + } else if (this.options.link == 'cancel' && !this.hiding){ + this.cancel(); + this.dissolve(); + } + return this; + }, + + reveal: function(){ + if (!this.showing && !this.hiding){ + if (this.element.getStyle('display') == 'none'){ + this.hiding = false; + this.showing = true; + this.hidden = false; + this.cssText = this.element.style.cssText; + + var startStyles; + this.element.measure(function(){ + startStyles = this.element.getComputedSize({ + styles: this.options.styles, + mode: this.options.mode + }); + }.bind(this)); + if (this.options.heightOverride != null) startStyles.height = this.options.heightOverride.toInt(); + if (this.options.widthOverride != null) startStyles.width = this.options.widthOverride.toInt(); + if (this.options.transitionOpacity){ + this.element.setStyle('opacity', 0); + startStyles.opacity = this.options.opacity; + } + + var zero = { + height: 0, + display: Function.from(this.options.display).call(this) + }; + Object.each(startStyles, function(style, name){ + zero[name] = 0; + }); + zero.overflow = 'hidden'; + + this.element.setStyles(zero); + + var hideThese = hideTheseOf(this); + if (hideThese) hideThese.setStyle('visibility', 'hidden'); + + this.$chain.unshift(function(){ + this.element.style.cssText = this.cssText; + this.element.setStyle('display', Function.from(this.options.display).call(this)); + if (!this.hidden) this.showing = false; + if (hideThese) hideThese.setStyle('visibility', 'visible'); + this.callChain(); + this.fireEvent('show', this.element); + }.bind(this)); + + this.start(startStyles); + } else { + this.callChain(); + this.fireEvent('complete', this.element); + this.fireEvent('show', this.element); + } + } else if (this.options.link == 'chain'){ + this.chain(this.reveal.bind(this)); + } else if (this.options.link == 'cancel' && !this.showing){ + this.cancel(); + this.reveal(); + } + return this; + }, + + toggle: function(){ + if (this.element.getStyle('display') == 'none'){ + this.reveal(); + } else { + this.dissolve(); + } + return this; + }, + + cancel: function(){ + this.parent.apply(this, arguments); + if (this.cssText != null) this.element.style.cssText = this.cssText; + this.hiding = false; + this.showing = false; + return this; + } + +}); + +Element.Properties.reveal = { + + set: function(options){ + this.get('reveal').cancel().setOptions(options); + return this; + }, + + get: function(){ + var reveal = this.retrieve('reveal'); + if (!reveal){ + reveal = new Fx.Reveal(this); + this.store('reveal', reveal); + } + return reveal; + } + +}; + +Element.Properties.dissolve = Element.Properties.reveal; + +Element.implement({ + + reveal: function(options){ + this.get('reveal').setOptions(options).reveal(); + return this; + }, + + dissolve: function(options){ + this.get('reveal').setOptions(options).dissolve(); + return this; + }, + + nix: function(options){ + var params = Array.link(arguments, {destroy: Type.isBoolean, options: Type.isObject}); + this.get('reveal').setOptions(options).dissolve().chain(function(){ + this[params.destroy ? 'destroy' : 'dispose'](); + }.bind(this)); + return this; + }, + + wink: function(){ + var params = Array.link(arguments, {duration: Type.isNumber, options: Type.isObject}); + var reveal = this.get('reveal').setOptions(params.options); + reveal.reveal().chain(function(){ + (function(){ + reveal.dissolve(); + }).delay(params.duration || 2000); + }); + } + +}); + +})(); + + /* --- @@ -2611,14 +4384,14 @@ Form.Request.Append = new Class({ Extends: Form.Request, options: { - //onBeforeEffect: $empty, + //onBeforeEffect: function(){}, useReveal: true, revealOptions: {}, inject: 'bottom' }, makeRequest: function(){ - this.request = new Request.HTML($merge({ + this.request = new Request.HTML(Object.merge({ url: this.element.get('action'), method: this.element.get('method') || 'post', spinnerTarget: this.element @@ -2629,7 +4402,7 @@ Form.Request.Append = new Class({ success: function(tree, elements, html, javascript){ var container; var kids = Elements.from(html); - if (kids.length == 1) { + if (kids.length == 1){ container = kids[0]; } else { container = new Element('div', { @@ -2638,14 +4411,14 @@ Form.Request.Append = new Class({ } }).adopt(kids); } - container.inject(this.update, this.options.inject); - if (this.options.requestOptions.evalScripts) $exec(javascript); + container.inject(this.target, this.options.inject); + if (this.options.requestOptions.evalScripts) Browser.exec(javascript); this.fireEvent('beforeEffect', container); var finish = function(){ - this.fireEvent('success', [container, this.update, tree, elements, html, javascript]); + this.fireEvent('success', [container, this.target, tree, elements, html, javascript]); }.bind(this); - if (this.options.useReveal) { - container.get('reveal', this.options.revealOptions).chain(finish); + if (this.options.useReveal){ + container.set('reveal', this.options.revealOptions).get('reveal').chain(finish); container.reveal(); } else { finish(); @@ -2655,10 +4428,69 @@ Form.Request.Append = new Class({ this.fireEvent('failure', xhr); }.bind(this) }); + this.attachReset(); } }); + +/* +--- + +name: Locale.en-US.Form.Validator + +description: Form Validator messages for English. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - /Locale + +provides: [Locale.en-US.Form.Validator] + +... +*/ + +Locale.define('en-US', 'FormValidator', { + + required: 'This field is required.', + minLength: 'Please enter at least {minLength} characters (you entered {length} characters).', + maxLength: 'Please enter no more than {maxLength} characters (you entered {length} characters).', + integer: 'Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.', + numeric: 'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").', + digits: 'Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).', + alpha: 'Please use only letters (a-z) within this field. No spaces or other characters are allowed.', + alphanum: 'Please use only letters (a-z) or numbers (0-9) in this field. No spaces or other characters are allowed.', + dateSuchAs: 'Please enter a valid date such as {date}', + dateInFormatMDY: 'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")', + email: 'Please enter a valid email address. For example "fred@domain.com".', + url: 'Please enter a valid URL such as http://www.example.com.', + currencyDollar: 'Please enter a valid $ amount. For example $100.00 .', + oneRequired: 'Please enter something for at least one of these inputs.', + errorPrefix: 'Error: ', + warningPrefix: 'Warning: ', + + // Form.Validator.Extras + noSpace: 'There can be no spaces in this input.', + reqChkByNode: 'No items are selected.', + requiredChk: 'This field is required.', + reqChkByName: 'Please select a {label}.', + match: 'This field needs to match the {matchName} field', + startDate: 'the start date', + endDate: 'the end date', + currendDate: 'the current date', + afterDate: 'The date should be the same or after {label}.', + beforeDate: 'The date should be the same or before {label}.', + startMonth: 'Please select a start month', + sameMonth: 'These two dates must be in the same month - you must change one or the other.', + creditcard: 'The credit card number entered is invalid. Please check the number and try again. {length} digits entered.' + +}); + + /* --- @@ -2676,15 +4508,15 @@ authors: requires: - Core/Options - Core/Events - - Core/Selectors + - Core/Slick.Finder - Core/Element.Event - Core/Element.Style - Core/JSON - - /Lang + - /Locale - /Class.Binds - - /Date + - /Date - /Element.Forms - - /Form.Validator.English + - /Locale.en-US.Form.Validator - /Element.Shortcuts provides: [Form.Validator, InputValidator, FormValidator.BaseValidators] @@ -2693,13 +4525,13 @@ provides: [Form.Validator, InputValidator, FormValidator.BaseValidators] */ if (!window.Form) window.Form = {}; -var InputValidator = new Class({ +var InputValidator = this.InputValidator = new Class({ Implements: [Options], options: { errorMsg: 'Validation failed.', - test: function(field){return true;} + test: Function.from(true) }, initialize: function(className, options){ @@ -2708,73 +4540,82 @@ var InputValidator = new Class({ }, test: function(field, props){ - if (document.id(field)) return this.options.test(document.id(field), props||this.getProps(field)); - else return false; + field = document.id(field); + return (field) ? this.options.test(field, props || this.getProps(field)) : false; }, getError: function(field, props){ + field = document.id(field); var err = this.options.errorMsg; - if ($type(err) == 'function') err = err(document.id(field), props||this.getProps(field)); + if (typeOf(err) == 'function') err = err(field, props || this.getProps(field)); return err; }, getProps: function(field){ - if (!document.id(field)) return {}; - return field.get('validatorProps'); + field = document.id(field); + return (field) ? field.get('validatorProps') : {}; } }); +Element.Properties.validators = { + + get: function(){ + return (this.get('data-validators') || this.className).clean().split(' '); + } + +}; + Element.Properties.validatorProps = { set: function(props){ - return this.eliminate('validatorProps').store('validatorProps', props); + return this.eliminate('$moo:validatorProps').store('$moo:validatorProps', props); }, get: function(props){ if (props) this.set(props); - if (this.retrieve('validatorProps')) return this.retrieve('validatorProps'); - if (this.getProperty('validatorProps')){ + if (this.retrieve('$moo:validatorProps')) return this.retrieve('$moo:validatorProps'); + if (this.getProperty('data-validator-properties') || this.getProperty('validatorProps')){ try { - this.store('validatorProps', JSON.decode(this.getProperty('validatorProps'))); + this.store('$moo:validatorProps', JSON.decode(this.getProperty('validatorProps') || this.getProperty('data-validator-properties'))); }catch(e){ return {}; } } else { - var vals = this.get('class').split(' ').filter(function(cls){ + var vals = this.get('validators').filter(function(cls){ return cls.test(':'); }); if (!vals.length){ - this.store('validatorProps', {}); + this.store('$moo:validatorProps', {}); } else { props = {}; vals.each(function(cls){ var split = cls.split(':'); - if (split[1]) { + if (split[1]){ try { props[split[0]] = JSON.decode(split[1]); - } catch(e) {} + } catch(e){} } }); - this.store('validatorProps', props); + this.store('$moo:validatorProps', props); } } - return this.retrieve('validatorProps'); + return this.retrieve('$moo:validatorProps'); } }; Form.Validator = new Class({ - Implements:[Options, Events], + Implements: [Options, Events], Binds: ['onSubmit'], options: {/* - onFormValidate: $empty(isValid, form, event), - onElementValidate: $empty(isValid, field, className, warn), - onElementPass: $empty(field), - onElementFail: $empty(field, validatorsFailed) */ + onFormValidate: function(isValid, form, event){}, + onElementValidate: function(isValid, field, className, warn){}, + onElementPass: function(field){}, + onElementFail: function(field, validatorsFailed){}, */ fieldSelectors: 'input, select, textarea', ignoreHidden: true, ignoreDisabled: true, @@ -2796,8 +4637,8 @@ Form.Validator = new Class({ this.setOptions(options); this.element = document.id(form); this.element.store('validator', this); - this.warningPrefix = $lambda(this.options.warningPrefix)(); - this.errorPrefix = $lambda(this.options.errorPrefix)(); + this.warningPrefix = Function.from(this.options.warningPrefix)(); + this.errorPrefix = Function.from(this.options.errorPrefix)(); if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this.onSubmit); if (this.options.evaluateFieldsOnBlur || this.options.evaluateFieldsOnChange) this.watchFields(this.getFields()); }, @@ -2820,13 +4661,12 @@ Form.Validator = new Class({ }, validationMonitor: function(){ - $clear(this.timer); + clearTimeout(this.timer); this.timer = this.validateField.delay(50, this, arguments); }, onSubmit: function(event){ - if (!this.validate(event) && event) event.preventDefault(); - else this.reset(); + if (this.validate(event)) this.reset(); }, reset: function(){ @@ -2837,7 +4677,9 @@ Form.Validator = new Class({ validate: function(event){ var result = this.getFields().map(function(field){ return this.validateField(field, true); - }, this).every(function(v){ return v;}); + }, this).every(function(v){ + return v; + }); this.fireEvent('formValidate', [result, this.element, event]); if (this.options.stopOnFailure && !result && event) event.preventDefault(); return result; @@ -2853,32 +4695,33 @@ Form.Validator = new Class({ warned = this.element.getElement('.warning'); } if (field && (!failed || force || field.hasClass('validation-failed') || (failed && !this.options.serial))){ - var validators = field.className.split(' ').some(function(cn){ + var validationTypes = field.get('validators'); + var validators = validationTypes.some(function(cn){ return this.getValidator(cn); }, this); var validatorsFailed = []; - field.className.split(' ').each(function(className){ + validationTypes.each(function(className){ if (className && !this.test(className, field)) validatorsFailed.include(className); }, this); passed = validatorsFailed.length === 0; - if (validators && !field.hasClass('warnOnly')){ + if (validators && !this.hasValidator(field, 'warnOnly')){ if (passed){ field.addClass('validation-passed').removeClass('validation-failed'); - this.fireEvent('elementPass', field); + this.fireEvent('elementPass', [field]); } else { field.addClass('validation-failed').removeClass('validation-passed'); this.fireEvent('elementFail', [field, validatorsFailed]); } } if (!warned){ - var warnings = field.className.split(' ').some(function(cn){ - if (cn.test('^warn-') || field.hasClass('warnOnly')) + var warnings = validationTypes.some(function(cn){ + if (cn.test('^warn')) return this.getValidator(cn.replace(/^warn-/,'')); else return null; }, this); field.removeClass('warning'); - var warnResult = field.className.split(' ').map(function(cn){ - if (cn.test('^warn-') || field.hasClass('warnOnly')) + var warnResult = validationTypes.map(function(cn){ + if (cn.test('^warn')) return this.test(cn.replace(/^warn-/,''), field, true); else return null; }, this); @@ -2889,20 +4732,24 @@ Form.Validator = new Class({ test: function(className, field, warn){ field = document.id(field); - if((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true; + if ((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true; var validator = this.getValidator(className); - warn = $pick(warn, false); - if (field.hasClass('warnOnly')) warn = true; - var isValid = field.hasClass('ignoreValidation') || (validator ? validator.test(field) : true); + if (warn != null) warn = false; + if (this.hasValidator(field, 'warnOnly')) warn = true; + var isValid = this.hasValidator(field, 'ignoreValidation') || (validator ? validator.test(field) : true); if (validator && field.isVisible()) this.fireEvent('elementValidate', [isValid, field, className, warn]); if (warn) return true; return isValid; }, + hasValidator: function(field, value){ + return field.get('validators').contains(value); + }, + resetField: function(field){ field = document.id(field); if (field){ - field.className.split(' ').each(function(className){ + field.get('validators').each(function(className){ if (className.test('^warn-')) className = className.replace(/^warn-/, ''); field.removeClass('validation-failed'); field.removeClass('warning'); @@ -2941,7 +4788,7 @@ Form.Validator = new Class({ }); Form.Validator.getMsg = function(key){ - return MooTools.lang.get('Form.Validator', key); + return Locale.get('FormValidator.' + key); }; Form.Validator.adders = { @@ -2961,7 +4808,7 @@ Form.Validator.adders = { }, addAllThese : function(validators){ - $A(validators).each(function(validator){ + Array.from(validators).each(function(validator){ this.add(validator[0], validator[1]); }, this); }, @@ -2972,7 +4819,7 @@ Form.Validator.adders = { }; -$extend(Form.Validator, Form.Validator.adders); +Object.append(Form.Validator, Form.Validator.adders); Form.Validator.implement(Form.Validator.adders); @@ -3001,12 +4848,12 @@ Form.Validator.addAllThese([ ['minLength', { errorMsg: function(element, props){ - if ($type(props.minLength)) + if (typeOf(props.minLength) != 'null') return Form.Validator.getMsg('minLength').substitute({minLength:props.minLength,length:element.get('value').length }); else return ''; }, test: function(element, props){ - if ($type(props.minLength)) return (element.get('value').length >= $pick(props.minLength, 0)); + if (typeOf(props.minLength) != 'null') return (element.get('value').length >= (props.minLength || 0)); else return true; } }], @@ -3014,13 +4861,12 @@ Form.Validator.addAllThese([ ['maxLength', { errorMsg: function(element, props){ //props is {maxLength:10} - if ($type(props.maxLength)) + if (typeOf(props.maxLength) != 'null') return Form.Validator.getMsg('maxLength').substitute({maxLength:props.maxLength,length:element.get('value').length }); else return ''; }, test: function(element, props){ - //if the value is <= than the maxLength value, element passes test - return (element.get('value').length <= $pick(props.maxLength, 10000)); + return element.get('value').length <= (props.maxLength || 10000); } }], @@ -3049,7 +4895,7 @@ Form.Validator.addAllThese([ ['validate-alpha', { errorMsg: Form.Validator.getMsg.pass('alpha'), test: function(element){ - return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value')); + return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value')); } }], @@ -3071,28 +4917,40 @@ Form.Validator.addAllThese([ }, test: function(element, props){ if (Form.Validator.getValidator('IsEmpty').test(element)) return true; - var d; - if (Date.parse){ - var format = props.dateFormat || '%x'; - d = Date.parse(element.get('value')); - var formatted = d.format(format); + var dateLocale = Locale.getCurrent().sets.Date, + dateNouns = new RegExp([dateLocale.days, dateLocale.days_abbr, dateLocale.months, dateLocale.months_abbr].flatten().join('|'), 'i'), + value = element.get('value'), + wordsInValue = value.match(/[a-z]+/gi); + + if (wordsInValue && !wordsInValue.every(dateNouns.exec, dateNouns)) return false; + + var date = Date.parse(value), + format = props.dateFormat || '%x', + formatted = date.format(format); + if (formatted != 'invalid date') element.set('value', formatted); - return !isNaN(d); - } else { - var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/; - if (!regex.test(element.get('value'))) return false; - d = new Date(element.get('value').replace(regex, '$1/$2/$3')); - return (parseInt(RegExp.$1, 10) == (1 + d.getMonth())) && - (parseInt(RegExp.$2, 10) == d.getDate()) && - (parseInt(RegExp.$3, 10) == d.getFullYear()); - } + return date.isValid(); } }], ['validate-email', { errorMsg: Form.Validator.getMsg.pass('email'), test: function(element){ - return Form.Validator.getValidator('IsEmpty').test(element) || (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).test(element.get('value')); + /* + var chars = "[a-z0-9!#$%&'*+/=?^_`{|}~-]", + local = '(?:' + chars + '\\.?){0,63}' + chars, + + label = '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?', + hostname = '(?:' + label + '\\.)*' + label; + + octet = '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)', + ipv4 = '\\[(?:' + octet + '\\.){3}' + octet + '\\]', + + domain = '(?:' + hostname + '|' + ipv4 + ')'; + + var regex = new RegExp('^' + local + '@' + domain + '$', 'i'); + */ + return Form.Validator.getValidator('IsEmpty').test(element) || (/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+\/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(element.get('value')); } }], @@ -3106,11 +4964,7 @@ Form.Validator.addAllThese([ ['validate-currency-dollar', { errorMsg: Form.Validator.getMsg.pass('currencyDollar'), test: function(element){ - // [$]1[##][,###]+[.##] - // [$]1###+[.##] - // [$]0.## - // [$].## - return Form.Validator.getValidator('IsEmpty').test(element) || (/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(element.get('value')); + return Form.Validator.getValidator('IsEmpty').test(element) || (/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(element.get('value')); } }], @@ -3130,17 +4984,16 @@ Form.Validator.addAllThese([ Element.Properties.validator = { set: function(options){ - var validator = this.retrieve('validator'); - if (validator) validator.setOptions(options); - return this.store('validator:options', options); + this.get('validator').setOptions(options); }, - get: function(options){ - if (options || !this.retrieve('validator')){ - if (options || !this.retrieve('validator:options')) this.set('validator', options); - this.store('validator', new Form.Validator(this, this.retrieve('validator:options'))); + get: function(){ + var validator = this.retrieve('validator'); + if (!validator){ + validator = new Form.Validator(this); + this.store('validator', validator); } - return this.retrieve('validator'); + return validator; } }; @@ -3149,12 +5002,15 @@ Element.implement({ validate: function(options){ if (options) this.set('validator', options); - return this.get('validator', options).validate(); + return this.get('validator').validate(); } }); -//legacy -var FormValidator = Form.Validator; + + + + + /* @@ -3219,11 +5075,11 @@ Form.Validator.Inline = new Class({ }, makeAdvice: function(className, field, error, warn){ - var errorMsg = (warn)?this.warningPrefix:this.errorPrefix; + var errorMsg = (warn) ? this.warningPrefix : this.errorPrefix; errorMsg += (this.options.useTitles) ? field.title || error:error; var cssClass = (warn) ? 'warning-advice' : 'validation-advice'; var advice = this.getAdvice(className, field); - if(advice) { + if (advice){ advice = advice.set('html', errorMsg); } else { advice = new Element('div', { @@ -3232,7 +5088,7 @@ Form.Validator.Inline = new Class({ id: 'advice-' + className.split(':')[0] + '-' + this.getFieldId(field) }).addClass(cssClass); } - field.store('advice-' + className, advice); + field.store('$moo:advice-' + className, advice); return advice; }, @@ -3242,11 +5098,16 @@ Form.Validator.Inline = new Class({ showAdvice: function(className, field){ var advice = this.getAdvice(className, field); - if (advice && !field.retrieve(this.getPropName(className)) - && (advice.getStyle('display') == 'none' - || advice.getStyle('visiblity') == 'hidden' - || advice.getStyle('opacity') == 0)){ - field.store(this.getPropName(className), true); + if ( + advice && + !field.retrieve('$moo:' + this.getPropName(className)) && + ( + advice.getStyle('display') == 'none' || + advice.getStyle('visiblity') == 'hidden' || + advice.getStyle('opacity') == 0 + ) + ){ + field.store('$moo:' + this.getPropName(className), true); this.options.showError(advice); this.fireEvent('showAdvice', [field, advice, className]); } @@ -3254,8 +5115,8 @@ Form.Validator.Inline = new Class({ hideAdvice: function(className, field){ var advice = this.getAdvice(className, field); - if (advice && field.retrieve(this.getPropName(className))){ - field.store(this.getPropName(className), false); + if (advice && field.retrieve('$moo:' + this.getPropName(className))){ + field.store('$moo:' + this.getPropName(className), false); this.options.hideError(advice); this.fireEvent('hideAdvice', [field, advice, className]); } @@ -3269,7 +5130,7 @@ Form.Validator.Inline = new Class({ field = document.id(field); if (!field) return this; this.parent(field); - field.className.split(' ').each(function(className){ + field.get('validators').each(function(className){ this.hideAdvice(className, field); }, this); return this; @@ -3278,7 +5139,7 @@ Form.Validator.Inline = new Class({ getAllAdviceMessages: function(field, force){ var advice = []; if (field.hasClass('ignoreValidation') && !force) return advice; - var validators = field.className.split(' ').some(function(cn){ + var validators = field.get('validators').some(function(cn){ var warner = cn.test('^warn-') || field.hasClass('warnOnly'); if (warner) cn = cn.replace(/^warn-/, ''); var validator = this.getValidator(cn); @@ -3294,7 +5155,7 @@ Form.Validator.Inline = new Class({ }, getAdvice: function(className, field){ - return field.retrieve('advice-' + className); + return field.retrieve('$moo:advice-' + className); }, insertAdvice: function(advice, field){ @@ -3302,7 +5163,7 @@ Form.Validator.Inline = new Class({ var props = field.get('validatorProps'); //Build advice if (!props.msgPos || !document.id(props.msgPos)){ - if(field.type.toLowerCase() == 'radio') field.getParent().adopt(advice); + if (field.type && field.type.toLowerCase() == 'radio') field.getParent().adopt(advice); else advice.inject(document.id(field), 'after'); } else { document.id(props.msgPos).grab(advice); @@ -3311,16 +5172,16 @@ Form.Validator.Inline = new Class({ validateField: function(field, force, scroll){ var result = this.parent(field, force); - if (((this.options.scrollToErrorsOnSubmit && scroll === undefined) || scroll) && !result){ + if (((this.options.scrollToErrorsOnSubmit && scroll == null) || scroll) && !result){ var failed = document.id(this).getElement('.validation-failed'); var par = document.id(this).getParent(); while (par != document.body && par.getScrollSize().y == par.getSize().y){ par = par.getParent(); } - var fx = par.retrieve('fvScroller'); + var fx = par.retrieve('$moo:fvScroller'); if (!fx && window.Fx && Fx.Scroll){ fx = new Fx.Scroll(par, this.options.scrollFxOptions); - par.store('fvScroller', fx); + par.store('$moo:fvScroller', fx); } if (failed){ if (fx) fx.toElement(failed); @@ -3332,10 +5193,10 @@ Form.Validator.Inline = new Class({ watchFields: function(fields){ fields.each(function(el){ - if (this.options.evaluateFieldsOnBlur){ - el.addEvent('blur', this.validationMonitor.pass([el, false, this.options.scrollToErrorsOnBlur], this)); - } - if (this.options.evaluateFieldsOnChange){ + if (this.options.evaluateFieldsOnBlur){ + el.addEvent('blur', this.validationMonitor.pass([el, false, this.options.scrollToErrorsOnBlur], this)); + } + if (this.options.evaluateFieldsOnChange){ el.addEvent('change', this.validationMonitor.pass([el, true, this.options.scrollToErrorsOnChange], this)); } }, this); @@ -3372,7 +5233,7 @@ Form.Validator.addAllThese([ var fv = element.getParent('form').retrieve('validator'); if (!fv) return true; (props.toEnforce || document.id(props.enforceChildrenOf).getElements('input, select, textarea')).map(function(item){ - if (element.checked) { + if (element.checked){ fv.enforceField(item); } else { fv.ignoreField(item); @@ -3388,7 +5249,7 @@ Form.Validator.addAllThese([ var fv = element.getParent('form').retrieve('validator'); if (!fv) return true; (props.toIgnore || document.id(props.ignoreChildrenOf).getElements('input, select, textarea')).each(function(item){ - if (element.checked) { + if (element.checked){ fv.ignoreField(item); fv.resetField(item); } else { @@ -3529,7 +5390,7 @@ Form.Validator.addAllThese([ }, test: function(element){ // required is a different test - if (Form.Validator.getValidator('IsEmpty').test(element)) { return true; } + if (Form.Validator.getValidator('IsEmpty').test(element)) return true; // Clean number value var ccNum = element.get('value'); @@ -3542,24 +5403,26 @@ Form.Validator.addAllThese([ else if (ccNum.test(/^3[47][0-9]{13}$/)) valid_type = 'American Express'; else if (ccNum.test(/^6011[0-9]{12}$/)) valid_type = 'Discover'; - if (valid_type) { + if (valid_type){ var sum = 0; var cur = 0; - for(var i=ccNum.length-1; i>=0; --i) { + for (var i=ccNum.length-1; i>=0; --i){ cur = ccNum.charAt(i).toInt(); - if (cur == 0) { continue; } + if (cur == 0) continue; - if ((ccNum.length-i) % 2 == 0) { cur += cur; } - if (cur > 9) { cur = cur.toString().charAt(0).toInt() + cur.toString().charAt(1).toInt(); } + if ((ccNum.length-i) % 2 == 0) cur += cur; + if (cur > 9){ + cur = cur.toString().charAt(0).toInt() + cur.toString().charAt(1).toInt(); + } sum += cur; } - if ((sum % 10) == 0) { return true; } + if ((sum % 10) == 0) return true; } var chunks = ''; - while (ccNum != '') { + while (ccNum != ''){ chunks += ' ' + ccNum.substr(0,4); ccNum = ccNum.substr(4); } @@ -3574,6 +5437,7 @@ Form.Validator.addAllThese([ ]); + /* --- @@ -3592,10 +5456,10 @@ requires: - Core/Options - Core/Events - Core/Element.Event - - /Class.Binds - - /Class.Occlude - - /Element.Position - - /Element.Shortcuts + - Class.Binds + - Class.Occlude + - Element.Position + - Element.Shortcuts provides: [OverText] @@ -3610,10 +5474,11 @@ var OverText = new Class({ options: {/* textOverride: null, - onFocus: $empty() - onTextHide: $empty(textEl, inputEl), - onTextShow: $empty(textEl, inputEl), */ + onFocus: function(){}, + onTextHide: function(textEl, inputEl){}, + onTextShow: function(textEl, inputEl){}, */ element: 'label', + labelClass: 'overTxtLabel', positionOptions: { position: 'upperLeft', edge: 'upperLeft', @@ -3630,13 +5495,15 @@ var OverText = new Class({ property: 'OverText', initialize: function(element, options){ - this.element = document.id(element); + element = this.element = document.id(element); + if (this.occlude()) return this.occluded; this.setOptions(options); - this.attach(this.element); + + this.attach(element); OverText.instances.push(this); + if (this.options.poll) this.poll(); - return this; }, toElement: function(){ @@ -3644,40 +5511,44 @@ var OverText = new Class({ }, attach: function(){ - var val = this.options.textOverride || this.element.get('alt') || this.element.get('title'); - if (!val) return; - this.text = new Element(this.options.element, { - 'class': 'overTxtLabel', + var element = this.element, + options = this.options, + value = options.textOverride || element.get('alt') || element.get('title'); + + if (!value) return this; + + var text = this.text = new Element(options.element, { + 'class': options.labelClass, styles: { lineHeight: 'normal', position: 'absolute', cursor: 'text' }, - html: val, + html: value, events: { - click: this.hide.pass(this.options.element == 'label', this) + click: this.hide.pass(options.element == 'label', this) } - }).inject(this.element, 'after'); - if (this.options.element == 'label') { - if (!this.element.get('id')) this.element.set('id', 'input_' + new Date().getTime()); - this.text.set('for', this.element.get('id')); + }).inject(element, 'after'); + + if (options.element == 'label'){ + if (!element.get('id')) element.set('id', 'input_' + String.uniqueID()); + text.set('for', element.get('id')); } - if (this.options.wrap) { - this.textHolder = new Element('div', { + if (options.wrap){ + this.textHolder = new Element('div.overTxtWrapper', { styles: { lineHeight: 'normal', position: 'relative' - }, - 'class':'overTxtWrapper' - }).adopt(this.text).inject(this.element, 'before'); + } + }).grab(text).inject(element, 'before'); } return this.enable(); }, destroy: function(){ - this.element.eliminate('OverTextDiv').eliminate('OverText'); + this.element.eliminate(this.property); // Class.Occlude storage this.disable(); if (this.text) this.text.destroy(); if (this.textHolder) this.textHolder.destroy(); @@ -3708,8 +5579,8 @@ var OverText = new Class({ }, wrap: function(){ - if (this.options.element == 'label') { - if (!this.element.get('id')) this.element.set('id', 'input_' + new Date().getTime()); + if (this.options.element == 'label'){ + if (!this.element.get('id')) this.element.set('id', 'input_' + String.uniqueID()); this.text.set('for', this.element.get('id')); } }, @@ -3724,11 +5595,14 @@ var OverText = new Class({ //pause on focus //resumeon blur if (this.poller && !stop) return this; - var test = function(){ - if (!this.pollingPaused) this.assert(true); - }.bind(this); - if (stop) $clear(this.poller); - else this.poller = test.periodical(this.options.pollInterval, this); + if (stop){ + clearInterval(this.poller); + } else { + this.poller = (function(){ + if (!this.pollingPaused) this.assert(true); + }).periodical(this.options.pollInterval, this); + } + return this; }, @@ -3738,8 +5612,8 @@ var OverText = new Class({ }, focus: function(){ - if (this.text && (!this.text.isDisplayed() || this.element.get('disabled'))) return; - this.hide(); + if (this.text && (!this.text.isDisplayed() || this.element.get('disabled'))) return this; + return this.hide(); }, hide: function(suppressFocus, force){ @@ -3767,19 +5641,22 @@ var OverText = new Class({ return this; }, - assert: function(suppressFocus){ - this[this.test() ? 'show' : 'hide'](suppressFocus); + test: function(){ + return !this.element.get('value'); }, - test: function(){ - var v = this.element.get('value'); - return !v; + assert: function(suppressFocus){ + return this[this.test() ? 'show' : 'hide'](suppressFocus); }, reposition: function(){ this.assert(true); if (!this.element.isVisible()) return this.stopPolling().hide(); - if (this.text && this.test()) this.text.position($merge(this.options.positionOptions, {relativeTo: this.element})); + if (this.text && this.test()){ + this.text.position(Object.merge(this.options.positionOptions, { + relativeTo: this.element + })); + } return this; } @@ -3787,15 +5664,14 @@ var OverText = new Class({ OverText.instances = []; -$extend(OverText, { +Object.append(OverText, { - each: function(fn) { - return OverText.instances.map(function(ot, i){ - if (ot.element && ot.text) return fn.apply(OverText, [ot, i]); - return null; //the input or the text was destroyed + each: function(fn){ + return OverText.instances.each(function(ot, i){ + if (ot.element && ot.text) fn.call(OverText, ot, i); }); }, - + update: function(){ return OverText.each(function(ot){ @@ -3813,18 +5689,14 @@ $extend(OverText, { }, showAll: function(){ - return OverText.each(function(ot) { + return OverText.each(function(ot){ return ot.show(); }); } }); -if (window.Fx && Fx.Reveal) { - Fx.Reveal.implement({ - hideInputs: Browser.Engine.trident ? 'select, input, textarea, object, embed, .overTxtLabel' : false - }); -} + /* --- @@ -3930,9 +5802,8 @@ Fx.Accordion = new Class({ Extends: Fx.Elements, options: {/* - onActive: $empty(toggler, section), - onBackground: $empty(toggler, section), - */ + onActive: function(toggler, section){}, + onBackground: function(toggler, section){},*/ fixedHeight: false, fixedWidth: false, display: 0, @@ -3943,85 +5814,117 @@ Fx.Accordion = new Class({ alwaysHide: false, trigger: 'click', initialDisplayFx: true, - returnHeightToAuto: true + resetHeight: true }, initialize: function(){ + var defined = function(obj){ + return obj != null; + }; + var params = Array.link(arguments, { - 'container': Element.type, //deprecated - 'options': Object.type, - 'togglers': $defined, - 'elements': $defined + 'container': Type.isElement, //deprecated + 'options': Type.isObject, + 'togglers': defined, + 'elements': defined }); this.parent(params.elements, params.options); - this.togglers = $$(params.togglers); + + var options = this.options, + togglers = this.togglers = $$(params.togglers); + this.previous = -1; this.internalChain = new Chain(); - if (this.options.alwaysHide) this.options.wait = true; - if ($chk(this.options.show)){ - this.options.display = false; - this.previous = this.options.show; + + if (options.alwaysHide) this.options.link = 'chain'; + + if (options.show || this.options.show === 0){ + options.display = false; + this.previous = options.show; } - if (this.options.start){ - this.options.display = false; - this.options.show = false; + + if (options.start){ + options.display = false; + options.show = false; } - this.effects = {}; - if (this.options.opacity) this.effects.opacity = 'fullOpacity'; - if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth'; - if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight'; - for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]); + + var effects = this.effects = {}; + + if (options.opacity) effects.opacity = 'fullOpacity'; + if (options.width) effects.width = options.fixedWidth ? 'fullWidth' : 'offsetWidth'; + if (options.height) effects.height = options.fixedHeight ? 'fullHeight' : 'scrollHeight'; + + for (var i = 0, l = togglers.length; i < l; i++) this.addSection(togglers[i], this.elements[i]); + this.elements.each(function(el, i){ - if (this.options.show === i){ - this.fireEvent('active', [this.togglers[i], el]); + if (options.show === i){ + this.fireEvent('active', [togglers[i], el]); } else { - for (var fx in this.effects) el.setStyle(fx, 0); + for (var fx in effects) el.setStyle(fx, 0); } }, this); - if ($chk(this.options.display) || this.options.initialDisplayFx === false) this.display(this.options.display, this.options.initialDisplayFx); - if (this.options.fixedHeight !== false) this.options.returnHeightToAuto = false; + + if (options.display || options.display === 0 || options.initialDisplayFx === false){ + this.display(options.display, options.initialDisplayFx); + } + + if (options.fixedHeight !== false) options.resetHeight = false; this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain)); }, addSection: function(toggler, element){ toggler = document.id(toggler); element = document.id(element); - var test = this.togglers.contains(toggler); this.togglers.include(toggler); this.elements.include(element); - var idx = this.togglers.indexOf(toggler); - var displayer = this.display.bind(this, idx); - toggler.store('accordion:display', displayer); - toggler.addEvent(this.options.trigger, displayer); - if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'}); - if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'}); + + var togglers = this.togglers, + options = this.options, + test = togglers.contains(toggler), + idx = togglers.indexOf(toggler), + displayer = this.display.pass(idx, this); + + toggler.store('accordion:display', displayer) + .addEvent(options.trigger, displayer); + + if (options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'}); + if (options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'}); + element.fullOpacity = 1; - if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth; - if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight; + if (options.fixedWidth) element.fullWidth = options.fixedWidth; + if (options.fixedHeight) element.fullHeight = options.fixedHeight; element.setStyle('overflow', 'hidden'); - if (!test){ - for (var fx in this.effects) element.setStyle(fx, 0); + + if (!test) for (var fx in this.effects){ + element.setStyle(fx, 0); } return this; }, - removeSection: function(toggler, displayIndex) { - var idx = this.togglers.indexOf(toggler); - var element = this.elements[idx]; + removeSection: function(toggler, displayIndex){ + var togglers = this.togglers, + idx = togglers.indexOf(toggler), + element = this.elements[idx]; + var remover = function(){ - this.togglers.erase(toggler); + togglers.erase(toggler); this.elements.erase(element); this.detach(toggler); }.bind(this); - if (this.now == idx || displayIndex != undefined) this.display($pick(displayIndex, idx - 1 >= 0 ? idx - 1 : 0)).chain(remover); - else remover(); + + if (this.now == idx || displayIndex != null){ + this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover); + } else { + remover(); + } return this; }, detach: function(toggler){ - var remove = function(toggler) { + var remove = function(toggler){ toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display')); }.bind(this); + if (!toggler) this.togglers.each(remove); else remove(toggler); return this; @@ -4029,74 +5932,57 @@ Fx.Accordion = new Class({ display: function(index, useFx){ if (!this.check(index, useFx)) return this; - useFx = $pick(useFx, true); - index = ($type(index) == 'element') ? this.elements.indexOf(index) : index; - if (index == this.previous && !this.options.alwaysHide) return this; - if (this.options.returnHeightToAuto){ - var prev = this.elements[this.previous]; + + var obj = {}, + elements = this.elements, + options = this.options, + effects = this.effects; + + if (useFx == null) useFx = true; + if (typeOf(index) == 'element') index = elements.indexOf(index); + if (index == this.previous && !options.alwaysHide) return this; + + if (options.resetHeight){ + var prev = elements[this.previous]; if (prev && !this.selfHidden){ - for (var fx in this.effects){ - prev.setStyle(fx, prev[this.effects[fx]]); - } + for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]); } } - if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this; + + if ((this.timer && options.link == 'chain') || (index === this.previous && !options.alwaysHide)) return this; + this.previous = index; - var obj = {}; - this.elements.each(function(el, i){ + this.selfHidden = false; + + elements.each(function(el, i){ obj[i] = {}; var hide; if (i != index){ hide = true; - } else if (this.options.alwaysHide && ((el.offsetHeight > 0 && this.options.height) || el.offsetWidth > 0 && this.options.width)){ + } else if (options.alwaysHide && ((el.offsetHeight > 0 && options.height) || el.offsetWidth > 0 && options.width)){ hide = true; this.selfHidden = true; } this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]); - for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]]; + for (var fx in effects) obj[i][fx] = hide ? 0 : el[effects[fx]]; + if (!useFx && !hide && options.resetHeight) obj[i].height = 'auto'; }, this); + this.internalChain.clearChain(); this.internalChain.chain(function(){ - if (this.options.returnHeightToAuto && !this.selfHidden){ - var el = this.elements[index]; + if (options.resetHeight && !this.selfHidden){ + var el = elements[index]; if (el) el.setStyle('height', 'auto'); - }; + } }.bind(this)); - return useFx ? this.start(obj) : this.set(obj); + + return useFx ? this.start(obj) : this.set(obj).internalChain.callChain(); } }); -/* - Compatibility with 1.2.0 -*/ -var Accordion = new Class({ - Extends: Fx.Accordion, - initialize: function(){ - this.parent.apply(this, arguments); - var params = Array.link(arguments, {'container': Element.type}); - this.container = params.container; - }, - - addSection: function(toggler, element, pos){ - toggler = document.id(toggler); - element = document.id(element); - var test = this.togglers.contains(toggler); - var len = this.togglers.length; - if (len && (!test || pos)){ - pos = $pick(pos, len - 1); - toggler.inject(this.togglers[pos], 'before'); - element.inject(toggler, 'after'); - } else if (this.container && !test){ - toggler.inject(this.container); - element.inject(this.container); - } - return this.parent.apply(this, arguments); - } - -}); /* --- @@ -4138,7 +6024,7 @@ Fx.Move = new Class({ if (topLeft.top == 'auto' || topLeft.left == 'auto'){ element.setPosition(element.getPosition(element.getOffsetParent())); } - return this.parent(element.position($merge(this.options, destination, {returnPos: true}))); + return this.parent(element.position(Object.merge({}, this.options, destination, {returnPos: true}))); } }); @@ -4146,17 +6032,17 @@ Fx.Move = new Class({ Element.Properties.move = { set: function(options){ - var morph = this.retrieve('move'); - if (morph) morph.cancel(); - return this.eliminate('move').store('move:options', $extend({link: 'cancel'}, options)); + this.get('move').cancel().setOptions(options); + return this; }, - get: function(options){ - if (options || !this.retrieve('move')){ - if (options || !this.retrieve('move:options')) this.set('move', options); - this.store('move', new Fx.Move(this, this.retrieve('move:options'))); + get: function(){ + var move = this.retrieve('move'); + if (!move){ + move = new Fx.Move(this, {link: 'cancel'}); + this.store('move', move); } - return this.retrieve('move'); + return move; } }; @@ -4171,402 +6057,6 @@ Element.implement({ }); -/* ---- - -script: Fx.Reveal.js - -name: Fx.Reveal - -description: Defines Fx.Reveal, a class that shows and hides elements with a transition. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Fx.Morph - - /Element.Shortcuts - - /Element.Measure - -provides: [Fx.Reveal] - -... -*/ - -Fx.Reveal = new Class({ - - Extends: Fx.Morph, - - options: {/* - onShow: $empty(thisElement), - onHide: $empty(thisElement), - onComplete: $empty(thisElement), - heightOverride: null, - widthOverride: null, */ - link: 'cancel', - styles: ['padding', 'border', 'margin'], - transitionOpacity: !Browser.Engine.trident4, - mode: 'vertical', - display: function(){ - return this.element.get('tag') != 'tr' ? 'block' : 'table-row'; - }, - hideInputs: Browser.Engine.trident ? 'select, input, textarea, object, embed' : false, - opacity: 1 - }, - - dissolve: function(){ - try { - if (!this.hiding && !this.showing){ - if (this.element.getStyle('display') != 'none'){ - this.hiding = true; - this.showing = false; - this.hidden = true; - this.cssText = this.element.style.cssText; - var startStyles = this.element.getComputedSize({ - styles: this.options.styles, - mode: this.options.mode - }); - this.element.setStyle('display', $lambda(this.options.display).apply(this)); - if (this.options.transitionOpacity) startStyles.opacity = this.options.opacity; - var zero = {}; - $each(startStyles, function(style, name){ - zero[name] = [style, 0]; - }, this); - this.element.setStyle('overflow', 'hidden'); - var hideThese = this.options.hideInputs ? this.element.getElements(this.options.hideInputs) : null; - this.$chain.unshift(function(){ - if (this.hidden){ - this.hiding = false; - $each(startStyles, function(style, name){ - startStyles[name] = style; - }, this); - this.element.style.cssText = this.cssText; - this.element.setStyle('display', 'none'); - if (hideThese) hideThese.setStyle('visibility', 'visible'); - } - this.fireEvent('hide', this.element); - this.callChain(); - }.bind(this)); - if (hideThese) hideThese.setStyle('visibility', 'hidden'); - this.start(zero); - } else { - this.callChain.delay(10, this); - this.fireEvent('complete', this.element); - this.fireEvent('hide', this.element); - } - } else if (this.options.link == 'chain'){ - this.chain(this.dissolve.bind(this)); - } else if (this.options.link == 'cancel' && !this.hiding){ - this.cancel(); - this.dissolve(); - } - } catch(e){ - this.hiding = false; - this.element.setStyle('display', 'none'); - this.callChain.delay(10, this); - this.fireEvent('complete', this.element); - this.fireEvent('hide', this.element); - } - return this; - }, - - reveal: function(){ - try { - if (!this.showing && !this.hiding){ - if (this.element.getStyle('display') == 'none'){ - this.showing = true; - this.hiding = this.hidden = false; - var startStyles; - this.cssText = this.element.style.cssText; - //toggle display, but hide it - this.element.measure(function(){ - //create the styles for the opened/visible state - startStyles = this.element.getComputedSize({ - styles: this.options.styles, - mode: this.options.mode - }); - }.bind(this)); - $each(startStyles, function(style, name){ - startStyles[name] = style; - }); - //if we're overridding height/width - if ($chk(this.options.heightOverride)) startStyles.height = this.options.heightOverride.toInt(); - if ($chk(this.options.widthOverride)) startStyles.width = this.options.widthOverride.toInt(); - if (this.options.transitionOpacity) { - this.element.setStyle('opacity', 0); - startStyles.opacity = this.options.opacity; - } - //create the zero state for the beginning of the transition - var zero = { - height: 0, - display: $lambda(this.options.display).apply(this) - }; - $each(startStyles, function(style, name){ zero[name] = 0; }); - //set to zero - this.element.setStyles($merge(zero, {overflow: 'hidden'})); - //hide inputs - var hideThese = this.options.hideInputs ? this.element.getElements(this.options.hideInputs) : null; - if (hideThese) hideThese.setStyle('visibility', 'hidden'); - //start the effect - this.start(startStyles); - this.$chain.unshift(function(){ - this.element.style.cssText = this.cssText; - this.element.setStyle('display', $lambda(this.options.display).apply(this)); - if (!this.hidden) this.showing = false; - if (hideThese) hideThese.setStyle('visibility', 'visible'); - this.callChain(); - this.fireEvent('show', this.element); - }.bind(this)); - } else { - this.callChain(); - this.fireEvent('complete', this.element); - this.fireEvent('show', this.element); - } - } else if (this.options.link == 'chain'){ - this.chain(this.reveal.bind(this)); - } else if (this.options.link == 'cancel' && !this.showing){ - this.cancel(); - this.reveal(); - } - } catch(e){ - this.element.setStyles({ - display: $lambda(this.options.display).apply(this), - visiblity: 'visible', - opacity: this.options.opacity - }); - this.showing = false; - this.callChain.delay(10, this); - this.fireEvent('complete', this.element); - this.fireEvent('show', this.element); - } - return this; - }, - - toggle: function(){ - if (this.element.getStyle('display') == 'none'){ - this.reveal(); - } else { - this.dissolve(); - } - return this; - }, - - cancel: function(){ - this.parent.apply(this, arguments); - this.element.style.cssText = this.cssText; - this.hiding = false; - this.showing = false; - return this; - } - -}); - -Element.Properties.reveal = { - - set: function(options){ - var reveal = this.retrieve('reveal'); - if (reveal) reveal.cancel(); - return this.eliminate('reveal').store('reveal:options', options); - }, - - get: function(options){ - if (options || !this.retrieve('reveal')){ - if (options || !this.retrieve('reveal:options')) this.set('reveal', options); - this.store('reveal', new Fx.Reveal(this, this.retrieve('reveal:options'))); - } - return this.retrieve('reveal'); - } - -}; - -Element.Properties.dissolve = Element.Properties.reveal; - -Element.implement({ - - reveal: function(options){ - this.get('reveal', options).reveal(); - return this; - }, - - dissolve: function(options){ - this.get('reveal', options).dissolve(); - return this; - }, - - nix: function(){ - var params = Array.link(arguments, {destroy: Boolean.type, options: Object.type}); - this.get('reveal', params.options).dissolve().chain(function(){ - this[params.destroy ? 'destroy' : 'dispose'](); - }.bind(this)); - return this; - }, - - wink: function(){ - var params = Array.link(arguments, {duration: Number.type, options: Object.type}); - var reveal = this.get('reveal', params.options); - reveal.reveal().chain(function(){ - (function(){ - reveal.dissolve(); - }).delay(params.duration || 2000); - }); - } - - -}); - -/* ---- - -script: Fx.Scroll.js - -name: Fx.Scroll - -description: Effect to smoothly scroll any element, including the window. - -license: MIT-style license - -authors: - - Valerio Proietti - -requires: - - Core/Fx - - Core/Element.Event - - Core/Element.Dimensions - - /MooTools.More - -provides: [Fx.Scroll] - -... -*/ - -Fx.Scroll = new Class({ - - Extends: Fx, - - options: { - offset: {x: 0, y: 0}, - wheelStops: true - }, - - initialize: function(element, options){ - this.element = this.subject = document.id(element); - this.parent(options); - var cancel = this.cancel.bind(this, false); - - if ($type(this.element) != 'element') this.element = document.id(this.element.getDocument().body); - - var stopper = this.element; - - if (this.options.wheelStops){ - this.addEvent('start', function(){ - stopper.addEvent('mousewheel', cancel); - }, true); - this.addEvent('complete', function(){ - stopper.removeEvent('mousewheel', cancel); - }, true); - } - }, - - set: function(){ - var now = Array.flatten(arguments); - if (Browser.Engine.gecko) now = [Math.round(now[0]), Math.round(now[1])]; - this.element.scrollTo(now[0] + this.options.offset.x, now[1] + this.options.offset.y); - }, - - compute: function(from, to, delta){ - return [0, 1].map(function(i){ - return Fx.compute(from[i], to[i], delta); - }); - }, - - start: function(x, y){ - if (!this.check(x, y)) return this; - var scrollSize = this.element.getScrollSize(), - scroll = this.element.getScroll(), - values = {x: x, y: y}; - for (var z in values){ - var max = scrollSize[z]; - if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z] : max; - else values[z] = scroll[z]; - values[z] += this.options.offset[z]; - } - return this.parent([scroll.x, scroll.y], [values.x, values.y]); - }, - - toTop: function(){ - return this.start(false, 0); - }, - - toLeft: function(){ - return this.start(0, false); - }, - - toRight: function(){ - return this.start('right', false); - }, - - toBottom: function(){ - return this.start(false, 'bottom'); - }, - - toElement: function(el){ - var position = document.id(el).getPosition(this.element); - return this.start(position.x, position.y); - }, - - scrollIntoView: function(el, axes, offset){ - axes = axes ? $splat(axes) : ['x','y']; - var to = {}; - el = document.id(el); - var pos = el.getPosition(this.element); - var size = el.getSize(); - var scroll = this.element.getScroll(); - var containerSize = this.element.getSize(); - var edge = { - x: pos.x + size.x, - y: pos.y + size.y - }; - ['x','y'].each(function(axis) { - if (axes.contains(axis)) { - if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis]; - if (pos[axis] < scroll[axis]) to[axis] = pos[axis]; - } - if (to[axis] == null) to[axis] = scroll[axis]; - if (offset && offset[axis]) to[axis] = to[axis] + offset[axis]; - }, this); - if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); - return this; - }, - - scrollToCenter: function(el, axes, offset){ - axes = axes ? $splat(axes) : ['x', 'y']; - el = $(el); - var to = {}, - pos = el.getPosition(this.element), - size = el.getSize(), - scroll = this.element.getScroll(), - containerSize = this.element.getSize(), - edge = { - x: pos.x + size.x, - y: pos.y + size.y - }; - - ['x','y'].each(function(axis){ - if(axes.contains(axis)){ - to[axis] = pos[axis] - (containerSize[axis] - size[axis])/2; - } - if(to[axis] == null) to[axis] = scroll[axis]; - if(offset && offset[axis]) to[axis] = to[axis] + offset[axis]; - }, this); - if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); - return this; - } - -}); - - /* --- @@ -4603,23 +6093,31 @@ Fx.Slide = new Class({ }, initialize: function(element, options){ - this.addEvent('complete', function(){ - this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0); - if (this.open && this.options.resetHeight) this.wrapper.setStyle('height', ''); - if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper); - }, true); - this.element = this.subject = document.id(element); + element = this.element = this.subject = document.id(element); this.parent(options); - var wrapper = this.element.retrieve('wrapper'); - var styles = this.element.getStyles('margin', 'position', 'overflow'); - if (this.options.hideOverflow) styles = $extend(styles, {overflow: 'hidden'}); - if (this.options.wrapper) wrapper = document.id(this.options.wrapper).setStyles(styles); - this.wrapper = wrapper || new Element('div', { + options = this.options; + + var wrapper = element.retrieve('wrapper'), + styles = element.getStyles('margin', 'position', 'overflow'); + + if (options.hideOverflow) styles = Object.append(styles, {overflow: 'hidden'}); + if (options.wrapper) wrapper = document.id(options.wrapper).setStyles(styles); + + if (!wrapper) wrapper = new Element('div', { styles: styles - }).wraps(this.element); - this.element.store('wrapper', this.wrapper).setStyle('margin', 0); + }).wraps(element); + + element.store('wrapper', wrapper).setStyle('margin', 0); + if (element.getStyle('overflow') == 'visible') element.setStyle('overflow', 'hidden'); + this.now = []; this.open = true; + this.wrapper = wrapper; + + this.addEvent('complete', function(){ + this.open = (wrapper['offset' + this.layout.capitalize()] != 0); + if (this.open && this.options.resetHeight) wrapper.setStyle('height', ''); + }, true); }, vertical: function(){ @@ -4649,11 +6147,13 @@ Fx.Slide = new Class({ start: function(how, mode){ if (!this.check(how, mode)) return this; this[mode || this.options.mode](); - var margin = this.element.getStyle(this.margin).toInt(); - var layout = this.wrapper.getStyle(this.layout).toInt(); - var caseIn = [[margin, layout], [0, this.offset]]; - var caseOut = [[margin, layout], [-this.offset, 0]]; - var start; + + var margin = this.element.getStyle(this.margin).toInt(), + layout = this.wrapper.getStyle(this.layout).toInt(), + caseIn = [[margin, layout], [0, this.offset]], + caseOut = [[margin, layout], [-this.offset, 0]], + start; + switch (how){ case 'in': start = caseIn; break; case 'out': start = caseOut; break; @@ -4691,17 +6191,17 @@ Fx.Slide = new Class({ Element.Properties.slide = { set: function(options){ - var slide = this.retrieve('slide'); - if (slide) slide.cancel(); - return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options)); + this.get('slide').cancel().setOptions(options); + return this; }, - get: function(options){ - if (options || !this.retrieve('slide')){ - if (options || !this.retrieve('slide:options')) this.set('slide', options); - this.store('slide', new Fx.Slide(this, this.retrieve('slide:options'))); + get: function(){ + var slide = this.retrieve('slide'); + if (!slide){ + slide = new Fx.Slide(this, {link: 'cancel'}); + this.store('slide', slide); } - return this.retrieve('slide'); + return slide; } }; @@ -4729,6 +6229,179 @@ Element.implement({ }); +/* +--- + +script: Fx.Scroll.js + +name: Fx.Scroll + +description: Effect to smoothly scroll any element, including the window. + +license: MIT-style license + +authors: + - Valerio Proietti + +requires: + - Core/Fx + - Core/Element.Event + - Core/Element.Dimensions + - /MooTools.More + +provides: [Fx.Scroll] + +... +*/ + +(function(){ + +Fx.Scroll = new Class({ + + Extends: Fx, + + options: { + offset: {x: 0, y: 0}, + wheelStops: true + }, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + + if (typeOf(this.element) != 'element') this.element = document.id(this.element.getDocument().body); + + if (this.options.wheelStops){ + var stopper = this.element, + cancel = this.cancel.pass(false, this); + this.addEvent('start', function(){ + stopper.addEvent('mousewheel', cancel); + }, true); + this.addEvent('complete', function(){ + stopper.removeEvent('mousewheel', cancel); + }, true); + } + }, + + set: function(){ + var now = Array.flatten(arguments); + if (Browser.firefox) now = [Math.round(now[0]), Math.round(now[1])]; // not needed anymore in newer firefox versions + this.element.scrollTo(now[0], now[1]); + return this; + }, + + compute: function(from, to, delta){ + return [0, 1].map(function(i){ + return Fx.compute(from[i], to[i], delta); + }); + }, + + start: function(x, y){ + if (!this.check(x, y)) return this; + var scroll = this.element.getScroll(); + return this.parent([scroll.x, scroll.y], [x, y]); + }, + + calculateScroll: function(x, y){ + var element = this.element, + scrollSize = element.getScrollSize(), + scroll = element.getScroll(), + size = element.getSize(), + offset = this.options.offset, + values = {x: x, y: y}; + + for (var z in values){ + if (!values[z] && values[z] !== 0) values[z] = scroll[z]; + if (typeOf(values[z]) != 'number') values[z] = scrollSize[z] - size[z]; + values[z] += offset[z]; + } + + return [values.x, values.y]; + }, + + toTop: function(){ + return this.start.apply(this, this.calculateScroll(false, 0)); + }, + + toLeft: function(){ + return this.start.apply(this, this.calculateScroll(0, false)); + }, + + toRight: function(){ + return this.start.apply(this, this.calculateScroll('right', false)); + }, + + toBottom: function(){ + return this.start.apply(this, this.calculateScroll(false, 'bottom')); + }, + + toElement: function(el, axes){ + axes = axes ? Array.from(axes) : ['x', 'y']; + var scroll = isBody(this.element) ? {x: 0, y: 0} : this.element.getScroll(); + var position = Object.map(document.id(el).getPosition(this.element), function(value, axis){ + return axes.contains(axis) ? value + scroll[axis] : false; + }); + return this.start.apply(this, this.calculateScroll(position.x, position.y)); + }, + + toElementEdge: function(el, axes, offset){ + axes = axes ? Array.from(axes) : ['x', 'y']; + el = document.id(el); + var to = {}, + position = el.getPosition(this.element), + size = el.getSize(), + scroll = this.element.getScroll(), + containerSize = this.element.getSize(), + edge = { + x: position.x + size.x, + y: position.y + size.y + }; + + ['x', 'y'].each(function(axis){ + if (axes.contains(axis)){ + if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis]; + if (position[axis] < scroll[axis]) to[axis] = position[axis]; + } + if (to[axis] == null) to[axis] = scroll[axis]; + if (offset && offset[axis]) to[axis] = to[axis] + offset[axis]; + }, this); + + if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); + return this; + }, + + toElementCenter: function(el, axes, offset){ + axes = axes ? Array.from(axes) : ['x', 'y']; + el = document.id(el); + var to = {}, + position = el.getPosition(this.element), + size = el.getSize(), + scroll = this.element.getScroll(), + containerSize = this.element.getSize(); + + ['x', 'y'].each(function(axis){ + if (axes.contains(axis)){ + to[axis] = position[axis] - (containerSize[axis] - size[axis]) / 2; + } + if (to[axis] == null) to[axis] = scroll[axis]; + if (offset && offset[axis]) to[axis] = to[axis] + offset[axis]; + }, this); + + if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); + return this; + } + +}); + + + +function isBody(element){ + return (/^(?:body|html)$/i).test(element.tagName); +} + +})(); + + /* --- @@ -4744,7 +6417,7 @@ authors: - Valerio Proietti requires: - - Core/Selectors + - Core/Slick.Finder - /Fx.Scroll provides: [Fx.SmoothScroll] @@ -4752,45 +6425,55 @@ provides: [Fx.SmoothScroll] ... */ -var SmoothScroll = Fx.SmoothScroll = new Class({ +Fx.SmoothScroll = new Class({ Extends: Fx.Scroll, + options: { + axes: ['x', 'y'] + }, + initialize: function(options, context){ context = context || document; this.doc = context.getDocument(); - var win = context.getWindow(); this.parent(this.doc, options); - this.links = $$(this.options.links || this.doc.links); - var location = win.location.href.match(/^[^#]*/)[0] + '#'; - this.links.each(function(link){ - if (link.href.indexOf(location) != 0) {return;} + + var win = context.getWindow(), + location = win.location.href.match(/^[^#]*/)[0] + '#', + links = $$(this.options.links || this.doc.links); + + links.each(function(link){ + if (link.href.indexOf(location) != 0) return; var anchor = link.href.substr(location.length); if (anchor) this.useLink(link, anchor); }, this); - if (!Browser.Engine.webkit419) { - this.addEvent('complete', function(){ - win.location.hash = this.anchor; - }, true); - } + + this.addEvent('complete', function(){ + win.location.hash = this.anchor; + this.element.scrollTo(this.to[0], this.to[1]); + }, true); }, useLink: function(link, anchor){ - var el; + link.addEvent('click', function(event){ - if (el !== false && !el) el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']'); - if (el) { - event.preventDefault(); - this.anchor = anchor; - this.toElement(el).chain(function(){ - this.fireEvent('scrolledTo', [link, el]); - }.bind(this)); - link.blur(); - } + var el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']'); + if (!el) return; + + event.preventDefault(); + this.toElement(el, this.options.axes).chain(function(){ + this.fireEvent('scrolledTo', [link, el]); + }.bind(this)); + + this.anchor = anchor; + }.bind(this)); + + return this; } }); + /* --- @@ -4837,13 +6520,16 @@ Fx.Sort = new Class({ }); }, - sort: function(newOrder){ - if ($type(newOrder) != 'array') return false; + sort: function(){ + if (!this.check(arguments)) return this; + var newOrder = Array.flatten(arguments); + var top = 0, left = 0, next = {}, zero = {}, vert = this.options.mode == 'vertical'; + var current = this.elements.map(function(el, index){ var size = el.getComputedSize({styles: ['border', 'padding', 'margin']}); var val; @@ -4868,6 +6554,7 @@ Fx.Sort = new Class({ zero[index][plane] = start || 0; return val; }, this); + this.set(zero); newOrder = newOrder.map(function(i){ return i.toInt(); }); if (newOrder.length != this.elements.length){ @@ -4877,8 +6564,9 @@ Fx.Sort = new Class({ if (newOrder.length > this.elements.length) newOrder.splice(this.elements.length-1, newOrder.length - this.elements.length); } - var margin = top = left = 0; - newOrder.each(function(item, index){ + var margin = 0; + top = left = 0; + newOrder.each(function(item){ var newPos = {}; if (vert){ newPos.top = top - current[item].top - margin; @@ -4891,11 +6579,12 @@ Fx.Sort = new Class({ next[item]=newPos; }, this); var mapped = {}; - $A(newOrder).sort().each(function(index){ + Array.clone(newOrder).sort().each(function(index){ mapped[index] = next[index]; }); this.start(mapped); this.currentOrder = newOrder; + return this; }, @@ -4923,6 +6612,10 @@ Fx.Sort = new Class({ }); }, + getCurrentOrder: function(){ + return this.currentOrder; + }, + forward: function(){ return this.sort(this.getDefaultOrder()); }, @@ -4942,17 +6635,19 @@ Fx.Sort = new Class({ }, swap: function(one, two){ - if ($type(one) == 'element') one = this.elements.indexOf(one); - if ($type(two) == 'element') two = this.elements.indexOf(two); - - var newOrder = $A(this.currentOrder); + if (typeOf(one) == 'element') one = this.elements.indexOf(one); + if (typeOf(two) == 'element') two = this.elements.indexOf(two); + + var newOrder = Array.clone(this.currentOrder); newOrder[this.currentOrder.indexOf(one)] = two; newOrder[this.currentOrder.indexOf(two)] = one; + return this.sort(newOrder); } }); + /* --- @@ -4987,12 +6682,12 @@ var Drag = new Class({ Implements: [Events, Options], options: {/* - onBeforeStart: $empty(thisElement), - onStart: $empty(thisElement, event), - onSnap: $empty(thisElement) - onDrag: $empty(thisElement, event), - onCancel: $empty(thisElement), - onComplete: $empty(thisElement, event),*/ + onBeforeStart: function(thisElement){}, + onStart: function(thisElement, event){}, + onSnap: function(thisElement){}, + onDrag: function(thisElement, event){}, + onCancel: function(thisElement){}, + onComplete: function(thisElement, event){},*/ snap: 6, unit: 'px', grid: false, @@ -5006,16 +6701,28 @@ var Drag = new Class({ }, initialize: function(){ - var params = Array.link(arguments, {'options': Object.type, 'element': $defined}); + var params = Array.link(arguments, { + 'options': Type.isObject, + 'element': function(obj){ + return obj != null; + } + }); + this.element = document.id(params.element); this.document = this.element.getDocument(); this.setOptions(params.options || {}); - var htype = $type(this.options.handle); + var htype = typeOf(this.options.handle); this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element; this.mouse = {'now': {}, 'pos': {}}; this.value = {'start': {}, 'now': {}}; - this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown'; + this.selection = (Browser.ie) ? 'selectstart' : 'mousedown'; + + + if (Browser.ie && !Drag.ondragstartFixed){ + document.ondragstart = Function.from(false); + Drag.ondragstartFixed = true; + } this.bound = { start: this.start.bind(this), @@ -5023,7 +6730,7 @@ var Drag = new Class({ drag: this.drag.bind(this), stop: this.stop.bind(this), cancel: this.cancel.bind(this), - eventStop: $lambda(false) + eventStop: Function.from(false) }; this.attach(); }, @@ -5039,51 +6746,58 @@ var Drag = new Class({ }, start: function(event){ + var options = this.options; + if (event.rightClick) return; - if (this.options.preventDefault) event.preventDefault(); - if (this.options.stopPropagation) event.stopPropagation(); + + if (options.preventDefault) event.preventDefault(); + if (options.stopPropagation) event.stopPropagation(); this.mouse.start = event.page; + this.fireEvent('beforeStart', this.element); - var limit = this.options.limit; + + var limit = options.limit; this.limit = {x: [], y: []}; - var styles = this.element.getStyles('left', 'right', 'top', 'bottom'); - this._invert = { - x: this.options.modifiers.x == 'left' && styles.left == 'auto' && - !isNaN(styles.right.toInt()) && (this.options.modifiers.x = 'right'), - y: this.options.modifiers.y == 'top' && styles.top == 'auto' && - !isNaN(styles.bottom.toInt()) && (this.options.modifiers.y = 'bottom') - }; var z, coordinates; - for (z in this.options.modifiers){ - if (!this.options.modifiers[z]) continue; + for (z in options.modifiers){ + if (!options.modifiers[z]) continue; - var style = this.element.getStyle(this.options.modifiers[z]); + var style = this.element.getStyle(options.modifiers[z]); // Some browsers (IE and Opera) don't always return pixels. if (style && !style.match(/px$/)){ if (!coordinates) coordinates = this.element.getCoordinates(this.element.getOffsetParent()); - style = coordinates[this.options.modifiers[z]]; + style = coordinates[options.modifiers[z]]; } - if (this.options.style) this.value.now[z] = (style || 0).toInt(); - else this.value.now[z] = this.element[this.options.modifiers[z]]; + if (options.style) this.value.now[z] = (style || 0).toInt(); + else this.value.now[z] = this.element[options.modifiers[z]]; - if (this.options.invert) this.value.now[z] *= -1; - if (this._invert[z]) this.value.now[z] *= -1; + if (options.invert) this.value.now[z] *= -1; this.mouse.pos[z] = event.page[z] - this.value.now[z]; if (limit && limit[z]){ - for (var i = 2; i--; i){ - if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])(); + var i = 2; + while (i--){ + var limitZI = limit[z][i]; + if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI; } } } - if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid}; - this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel}); - this.document.addEvent(this.selection, this.bound.eventStop); + if (typeOf(this.options.grid) == 'number') this.options.grid = { + x: this.options.grid, + y: this.options.grid + }; + + var events = { + mousemove: this.bound.check, + mouseup: this.bound.cancel + }; + events[this.selection] = this.bound.eventStop; + this.document.addEvents(events); }, check: function(event){ @@ -5100,33 +6814,39 @@ var Drag = new Class({ }, drag: function(event){ - if (this.options.preventDefault) event.preventDefault(); + var options = this.options; + + if (options.preventDefault) event.preventDefault(); this.mouse.now = event.page; - for (var z in this.options.modifiers){ - if (!this.options.modifiers[z]) continue; + + for (var z in options.modifiers){ + if (!options.modifiers[z]) continue; this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; - if (this.options.invert) this.value.now[z] *= -1; - if (this._invert[z]) this.value.now[z] *= -1; - if (this.options.limit && this.limit[z]){ - if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ + + if (options.invert) this.value.now[z] *= -1; + + if (options.limit && this.limit[z]){ + if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){ this.value.now[z] = this.limit[z][1]; - } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ + } else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){ this.value.now[z] = this.limit[z][0]; } } - if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]); - if (this.options.style) { - this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); - } else { - this.element[this.options.modifiers[z]] = this.value.now[z]; - } + + if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]); + + if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit); + else this.element[options.modifiers[z]] = this.value.now[z]; } + this.fireEvent('drag', [this.element, event]); }, cancel: function(event){ - this.document.removeEvent('mousemove', this.bound.check); - this.document.removeEvent('mouseup', this.bound.cancel); + this.document.removeEvents({ + mousemove: this.bound.check, + mouseup: this.bound.cancel + }); if (event){ this.document.removeEvent(this.selection, this.bound.eventStop); this.fireEvent('cancel', this.element); @@ -5134,9 +6854,12 @@ var Drag = new Class({ }, stop: function(event){ - this.document.removeEvent(this.selection, this.bound.eventStop); - this.document.removeEvent('mousemove', this.bound.drag); - this.document.removeEvent('mouseup', this.bound.stop); + var events = { + mousemove: this.bound.drag, + mouseup: this.bound.stop + }; + events[this.selection] = this.bound.eventStop; + this.document.removeEvents(events); if (event) this.fireEvent('complete', [this.element, event]); } @@ -5145,7 +6868,13 @@ var Drag = new Class({ Element.implement({ makeResizable: function(options){ - var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options)); + var drag = new Drag(this, Object.merge({ + modifiers: { + x: 'width', + y: 'height' + } + }, options)); + this.store('resizer', drag); return drag.addEvent('drag', function(){ this.fireEvent('resize', drag); @@ -5187,9 +6916,9 @@ Drag.Move = new Class({ Extends: Drag, options: {/* - onEnter: $empty(thisElement, overed), - onLeave: $empty(thisElement, overed), - onDrop: $empty(thisElement, overed, event),*/ + onEnter: function(thisElement, overed){}, + onLeave: function(thisElement, overed){}, + onDrop: function(thisElement, overed, event){},*/ droppables: [], container: false, precalculate: false, @@ -5200,68 +6929,63 @@ Drag.Move = new Class({ initialize: function(element, options){ this.parent(element, options); element = this.element; - + this.droppables = $$(this.options.droppables); this.container = document.id(this.options.container); - - if (this.container && $type(this.container) != 'element') + + if (this.container && typeOf(this.container) != 'element') this.container = document.id(this.container.getDocument().body); if (this.options.style){ - if (this.options.modifiers.x == "left" && this.options.modifiers.y == "top"){ - var parentStyles, - parent = document.id(element.getOffsetParent()); - if (parent) parentStyles = parent.getStyles('border-top-width', 'border-left-width'); - - var styles = element.getStyles('left', 'top'); + if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){ + var parent = element.getOffsetParent(), + styles = element.getStyles('left', 'top'); if (parent && (styles.left == 'auto' || styles.top == 'auto')){ - var parentPosition = element.getPosition(parent); - parentPosition.x = parentPosition.x - (parentStyles['border-left-width'] ? parentStyles['border-left-width'].toInt() : 0); - parentPosition.y = parentPosition.y - (parentStyles['border-top-width'] ? parentStyles['border-top-width'].toInt() : 0); - element.setPosition(parentPosition); + element.setPosition(element.getPosition(parent)); } } + if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute'); } this.addEvent('start', this.checkDroppables, true); - this.overed = null; }, start: function(event){ if (this.container) this.options.limit = this.calculateLimit(); - + if (this.options.precalculate){ this.positions = this.droppables.map(function(el){ return el.getCoordinates(); }); } - + this.parent(event); }, - + calculateLimit: function(){ - var offsetParent = document.id(this.element.getOffsetParent()) || document.body, - containerCoordinates = this.container.getCoordinates(offsetParent), - containerBorder = {}, + var element = this.element, + container = this.container, + + offsetParent = document.id(element.getOffsetParent()) || document.body, + containerCoordinates = container.getCoordinates(offsetParent), elementMargin = {}, elementBorder = {}, containerMargin = {}, - offsetParentBorder = {}, + containerBorder = {}, offsetParentPadding = {}; ['top', 'right', 'bottom', 'left'].each(function(pad){ - containerBorder[pad] = this.container.getStyle('border-' + pad).toInt(); - elementBorder[pad] = this.element.getStyle('border-' + pad).toInt(); - elementMargin[pad] = this.element.getStyle('margin-' + pad).toInt(); - containerMargin[pad] = this.container.getStyle('margin-' + pad).toInt(); + elementMargin[pad] = element.getStyle('margin-' + pad).toInt(); + elementBorder[pad] = element.getStyle('border-' + pad).toInt(); + containerMargin[pad] = container.getStyle('margin-' + pad).toInt(); + containerBorder[pad] = container.getStyle('border-' + pad).toInt(); offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt(); - offsetParentBorder[pad] = offsetParent.getStyle('border-' + pad).toInt(); }, this); - var width = this.element.offsetWidth + elementMargin.left + elementMargin.right, - height = this.element.offsetHeight + elementMargin.top + elementMargin.bottom, + var width = element.offsetWidth + elementMargin.left + elementMargin.right, + height = element.offsetHeight + elementMargin.top + elementMargin.bottom, left = 0, top = 0, right = containerCoordinates.right - containerBorder.right - width, @@ -5274,49 +6998,59 @@ Drag.Move = new Class({ right += elementMargin.right; bottom += elementMargin.bottom; } - - if (this.element.getStyle('position') == 'relative'){ - var coords = this.element.getCoordinates(offsetParent); - coords.left -= this.element.getStyle('left').toInt(); - coords.top -= this.element.getStyle('top').toInt(); - - left += containerBorder.left - coords.left; - top += containerBorder.top - coords.top; + + if (element.getStyle('position') == 'relative'){ + var coords = element.getCoordinates(offsetParent); + coords.left -= element.getStyle('left').toInt(); + coords.top -= element.getStyle('top').toInt(); + + left -= coords.left; + top -= coords.top; + if (container.getStyle('position') != 'relative'){ + left += containerBorder.left; + top += containerBorder.top; + } right += elementMargin.left - coords.left; bottom += elementMargin.top - coords.top; - - if (this.container != offsetParent){ + + if (container != offsetParent){ left += containerMargin.left + offsetParentPadding.left; - top += (Browser.Engine.trident4 ? 0 : containerMargin.top) + offsetParentPadding.top; + top += ((Browser.ie6 || Browser.ie7) ? 0 : containerMargin.top) + offsetParentPadding.top; } } else { left -= elementMargin.left; top -= elementMargin.top; - if (this.container == offsetParent){ - right -= containerBorder.left; - bottom -= containerBorder.top; - } else { - left += containerCoordinates.left + containerBorder.left - offsetParentBorder.left; - top += containerCoordinates.top + containerBorder.top - offsetParentBorder.top; - right -= offsetParentBorder.left; - bottom -= offsetParentBorder.top; + if (container != offsetParent){ + left += containerCoordinates.left + containerBorder.left; + top += containerCoordinates.top + containerBorder.top; } } - + return { x: [left, right], y: [top, bottom] }; }, - checkAgainst: function(el, i){ - el = (this.positions) ? this.positions[i] : el.getCoordinates(); - var now = this.mouse.now; - return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top); + getDroppableCoordinates: function(element){ + var position = element.getCoordinates(); + if (element.getStyle('position') == 'fixed'){ + var scroll = window.getScroll(); + position.left += scroll.x; + position.right += scroll.x; + position.top += scroll.y; + position.bottom += scroll.y; + } + return position; }, checkDroppables: function(){ - var overed = this.droppables.filter(this.checkAgainst, this).getLast(); + var overed = this.droppables.filter(function(el, i){ + el = this.positions ? this.positions[i] : this.getDroppableCoordinates(el); + var now = this.mouse.now; + return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top); + }, this).getLast(); + if (this.overed != overed){ if (this.overed) this.fireEvent('leave', [this.element, this.overed]); if (overed) this.fireEvent('enter', [this.element, overed]); @@ -5381,12 +7115,11 @@ var Slider = new Class({ Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'], options: {/* - onTick: $empty(intPosition), - onChange: $empty(intStep), - onComplete: $empty(strStep),*/ + onTick: function(intPosition){}, + onChange: function(intStep){}, + onComplete: function(strStep){},*/ onTick: function(position){ - if (this.options.snap) position = this.toPosition(this.step); - this.knob.setStyle(this.property, position); + this.setKnobPosition(position); }, initialStep: 0, snap: false, @@ -5399,32 +7132,33 @@ var Slider = new Class({ initialize: function(element, knob, options){ this.setOptions(options); + options = this.options; this.element = document.id(element); - this.knob = document.id(knob); + knob = this.knob = document.id(knob); this.previousChange = this.previousEnd = this.step = -1; - var offset, limit = {}, modifiers = {'x': false, 'y': false}; - switch (this.options.mode){ + + var limit = {}, + modifiers = {x: false, y: false}; + + switch (options.mode){ case 'vertical': this.axis = 'y'; this.property = 'top'; - offset = 'offsetHeight'; + this.offset = 'offsetHeight'; break; case 'horizontal': this.axis = 'x'; this.property = 'left'; - offset = 'offsetWidth'; + this.offset = 'offsetWidth'; } - - this.full = this.element.measure(function(){ - this.half = this.knob[offset] / 2; - return this.element[offset] - this.knob[offset] + (this.options.offset * 2); - }.bind(this)); - - this.setRange(this.options.range); - this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset); + this.setSliderDimensions(); + this.setRange(options.range); + + if (knob.getStyle('position') == 'static') knob.setStyle('position', 'relative'); + knob.setStyle(this.property, -options.offset); modifiers[this.axis] = this.property; - limit[this.axis] = [- this.options.offset, this.full - this.options.offset]; + limit[this.axis] = [-options.offset, this.full - options.offset]; var dragOptions = { snap: 0, @@ -5435,7 +7169,7 @@ var Slider = new Class({ onBeforeStart: (function(){ this.isDragging = true; }).bind(this), - onCancel: function() { + onCancel: function(){ this.isDragging = false; }.bind(this), onComplete: function(){ @@ -5444,14 +7178,11 @@ var Slider = new Class({ this.end(); }.bind(this) }; - if (this.options.snap){ - dragOptions.grid = Math.ceil(this.stepWidth); - dragOptions.limit[this.axis][1] = this.full; - } + if (options.snap) this.setSnap(dragOptions); - this.drag = new Drag(this.knob, dragOptions); + this.drag = new Drag(knob, dragOptions); this.attach(); - if (this.options.initialStep != null) this.set(this.options.initialStep) + if (options.initialStep != null) this.set(options.initialStep); }, attach: function(){ @@ -5462,73 +7193,109 @@ var Slider = new Class({ }, detach: function(){ - this.element.removeEvent('mousedown', this.clickedElement); - this.element.removeEvent('mousewheel', this.scrolledElement); + this.element.removeEvent('mousedown', this.clickedElement) + .removeEvent('mousewheel', this.scrolledElement); this.drag.detach(); return this; }, + autosize: function(){ + this.setSliderDimensions() + .setKnobPosition(this.toPosition(this.step)); + this.drag.options.limit[this.axis] = [-this.options.offset, this.full - this.options.offset]; + if (this.options.snap) this.setSnap(); + return this; + }, + + setSnap: function(options){ + if (!options) options = this.drag.options; + options.grid = Math.ceil(this.stepWidth); + options.limit[this.axis][1] = this.full; + return this; + }, + + setKnobPosition: function(position){ + if (this.options.snap) position = this.toPosition(this.step); + this.knob.setStyle(this.property, position); + return this; + }, + + setSliderDimensions: function(){ + this.full = this.element.measure(function(){ + this.half = this.knob[this.offset] / 2; + return this.element[this.offset] - this.knob[this.offset] + (this.options.offset * 2); + }.bind(this)); + return this; + }, + set: function(step){ if (!((this.range > 0) ^ (step < this.min))) step = this.min; if (!((this.range > 0) ^ (step > this.max))) step = this.max; this.step = Math.round(step); - this.checkStep(); - this.fireEvent('tick', this.toPosition(this.step)); - this.end(); - return this; + return this.checkStep() + .fireEvent('tick', this.toPosition(this.step)) + .end(); }, - + setRange: function(range, pos){ - this.min = $pick(range[0], 0); - this.max = $pick(range[1], this.options.steps); + this.min = Array.pick([range[0], 0]); + this.max = Array.pick([range[1], this.options.steps]); this.range = this.max - this.min; this.steps = this.options.steps || this.full; this.stepSize = Math.abs(this.range) / this.steps; this.stepWidth = this.stepSize * this.full / Math.abs(this.range); - this.set($pick(pos, this.step).floor(this.min).max(this.max)); + if (range) this.set(Array.pick([pos, this.step]).floor(this.min).max(this.max)); return this; }, clickedElement: function(event){ if (this.isDragging || event.target == this.knob) return; - var dir = this.range < 0 ? -1 : 1; - var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half; - position = position.limit(-this.options.offset, this.full -this.options.offset); + var dir = this.range < 0 ? -1 : 1, + position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half; + + position = position.limit(-this.options.offset, this.full - this.options.offset); this.step = Math.round(this.min + dir * this.toStep(position)); - this.checkStep(); - this.fireEvent('tick', position); - this.end(); + + this.checkStep() + .fireEvent('tick', position) + .end(); }, scrolledElement: function(event){ var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0); - this.set(mode ? this.step - this.stepSize : this.step + this.stepSize); + this.set(this.step + (mode ? -1 : 1) * this.stepSize); event.stop(); }, draggedKnob: function(){ - var dir = this.range < 0 ? -1 : 1; - var position = this.drag.value.now[this.axis]; + var dir = this.range < 0 ? -1 : 1, + position = this.drag.value.now[this.axis]; + position = position.limit(-this.options.offset, this.full -this.options.offset); + this.step = Math.round(this.min + dir * this.toStep(position)); this.checkStep(); }, checkStep: function(){ - if (this.previousChange != this.step){ - this.previousChange = this.step; - this.fireEvent('change', this.step); + var step = this.step; + if (this.previousChange != step){ + this.previousChange = step; + this.fireEvent('change', step); } + return this; }, end: function(){ - if (this.previousEnd !== this.step){ - this.previousEnd = this.step; - this.fireEvent('complete', this.step + ''); + var step = this.step; + if (this.previousEnd !== step){ + this.previousEnd = step; + this.fireEvent('complete', step + ''); } + return this; }, toStep: function(position){ @@ -5558,6 +7325,7 @@ authors: - Tom Occhino requires: + - Core/Fx.Morph - /Drag.Move provides: [Sortables] @@ -5570,27 +7338,30 @@ var Sortables = new Class({ Implements: [Events, Options], options: {/* - onSort: $empty(element, clone), - onStart: $empty(element, clone), - onComplete: $empty(element),*/ - snap: 4, + onSort: function(element, clone){}, + onStart: function(element, clone){}, + onComplete: function(element){},*/ opacity: 1, clone: false, revert: false, handle: false, - constrain: false, - preventDefault: false + dragOptions: {} }, initialize: function(lists, options){ this.setOptions(options); + this.elements = []; this.lists = []; this.idle = true; this.addLists($$(document.id(lists) || lists)); + if (!this.options.clone) this.options.revert = false; - if (this.options.revert) this.effect = new Fx.Morph(null, $merge({duration: 250, link: 'cancel'}, this.options.revert)); + if (this.options.revert) this.effect = new Fx.Morph(null, Object.merge({ + duration: 250, + link: 'cancel' + }, this.options.revert)); }, attach: function(){ @@ -5606,7 +7377,9 @@ var Sortables = new Class({ addItems: function(){ Array.flatten(arguments).each(function(element){ this.elements.push(element); - var start = element.retrieve('sortables:start', this.start.bindWithEvent(this, element)); + var start = element.retrieve('sortables:start', function(event){ + this.start.call(this, event, element); + }.bind(this)); (this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start); }, this); return this; @@ -5614,7 +7387,7 @@ var Sortables = new Class({ addLists: function(){ Array.flatten(arguments).each(function(list){ - this.lists.push(list); + this.lists.include(list); this.addItems(list.getChildren()); }, this); return this; @@ -5625,7 +7398,7 @@ var Sortables = new Class({ this.elements.erase(element); var start = element.retrieve('sortables:start'); (this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start); - + return element; }, this)); }, @@ -5634,35 +7407,37 @@ var Sortables = new Class({ return $$(Array.flatten(arguments).map(function(list){ this.lists.erase(list); this.removeItems(list.getChildren()); - + return list; }, this)); }, getClone: function(event, element){ if (!this.options.clone) return new Element(element.tagName).inject(document.body); - if ($type(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list); + if (typeOf(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list); var clone = element.clone(true).setStyles({ - margin: '0px', + margin: 0, position: 'absolute', visibility: 'hidden', - 'width': element.getStyle('width') + width: element.getStyle('width') + }).addEvent('mousedown', function(event){ + element.fireEvent('mousedown', event); }); //prevent the duplicated radio inputs from unchecking the real one - if (clone.get('html').test('radio')) { - clone.getElements('input[type=radio]').each(function(input, i) { + if (clone.get('html').test('radio')){ + clone.getElements('input[type=radio]').each(function(input, i){ input.set('name', 'clone_' + i); if (input.get('checked')) element.getElements('input[type=radio]')[i].set('checked', true); }); } - + return clone.inject(this.list).setPosition(element.getPosition(element.getOffsetParent())); }, getDroppables: function(){ - var droppables = this.list.getChildren(); - if (!this.options.constrain) droppables = this.lists.concat(droppables).erase(this.list); - return droppables.erase(this.clone).erase(this.element); + var droppables = this.list.getChildren().erase(this.clone).erase(this.element); + if (!this.options.constrain) droppables.append(this.lists).erase(this.list); + return droppables; }, insert: function(dragging, element){ @@ -5681,7 +7456,7 @@ var Sortables = new Class({ if ( !this.idle || event.rightClick || - ['button', 'input'].contains(document.id(event.target).get('tag')) + ['button', 'input', 'a'].contains(event.target.get('tag')) ) return; this.idle = false; @@ -5690,11 +7465,10 @@ var Sortables = new Class({ this.list = element.getParent(); this.clone = this.getClone(event, element); - this.drag = new Drag.Move(this.clone, { - preventDefault: this.options.preventDefault, - snap: this.options.snap, - container: this.options.constrain && this.element.getParent(), - droppables: this.getDroppables(), + this.drag = new Drag.Move(this.clone, Object.merge({ + + droppables: this.getDroppables() + }, this.options.dragOptions)).addEvents({ onSnap: function(){ event.stop(); this.clone.setStyle('visibility', 'visible'); @@ -5702,7 +7476,7 @@ var Sortables = new Class({ this.fireEvent('start', [this.element, this.clone]); }.bind(this), onEnter: this.insert.bind(this), - onCancel: this.reset.bind(this), + onCancel: this.end.bind(this), onComplete: this.end.bind(this) }); @@ -5714,29 +7488,41 @@ var Sortables = new Class({ this.drag.detach(); this.element.set('opacity', this.opacity); if (this.effect){ - var dim = this.element.getStyles('width', 'height'); - var pos = this.clone.computePosition(this.element.getPosition(this.clone.getOffsetParent())); - this.effect.element = this.clone; + var dim = this.element.getStyles('width', 'height'), + clone = this.clone, + pos = clone.computePosition(this.element.getPosition(this.clone.getOffsetParent())); + + var destroy = function(){ + this.removeEvent('cancel', destroy); + clone.destroy(); + }; + + this.effect.element = clone; this.effect.start({ top: pos.top, left: pos.left, width: dim.width, height: dim.height, opacity: 0.25 - }).chain(this.reset.bind(this)); + }).addEvent('cancel', destroy).chain(destroy); } else { - this.reset(); + this.clone.destroy(); } + this.reset(); }, reset: function(){ this.idle = true; - this.clone.destroy(); this.fireEvent('complete', this.element); }, serialize: function(){ - var params = Array.link(arguments, {modifier: Function.type, index: $defined}); + var params = Array.link(arguments, { + modifier: Type.isFunction, + index: function(obj){ + return obj != null; + } + }); var serial = this.lists.map(function(list){ return list.getChildren().map(params.modifier || function(element){ return element.get('id'); @@ -5745,7 +7531,7 @@ var Sortables = new Class({ var index = params.index; if (this.lists.length == 1) index = 0; - return $chk(index) && index >= 0 && index < this.lists.length ? serial[index] : serial; + return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial; } }); @@ -5765,11 +7551,12 @@ license: MIT-style license authors: - Aaron Newton - Guillermo Rauch + - Arian Stolwijk requires: - Core/Element - Core/Request - - /Log + - MooTools.More provides: [Request.JSONP] @@ -5778,112 +7565,114 @@ provides: [Request.JSONP] Request.JSONP = new Class({ - Implements: [Chain, Events, Options, Log], + Implements: [Chain, Events, Options], options: {/* - onRetry: $empty(intRetries), - onRequest: $empty(scriptElement), - onComplete: $empty(data), - onSuccess: $empty(data), - onCancel: $empty(), - log: false, - */ + onRequest: function(src, scriptElement){}, + onComplete: function(data){}, + onSuccess: function(data){}, + onCancel: function(){}, + onTimeout: function(){}, + onError: function(){}, */ + onRequest: function(src){ + if (this.options.log && window.console && console.log){ + console.log('JSONP retrieving script with url:' + src); + } + }, + onError: function(src){ + if (this.options.log && window.console && console.warn){ + console.warn('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs'); + } + }, url: '', - data: {}, - retries: 0, - timeout: 0, - link: 'ignore', callbackKey: 'callback', - injectScript: document.head + injectScript: document.head, + data: '', + link: 'ignore', + timeout: 0, + log: false }, initialize: function(options){ this.setOptions(options); - if (this.options.log) this.enableLog(); - this.running = false; - this.requests = 0; - this.triesRemaining = []; - }, - - check: function(){ - if (!this.running) return true; - switch (this.options.link){ - case 'cancel': this.cancel(); return true; - case 'chain': this.chain(this.caller.bind(this, arguments)); return false; - } - return false; }, send: function(options){ - if (!$chk(arguments[1]) && !this.check(options)) return this; + if (!Request.prototype.check.call(this, options)) return this; + this.running = true; - var type = $type(options), - old = this.options, - index = $chk(arguments[1]) ? arguments[1] : this.requests++; + var type = typeOf(options); if (type == 'string' || type == 'element') options = {data: options}; + options = Object.merge(this.options, options || {}); - options = $extend({data: old.data, url: old.url}, options); + var data = options.data; + switch (typeOf(data)){ + case 'element': data = document.id(data).toQueryString(); break; + case 'object': case 'hash': data = Object.toQueryString(data); + } - if (!$chk(this.triesRemaining[index])) this.triesRemaining[index] = this.options.retries; - var remaining = this.triesRemaining[index]; + var index = this.index = Request.JSONP.counter++; - (function(){ - var script = this.getScript(options); - this.log('JSONP retrieving script with url: ' + script.get('src')); - this.fireEvent('request', script); - this.running = true; + var src = options.url + + (options.url.test('\\?') ? '&' :'?') + + (options.callbackKey) + + '=Request.JSONP.request_map.request_'+ index + + (data ? '&' + data : ''); + + if (src.length > 2083) this.fireEvent('error', src); + + Request.JSONP.request_map['request_' + index] = function(){ + this.success(arguments, index); + }.bind(this); + + var script = this.getScript(src).inject(options.injectScript); + this.fireEvent('request', [src, script]); + + if (options.timeout) this.timeout.delay(options.timeout, this); - (function(){ - if (remaining){ - this.triesRemaining[index] = remaining - 1; - if (script){ - script.destroy(); - this.send(options, index).fireEvent('retry', this.triesRemaining[index]); - } - } else if(this.running && script && this.options.timeout){ - script.destroy(); - this.cancel().fireEvent('failure'); - } - }).delay(this.options.timeout, this); - }).delay(Browser.Engine.trident ? 50 : 0, this); return this; }, + getScript: function(src){ + if (!this.script) this.script = new Element('script', { + type: 'text/javascript', + async: true, + src: src + }); + return this.script; + }, + + success: function(args, index){ + if (!this.running) return; + this.clear() + .fireEvent('complete', args).fireEvent('success', args) + .callChain(); + }, + cancel: function(){ - if (!this.running) return this; - this.running = false; - this.fireEvent('cancel'); + if (this.running) this.clear().fireEvent('cancel'); return this; }, - getScript: function(options){ - var index = Request.JSONP.counter, - data; - Request.JSONP.counter++; - - switch ($type(options.data)){ - case 'element': data = document.id(options.data).toQueryString(); break; - case 'object': case 'hash': data = Hash.toQueryString(options.data); - } - - var src = options.url + - (options.url.test('\\?') ? '&' :'?') + - (options.callbackKey || this.options.callbackKey) + - '=Request.JSONP.request_map.request_'+ index + - (data ? '&' + data : ''); - if (src.length > 2083) this.log('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs'); - - var script = new Element('script', {type: 'text/javascript', src: src}); - Request.JSONP.request_map['request_' + index] = function(){ this.success(arguments, script); }.bind(this); - return script.inject(this.options.injectScript); + isRunning: function(){ + return !!this.running; }, - success: function(args, script){ - if (!this.running) return false; - if (script) script.destroy(); + clear: function(){ this.running = false; - this.log('JSONP successfully retrieved: ', args); - this.fireEvent('complete', args).fireEvent('success', args).callChain(); + if (this.script){ + this.script.destroy(); + this.script = null; + } + return this; + }, + + timeout: function(){ + if (this.running){ + this.running = false; + this.fireEvent('timeout', [this.script.get('src'), this.script]).fireEvent('failure').cancel(); + } + return this; } }); @@ -5909,7 +7698,7 @@ authors: requires: - Core/Element - Core/Request - - /Log + - /Class.Binds provides: [Request.Queue] @@ -5923,13 +7712,13 @@ Request.Queue = new Class({ Binds: ['attach', 'request', 'complete', 'cancel', 'success', 'failure', 'exception'], options: {/* - onRequest: $empty(argsPassedToOnRequest), - onSuccess: $empty(argsPassedToOnSuccess), - onComplete: $empty(argsPassedToOnComplete), - onCancel: $empty(argsPassedToOnCancel), - onException: $empty(argsPassedToOnException), - onFailure: $empty(argsPassedToOnFailure), - onEnd: $empty, + onRequest: function(argsPassedToOnRequest){}, + onSuccess: function(argsPassedToOnSuccess){}, + onComplete: function(argsPassedToOnComplete){}, + onCancel: function(argsPassedToOnCancel){}, + onException: function(argsPassedToOnException){}, + onFailure: function(argsPassedToOnFailure){}, + onEnd: function(){}, */ stopOnFailure: true, autoAdvance: true, @@ -5938,41 +7727,42 @@ Request.Queue = new Class({ }, initialize: function(options){ - if(options){ - var requests = options.requests; - delete options.requests; + var requests; + if (options){ + requests = options.requests; + delete options.requests; } this.setOptions(options); - this.requests = new Hash; + this.requests = {}; this.queue = []; this.reqBinders = {}; - - if(requests) this.addRequests(requests); + + if (requests) this.addRequests(requests); }, addRequest: function(name, request){ - this.requests.set(name, request); + this.requests[name] = request; this.attach(name, request); return this; }, addRequests: function(obj){ - $each(obj, function(req, name){ + Object.each(obj, function(req, name){ this.addRequest(name, req); }, this); return this; }, getName: function(req){ - return this.requests.keyOf(req); + return Object.keyOf(this.requests, req); }, attach: function(name, req){ if (req._groupSend) return this; ['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){ - if(!this.reqBinders[name]) this.reqBinders[name] = {}; + if (!this.reqBinders[name]) this.reqBinders[name] = {}; this.reqBinders[name][evt] = function(){ - this['on' + evt.capitalize()].apply(this, [name, req].extend(arguments)); + this['on' + evt.capitalize()].apply(this, [name, req].append(arguments)); }.bind(this); req.addEvent(evt, this.reqBinders[name][evt]); }, this); @@ -5985,9 +7775,9 @@ Request.Queue = new Class({ }, removeRequest: function(req){ - var name = $type(req) == 'object' ? this.getName(req) : req; - if (!name && $type(name) != 'string') return this; - req = this.requests.get(name); + var name = typeOf(req) == 'object' ? this.getName(req) : req; + if (!name && typeOf(name) != 'string') return this; + req = this.requests[name]; if (!req) return this; ['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){ req.removeEvent(evt, this.reqBinders[name][evt]); @@ -5998,22 +7788,23 @@ Request.Queue = new Class({ }, getRunning: function(){ - return this.requests.filter(function(r){ + return Object.filter(this.requests, function(r){ return r.running; }); }, isRunning: function(){ - return !!(this.getRunning().getKeys().length); + return !!(Object.keys(this.getRunning()).length); }, send: function(name, options){ var q = function(){ - this.requests.get(name)._groupSend(options); + this.requests[name]._groupSend(options); this.queue.erase(q); }.bind(this); + q.name = name; - if (this.getRunning().getKeys().length >= this.options.concurrent || (this.error && this.options.stopOnFailure)) this.queue.push(q); + if (Object.keys(this.getRunning()).length >= this.options.concurrent || (this.error && this.options.stopOnFailure)) this.queue.push(q); else q(); return this; }, @@ -6024,7 +7815,7 @@ Request.Queue = new Class({ resume: function(){ this.error = false; - (this.options.concurrent - this.getRunning().getKeys().length).times(this.runNext, this); + (this.options.concurrent - Object.keys(this.getRunning()).length).times(this.runNext, this); return this; }, @@ -6044,8 +7835,8 @@ Request.Queue = new Class({ return this; }, - runAll: function() { - this.queue.each(function(q) { + runAll: function(){ + this.queue.each(function(q){ q(); }); return this; @@ -6058,13 +7849,15 @@ Request.Queue = new Class({ this.queue = this.queue.map(function(q){ if (q.name != name) return q; else return false; - }).filter(function(q){ return q; }); + }).filter(function(q){ + return q; + }); } return this; }, cancel: function(name){ - this.requests.get(name).cancel(); + this.requests[name].cancel(); return this; }, @@ -6137,10 +7930,10 @@ Request.implement({ var fn = function(){ if (!this.running) this.send({data: data}); }; - this.timer = fn.delay(this.options.initialDelay, this); this.lastDelay = this.options.initialDelay; + this.timer = fn.delay(this.lastDelay, this); this.completeCheck = function(response){ - $clear(this.timer); + clearTimeout(this.timer); this.lastDelay = (response) ? this.options.delay : (this.lastDelay + this.options.delay).min(this.options.limit); this.timer = fn.delay(this.lastDelay, this); }; @@ -6148,12 +7941,13 @@ Request.implement({ }, stopTimer: function(){ - $clear(this.timer); + clearTimeout(this.timer); return this.removeEvent('complete', this.completeCheck); } }); + /* --- @@ -6180,75 +7974,64 @@ provides: [Assets] var Asset = { javascript: function(source, properties){ - properties = $extend({ - onload: $empty, - document: document, - check: $lambda(true) - }, properties); - - if (properties.onLoad) { - properties.onload = properties.onLoad; - delete properties.onLoad; - } - var script = new Element('script', {src: source, type: 'text/javascript'}); + if (!properties) properties = {}; + + var script = new Element('script', {src: source, type: 'text/javascript'}), + doc = properties.document || document, + loaded = 0, + loadEvent = properties.onload || properties.onLoad; + + var load = loadEvent ? function(){ // make sure we only call the event once + if (++loaded == 1) loadEvent.call(this); + } : function(){}; - var load = properties.onload.bind(script), - check = properties.check, - doc = properties.document; delete properties.onload; - delete properties.check; + delete properties.onLoad; delete properties.document; - script.addEvents({ + return script.addEvents({ load: load, readystatechange: function(){ - if (['loaded', 'complete'].contains(this.readyState)) load(); + if (['loaded', 'complete'].contains(this.readyState)) load.call(this); } - }).set(properties); - - if (Browser.Engine.webkit419) var checker = (function(){ - if (!$try(check)) return; - $clear(checker); - load(); - }).periodical(50); - - return script.inject(doc.head); + }).set(properties).inject(doc.head); }, css: function(source, properties){ - properties = properties || {}; - var onload = properties.onload || properties.onLoad; - if (onload) { - properties.events = properties.events || {}; - properties.events.load = onload; - delete properties.onload; - delete properties.onLoad; - } - return new Element('link', $merge({ + if (!properties) properties = {}; + + var link = new Element('link', { rel: 'stylesheet', media: 'screen', type: 'text/css', href: source - }, properties)).inject(document.head); + }); + + var load = properties.onload || properties.onLoad, + doc = properties.document || document; + + delete properties.onload; + delete properties.onLoad; + delete properties.document; + + if (load) link.addEvent('load', load); + return link.set(properties).inject(doc.head); }, image: function(source, properties){ - properties = $merge({ - onload: $empty, - onabort: $empty, - onerror: $empty - }, properties); - var image = new Image(); - var element = document.id(image) || new Element('img'); + if (!properties) properties = {}; + + var image = new Image(), + element = document.id(image) || new Element('img'); + ['load', 'abort', 'error'].each(function(name){ - var type = 'on' + name; - var cap = name.capitalize(); - if (properties['on' + cap]) { - properties[type] = properties['on' + cap]; - delete properties['on' + cap]; - } - var event = properties[type]; + var type = 'on' + name, + cap = 'on' + name.capitalize(), + event = properties[type] || properties[cap] || function(){}; + + delete properties[cap]; delete properties[type]; + image[type] = function(){ if (!image) return; if (!element.parentNode){ @@ -6260,31 +8043,35 @@ var Asset = { element.fireEvent(name, element, 1); }; }); + image.src = element.src = source; if (image && image.complete) image.onload.delay(1); return element.set(properties); }, images: function(sources, options){ - options = $merge({ - onComplete: $empty, - onProgress: $empty, - onError: $empty, + sources = Array.from(sources); + + var fn = function(){}, + counter = 0; + + options = Object.merge({ + onComplete: fn, + onProgress: fn, + onError: fn, properties: {} }, options); - sources = $splat(sources); - var images = []; - var counter = 0; + return new Elements(sources.map(function(source, index){ - return Asset.image(source, $extend(options.properties, { + return Asset.image(source, Object.append(options.properties, { onload: function(){ - options.onProgress.call(this, counter, index); counter++; + options.onProgress.call(this, counter, index, source); if (counter == sources.length) options.onComplete(); }, onerror: function(){ - options.onError.call(this, counter, index); counter++; + options.onError.call(this, counter, index, source); if (counter == sources.length) options.onComplete(); } })); @@ -6293,6 +8080,7 @@ var Asset = { }; + /* --- @@ -6313,45 +8101,43 @@ requires: - Core/Number - Core/Hash - Core/Function - - Core/$util + - MooTools.More provides: [Color] ... */ -var Color = new Native({ +(function(){ - initialize: function(color, type){ - if (arguments.length >= 3){ - type = 'rgb'; color = Array.slice(arguments, 0, 3); - } else if (typeof color == 'string'){ - if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true); - else if (color.match(/hsb/)) color = color.hsbToRgb(); - else color = color.hexToRgb(true); - } - type = type || 'rgb'; - switch (type){ - case 'hsb': - var old = color; - color = color.hsbToRgb(); - color.hsb = old; - break; - case 'hex': color = color.hexToRgb(true); break; - } - color.rgb = color.slice(0, 3); - color.hsb = color.hsb || color.rgbToHsb(); - color.hex = color.rgbToHex(); - return $extend(color, this); +var Color = this.Color = new Type('Color', function(color, type){ + if (arguments.length >= 3){ + type = 'rgb'; color = Array.slice(arguments, 0, 3); + } else if (typeof color == 'string'){ + if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true); + else if (color.match(/hsb/)) color = color.hsbToRgb(); + else color = color.hexToRgb(true); } - + type = type || 'rgb'; + switch (type){ + case 'hsb': + var old = color; + color = color.hsbToRgb(); + color.hsb = old; + break; + case 'hex': color = color.hexToRgb(true); break; + } + color.rgb = color.slice(0, 3); + color.hsb = color.hsb || color.rgbToHsb(); + color.hex = color.rgbToHex(); + return Object.append(color, this); }); Color.implement({ mix: function(){ var colors = Array.slice(arguments); - var alpha = ($type(colors.getLast()) == 'number') ? colors.pop() : 50; + var alpha = (typeOf(colors.getLast()) == 'number') ? colors.pop() : 50; var rgb = this.slice(); colors.each(function(color){ color = new Color(color); @@ -6380,15 +8166,15 @@ Color.implement({ }); -var $RGB = function(r, g, b){ +this.$RGB = function(r, g, b){ return new Color([r, g, b], 'rgb'); }; -var $HSB = function(h, s, b){ +this.$HSB = function(h, s, b){ return new Color([h, s, b], 'hsb'); }; -var $HEX = function(hex){ +this.$HEX = function(hex){ return new Color(hex, 'hex'); }; @@ -6404,7 +8190,7 @@ Array.implement({ var delta = max - min; var brightness = max / 255, saturation = (max != 0) ? delta / max : 0; - if(saturation != 0) { + if (saturation != 0){ var rr = (max - red) / delta; var gr = (max - green) / delta; var br = (max - blue) / delta; @@ -6455,6 +8241,9 @@ String.implement({ }); +})(); + + /* --- @@ -6479,7 +8268,9 @@ provides: [Group] ... */ -var Group = new Class({ +(function(){ + +this.Group = new Class({ initialize: function(){ this.instances = Array.flatten(arguments); @@ -6493,7 +8284,7 @@ var Group = new Class({ if (this.events[type].contains(fn)) return false; else this.events[type].push(fn); this.instances.each(function(instance, i){ - instance.addEvent(type, this.check.bind(this, [type, instance, i])); + instance.addEvent(type, this.check.pass([type, instance, i], this)); }, this); return this; }, @@ -6512,6 +8303,9 @@ var Group = new Class({ }); +})(); + + /* --- @@ -6532,6 +8326,7 @@ requires: - Core/Cookie - Core/JSON - /MooTools.More + - /Hash provides: [Hash.Cookie] @@ -6574,136 +8369,64 @@ Hash.each(Hash.prototype, function(method, name){ }); }); + /* --- - -script: IframeShim.js - -name: IframeShim - -description: Defines IframeShim, a class for obscuring select lists and flash objects in IE. - +name: Table +description: LUA-Style table implementation. license: MIT-style license - authors: - - Aaron Newton - -requires: - - Core/Element.Event - - Core/Element.Style - - Core/Options - - Core/Events - - /Element.Position - - /Class.Occlude - -provides: [IframeShim] - + - Valerio Proietti +requires: [Core/Array] +provides: [Table] ... */ -var IframeShim = new Class({ +(function(){ - Implements: [Options, Events, Class.Occlude], +var Table = this.Table = function(){ - options: { - className: 'iframeShim', - src: 'javascript:false;document.write("");', - display: false, - zIndex: null, - margin: 0, - offset: {x: 0, y: 0}, - browsers: (Browser.Engine.trident4 || (Browser.Engine.gecko && !Browser.Engine.gecko19 && Browser.Platform.mac)) - }, - - property: 'IframeShim', - - initialize: function(element, options){ - this.element = document.id(element); - if (this.occlude()) return this.occluded; - this.setOptions(options); - this.makeShim(); - return this; - }, - - makeShim: function(){ - if(this.options.browsers){ - var zIndex = this.element.getStyle('zIndex').toInt(); - - if (!zIndex){ - zIndex = 1; - var pos = this.element.getStyle('position'); - if (pos == 'static' || !pos) this.element.setStyle('position', 'relative'); - this.element.setStyle('zIndex', zIndex); - } - zIndex = ($chk(this.options.zIndex) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1; - if (zIndex < 0) zIndex = 1; - this.shim = new Element('iframe', { - src: this.options.src, - scrolling: 'no', - frameborder: 0, - styles: { - zIndex: zIndex, - position: 'absolute', - border: 'none', - filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)' - }, - 'class': this.options.className - }).store('IframeShim', this); - var inject = (function(){ - this.shim.inject(this.element, 'after'); - this[this.options.display ? 'show' : 'hide'](); - this.fireEvent('inject'); - }).bind(this); - if (!IframeShim.ready) window.addEvent('load', inject); - else inject(); + this.length = 0; + var keys = [], + values = []; + + this.set = function(key, value){ + var index = keys.indexOf(key); + if (index == -1){ + var length = keys.length; + keys[length] = key; + values[length] = value; + this.length++; } else { - this.position = this.hide = this.show = this.dispose = $lambda(this); + values[index] = value; } - }, + return this; + }; - position: function(){ - if (!IframeShim.ready || !this.shim) return this; - var size = this.element.measure(function(){ - return this.getSize(); - }); - if (this.options.margin != undefined){ - size.x = size.x - (this.options.margin * 2); - size.y = size.y - (this.options.margin * 2); - this.options.offset.x += this.options.margin; - this.options.offset.y += this.options.margin; + this.get = function(key){ + var index = keys.indexOf(key); + return (index == -1) ? null : values[index]; + }; + + this.erase = function(key){ + var index = keys.indexOf(key); + if (index != -1){ + this.length--; + keys.splice(index, 1); + return values.splice(index, 1)[0]; } - this.shim.set({width: size.x, height: size.y}).position({ - relativeTo: this.element, - offset: this.options.offset - }); - return this; - }, + return null; + }; - hide: function(){ - if (this.shim) this.shim.setStyle('display', 'none'); - return this; - }, + this.each = this.forEach = function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++) fn.call(bind, keys[i], values[i], this); + }; + +}; - show: function(){ - if (this.shim) this.shim.setStyle('display', 'block'); - return this.position(); - }, +if (this.Type) new Type('Table', Table); - dispose: function(){ - if (this.shim) this.shim.dispose(); - return this; - }, - - destroy: function(){ - if (this.shim) this.shim.destroy(); - return this; - } - -}); - -window.addEvent('load', function(){ - IframeShim.ready = true; -}); +})(); /* @@ -6748,8 +8471,9 @@ var HtmlTable = new Class({ property: 'HtmlTable', initialize: function(){ - var params = Array.link(arguments, {options: Object.type, table: Element.type}); + var params = Array.link(arguments, {options: Type.isObject, table: Type.isElement, id: Type.isString}); this.setOptions(params.options); + if (!params.table && params.id) params.table = document.id(params.id); this.element = params.table || new Element('table', this.options.properties); if (this.occlude()) return this.occluded; this.build(); @@ -6763,19 +8487,16 @@ var HtmlTable = new Class({ if (this.options.headers.length) this.setHeaders(this.options.headers); else this.thead = document.id(this.element.tHead); - if (this.thead) this.head = document.id(this.thead.rows[0]); + if (this.thead) this.head = this.getHead(); if (this.options.footers.length) this.setFooters(this.options.footers); + this.tfoot = document.id(this.element.tFoot); if (this.tfoot) this.foot = document.id(this.tfoot.rows[0]); this.options.rows.each(function(row){ this.push(row); }, this); - - ['adopt', 'inject', 'wraps', 'grab', 'replaces', 'dispose'].each(function(method){ - this[method] = this.element[method].bind(this.element); - }, this); }, toElement: function(){ @@ -6787,15 +8508,24 @@ var HtmlTable = new Class({ return this; }, - set: function(what, items) { - var target = (what == 'headers') ? 'tHead' : 'tFoot'; - this[target.toLowerCase()] = (document.id(this.element[target]) || new Element(target.toLowerCase()).inject(this.element, 'top')).empty(); - var data = this.push(items, {}, this[target.toLowerCase()], what == 'headers' ? 'th' : 'td'); - if (what == 'headers') this.head = document.id(this.thead.rows[0]); - else this.foot = document.id(this.thead.rows[0]); + set: function(what, items){ + var target = (what == 'headers') ? 'tHead' : 'tFoot', + lower = target.toLowerCase(); + + this[lower] = (document.id(this.element[target]) || new Element(lower).inject(this.element, 'top')).empty(); + var data = this.push(items, {}, this[lower], what == 'headers' ? 'th' : 'td'); + + if (what == 'headers') this.head = this.getHead(); + else this.foot = this.getHead(); + return data; }, + getHead: function(){ + var rows = this.thead.rows; + return rows.length > 1 ? $$(rows) : rows.length ? document.id(rows[0]) : false; + }, + setHeaders: function(headers){ this.set('headers', headers); return this; @@ -6806,26 +8536,28 @@ var HtmlTable = new Class({ return this; }, - push: function(row, rowProperties, target, tag){ - if ($type(row) == "element" && row.get('tag') == 'tr') { - row.inject(target || this.body); + push: function(row, rowProperties, target, tag, where){ + if (typeOf(row) == 'element' && row.get('tag') == 'tr'){ + row.inject(target || this.body, where); return { tr: row, tds: row.getChildren('td') }; } + var tds = row.map(function(data){ var td = new Element(tag || 'td', data ? data.properties : {}), - type = (data ? data.content : '') || data, - element = document.id(type); - if($type(type) != 'string' && element) td.adopt(element); - else td.set('html', type); + content = (data ? data.content : '') || data, + type = typeOf(content); + + if (['element', 'array', 'collection', 'elements'].contains(type)) td.adopt(content); + else td.set('html', content); return td; }); return { - tr: new Element('tr', rowProperties).inject(target || this.body).adopt(tds), + tr: new Element('tr', rowProperties).inject(target || this.body, where).adopt(tds), tds: tds }; } @@ -6833,6 +8565,16 @@ var HtmlTable = new Class({ }); +['adopt', 'inject', 'wraps', 'grab', 'replaces', 'dispose'].each(function(method){ + HtmlTable.implement(method, function(){ + this.element[method].apply(this.element, arguments); + return this; + }); +}); + + + + /* --- @@ -6874,6 +8616,11 @@ HtmlTable = Class.refactor(HtmlTable, { Array.each(this.body.rows, this.zebra, this); }, + setRowStyle: function(row, i){ + if (this.previous) this.previous(row, i); + this.zebra(row, i); + }, + zebra: function(row, i){ return row[((i % 2) ? 'remove' : 'add')+'Class'](this.options.classZebra); }, @@ -6886,6 +8633,7 @@ HtmlTable = Class.refactor(HtmlTable, { }); + /* --- @@ -6900,6 +8648,7 @@ license: MIT-style license authors: - Harald Kirschner - Aaron Newton + - Jacob Thornton requires: - Core/Hash @@ -6917,7 +8666,7 @@ provides: [HtmlTable.Sort] HtmlTable = Class.refactor(HtmlTable, { options: {/* - onSort: $empty, */ + onSort: function(){}, */ sortIndex: 0, sortReverse: false, parsers: [], @@ -6930,10 +8679,11 @@ HtmlTable = Class.refactor(HtmlTable, { classGroup: 'table-tr-group', classCellSort: 'table-td-sort', classSortSpan: 'table-th-sort-span', - sortable: false + sortable: false, + thSelector: 'th' }, - initialize: function () { + initialize: function (){ this.previous.apply(this, arguments); if (this.occluded) return this.occluded; this.sorted = {index: null, dir: 1}; @@ -6941,168 +8691,194 @@ HtmlTable = Class.refactor(HtmlTable, { headClick: this.headClick.bind(this) }; this.sortSpans = new Elements(); - if (this.options.sortable) { + if (this.options.sortable){ this.enableSort(); if (this.options.sortIndex != null) this.sort(this.options.sortIndex, this.options.sortReverse); } }, attachSorts: function(attach){ - this.element.removeEvents('click:relay(th)'); - this.element[$pick(attach, true) ? 'addEvent' : 'removeEvent']('click:relay(th)', this.bound.headClick); + this.detachSorts(); + if (attach !== false) this.element.addEvent('click:relay(' + this.options.thSelector + ')', this.bound.headClick); + }, + + detachSorts: function(){ + this.element.removeEvents('click:relay(' + this.options.thSelector + ')'); }, setHeaders: function(){ this.previous.apply(this, arguments); - if (this.sortEnabled) this.detectParsers(); + if (this.sortEnabled) this.setParsers(); }, - - detectParsers: function(force){ - if (!this.head) return; - var parsers = this.options.parsers, - rows = this.body.rows; - // auto-detect - this.parsers = $$(this.head.cells).map(function(cell, index) { - if (!force && (cell.hasClass(this.options.classNoSort) || cell.retrieve('htmltable-parser'))) return cell.retrieve('htmltable-parser'); - var thDiv = new Element('div'); - $each(cell.childNodes, function(node) { - thDiv.adopt(node); - }); - thDiv.inject(cell); - var sortSpan = new Element('span', {'html': ' ', 'class': this.options.classSortSpan}).inject(thDiv, 'top'); - - this.sortSpans.push(sortSpan); + setParsers: function(){ + this.parsers = this.detectParsers(); + }, - var parser = parsers[index], - cancel; - switch ($type(parser)) { - case 'function': parser = {convert: parser}; cancel = true; break; - case 'string': parser = parser; cancel = true; break; - } - if (!cancel) { - HtmlTable.Parsers.some(function(current) { - var match = current.match; - if (!match) return false; - for (var i = 0, j = rows.length; i < j; i++) { - var cell = document.id(rows[i].cells[index]); - var text = cell ? cell.get('html').clean() : ''; - if (text && match.test(text)) { - parser = current; - return true; - } + detectParsers: function(){ + return this.head && this.head.getElements(this.options.thSelector).flatten().map(this.detectParser, this); + }, + + detectParser: function(cell, index){ + if (cell.hasClass(this.options.classNoSort) || cell.retrieve('htmltable-parser')) return cell.retrieve('htmltable-parser'); + var thDiv = new Element('div'); + thDiv.adopt(cell.childNodes).inject(cell); + var sortSpan = new Element('span', {'class': this.options.classSortSpan}).inject(thDiv, 'top'); + this.sortSpans.push(sortSpan); + var parser = this.options.parsers[index], + rows = this.body.rows, + cancel; + switch (typeOf(parser)){ + case 'function': parser = {convert: parser}; cancel = true; break; + case 'string': parser = parser; cancel = true; break; + } + if (!cancel){ + HtmlTable.ParserPriority.some(function(parserName){ + var current = HtmlTable.Parsers[parserName], + match = current.match; + if (!match) return false; + for (var i = 0, j = rows.length; i < j; i++){ + var cell = document.id(rows[i].cells[index]), + text = cell ? cell.get('html').clean() : ''; + if (text && match.test(text)){ + parser = current; + return true; } - }); - } - - if (!parser) parser = this.options.defaultParser; - cell.store('htmltable-parser', parser); - return parser; - }, this); - }, - - headClick: function(event, el) { - if (!this.head || el.hasClass(this.options.classNoSort)) return; - var index = Array.indexOf(this.head.cells, el); - this.sort(index); - return false; - }, - - sort: function(index, reverse, pre) { - if (!this.head) return; - pre = !!(pre); - var classCellSort = this.options.classCellSort; - var classGroup = this.options.classGroup, - classGroupHead = this.options.classGroupHead; - - if (!pre) { - if (index != null) { - if (this.sorted.index == index) { - this.sorted.reverse = !(this.sorted.reverse); - } else { - if (this.sorted.index != null) { - this.sorted.reverse = false; - this.head.cells[this.sorted.index].removeClass(this.options.classHeadSort).removeClass(this.options.classHeadSortRev); - } else { - this.sorted.reverse = true; - } - this.sorted.index = index; } - } else { - index = this.sorted.index; + }); + } + if (!parser) parser = this.options.defaultParser; + cell.store('htmltable-parser', parser); + return parser; + }, + + headClick: function(event, el){ + if (!this.head || el.hasClass(this.options.classNoSort)) return; + return this.sort(Array.indexOf(this.head.getElements(this.options.thSelector).flatten(), el) % this.body.rows[0].cells.length); + }, + + serialize: function() { + var previousSerialization = this.previous.apply(this, arguments) || {}; + if (this.options.sortable) { + previousSerialization.sortIndex = this.sorted.index; + previousSerialization.sortReverse = this.sorted.reverse; + } + return previousSerialization; + }, + + restore: function(tableState) { + if(this.options.sortable && tableState.sortIndex) { + this.sort(tableState.sortIndex, tableState.sortReverse); + } + this.previous.apply(this, arguments); + }, + + setSortedState: function(index, reverse){ + if (reverse != null) this.sorted.reverse = reverse; + else if (this.sorted.index == index) this.sorted.reverse = !this.sorted.reverse; + else this.sorted.reverse = this.sorted.index == null; + + if (index != null) this.sorted.index = index; + }, + + setHeadSort: function(sorted){ + var head = $$(!this.head.length ? this.head.cells[this.sorted.index] : this.head.map(function(row){ + return row.getElements(this.options.thSelector)[this.sorted.index]; + }, this).clean()); + if (!head.length) return; + if (sorted){ + head.addClass(this.options.classHeadSort); + if (this.sorted.reverse) head.addClass(this.options.classHeadSortRev); + else head.removeClass(this.options.classHeadSortRev); + } else { + head.removeClass(this.options.classHeadSort).removeClass(this.options.classHeadSortRev); + } + }, + + setRowSort: function(data, pre){ + var count = data.length, + body = this.body, + group, + rowIndex; + + while (count){ + var item = data[--count], + position = item.position, + row = body.rows[position]; + + if (row.disabled) continue; + if (!pre){ + group = this.setGroupSort(group, row, item); + this.setRowStyle(row, count); } + body.appendChild(row); - if (reverse != null) this.sorted.reverse = reverse; - - var head = document.id(this.head.cells[index]); - if (head) { - head.addClass(this.options.classHeadSort); - if (this.sorted.reverse) head.addClass(this.options.classHeadSortRev); - else head.removeClass(this.options.classHeadSortRev); + for (rowIndex = 0; rowIndex < count; rowIndex++){ + if (data[rowIndex].position > position) data[rowIndex].position--; } + } + }, - this.body.getElements('td').removeClass(this.options.classCellSort); + setRowStyle: function(row, i){ + this.previous(row, i); + row.cells[this.sorted.index].addClass(this.options.classCellSort); + }, + + setGroupSort: function(group, row, item){ + if (group == item.value) row.removeClass(this.options.classGroupHead).addClass(this.options.classGroup); + else row.removeClass(this.options.classGroup).addClass(this.options.classGroupHead); + return item.value; + }, + + getParser: function(){ + var parser = this.parsers[this.sorted.index]; + return typeOf(parser) == 'string' ? HtmlTable.Parsers[parser] : parser; + }, + + sort: function(index, reverse, pre){ + if (!this.head) return; + + if (!pre){ + this.clearSort(); + this.setSortedState(index, reverse); + this.setHeadSort(true); } - var parser = this.parsers[index]; - if ($type(parser) == 'string') parser = HtmlTable.Parsers.get(parser); + var parser = this.getParser(); if (!parser) return; - if (!Browser.Engine.trident) { - var rel = this.body.getParent(); + var rel; + if (!Browser.ie){ + rel = this.body.getParent(); this.body.dispose(); } - var data = Array.map(this.body.rows, function(row, i) { - var value = parser.convert.call(document.id(row.cells[index])); - - return { - position: i, - value: value, - toString: function() { - return value.toString(); - } - }; - }, this); - data.reverse(true); - - data.sort(function(a, b){ + var data = this.parseData(parser).sort(function(a, b){ if (a.value === b.value) return 0; return a.value > b.value ? 1 : -1; }); - if (!this.sorted.reverse) data.reverse(true); + if (this.sorted.reverse == (parser == HtmlTable.Parsers['input-checked'])) data.reverse(true); + this.setRowSort(data, pre); - var i = data.length, body = this.body; - var j, position, entry, group; + if (rel) rel.grab(this.body); + this.fireEvent('stateChanged'); + return this.fireEvent('sort', [this.body, this.sorted.index]); + }, - while (i) { - var item = data[--i]; - position = item.position; - var row = body.rows[position]; - if (row.disabled) continue; + parseData: function(parser){ + return Array.map(this.body.rows, function(row, i){ + var value = parser.convert.call(document.id(row.cells[this.sorted.index])); + return { + position: i, + value: value + }; + }, this); + }, - if (!pre) { - if (group === item.value) { - row.removeClass(classGroupHead).addClass(classGroup); - } else { - group = item.value; - row.removeClass(classGroup).addClass(classGroupHead); - } - if (this.options.zebra) this.zebra(row, i); - - row.cells[index].addClass(classCellSort); - } - - body.appendChild(row); - for (j = 0; j < i; j++) { - if (data[j].position > position) data[j].position--; - } - }; - data = null; - if (rel) rel.grab(body); - - return this.fireEvent('sort', [body, index]); + clearSort: function(){ + this.setHeadSort(false); + this.body.getElements('td').removeClass(this.options.classCellSort); }, reSort: function(){ @@ -7113,7 +8889,7 @@ HtmlTable = Class.refactor(HtmlTable, { enableSort: function(){ this.element.addClass(this.options.classSortable); this.attachSorts(true); - this.detectParsers(); + this.setParsers(); this.sortEnabled = true; return this; }, @@ -7121,7 +8897,9 @@ HtmlTable = Class.refactor(HtmlTable, { disableSort: function(){ this.element.removeClass(this.options.classSortable); this.attachSorts(false); - this.sortSpans.each(function(span) { span.destroy(); }); + this.sortSpans.each(function(span){ + span.destroy(); + }); this.sortSpans.empty(); this.sortEnabled = false; return this; @@ -7129,354 +8907,82 @@ HtmlTable = Class.refactor(HtmlTable, { }); -HtmlTable.Parsers = new Hash({ +HtmlTable.ParserPriority = ['date', 'input-checked', 'input-value', 'float', 'number']; + +HtmlTable.Parsers = { 'date': { match: /^\d{2}[-\/ ]\d{2}[-\/ ]\d{2,4}$/, - convert: function() { + convert: function(){ var d = Date.parse(this.get('text').stripTags()); - return $type(d) == 'date' ? d.format('db') : ''; + return (typeOf(d) == 'date') ? d.format('db') : ''; }, type: 'date' }, 'input-checked': { match: / type="(radio|checkbox)" /, - convert: function() { + convert: function(){ return this.getElement('input').checked; } }, 'input-value': { match: /= this.body.rows.length) index = null; - return index; - }, - - _attachSelects: function(attach){ - attach = $pick(attach, true); - var method = attach ? 'addEvents' : 'removeEvents'; - this.element[method]({ - mouseleave: this._bound.mouseleave - }); - this.body[method]({ - 'click:relay(tr)': this._bound.clickRow, - 'contextmenu:relay(tr)': this._bound.clickRow - }); - if (this.options.useKeyboard || this.keyboard){ - if (!this.keyboard) { - var timer, held; - var move = function(offset){ - var mover = function(e){ - $clear(timer); - e.preventDefault(); - var to = this.body.rows[this._getRowByOffset(offset)]; - if (e.shift && to && this.isSelected(to)) { - this.deselectRow(this._focused); - this._focused = to; - } else { - if (to && (!this.options.allowMultiSelect || !e.shift)) { - this.selectNone(); - } - this._shiftFocus(offset, e); - } - if (held) { - timer = mover.delay(100, this, e); - } else { - timer = (function(){ - held = true; - mover(e); - }).delay(400); - } - }.bind(this); - return mover; - }.bind(this); - - var clear = function(){ - $clear(timer); - held = false; - }; - - this.keyboard = new Keyboard({ - events: { - 'keydown:shift+up': move(-1), - 'keydown:shift+down': move(1), - 'keyup:shift+up': clear, - 'keyup:shift+down': clear, - 'keyup:up': clear, - 'keyup:down': clear - }, - active: true - }); - - var shiftHint = ''; - if (this.options.allowMultiSelect && this.options.shiftForMultiSelect && this.options.useKeyboard) { - shiftHint = " (Shift multi-selects)."; - } - - this.keyboard.addShortcuts({ - 'Select Previous Row': { - keys: 'up', - shortcut: 'up arrow', - handler: move(-1), - description: 'Select the previous row in the table.' + shiftHint - }, - 'Select Next Row': { - keys: 'down', - shortcut: 'down arrow', - handler: move(1), - description: 'Select the next row in the table.' + shiftHint - } - }); - } - this.keyboard[attach ? 'activate' : 'deactivate'](); - } - this._updateSelects(); - }, - - _mouseleave: function(){ - if (this._hovered) this._leaveRow(this._hovered); +HtmlTable.defineParsers = function(parsers){ + HtmlTable.Parsers = Object.append(HtmlTable.Parsers, parsers); + for (var parser in parsers){ + HtmlTable.ParserPriority.unshift(parser); } +}; -}); /* --- @@ -7498,7 +9004,7 @@ requires: - Core/Events - Core/Options - Core/Element.Event - - /Log + - Element.Event.Pseudos.Keys provides: [Keyboard] @@ -7506,18 +9012,16 @@ provides: [Keyboard] */ (function(){ - + var Keyboard = this.Keyboard = new Class({ Extends: Events, - Implements: [Options, Log], + Implements: [Options], - options: { - /* - onActivate: $empty, - onDeactivate: $empty, - */ + options: {/* + onActivate: function(){}, + onDeactivate: function(){},*/ defaultEventType: 'keydown', active: false, manager: null, @@ -7526,32 +9030,12 @@ provides: [Keyboard] }, initialize: function(options){ - if (options && options.manager) { - this.manager = options.manager; + if (options && options.manager){ + this._manager = options.manager; delete options.manager; } this.setOptions(options); - this.setup(); - }, - setup: function(){ - this.addEvents(this.options.events); - //if this is the root manager, nothing manages it - if (Keyboard.manager && !this.manager) Keyboard.manager.manage(this); - if (this.options.active) this.activate(); - }, - - handle: function(event, type){ - //Keyboard.stop(event) prevents key propagation - if (event.preventKeyboardPropagation) return; - - var bubbles = !!this.manager; - if (bubbles && this.activeKB){ - this.activeKB.handle(event, type); - if (event.preventKeyboardPropagation) return; - } - this.fireEvent(type, event); - - if (!bubbles && this.activeKB) this.activeKB.handle(event, type); + this._setup(); }, addEvent: function(type, fn, internal){ @@ -7563,86 +9047,118 @@ provides: [Keyboard] }, toggleActive: function(){ - return this[this.active ? 'deactivate' : 'activate'](); + return this[this.isActive() ? 'deactivate' : 'activate'](); }, activate: function(instance){ - if (instance) { + if (instance){ if (instance.isActive()) return this; //if we're stealing focus, store the last keyboard to have it so the relinquish command works - if (this.activeKB && instance != this.activeKB) { - this.previous = this.activeKB; + if (this._activeKB && instance != this._activeKB){ + this.previous = this._activeKB; this.previous.fireEvent('deactivate'); } //if we're enabling a child, assign it so that events are now passed to it - this.activeKB = instance.fireEvent('activate'); + this._activeKB = instance.fireEvent('activate'); Keyboard.manager.fireEvent('changed'); - } else if (this.manager) { + } else if (this._manager){ //else we're enabling ourselves, we must ask our parent to do it for us - this.manager.activate(this); + this._manager.activate(this); } return this; }, isActive: function(){ - return this.manager ? this.manager.activeKB == this : Keyboard.manager == this; + return this._manager ? (this._manager._activeKB == this) : (Keyboard.manager == this); }, deactivate: function(instance){ - if (instance) { - if(instance === this.activeKB) { - this.activeKB = null; + if (instance){ + if (instance === this._activeKB){ + this._activeKB = null; instance.fireEvent('deactivate'); Keyboard.manager.fireEvent('changed'); } - } else if (this.manager) { - this.manager.deactivate(this); + } else if (this._manager){ + this._manager.deactivate(this); } return this; }, relinquish: function(){ - if (this.isActive() && this.manager && this.manager.previous) this.manager.activate(this.manager.previous); + if (this.isActive() && this._manager && this._manager.previous) this._manager.activate(this._manager.previous); + else this.deactivate(); + return this; }, //management logic manage: function(instance){ - if (instance.manager && instance.manager != Keyboard.manager && this != Keyboard.manager) instance.manager.drop(instance); - this.instances.push(instance); - instance.manager = this; - if (!this.activeKB) this.activate(instance); - }, - - _disable: function(instance){ - if (this.activeKB == instance) this.activeKB = null; + if (instance._manager) instance._manager.drop(instance); + this._instances.push(instance); + instance._manager = this; + if (!this._activeKB) this.activate(instance); + return this; }, drop: function(instance){ - this._disable(instance); - this.instances.erase(instance); - Keyboard.manager.manage(instance); - if (this.activeKB == instance && this.previous && this.instances.contains(this.previous)) this.activate(this.previous); + instance.relinquish(); + this._instances.erase(instance); + if (this._activeKB == instance){ + if (this.previous && this._instances.contains(this.previous)) this.activate(this.previous); + else this._activeKB = this._instances[0]; + } + return this; }, - instances: [], - trace: function(){ Keyboard.trace(this); }, each: function(fn){ Keyboard.each(this, fn); + }, + + /* + PRIVATE METHODS + */ + + _instances: [], + + _disable: function(instance){ + if (this._activeKB == instance) this._activeKB = null; + }, + + _setup: function(){ + this.addEvents(this.options.events); + //if this is the root manager, nothing manages it + if (Keyboard.manager && !this._manager) Keyboard.manager.manage(this); + if (this.options.active) this.activate(); + else this.relinquish(); + }, + + _handle: function(event, type){ + //Keyboard.stop(event) prevents key propagation + if (event.preventKeyboardPropagation) return; + + var bubbles = !!this._manager; + if (bubbles && this._activeKB){ + this._activeKB._handle(event, type); + if (event.preventKeyboardPropagation) return; + } + this.fireEvent(type, event); + + if (!bubbles && this._activeKB) this._activeKB._handle(event, type); } }); - + var parsed = {}; var modifiers = ['shift', 'control', 'alt', 'meta']; var regex = /^(?:shift|control|ctrl|alt|meta)$/; - + Keyboard.parse = function(type, eventType, ignore){ if (ignore && ignore.contains(type.toLowerCase())) return type; - + type = type.toLowerCase().replace(/^(keyup|keydown):/, function($0, $1){ eventType = $1; return ''; @@ -7656,24 +9172,24 @@ provides: [Keyboard] }); mods.control = mods.control || mods.ctrl; // allow both control and ctrl - + var keys = []; modifiers.each(function(mod){ if (mods[mod]) keys.push(mod); }); - + if (key) keys.push(key); parsed[type] = keys.join('+'); } - return eventType + ':' + parsed[type]; + return eventType + ':keys(' + parsed[type] + ')'; }; Keyboard.each = function(keyboard, fn){ var current = keyboard || Keyboard.manager; while (current){ fn.run(current); - current = current.activeKB; + current = current._activeKB; } }; @@ -7684,55 +9200,31 @@ provides: [Keyboard] Keyboard.manager = new Keyboard({ active: true }); - + Keyboard.trace = function(keyboard){ keyboard = keyboard || Keyboard.manager; - keyboard.enableLog(); - keyboard.log('the following items have focus: '); + var hasConsole = window.console && console.log; + if (hasConsole) console.log('the following items have focus: '); Keyboard.each(keyboard, function(current){ - keyboard.log(document.id(current.widget) || current.wiget || current); + if (hasConsole) console.log(document.id(current.widget) || current.wiget || current); }); }; - + var handler = function(event){ var keys = []; modifiers.each(function(mod){ if (event[mod]) keys.push(mod); }); - + if (!regex.test(event.key)) keys.push(event.key); - Keyboard.manager.handle(event, event.type + ':' + keys.join('+')); + Keyboard.manager._handle(event, event.type + ':keys(' + keys.join('+') + ')'); }; - + document.addEvents({ 'keyup': handler, 'keydown': handler }); - Event.Keys.extend({ - 'shift': 16, - 'control': 17, - 'alt': 18, - 'capslock': 20, - 'pageup': 33, - 'pagedown': 34, - 'end': 35, - 'home': 36, - 'numlock': 144, - 'scrolllock': 145, - ';': 186, - '=': 187, - ',': 188, - '-': Browser.Engine.gecko ? 109 : 189, - '.': 190, - '/': 191, - '`': 192, - '[': 219, - '\\': 220, - ']': 221, - "'": 222 - }); - })(); @@ -7770,50 +9262,50 @@ Keyboard.implement({ 'handler': function(){} // the event handler to run when keys are pressed. } */ - addShortcut: function(name, shortcut) { - this.shortcuts = this.shortcuts || []; - this.shortcutIndex = this.shortcutIndex || {}; - - shortcut.getKeyboard = $lambda(this); + addShortcut: function(name, shortcut){ + this._shortcuts = this._shortcuts || []; + this._shortcutIndex = this._shortcutIndex || {}; + + shortcut.getKeyboard = Function.from(this); shortcut.name = name; - this.shortcutIndex[name] = shortcut; - this.shortcuts.push(shortcut); - if(shortcut.keys) this.addEvent(shortcut.keys, shortcut.handler); + this._shortcutIndex[name] = shortcut; + this._shortcuts.push(shortcut); + if (shortcut.keys) this.addEvent(shortcut.keys, shortcut.handler); return this; }, addShortcuts: function(obj){ - for(var name in obj) this.addShortcut(name, obj[name]); + for (var name in obj) this.addShortcut(name, obj[name]); return this; }, - removeShortcut: function(name) { + removeShortcut: function(name){ var shortcut = this.getShortcut(name); - if (shortcut && shortcut.keys) { + if (shortcut && shortcut.keys){ this.removeEvent(shortcut.keys, shortcut.handler); - delete this.shortcutIndex[name]; - this.shortcuts.erase(shortcut); + delete this._shortcutIndex[name]; + this._shortcuts.erase(shortcut); } return this; }, - removeShortcuts: function(names) { + removeShortcuts: function(names){ names.each(this.removeShortcut, this); return this; }, getShortcuts: function(){ - return this.shortcuts || []; + return this._shortcuts || []; }, getShortcut: function(name){ - return (this.shortcutIndex || {})[name]; + return (this._shortcutIndex || {})[name]; } }); Keyboard.rebind = function(newKeys, shortcuts){ - $splat(shortcuts).each(function(shortcut){ + Array.from(shortcuts).each(function(shortcut){ shortcut.getKeyboard().removeEvent(shortcut.keys, shortcut.handler); shortcut.getKeyboard().addEvent(newKeys, shortcut.handler); shortcut.keys = newKeys; @@ -7822,7 +9314,7 @@ Keyboard.rebind = function(newKeys, shortcuts){ }; -Keyboard.getActiveShortcuts = function(keyboard) { +Keyboard.getActiveShortcuts = function(keyboard){ var activeKBS = [], activeSCS = []; Keyboard.each(keyboard, [].push.bind(activeKBS)); activeKBS.each(function(kb){ activeSCS.extend(kb.getShortcuts()); }); @@ -7834,15 +9326,15 @@ Keyboard.getShortcut = function(name, keyboard, opts){ var shortcuts = opts.many ? [] : null, set = opts.many ? function(kb){ var shortcut = kb.getShortcut(name); - if(shortcut) shortcuts.push(shortcut); - } : function(kb) { - if(!shortcuts) shortcuts = kb.getShortcut(name); + if (shortcut) shortcuts.push(shortcut); + } : function(kb){ + if (!shortcuts) shortcuts = kb.getShortcut(name); }; Keyboard.each(keyboard, set); return shortcuts; }; -Keyboard.getShortcuts = function(name, keyboard) { +Keyboard.getShortcuts = function(name, keyboard){ return Keyboard.getShortcut(name, keyboard, { many: true }); }; @@ -7850,200 +9342,341 @@ Keyboard.getShortcuts = function(name, keyboard) { /* --- -script: Mask.js +script: HtmlTable.Select.js -name: Mask +name: HtmlTable.Select -description: Creates a mask element to cover another. +description: Builds a stripy, sortable table with methods to add rows. Rows can be selected with the mouse or keyboard navigation. license: MIT-style license authors: + - Harald Kirschner - Aaron Newton requires: - - Core/Options - - Core/Events - - Core/Element.Event - - /Class.Binds - - /Element.Position - - /IframeShim + - /Keyboard + - /Keyboard.Extras + - /HtmlTable + - /Class.refactor + - /Element.Delegation + - /Element.Shortcuts -provides: [Mask] +provides: [HtmlTable.Select] ... */ -var Mask = new Class({ - - Implements: [Options, Events], - - Binds: ['position'], +HtmlTable = Class.refactor(HtmlTable, { options: { - // onShow: $empty, - // onHide: $empty, - // onDestroy: $empty, - // onClick: $empty, - //inject: { - // where: 'after', - // target: null, - //}, - // hideOnClick: false, - // id: null, - // destroyOnHide: false, - style: {}, - 'class': 'mask', - maskMargins: false, - useIframeShim: true, - iframeShimOptions: {} + /*onRowFocus: function(){}, + onRowUnfocus: function(){},*/ + useKeyboard: true, + classRowSelected: 'table-tr-selected', + classRowHovered: 'table-tr-hovered', + classSelectable: 'table-selectable', + shiftForMultiSelect: true, + allowMultiSelect: true, + selectable: false }, - initialize: function(target, options){ - this.target = document.id(target) || document.id(document.body); - this.target.store('Mask', this); - this.setOptions(options); - this.render(); - this.inject(); - }, - - render: function() { - this.element = new Element('div', { - 'class': this.options['class'], - id: this.options.id || 'mask-' + $time(), - styles: $merge(this.options.style, { - display: 'none' - }), - events: { - click: function(){ - this.fireEvent('click'); - if (this.options.hideOnClick) this.hide(); - }.bind(this) - } - }); - this.hidden = true; - }, + initialize: function(){ + this.previous.apply(this, arguments); + if (this.occluded) return this.occluded; - toElement: function(){ - return this.element; - }, + this.selectedRows = new Elements(); - inject: function(target, where){ - where = where || this.options.inject ? this.options.inject.where : '' || this.target == document.body ? 'inside' : 'after'; - target = target || this.options.inject ? this.options.inject.target : '' || this.target; - this.element.inject(target, where); - if (this.options.useIframeShim) { - this.shim = new IframeShim(this.element, this.options.iframeShimOptions); - this.addEvents({ - show: this.shim.show.bind(this.shim), - hide: this.shim.hide.bind(this.shim), - destroy: this.shim.destroy.bind(this.shim) - }); - } - }, - - position: function(){ - this.resize(this.options.width, this.options.height); - this.element.position({ - relativeTo: this.target, - position: 'topLeft', - ignoreMargins: !this.options.maskMargins, - ignoreScroll: this.target == document.body - }); - return this; - }, - - resize: function(x, y){ - var opt = { - styles: ['padding', 'border'] + this.bound = { + mouseleave: this.mouseleave.bind(this), + clickRow: this.clickRow.bind(this), + activateKeyboard: function() { + if (this.keyboard && this.selectEnabled) this.keyboard.activate(); + }.bind(this) }; - if (this.options.maskMargins) opt.styles.push('margin'); - var dim = this.target.getComputedSize(opt); - if (this.target == document.body) { - var win = window.getScrollSize(); - if (dim.totalHeight < win.y) dim.totalHeight = win.y; - if (dim.totalWidth < win.x) dim.totalWidth = win.x; + + if (this.options.selectable) this.enableSelect(); + }, + + empty: function(){ + this.selectNone(); + return this.previous(); + }, + + enableSelect: function(){ + this.selectEnabled = true; + this.attachSelects(); + this.element.addClass(this.options.classSelectable); + return this; + }, + + disableSelect: function(){ + this.selectEnabled = false; + this.attachSelects(false); + this.element.removeClass(this.options.classSelectable); + return this; + }, + + push: function(){ + var ret = this.previous.apply(this, arguments); + this.updateSelects(); + return ret; + }, + + isSelected: function(row){ + return this.selectedRows.contains(row); + }, + + toggleRow: function(row){ + return this[(this.isSelected(row) ? 'de' : '') + 'selectRow'](row); + }, + + selectRow: function(row, _nocheck){ + //private variable _nocheck: boolean whether or not to confirm the row is in the table body + //added here for optimization when selecting ranges + if (this.isSelected(row) || (!_nocheck && !this.body.getChildren().contains(row))) return; + if (!this.options.allowMultiSelect) this.selectNone(); + + if (!this.isSelected(row)){ + this.selectedRows.push(row); + row.addClass(this.options.classRowSelected); + this.fireEvent('rowFocus', [row, this.selectedRows]); + this.fireEvent('stateChanged'); } - this.element.setStyles({ - width: $pick(x, dim.totalWidth, dim.x), - height: $pick(y, dim.totalHeight, dim.y) + + this.focused = row; + document.clearSelection(); + + return this; + }, + + getSelected: function(){ + return this.selectedRows; + }, + + serialize: function() { + var previousSerialization = this.previous.apply(this, arguments) || {}; + if (this.options.selectable) { + previousSerialization.selectedRows = this.selectedRows.map(function(row) { + return Array.indexOf(this.body.rows, row); + }.bind(this)); + } + return previousSerialization; + }, + + restore: function(tableState) { + if(this.options.selectable && tableState.selectedRows) { + tableState.selectedRows.each(function(index) { + this.selectRow(this.body.rows[index]); + }.bind(this)); + } + this.previous.apply(this, arguments); + }, + + deselectRow: function(row, _nocheck){ + if (!this.isSelected(row) || (!_nocheck && !this.body.getChildren().contains(row))) return; + + this.selectedRows = new Elements(Array.from(this.selectedRows).erase(row)); + row.removeClass(this.options.classRowSelected); + this.fireEvent('rowUnfocus', [row, this.selectedRows]); + this.fireEvent('stateChanged'); + return this; + }, + + selectAll: function(selectNone){ + if (!selectNone && !this.options.allowMultiSelect) return; + this.selectRange(0, this.body.rows.length, selectNone); + return this; + }, + + selectNone: function(){ + return this.selectAll(true); + }, + + selectRange: function(startRow, endRow, _deselect){ + if (!this.options.allowMultiSelect && !_deselect) return; + var method = _deselect ? 'deselectRow' : 'selectRow', + rows = Array.clone(this.body.rows); + + if (typeOf(startRow) == 'element') startRow = rows.indexOf(startRow); + if (typeOf(endRow) == 'element') endRow = rows.indexOf(endRow); + endRow = endRow < rows.length - 1 ? endRow : rows.length - 1; + + if (endRow < startRow){ + var tmp = startRow; + startRow = endRow; + endRow = tmp; + } + + for (var i = startRow; i <= endRow; i++) this[method](rows[i], true); + + return this; + }, + + deselectRange: function(startRow, endRow){ + this.selectRange(startRow, endRow, true); + }, + + getSelected: function(){ + return this.selectedRows; + }, + +/* + Private methods: +*/ + + enterRow: function(row){ + if (this.hovered) this.hovered = this.leaveRow(this.hovered); + this.hovered = row.addClass(this.options.classRowHovered); + }, + + leaveRow: function(row){ + row.removeClass(this.options.classRowHovered); + }, + + updateSelects: function(){ + Array.each(this.body.rows, function(row){ + var binders = row.retrieve('binders'); + if (!binders && !this.selectEnabled) return; + if (!binders){ + binders = { + mouseenter: this.enterRow.pass([row], this), + mouseleave: this.leaveRow.pass([row], this) + }; + row.store('binders', binders); + } + if (this.selectEnabled) row.addEvents(binders); + else row.removeEvents(binders); + }, this); + }, + + shiftFocus: function(offset, event){ + if (!this.focused) return this.selectRow(this.body.rows[0], event); + var to = this.getRowByOffset(offset); + if (to === null || this.focused == this.body.rows[to]) return this; + this.toggleRow(this.body.rows[to], event); + }, + + clickRow: function(event, row){ + var selecting = (event.shift || event.meta || event.control) && this.options.shiftForMultiSelect; + if (!selecting && !(event.rightClick && this.isSelected(row) && this.options.allowMultiSelect)) this.selectNone(); + + if (event.rightClick) this.selectRow(row); + else this.toggleRow(row); + + if (event.shift){ + this.selectRange(this.rangeStart || this.body.rows[0], row, this.rangeStart ? !this.isSelected(row) : true); + this.focused = row; + } + this.rangeStart = row; + }, + + getRowByOffset: function(offset){ + if (!this.focused) return 0; + var rows = Array.clone(this.body.rows), + index = rows.indexOf(this.focused) + offset; + + if (index < 0) index = null; + if (index >= rows.length) index = null; + + return index; + }, + + attachSelects: function(attach){ + attach = attach != null ? attach : true; + + var method = attach ? 'addEvents' : 'removeEvents'; + this.element[method]({ + mouseleave: this.bound.mouseleave, + click: this.bound.activateKeyboard }); - return this; - }, - show: function(){ - if (!this.hidden) return this; - window.addEvent('resize', this.position); - this.position(); - this.showMask.apply(this, arguments); - return this; - }, + this.body[method]({ + 'click:relay(tr)': this.bound.clickRow, + 'contextmenu:relay(tr)': this.bound.clickRow + }); - showMask: function(){ - this.element.setStyle('display', 'block'); - this.hidden = false; - this.fireEvent('show'); - }, + if (this.options.useKeyboard || this.keyboard){ + if (!this.keyboard) this.keyboard = new Keyboard(); + if (!this.selectKeysDefined) { + this.selectKeysDefined = true; + var timer, held; - hide: function(){ - if (this.hidden) return this; - window.removeEvent('resize', this.position); - this.hideMask.apply(this, arguments); - if (this.options.destroyOnHide) return this.destroy(); - return this; - }, + var move = function(offset){ + var mover = function(e){ + clearTimeout(timer); + e.preventDefault(); - hideMask: function(){ - this.element.setStyle('display', 'none'); - this.hidden = true; - this.fireEvent('hide'); - }, + var to = this.body.rows[this.getRowByOffset(offset)]; + if (e.shift && to && this.isSelected(to)){ + this.deselectRow(this.focused); + this.focused = to; + } else { + if (to && (!this.options.allowMultiSelect || !e.shift)){ + this.selectNone(); + } + this.shiftFocus(offset, e); + } - toggle: function(){ - this[this.hidden ? 'show' : 'hide'](); - }, + if (held){ + timer = mover.delay(100, this, e); + } else { + timer = (function(){ + held = true; + mover(e); + }).delay(400); + } + }.bind(this); + return mover; + }.bind(this); - destroy: function(){ - this.hide(); - this.element.destroy(); - this.fireEvent('destroy'); - this.target.eliminate('mask'); - } + var clear = function(){ + clearTimeout(timer); + held = false; + }; + + this.keyboard.addEvents({ + 'keydown:shift+up': move(-1), + 'keydown:shift+down': move(1), + 'keyup:shift+up': clear, + 'keyup:shift+down': clear, + 'keyup:up': clear, + 'keyup:down': clear + }); -}); + var shiftHint = ''; + if (this.options.allowMultiSelect && this.options.shiftForMultiSelect && this.options.useKeyboard){ + shiftHint = " (Shift multi-selects)."; + } -Element.Properties.mask = { + this.keyboard.addShortcuts({ + 'Select Previous Row': { + keys: 'up', + shortcut: 'up arrow', + handler: move(-1), + description: 'Select the previous row in the table.' + shiftHint + }, + 'Select Next Row': { + keys: 'down', + shortcut: 'down arrow', + handler: move(1), + description: 'Select the next row in the table.' + shiftHint + } + }); - set: function(options){ - var mask = this.retrieve('mask'); - return this.eliminate('mask').store('mask:options', options); - }, - - get: function(options){ - if (options || !this.retrieve('mask')){ - if (this.retrieve('mask')) this.retrieve('mask').destroy(); - if (options || !this.retrieve('mask:options')) this.set('mask', options); - this.store('mask', new Mask(this, this.retrieve('mask:options'))); + } + this.keyboard[attach ? 'activate' : 'deactivate'](); } - return this.retrieve('mask'); - } - -}; - -Element.implement({ - - mask: function(options){ - this.get('mask', options).show(); - return this; + this.updateSelects(); }, - unmask: function(){ - this.get('mask').hide(); - return this; + mouseleave: function(){ + if (this.hovered) this.leaveRow(this.hovered); } }); + /* --- @@ -8063,6 +9696,7 @@ requires: - Core/Options - Core/Element.Event - Core/Element.Dimensions + - MooTools.More provides: [Scroller] @@ -8086,7 +9720,7 @@ var Scroller = new Class({ this.setOptions(options); this.element = document.id(element); this.docBody = document.id(this.element.getDocument().body); - this.listener = ($type(this.element) != 'element') ? this.docBody : this.element; + this.listener = (typeOf(this.element) != 'element') ? this.docBody : this.element; this.timer = null; this.bound = { attach: this.attach.bind(this), @@ -8097,18 +9731,20 @@ var Scroller = new Class({ start: function(){ this.listener.addEvents({ - mouseenter: this.bound.attach, + mouseover: this.bound.attach, mouseleave: this.bound.detach }); + return this; }, stop: function(){ this.listener.removeEvents({ - mouseenter: this.bound.attach, + mouseover: this.bound.attach, mouseleave: this.bound.detach }); this.detach(); - this.timer = $clear(this.timer); + this.timer = clearInterval(this.timer); + return this; }, attach: function(){ @@ -8117,7 +9753,7 @@ var Scroller = new Class({ detach: function(){ this.listener.removeEvent('mousemove', this.bound.getCoords); - this.timer = $clear(this.timer); + this.timer = clearInterval(this.timer); }, getCoords: function(event){ @@ -8126,17 +9762,17 @@ var Scroller = new Class({ }, scroll: function(){ - var size = this.element.getSize(), - scroll = this.element.getScroll(), - pos = this.element != this.docBody ? this.element.getOffsets() : {x: 0, y:0}, - scrollSize = this.element.getScrollSize(), + var size = this.element.getSize(), + scroll = this.element.getScroll(), + pos = this.element != this.docBody ? this.element.getOffsets() : {x: 0, y:0}, + scrollSize = this.element.getScrollSize(), change = {x: 0, y: 0}, top = this.options.area.top || this.options.area, - bottom = this.options.area.bottom || this.options.area; + bottom = this.options.area.bottom || this.options.area; for (var z in this.page){ - if (this.page[z] < (top + pos[z]) && scroll[z] != 0) { + if (this.page[z] < (top + pos[z]) && scroll[z] != 0){ change[z] = (this.page[z] - top - pos[z]) * this.options.velocity; - } else if (this.page[z] + bottom > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z]) { + } else if (this.page[z] + bottom > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z]){ change[z] = (this.page[z] - size[z] + bottom - pos[z]) * this.options.velocity; } change[z] = change[z].round(); @@ -8161,6 +9797,7 @@ license: MIT-style license authors: - Valerio Proietti - Christoph Pojer + - Luis Merino requires: - Core/Options @@ -8178,18 +9815,17 @@ provides: [Tips] (function(){ var read = function(option, element){ - return (option) ? ($type(option) == 'function' ? option(element) : element.get(option)) : ''; + return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : ''; }; this.Tips = new Class({ Implements: [Events, Options], - options: { - /* - onAttach: $empty(element), - onDetach: $empty(element), - */ + options: {/* + onAttach: function(element){}, + onDetach: function(element){}, + onBound: function(coords){},*/ onShow: function(){ this.tip.setStyle('display', 'block'); }, @@ -8209,7 +9845,12 @@ this.Tips = new Class({ }, initialize: function(){ - var params = Array.link(arguments, {options: Object.type, elements: $defined}); + var params = Array.link(arguments, { + options: Type.isObject, + elements: function(obj){ + return obj != null; + } + }); this.setOptions(params.options); if (params.elements) this.attach(params.elements); this.container = new Element('div', {'class': 'tip'}); @@ -8218,7 +9859,7 @@ this.Tips = new Class({ toElement: function(){ if (this.tip) return this.tip; - return this.tip = new Element('div', { + this.tip = new Element('div', { 'class': this.options.className, styles: { position: 'absolute', @@ -8230,28 +9871,32 @@ this.Tips = new Class({ this.container, new Element('div', {'class': 'tip-bottom'}) ); + + return this.tip; }, attach: function(elements){ $$(elements).each(function(element){ var title = read(this.options.title, element), text = read(this.options.text, element); - - element.erase('title').store('tip:native', title).retrieve('tip:title', title); + + element.set('title', '').store('tip:native', title).retrieve('tip:title', title); element.retrieve('tip:text', text); this.fireEvent('attach', [element]); - + var events = ['enter', 'leave']; if (!this.options.fixed) events.push('move'); - + events.each(function(value){ var event = element.retrieve('tip:' + value); - if (!event) event = this['element' + value.capitalize()].bindWithEvent(this, element); - + if (!event) event = function(event){ + this['element' + value.capitalize()].apply(this, [event, element]); + }.bind(this); + element.store('tip:' + value, event).addEvent('mouse' + value, event); }, this); }, this); - + return this; }, @@ -8260,39 +9905,57 @@ this.Tips = new Class({ ['enter', 'leave', 'move'].each(function(value){ element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value); }); - + this.fireEvent('detach', [element]); - + if (this.options.title == 'title'){ // This is necessary to check if we can revert the title var original = element.retrieve('tip:native'); if (original) element.set('title', original); } }, this); - + return this; }, elementEnter: function(event, element){ - this.container.empty(); - - ['title', 'text'].each(function(value){ - var content = element.retrieve('tip:' + value); - if (content) this.fill(new Element('div', {'class': 'tip-' + value}).inject(this.container), content); - }, this); - - $clear(this.timer); + clearTimeout(this.timer); this.timer = (function(){ + this.container.empty(); + + ['title', 'text'].each(function(value){ + var content = element.retrieve('tip:' + value); + var div = this['_' + value + 'Element'] = new Element('div', { + 'class': 'tip-' + value + }).inject(this.container); + if (content) this.fill(div, content); + }, this); this.show(element); this.position((this.options.fixed) ? {page: element.getPosition()} : event); }).delay(this.options.showDelay, this); }, elementLeave: function(event, element){ - $clear(this.timer); + clearTimeout(this.timer); this.timer = this.hide.delay(this.options.hideDelay, this, element); this.fireForParent(event, element); }, + setTitle: function(title){ + if (this._titleElement){ + this._titleElement.empty(); + this.fill(this._titleElement, title); + } + return this; + }, + + setText: function(text){ + if (this._textElement){ + this._textElement.empty(); + this.fill(this._textElement, text); + } + return this; + }, + fireForParent: function(event, element){ element = element.getParent(); if (!element || element == document.body) return; @@ -8310,18 +9973,24 @@ this.Tips = new Class({ var size = window.getSize(), scroll = window.getScroll(), tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight}, props = {x: 'left', y: 'top'}, + bounds = {y: false, x2: false, y2: false, x: false}, obj = {}; - + for (var z in props){ obj[props[z]] = event.page[z] + this.options.offset[z]; - if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; + if (obj[props[z]] < 0) bounds[z] = true; + if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]){ + obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; + bounds[z+'2'] = true; + } } - + + this.fireEvent('bound', bounds); this.tip.setStyles(obj); }, fill: function(element, contents){ - if(typeof contents == 'string') element.set('html', contents); + if (typeof contents == 'string') element.set('html', contents); else element.adopt(contents); }, @@ -8344,11 +10013,9 @@ this.Tips = new Class({ /* --- -script: Spinner.js +name: Locale.en-GB.Date -name: Spinner - -description: Adds a semi-transparent overlay over a dom element with a spinnin ajax icon. +description: Date messages for British English. license: MIT-style license @@ -8356,319 +10023,20 @@ authors: - Aaron Newton requires: - - Core/Fx.Tween - - Core/Request - - /Class.refactor - - /Mask + - /Locale + - /Locale.en-US.Date -provides: [Spinner] +provides: [Locale.en-GB.Date] ... */ -var Spinner = new Class({ +Locale.define('en-GB', 'Date', { - Extends: Mask, + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M' - options: { - /*message: false,*/ - 'class':'spinner', - containerPosition: {}, - content: { - 'class':'spinner-content' - }, - messageContainer: { - 'class':'spinner-msg' - }, - img: { - 'class':'spinner-img' - }, - fxOptions: { - link: 'chain' - } - }, +}).inherit('en-US', 'Date'); - initialize: function(){ - this.parent.apply(this, arguments); - this.target.store('spinner', this); - - //add this to events for when noFx is true; parent methods handle hide/show - var deactivate = function(){ this.active = false; }.bind(this); - this.addEvents({ - hide: deactivate, - show: deactivate - }); - }, - - render: function(){ - this.parent(); - this.element.set('id', this.options.id || 'spinner-'+$time()); - this.content = document.id(this.options.content) || new Element('div', this.options.content); - this.content.inject(this.element); - if (this.options.message) { - this.msg = document.id(this.options.message) || new Element('p', this.options.messageContainer).appendText(this.options.message); - this.msg.inject(this.content); - } - if (this.options.img) { - this.img = document.id(this.options.img) || new Element('div', this.options.img); - this.img.inject(this.content); - } - this.element.set('tween', this.options.fxOptions); - }, - - show: function(noFx){ - if (this.active) return this.chain(this.show.bind(this)); - if (!this.hidden) { - this.callChain.delay(20, this); - return this; - } - this.active = true; - return this.parent(noFx); - }, - - showMask: function(noFx){ - var pos = function(){ - this.content.position($merge({ - relativeTo: this.element - }, this.options.containerPosition)); - }.bind(this); - if (noFx) { - this.parent(); - pos(); - } else { - this.element.setStyles({ - display: 'block', - opacity: 0 - }).tween('opacity', this.options.style.opacity || 0.9); - pos(); - this.hidden = false; - this.fireEvent('show'); - this.callChain(); - } - }, - - hide: function(noFx){ - if (this.active) return this.chain(this.hide.bind(this)); - if (this.hidden) { - this.callChain.delay(20, this); - return this; - } - this.active = true; - return this.parent(noFx); - }, - - hideMask: function(noFx){ - if (noFx) return this.parent(); - this.element.tween('opacity', 0).get('tween').chain(function(){ - this.element.setStyle('display', 'none'); - this.hidden = true; - this.fireEvent('hide'); - this.callChain(); - }.bind(this)); - }, - - destroy: function(){ - this.content.destroy(); - this.parent(); - this.target.eliminate('spinner'); - } - -}); - -Spinner.implement(new Chain); - -Request = Class.refactor(Request, { - - options: { - useSpinner: false, - spinnerOptions: {}, - spinnerTarget: false - }, - - initialize: function(options){ - this._send = this.send; - this.send = function(options){ - var spinner = this.getSpinner(); - if (spinner) spinner.chain(this._send.bind(this, options)).show(); - else this._send(options); - return this; - }; - this.previous(options); - }, - - getSpinner: function(){ - if (!this.spinner) { - var update = document.id(this.options.spinnerTarget) || document.id(this.options.update); - if (this.options.useSpinner && update) { - this.spinner = update.get('spinner', this.options.spinnerOptions); - ['onComplete', 'onException', 'onCancel'].each(function(event){ - this.addEvent(event, this.spinner.hide.bind(this.spinner)); - }, this); - } - } - return this.spinner; - } - -}); - -Element.Properties.spinner = { - - set: function(options){ - var spinner = this.retrieve('spinner'); - return this.eliminate('spinner').store('spinner:options', options); - }, - - get: function(options){ - if (options || !this.retrieve('spinner')){ - if (this.retrieve('spinner')) this.retrieve('spinner').destroy(); - if (options || !this.retrieve('spinner:options')) this.set('spinner', options); - new Spinner(this, this.retrieve('spinner:options')); - } - return this.retrieve('spinner'); - } - -}; - -Element.implement({ - - spin: function(options){ - this.get('spinner', options).show(); - return this; - }, - - unspin: function(){ - var opt = Array.link(arguments, {options: Object.type, callback: Function.type}); - this.get('spinner', opt.options).hide(opt.callback); - return this; - } - -}); - -/* ---- - -script: Date.English.US.js - -name: Date.English.US - -description: Date messages for US English. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - /Lang - -provides: [Date.English.US] - -... -*/ - -MooTools.lang.set('en-US', 'Date', { - - months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - - // Culture's date order: MM/DD/YYYY - dateOrder: ['month', 'date', 'year'], - shortDate: '%m/%d/%Y', - shortTime: '%I:%M%p', - AM: 'AM', - PM: 'PM', - - // Date.Extras - ordinal: function(dayOfMonth){ - // 1st, 2nd, 3rd, etc. - return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)]; - }, - - lessThanMinuteAgo: 'less than a minute ago', - minuteAgo: 'about a minute ago', - minutesAgo: '{delta} minutes ago', - hourAgo: 'about an hour ago', - hoursAgo: 'about {delta} hours ago', - dayAgo: '1 day ago', - daysAgo: '{delta} days ago', - weekAgo: '1 week ago', - weeksAgo: '{delta} weeks ago', - monthAgo: '1 month ago', - monthsAgo: '{delta} months ago', - yearAgo: '1 year ago', - yearsAgo: '{delta} years ago', - - lessThanMinuteUntil: 'less than a minute from now', - minuteUntil: 'about a minute from now', - minutesUntil: '{delta} minutes from now', - hourUntil: 'about an hour from now', - hoursUntil: 'about {delta} hours from now', - dayUntil: '1 day from now', - daysUntil: '{delta} days from now', - weekUntil: '1 week from now', - weeksUntil: '{delta} weeks from now', - monthUntil: '1 month from now', - monthsUntil: '{delta} months from now', - yearUntil: '1 year from now', - yearsUntil: '{delta} years from now' - -}); - - -/* ---- - -script: Form.Validator.English.js - -name: Form.Validator.English - -description: Form Validator messages for English. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - /Lang - -provides: [Form.Validator.English] - -... -*/ - -MooTools.lang.set('en-US', 'Form.Validator', { - - required: 'This field is required.', - minLength: 'Please enter at least {minLength} characters (you entered {length} characters).', - maxLength: 'Please enter no more than {maxLength} characters (you entered {length} characters).', - integer: 'Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.', - numeric: 'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").', - digits: 'Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).', - alpha: 'Please use only letters (a-z) within this field. No spaces or other characters are allowed.', - alphanum: 'Please use only letters (a-z) or numbers (0-9) in this field. No spaces or other characters are allowed.', - dateSuchAs: 'Please enter a valid date such as {date}', - dateInFormatMDY: 'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")', - email: 'Please enter a valid email address. For example "fred@domain.com".', - url: 'Please enter a valid URL such as http://www.google.com.', - currencyDollar: 'Please enter a valid $ amount. For example $100.00 .', - oneRequired: 'Please enter something for at least one of these inputs.', - errorPrefix: 'Error: ', - warningPrefix: 'Warning: ', - - // Form.Validator.Extras - noSpace: 'There can be no spaces in this input.', - reqChkByNode: 'No items are selected.', - requiredChk: 'This field is required.', - reqChkByName: 'Please select a {label}.', - match: 'This field needs to match the {matchName} field', - startDate: 'the start date', - endDate: 'the end date', - currendDate: 'the current date', - afterDate: 'The date should be the same or after {label}.', - beforeDate: 'The date should be the same or before {label}.', - startMonth: 'Please select a start month', - sameMonth: 'These two dates must be in the same month - you must change one or the other.', - creditcard: 'The credit card number entered is invalid. Please check the number and try again. {length} digits entered.' - -}); diff --git a/web/tools/mootools/mootools-more-1.3.2.1-yc.js b/web/tools/mootools/mootools-more-1.3.2.1-yc.js new file mode 100644 index 000000000..807e27ecf --- /dev/null +++ b/web/tools/mootools/mootools-more-1.3.2.1-yc.js @@ -0,0 +1,742 @@ +// MooTools: the javascript framework. +// Load this file's selection again by visiting: http://mootools.net/more/09f3e47813269cd5026cbf8c1f828e72 +// Or build this file again with packager using: packager build More/Chain.Wait More/Array.Extras More/Date More/Date.Extras More/Number.Format More/String.Extras More/String.QueryString More/URI More/URI.Relative More/Hash More/Hash.Extras More/Element.Forms More/Elements.From More/Element.Event.Pseudos.Keys More/Element.Pin More/Element.Position More/Element.Shortcuts More/Form.Request More/Form.Request.Append More/Form.Validator.Inline More/Form.Validator.Extras More/OverText More/Fx.Accordion More/Fx.Move More/Fx.Reveal More/Fx.Slide More/Fx.SmoothScroll More/Fx.Sort More/Drag.Move More/Slider More/Sortables More/Request.JSONP More/Request.Queue More/Request.Periodical More/Assets More/Color More/Group More/Hash.Cookie More/Table More/HtmlTable.Zebra More/HtmlTable.Sort More/HtmlTable.Select More/Keyboard.Extras More/Mask More/Scroller More/Tips More/Locale.en-GB.Date +/* +--- +copyrights: + - [MooTools](http://mootools.net) + +licenses: + - [MIT License](http://mootools.net/license.txt) +... +*/ +MooTools.More={version:"1.3.2.1",build:"e586bcd2496e9b22acfde32e12f84d49ce09e59d"};(function(){var a={wait:function(b){return this.chain(function(){this.callChain.delay(b==null?500:b,this); +return this;}.bind(this));}};Chain.implement(a);if(this.Fx){Fx.implement(a);}if(this.Element&&Element.implement&&this.Fx){Element.implement({chains:function(b){Array.from(b||["tween","morph","reveal"]).each(function(c){c=this.get(c); +if(!c){return;}c.setOptions({link:"chain"});},this);return this;},pauseFx:function(c,b){this.chains(b).get(b||"tween").wait(c);return this;}});}})();(function(a){Array.implement({min:function(){return Math.min.apply(null,this); +},max:function(){return Math.max.apply(null,this);},average:function(){return this.length?this.sum()/this.length:0;},sum:function(){var b=0,c=this.length; +if(c){while(c--){b+=this[c];}}return b;},unique:function(){return[].combine(this);},shuffle:function(){for(var c=this.length;c&&--c;){var b=this[c],d=Math.floor(Math.random()*(c+1)); +this[c]=this[d];this[d]=b;}return this;},reduce:function(d,e){for(var c=0,b=this.length;c3&&a<21)?"th":["th","st","nd","rd","th"][Math.min(a%10,4)]; +},lessThanMinuteAgo:"less than a minute ago",minuteAgo:"about a minute ago",minutesAgo:"{delta} minutes ago",hourAgo:"about an hour ago",hoursAgo:"about {delta} hours ago",dayAgo:"1 day ago",daysAgo:"{delta} days ago",weekAgo:"1 week ago",weeksAgo:"{delta} weeks ago",monthAgo:"1 month ago",monthsAgo:"{delta} months ago",yearAgo:"1 year ago",yearsAgo:"{delta} years ago",lessThanMinuteUntil:"less than a minute from now",minuteUntil:"about a minute from now",minutesUntil:"{delta} minutes from now",hourUntil:"about an hour from now",hoursUntil:"about {delta} hours from now",dayUntil:"1 day from now",daysUntil:"{delta} days from now",weekUntil:"1 week from now",weeksUntil:"{delta} weeks from now",monthUntil:"1 month from now",monthsUntil:"{delta} months from now",yearUntil:"1 year from now",yearsUntil:"{delta} years from now"}); +(function(){var a=this.Date;var f=a.Methods={ms:"Milliseconds",year:"FullYear",min:"Minutes",mo:"Month",sec:"Seconds",hr:"Hours"};["Date","Day","FullYear","Hours","Milliseconds","Minutes","Month","Seconds","Time","TimezoneOffset","Week","Timezone","GMTOffset","DayOfYear","LastMonth","LastDayOfMonth","UTCDate","UTCDay","UTCFullYear","AMPM","Ordinal","UTCHours","UTCMilliseconds","UTCMinutes","UTCMonth","UTCSeconds","UTCMilliseconds"].each(function(t){a.Methods[t.toLowerCase()]=t; +});var p=function(v,u,t){if(u==1){return v;}return v28){return 1;}if(z==0&&t<-2){y=new a(y).decrement("day",v); +v=0;}x=new a(y.get("year"),0,1).get("day")||7;if(x>4){u=-7;}}else{x=new a(y.get("year"),0,1).get("day");}u+=y.get("dayofyear");u+=6-v;u+=(7+x-w)%7;return(u/7); +},getOrdinal:function(t){return a.getMsg("ordinal",t||this.get("date"));},getTimezone:function(){return this.toString().replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3"); +},getGMTOffset:function(){var t=this.get("timezoneOffset");return((t>0)?"-":"+")+p((t.abs()/60).floor(),2)+p(t%60,2);},setAMPM:function(t){t=t.toUpperCase(); +var u=this.get("hr");if(u>11&&t=="AM"){return this.decrement("hour",12);}else{if(u<12&&t=="PM"){return this.increment("hour",12);}}return this;},getAMPM:function(){return(this.get("hr")<12)?"AM":"PM"; +},parse:function(t){this.set("time",a.parse(t));return this;},isValid:function(t){return !isNaN((t||this).valueOf());},format:function(u){if(!this.isValid()){return"invalid date"; +}if(!u){u="%x %X";}var t=u.toLowerCase();if(s[t]){return s[t](this);}u=g[t]||u;var v=this;return u.replace(/%([a-z%])/gi,function(x,w){switch(w){case"a":return a.getMsg("days_abbr")[v.get("day")]; +case"A":return a.getMsg("days")[v.get("day")];case"b":return a.getMsg("months_abbr")[v.get("month")];case"B":return a.getMsg("months")[v.get("month")]; +case"c":return v.format("%a %b %d %H:%M:%S %Y");case"d":return p(v.get("date"),2);case"e":return p(v.get("date"),2," ");case"H":return p(v.get("hr"),2); +case"I":return p((v.get("hr")%12)||12,2);case"j":return p(v.get("dayofyear"),3);case"k":return p(v.get("hr"),2," ");case"l":return p((v.get("hr")%12)||12,2," "); +case"L":return p(v.get("ms"),3);case"m":return p((v.get("mo")+1),2);case"M":return p(v.get("min"),2);case"o":return v.get("ordinal");case"p":return a.getMsg(v.get("ampm")); +case"s":return Math.round(v/1000);case"S":return p(v.get("seconds"),2);case"T":return v.format("%H:%M:%S");case"U":return p(v.get("week"),2);case"w":return v.get("day"); +case"x":return v.format(a.getMsg("shortDate"));case"X":return v.format(a.getMsg("shortTime"));case"y":return v.get("year").toString().substr(2);case"Y":return v.get("year"); +case"z":return v.get("GMTOffset");case"Z":return v.get("Timezone");}return w;});},toISOString:function(){return this.format("iso8601");}}).alias({toJSON:"toISOString",compare:"diff",strftime:"format"}); +var g={db:"%Y-%m-%d %H:%M:%S",compact:"%Y%m%dT%H%M%S","short":"%d %b %H:%M","long":"%B %d, %Y %H:%M"};var k=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; +var s={rfc822:function(t){return k[t.get("day")]+t.format(", %d ")+h[t.get("month")]+t.format(" %Y %H:%M:%S %Z");},rfc2822:function(t){return k[t.get("day")]+t.format(", %d ")+h[t.get("month")]+t.format(" %Y %H:%M:%S %z"); +},iso8601:function(t){return(t.getUTCFullYear()+"-"+p(t.getUTCMonth()+1,2)+"-"+p(t.getUTCDate(),2)+"T"+p(t.getUTCHours(),2)+":"+p(t.getUTCMinutes(),2)+":"+p(t.getUTCSeconds(),2)+"."+p(t.getUTCMilliseconds(),3)+"Z"); +}};var c=[],n=a.parse;var r=function(w,y,v){var u=-1,x=a.getMsg(w+"s");switch(typeOf(y)){case"object":u=x[y.get(w)];break;case"number":u=x[y];if(!u){throw new Error("Invalid "+w+" index: "+y); +}break;case"string":var t=x.filter(function(z){return this.test(z);},new RegExp("^"+y,"i"));if(!t.length){throw new Error("Invalid "+w+" string");}if(t.length>1){throw new Error("Ambiguous "+w); +}u=t[0];}return(v)?x.indexOf(u):u;};var i=1900,o=70;a.extend({getMsg:function(u,t){return Locale.get("Date."+u,t);},units:{ms:Function.from(1),second:Function.from(1000),minute:Function.from(60000),hour:Function.from(3600000),day:Function.from(86400000),week:Function.from(608400000),month:function(u,t){var v=new a; +return a.daysInMonth(u!=null?u:v.get("mo"),t!=null?t:v.get("year"))*86400000;},year:function(t){t=t||new a().get("year");return a.isLeapYear(t)?31622400000:31536000000; +}},daysInMonth:function(u,t){return[31,a.isLeapYear(t)?29:28,31,30,31,30,31,31,30,31,30,31][u];},isLeapYear:function(t){return((t%4===0)&&(t%100!==0))||(t%400===0); +},parse:function(w){var v=typeOf(w);if(v=="number"){return new a(w);}if(v!="string"){return w;}w=w.clean();if(!w.length){return null;}var u;c.some(function(x){var t=x.re.exec(w); +return(t)?(u=x.handler(t)):false;});if(!(u&&u.isValid())){u=new a(n(w));if(!(u&&u.isValid())){u=new a(w.toInt());}}return u;},parseDay:function(t,u){return r("day",t,u); +},parseMonth:function(u,t){return r("month",u,t);},parseUTC:function(u){var t=new a(u);var v=a.UTC(t.get("year"),t.get("mo"),t.get("date"),t.get("hr"),t.get("min"),t.get("sec"),t.get("ms")); +return new a(v);},orderIndex:function(t){return a.getMsg("dateOrder").indexOf(t)+1;},defineFormat:function(t,u){g[t]=u;return this;},defineFormats:function(t){for(var u in t){a.defineFormat(u,t[u]); +}return this;},defineParser:function(t){c.push((t.re&&t.handler)?t:l(t));return this;},defineParsers:function(){Array.flatten(arguments).each(a.defineParser); +return this;},define2DigitYearStart:function(t){o=t%100;i=t-o;return this;}});var d=function(t){return new RegExp("(?:"+a.getMsg(t).map(function(u){return u.substr(0,3); +}).join("|")+")[a-z]*");};var m=function(t){switch(t){case"T":return"%H:%M:%S";case"x":return((a.orderIndex("month")==1)?"%m[-./]%d":"%d[-./]%m")+"([-./]%y)?"; +case"X":return"%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?";}return null;};var j={d:/[0-2]?[0-9]|3[01]/,H:/[01]?[0-9]|2[0-3]/,I:/0?[1-9]|1[0-2]/,M:/[0-5]?\d/,s:/\d+/,o:/[a-z]*/,p:/[ap]\.?m\.?/,y:/\d{2}|\d{4}/,Y:/\d{4}/,z:/Z|[+-]\d{2}(?::?\d{2})?/}; +j.m=j.I;j.S=j.M;var e;var b=function(t){e=t;j.a=j.A=d("days");j.b=j.B=d("months");c.each(function(v,u){if(v.format){c[u]=l(v.format);}});};var l=function(v){if(!e){return{format:v}; +}var t=[];var u=(v.source||v).replace(/%([a-z])/gi,function(x,w){return m(w)||x;}).replace(/\((?!\?)/g,"(?:").replace(/ (?!\?|\*)/g,",? ").replace(/%([a-z%])/gi,function(x,w){var y=j[w]; +if(!y){return w;}t.push(w);return"("+y.source+")";}).replace(/\[a-z\]/gi,"[a-z\\u00c0-\\uffff;&]");return{format:v,re:new RegExp("^"+u+"$","i"),handler:function(z){z=z.slice(1).associate(t); +var w=new a().clearTime(),y=z.y||z.Y;if(y!=null){q.call(w,"y",y);}if("d" in z){q.call(w,"d",1);}if("m" in z||z.b||z.B){q.call(w,"m",1);}for(var x in z){q.call(w,x,z[x]); +}return w;}};};var q=function(t,u){if(!u){return this;}switch(t){case"a":case"A":return this.set("day",a.parseDay(u,true));case"b":case"B":return this.set("mo",a.parseMonth(u,true)); +case"d":return this.set("date",u);case"H":case"I":return this.set("hr",u);case"m":return this.set("mo",u-1);case"M":return this.set("min",u);case"p":return this.set("ampm",u.replace(/\./g,"")); +case"S":return this.set("sec",u);case"s":return this.set("ms",("0."+u)*1000);case"w":return this.set("day",u);case"Y":return this.set("year",u);case"y":u=+u; +if(u<100){u+=i+(u0.75*a){e=c;}break;}f/=a;e=c+"s";}f=f.round();return Date.getMsg(e+d,f).substitute({delta:f});}}).defineParsers({re:/^(?:tod|tom|yes)/i,handler:function(a){var b=new Date().clearTime(); +switch(a[0]){case"tom":return b.increment();case"yes":return b.decrement();default:return b;}}},{re:/^(next|last) ([a-z]+)$/i,handler:function(e){var f=new Date().clearTime(); +var b=f.getDay();var c=Date.parseDay(e[2],true);var a=c-b;if(c<=b){a+=7;}if(e[1]=="last"){a-=7;}return f.set("date",f.getDate()+a);}}).alias("timeAgoInWords","timeDiffInWords"); +Locale.define("en-US","Number",{decimal:".",group:",",currency:{prefix:"$ "}});Number.implement({format:function(q){var n=this;q=q?Object.clone(q):{};var a=function(i){if(q[i]!=null){return q[i]; +}return Locale.get("Number."+i);};var f=n<0,h=a("decimal"),k=a("precision"),o=a("group"),c=a("decimals");if(f){var e=a("negative")||{};if(e.prefix==null&&e.suffix==null){e.prefix="-"; +}["prefix","suffix"].each(function(i){if(e[i]){q[i]=a(i)+e[i];}});n=-n;}var l=a("prefix"),p=a("suffix");if(c!==""&&c>=0&&c<=20){n=n.toFixed(c);}if(k>=1&&k<=21){n=(+n).toPrecision(k); +}n+="";var m;if(a("scientific")===false&&n.indexOf("e")>-1){var j=n.split("e"),b=+j[1];n=j[0].replace(".","");if(b<0){b=-b-1;m=j[0].indexOf(".");if(m>-1){b-=m-1; +}while(b--){n="0"+n;}n="0."+n;}else{m=j[0].lastIndexOf(".");if(m>-1){b-=j[0].length-m-1;}while(b--){n+="0";}}}if(h!="."){n=n.replace(".",h);}if(o){m=n.lastIndexOf(h); +m=(m>-1)?m:n.length;var d=n.substring(m),g=m;while(g--){if((m-g-1)%3==0&&g!=(m-1)){d=o+d;}d=n.charAt(g)+d;}n=d;}if(l){n=l+n;}if(p){n+=p;}return n;},formatCurrency:function(){var a=Locale.get("Number.currency")||{}; +if(a.scientific==null){a.scientific=false;}if(a.decimals==null){a.decimals=2;}return this.format(a);},formatPercentage:function(){var a=Locale.get("Number.percentage")||{}; +if(a.suffix==null){a.suffix="%";}if(a.decimals==null){a.decimals=2;}return this.format(a);}});(function(){var c={a:/[àáâãäåăą]/g,A:/[ÀÃÂÃÄÅĂĄ]/g,c:/[ćÄç]/g,C:/[ĆČÇ]/g,d:/[ÄÄ‘]/g,D:/[ÄŽÃ]/g,e:/[èéêëěę]/g,E:/[ÈÉÊËĚĘ]/g,g:/[ÄŸ]/g,G:/[Äž]/g,i:/[ìíîï]/g,I:/[ÃŒÃÃŽÃ]/g,l:/[ĺľł]/g,L:/[ĹĽÅ]/g,n:/[ñňń]/g,N:/[ÑŇŃ]/g,o:/[òóôõöøő]/g,O:/[ÒÓÔÕÖØ]/g,r:/[řŕ]/g,R:/[ŘŔ]/g,s:/[Å¡Å¡ÅŸ]/g,S:/[ŠŞŚ]/g,t:/[ťţ]/g,T:/[ŤŢ]/g,ue:/[ü]/g,UE:/[Ãœ]/g,u:/[ùúûůµ]/g,U:/[ÙÚÛŮ]/g,y:/[ÿý]/g,Y:/[ŸÃ]/g,z:/[žźż]/g,Z:/[ŽŹŻ]/g,th:/[þ]/g,TH:/[Þ]/g,dh:/[ð]/g,DH:/[Ã]/g,ss:/[ß]/g,oe:/[Å“]/g,OE:/[Å’]/g,ae:/[æ]/g,AE:/[Æ]/g},b={" ":/[\xa0\u2002\u2003\u2009]/g,"*":/[\xb7]/g,"'":/[\u2018\u2019]/g,'"':/[\u201c\u201d]/g,"...":/[\u2026]/g,"-":/[\u2013]/g,"»":/[\uFFFD]/g}; +var a=function(f,h){var e=f,g;for(g in h){e=e.replace(h[g],g);}return e;};var d=function(e,g){e=e||"";var h=g?"<"+e+"(?!\\w)[^>]*>([\\s\\S]*?)":"]+)?>",f=new RegExp(h,"gi"); +return f;};String.implement({standardize:function(){return a(this,c);},repeat:function(e){return new Array(e+1).join(this);},pad:function(e,h,g){if(this.length>=e){return this; +}var f=(h==null?" ":""+h).repeat(e-this.length).substr(0,e-this.length);if(!g||g=="right"){return this+f;}if(g=="left"){return f+this;}return f.substr(0,(f.length/2).floor())+this+f.substr(0,(f.length/2).ceil()); +},getTags:function(e,f){return this.match(d(e,f))||[];},stripTags:function(e,f){return this.replace(d(e,f),"");},tidy:function(){return a(this,b);},truncate:function(e,f,i){var h=this; +if(f==null&&arguments.length==1){f="…";}if(h.length>e){h=h.substring(0,e);if(i){var g=h.lastIndexOf(i);if(g!=-1){h=h.substr(0,g);}}if(f){h+=f;}}return h; +}});})();String.implement({parseQueryString:function(d,a){if(d==null){d=true;}if(a==null){a=true;}var c=this.split(/[&;]/),b={};if(!c.length){return b; +}c.each(function(i){var e=i.indexOf("=")+1,g=e?i.substr(e):"",f=e?i.substr(0,e-1).match(/([^\]\[]+|(\B)(?=\]))/g):[i],h=b;if(!f){return;}if(a){g=decodeURIComponent(g); +}f.each(function(k,j){if(d){k=decodeURIComponent(k);}var l=h[k];if(j0){c.pop(); +}else{if(f!="."){c.push(f);}}});return c.join("/")+"/";},combine:function(c){return c.value||c.scheme+"://"+(c.user?c.user+(c.password?":"+c.password:"")+"@":"")+(c.host||"")+(c.port&&c.port!=this.schemes[c.scheme]?":"+c.port:"")+(c.directory||"/")+(c.file||"")+(c.query?"?"+c.query:"")+(c.fragment?"#"+c.fragment:""); +},set:function(d,f,e){if(d=="value"){var c=f.match(a.regs.scheme);if(c){c=c[1];}if(c&&this.schemes[c.toLowerCase()]==null){this.parsed={scheme:c,value:f}; +}else{this.parsed=this.parse(f,(e||this).parsed)||(c?{scheme:c,value:f}:{value:f});}}else{if(d=="data"){this.setData(f);}else{this.parsed[d]=f;}}return this; +},get:function(c,d){switch(c){case"value":return this.combine(this.parsed,d?d.parsed:false);case"data":return this.getData();}return this.parsed[c]||""; +},go:function(){document.location.href=this.toString();},toURI:function(){return this;},getData:function(e,d){var c=this.get(d||"query");if(!(c||c===0)){return e?null:{}; +}var f=c.parseQueryString();return e?f[e]:f;},setData:function(c,f,d){if(typeof c=="string"){var e=this.getData();e[arguments[0]]=arguments[1];c=e;}else{if(f){c=Object.merge(this.getData(),c); +}}return this.set(d||"query",Object.toQueryString(c));},clearData:function(c){return this.set(c||"query","");},toString:b,valueOf:b});a.regs={endSlash:/\/$/,scheme:/^(\w+):/,directoryDot:/\.\/|\.$/}; +a.base=new a(Array.from(document.getElements("base[href]",true)).getLast(),{base:document.location});String.implement({toURI:function(c){return new a(this,c); +}});})();Class.refactor=function(b,a){Object.each(a,function(e,d){var c=b.prototype[d];c=(c&&c.$origin)||c||function(){};b.implement(d,(typeof e=="function")?function(){var f=this.previous; +this.previous=c;var g=e.apply(this,arguments);this.previous=f;return g;}:e);});return b;};URI=Class.refactor(URI,{combine:function(f,e){if(!e||f.scheme!=e.scheme||f.host!=e.host||f.port!=e.port){return this.previous.apply(this,arguments); +}var a=f.file+(f.query?"?"+f.query:"")+(f.fragment?"#"+f.fragment:"");if(!e.directory){return(f.directory||(f.file?"":"./"))+a;}var d=e.directory.split("/"),c=f.directory.split("/"),g="",h; +var b=0;for(h=0;h=0||g.parentPositioned||d.allowNegative)?c.x:0).toInt(); +c.top=((c.y>=0||g.parentPositioned||d.allowNegative)?c.y:0).toInt();a.toMinMax(c,d);if(d.relFixedPosition||f.getStyle("position")=="fixed"){a.toRelFixedPosition(f,c); +}if(d.ignoreScroll){a.toIgnoreScroll(f,c);}if(d.ignoreMargins){a.toIgnoreMargins(c,d);}c.left=Math.ceil(c.left);c.top=Math.ceil(c.top);delete c.x;delete c.y; +return c;},setPositionCoordinates:function(k,g,d){var f=k.offset.y,h=k.offset.x,e=(d==document.body)?window.getScroll():d.getPosition(),j=e.y,c=e.x,i=window.getSize(); +switch(k.position.x){case"left":g.x=c+h;break;case"right":g.x=c+h+d.offsetWidth;break;default:g.x=c+((d==document.body?i.x:d.offsetWidth)/2)+h;break;}switch(k.position.y){case"top":g.y=j+f; +break;case"bottom":g.y=j+f+d.offsetHeight;break;default:g.y=j+((d==document.body?i.y:d.offsetHeight)/2)+f;break;}},toMinMax:function(c,d){var f={left:"x",top:"y"},e; +["minimum","maximum"].each(function(g){["left","top"].each(function(h){e=d[g]?d[g][f[h]]:null;if(e!=null&&((g=="minimum")?c[h]e)){c[h]=e;}});}); +},toRelFixedPosition:function(e,c){var d=window.getScroll();c.top+=d.y;c.left+=d.x;},toIgnoreScroll:function(e,d){var c=e.getScroll();d.top-=c.y;d.left-=c.x; +},toIgnoreMargins:function(c,d){c.left+=d.edge.x=="right"?d.dimensions["margin-right"]:(d.edge.x!="center"?-d.dimensions["margin-left"]:-d.dimensions["margin-left"]+((d.dimensions["margin-right"]+d.dimensions["margin-left"])/2)); +c.top+=d.edge.y=="bottom"?d.dimensions["margin-bottom"]:(d.edge.y!="center"?-d.dimensions["margin-top"]:-d.dimensions["margin-top"]+((d.dimensions["margin-bottom"]+d.dimensions["margin-top"])/2)); +},toEdge:function(c,d){var e={},g=d.dimensions,f=d.edge;switch(f.x){case"left":e.x=0;break;case"right":e.x=-g.x-g.computedRight-g.computedLeft;break;default:e.x=-(Math.round(g.totalWidth/2)); +break;}switch(f.y){case"top":e.y=0;break;case"bottom":e.y=-g.y-g.computedTop-g.computedBottom;break;default:e.y=-(Math.round(g.totalHeight/2));break;}c.x+=e.x; +c.y+=e.y;},getCoordinateFromValue:function(c){if(typeOf(c)!="string"){return c;}c=c.toLowerCase();return{x:c.test("left")?"left":(c.test("right")?"right":"center"),y:c.test(/upper|top/)?"top":(c.test("bottom")?"bottom":"center")}; +}};Element.implement({position:function(d){if(d&&(d.x!=null||d.y!=null)){return(b?b.apply(this,arguments):this);}var c=this.setStyle("position","absolute").calculatePosition(d); +return(d&&d.returnPos)?c:this.setStyles(c);},calculatePosition:function(c){return a.getPosition(this,c);}});})(Element.prototype.position);Element.implement({isDisplayed:function(){return this.getStyle("display")!="none"; +},isVisible:function(){var a=this.offsetWidth,b=this.offsetHeight;return(a==0&&b==0)?false:(a>0&&b>0)?true:this.style.display!="none";},toggle:function(){return this[this.isDisplayed()?"hide":"show"](); +},hide:function(){var b;try{b=this.getStyle("display");}catch(a){}if(b=="none"){return this;}return this.store("element:_originalDisplay",b||"").setStyle("display","none"); +},show:function(a){if(!a&&this.isDisplayed()){return this;}a=a||this.retrieve("element:_originalDisplay")||"block";return this.setStyle("display",(a=="none")?"block":a); +},swapClass:function(a,b){return this.removeClass(a).addClass(b);}});Document.implement({clearSelection:function(){if(window.getSelection){var a=window.getSelection(); +if(a&&a.removeAllRanges){a.removeAllRanges();}}else{if(document.selection&&document.selection.empty){try{document.selection.empty();}catch(b){}}}}});Class.Mutators.Binds=function(a){if(!this.prototype.initialize){this.implement("initialize",function(){}); +}return Array.from(a).concat(this.prototype.Binds||[]);};Class.Mutators.initialize=function(a){return function(){Array.from(this.Binds).each(function(b){var c=this[b]; +if(c){this[b]=c.bind(this);}},this);return a.apply(this,arguments);};};Class.Occlude=new Class({occlude:function(c,b){b=document.id(b||this.element);var a=b.retrieve(c||this.property); +if(a&&!this.occluded){return(this.occluded=a);}this.occluded=false;b.store(c||this.property,this);return this.occluded;}});var IframeShim=new Class({Implements:[Options,Events,Class.Occlude],options:{className:"iframeShim",src:'javascript:false;document.write("");',display:false,zIndex:null,margin:0,offset:{x:0,y:0},browsers:(Browser.ie6||(Browser.firefox&&Browser.version<3&&Browser.Platform.mac))},property:"IframeShim",initialize:function(b,a){this.element=document.id(b); +if(this.occlude()){return this.occluded;}this.setOptions(a);this.makeShim();return this;},makeShim:function(){if(this.options.browsers){var c=this.element.getStyle("zIndex").toInt(); +if(!c){c=1;var b=this.element.getStyle("position");if(b=="static"||!b){this.element.setStyle("position","relative");}this.element.setStyle("zIndex",c); +}c=((this.options.zIndex!=null||this.options.zIndex===0)&&c>this.options.zIndex)?this.options.zIndex:c-1;if(c<0){c=1;}this.shim=new Element("iframe",{src:this.options.src,scrolling:"no",frameborder:0,styles:{zIndex:c,position:"absolute",border:"none",filter:"progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"},"class":this.options.className}).store("IframeShim",this); +var a=(function(){this.shim.inject(this.element,"after");this[this.options.display?"show":"hide"]();this.fireEvent("inject");}).bind(this);if(!IframeShim.ready){window.addEvent("load",a); +}else{a();}}else{this.position=this.hide=this.show=this.dispose=Function.from(this);}},position:function(){if(!IframeShim.ready||!this.shim){return this; +}var a=this.element.measure(function(){return this.getSize();});if(this.options.margin!=undefined){a.x=a.x-(this.options.margin*2);a.y=a.y-(this.options.margin*2); +this.options.offset.x+=this.options.margin;this.options.offset.y+=this.options.margin;}this.shim.set({width:a.x,height:a.y}).position({relativeTo:this.element,offset:this.options.offset}); +return this;},hide:function(){if(this.shim){this.shim.setStyle("display","none");}return this;},show:function(){if(this.shim){this.shim.setStyle("display","block"); +}return this.position();},dispose:function(){if(this.shim){this.shim.dispose();}return this;},destroy:function(){if(this.shim){this.shim.destroy();}return this; +}});window.addEvent("load",function(){IframeShim.ready=true;});var Mask=new Class({Implements:[Options,Events],Binds:["position"],options:{style:{},"class":"mask",maskMargins:false,useIframeShim:true,iframeShimOptions:{}},initialize:function(b,a){this.target=document.id(b)||document.id(document.body); +this.target.store("mask",this);this.setOptions(a);this.render();this.inject();},render:function(){this.element=new Element("div",{"class":this.options["class"],id:this.options.id||"mask-"+String.uniqueID(),styles:Object.merge({},this.options.style,{display:"none"}),events:{click:function(a){this.fireEvent("click",a); +if(this.options.hideOnClick){this.hide();}}.bind(this)}});this.hidden=true;},toElement:function(){return this.element;},inject:function(b,a){a=a||(this.options.inject?this.options.inject.where:"")||this.target==document.body?"inside":"after"; +b=b||(this.options.inject&&this.options.inject.target)||this.target;this.element.inject(b,a);if(this.options.useIframeShim){this.shim=new IframeShim(this.element,this.options.iframeShimOptions); +this.addEvents({show:this.shim.show.bind(this.shim),hide:this.shim.hide.bind(this.shim),destroy:this.shim.destroy.bind(this.shim)});}},position:function(){this.resize(this.options.width,this.options.height); +this.element.position({relativeTo:this.target,position:"topLeft",ignoreMargins:!this.options.maskMargins,ignoreScroll:this.target==document.body});return this; +},resize:function(a,e){var b={styles:["padding","border"]};if(this.options.maskMargins){b.styles.push("margin");}var d=this.target.getComputedSize(b);if(this.target==document.body){this.element.setStyles({width:0,height:0}); +var c=window.getScrollSize();if(d.totalHeight=0&&a.options[a.selectedIndex].value!=""); +}else{return((a.get("value")==null)||(a.get("value").length==0));}}});Form.Validator.addAllThese([["required",{errorMsg:function(){return Form.Validator.getMsg("required"); +},test:function(a){return !Form.Validator.getValidator("IsEmpty").test(a);}}],["minLength",{errorMsg:function(a,b){if(typeOf(b.minLength)!="null"){return Form.Validator.getMsg("minLength").substitute({minLength:b.minLength,length:a.get("value").length}); +}else{return"";}},test:function(a,b){if(typeOf(b.minLength)!="null"){return(a.get("value").length>=(b.minLength||0));}else{return true;}}}],["maxLength",{errorMsg:function(a,b){if(typeOf(b.maxLength)!="null"){return Form.Validator.getMsg("maxLength").substitute({maxLength:b.maxLength,length:a.get("value").length}); +}else{return"";}},test:function(a,b){return a.get("value").length<=(b.maxLength||10000);}}],["validate-integer",{errorMsg:Form.Validator.getMsg.pass("integer"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^(-?[1-9]\d*|0)$/).test(a.get("value")); +}}],["validate-numeric",{errorMsg:Form.Validator.getMsg.pass("numeric"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(a.get("value")); +}}],["validate-digits",{errorMsg:Form.Validator.getMsg.pass("digits"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^[\d() .:\-\+#]+$/.test(a.get("value"))); +}}],["validate-alpha",{errorMsg:Form.Validator.getMsg.pass("alpha"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^[a-zA-Z]+$/).test(a.get("value")); +}}],["validate-alphanum",{errorMsg:Form.Validator.getMsg.pass("alphanum"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||!(/\W/).test(a.get("value")); +}}],["validate-date",{errorMsg:function(a,b){if(Date.parse){var c=b.dateFormat||"%x";return Form.Validator.getMsg("dateSuchAs").substitute({date:new Date().format(c)}); +}else{return Form.Validator.getMsg("dateInFormatMDY");}},test:function(e,g){if(Form.Validator.getValidator("IsEmpty").test(e)){return true;}var a=Locale.getCurrent().sets.Date,b=new RegExp([a.days,a.days_abbr,a.months,a.months_abbr].flatten().join("|"),"i"),i=e.get("value"),f=i.match(/[a-z]+/gi); +if(f&&!f.every(b.exec,b)){return false;}var c=Date.parse(i),h=g.dateFormat||"%x",d=c.format(h);if(d!="invalid date"){e.set("value",d);}return c.isValid(); +}}],["validate-email",{errorMsg:Form.Validator.getMsg.pass("email"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+\/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(a.get("value")); +}}],["validate-url",{errorMsg:Form.Validator.getMsg.pass("url"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i).test(a.get("value")); +}}],["validate-currency-dollar",{errorMsg:Form.Validator.getMsg.pass("currencyDollar"),test:function(a){return Form.Validator.getValidator("IsEmpty").test(a)||(/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(a.get("value")); +}}],["validate-one-required",{errorMsg:Form.Validator.getMsg.pass("oneRequired"),test:function(a,b){var c=document.id(b["validate-one-required"])||a.getParent(b["validate-one-required"]); +return c.getElements("input").some(function(d){if(["checkbox","radio"].contains(d.get("type"))){return d.get("checked");}return d.get("value");});}}]]); +Element.Properties.validator={set:function(a){this.get("validator").setOptions(a);},get:function(){var a=this.retrieve("validator");if(!a){a=new Form.Validator(this); +this.store("validator",a);}return a;}};Element.implement({validate:function(a){if(a){this.set("validator",a);}return this.get("validator").validate();}}); +Form.Validator.Inline=new Class({Extends:Form.Validator,options:{showError:function(a){if(a.reveal){a.reveal();}else{a.setStyle("display","block");}},hideError:function(a){if(a.dissolve){a.dissolve(); +}else{a.setStyle("display","none");}},scrollToErrorsOnSubmit:true,scrollToErrorsOnBlur:false,scrollToErrorsOnChange:false,scrollFxOptions:{transition:"quad:out",offset:{y:-20}}},initialize:function(b,a){this.parent(b,a); +this.addEvent("onElementValidate",function(g,f,e,h){var d=this.getValidator(e);if(!g&&d.getError(f)){if(h){f.addClass("warning");}var c=this.makeAdvice(e,f,d.getError(f),h); +this.insertAdvice(c,f);this.showAdvice(e,f);}else{this.hideAdvice(e,f);}});},makeAdvice:function(d,f,c,g){var e=(g)?this.warningPrefix:this.errorPrefix; +e+=(this.options.useTitles)?f.title||c:c;var a=(g)?"warning-advice":"validation-advice";var b=this.getAdvice(d,f);if(b){b=b.set("html",e);}else{b=new Element("div",{html:e,styles:{display:"none"},id:"advice-"+d.split(":")[0]+"-"+this.getFieldId(f)}).addClass(a); +}f.store("$moo:advice-"+d,b);return b;},getFieldId:function(a){return a.id?a.id:a.id="input_"+a.name;},showAdvice:function(b,c){var a=this.getAdvice(b,c); +if(a&&!c.retrieve("$moo:"+this.getPropName(b))&&(a.getStyle("display")=="none"||a.getStyle("visiblity")=="hidden"||a.getStyle("opacity")==0)){c.store("$moo:"+this.getPropName(b),true); +this.options.showError(a);this.fireEvent("showAdvice",[c,a,b]);}},hideAdvice:function(b,c){var a=this.getAdvice(b,c);if(a&&c.retrieve("$moo:"+this.getPropName(b))){c.store("$moo:"+this.getPropName(b),false); +this.options.hideError(a);this.fireEvent("hideAdvice",[c,a,b]);}},getPropName:function(a){return"advice"+a;},resetField:function(a){a=document.id(a);if(!a){return this; +}this.parent(a);a.get("validators").each(function(b){this.hideAdvice(b,a);},this);return this;},getAllAdviceMessages:function(d,c){var b=[];if(d.hasClass("ignoreValidation")&&!c){return b; +}var a=d.get("validators").some(function(g){var e=g.test("^warn-")||d.hasClass("warnOnly");if(e){g=g.replace(/^warn-/,"");}var f=this.getValidator(g);if(!f){return; +}b.push({message:f.getError(d),warnOnly:e,passed:f.test(),validator:f});},this);return b;},getAdvice:function(a,b){return b.retrieve("$moo:advice-"+a); +},insertAdvice:function(a,c){var b=c.get("validatorProps");if(!b.msgPos||!document.id(b.msgPos)){if(c.type&&c.type.toLowerCase()=="radio"){c.getParent().adopt(a); +}else{a.inject(document.id(c),"after");}}else{document.id(b.msgPos).grab(a);}},validateField:function(g,f,b){var a=this.parent(g,f);if(((this.options.scrollToErrorsOnSubmit&&b==null)||b)&&!a){var c=document.id(this).getElement(".validation-failed"); +var d=document.id(this).getParent();while(d!=document.body&&d.getScrollSize().y==d.getSize().y){d=d.getParent();}var e=d.retrieve("$moo:fvScroller");if(!e&&window.Fx&&Fx.Scroll){e=new Fx.Scroll(d,this.options.scrollFxOptions); +d.store("$moo:fvScroller",e);}if(c){if(e){e.toElement(c);}else{d.scrollTo(d.getScroll().x,c.getPosition(d).y-20);}}}return a;},watchFields:function(a){a.each(function(b){if(this.options.evaluateFieldsOnBlur){b.addEvent("blur",this.validationMonitor.pass([b,false,this.options.scrollToErrorsOnBlur],this)); +}if(this.options.evaluateFieldsOnChange){b.addEvent("change",this.validationMonitor.pass([b,true,this.options.scrollToErrorsOnChange],this));}},this);}}); +Form.Validator.addAllThese([["validate-enforce-oncheck",{test:function(a,b){var c=a.getParent("form").retrieve("validator");if(!c){return true;}(b.toEnforce||document.id(b.enforceChildrenOf).getElements("input, select, textarea")).map(function(d){if(a.checked){c.enforceField(d); +}else{c.ignoreField(d);c.resetField(d);}});return true;}}],["validate-ignore-oncheck",{test:function(a,b){var c=a.getParent("form").retrieve("validator"); +if(!c){return true;}(b.toIgnore||document.id(b.ignoreChildrenOf).getElements("input, select, textarea")).each(function(d){if(a.checked){c.ignoreField(d); +c.resetField(d);}else{c.enforceField(d);}});return true;}}],["validate-nospace",{errorMsg:function(){return Form.Validator.getMsg("noSpace");},test:function(a,b){return !a.get("value").test(/\s/); +}}],["validate-toggle-oncheck",{test:function(b,c){var d=b.getParent("form").retrieve("validator");if(!d){return true;}var a=c.toToggle||document.id(c.toToggleChildrenOf).getElements("input, select, textarea"); +if(!b.checked){a.each(function(e){d.ignoreField(e);d.resetField(e);});}else{a.each(function(e){d.enforceField(e);});}return true;}}],["validate-reqchk-bynode",{errorMsg:function(){return Form.Validator.getMsg("reqChkByNode"); +},test:function(a,b){return(document.id(b.nodeId).getElements(b.selector||"input[type=checkbox], input[type=radio]")).some(function(c){return c.checked; +});}}],["validate-required-check",{errorMsg:function(a,b){return b.useTitle?a.get("title"):Form.Validator.getMsg("requiredChk");},test:function(a,b){return !!a.checked; +}}],["validate-reqchk-byname",{errorMsg:function(a,b){return Form.Validator.getMsg("reqChkByName").substitute({label:b.label||a.get("type")});},test:function(b,d){var c=d.groupName||b.get("name"); +var a=$$(document.getElementsByName(c)).some(function(g,f){return g.checked;});var e=b.getParent("form").retrieve("validator");if(a&&e){e.resetField(b); +}return a;}}],["validate-match",{errorMsg:function(a,b){return Form.Validator.getMsg("match").substitute({matchName:b.matchName||document.id(b.matchInput).get("name")}); +},test:function(b,c){var d=b.get("value");var a=document.id(c.matchInput)&&document.id(c.matchInput).get("value");return d&&a?d==a:true;}}],["validate-after-date",{errorMsg:function(a,b){return Form.Validator.getMsg("afterDate").substitute({label:b.afterLabel||(b.afterElement?Form.Validator.getMsg("startDate"):Form.Validator.getMsg("currentDate"))}); +},test:function(b,c){var d=document.id(c.afterElement)?Date.parse(document.id(c.afterElement).get("value")):new Date();var a=Date.parse(b.get("value")); +return a&&d?a>=d:true;}}],["validate-before-date",{errorMsg:function(a,b){return Form.Validator.getMsg("beforeDate").substitute({label:b.beforeLabel||(b.beforeElement?Form.Validator.getMsg("endDate"):Form.Validator.getMsg("currentDate"))}); +},test:function(b,c){var d=Date.parse(b.get("value"));var a=document.id(c.beforeElement)?Date.parse(document.id(c.beforeElement).get("value")):new Date(); +return a&&d?a>=d:true;}}],["validate-custom-required",{errorMsg:function(){return Form.Validator.getMsg("required");},test:function(a,b){return a.get("value")!=b.emptyValue; +}}],["validate-same-month",{errorMsg:function(a,b){var c=document.id(b.sameMonthAs)&&document.id(b.sameMonthAs).get("value");var d=a.get("value");if(d!=""){return Form.Validator.getMsg(c?"sameMonth":"startMonth"); +}},test:function(a,b){var d=Date.parse(a.get("value"));var c=Date.parse(document.id(b.sameMonthAs)&&document.id(b.sameMonthAs).get("value"));return d&&c?d.format("%B")==c.format("%B"):true; +}}],["validate-cc-num",{errorMsg:function(a){var b=a.get("value").replace(/[^0-9]/g,"");return Form.Validator.getMsg("creditcard").substitute({length:b.length}); +},test:function(c){if(Form.Validator.getValidator("IsEmpty").test(c)){return true;}var g=c.get("value");g=g.replace(/[^0-9]/g,"");var a=false;if(g.test(/^4[0-9]{12}([0-9]{3})?$/)){a="Visa"; +}else{if(g.test(/^5[1-5]([0-9]{14})$/)){a="Master Card";}else{if(g.test(/^3[47][0-9]{13}$/)){a="American Express";}else{if(g.test(/^6011[0-9]{12}$/)){a="Discover"; +}}}}if(a){var d=0;var e=0;for(var b=g.length-1;b>=0;--b){e=g.charAt(b).toInt();if(e==0){continue;}if((g.length-b)%2==0){e+=e;}if(e>9){e=e.toString().charAt(0).toInt()+e.toString().charAt(1).toInt(); +}d+=e;}if((d%10)==0){return true;}}var f="";while(g!=""){f+=" "+g.substr(0,4);g=g.substr(4);}c.getParent("form").retrieve("validator").ignoreField(c);c.set("value",f.clean()); +c.getParent("form").retrieve("validator").enforceField(c);return false;}}]]);var OverText=new Class({Implements:[Options,Events,Class.Occlude],Binds:["reposition","assert","focus","hide"],options:{element:"label",labelClass:"overTxtLabel",positionOptions:{position:"upperLeft",edge:"upperLeft",offset:{x:4,y:2}},poll:false,pollInterval:250,wrap:false},property:"OverText",initialize:function(b,a){b=this.element=document.id(b); +if(this.occlude()){return this.occluded;}this.setOptions(a);this.attach(b);OverText.instances.push(this);if(this.options.poll){this.poll();}},toElement:function(){return this.element; +},attach:function(){var b=this.element,a=this.options,c=a.textOverride||b.get("alt")||b.get("title");if(!c){return this;}var d=this.text=new Element(a.element,{"class":a.labelClass,styles:{lineHeight:"normal",position:"absolute",cursor:"text"},html:c,events:{click:this.hide.pass(a.element=="label",this)}}).inject(b,"after"); +if(a.element=="label"){if(!b.get("id")){b.set("id","input_"+String.uniqueID());}d.set("for",b.get("id"));}if(a.wrap){this.textHolder=new Element("div.overTxtWrapper",{styles:{lineHeight:"normal",position:"relative"}}).grab(d).inject(b,"before"); +}return this.enable();},destroy:function(){this.element.eliminate(this.property);this.disable();if(this.text){this.text.destroy();}if(this.textHolder){this.textHolder.destroy(); +}return this;},disable:function(){this.element.removeEvents({focus:this.focus,blur:this.assert,change:this.assert});window.removeEvent("resize",this.reposition); +this.hide(true,true);return this;},enable:function(){this.element.addEvents({focus:this.focus,blur:this.assert,change:this.assert});window.addEvent("resize",this.reposition); +this.assert(true);this.reposition();return this;},wrap:function(){if(this.options.element=="label"){if(!this.element.get("id")){this.element.set("id","input_"+String.uniqueID()); +}this.text.set("for",this.element.get("id"));}},startPolling:function(){this.pollingPaused=false;return this.poll();},poll:function(a){if(this.poller&&!a){return this; +}if(a){clearInterval(this.poller);}else{this.poller=(function(){if(!this.pollingPaused){this.assert(true);}}).periodical(this.options.pollInterval,this); +}return this;},stopPolling:function(){this.pollingPaused=true;return this.poll(true);},focus:function(){if(this.text&&(!this.text.isDisplayed()||this.element.get("disabled"))){return this; +}return this.hide();},hide:function(c,a){if(this.text&&(this.text.isDisplayed()&&(!this.element.get("disabled")||a))){this.text.hide();this.fireEvent("textHide",[this.text,this.element]); +this.pollingPaused=true;if(!c){try{this.element.fireEvent("focus");this.element.focus();}catch(b){}}}return this;},show:function(){if(this.text&&!this.text.isDisplayed()){this.text.show(); +this.reposition();this.fireEvent("textShow",[this.text,this.element]);this.pollingPaused=false;}return this;},test:function(){return !this.element.get("value"); +},assert:function(a){return this[this.test()?"show":"hide"](a);},reposition:function(){this.assert(true);if(!this.element.isVisible()){return this.stopPolling().hide(); +}if(this.text&&this.test()){this.text.position(Object.merge(this.options.positionOptions,{relativeTo:this.element}));}return this;}});OverText.instances=[]; +Object.append(OverText,{each:function(a){return OverText.instances.each(function(c,b){if(c.element&&c.text){a.call(OverText,c,b);}});},update:function(){return OverText.each(function(a){return a.reposition(); +});},hideAll:function(){return OverText.each(function(a){return a.hide(true,true);});},showAll:function(){return OverText.each(function(a){return a.show(); +});}});Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(b,a){this.elements=this.subject=$$(b);this.parent(a);},compute:function(g,h,j){var c={}; +for(var d in g){var a=g[d],e=h[d],f=c[d]={};for(var b in a){f[b]=this.parent(a[b],e[b],j);}}return c;},set:function(b){for(var c in b){if(!this.elements[c]){continue; +}var a=b[c];for(var d in a){this.render(this.elements[c],d,a[d],this.options.unit);}}return this;},start:function(c){if(!this.check(c)){return this;}var h={},j={}; +for(var d in c){if(!this.elements[d]){continue;}var f=c[d],a=h[d]={},g=j[d]={};for(var b in f){var e=this.prepare(this.elements[d],b,f[b]);a[b]=e.from; +g[b]=e.to;}}return this.parent(h,j);}});Fx.Accordion=new Class({Extends:Fx.Elements,options:{fixedHeight:false,fixedWidth:false,display:0,show:false,height:true,width:false,opacity:true,alwaysHide:false,trigger:"click",initialDisplayFx:true,resetHeight:true},initialize:function(){var g=function(h){return h!=null; +};var f=Array.link(arguments,{container:Type.isElement,options:Type.isObject,togglers:g,elements:g});this.parent(f.elements,f.options);var b=this.options,e=this.togglers=$$(f.togglers); +this.previous=-1;this.internalChain=new Chain();if(b.alwaysHide){this.options.link="chain";}if(b.show||this.options.show===0){b.display=false;this.previous=b.show; +}if(b.start){b.display=false;b.show=false;}var d=this.effects={};if(b.opacity){d.opacity="fullOpacity";}if(b.width){d.width=b.fixedWidth?"fullWidth":"offsetWidth"; +}if(b.height){d.height=b.fixedHeight?"fullHeight":"scrollHeight";}for(var c=0,a=e.length;c=0?a-1:0)).chain(d);}else{d();}return this;},detach:function(b){var a=function(c){c.removeEvent(this.options.trigger,c.retrieve("accordion:display")); +}.bind(this);if(!b){this.togglers.each(a);}else{a(b);}return this;},display:function(b,c){if(!this.check(b,c)){return this;}var h={},g=this.elements,a=this.options,f=this.effects; +if(c==null){c=true;}if(typeOf(b)=="element"){b=g.indexOf(b);}if(b==this.previous&&!a.alwaysHide){return this;}if(a.resetHeight){var e=g[this.previous]; +if(e&&!this.selfHidden){for(var d in f){e.setStyle(d,e[f[d]]);}}}if((this.timer&&a.link=="chain")||(b===this.previous&&!a.alwaysHide)){return this;}this.previous=b; +this.selfHidden=false;g.each(function(l,k){h[k]={};var j;if(k!=b){j=true;}else{if(a.alwaysHide&&((l.offsetHeight>0&&a.height)||l.offsetWidth>0&&a.width)){j=true; +this.selfHidden=true;}}this.fireEvent(j?"background":"active",[this.togglers[k],l]);for(var m in f){h[k][m]=j?0:l[f[m]];}if(!c&&!j&&a.resetHeight){h[k].height="auto"; +}},this);this.internalChain.clearChain();this.internalChain.chain(function(){if(a.resetHeight&&!this.selfHidden){var i=g[b];if(i){i.setStyle("height","auto"); +}}}.bind(this));return c?this.start(h):this.set(h).internalChain.callChain();}});Fx.Move=new Class({Extends:Fx.Morph,options:{relativeTo:document.body,position:"center",edge:false,offset:{x:0,y:0}},start:function(a){var b=this.element,c=b.getStyles("top","left"); +if(c.top=="auto"||c.left=="auto"){b.setPosition(b.getPosition(b.getOffsetParent()));}return this.parent(b.position(Object.merge({},this.options,a,{returnPos:true}))); +}});Element.Properties.move={set:function(a){this.get("move").cancel().setOptions(a);return this;},get:function(){var a=this.retrieve("move");if(!a){a=new Fx.Move(this,{link:"cancel"}); +this.store("move",a);}return a;}};Element.implement({move:function(a){this.get("move").start(a);return this;}});Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical",wrapper:false,hideOverflow:true,resetHeight:false},initialize:function(b,a){b=this.element=this.subject=document.id(b); +this.parent(a);a=this.options;var d=b.retrieve("wrapper"),c=b.getStyles("margin","position","overflow");if(a.hideOverflow){c=Object.append(c,{overflow:"hidden"}); +}if(a.wrapper){d=document.id(a.wrapper).setStyles(c);}if(!d){d=new Element("div",{styles:c}).wraps(b);}b.store("wrapper",d).setStyle("margin",0);if(b.getStyle("overflow")=="visible"){b.setStyle("overflow","hidden"); +}this.now=[];this.open=true;this.wrapper=d;this.addEvent("complete",function(){this.open=(d["offset"+this.layout.capitalize()]!=0);if(this.open&&this.options.resetHeight){d.setStyle("height",""); +}},true);},vertical:function(){this.margin="margin-top";this.layout="height";this.offset=this.element.offsetHeight;},horizontal:function(){this.margin="margin-left"; +this.layout="width";this.offset=this.element.offsetWidth;},set:function(a){this.element.setStyle(this.margin,a[0]);this.wrapper.setStyle(this.layout,a[1]); +return this;},compute:function(c,b,a){return[0,1].map(function(d){return Fx.compute(c[d],b[d],a);});},start:function(b,e){if(!this.check(b,e)){return this; +}this[e||this.options.mode]();var d=this.element.getStyle(this.margin).toInt(),c=this.wrapper.getStyle(this.layout).toInt(),a=[[d,c],[0,this.offset]],g=[[d,c],[-this.offset,0]],f; +switch(b){case"in":f=a;break;case"out":f=g;break;case"toggle":f=(c==0)?a:g;}return this.parent(f[0],f[1]);},slideIn:function(a){return this.start("in",a); +},slideOut:function(a){return this.start("out",a);},hide:function(a){this[a||this.options.mode]();this.open=false;return this.set([-this.offset,0]);},show:function(a){this[a||this.options.mode](); +this.open=true;return this.set([0,this.offset]);},toggle:function(a){return this.start("toggle",a);}});Element.Properties.slide={set:function(a){this.get("slide").cancel().setOptions(a); +return this;},get:function(){var a=this.retrieve("slide");if(!a){a=new Fx.Slide(this,{link:"cancel"});this.store("slide",a);}return a;}};Element.implement({slide:function(d,e){d=d||"toggle"; +var b=this.get("slide"),a;switch(d){case"hide":b.hide(e);break;case"show":b.show(e);break;case"toggle":var c=this.retrieve("slide:flag",b.open);b[c?"slideOut":"slideIn"](e); +this.store("slide:flag",!c);a=true;break;default:b.start(d,e);}if(!a){this.eliminate("slide:flag");}return this;}});(function(){Fx.Scroll=new Class({Extends:Fx,options:{offset:{x:0,y:0},wheelStops:true},initialize:function(c,b){this.element=this.subject=document.id(c); +this.parent(b);if(typeOf(this.element)!="element"){this.element=document.id(this.element.getDocument().body);}if(this.options.wheelStops){var d=this.element,e=this.cancel.pass(false,this); +this.addEvent("start",function(){d.addEvent("mousewheel",e);},true);this.addEvent("complete",function(){d.removeEvent("mousewheel",e);},true);}},set:function(){var b=Array.flatten(arguments); +if(Browser.firefox){b=[Math.round(b[0]),Math.round(b[1])];}this.element.scrollTo(b[0],b[1]);return this;},compute:function(d,c,b){return[0,1].map(function(e){return Fx.compute(d[e],c[e],b); +});},start:function(c,d){if(!this.check(c,d)){return this;}var b=this.element.getScroll();return this.parent([b.x,b.y],[c,d]);},calculateScroll:function(g,f){var d=this.element,b=d.getScrollSize(),h=d.getScroll(),j=d.getSize(),c=this.options.offset,i={x:g,y:f}; +for(var e in i){if(!i[e]&&i[e]!==0){i[e]=h[e];}if(typeOf(i[e])!="number"){i[e]=b[e]-j[e];}i[e]+=c[e];}return[i.x,i.y];},toTop:function(){return this.start.apply(this,this.calculateScroll(false,0)); +},toLeft:function(){return this.start.apply(this,this.calculateScroll(0,false));},toRight:function(){return this.start.apply(this,this.calculateScroll("right",false)); +},toBottom:function(){return this.start.apply(this,this.calculateScroll(false,"bottom"));},toElement:function(d,e){e=e?Array.from(e):["x","y"];var c=a(this.element)?{x:0,y:0}:this.element.getScroll(); +var b=Object.map(document.id(d).getPosition(this.element),function(g,f){return e.contains(f)?g+c[f]:false;});return this.start.apply(this,this.calculateScroll(b.x,b.y)); +},toElementEdge:function(d,g,e){g=g?Array.from(g):["x","y"];d=document.id(d);var i={},f=d.getPosition(this.element),j=d.getSize(),h=this.element.getScroll(),b=this.element.getSize(),c={x:f.x+j.x,y:f.y+j.y}; +["x","y"].each(function(k){if(g.contains(k)){if(c[k]>h[k]+b[k]){i[k]=c[k]-b[k];}if(f[k]this.elements.length){e.splice(this.elements.length-1,e.length-this.elements.length); +}}var b=0;i=a=0;e.each(function(k){var j={};if(d){j.top=i-f[k].top-b;i+=f[k].height;}else{j.left=a-f[k].left;a+=f[k].width;}b=b+f[k].margin;c[k]=j;},this); +var g={};Array.clone(e).sort().each(function(j){g[j]=c[j];});this.start(g);this.currentOrder=e;return this;},rearrangeDOM:function(a){a=a||this.currentOrder; +var b=this.elements[0].getParent();var c=[];this.elements.setStyle("opacity",0);a.each(function(d){c.push(this.elements[d].inject(b).setStyles({top:0,left:0})); +},this);this.elements.setStyle("opacity",1);this.elements=$$(c);this.setDefaultOrder();return this;},getDefaultOrder:function(){return this.elements.map(function(b,a){return a; +});},getCurrentOrder:function(){return this.currentOrder;},forward:function(){return this.sort(this.getDefaultOrder());},backward:function(){return this.sort(this.getDefaultOrder().reverse()); +},reverse:function(){return this.sort(this.currentOrder.reverse());},sortByElements:function(a){return this.sort(a.map(function(b){return this.elements.indexOf(b); +},this));},swap:function(c,b){if(typeOf(c)=="element"){c=this.elements.indexOf(c);}if(typeOf(b)=="element"){b=this.elements.indexOf(b);}var a=Array.clone(this.currentOrder); +a[this.currentOrder.indexOf(c)]=b;a[this.currentOrder.indexOf(b)]=c;return this.sort(a);}});var Drag=new Class({Implements:[Events,Options],options:{snap:6,unit:"px",grid:false,style:true,limit:false,handle:false,invert:false,preventDefault:false,stopPropagation:false,modifiers:{x:"left",y:"top"}},initialize:function(){var b=Array.link(arguments,{options:Type.isObject,element:function(c){return c!=null; +}});this.element=document.id(b.element);this.document=this.element.getDocument();this.setOptions(b.options||{});var a=typeOf(this.options.handle);this.handles=((a=="array"||a=="collection")?$$(this.options.handle):document.id(this.options.handle))||this.element; +this.mouse={now:{},pos:{}};this.value={start:{},now:{}};this.selection=(Browser.ie)?"selectstart":"mousedown";if(Browser.ie&&!Drag.ondragstartFixed){document.ondragstart=Function.from(false); +Drag.ondragstartFixed=true;}this.bound={start:this.start.bind(this),check:this.check.bind(this),drag:this.drag.bind(this),stop:this.stop.bind(this),cancel:this.cancel.bind(this),eventStop:Function.from(false)}; +this.attach();},attach:function(){this.handles.addEvent("mousedown",this.bound.start);return this;},detach:function(){this.handles.removeEvent("mousedown",this.bound.start); +return this;},start:function(a){var j=this.options;if(a.rightClick){return;}if(j.preventDefault){a.preventDefault();}if(j.stopPropagation){a.stopPropagation(); +}this.mouse.start=a.page;this.fireEvent("beforeStart",this.element);var c=j.limit;this.limit={x:[],y:[]};var e,g;for(e in j.modifiers){if(!j.modifiers[e]){continue; +}var b=this.element.getStyle(j.modifiers[e]);if(b&&!b.match(/px$/)){if(!g){g=this.element.getCoordinates(this.element.getOffsetParent());}b=g[j.modifiers[e]]; +}if(j.style){this.value.now[e]=(b||0).toInt();}else{this.value.now[e]=this.element[j.modifiers[e]];}if(j.invert){this.value.now[e]*=-1;}this.mouse.pos[e]=a.page[e]-this.value.now[e]; +if(c&&c[e]){var d=2;while(d--){var f=c[e][d];if(f||f===0){this.limit[e][d]=(typeof f=="function")?f():f;}}}}if(typeOf(this.options.grid)=="number"){this.options.grid={x:this.options.grid,y:this.options.grid}; +}var h={mousemove:this.bound.check,mouseup:this.bound.cancel};h[this.selection]=this.bound.eventStop;this.document.addEvents(h);},check:function(a){if(this.options.preventDefault){a.preventDefault(); +}var b=Math.round(Math.sqrt(Math.pow(a.page.x-this.mouse.start.x,2)+Math.pow(a.page.y-this.mouse.start.y,2)));if(b>this.options.snap){this.cancel();this.document.addEvents({mousemove:this.bound.drag,mouseup:this.bound.stop}); +this.fireEvent("start",[this.element,a]).fireEvent("snap",this.element);}},drag:function(b){var a=this.options;if(a.preventDefault){b.preventDefault(); +}this.mouse.now=b.page;for(var c in a.modifiers){if(!a.modifiers[c]){continue;}this.value.now[c]=this.mouse.now[c]-this.mouse.pos[c];if(a.invert){this.value.now[c]*=-1; +}if(a.limit&&this.limit[c]){if((this.limit[c][1]||this.limit[c][1]===0)&&(this.value.now[c]>this.limit[c][1])){this.value.now[c]=this.limit[c][1];}else{if((this.limit[c][0]||this.limit[c][0]===0)&&(this.value.now[c]d.left&&b.xd.top);},this).getLast();if(this.overed!=a){if(this.overed){this.fireEvent("leave",[this.element,this.overed]); +}if(a){this.fireEvent("enter",[this.element,a]);}this.overed=a;}},drag:function(a){this.parent(a);if(this.options.checkDroppables&&this.droppables.length){this.checkDroppables(); +}},stop:function(a){this.checkDroppables();this.fireEvent("drop",[this.element,this.overed,a]);this.overed=null;return this.parent(a);}});Element.implement({makeDraggable:function(a){var b=new Drag.Move(this,a); +this.store("dragger",b);return b;}});var Slider=new Class({Implements:[Events,Options],Binds:["clickedElement","draggedKnob","scrolledElement"],options:{onTick:function(a){this.setKnobPosition(a); +},initialStep:0,snap:false,offset:0,range:false,wheel:false,steps:100,mode:"horizontal"},initialize:function(f,a,e){this.setOptions(e);e=this.options;this.element=document.id(f); +a=this.knob=document.id(a);this.previousChange=this.previousEnd=this.step=-1;var b={},d={x:false,y:false};switch(e.mode){case"vertical":this.axis="y";this.property="top"; +this.offset="offsetHeight";break;case"horizontal":this.axis="x";this.property="left";this.offset="offsetWidth";}this.setSliderDimensions();this.setRange(e.range); +if(a.getStyle("position")=="static"){a.setStyle("position","relative");}a.setStyle(this.property,-e.offset);d[this.axis]=this.property;b[this.axis]=[-e.offset,this.full-e.offset]; +var c={snap:0,limit:b,modifiers:d,onDrag:this.draggedKnob,onStart:this.draggedKnob,onBeforeStart:(function(){this.isDragging=true;}).bind(this),onCancel:function(){this.isDragging=false; +}.bind(this),onComplete:function(){this.isDragging=false;this.draggedKnob();this.end();}.bind(this)};if(e.snap){this.setSnap(c);}this.drag=new Drag(a,c); +this.attach();if(e.initialStep!=null){this.set(e.initialStep);}},attach:function(){this.element.addEvent("mousedown",this.clickedElement);if(this.options.wheel){this.element.addEvent("mousewheel",this.scrolledElement); +}this.drag.attach();return this;},detach:function(){this.element.removeEvent("mousedown",this.clickedElement).removeEvent("mousewheel",this.scrolledElement); +this.drag.detach();return this;},autosize:function(){this.setSliderDimensions().setKnobPosition(this.toPosition(this.step));this.drag.options.limit[this.axis]=[-this.options.offset,this.full-this.options.offset]; +if(this.options.snap){this.setSnap();}return this;},setSnap:function(a){if(!a){a=this.drag.options;}a.grid=Math.ceil(this.stepWidth);a.limit[this.axis][1]=this.full; +return this;},setKnobPosition:function(a){if(this.options.snap){a=this.toPosition(this.step);}this.knob.setStyle(this.property,a);return this;},setSliderDimensions:function(){this.full=this.element.measure(function(){this.half=this.knob[this.offset]/2; +return this.element[this.offset]-this.knob[this.offset]+(this.options.offset*2);}.bind(this));return this;},set:function(a){if(!((this.range>0)^(a0)^(a>this.max))){a=this.max;}this.step=Math.round(a);return this.checkStep().fireEvent("tick",this.toPosition(this.step)).end();},setRange:function(a,b){this.min=Array.pick([a[0],0]); +this.max=Array.pick([a[1],this.options.steps]);this.range=this.max-this.min;this.steps=this.options.steps||this.full;this.stepSize=Math.abs(this.range)/this.steps; +this.stepWidth=this.stepSize*this.full/Math.abs(this.range);if(a){this.set(Array.pick([b,this.step]).floor(this.min).max(this.max));}return this;},clickedElement:function(c){if(this.isDragging||c.target==this.knob){return; +}var b=this.range<0?-1:1,a=c.page[this.axis]-this.element.getPosition()[this.axis]-this.half;a=a.limit(-this.options.offset,this.full-this.options.offset); +this.step=Math.round(this.min+b*this.toStep(a));this.checkStep().fireEvent("tick",a).end();},scrolledElement:function(a){var b=(this.options.mode=="horizontal")?(a.wheel<0):(a.wheel>0); +this.set(this.step+(b?-1:1)*this.stepSize);a.stop();},draggedKnob:function(){var b=this.range<0?-1:1,a=this.drag.value.now[this.axis];a=a.limit(-this.options.offset,this.full-this.options.offset); +this.step=Math.round(this.min+b*this.toStep(a));this.checkStep();},checkStep:function(){var a=this.step;if(this.previousChange!=a){this.previousChange=a; +this.fireEvent("change",a);}return this;},end:function(){var a=this.step;if(this.previousEnd!==a){this.previousEnd=a;this.fireEvent("complete",a+"");}return this; +},toStep:function(a){var b=(a+this.options.offset)*this.stepSize/this.full*this.steps;return this.options.steps?Math.round(b-=b%this.stepSize):b;},toPosition:function(a){return(this.full*Math.abs(this.min-a))/(this.steps*this.stepSize)-this.options.offset; +}});var Sortables=new Class({Implements:[Events,Options],options:{opacity:1,clone:false,revert:false,handle:false,dragOptions:{}},initialize:function(a,b){this.setOptions(b); +this.elements=[];this.lists=[];this.idle=true;this.addLists($$(document.id(a)||a));if(!this.options.clone){this.options.revert=false;}if(this.options.revert){this.effect=new Fx.Morph(null,Object.merge({duration:250,link:"cancel"},this.options.revert)); +}},attach:function(){this.addLists(this.lists);return this;},detach:function(){this.lists=this.removeLists(this.lists);return this;},addItems:function(){Array.flatten(arguments).each(function(a){this.elements.push(a); +var b=a.retrieve("sortables:start",function(c){this.start.call(this,c,a);}.bind(this));(this.options.handle?a.getElement(this.options.handle)||a:a).addEvent("mousedown",b); +},this);return this;},addLists:function(){Array.flatten(arguments).each(function(a){this.lists.include(a);this.addItems(a.getChildren());},this);return this; +},removeItems:function(){return $$(Array.flatten(arguments).map(function(a){this.elements.erase(a);var b=a.retrieve("sortables:start");(this.options.handle?a.getElement(this.options.handle)||a:a).removeEvent("mousedown",b); +return a;},this));},removeLists:function(){return $$(Array.flatten(arguments).map(function(a){this.lists.erase(a);this.removeItems(a.getChildren());return a; +},this));},getClone:function(b,a){if(!this.options.clone){return new Element(a.tagName).inject(document.body);}if(typeOf(this.options.clone)=="function"){return this.options.clone.call(this,b,a,this.list); +}var c=a.clone(true).setStyles({margin:0,position:"absolute",visibility:"hidden",width:a.getStyle("width")}).addEvent("mousedown",function(d){a.fireEvent("mousedown",d); +});if(c.get("html").test("radio")){c.getElements("input[type=radio]").each(function(d,e){d.set("name","clone_"+e);if(d.get("checked")){a.getElements("input[type=radio]")[e].set("checked",true); +}});}return c.inject(this.list).setPosition(a.getPosition(a.getOffsetParent()));},getDroppables:function(){var a=this.list.getChildren().erase(this.clone).erase(this.element); +if(!this.options.constrain){a.append(this.lists).erase(this.list);}return a;},insert:function(c,b){var a="inside";if(this.lists.contains(b)){this.list=b; +this.drag.droppables=this.getDroppables();}else{a=this.element.getAllPrevious().contains(b)?"before":"after";}this.element.inject(b,a);this.fireEvent("sort",[this.element,this.clone]); +},start:function(b,a){if(!this.idle||b.rightClick||["button","input","a"].contains(b.target.get("tag"))){return;}this.idle=false;this.element=a;this.opacity=a.get("opacity"); +this.list=a.getParent();this.clone=this.getClone(b,a);this.drag=new Drag.Move(this.clone,Object.merge({droppables:this.getDroppables()},this.options.dragOptions)).addEvents({onSnap:function(){b.stop(); +this.clone.setStyle("visibility","visible");this.element.set("opacity",this.options.opacity||0);this.fireEvent("start",[this.element,this.clone]);}.bind(this),onEnter:this.insert.bind(this),onCancel:this.end.bind(this),onComplete:this.end.bind(this)}); +this.clone.inject(this.element,"before");this.drag.start(b);},end:function(){this.drag.detach();this.element.set("opacity",this.opacity);if(this.effect){var b=this.element.getStyles("width","height"),d=this.clone,c=d.computePosition(this.element.getPosition(this.clone.getOffsetParent())); +var a=function(){this.removeEvent("cancel",a);d.destroy();};this.effect.element=d;this.effect.start({top:c.top,left:c.left,width:b.width,height:b.height,opacity:0.25}).addEvent("cancel",a).chain(a); +}else{this.clone.destroy();}this.reset();},reset:function(){this.idle=true;this.fireEvent("complete",this.element);},serialize:function(){var c=Array.link(arguments,{modifier:Type.isFunction,index:function(d){return d!=null; +}});var b=this.lists.map(function(d){return d.getChildren().map(c.modifier||function(e){return e.get("id");},this);},this);var a=c.index;if(this.lists.length==1){a=0; +}return(a||a===0)&&a>=0&&a2083){this.fireEvent("error",f);}Request.JSONP.request_map["request_"+b]=function(){this.success(arguments,b);}.bind(this);var a=this.getScript(f).inject(c.injectScript); +this.fireEvent("request",[f,a]);if(c.timeout){this.timeout.delay(c.timeout,this);}return this;},getScript:function(a){if(!this.script){this.script=new Element("script",{type:"text/javascript",async:true,src:a}); +}return this.script;},success:function(b,a){if(!this.running){return;}this.clear().fireEvent("complete",b).fireEvent("success",b).callChain();},cancel:function(){if(this.running){this.clear().fireEvent("cancel"); +}return this;},isRunning:function(){return !!this.running;},clear:function(){this.running=false;if(this.script){this.script.destroy();this.script=null; +}return this;},timeout:function(){if(this.running){this.running=false;this.fireEvent("timeout",[this.script.get("src"),this.script]).fireEvent("failure").cancel(); +}return this;}});Request.JSONP.counter=0;Request.JSONP.request_map={};Request.Queue=new Class({Implements:[Options,Events],Binds:["attach","request","complete","cancel","success","failure","exception"],options:{stopOnFailure:true,autoAdvance:true,concurrent:1,requests:{}},initialize:function(a){var b; +if(a){b=a.requests;delete a.requests;}this.setOptions(a);this.requests={};this.queue=[];this.reqBinders={};if(b){this.addRequests(b);}},addRequest:function(a,b){this.requests[a]=b; +this.attach(a,b);return this;},addRequests:function(a){Object.each(a,function(c,b){this.addRequest(b,c);},this);return this;},getName:function(a){return Object.keyOf(this.requests,a); +},attach:function(a,b){if(b._groupSend){return this;}["request","complete","cancel","success","failure","exception"].each(function(c){if(!this.reqBinders[a]){this.reqBinders[a]={}; +}this.reqBinders[a][c]=function(){this["on"+c.capitalize()].apply(this,[a,b].append(arguments));}.bind(this);b.addEvent(c,this.reqBinders[a][c]);},this); +b._groupSend=b.send;b.send=function(c){this.send(a,c);return b;}.bind(this);return this;},removeRequest:function(b){var a=typeOf(b)=="object"?this.getName(b):b; +if(!a&&typeOf(a)!="string"){return this;}b=this.requests[a];if(!b){return this;}["request","complete","cancel","success","failure","exception"].each(function(c){b.removeEvent(c,this.reqBinders[a][c]); +},this);b.send=b._groupSend;delete b._groupSend;return this;},getRunning:function(){return Object.filter(this.requests,function(a){return a.running;}); +},isRunning:function(){return !!(Object.keys(this.getRunning()).length);},send:function(b,a){var c=function(){this.requests[b]._groupSend(a);this.queue.erase(c); +}.bind(this);c.name=b;if(Object.keys(this.getRunning()).length>=this.options.concurrent||(this.error&&this.options.stopOnFailure)){this.queue.push(c);}else{c(); +}return this;},hasNext:function(a){return(!a)?!!this.queue.length:!!this.queue.filter(function(b){return b.name==a;}).length;},resume:function(){this.error=false; +(this.options.concurrent-Object.keys(this.getRunning()).length).times(this.runNext,this);return this;},runNext:function(a){if(!this.queue.length){return this; +}if(!a){this.queue[0]();}else{var b;this.queue.each(function(c){if(!b&&c.name==a){b=true;c();}});}return this;},runAll:function(){this.queue.each(function(a){a(); +});return this;},clear:function(a){if(!a){this.queue.empty();}else{this.queue=this.queue.map(function(b){if(b.name!=a){return b;}else{return false;}}).filter(function(b){return b; +});}return this;},cancel:function(a){this.requests[a].cancel();return this;},onRequest:function(){this.fireEvent("request",arguments);},onComplete:function(){this.fireEvent("complete",arguments); +if(!this.queue.length){this.fireEvent("end");}},onCancel:function(){if(this.options.autoAdvance&&!this.error){this.runNext();}this.fireEvent("cancel",arguments); +},onSuccess:function(){if(this.options.autoAdvance&&!this.error){this.runNext();}this.fireEvent("success",arguments);},onFailure:function(){this.error=true; +if(!this.options.stopOnFailure&&this.options.autoAdvance){this.runNext();}this.fireEvent("failure",arguments);},onException:function(){this.error=true; +if(!this.options.stopOnFailure&&this.options.autoAdvance){this.runNext();}this.fireEvent("exception",arguments);}});Request.implement({options:{initialDelay:5000,delay:5000,limit:60000},startTimer:function(b){var a=function(){if(!this.running){this.send({data:b}); +}};this.lastDelay=this.options.initialDelay;this.timer=a.delay(this.lastDelay,this);this.completeCheck=function(c){clearTimeout(this.timer);this.lastDelay=(c)?this.options.delay:(this.lastDelay+this.options.delay).min(this.options.limit); +this.timer=a.delay(this.lastDelay,this);};return this.addEvent("complete",this.completeCheck);},stopTimer:function(){clearTimeout(this.timer);return this.removeEvent("complete",this.completeCheck); +}});var Asset={javascript:function(f,c){if(!c){c={};}var a=new Element("script",{src:f,type:"text/javascript"}),g=c.document||document,b=0,d=c.onload||c.onLoad; +var e=d?function(){if(++b==1){d.call(this);}}:function(){};delete c.onload;delete c.onLoad;delete c.document;return a.addEvents({load:e,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){e.call(this); +}}}).set(c).inject(g.head);},css:function(d,a){if(!a){a={};}var b=new Element("link",{rel:"stylesheet",media:"screen",type:"text/css",href:d});var c=a.onload||a.onLoad,e=a.document||document; +delete a.onload;delete a.onLoad;delete a.document;if(c){b.addEvent("load",c);}return b.set(a).inject(e.head);},image:function(c,b){if(!b){b={};}var d=new Image(),a=document.id(d)||new Element("img"); +["load","abort","error"].each(function(e){var g="on"+e,f="on"+e.capitalize(),h=b[g]||b[f]||function(){};delete b[f];delete b[g];d[g]=function(){if(!d){return; +}if(!a.parentNode){a.width=d.width;a.height=d.height;}d=d.onload=d.onabort=d.onerror=null;h.delay(1,a,a);a.fireEvent(e,a,1);};});d.src=a.src=c;if(d&&d.complete){d.onload.delay(1); +}return a.set(b);},images:function(c,b){c=Array.from(c);var d=function(){},a=0;b=Object.merge({onComplete:d,onProgress:d,onError:d,properties:{}},b);return new Elements(c.map(function(f,e){return Asset.image(f,Object.append(b.properties,{onload:function(){a++; +b.onProgress.call(this,a,e,f);if(a==c.length){b.onComplete();}},onerror:function(){a++;b.onError.call(this,a,e,f);if(a==c.length){b.onComplete();}}})); +}));}};(function(){var a=this.Color=new Type("Color",function(c,d){if(arguments.length>=3){d="rgb";c=Array.slice(arguments,0,3);}else{if(typeof c=="string"){if(c.match(/rgb/)){c=c.rgbToHex().hexToRgb(true); +}else{if(c.match(/hsb/)){c=c.hsbToRgb();}else{c=c.hexToRgb(true);}}}}d=d||"rgb";switch(d){case"hsb":var b=c;c=c.hsbToRgb();c.hsb=b;break;case"hex":c=c.hexToRgb(true); +break;}c.rgb=c.slice(0,3);c.hsb=c.hsb||c.rgbToHsb();c.hex=c.rgbToHex();return Object.append(c,this);});a.implement({mix:function(){var b=Array.slice(arguments); +var d=(typeOf(b.getLast())=="number")?b.pop():50;var c=this.slice();b.each(function(e){e=new a(e);for(var f=0;f<3;f++){c[f]=Math.round((c[f]/100*(100-d))+(e[f]/100*d)); +}});return new a(c,"rgb");},invert:function(){return new a(this.map(function(b){return 255-b;}));},setHue:function(b){return new a([b,this.hsb[1],this.hsb[2]],"hsb"); +},setSaturation:function(b){return new a([this.hsb[0],b,this.hsb[2]],"hsb");},setBrightness:function(b){return new a([this.hsb[0],this.hsb[1],b],"hsb"); +}});this.$RGB=function(e,d,c){return new a([e,d,c],"rgb");};this.$HSB=function(e,d,c){return new a([e,d,c],"hsb");};this.$HEX=function(b){return new a(b,"hex"); +};Array.implement({rgbToHsb:function(){var c=this[0],d=this[1],k=this[2],h=0;var j=Math.max(c,d,k),f=Math.min(c,d,k);var l=j-f;var i=j/255,g=(j!=0)?l/j:0; +if(g!=0){var e=(j-c)/l;var b=(j-d)/l;var m=(j-k)/l;if(c==j){h=m-b;}else{if(d==j){h=2+e-m;}else{h=4+b-e;}}h/=6;if(h<0){h++;}}return[Math.round(h*360),Math.round(g*100),Math.round(i*100)]; +},hsbToRgb:function(){var d=Math.round(this[2]/100*255);if(this[1]==0){return[d,d,d];}else{var b=this[0]%360;var g=b%60;var h=Math.round((this[2]*(100-this[1]))/10000*255); +var e=Math.round((this[2]*(6000-this[1]*g))/600000*255);var c=Math.round((this[2]*(6000-this[1]*(60-g)))/600000*255);switch(Math.floor(b/60)){case 0:return[d,c,h]; +case 1:return[e,d,h];case 2:return[h,d,c];case 3:return[h,e,d];case 4:return[c,h,d];case 5:return[d,h,e];}}return false;}});String.implement({rgbToHsb:function(){var b=this.match(/\d{1,3}/g); +return(b)?b.rgbToHsb():null;},hsbToRgb:function(){var b=this.match(/\d{1,3}/g);return(b)?b.hsbToRgb():null;}});})();(function(){this.Group=new Class({initialize:function(){this.instances=Array.flatten(arguments); +this.events={};this.checker={};},addEvent:function(b,a){this.checker[b]=this.checker[b]||{};this.events[b]=this.events[b]||[];if(this.events[b].contains(a)){return false; +}else{this.events[b].push(a);}this.instances.each(function(c,d){c.addEvent(b,this.check.pass([b,c,d],this));},this);return this;},check:function(c,a,b){this.checker[c][b]=true; +var d=this.instances.every(function(f,e){return this.checker[c][e]||false;},this);if(!d){return;}this.checker[c]={};this.events[c].each(function(e){e.call(this,this.instances,a); +},this);}});})();Hash.Cookie=new Class({Extends:Cookie,options:{autoSave:true},initialize:function(b,a){this.parent(b,a);this.load();},save:function(){var a=JSON.encode(this.hash); +if(!a||a.length>4096){return false;}if(a=="{}"){this.dispose();}else{this.write(a);}return true;},load:function(){this.hash=new Hash(JSON.decode(this.read(),true)); +return this;}});Hash.each(Hash.prototype,function(b,a){if(typeof b=="function"){Hash.Cookie.implement(a,function(){var c=b.apply(this.hash,arguments);if(this.options.autoSave){this.save(); +}return c;});}});(function(){var a=this.Table=function(){this.length=0;var c=[],b=[];this.set=function(e,g){var d=c.indexOf(e);if(d==-1){var f=c.length; +c[f]=e;b[f]=g;this.length++;}else{b[d]=g;}return this;};this.get=function(e){var d=c.indexOf(e);return(d==-1)?null:b[d];};this.erase=function(e){var d=c.indexOf(e); +if(d!=-1){this.length--;c.splice(d,1);return b.splice(d,1)[0];}return null;};this.each=this.forEach=function(f,g){for(var e=0,d=this.length;e1?$$(a):a.length?document.id(a[0]):false;},setHeaders:function(a){this.set("headers",a); +return this;},setFooters:function(a){this.set("footers",a);return this;},push:function(f,c,e,a,b){if(typeOf(f)=="element"&&f.get("tag")=="tr"){f.inject(e||this.body,b); +return{tr:f,tds:f.getChildren("td")};}var d=f.map(function(i){var j=new Element(a||"td",i?i.properties:{}),h=(i?i.content:"")||i,g=typeOf(h);if(["element","array","collection","elements"].contains(g)){j.adopt(h); +}else{j.set("html",h);}return j;});return{tr:new Element("tr",c).inject(e||this.body,b).adopt(d),tds:d};}});["adopt","inject","wraps","grab","replaces","dispose"].each(function(a){HtmlTable.implement(a,function(){this.element[a].apply(this.element,arguments); +return this;});});HtmlTable=Class.refactor(HtmlTable,{options:{classZebra:"table-tr-odd",zebra:true},initialize:function(){this.previous.apply(this,arguments); +if(this.occluded){return this.occluded;}if(this.options.zebra){this.updateZebras();}},updateZebras:function(){Array.each(this.body.rows,this.zebra,this); +},setRowStyle:function(b,a){if(this.previous){this.previous(b,a);}this.zebra(b,a);},zebra:function(b,a){return b[((a%2)?"remove":"add")+"Class"](this.options.classZebra); +},push:function(){var a=this.previous.apply(this,arguments);if(this.options.zebra){this.updateZebras();}return a;}});HtmlTable=Class.refactor(HtmlTable,{options:{sortIndex:0,sortReverse:false,parsers:[],defaultParser:"string",classSortable:"table-sortable",classHeadSort:"table-th-sort",classHeadSortRev:"table-th-sort-rev",classNoSort:"table-th-nosort",classGroupHead:"table-tr-group-head",classGroup:"table-tr-group",classCellSort:"table-td-sort",classSortSpan:"table-th-sort-span",sortable:false,thSelector:"th"},initialize:function(){this.previous.apply(this,arguments); +if(this.occluded){return this.occluded;}this.sorted={index:null,dir:1};this.bound={headClick:this.headClick.bind(this)};this.sortSpans=new Elements();if(this.options.sortable){this.enableSort(); +if(this.options.sortIndex!=null){this.sort(this.options.sortIndex,this.options.sortReverse);}}},attachSorts:function(a){this.detachSorts();if(a!==false){this.element.addEvent("click:relay("+this.options.thSelector+")",this.bound.headClick); +}},detachSorts:function(){this.element.removeEvents("click:relay("+this.options.thSelector+")");},setHeaders:function(){this.previous.apply(this,arguments); +if(this.sortEnabled){this.setParsers();}},setParsers:function(){this.parsers=this.detectParsers();},detectParsers:function(){return this.head&&this.head.getElements(this.options.thSelector).flatten().map(this.detectParser,this); +},detectParser:function(a,b){if(a.hasClass(this.options.classNoSort)||a.retrieve("htmltable-parser")){return a.retrieve("htmltable-parser");}var c=new Element("div"); +c.adopt(a.childNodes).inject(a);var f=new Element("span",{"class":this.options.classSortSpan}).inject(c,"top");this.sortSpans.push(f);var g=this.options.parsers[b],e=this.body.rows,d; +switch(typeOf(g)){case"function":g={convert:g};d=true;break;case"string":g=g;d=true;break;}if(!d){HtmlTable.ParserPriority.some(function(k){var o=HtmlTable.Parsers[k],m=o.match; +if(!m){return false;}for(var n=0,l=e.length;nc){b[f].position--;}}}},setRowStyle:function(b,a){this.previous(b,a);b.cells[this.sorted.index].addClass(this.options.classCellSort); +},setGroupSort:function(b,c,a){if(b==a.value){c.removeClass(this.options.classGroupHead).addClass(this.options.classGroup);}else{c.removeClass(this.options.classGroup).addClass(this.options.classGroupHead); +}return a.value;},getParser:function(){var a=this.parsers[this.sorted.index];return typeOf(a)=="string"?HtmlTable.Parsers[a]:a;},sort:function(c,b,e){if(!this.head){return; +}if(!e){this.clearSort();this.setSortedState(c,b);this.setHeadSort(true);}var f=this.getParser();if(!f){return;}var a;if(!Browser.ie){a=this.body.getParent(); +this.body.dispose();}var d=this.parseData(f).sort(function(h,g){if(h.value===g.value){return 0;}return h.value>g.value?1:-1;});if(this.sorted.reverse==(f==HtmlTable.Parsers["input-checked"])){d.reverse(true); +}this.setRowSort(d,e);if(a){a.grab(this.body);}this.fireEvent("stateChanged");return this.fireEvent("sort",[this.body,this.sorted.index]);},parseData:function(a){return Array.map(this.body.rows,function(d,b){var c=a.convert.call(document.id(d.cells[this.sorted.index])); +return{position:b,value:c};},this);},clearSort:function(){this.setHeadSort(false);this.body.getElements("td").removeClass(this.options.classCellSort);},reSort:function(){if(this.sortEnabled){this.sort.call(this,this.sorted.index,this.sorted.reverse); +}return this;},enableSort:function(){this.element.addClass(this.options.classSortable);this.attachSorts(true);this.setParsers();this.sortEnabled=true;return this; +},disableSort:function(){this.element.removeClass(this.options.classSortable);this.attachSorts(false);this.sortSpans.each(function(a){a.destroy();});this.sortSpans.empty(); +this.sortEnabled=false;return this;}});HtmlTable.ParserPriority=["date","input-checked","input-value","float","number"];HtmlTable.Parsers={date:{match:/^\d{2}[-\/ ]\d{2}[-\/ ]\d{2,4}$/,convert:function(){var a=Date.parse(this.get("text").stripTags()); +return(typeOf(a)=="date")?a.format("db"):"";},type:"date"},"input-checked":{match:/ type="(radio|checkbox)" /,convert:function(){return this.getElement("input").checked; +}},"input-value":{match:/=b.length){a=null;}return a;},attachSelects:function(d){d=d!=null?d:true; +var g=d?"addEvents":"removeEvents";this.element[g]({mouseleave:this.bound.mouseleave,click:this.bound.activateKeyboard});this.body[g]({"click:relay(tr)":this.bound.clickRow,"contextmenu:relay(tr)":this.bound.clickRow}); +if(this.options.useKeyboard||this.keyboard){if(!this.keyboard){this.keyboard=new Keyboard();}if(!this.selectKeysDefined){this.selectKeysDefined=true;var f,e; +var c=function(i){var h=function(j){clearTimeout(f);j.preventDefault();var k=this.body.rows[this.getRowByOffset(i)];if(j.shift&&k&&this.isSelected(k)){this.deselectRow(this.focused); +this.focused=k;}else{if(k&&(!this.options.allowMultiSelect||!j.shift)){this.selectNone();}this.shiftFocus(i,j);}if(e){f=h.delay(100,this,j);}else{f=(function(){e=true; +h(j);}).delay(400);}}.bind(this);return h;}.bind(this);var b=function(){clearTimeout(f);e=false;};this.keyboard.addEvents({"keydown:shift+up":c(-1),"keydown:shift+down":c(1),"keyup:shift+up":b,"keyup:shift+down":b,"keyup:up":b,"keyup:down":b}); +var a="";if(this.options.allowMultiSelect&&this.options.shiftForMultiSelect&&this.options.useKeyboard){a=" (Shift multi-selects).";}this.keyboard.addShortcuts({"Select Previous Row":{keys:"up",shortcut:"up arrow",handler:c(-1),description:"Select the previous row in the table."+a},"Select Next Row":{keys:"down",shortcut:"down arrow",handler:c(1),description:"Select the next row in the table."+a}}); +}this.keyboard[d?"activate":"deactivate"]();}this.updateSelects();},mouseleave:function(){if(this.hovered){this.leaveRow(this.hovered);}}});var Scroller=new Class({Implements:[Events,Options],options:{area:20,velocity:1,onChange:function(a,b){this.element.scrollTo(a,b); +},fps:50},initialize:function(b,a){this.setOptions(a);this.element=document.id(b);this.docBody=document.id(this.element.getDocument().body);this.listener=(typeOf(this.element)!="element")?this.docBody:this.element; +this.timer=null;this.bound={attach:this.attach.bind(this),detach:this.detach.bind(this),getCoords:this.getCoords.bind(this)};},start:function(){this.listener.addEvents({mouseover:this.bound.attach,mouseleave:this.bound.detach}); +return this;},stop:function(){this.listener.removeEvents({mouseover:this.bound.attach,mouseleave:this.bound.detach});this.detach();this.timer=clearInterval(this.timer); +return this;},attach:function(){this.listener.addEvent("mousemove",this.bound.getCoords);},detach:function(){this.listener.removeEvent("mousemove",this.bound.getCoords); +this.timer=clearInterval(this.timer);},getCoords:function(a){this.page=(this.listener.get("tag")=="body")?a.client:a.page;if(!this.timer){this.timer=this.scroll.periodical(Math.round(1000/this.options.fps),this); +}},scroll:function(){var c=this.element.getSize(),a=this.element.getScroll(),h=this.element!=this.docBody?this.element.getOffsets():{x:0,y:0},d=this.element.getScrollSize(),g={x:0,y:0},e=this.options.area.top||this.options.area,b=this.options.area.bottom||this.options.area; +for(var f in this.page){if(this.page[f]<(e+h[f])&&a[f]!=0){g[f]=(this.page[f]-e-h[f])*this.options.velocity;}else{if(this.page[f]+b>(c[f]+h[f])&&a[f]+c[f]!=d[f]){g[f]=(this.page[f]-c[f]+b-h[f])*this.options.velocity; +}}g[f]=g[f].round();}if(g.y||g.x){this.fireEvent("change",[a.x+g.x,a.y+g.y]);}}});(function(){var a=function(c,b){return(c)?(typeOf(c)=="function"?c(b):b.get(c)):""; +};this.Tips=new Class({Implements:[Events,Options],options:{onShow:function(){this.tip.setStyle("display","block");},onHide:function(){this.tip.setStyle("display","none"); +},title:"title",text:function(b){return b.get("rel")||b.get("href");},showDelay:100,hideDelay:100,className:"tip-wrap",offset:{x:16,y:16},windowPadding:{x:0,y:0},fixed:false},initialize:function(){var b=Array.link(arguments,{options:Type.isObject,elements:function(c){return c!=null; +}});this.setOptions(b.options);if(b.elements){this.attach(b.elements);}this.container=new Element("div",{"class":"tip"});},toElement:function(){if(this.tip){return this.tip; +}this.tip=new Element("div",{"class":this.options.className,styles:{position:"absolute",top:0,left:0}}).adopt(new Element("div",{"class":"tip-top"}),this.container,new Element("div",{"class":"tip-bottom"})); +return this.tip;},attach:function(b){$$(b).each(function(d){var f=a(this.options.title,d),e=a(this.options.text,d);d.set("title","").store("tip:native",f).retrieve("tip:title",f); +d.retrieve("tip:text",e);this.fireEvent("attach",[d]);var c=["enter","leave"];if(!this.options.fixed){c.push("move");}c.each(function(h){var g=d.retrieve("tip:"+h); +if(!g){g=function(i){this["element"+h.capitalize()].apply(this,[i,d]);}.bind(this);}d.store("tip:"+h,g).addEvent("mouse"+h,g);},this);},this);return this; +},detach:function(b){$$(b).each(function(d){["enter","leave","move"].each(function(e){d.removeEvent("mouse"+e,d.retrieve("tip:"+e)).eliminate("tip:"+e); +});this.fireEvent("detach",[d]);if(this.options.title=="title"){var c=d.retrieve("tip:native");if(c){d.set("title",c);}}},this);return this;},elementEnter:function(c,b){clearTimeout(this.timer); +this.timer=(function(){this.container.empty();["title","text"].each(function(e){var d=b.retrieve("tip:"+e);var f=this["_"+e+"Element"]=new Element("div",{"class":"tip-"+e}).inject(this.container); +if(d){this.fill(f,d);}},this);this.show(b);this.position((this.options.fixed)?{page:b.getPosition()}:c);}).delay(this.options.showDelay,this);},elementLeave:function(c,b){clearTimeout(this.timer); +this.timer=this.hide.delay(this.options.hideDelay,this,b);this.fireForParent(c,b);},setTitle:function(b){if(this._titleElement){this._titleElement.empty(); +this.fill(this._titleElement,b);}return this;},setText:function(b){if(this._textElement){this._textElement.empty();this.fill(this._textElement,b);}return this; +},fireForParent:function(c,b){b=b.getParent();if(!b||b==document.body){return;}if(b.retrieve("tip:enter")){b.fireEvent("mouseenter",c);}else{this.fireForParent(c,b); +}},elementMove:function(c,b){this.position(c);},position:function(f){if(!this.tip){document.id(this);}var c=window.getSize(),b=window.getScroll(),g={x:this.tip.offsetWidth,y:this.tip.offsetHeight},d={x:"left",y:"top"},e={y:false,x2:false,y2:false,x:false},h={}; +for(var i in d){h[d[i]]=f.page[i]+this.options.offset[i];if(h[d[i]]<0){e[i]=true;}if((h[d[i]]+g[i]-b[i])>c[i]-this.options.windowPadding[i]){h[d[i]]=f.page[i]-this.options.offset[i]-g[i]; +e[i+"2"]=true;}}this.fireEvent("bound",e);this.tip.setStyles(h);},fill:function(b,c){if(typeof c=="string"){b.set("html",c);}else{b.adopt(c);}},show:function(b){if(!this.tip){document.id(this); +}if(!this.tip.getParent()){this.tip.inject(document.body);}this.fireEvent("show",[this.tip,b]);},hide:function(b){if(!this.tip){document.id(this);}this.fireEvent("hide",[this.tip,b]); +}});})();Locale.define("en-GB","Date",{dateOrder:["date","month","year"],shortDate:"%d/%m/%Y",shortTime:"%H:%M"}).inherit("en-US","Date"); \ No newline at end of file diff --git a/web/views/file.php b/web/views/file.php index f36614c94..772226a55 100644 --- a/web/views/file.php +++ b/web/views/file.php @@ -50,7 +50,7 @@ else // Simple version if ( $errorText ) - error_log( $errorText ); + Error( $errorText ); else readfile( ZM_DIR_EVENTS.'/'.$path ); ?> diff --git a/web/views/image.php b/web/views/image.php index fdac51e4c..b56f34730 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -55,7 +55,7 @@ if ( true ) { // Simple version if ( $errorText ) - error_log( $errorText ); + Error( $errorText ); else readfile( ZM_DIR_EVENTS.'/'.$path ); } @@ -63,7 +63,7 @@ else { // Not so simple version if ( !function_exists( "imagecreatefromjpeg" ) ) - error_log( "No function" ); + Warning( "The imagecreatefromjpeg function is not present, php-gd not installed?" ); if ( !$errorText ) { @@ -71,7 +71,7 @@ else { $errorText = "Can't load image"; $error = error_get_last(); - error_log( $error['message'] ); + Error( $error['message'] ); } } @@ -80,19 +80,19 @@ else if ( !($image = imagecreatetruecolor( 160, 120 )) ) { $error = error_get_last(); - error_log( $error['message'] ); + Error( $error['message'] ); } if ( !($textColor = imagecolorallocate( $image, 255, 0, 0 )) ) { $error = error_get_last(); - error_log( $error['message'] ); + Error( $error['message'] ); } if ( !imagestring( $image, 1, 20, 60, $errorText, $textColor ) ) { $error = error_get_last(); - error_log( $error['message'] ); + Error( $error['message'] ); } - error_log( $errorText." - ".$path ); + Fatal( $errorText." - ".$path ); } imagejpeg( $image );