From 1ffb4977579b68f04d42367f69cdca38c651024f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Feb 2015 09:18:49 -0500 Subject: [PATCH 001/154] add lowercase test for BSD, add check for sendmail, don't check for libdl, add check for backtrace --- configure.ac | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/configure.ac b/configure.ac index 0cde4661b..b0cb929ed 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,12 @@ case $host_os in *BSD*) # Do something specific for BSD HOST_OS='BSD' + AC_DEFINE(BSD,1,"This is a BSD system") + ;; + *bsd*) + # Do something specific for BSD + HOST_OS='BSD' + AC_DEFINE(BSD,1,"This is a BSD system") ;; *) #Default Case @@ -315,7 +321,8 @@ AC_FUNC_STRTOD AC_FUNC_VPRINTF AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strspn strstr strtol strtoull]) AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction]) - +# this is required for freebsd to compile +AC_CHECK_SENDFILE # Other programs AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no) AC_PATH_PROG(PATH_FFMPEG,ffmpeg) @@ -330,7 +337,10 @@ AC_CHECK_LIB(rt,clock_gettime,,AC_MSG_ERROR(zm requires librt)) AC_SEARCH_LIBS(mysql_init,[mysqlclient mariadbclient],,AC_MSG_ERROR(zm requires libmysqlclient.a or libmariadbclient.a)) AC_CHECK_LIB(jpeg,jpeg_start_compress,,AC_MSG_ERROR(zm requires libjpeg.a)) AC_CHECK_LIB(pthread,pthread_create,,AC_MSG_ERROR(zm requires libpthread.a)) +if test "$BSD" == "0"; then AC_CHECK_LIB(dl,dlsym,,AC_MSG_ERROR(zm requires libdl.a)) +fi +AC_CHECK_LIB(execinfo,backtrace, , AC_MSG_ERROR([unable to find the backtrace() function])) if test "$ZM_SSL_LIB" == "openssl"; then AC_CHECK_HEADERS(openssl/md5.h,,AC_MSG_WARN(zm requires openssl/md5.h header to be installed for openssl),) AC_CHECK_LIB(crypto,MD5,,AC_MSG_WARN([libcrypto.a is required for authenticated streaming - use ZM_SSL_LIB option to select gnutls instead])) @@ -470,32 +480,6 @@ fi AC_SUBST(PERL_MM_PARMS) AC_SUBST(EXTRA_PERL_LIB) -# -# Platform specific setup -# -############################# -AC_CANONICAL_HOST -# Check for which host we are on and setup a few things -# specifically based on the host -case $host_os in - darwin* ) - # Do something specific for mac - HOST_OS='darwin' - ;; - linux*) - # Do something specific for linux - HOST_OS='linux' - ;; - *BSD*) - # Do something specific for BSD - HOST_OS='BSD' - ;; - *) - #Default Case - AC_MSG_ERROR([Your platform is not currently supported]) - ;; -esac - AC_CONFIG_FILES([Makefile zm.conf zmconfgen.pl db/Makefile db/zm_create.sql misc/Makefile misc/apache.conf misc/logrotate.conf misc/syslog.conf misc/com.zoneminder.systemctl.policy misc/com.zoneminder.systemctl.rules onvif/Makefile onvif/scripts/Makefile scripts/Makefile scripts/zm scripts/zmaudit.pl scripts/zmcontrol.pl scripts/zmdc.pl scripts/zmfilter.pl scripts/zmpkg.pl scripts/zmtrack.pl scripts/zmcamtool.pl scripts/zmsystemctl.pl scripts/zmtrigger.pl scripts/zmupdate.pl scripts/zmvideo.pl scripts/zmwatch.pl scripts/zmx10.pl scripts/zmdbbackup scripts/zmdbrestore scripts/zmeventdump scripts/zmlogrotate.conf scripts/ZoneMinder/lib/ZoneMinder/Base.pm scripts/ZoneMinder/lib/ZoneMinder/Config.pm scripts/ZoneMinder/lib/ZoneMinder/Memory.pm scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm src/Makefile src/zm_config.h web/Makefile web/ajax/Makefile web/css/Makefile web/graphics/Makefile web/includes/Makefile web/includes/config.php web/js/Makefile web/lang/Makefile web/skins/Makefile web/skins/classic/Makefile web/skins/classic/ajax/Makefile web/skins/classic/css/Makefile web/skins/classic/css/classic/Makefile web/skins/classic/css/classic/views/Makefile web/skins/classic/css/flat/Makefile web/skins/classic/css/flat/views/Makefile web/skins/classic/graphics/Makefile web/skins/classic/includes/Makefile web/skins/classic/js/Makefile web/skins/classic/lang/Makefile web/skins/classic/views/Makefile web/skins/classic/views/js/Makefile web/skins/mobile/Makefile web/skins/mobile/ajax/Makefile web/skins/mobile/css/Makefile web/skins/mobile/graphics/Makefile web/skins/mobile/includes/Makefile web/skins/mobile/lang/Makefile web/skins/mobile/views/Makefile web/skins/mobile/views/css/Makefile web/tools/Makefile web/tools/mootools/Makefile web/views/Makefile web/skins/xml/Makefile web/skins/xml/views/Makefile web/skins/xml/includes/Makefile]) # Create the definitions for compilation and defaults for the database From 0bea3815109784fd632e8cb31f44c833ef4a8670 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Feb 2015 09:20:55 -0500 Subject: [PATCH 002/154] sendfile tricks --- ac_check_sendfile.m4 | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/zm_event.cpp | 8 +++++- src/zm_sendfile.h | 31 ++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 ac_check_sendfile.m4 create mode 100644 src/zm_sendfile.h diff --git a/ac_check_sendfile.m4 b/ac_check_sendfile.m4 new file mode 100644 index 000000000..12605d588 --- /dev/null +++ b/ac_check_sendfile.m4 @@ -0,0 +1,63 @@ +AC_DEFUN([AC_CHECK_SENDFILE],[ +AC_MSG_CHECKING([whether sendfile() is supported and what prototype it has]) + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror-implicit-function-declaration" +ac_sendfile_supported=no +AC_TRY_LINK([#include + #include ], + [sendfile(1, 1, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, + [Define this if Linux/Solaris sendfile() is supported]) + AC_MSG_RESULT([Linux sendfile()]) + ac_sendfile_supported=yes + ], []) + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we need libsendfile + dnl Presumably on Solaris + AC_CHECK_LIB(sendfile, sendfile, + [ + AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, + [Define this if Linux/Solaris sendfile() is supported]) + SENDFILE_LIBS="-lsendfile" + AC_SUBST(SENDFILE_LIBS) + AC_MSG_RESULT([Solaris sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we have FreeBSD-like sendfile() support. + AC_TRY_LINK([#include + #include ], + [sendfile(1, 1, 0, 0, NULL, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE7_SUPPORT, 1, + [Define this if FreeBSD sendfile() is supported]) + AC_MSG_RESULT([FreeBSD sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we have MacOS-like sendfile() support. + AC_TRY_LINK([#include + #include + #include ], + [sendfile(1, 1, 0, NULL, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE6_SUPPORT, 1, + [Define this if MacOS sendfile() is supported]) + AC_MSG_RESULT([MacOS sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +CFLAGS="$saved_CFLAGS" + +if test x$ac_sendfile_supported = xno; then + AC_MSG_RESULT([no sendfile() support, using read/send]) +fi +]) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 1c7e13e7d..464fe7e56 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -36,6 +36,12 @@ #include "zm_event.h" #include "zm_monitor.h" +// sendfile tricks +extern "C" +{ +#include "zm_sendfile.h" +} + #include "zmf.h" #if HAVE_SYS_SENDFILE_H @@ -1309,7 +1315,7 @@ bool EventStream::sendFrame( int delta_us ) if(send_raw) { #if HAVE_SENDFILE fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size ); - if(sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) { + if(zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) { /* sendfile() failed, use standard way instead */ img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { diff --git a/src/zm_sendfile.h b/src/zm_sendfile.h new file mode 100644 index 000000000..ce3405d66 --- /dev/null +++ b/src/zm_sendfile.h @@ -0,0 +1,31 @@ +#ifdef HAVE_SENDFILE4_SUPPORT +#include +int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) { + int err; + + err = sendfile(out_fd, in_fd, offset, size); + if (err < 0) + return -errno; + + return err; +} +#elif HAVE_SENDFILE7_SUPPORT +#include +#include +#include +int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) { + int err; + err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0); + if (err && errno != EAGAIN) + return -errno; + + if (size) { + *offset += size; + return size; + } + + return -EAGAIN; +} +#else +#error "Your platform does not support sendfile. Sorry." +#endif From 3cc4c2e24d41ea9ef34eaf6c6fd36a8428100aef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Feb 2015 09:22:08 -0500 Subject: [PATCH 003/154] fixes to get pid on FreeBSD --- src/zm_logger.cpp | 11 +++++++++++ src/zm_thread.h | 28 +++++++++++++++++++++++++--- src/zm_timer.h | 14 +++++++++++++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index c64f6e7c0..4b37580f7 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -31,6 +31,9 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#endif bool Logger::smInitialised = false; Logger *Logger::smInstance = 0; @@ -527,9 +530,17 @@ void Logger::logPrint( bool hex, const char * const file, const int line, const #endif pid_t tid; +#ifdef __FreeBSD__ + long lwpid; + thr_self(&lwpid); + tid = lwpid; + + if (tid < 0 ) // Thread/Process id +#else #ifdef HAVE_SYSCALL if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id #endif // HAVE_SYSCALL +#endif tid = getpid(); // Process id char *logPtr = logString; diff --git a/src/zm_thread.h b/src/zm_thread.h index 6a0d169f0..3ba80c09f 100644 --- a/src/zm_thread.h +++ b/src/zm_thread.h @@ -28,12 +28,26 @@ #endif // HAVE_SYS_SYSCALL_H #include "zm_exception.h" #include "zm_utils.h" +#ifdef __FreeBSD__ +#include +#endif class ThreadException : public Exception { +private: +pid_t pid() { +pid_t tid; +#ifdef __FreeBSD__ +long lwpid; +thr_self(&lwpid); +tid = lwpid; +#else +tid=syscall(SYS_gettid); +#endif +return tid; +} public: - ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)syscall(SYS_gettid) ) ) - { + ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { } }; @@ -205,7 +219,15 @@ protected: pid_t id() const { - return( (pid_t)syscall(SYS_gettid) ); +pid_t tid; +#ifdef __FreeBSD__ +long lwpid; +thr_self(&lwpid); +tid = lwpid; +#else +tid=syscall(SYS_gettid); +#endif +return tid; } void exit( int status = 0 ) { diff --git a/src/zm_timer.h b/src/zm_timer.h index 6c7663b87..80461cf07 100644 --- a/src/zm_timer.h +++ b/src/zm_timer.h @@ -32,8 +32,20 @@ class Timer private: class TimerException : public Exception { + private: + pid_t pid() { + pid_t tid; +#ifdef __FreeBSD__ + long lwpid; + thr_self(&lwpid); + tid = lwpid; +#else + tid=syscall(SYS_gettid); +#endif + return tid; + } public: - TimerException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)syscall(SYS_gettid) ) ) + TimerException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { } }; From 52938920de70da46d89d054586bface543919410 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Feb 2015 09:22:39 -0500 Subject: [PATCH 004/154] backtrace is in execinfo on FreeBSD --- src/zm_signal.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index 6db4697ed..8f5b929d0 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -23,6 +23,9 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#endif #define TRACE_SIZE 16 From c7dc157f4d0f78cfc44d5f52606cb54ee0c58989 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Feb 2015 09:22:55 -0500 Subject: [PATCH 005/154] FreeBSD fix --- src/zmc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 397468140..d993bb0b5 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -19,12 +19,16 @@ #include #include -#if defined(BSD) +#if defined(__FreeBSD__) #include #else #include #endif +#if !defined(MAXINT) +#define MAXINT INT_MAX +#endif + #include "zm.h" #include "zm_db.h" #include "zm_time.h" From 20107ac1e6a79d07d0a896478675db3b48ffb5a4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 1 Mar 2015 10:51:04 -0600 Subject: [PATCH 006/154] remove NETPBM dependency from autotools --- configure.ac | 5 ----- web/lang/ro_ro.php | 8 -------- 2 files changed, 13 deletions(-) diff --git a/configure.ac b/configure.ac index 8994ae159..c42847877 100644 --- a/configure.ac +++ b/configure.ac @@ -319,11 +319,6 @@ AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction]) # Other programs AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no) AC_PATH_PROG(PATH_FFMPEG,ffmpeg) -AC_CHECK_PROG(OPT_NETPBM,pnmscale,yes,no) -AC_PATH_PROG(PATH_NETPBM,pnmscale) -if test "$OPT_NETPBM" == "yes"; then -PATH_NETPBM=`dirname $PATH_NETPBM` -fi # Checks for libraries. AC_CHECK_LIB(rt,clock_gettime,,AC_MSG_ERROR(zm requires librt)) diff --git a/web/lang/ro_ro.php b/web/lang/ro_ro.php index 74da43406..f82573f6b 100644 --- a/web/lang/ro_ro.php +++ b/web/lang/ro_ro.php @@ -1144,14 +1144,6 @@ $OLANG = array( 'Prompt' => "Opţiuni adiţionale pentru ffmpeg", 'Help' => "Ffmpeg suportă multe opţiuni pentru controlul calităţii secvenţei video produse. Această opţiune vă permite să specificaţi propriile opţiuni. Citiţi documentaţia ffmpeg pentru mai multe detalii." ), - 'OPT_NETPBM' => array( - 'Prompt' => "Sunt instalate utilitarele Netpbm (opţional)", - 'Help' => "În cazul laţimii de bandă redusă ZoneMinder va miniaturiza imaginile înainte de a le direcţiona spre browser pentru a reduce traficul. Pentru aceasta foloseşte pachetul Netpbm; această opţiune ar trebuie să direcţioneze ZoneMinder spre binarele pachetului. Dacă nu aveţi pachetul Netpbm instalat imaginilor vor fi întotdeauna trimise la scară reală şi redimensionate în browser." - ), - 'PATH_NETPBM' => array( - 'Prompt' => "Cale la utilitarele Netpbm (opţional)", - 'Help' => "Calea la utilitarele Netpbm (opţional)" - ), 'OPT_TRIGGERS' => array( 'Prompt' => "Interacţionează cu declanşatoare externe via socket sau fişierele dispozitivelor", 'Help' => "ZoneMinder poate interacţiona cu sisteme externe care acţionează sau revocă o alarmă. Acest lucru este realizat prin intermediului script-ului zmtrigger.pl. Această opţiune indică folosirea declanşatoarelor externe, majoritatea vor alege nu aici." From 2e10263b64c2d6756484af1616ae03e417c56b06 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Mar 2015 16:34:31 -0500 Subject: [PATCH 007/154] Improve logging to include monitor name and for shared cameras show 1/1 instead of 0/1 --- src/zmc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 397468140..cbfc80e37 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -270,21 +270,21 @@ int main( int argc, char *argv[] ) { if ( monitors[i]->PreCapture() < 0 ) { - Error( "Failed to pre-capture monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors ); + Error( "Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); zm_terminate = true; result = -1; break; } if ( monitors[i]->Capture() < 0 ) { - Error( "Failed to capture image from monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors ); + Error( "Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); zm_terminate = true; result = -1; break; } if ( monitors[i]->PostCapture() < 0 ) { - Error( "Failed to post-capture monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors ); + Error( "Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); zm_terminate = true; result = -1; break; From 6114acdadf694981edce035e9bebcae310408ebd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2015 15:15:12 -0400 Subject: [PATCH 008/154] tell configure to look in m4 for additional macros --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b0cb929ed..be27a45de 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ AC_INIT(zm,1.28.1,[http://www.zoneminder.com/forums/ - Please check FAQ first],z AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AC_CONFIG_HEADERS(config.h) +AC_CONFIG_MACRO_DIR([m4]) AC_SUBST([AM_CXXFLAGS], [-D__STDC_CONSTANT_MACROS]) @@ -340,7 +341,6 @@ AC_CHECK_LIB(pthread,pthread_create,,AC_MSG_ERROR(zm requires libpthread.a)) if test "$BSD" == "0"; then AC_CHECK_LIB(dl,dlsym,,AC_MSG_ERROR(zm requires libdl.a)) fi -AC_CHECK_LIB(execinfo,backtrace, , AC_MSG_ERROR([unable to find the backtrace() function])) if test "$ZM_SSL_LIB" == "openssl"; then AC_CHECK_HEADERS(openssl/md5.h,,AC_MSG_WARN(zm requires openssl/md5.h header to be installed for openssl),) AC_CHECK_LIB(crypto,MD5,,AC_MSG_WARN([libcrypto.a is required for authenticated streaming - use ZM_SSL_LIB option to select gnutls instead])) From ef340255d3cacd7a868398988e6d3ffbe020dabd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2015 15:15:55 -0400 Subject: [PATCH 009/154] move the macro for AC_SENDFILE into the m4 directory --- m4/ac_check_sendfile.m4 | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 m4/ac_check_sendfile.m4 diff --git a/m4/ac_check_sendfile.m4 b/m4/ac_check_sendfile.m4 new file mode 100644 index 000000000..12605d588 --- /dev/null +++ b/m4/ac_check_sendfile.m4 @@ -0,0 +1,63 @@ +AC_DEFUN([AC_CHECK_SENDFILE],[ +AC_MSG_CHECKING([whether sendfile() is supported and what prototype it has]) + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror-implicit-function-declaration" +ac_sendfile_supported=no +AC_TRY_LINK([#include + #include ], + [sendfile(1, 1, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, + [Define this if Linux/Solaris sendfile() is supported]) + AC_MSG_RESULT([Linux sendfile()]) + ac_sendfile_supported=yes + ], []) + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we need libsendfile + dnl Presumably on Solaris + AC_CHECK_LIB(sendfile, sendfile, + [ + AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, + [Define this if Linux/Solaris sendfile() is supported]) + SENDFILE_LIBS="-lsendfile" + AC_SUBST(SENDFILE_LIBS) + AC_MSG_RESULT([Solaris sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we have FreeBSD-like sendfile() support. + AC_TRY_LINK([#include + #include ], + [sendfile(1, 1, 0, 0, NULL, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE7_SUPPORT, 1, + [Define this if FreeBSD sendfile() is supported]) + AC_MSG_RESULT([FreeBSD sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we have MacOS-like sendfile() support. + AC_TRY_LINK([#include + #include + #include ], + [sendfile(1, 1, 0, NULL, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE6_SUPPORT, 1, + [Define this if MacOS sendfile() is supported]) + AC_MSG_RESULT([MacOS sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +CFLAGS="$saved_CFLAGS" + +if test x$ac_sendfile_supported = xno; then + AC_MSG_RESULT([no sendfile() support, using read/send]) +fi +]) From ed28eebba4518199c9b1ecc778c45ac14f5dd394 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2015 15:16:15 -0400 Subject: [PATCH 010/154] This is already included in zm_signal.h --- src/zm_signal.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index 8f5b929d0..6db4697ed 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -23,9 +23,6 @@ #include #include #include -#ifdef __FreeBSD__ -#include -#endif #define TRACE_SIZE 16 From 11f7af3b03b2ce24cd87242be44ab7f9ed91e39c Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Mon, 30 Mar 2015 14:41:01 +1100 Subject: [PATCH 011/154] fixing POD errors manpage-has-errors-from-pod2man (forgotten '=back' before '=head2') Signed-off-by: Dmitry Smirnov --- scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm | 2 ++ scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 2 ++ scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 2 ++ scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in | 12 +++++++++--- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm b/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm index 673e13c98..d57493fc8 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm @@ -195,6 +195,8 @@ Loads existing configuration from the database (if any) and merges it with the d Saves configuration held in memory to the database. The act of loading and saving configuration is a convenient way to ensure that the configuration held in the database corresponds with the most recent definitions and that all components are using the same set of configuration. +=back + =head2 EXPORT None by default. diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 46da03bf0..ac64d46ff 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2012,6 +2012,8 @@ Loads existing configuration from the database (if any) and merges it with the d Saves configuration held in memory to the database. The act of loading and saving configuration is a convenient way to ensure that the configuration held in the database corresponds with the most recent definitions and that all components are using the same set of configuration. +=back + =head2 EXPORT None by default. diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 5b4438c72..ea786e66a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -827,6 +827,8 @@ This method will output a fatal error message and then die if the current debug 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. +=back + =head2 EXPORT None by default. diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in index df32e7608..fbb213414 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in @@ -733,10 +733,10 @@ The core elements of ZoneMinder used mapped memory to allow multiple access to r All the methods listed below require a 'monitor' parameter. This must be a reference to a hash with at least the 'Id' field set to the monitor id of the mapped memory you wish to access. Using database methods to select the monitor details will also return this kind of data. Some of the mapped memory methods will add and amend new fields to this hash. -=over 4 - =head1 METHODS +=over 4 + =item zmMemVerify ( $monitor ); Verify that the mapped memory of the monitor given exists and is valid. It will return an undefined value if it is not valid. You should generally call this method first before using any of the other methods, but most of the remaining methods will also do so if the memory has not already been verified. @@ -809,6 +809,8 @@ Cancel any previous trigger on or off requests. This stops a triggered alarm if Indicate that the given text should be displayed in the timestamp annotation on any images captured, if the format of the annotation string defined for the monitor permits. +=back + =head1 DATA The data fields in mapped memory that may be accessed are as follows. There are two main sections, shared_data which is general data and trigger_data which is used for event triggering. Whilst reading from these fields is harmless, extreme care must be taken when writing to mapped memory, especially in the shared_data section as this is normally written to only by monitor capture and analysis processes. @@ -844,6 +846,8 @@ The data fields in mapped memory that may be accessed are as follows. There are The following constants are used by the methods above, but can also be used by user scripts if required. +=over 4 + =item STATE_IDLE STATE_PREALARM STATE_ALARM STATE_ALERT STATE_TAPE These constants define the state of the monitor with respect to alarms and events. They are used in the shared_data:state field. @@ -852,10 +856,12 @@ These constants define the state of the monitor with respect to alarms and event These constants defines the various values that can exist in the shared_data:action field. This is a bitmask which when non-zero defines an action that an executing monitor process should take. ACTION_GET requires that the current values of brightness, contrast, colour and hue are taken from the camera and written to the equivalent mapped memory fields. ACTION_SET implies the reverse, that the values in mapped memory should be written to the camera. ACTION_RELOAD signal that the monitor process should reload itself from the database in case any settings have changed there. ACTION_SUSPEND signals that a monitor should stop exaiming images for motion, though other alarms may still occur. ACTION_RESUME sigansl that a monitor should resume motion detectiom. -=item TRIGGER_CANCEL TRIGGER_ON TRIGGER_OFF +=item TRIGGER_CANCEL TRIGGER_ON TRIGGER_OFF These constants are used in the definition of external triggers. TRIGGER_CANCEL is used to indicated that any previous trigger settings should be cancelled, TRIGGER_ON signals that an alarm should be created (or continued)) as a result of the current trigger and TRIGGER_OFF signals that the trigger should prevent any alarms from being generated. See the trigger methods above for further details. +=back + =head1 EXPORT None by default. From b0faa138bdf8c1f1d2222d4382eebff482b8d431 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Mon, 30 Mar 2015 15:07:03 +1100 Subject: [PATCH 012/154] POD: added missing NAME sections Signed-off-by: Dmitry Smirnov --- scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm | 4 ++-- scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm | 4 ++-- scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm | 4 ++++ scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm index 7ffbf248a..b12f42021 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm @@ -658,9 +658,9 @@ sub presetGoto __END__ # Below is stub documentation for your module. You'd better edit it! -=head1 FI-8608W +=head1 NAME -ZoneMinder::Database - Perl extension for FOSCAM FI-8608W by Christophe_Y2k +ZoneMinder::Control::FI-8608W - Perl extension for FOSCAM FI-8608W by Christophe_Y2k =head1 SYNOPSIS diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm index 7d9cd261d..ece4736e4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm @@ -734,9 +734,9 @@ sub presetGoto __END__ # Below is stub documentation for your module. You'd better edit it! -=head1 FI8620 +=head1 NAME -ZoneMinder::Database - Perl extension for FOSCAM FI8620 +ZoneMinder::Control::FI8620 - Perl extension for FOSCAM FI8620 =head1 SYNOPSIS diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm index ab877c609..cd925f72b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm @@ -220,6 +220,10 @@ sub presetHome __END__ =pod +=head1 NAME + +ZoneMinder::Control::FI8908W - Foscam FI8908W camera control + =head1 DESCRIPTION This module contains the implementation of the Foscam FI8908W / FI8918W IP camera control diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm index 4177f5857..e31ab0052 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm @@ -696,9 +696,9 @@ sub presetGoto __END__ # Below is stub documentation for your module. You'd better edit it! -=head1 FI9821W +=head1 NAME -ZoneMinder::Database - Perl extension for FOSCAM FI9821W +ZoneMinder::Control::FI9821W - Perl extension for FOSCAM FI9821W =head1 SYNOPSIS From 6bbe42c5eb3351166a4d47fc66a5690e06d5cca8 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Mon, 30 Mar 2015 15:26:59 +1100 Subject: [PATCH 013/154] build: fix FTBFS with format-hardening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~~~~ x86_64-linux-gnu-g++ -DHAVE_CONFIG_H -I. -I.. -I/usr/include -I/usr/include -I/usr/include -D__STDC_CONSTANT_MACROS -Wall -finline-functions -fomit-frame-pointer -I/usr/include -D__STDC_CONSTANT_MACROS -D_FORTIFY_SOURCE=2 -D__STDC_CONSTANT_MACROS -D__STDC_CONSTANT_MACROS -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -DZM_FFMPEG_CVS -DHAVE_LIBCRYPTO -MT zm_mpeg.o -MD -MP -MF .deps/zm_mpeg.Tpo -c -o zm_mpeg.o zm_mpeg.cpp zm_mpeg.cpp: In member function ‘void VideoStream::SetupFormat()’: zm_mpeg.cpp:112:56: error: format not a string literal and no format arguments [-Werror=format-security] snprintf( s->filename, sizeof(s->filename), filename ); ^ zm_mpeg.cpp:112:56: error: format not a string literal and no format arguments [-Werror=format-security] ~~~~ Signed-off-by: Dmitry Smirnov --- src/zm_mpeg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index 2e29880ca..e3e544e73 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -109,7 +109,7 @@ void VideoStream::SetupFormat( ) if(filename) { - snprintf( s->filename, sizeof(s->filename), filename ); + snprintf( s->filename, sizeof(s->filename), "%s", filename ); } ofc = s; From 5f6c559476b9303aab0584d478bf21a64ab10551 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Tue, 31 Mar 2015 02:47:16 +1100 Subject: [PATCH 014/154] POD: zmupdate.pl converted to "pod2usage" Best practice for POD documentation is to (re-)use it for displaying usage info. Now `perldoc zmupdate.pl` shows expected information and we can even generate man page automatically with `pod2man zmupdate.pl`. Signed-off-by: Dmitry Smirnov --- scripts/zmupdate.pl.in | 69 +++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 41a081fc1..2650ba812 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -20,11 +20,33 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script just checks what the most recent release of ZoneMinder is -# at the the moment. It will eventually be responsible for applying and -# configuring upgrades etc, including on the fly upgrades. -# + +=head1 NAME + +zmupdate.pl - check and upgrade Zoneminer database + +=head1 SYNOPSIS + + zmupdate.pl -c,--check | -f,--freshen | -v,--version= [-u -p] + +=head1 DESCRIPTION + +This script just checks what the most recent release of ZoneMinder is +at the the moment. It will eventually be responsible for applying and +configuring upgrades etc, including on the fly upgrades. + +=head1 OPTIONS + + -c, --check - Check for updated versions of ZoneMinder + -f, --freshen - Freshen the configuration in the database. Equivalent of old zmconfig.pl -noi + -v, --version= - Force upgrade to the current version from + -u, --user= - Alternate DB user with privileges to alter DB + -p, --pass= - Password of alternate DB user with privileges to alter DB + -d,--dir= - Directory containing update files if not in default build location + -interactive - interact with the user + -nointeractive - do not interact with the user + +=cut use strict; use bytes; @@ -52,6 +74,7 @@ use ZoneMinder::ConfigAdmin qw( :functions ); use POSIX; use DBI; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use Data::Dumper; use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); @@ -78,27 +101,19 @@ my $version = ''; my $dbUser = $Config{ZM_DB_USER}; my $dbPass = $Config{ZM_DB_PASS}; my $updateDir = ''; -sub Usage -{ - print( " -Usage: zmupdate.pl <-c,--check|-f,--freshen|-v,--version=> [-u -p]> -Parameters are :- --c, --check - Check for updated versions of ZoneMinder --f, --freshen - Freshen the configuration in the database. Equivalent of old zmconfig.pl -noi --v, --version= - Force upgrade to the current version from --u, --user= - Alternate DB user with privileges to alter DB --p, --pass= - Password of alternate DB user with privileges to alter DB --d,--dir= - Directory containing update files if not in default build location --interactive - interact with the user --nointeractive - do not interact with the user -"); - exit( -1 ); -} -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(); -} +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 +) or pod2usage(-exitstatus => -1); my $dbh = zmDbConnect(); $Config{ZM_DB_USER} = $dbUser; @@ -113,14 +128,14 @@ if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) else { print( STDERR "Please give a valid option\n" ); - Usage(); + pod2usage(-exitstatus => -1); } } if ( ($check + $freshen + $rename + $zoneFix + $migrateEvents + ($version?1:0)) > 1 ) { print( STDERR "Please give only one option\n" ); - Usage(); + pod2usage(-exitstatus => -1); } if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) From ca041a3ce50b9efa43f1bc208e14f8229277e29d Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Mon, 30 Mar 2015 20:06:59 +0200 Subject: [PATCH 015/154] Revert "Update fr_fr.php" This reverts commit 3b9c3f0776cb2ab4d48069accf1137b3a0a333e1. --- web/lang/fr_fr.php | 526 ++++++++++++++++++++++----------------------- 1 file changed, 263 insertions(+), 263 deletions(-) diff --git a/web/lang/fr_fr.php b/web/lang/fr_fr.php index 3ee74aa23..def9d1575 100644 --- a/web/lang/fr_fr.php +++ b/web/lang/fr_fr.php @@ -75,27 +75,27 @@ $SLANG = array( '32BitColour' => 'Couleur 32 bit', // Added - 2011-06-15 '8BitGrey' => 'Gris 8 bit', 'Action' => 'Action', - 'Actual' => 'RÈel', - 'AddNewControl' => 'Ajouter controle', - 'AddNewMonitor' => 'Ajouter camÈra', - 'AddNewUser' => 'Ajouter utilisateur', - 'AddNewZone' => 'Ajouter zone', + 'Actual' => 'Réel', + 'AddNewControl' => 'Add New Control', + 'AddNewMonitor' => 'Aj. nouv. écran', + 'AddNewUser' => 'Aj. nouv. util.', + 'AddNewZone' => 'Aj. nouv. zone', 'Alarm' => 'Alarme', 'AlarmBrFrames' => 'Images
alarme', 'AlarmFrame' => 'Image alarme', - 'AlarmFrameCount' => 'Nombre dimage alarme', + 'AlarmFrameCount' => 'Alarm Frame Count', 'AlarmLimits' => 'Limites alarme', - 'AlarmMaximumFPS' => 'i/s maximum pendant alarme', + 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Px Alarme', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', 'Alert' => 'Alerte', 'All' => 'Tous', 'Apply' => 'Appliquer', - 'ApplyingStateChange' => 'Appl. chgt Ètat', - 'ArchArchived' => 'ArchivÈ seul.', + 'ApplyingStateChange' => 'Appl. chgt état', + 'ArchArchived' => 'Archivé seul.', 'ArchUnarchived' => 'Non-arch. seul.', 'Archive' => 'Archiver', - 'Archived' => 'ArchivÈs', + 'Archived' => 'Archived', 'Area' => 'Area', 'AreaUnits' => 'Area (px/%)', 'AttrAlarmFrames' => 'Images alarme', @@ -103,27 +103,27 @@ $SLANG = array( 'AttrAvgScore' => 'Score moy.', 'AttrCause' => 'Cause', 'AttrDate' => 'Date', - 'AttrDateTime' => 'Date/Heure', + 'AttrDateTime' => 'Date/temps', 'AttrDiskBlocks' => 'Disk Blocks', 'AttrDiskPercent' => 'Disk Percent', - 'AttrDuration' => 'DurÈe', + 'AttrDuration' => 'Durée', 'AttrFrames' => 'Images', 'AttrId' => 'Id', 'AttrMaxScore' => 'Score max.', - 'AttrMonitorId' => 'N∞ camÈra', - 'AttrMonitorName' => 'Nom camÈra', - 'AttrName' => 'Nom', + 'AttrMonitorId' => 'N° écran', + 'AttrMonitorName' => 'Nom écran', + 'AttrName' => 'Name', 'AttrNotes' => 'Notes', - 'AttrSystemLoad' => 'Charge SystËme', - 'AttrTime' => 'Heure', + 'AttrSystemLoad' => 'System Load', + 'AttrTime' => 'Temps', 'AttrTotalScore' => 'Score total', 'AttrWeekday' => 'Semaine', 'Auto' => 'Auto', 'AutoStopTimeout' => 'Auto Stop Timeout', - 'Available' => 'Disponible', // Added - 2009-03-31 + 'Available' => 'Available', // Added - 2009-03-31 'AvgBrScore' => 'Score
moy.', - 'Background' => 'ArriËre-plan', - 'BackgroundFilter' => 'Lancer les filtres en arriËre-plan', + 'Background' => 'Background', + 'BackgroundFilter' => 'Run filter in background', 'BadAlarmFrameCount' => 'Alarm frame count must be an integer of one or more', 'BadAlarmMaxFPS' => 'Alarm Maximum FPS must be a positive integer or floating point value', 'BadChannel' => 'Channel must be set to an integer of zero or more', @@ -139,7 +139,7 @@ $SLANG = array( 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', - 'BadNameChars' => 'Les noms ne peuvent contenir que des lettres, chiffres, trait d\'union ou soulignÈ', + 'BadNameChars' => 'Les noms ne peuvent contenir que des lettres, chiffres, trait d\'union ou souligné', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', 'BadPort' => 'Port must be set to a valid number', @@ -152,12 +152,12 @@ $SLANG = array( 'BadWarmupCount' => 'Warmup frames must be an integer of zero or more', 'BadWebColour' => 'Web colour must be a valid web colour string', 'BadWidth' => 'Width must be set to a valid value', - 'Bandwidth' => 'dÈbit', - 'BandwidthHead' => 'dÈbit', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'Bandwidth' => 'Bande-pass.', + 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing 'BlobPx' => 'Px forme', 'BlobSizes' => 'Taille forme', 'Blobs' => 'Formes', - 'Brightness' => 'LuminositÈ;', + 'Brightness' => 'Luminosité;', 'Buffers' => 'Tampons', 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', @@ -197,33 +197,33 @@ $SLANG = array( 'CanZoomAbs' => 'Can Zoom Absolute', 'CanZoomCon' => 'Can Zoom Continuous', 'CanZoomRel' => 'Can Zoom Relative', - 'Cancel' => 'Annuler', - 'CancelForcedAlarm' => 'Annuler Alarme ForcÈe', - 'CaptureHeight' => 'Hauteur', - 'CaptureMethod' => 'MÈthode', // Added - 2009-02-08 - 'CapturePalette' => 'Palette', - 'CaptureWidth' => 'Largeur', + 'Cancel' => 'Annul.', + 'CancelForcedAlarm' => 'Annul. Forcé Alarme', + 'CaptureHeight' => 'Haut. capture', + 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 + 'CapturePalette' => 'palette capture', + 'CaptureWidth' => 'Larg. capture', 'Cause' => 'Cause', - 'CheckMethod' => 'MÈthode vÈrif. alarme', + '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' => 'Choisir PrÈrÈglages', - 'Clear' => 'Effacer', // Added - 2011-06-16 + 'ChoosePreset' => 'Choose Preset', + 'Clear' => 'Clear', // Added - 2011-06-16 'Close' => 'Fermer', 'Colour' => 'Couleur', - 'Command' => 'Commande', + 'Command' => 'Command', 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', - 'ConfiguredFor' => 'ConfigurÈ pour', + 'ConfiguredFor' => 'Configuré pour', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', - 'ConfirmPassword' => 'Confirmer mot de passe', + 'ConfirmPassword' => 'Confirmer mt de pass.', 'ConjAnd' => 'et', 'ConjOr' => 'ou', 'Console' => 'Console', 'ContactAdmin' => 'Contactez votre administrateur SVP', - 'Continue' => 'Continuer', + 'Continue' => 'Continue', 'Contrast' => 'Contraste', 'Control' => 'Control', 'ControlAddress' => 'Control Address', @@ -235,27 +235,27 @@ $SLANG = array( 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle vision', 'DateTime' => 'Date/Time', // Added - 2011-06-16 - 'Day' => 'Aujourd'hui', + 'Day' => 'Jour', 'Debug' => 'Debug', - 'DefaultRate' => 'Vitesse par dÈfaut', - 'DefaultScale' => 'Echelle par dÈfaut', - 'DefaultView' => 'Vue par dÈfaut', - 'Delete' => 'Effacer', + 'DefaultRate' => 'Default Rate', + 'DefaultScale' => 'Default Scale', + 'DefaultView' => 'Default View', + 'Delete' => 'Eff.', 'DeleteAndNext' => 'Eff. & suiv.', 'DeleteAndPrev' => 'Eff. & prec.', - 'DeleteSavedFilter' => 'Eff. filtre sauvÈ', + 'DeleteSavedFilter' => 'Eff. filtre sauvé', 'Description' => 'Description', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'Device' => 'CamÈra', // Added - 2009-02-08 - 'DeviceChannel' => 'Canal camÈra', - 'DeviceFormat' => 'Format camÈra', - 'DeviceNumber' => 'NumÈro camÈra', - 'DevicePath' => 'Chemin', - 'Devices' => 'CamÈras', + 'Device' => 'Device', // Added - 2009-02-08 + 'DeviceChannel' => 'Canal caméra', + 'DeviceFormat' => 'Format caméra', + 'DeviceNumber' => 'Numéro caméra', + 'DevicePath' => 'Device Path', + 'Devices' => 'Devices', 'Dimensions' => 'Dimensions', - 'DisableAlarms' => 'DÈsactiver les alarmes', - 'Disk' => 'Stockage', - 'Display' => 'Affichage', // Added - 2011-01-30 + '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', @@ -267,58 +267,58 @@ $SLANG = array( 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', 'DoNativeMotionDetection'=> 'Do Native Motion Detection', - 'Download' => 'TÈlÈcharger', + 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 - 'Duration' => 'DurÈe', + 'Duration' => 'Durée', 'Edit' => 'Editer', - 'Email' => 'Email', - 'EnableAlarms' => 'Activer les alarmes', - 'Enabled' => 'ActivÈ', + 'Email' => 'Courriel', + 'EnableAlarms' => 'Enable Alarms', + 'Enabled' => 'Activé', 'EnterNewFilterName' => 'Entrer nom nouv. filtre', 'Error' => 'Erreur', - 'ErrorBrackets' => 'Erreur, vÈrifiez que toutes les parenthËses ouvertes sont fermÈes', - 'ErrorValidValue' => 'Erreur, vÈrifiez que tous les termes ont une valeur valide', + 'ErrorBrackets' => 'Erreur, vérifiez que toutes les parenthèses ouvertes sont fermées', + 'ErrorValidValue' => 'Erreur, vérifiez que tous les termes ont une valeur valide', 'Etc' => 'etc', - 'Event' => 'ÈvÈnement', - 'EventFilter' => 'Filtre ÈvÈnement', - 'EventId' => 'Id', - 'EventName' => 'Nom', - 'EventPrefix' => 'Prefix', - 'Events' => 'ÈvÈnements', + 'Event' => 'Evènt', + 'EventFilter' => 'Filtre evènt', + 'EventId' => 'Event Id', + 'EventName' => 'Event Name', + 'EventPrefix' => 'Event Prefix', + 'Events' => 'Evènts', 'Exclude' => 'Exclure', - 'Execute' => 'Executer', - 'Export' => 'Exporter', - 'ExportDetails' => 'Exporter dÈtails ÈvÈnement', - 'ExportFailed' => 'Exportation ÈchouÈe', - 'ExportFormat' => 'Format', + 'Execute' => 'Execute', + 'Export' => 'Export', + 'ExportDetails' => 'Export Event Details', + 'ExportFailed' => 'Export Failed', + 'ExportFormat' => 'Export File Format', 'ExportFormatTar' => 'Tar', 'ExportFormatZip' => 'Zip', - 'ExportFrames' => 'Exporter dÈtails image', - 'ExportImageFiles' => 'Exporter fichiers image', - 'ExportLog' => 'Exporter Log', // Added - 2011-06-17 - 'ExportMiscFiles' => 'Exporter autres fichiers', - 'ExportOptions' => 'Options d'exportation', - 'ExportSucceeded' => 'Exportation rÈussie', // Added - 2009-02-08 - 'ExportVideoFiles' => 'Exporter fichiers video', - 'Exporting' => 'Exportation', + '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 + 'ExportVideoFiles' => 'Export Video Files (if present)', + 'Exporting' => 'Exporting', 'FPS' => 'i/s', 'FPSReportInterval' => 'FPS Report Interval', 'FTP' => 'FTP', - 'Far' => 'Loin', - 'FastForward' => 'Avance rapide', - 'Feed' => 'Flux', + 'Far' => 'Far', + 'FastForward' => 'Fast Forward', + 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 - 'File' => 'Fichier', - 'FilterArchiveEvents' => 'Archiver', - 'FilterDeleteEvents' => 'Effacer', - 'FilterEmailEvents' => 'Envoyer les dÈtails par mail', - 'FilterExecuteEvents' => 'Executer une commande', - 'FilterMessageEvents' => 'Envoyer les dÈtails par message', + 'File' => 'File', + 'FilterArchiveEvents' => 'Archive all matches', + 'FilterDeleteEvents' => 'Delete all matches', + 'FilterEmailEvents' => 'Email details of all matches', + 'FilterExecuteEvents' => 'Execute command on all matches', + 'FilterMessageEvents' => 'Message details of all matches', 'FilterPx' => 'Filter Px', 'FilterUnset' => 'You must specify a filter width and height', - 'FilterUploadEvents' => 'TransfÈrer', - 'FilterVideoEvents' => 'CrÈer video', - 'Filters' => 'Filtres', + 'FilterUploadEvents' => 'Upload all matches', + 'FilterVideoEvents' => 'Create video for all matches', + 'Filters' => 'Filters', 'First' => 'Prem.', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', @@ -332,21 +332,21 @@ $SLANG = array( 'ForceAlarm' => 'Force Alarme', 'Format' => 'Format', 'Frame' => 'Image', - 'FrameId' => 'N∞ image', - 'FrameRate' => 'Cadence Image', + 'FrameId' => 'N° image', + 'FrameRate' => 'Débit image', 'FrameSkip' => 'Saut image', 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'images', 'Func' => 'Fct', - 'Function' => 'Mode', + 'Function' => 'Fonction', 'Gain' => 'Gain', - 'General' => 'GÈnÈral', - 'GenerateVideo' => 'GÈnÈrer VidÈo', - 'GeneratingVideo' => 'GÈnÈration VidÈo', + 'General' => 'General', + 'GenerateVideo' => 'Générer Vidéo', + 'GeneratingVideo' => 'Génération Vidéo', 'GoToZoneMinder' => 'Aller sur ZoneMinder.com', 'Grey' => 'Gris', - 'Group' => 'Groupe', - 'Groups' => 'Groupes', + 'Group' => 'Group', + 'Groups' => 'Groups', 'HasFocusSpeed' => 'Has Focus Speed', 'HasGainSpeed' => 'Has Gain Speed', 'HasHomePreset' => 'Has Home Preset', @@ -363,7 +363,7 @@ $SLANG = array( 'Home' => 'Home', 'Hour' => 'Heure', 'Hue' => 'Teinte', - 'Id' => 'N∞', + 'Id' => 'N°', 'Idle' => 'Vide', 'Ignore' => 'Ignorer', 'Image' => 'Image', @@ -371,35 +371,35 @@ $SLANG = array( 'Images' => 'Images', 'In' => 'In', 'Include' => 'Inclure', - 'Inverted' => 'InversÈ', + 'Inverted' => 'Inversé', 'Iris' => 'Iris', 'KeyString' => 'Key String', 'Label' => 'Label', 'Language' => 'Langue', 'Last' => 'Dernier', - 'Layout' => 'Disposition', // Added - 2009-02-08 - 'Level' => 'Niveau', // Added - 2011-06-16 + 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Level', // Added - 2011-06-16 'Libvlc' => 'Libvlc', - 'LimitResultsPost' => 'rÈsultats seulement;', // This is used at the end of the phrase 'Limit to first N results only' - 'LimitResultsPre' => 'Limite au premier', // This is used at the beginning of the phrase 'Limit to first N results only' - 'Line' => 'Ligne', // Added - 2011-06-16 - 'LinkedMonitors' => 'CamÈra(s) liÈ(s)', - 'List' => 'Liste', - 'Load' => 'CPU', + '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Ù', + 'LoggedInAs' => 'Connecté cô', 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Connexion', 'Login' => 'Login', - 'Logout' => 'DÈconnexion', + 'Logout' => 'Déconnexion', 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Bas', 'LowBW' => 'Basse N/B', - 'Main' => 'Principal', + 'Main' => 'Main', 'Man' => 'Man', - 'Manual' => 'Manuel', - 'Mark' => 'SÈlÈctionner', + 'Manual' => 'Manual', + 'Mark' => 'Marque', 'Max' => 'Max', 'MaxBandwidth' => 'Max Bandwidth', 'MaxBrScore' => 'Score
max', @@ -425,15 +425,15 @@ $SLANG = array( 'MaxZoomSpeed' => 'Max Zoom Speed', 'MaxZoomStep' => 'Max Zoom Step', 'MaximumFPS' => 'i/s maximum', - 'Medium' => 'Moyen', + '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', + 'MinBlobAreaLtMax' => 'Aire blob min. doit ê < aire blob maximum', 'MinBlobAreaUnset' => 'You must specify the minimum blob pixel count', 'MinBlobLtMinFilter' => 'Minimum blob area should be less than or equal to minimum filter area', - 'MinBlobsLtMax' => 'Blobs min. doit Í < blobs max.', + 'MinBlobsLtMax' => 'Blobs min. doit ê < blobs max.', 'MinBlobsUnset' => 'You must specify the minimum blob count', 'MinFilterAreaLtMax' => 'Minimum filter area should be less than maximum', 'MinFilterAreaUnset' => 'You must specify the minimum filter pixel count', @@ -450,7 +450,7 @@ $SLANG = array( 'MinPanRange' => 'Min Pan Range', 'MinPanSpeed' => 'Min Pan Speed', 'MinPanStep' => 'Min Pan Step', - 'MinPixelThresLtMax' => 'Seuil pixel min. doit Í < seuil pixel max.', + 'MinPixelThresLtMax' => 'Seuil pixel min. doit ê < seuil pixel max.', 'MinPixelThresUnset' => 'You must specify a minimum pixel threshold', 'MinTiltRange' => 'Min Tilt Range', 'MinTiltSpeed' => 'Min Tilt Speed', @@ -461,166 +461,166 @@ $SLANG = array( 'MinZoomRange' => 'Min Zoom Range', 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', - 'Misc' => 'Divers', - 'Monitor' => 'CamÈra', - 'MonitorIds' => 'N∞ camÈra', - 'MonitorPreset' => 'PrÈrÈglages camÈra', + 'Misc' => 'Div.', + 'Monitor' => 'Ecran', + 'MonitorIds' => 'N° écran', + 'MonitorPreset' => 'Monitor Preset', 'MonitorPresetIntro' => 'Select an appropriate preset from the list below.

Please note that this may overwrite any values you already have configured for this monitor.

', - 'MonitorProbe' => 'Scanner CamÈra', // Added - 2009-03-31 + 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 - 'Monitors' => 'CamÈras', + 'Monitors' => 'Ecrans', 'Montage' => 'Montage', 'Month' => 'Mois', - 'More' => 'Plus', // Added - 2011-06-16 - 'Move' => 'DÈplacer', + 'More' => 'More', // Added - 2011-06-16 + 'Move' => 'Move', 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. - 'MustBeGe' => 'doit Ítre sup. ou Ègal ‡', - 'MustBeLe' => 'doit Ítre inf. ou Ègal ‡', + 'MustBeGe' => 'doit être sup. ou égal à', + 'MustBeLe' => 'doit être inf. ou égal à', 'MustConfirmPassword' => 'Confirmez le mot de passe', 'MustSupplyPassword' => 'Entrez un mot de passe', 'MustSupplyUsername' => 'Entrez un nom d\'utilisateur', 'Name' => 'Nom', - 'Near' => 'PrËs', - 'Network' => 'RÈseau', + 'Near' => 'Near', + 'Network' => 'Réseau', 'New' => 'Nouv.', - 'NewGroup' => 'Nouv. Groupe', - 'NewLabel' => 'Nouv. Label', + 'NewGroup' => 'New Group', + 'NewLabel' => 'New Label', 'NewPassword' => 'Nouv. mt de passe', - 'NewState' => 'Nv Ètat', + 'NewState' => 'Nv état', 'NewUser' => 'Nv util.', - 'Next' => 'Suivant', + 'Next' => 'Suiv.', 'No' => 'Non', - 'NoDetectedCameras' => 'Pas de caméras dÈtectÈ', // Added - 2009-03-31 - 'NoFramesRecorded' => 'Pas d\'image enregistrÈe pour cet ÈvÈnement', - 'NoGroup' => 'Pas de groupe', + 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 + 'NoFramesRecorded' => 'Pas d\'image enregistrée pour cet évènement', + 'NoGroup' => 'No Group', 'NoSavedFilters' => 'Pasfiltressauv', - 'NoStatisticsRecorded' => 'Pas de statistiques disponibles pour cet ÈvÈnmnt/imag.', + 'NoStatisticsRecorded' => 'Pas de statistiques disponibles pour cet évènmnt/imag.', 'None' => 'Aucun', 'NoneAvailable' => 'Aucun disponible', 'Normal' => 'Normal', 'Notes' => 'Notes', - 'NumPresets' => 'Num PrÈrÈglages', + 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', - 'OpEq' => 'Ègal ‡', - 'OpGt' => 'sup. ‡', - 'OpGtEq' => 'plus grand ou Ègal ‡', + 'OpEq' => 'égal à', + 'OpGt' => 'sup. à', + 'OpGtEq' => 'plus grand ou égal à', 'OpIn' => 'en lot', - 'OpLt' => 'inf. ‡', - 'OpLtEq' => 'inf. ou Ègal ‡', + 'OpLt' => 'inf. à', + 'OpLtEq' => 'inf. ou égal à', 'OpMatches' => 'correspond', 'OpNe' => 'diff. de', 'OpNotIn' => 'pas en lot', 'OpNotMatches' => 'ne correspond pas', - 'Open' => 'Ouvrir', - 'OptionHelp' => 'Aide', + 'Open' => 'Open', + 'OptionHelp' => 'OptionAide', 'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.', 'Options' => 'Options', 'OrEnterNewName' => 'ou entrez nv nom', - 'Order' => 'Ordre', + 'Order' => 'Order', 'Orientation' => 'Orientation', 'Out' => 'Out', 'OverwriteExisting' => 'Ecraser l\'existant', - 'Paged' => 'PaginÈe', + 'Paged' => 'Paged', 'Pan' => 'Pan', 'PanLeft' => 'Pan Left', 'PanRight' => 'Pan Right', 'PanTilt' => 'Pan/Tilt', - 'Parameter' => 'ParamËtre', + 'Parameter' => 'Paramètre', 'Password' => 'Mt de passe', - 'PasswordsDifferent' => 'Les 2 mots de passe sont diffÈrents', - 'Paths' => 'Chemins', + 'PasswordsDifferent' => 'Les 2 mots de passe sont différents', + 'Paths' => 'Paths', 'Pause' => 'Pause', - 'Phone' => 'TÈlÈphone', + 'Phone' => 'Phone', 'PhoneBW' => 'Phone B/W', 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', - 'Play' => 'Lire', - 'PlayAll' => 'Tout lire', + 'Play' => 'Play', + 'PlayAll' => 'Play All', 'PleaseWait' => 'Attendez', 'Plugins' => 'Plugins', 'Point' => 'Point', - 'PostEventImageBuffer' => 'Nombre dimage(s) post-ÈvÈnement', - 'PreEventImageBuffer' => 'Nombre dimage(s) prÈ-ÈvÈnement', - 'PreserveAspect' => 'Conserver les proportions', - 'Preset' => 'PrÈrÈglage', - 'Presets' => 'PrÈrÈglages', - 'Prev' => 'PrecÈdent', - 'Probe' => 'Scanner', // Added - 2009-03-31 - 'Protocol' => 'Protocole', - 'Rate' => 'Vitesse', - 'Real' => 'RÈel', - 'Record' => 'Enregistrer', + 'PostEventImageBuffer' => 'Post Event Image Count', + 'PreEventImageBuffer' => 'Pre Event Image Count', + 'PreserveAspect' => 'Preserve Aspect Ratio', + 'Preset' => 'Preset', + 'Presets' => 'Presets', + 'Prev' => 'Prec.', + 'Probe' => 'Probe', // Added - 2009-03-31 + 'Protocol' => 'Protocol', + 'Rate' => 'Débit', + 'Real' => 'Réel', + 'Record' => 'Enreg.', 'RefImageBlendPct' => 'Reference Image Blend %ge', - 'Refresh' => 'RafraÓchir', - 'Remote' => 'Distant', - 'RemoteHostName' => 'IP/DNS', - 'RemoteHostPath' => 'Chemin', - 'RemoteHostPort' => 'Port', - 'RemoteHostSubPath' => 'Sous-chemin', // Added - 2009-02-08 - 'RemoteImageColours' => 'Nombre de couleurs', - 'RemoteMethod' => 'MÈthode', // Added - 2009-02-08 - 'RemoteProtocol' => 'Protocole', // Added - 2009-02-08 + 'Refresh' => 'Rafraîchir', + 'Remote' => 'Remote', + 'RemoteHostName' => 'Remote Host Name', + 'RemoteHostPath' => 'Remote Host Path', + 'RemoteHostPort' => 'Remote Host Port', + 'RemoteHostSubPath' => 'Remote Host SubPath', // Added - 2009-02-08 + 'RemoteImageColours' => 'Remote Image Colours', + 'RemoteMethod' => 'Remote Method', // Added - 2009-02-08 + 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 'Rename' => 'Renommer', - 'Replay' => 'Relire', - 'ReplayAll' => 'Tous les ÈvÈnements', - 'ReplayGapless' => 'EvÈnement Gapless', - 'ReplaySingle' => 'EvÈnement unique', - 'Reset' => 'RAZ', - 'ResetEventCounts' => 'Rem. ‡ 0 comptage des Èvts', - 'Restart' => 'RedÈmarrer', - 'Restarting' => 'RedÈmarrage', - 'RestrictedCameraIds' => 'N∞ camÈras confid.', + 'Replay' => 'Replay', + 'ReplayAll' => 'All Events', + 'ReplayGapless' => 'Gapless Events', + 'ReplaySingle' => 'Single Event', + 'Reset' => 'Reset', + 'ResetEventCounts' => 'Rem. à 0 comptage des évts', + 'Restart' => 'Redémarrer', + 'Restarting' => 'Redémarrage', + 'RestrictedCameraIds' => 'N° caméras confid.', 'RestrictedMonitors' => 'Restricted Monitors', 'ReturnDelay' => 'Return Delay', 'ReturnLocation' => 'Return Location', - 'Rewind' => 'Rembobiner', + 'Rewind' => 'Rewind', 'RotateLeft' => 'Rotation g.', 'RotateRight' => 'Rotation d.', 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 - 'RunMode' => 'Mode de lancement', - 'RunState' => 'Changer Ètat', - 'Running' => 'En Fonctionnement', - 'Save' => 'OK', - 'SaveAs' => 'Sauvegarder sous', - 'SaveFilter' => 'Sauvegarder Filtre', + 'RunMode' => 'Run Mode', + 'RunState' => 'Run State', + 'Running' => 'Ca tourne', + 'Save' => 'Enr.', + 'SaveAs' => 'Enr. ss', + 'SaveFilter' => 'Save Filter', 'Scale' => 'Echelle', 'Score' => 'Score', 'Secs' => 'Secs', 'Sectionlength' => 'Longueur section', - 'Select' => 'SÈlectionner', - 'SelectFormat' => 'SÈlectionner Format', // Added - 2011-06-17 - 'SelectLog' => 'SÈlectionner Log', // Added - 2011-06-17 - 'SelectMonitors' => 'SÈlectionner camÈras', + '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' => 'DÉfinir', - 'SetNewBandwidth' => 'RÈgler le dÈbit', - 'SetPreset' => 'DÈfinir PrÈrÈglages', - 'Settings' => 'RÈglages', - 'ShowFilterWindow' => 'Filtres', - 'ShowTimeline' => 'Afficher Chronologie', + 'Set' => 'Set', + 'SetNewBandwidth' => 'Régler la bande passante', + 'SetPreset' => 'Set Preset', + 'Settings' => 'Réglages', + 'ShowFilterWindow' => 'Montrerfen.filtre', + 'ShowTimeline' => 'Show Timeline', 'SignalCheckColour' => 'Signal Check Colour', - 'Size' => 'Taille', + 'Size' => 'Size', 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 - 'Sleep' => 'Veille', + 'Sleep' => 'Sleep', 'SortAsc' => 'Asc', - 'SortBy' => 'Trier par', + 'SortBy' => 'Sort by', 'SortDesc' => 'Desc', 'Source' => 'Source', - 'SourceColours' => 'Couleurs', // Added - 2009-02-08 - 'SourcePath' => 'Chemin', // Added - 2009-02-08 - 'SourceType' => 'Type de Source', - 'Speed' => 'Vitesse', - 'SpeedHigh' => 'Rapide', - 'SpeedLow' => 'Lent', - 'SpeedMedium' => 'Moyen', - 'SpeedTurbo' => 'Turbo', - 'Start' => 'DÈmarrer', + 'SourceColours' => 'Source Colours', // Added - 2009-02-08 + 'SourcePath' => 'Source Path', // Added - 2009-02-08 + 'SourceType' => 'Source Type', + 'Speed' => 'Speed', + 'SpeedHigh' => 'High Speed', + 'SpeedLow' => 'Low Speed', + 'SpeedMedium' => 'Medium Speed', + 'SpeedTurbo' => 'Turbo Speed', + 'Start' => 'Démarrer', 'State' => 'Etat', 'Stats' => 'Stats', 'Status' => 'Statut', @@ -632,54 +632,54 @@ $SLANG = array( 'StepNone' => 'No Step', 'StepSmall' => 'Small Step', 'Stills' => 'Photos', - 'Stop' => 'ArrÍter', - 'Stopped' => 'ArrÍtÈ', + 'Stop' => 'Stop', + 'Stopped' => 'Arrêté', 'Stream' => 'Flux', 'StreamReplayBuffer' => 'Stream Replay Image Buffer', - 'Submit' => 'Soumettre', - 'System' => 'SystËme', + 'Submit' => 'Submit', + 'System' => 'Système', 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', - 'Thumbnail' => 'Miniature', + 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', - 'Time' => 'Heure', + 'Time' => 'Temps', 'TimeDelta' => 'Time Delta', - 'TimeStamp' => 'Horodatage', - 'Timeline' => 'Chronologie', + 'TimeStamp' => 'Time Stamp', + 'Timeline' => 'Timeline', 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. - 'Timestamp' => 'Horodatage', - 'TimestampLabelFormat' => 'Format Horodatage', - 'TimestampLabelX' => 'Label Horodatage X', - 'TimestampLabelY' => 'Label Horodatage Y', - 'Today' => 'Aujourd'hui', + 'Timestamp' => 'Timestamp', + 'TimestampLabelFormat' => 'Timestamp Label Format', + 'TimestampLabelX' => 'Timestamp Label X', + 'TimestampLabelY' => 'Timestamp Label Y', + 'Today' => 'Today', 'Tools' => 'Outils', 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Score
total', 'TrackDelay' => 'Track Delay', 'TrackMotion' => 'Track Motion', - 'Triggers' => 'DÈclenchements', + 'Triggers' => 'Déclenchements', 'TurboPanSpeed' => 'Turbo Pan Speed', 'TurboTiltSpeed' => 'Turbo Tilt Speed', 'Type' => 'Type', - 'Unarchive' => 'DÈsarchiver', - 'Undefined' => 'indÈfini', // Added - 2009-02-08 - 'Units' => 'UnitÈs', + 'Unarchive' => 'Désarchiv.', + 'Undefined' => 'Undefined', // Added - 2009-02-08 + 'Units' => 'Unités', 'Unknown' => 'Inconnu', - 'Update' => 'Actualiser', - 'UpdateAvailable' => 'Mise ‡ jour de ZM disponible', - 'UpdateNotNecessary' => 'Pas de mise ‡ jour disponible', - 'Updated' => 'ActualisÈ', // Added - 2011-06-16 - 'Upload' => 'TransfÈrer', // Added - 2011-08-23 + 'Update' => 'Update', + 'UpdateAvailable' => 'Mise à jour de ZM dispo.', + 'UpdateNotNecessary' => 'Pas de mise à jour dispo.', + 'Updated' => 'Updated', // Added - 2011-06-16 + 'Upload' => 'Upload', // Added - 2011-08-23 'UsedPlugins' => 'Used Plugins', - 'UseFilter' => 'Utiliser Filtre', + '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' - 'User' => 'Utilisateur', - 'Username' => 'Login', - 'Users' => 'Utilisateurs', + 'User' => 'Util.', + 'Username' => 'nom util.', + 'Users' => 'Utils', 'Value' => 'Valeur', 'Version' => 'Version', 'VersionIgnore' => 'Ignorer cette version', @@ -687,19 +687,19 @@ $SLANG = array( 'VersionRemindHour' => 'Me rappleler dans 1 h.', 'VersionRemindNever' => 'Ne pas avertir des nvelles versions', 'VersionRemindWeek' => 'Me rappeler ds 1 sem.', - 'Video' => 'VidÈo', - 'VideoFormat' => 'Format de la VidÈo', - 'VideoGenFailed' => 'Echec gÈnÈration vidÈo!', + 'Video' => 'Vidéo', + 'VideoFormat' => 'Video Format', + 'VideoGenFailed' => 'Echec génération vidéo!', 'VideoGenFiles' => 'Existing Video Files', - 'VideoGenNoFiles' => 'Aucun fichier vidéo trouvé', - 'VideoGenParms' => 'ParamËtres gÈnÈration vidÈo', - 'VideoGenSucceeded' => 'VidÈo gÈnÈrÈe avec succËs!', - 'VideoSize' => 'taille vidÈo', + 'VideoGenNoFiles' => 'No Video Files Found', + 'VideoGenParms' => 'Paramètres génération vidéo', + 'VideoGenSucceeded' => 'Video Generation Succeeded!', + 'VideoSize' => 'taille vidéo', 'View' => 'Voir', - 'ViewAll' => 'Tout voir', - 'ViewEvent' => 'Voir ÈvÈnement', - 'ViewPaged' => 'Vue paginÈe', - 'Wake' => 'RÈveiller', + 'ViewAll' => 'Voir tt', + 'ViewEvent' => 'View Event', + 'ViewPaged' => 'Vue recherchée', + 'Wake' => 'Wake', 'WarmupFrames' => 'Images test', 'Watch' => 'Regarder', 'Web' => 'Web', @@ -707,15 +707,15 @@ $SLANG = array( 'Week' => 'Semaine', 'White' => 'White', 'WhiteBalance' => 'White Balance', - 'Wide' => 'Large', + 'Wide' => 'Wide', 'X' => 'X', 'X10' => 'X10', - 'X10ActivationString' => 'X10:chaÓne activation', - 'X10InputAlarmString' => 'X10:chaÓne alarme entrÈe', - 'X10OutputAlarmString' => 'X10:chaÓne alarme sortie', + 'X10ActivationString' => 'X10:chaîne activation', + 'X10InputAlarmString' => 'X10:chaîne alarme entrée', + 'X10OutputAlarmString' => 'X10:chaîne alarme sortie', 'Y' => 'Y', 'Yes' => 'Oui', - 'YouNoPerms' => 'Permissions nÈcessaires pour cette ressource.', + 'YouNoPerms' => 'Permissions nécessaires pour cette ressource.', 'Zone' => 'Zone', 'ZoneAlarmColour' => 'Couleur alarme (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', @@ -730,19 +730,19 @@ $SLANG = array( 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zones', 'Zoom' => 'Zoom', - 'ZoomIn' => 'Zoom avant', - 'ZoomOut' => 'Zoom arriËre', + 'ZoomIn' => 'Zoom In', + 'ZoomOut' => 'Zoom Out', ); // Complex replacements with formatting and/or placements, must be passed through sprintf $CLANG = array( 'CurrentLogin' => 'Util. Actuel: \'%1$s\'', - 'EventCount' => '%1$s %2$s', // par ex. '37 ÈvËnts' (voir Vlang ci-dessous) - 'LastEvents' => '%1$s derniers %2$s', // par ex. '37 derniers ÈvËnts' (voir Vlang ci-dessous) - 'LatestRelease' => 'La derniËre version est v%1$s, vous avez v%2$s.', - 'MonitorCount' => '%1$s %2$s', // par exemple '4 camÈras' (voir Vlang ci-dessous) - 'MonitorFunction' => 'CamÈra %1$s Fonction', - 'RunningRecentVer' => 'Vs avez la derniËre version de ZoneMinder, v%s.', + 'EventCount' => '%1$s %2$s', // par ex. '37 évènts' (voir Vlang ci-dessous) + 'LastEvents' => '%1$s derniers %2$s', // par ex. '37 derniers évènts' (voir Vlang ci-dessous) + 'LatestRelease' => 'La dernière version est v%1$s, vous avez v%2$s.', + 'MonitorCount' => '%1$s %2$s', // par exemple '4 écrans' (voir Vlang ci-dessous) + 'MonitorFunction' => 'Ecran %1$s Fonction', + 'RunningRecentVer' => 'Vs avez la dernière version de ZoneMinder, v%s.', 'VersionMismatch' => 'Version mismatch, system is version %1$s, database is %2$s.', // Added - 2011-05-25 ); @@ -780,8 +780,8 @@ $CLANG = array( // Variable arrays expressing plurality, see the zmVlang description above $VLANG = array( - 'Event' => array( 0=>'ÈvÈnements', 1=>'ÈvÈnement', 2=>'ÈvÈnements' ), - 'Monitor' => array( 0=>'camÈras', 1=>'camÈra', 2=>'camÈras' ), + 'Event' => array( 0=>'évènts', 1=>'évènt', 2=>'évènts' ), + 'Monitor' => array( 0=>'écrans', 1=>'écran', 2=>'écrans' ), ); // You will need to choose or write a function that can correlate the plurality string arrays From c0b41ed6a8cfbde48b0f4b37e3d1a76fd5d46bb7 Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Mon, 30 Mar 2015 20:50:42 +0200 Subject: [PATCH 016/154] Readd translations from Jypy --- web/lang/fr_fr.php | 430 ++++++++++++++++++++++----------------------- 1 file changed, 215 insertions(+), 215 deletions(-) diff --git a/web/lang/fr_fr.php b/web/lang/fr_fr.php index def9d1575..5a3f34518 100644 --- a/web/lang/fr_fr.php +++ b/web/lang/fr_fr.php @@ -76,16 +76,16 @@ $SLANG = array( '8BitGrey' => 'Gris 8 bit', 'Action' => 'Action', 'Actual' => 'Réel', - 'AddNewControl' => 'Add New Control', - 'AddNewMonitor' => 'Aj. nouv. écran', - 'AddNewUser' => 'Aj. nouv. util.', - 'AddNewZone' => 'Aj. nouv. zone', + 'AddNewControl' => 'Ajouter contrôle', + 'AddNewMonitor' => 'Ajouter caméra', + 'AddNewUser' => 'Ajouter utilisateur', + 'AddNewZone' => 'Ajouter zone', 'Alarm' => 'Alarme', 'AlarmBrFrames' => 'Images
alarme', 'AlarmFrame' => 'Image alarme', - 'AlarmFrameCount' => 'Alarm Frame Count', + 'AlarmFrameCount' => 'Nombre d\'images en alarme', 'AlarmLimits' => 'Limites alarme', - 'AlarmMaximumFPS' => 'Alarm Maximum FPS', + 'AlarmMaximumFPS' => 'IPS max. pendant alarme', 'AlarmPx' => 'Px Alarme', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', 'Alert' => 'Alerte', @@ -103,27 +103,27 @@ $SLANG = array( 'AttrAvgScore' => 'Score moy.', 'AttrCause' => 'Cause', 'AttrDate' => 'Date', - 'AttrDateTime' => 'Date/temps', + 'AttrDateTime' => 'Date/heure', 'AttrDiskBlocks' => 'Disk Blocks', 'AttrDiskPercent' => 'Disk Percent', 'AttrDuration' => 'Durée', 'AttrFrames' => 'Images', 'AttrId' => 'Id', 'AttrMaxScore' => 'Score max.', - 'AttrMonitorId' => 'N° écran', - 'AttrMonitorName' => 'Nom écran', - 'AttrName' => 'Name', + 'AttrMonitorId' => 'N° caméra', + 'AttrMonitorName' => 'Nom caméra', + 'AttrName' => 'Nom', 'AttrNotes' => 'Notes', - 'AttrSystemLoad' => 'System Load', - 'AttrTime' => 'Temps', + 'AttrSystemLoad' => 'Charge système', + 'AttrTime' => 'Heure', 'AttrTotalScore' => 'Score total', 'AttrWeekday' => 'Semaine', 'Auto' => 'Auto', 'AutoStopTimeout' => 'Auto Stop Timeout', - 'Available' => 'Available', // Added - 2009-03-31 + 'Available' => 'Disponible', // Added - 2009-03-31 'AvgBrScore' => 'Score
moy.', - 'Background' => 'Background', - 'BackgroundFilter' => 'Run filter in background', + 'Background' => 'Arrère-plan', + 'BackgroundFilter' => 'Lancer les filtres en arrière-plan', 'BadAlarmFrameCount' => 'Alarm frame count must be an integer of one or more', 'BadAlarmMaxFPS' => 'Alarm Maximum FPS must be a positive integer or floating point value', 'BadChannel' => 'Channel must be set to an integer of zero or more', @@ -152,8 +152,8 @@ $SLANG = array( 'BadWarmupCount' => 'Warmup frames must be an integer of zero or more', 'BadWebColour' => 'Web colour must be a valid web colour string', 'BadWidth' => 'Width must be set to a valid value', - 'Bandwidth' => 'Bande-pass.', - 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'Bandwidth' => 'Débit', + 'BandwidthHead' => 'Débit', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing 'BlobPx' => 'Px forme', 'BlobSizes' => 'Taille forme', 'Blobs' => 'Formes', @@ -197,33 +197,33 @@ $SLANG = array( 'CanZoomAbs' => 'Can Zoom Absolute', 'CanZoomCon' => 'Can Zoom Continuous', 'CanZoomRel' => 'Can Zoom Relative', - 'Cancel' => 'Annul.', - 'CancelForcedAlarm' => 'Annul. Forcé Alarme', - 'CaptureHeight' => 'Haut. capture', - 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 - 'CapturePalette' => 'palette capture', - 'CaptureWidth' => 'Larg. capture', + 'Cancel' => 'Annuler', + 'CancelForcedAlarm' => 'Annuler alarme forcée', + 'CaptureHeight' => 'Hauteur', + 'CaptureMethod' => 'Méthode', // Added - 2009-02-08 + 'CapturePalette' => 'Palette', + 'CaptureWidth' => 'Largeur', 'Cause' => 'Cause', '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 + 'ChoosePreset' => 'Choisir préréglage', + 'Clear' => 'Effacer', // Added - 2011-06-16 'Close' => 'Fermer', 'Colour' => 'Couleur', - 'Command' => 'Command', + 'Command' => 'Commande', 'Component' => 'Component', // Added - 2011-06-16 'Config' => 'Config', 'ConfiguredFor' => 'Configuré pour', 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', - 'ConfirmPassword' => 'Confirmer mt de pass.', + 'ConfirmPassword' => 'Confirmer mot de passe', 'ConjAnd' => 'et', 'ConjOr' => 'ou', 'Console' => 'Console', 'ContactAdmin' => 'Contactez votre administrateur SVP', - 'Continue' => 'Continue', + 'Continue' => 'Continuer', 'Contrast' => 'Contraste', 'Control' => 'Control', 'ControlAddress' => 'Control Address', @@ -235,27 +235,27 @@ $SLANG = array( 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle vision', 'DateTime' => 'Date/Time', // Added - 2011-06-16 - 'Day' => 'Jour', + 'Day' => 'Aujourd\'hui', 'Debug' => 'Debug', - 'DefaultRate' => 'Default Rate', - 'DefaultScale' => 'Default Scale', - 'DefaultView' => 'Default View', - 'Delete' => 'Eff.', + 'DefaultRate' => 'Vitess par défaut', + 'DefaultScale' => 'Echelle par défaut', + 'DefaultView' => 'Vue par défaut', + 'Delete' => 'Effacer', 'DeleteAndNext' => 'Eff. & suiv.', 'DeleteAndPrev' => 'Eff. & prec.', 'DeleteSavedFilter' => 'Eff. filtre sauvé', 'Description' => 'Description', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'Device' => 'Device', // Added - 2009-02-08 + 'Device' => 'Caméra', // Added - 2009-02-08 'DeviceChannel' => 'Canal caméra', 'DeviceFormat' => 'Format caméra', 'DeviceNumber' => 'Numéro caméra', - 'DevicePath' => 'Device Path', - 'Devices' => 'Devices', + 'DevicePath' => 'Chemin', + 'Devices' => 'Caméras', 'Dimensions' => 'Dimensions', - 'DisableAlarms' => 'Disable Alarms', - 'Disk' => 'Disk', - 'Display' => 'Display', // Added - 2011-01-30 + 'DisableAlarms' => 'Désactiver les alarmes', + 'Disk' => 'Stockage', + 'Display' => 'Affichage', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', @@ -267,58 +267,58 @@ $SLANG = array( 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', 'DoNativeMotionDetection'=> 'Do Native Motion Detection', - 'Download' => 'Download', + 'Download' => 'Télécharger', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Durée', 'Edit' => 'Editer', - 'Email' => 'Courriel', - 'EnableAlarms' => 'Enable Alarms', + 'Email' => 'Email', + 'EnableAlarms' => 'Activer les alarmes', 'Enabled' => 'Activé', 'EnterNewFilterName' => 'Entrer nom nouv. filtre', 'Error' => 'Erreur', 'ErrorBrackets' => 'Erreur, vérifiez que toutes les parenthèses ouvertes sont fermées', 'ErrorValidValue' => 'Erreur, vérifiez que tous les termes ont une valeur valide', 'Etc' => 'etc', - 'Event' => 'Evènt', - 'EventFilter' => 'Filtre evènt', - 'EventId' => 'Event Id', - 'EventName' => 'Event Name', - 'EventPrefix' => 'Event Prefix', - 'Events' => 'Evènts', + 'Event' => 'Evénement', + 'EventFilter' => 'Filtre événement', + 'EventId' => 'Id', + 'EventName' => 'Nom', + 'EventPrefix' => 'Préfixe', + 'Events' => 'Evénements', 'Exclude' => 'Exclure', - 'Execute' => 'Execute', - 'Export' => 'Export', - 'ExportDetails' => 'Export Event Details', - 'ExportFailed' => 'Export Failed', - 'ExportFormat' => 'Export File Format', + 'Execute' => 'Executer', + 'Export' => 'Exporter', + 'ExportDetails' => 'Exporter détails événements', + 'ExportFailed' => 'Exportation échouée', + 'ExportFormat' => 'Format', 'ExportFormatTar' => 'Tar', 'ExportFormatZip' => 'Zip', - 'ExportFrames' => 'Export Frame Details', - 'ExportImageFiles' => 'Export Image Files', - 'ExportLog' => 'Export Log', // Added - 2011-06-17 - 'ExportMiscFiles' => 'Export Other Files (if present)', + 'ExportFrames' => 'Exporter détails image', + 'ExportImageFiles' => 'Exporter fichiers images', + 'ExportLog' => 'Exporter fichiers journaux', // Added - 2011-06-17 + 'ExportMiscFiles' => 'Exporter autres fichiers', 'ExportOptions' => 'Export Options', 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 'ExportVideoFiles' => 'Export Video Files (if present)', - 'Exporting' => 'Exporting', - 'FPS' => 'i/s', + 'Exporting' => 'Exportation', + 'FPS' => 'IPS', 'FPSReportInterval' => 'FPS Report Interval', 'FTP' => 'FTP', - 'Far' => 'Far', - 'FastForward' => 'Fast Forward', - 'Feed' => 'Feed', + 'Far' => 'Loin', + 'FastForward' => 'Avance rapide', + 'Feed' => 'Flux', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 - 'File' => 'File', - 'FilterArchiveEvents' => 'Archive all matches', - 'FilterDeleteEvents' => 'Delete all matches', - 'FilterEmailEvents' => 'Email details of all matches', - 'FilterExecuteEvents' => 'Execute command on all matches', - 'FilterMessageEvents' => 'Message details of all matches', + 'File' => 'Fichier', + 'FilterArchiveEvents' => 'Archiver', + 'FilterDeleteEvents' => 'Effacer', + 'FilterEmailEvents' => 'Envoyer les détails par email', + 'FilterExecuteEvents' => 'Executer une commande', + 'FilterMessageEvents' => 'Envoyer les détails par message', 'FilterPx' => 'Filter Px', 'FilterUnset' => 'You must specify a filter width and height', - 'FilterUploadEvents' => 'Upload all matches', - 'FilterVideoEvents' => 'Create video for all matches', - 'Filters' => 'Filters', + 'FilterUploadEvents' => 'Transférer', + 'FilterVideoEvents' => 'Créer vidéo', + 'Filters' => 'Filtres', 'First' => 'Prem.', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', @@ -333,20 +333,20 @@ $SLANG = array( 'Format' => 'Format', 'Frame' => 'Image', 'FrameId' => 'N° image', - 'FrameRate' => 'Débit image', + 'FrameRate' => 'Cadence image', 'FrameSkip' => 'Saut image', 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'images', 'Func' => 'Fct', - 'Function' => 'Fonction', + 'Function' => 'Mode', 'Gain' => 'Gain', - 'General' => 'General', - 'GenerateVideo' => 'Générer Vidéo', - 'GeneratingVideo' => 'Génération Vidéo', + 'General' => 'Général', + 'GenerateVideo' => 'Générer vidéo', + 'GeneratingVideo' => 'Génération vidéo', 'GoToZoneMinder' => 'Aller sur ZoneMinder.com', 'Grey' => 'Gris', - 'Group' => 'Group', - 'Groups' => 'Groups', + 'Group' => 'Groupe', + 'Groups' => 'Groupes', 'HasFocusSpeed' => 'Has Focus Speed', 'HasGainSpeed' => 'Has Gain Speed', 'HasHomePreset' => 'Has Home Preset', @@ -361,7 +361,7 @@ $SLANG = array( 'High' => 'Haut', 'HighBW' => 'Haut N/B', 'Home' => 'Home', - 'Hour' => 'Heure', + 'Hour' => 'Dans l\'heure', 'Hue' => 'Teinte', 'Id' => 'N°', 'Idle' => 'Vide', @@ -377,18 +377,18 @@ $SLANG = array( 'Label' => 'Label', 'Language' => 'Langue', 'Last' => 'Dernier', - 'Layout' => 'Layout', // Added - 2009-02-08 - 'Level' => 'Level', // Added - 2011-06-16 + 'Layout' => 'Disposition', // Added - 2009-02-08 + 'Level' => 'Niveau', // Added - 2011-06-16 'Libvlc' => 'Libvlc', - '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', + 'LimitResultsPost' => 'résultat(s) seulement;', // This is used at the end of the phrase 'Limit to first N results only' + 'LimitResultsPre' => 'Limiter au(x) premier(s)', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Ligne', // Added - 2011-06-16 + 'LinkedMonitors' => 'Caméra(s) liée(s)', + 'List' => 'Liste', + 'Load' => 'Charge', 'Local' => 'Local', 'Log' => 'Log', // Added - 2011-06-16 - 'LoggedInAs' => 'Connecté cô', + 'LoggedInAs' => 'Connecté en tant que', 'Logging' => 'Logging', // Added - 2011-06-16 'LoggingIn' => 'Connexion', 'Login' => 'Login', @@ -396,10 +396,10 @@ $SLANG = array( 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'Bas', 'LowBW' => 'Basse N/B', - 'Main' => 'Main', + 'Main' => 'Principal', 'Man' => 'Man', - 'Manual' => 'Manual', - 'Mark' => 'Marque', + 'Manual' => 'Manuel', + 'Mark' => 'Sélectionner', 'Max' => 'Max', 'MaxBandwidth' => 'Max Bandwidth', 'MaxBrScore' => 'Score
max', @@ -424,8 +424,8 @@ $SLANG = array( 'MaxZoomRange' => 'Max Zoom Range', 'MaxZoomSpeed' => 'Max Zoom Speed', 'MaxZoomStep' => 'Max Zoom Step', - 'MaximumFPS' => 'i/s maximum', - 'Medium' => 'Medium', + 'MaximumFPS' => 'IPS maximum', + 'Medium' => 'Moyen', 'MediumBW' => 'Moy. N/B', 'Message' => 'Message', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', @@ -461,18 +461,18 @@ $SLANG = array( 'MinZoomRange' => 'Min Zoom Range', 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', - 'Misc' => 'Div.', - 'Monitor' => 'Ecran', - 'MonitorIds' => 'N° écran', - 'MonitorPreset' => 'Monitor Preset', + 'Misc' => 'Divers', + 'Monitor' => 'Caméra', + 'MonitorIds' => 'N° caméra', + 'MonitorPreset' => 'Préréglage caméra', 'MonitorPresetIntro' => 'Select an appropriate preset from the list below.

Please note that this may overwrite any values you already have configured for this monitor.

', - 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 + 'MonitorProbe' => 'Scanner caméra', // Added - 2009-03-31 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 - 'Monitors' => 'Ecrans', + 'Monitors' => 'Caméras', 'Montage' => 'Montage', 'Month' => 'Mois', - 'More' => 'More', // Added - 2011-06-16 - 'Move' => 'Move', + 'More' => 'Plus', // Added - 2011-06-16 + 'Move' => 'Déplacer', 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. @@ -484,26 +484,26 @@ $SLANG = array( 'MustSupplyPassword' => 'Entrez un mot de passe', 'MustSupplyUsername' => 'Entrez un nom d\'utilisateur', 'Name' => 'Nom', - 'Near' => 'Near', + 'Near' => 'Près', 'Network' => 'Réseau', 'New' => 'Nouv.', - 'NewGroup' => 'New Group', - 'NewLabel' => 'New Label', - 'NewPassword' => 'Nouv. mt de passe', + 'NewGroup' => 'Nouv. groupe', + 'NewLabel' => 'Nouv. label', + 'NewPassword' => 'Nouv. mot de passe', 'NewState' => 'Nv état', 'NewUser' => 'Nv util.', - 'Next' => 'Suiv.', + 'Next' => 'Suivant', 'No' => 'Non', - 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 - 'NoFramesRecorded' => 'Pas d\'image enregistrée pour cet évènement', - 'NoGroup' => 'No Group', - 'NoSavedFilters' => 'Pasfiltressauv', - 'NoStatisticsRecorded' => 'Pas de statistiques disponibles pour cet évènmnt/imag.', + 'NoDetectedCameras' => 'Pas de caméras détectées', // Added - 2009-03-31 + 'NoFramesRecorded' => 'Pas d\'images enregistrées pour cet événement', + 'NoGroup' => 'Pas de groupe', + 'NoSavedFilters' => 'Pas de filtres sauvegardés', + 'NoStatisticsRecorded' => 'Pas de statistiques disponibles pour cet événmnt/imag.', 'None' => 'Aucun', 'NoneAvailable' => 'Aucun disponible', 'Normal' => 'Normal', 'Notes' => 'Notes', - 'NumPresets' => 'Num Presets', + 'NumPresets' => 'Num. préréglage', 'Off' => 'Off', 'On' => 'On', 'OpEq' => 'égal à', @@ -516,16 +516,16 @@ $SLANG = array( 'OpNe' => 'diff. de', 'OpNotIn' => 'pas en lot', 'OpNotMatches' => 'ne correspond pas', - 'Open' => 'Open', - 'OptionHelp' => 'OptionAide', + 'Open' => 'Ouvrir', + 'OptionHelp' => 'Aide', 'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.', 'Options' => 'Options', 'OrEnterNewName' => 'ou entrez nv nom', - 'Order' => 'Order', + 'Order' => 'Ordre', 'Orientation' => 'Orientation', 'Out' => 'Out', 'OverwriteExisting' => 'Ecraser l\'existant', - 'Paged' => 'Paged', + 'Paged' => 'Paginée', 'Pan' => 'Pan', 'PanLeft' => 'Pan Left', 'PanRight' => 'Pan Right', @@ -533,93 +533,93 @@ $SLANG = array( 'Parameter' => 'Paramètre', 'Password' => 'Mt de passe', 'PasswordsDifferent' => 'Les 2 mots de passe sont différents', - 'Paths' => 'Paths', + 'Paths' => 'Chemins', 'Pause' => 'Pause', - 'Phone' => 'Phone', + 'Phone' => 'Téléphone', 'PhoneBW' => 'Phone B/W', 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel Diff', 'Pixels' => 'pixels', - 'Play' => 'Play', - 'PlayAll' => 'Play All', + 'Play' => 'Lire', + 'PlayAll' => 'Tout lire', 'PleaseWait' => 'Attendez', 'Plugins' => 'Plugins', 'Point' => 'Point', - 'PostEventImageBuffer' => 'Post Event Image Count', - 'PreEventImageBuffer' => 'Pre Event Image Count', - 'PreserveAspect' => 'Preserve Aspect Ratio', - 'Preset' => 'Preset', - 'Presets' => 'Presets', - 'Prev' => 'Prec.', - 'Probe' => 'Probe', // Added - 2009-03-31 - 'Protocol' => 'Protocol', - 'Rate' => 'Débit', + 'PostEventImageBuffer' => 'Nombre d\'image(s) post-événement', + 'PreEventImageBuffer' => 'Nombre d\'image(s) pré-événement', + 'PreserveAspect' => 'Préserver les proportions', + 'Preset' => 'Préréglage', + 'Presets' => 'Préréglages', + 'Prev' => 'Précédent', + 'Probe' => 'Scanner', // Added - 2009-03-31 + 'Protocol' => 'Protocole', + 'Rate' => 'Vitesse', 'Real' => 'Réel', - 'Record' => 'Enreg.', + 'Record' => 'Enregistrer', 'RefImageBlendPct' => 'Reference Image Blend %ge', 'Refresh' => 'Rafraîchir', - 'Remote' => 'Remote', - 'RemoteHostName' => 'Remote Host Name', - 'RemoteHostPath' => 'Remote Host Path', - 'RemoteHostPort' => 'Remote Host Port', - 'RemoteHostSubPath' => 'Remote Host SubPath', // Added - 2009-02-08 - 'RemoteImageColours' => 'Remote Image Colours', - 'RemoteMethod' => 'Remote Method', // Added - 2009-02-08 - 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 + 'Remote' => 'Distant', + 'RemoteHostName' => 'Nom d\'hôte', + 'RemoteHostPath' => 'Chemin', + 'RemoteHostPort' => 'Port', + 'RemoteHostSubPath' => 'Sous-chemin', // Added - 2009-02-08 + 'RemoteImageColours' => 'Nombre de couleurs', + 'RemoteMethod' => 'Méthode', // Added - 2009-02-08 + 'RemoteProtocol' => 'Protocole', // Added - 2009-02-08 'Rename' => 'Renommer', - 'Replay' => 'Replay', - 'ReplayAll' => 'All Events', - 'ReplayGapless' => 'Gapless Events', - 'ReplaySingle' => 'Single Event', - 'Reset' => 'Reset', - 'ResetEventCounts' => 'Rem. à 0 comptage des évts', + 'Replay' => 'Relire', + 'ReplayAll' => 'Tous les événements', + 'ReplayGapless' => 'Rejouer sans blancs', + 'ReplaySingle' => 'Rejouer seul', + 'Reset' => 'Réinitialiser', + 'ResetEventCounts' => 'Réinitialiser compteur évts', 'Restart' => 'Redémarrer', 'Restarting' => 'Redémarrage', 'RestrictedCameraIds' => 'N° caméras confid.', 'RestrictedMonitors' => 'Restricted Monitors', 'ReturnDelay' => 'Return Delay', 'ReturnLocation' => 'Return Location', - 'Rewind' => 'Rewind', + 'Rewind' => 'Reculer', 'RotateLeft' => 'Rotation g.', 'RotateRight' => 'Rotation d.', 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 - 'RunMode' => 'Run Mode', - 'RunState' => 'Run State', - 'Running' => 'Ca tourne', - 'Save' => 'Enr.', - 'SaveAs' => 'Enr. ss', - 'SaveFilter' => 'Save Filter', + 'RunMode' => 'Mode de lancement', + 'RunState' => 'Changer d\état', + 'Running' => 'En marche', + 'Save' => 'Sauvegarder', + 'SaveAs' => 'Sauvegarder sous', + 'SaveFilter' => 'Sauvegarder filtre', 'Scale' => 'Echelle', 'Score' => 'Score', 'Secs' => 'Secs', 'Sectionlength' => 'Longueur section', - 'Select' => 'Select', - 'SelectFormat' => 'Select Format', // Added - 2011-06-17 - 'SelectLog' => 'Select Log', // Added - 2011-06-17 - 'SelectMonitors' => 'Select Monitors', + 'Select' => 'Sélectionner', + 'SelectFormat' => 'Sélectionner format', // Added - 2011-06-17 + 'SelectLog' => 'Sélectionner journal', // Added - 2011-06-17 + 'SelectMonitors' => 'Sélectionner caméras', 'SelfIntersecting' => 'Polygon edges must not intersect', - 'Set' => 'Set', - 'SetNewBandwidth' => 'Régler la bande passante', - 'SetPreset' => 'Set Preset', + 'Set' => 'Définir', + 'SetNewBandwidth' => 'Régler le débit', + 'SetPreset' => 'Définir préréglage', 'Settings' => 'Réglages', - 'ShowFilterWindow' => 'Montrerfen.filtre', - 'ShowTimeline' => 'Show Timeline', + 'ShowFilterWindow' => 'Filtres', + 'ShowTimeline' => 'Afficher chronologie', 'SignalCheckColour' => 'Signal Check Colour', - 'Size' => 'Size', + 'Size' => 'Taille', 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 - 'Sleep' => 'Sleep', + 'Sleep' => 'Veille', 'SortAsc' => 'Asc', - 'SortBy' => 'Sort by', + 'SortBy' => 'Trier par', 'SortDesc' => 'Desc', 'Source' => 'Source', - 'SourceColours' => 'Source Colours', // Added - 2009-02-08 - 'SourcePath' => 'Source Path', // Added - 2009-02-08 - 'SourceType' => 'Source Type', - 'Speed' => 'Speed', - 'SpeedHigh' => 'High Speed', - 'SpeedLow' => 'Low Speed', - 'SpeedMedium' => 'Medium Speed', - 'SpeedTurbo' => 'Turbo Speed', + 'SourceColours' => 'Couleurs', // Added - 2009-02-08 + 'SourcePath' => 'Chemin', // Added - 2009-02-08 + 'SourceType' => 'Type de source', + 'Speed' => 'Vitesse', + 'SpeedHigh' => 'Rapide', + 'SpeedLow' => 'Lent', + 'SpeedMedium' => 'Moyen', + 'SpeedTurbo' => 'Turbo', 'Start' => 'Démarrer', 'State' => 'Etat', 'Stats' => 'Stats', @@ -632,29 +632,29 @@ $SLANG = array( 'StepNone' => 'No Step', 'StepSmall' => 'Small Step', 'Stills' => 'Photos', - 'Stop' => 'Stop', + 'Stop' => 'Arrêter', 'Stopped' => 'Arrêté', 'Stream' => 'Flux', 'StreamReplayBuffer' => 'Stream Replay Image Buffer', - 'Submit' => 'Submit', + 'Submit' => 'Soumettre', 'System' => 'Système', 'SystemLog' => 'System Log', // Added - 2011-06-16 'Tele' => 'Tele', - 'Thumbnail' => 'Thumbnail', + 'Thumbnail' => 'Miniature', 'Tilt' => 'Tilt', - 'Time' => 'Temps', + 'Time' => 'Heure', 'TimeDelta' => 'Time Delta', - 'TimeStamp' => 'Time Stamp', - 'Timeline' => 'Timeline', + 'TimeStamp' => 'Horodatage', + 'Timeline' => 'Chronologie', 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. - 'Timestamp' => 'Timestamp', - 'TimestampLabelFormat' => 'Timestamp Label Format', - 'TimestampLabelX' => 'Timestamp Label X', - 'TimestampLabelY' => 'Timestamp Label Y', - 'Today' => 'Today', + 'Timestamp' => 'Horodatage', + 'TimestampLabelFormat' => 'Format horodatage', + 'TimestampLabelX' => 'Label horodatage X', + 'TimestampLabelY' => 'Label horodatage Y', + 'Today' => 'Aujourd\'hui', 'Tools' => 'Outils', 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Score
total', @@ -665,21 +665,21 @@ $SLANG = array( 'TurboTiltSpeed' => 'Turbo Tilt Speed', 'Type' => 'Type', 'Unarchive' => 'Désarchiv.', - 'Undefined' => 'Undefined', // Added - 2009-02-08 + 'Undefined' => 'Indéfini', // Added - 2009-02-08 'Units' => 'Unités', 'Unknown' => 'Inconnu', - 'Update' => 'Update', - 'UpdateAvailable' => 'Mise à jour de ZM dispo.', + 'Update' => 'Mettre à jour', + 'UpdateAvailable' => 'Mise à jour dispo.', 'UpdateNotNecessary' => 'Pas de mise à jour dispo.', - 'Updated' => 'Updated', // Added - 2011-06-16 - 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', - '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' - 'User' => 'Util.', - 'Username' => 'nom util.', - 'Users' => 'Utils', + 'Updated' => 'Mis à jour', // Added - 2011-06-16 + 'Upload' => 'Transférer', // Added - 2011-08-23 + 'UsedPlugins' => 'Filtres utilisés', + 'UseFilter' => 'Utiliser filtre', + 'UseFilterExprsPost' => ' filtre expressions', // This is used at the end of the phrase 'use N filter expressions' + 'UseFilterExprsPre' => 'Utiliser ', // This is used at the beginning of the phrase 'use N filter expressions' + 'User' => 'Utilisateur', + 'Username' => 'Nom d\'utilisateur', + 'Users' => 'Utilisateurs', 'Value' => 'Valeur', 'Version' => 'Version', 'VersionIgnore' => 'Ignorer cette version', @@ -688,26 +688,26 @@ $SLANG = array( 'VersionRemindNever' => 'Ne pas avertir des nvelles versions', 'VersionRemindWeek' => 'Me rappeler ds 1 sem.', 'Video' => 'Vidéo', - 'VideoFormat' => 'Video Format', - 'VideoGenFailed' => 'Echec génération vidéo!', - 'VideoGenFiles' => 'Existing Video Files', - 'VideoGenNoFiles' => 'No Video Files Found', + 'VideoFormat' => 'Format de la vidéo', + 'VideoGenFailed' => 'Echec génération vidéo !', + 'VideoGenFiles' => 'Fichiers vidéo existants', + 'VideoGenNoFiles' => 'Aucun fichier vidéo trouvé', 'VideoGenParms' => 'Paramètres génération vidéo', - 'VideoGenSucceeded' => 'Video Generation Succeeded!', + 'VideoGenSucceeded' => 'Vidéo générée avec succès !', 'VideoSize' => 'taille vidéo', 'View' => 'Voir', - 'ViewAll' => 'Voir tt', - 'ViewEvent' => 'View Event', - 'ViewPaged' => 'Vue recherchée', - 'Wake' => 'Wake', + 'ViewAll' => 'Tout voir', + 'ViewEvent' => 'Voir événement', + 'ViewPaged' => 'Vue paginée', + 'Wake' => 'Réveiller', 'WarmupFrames' => 'Images test', 'Watch' => 'Regarder', 'Web' => 'Web', - 'WebColour' => 'Web Colour', + 'WebColour' => 'Couleur web', 'Week' => 'Semaine', - 'White' => 'White', - 'WhiteBalance' => 'White Balance', - 'Wide' => 'Wide', + 'White' => 'Blanc', + 'WhiteBalance' => 'Balance des blancs', + 'Wide' => 'Large', 'X' => 'X', 'X10' => 'X10', 'X10ActivationString' => 'X10:chaîne activation', @@ -717,8 +717,8 @@ $SLANG = array( 'Yes' => 'Oui', 'YouNoPerms' => 'Permissions nécessaires pour cette ressource.', 'Zone' => 'Zone', - 'ZoneAlarmColour' => 'Couleur alarme (Red/Green/Blue)', - 'ZoneArea' => 'Zone Area', + 'ZoneAlarmColour' => 'Couleur alarme (Rouge/Vert/Bleu)', + 'ZoneArea' => 'Aire de la zone', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -730,8 +730,8 @@ $SLANG = array( 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zones', 'Zoom' => 'Zoom', - 'ZoomIn' => 'Zoom In', - 'ZoomOut' => 'Zoom Out', + 'ZoomIn' => 'Zoom avant', + 'ZoomOut' => 'Zoom arrière', ); // Complex replacements with formatting and/or placements, must be passed through sprintf @@ -740,8 +740,8 @@ $CLANG = array( 'EventCount' => '%1$s %2$s', // par ex. '37 évènts' (voir Vlang ci-dessous) 'LastEvents' => '%1$s derniers %2$s', // par ex. '37 derniers évènts' (voir Vlang ci-dessous) 'LatestRelease' => 'La dernière version est v%1$s, vous avez v%2$s.', - 'MonitorCount' => '%1$s %2$s', // par exemple '4 écrans' (voir Vlang ci-dessous) - 'MonitorFunction' => 'Ecran %1$s Fonction', + 'MonitorCount' => '%1$s %2$s', // par exemple '4 caméras' (voir Vlang ci-dessous) + 'MonitorFunction' => 'Caméra %1$s Fonction', 'RunningRecentVer' => 'Vs avez la dernière version de ZoneMinder, v%s.', 'VersionMismatch' => 'Version mismatch, system is version %1$s, database is %2$s.', // Added - 2011-05-25 ); @@ -780,8 +780,8 @@ $CLANG = array( // Variable arrays expressing plurality, see the zmVlang description above $VLANG = array( - 'Event' => array( 0=>'évènts', 1=>'évènt', 2=>'évènts' ), - 'Monitor' => array( 0=>'écrans', 1=>'écran', 2=>'écrans' ), + 'Event' => array( 0=>'événements', 1=>'événement', 2=>'événements' ), + 'Monitor' => array( 0=>'caméras', 1=>'caméra', 2=>'caméras' ), ); // You will need to choose or write a function that can correlate the plurality string arrays From 039cf09da9b7dbf304340b816e1061934bac13ca Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Mon, 30 Mar 2015 21:16:33 +0200 Subject: [PATCH 017/154] Fix bad translations (first checking before tests) --- web/lang/fr_fr.php | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/web/lang/fr_fr.php b/web/lang/fr_fr.php index 5a3f34518..cdaeb35b6 100644 --- a/web/lang/fr_fr.php +++ b/web/lang/fr_fr.php @@ -85,7 +85,7 @@ $SLANG = array( 'AlarmFrame' => 'Image alarme', 'AlarmFrameCount' => 'Nombre d\'images en alarme', 'AlarmLimits' => 'Limites alarme', - 'AlarmMaximumFPS' => 'IPS max. pendant alarme', + 'AlarmMaximumFPS' => 'i/s maximum pendant alarme', 'AlarmPx' => 'Px Alarme', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', 'Alert' => 'Alerte', @@ -95,7 +95,7 @@ $SLANG = array( 'ArchArchived' => 'Archivé seul.', 'ArchUnarchived' => 'Non-arch. seul.', 'Archive' => 'Archiver', - 'Archived' => 'Archived', + 'Archived' => 'Archivés', 'Area' => 'Area', 'AreaUnits' => 'Area (px/%)', 'AttrAlarmFrames' => 'Images alarme', @@ -103,7 +103,7 @@ $SLANG = array( 'AttrAvgScore' => 'Score moy.', 'AttrCause' => 'Cause', 'AttrDate' => 'Date', - 'AttrDateTime' => 'Date/heure', + 'AttrDateTime' => 'Date/Heure', 'AttrDiskBlocks' => 'Disk Blocks', 'AttrDiskPercent' => 'Disk Percent', 'AttrDuration' => 'Durée', @@ -122,7 +122,7 @@ $SLANG = array( 'AutoStopTimeout' => 'Auto Stop Timeout', 'Available' => 'Disponible', // Added - 2009-03-31 'AvgBrScore' => 'Score
moy.', - 'Background' => 'Arrère-plan', + 'Background' => 'Arrière-plan', 'BackgroundFilter' => 'Lancer les filtres en arrière-plan', 'BadAlarmFrameCount' => 'Alarm frame count must be an integer of one or more', 'BadAlarmMaxFPS' => 'Alarm Maximum FPS must be a positive integer or floating point value', @@ -237,7 +237,7 @@ $SLANG = array( 'DateTime' => 'Date/Time', // Added - 2011-06-16 'Day' => 'Aujourd\'hui', 'Debug' => 'Debug', - 'DefaultRate' => 'Vitess par défaut', + 'DefaultRate' => 'Vitesse par défaut', 'DefaultScale' => 'Echelle par défaut', 'DefaultView' => 'Vue par défaut', 'Delete' => 'Effacer', @@ -297,12 +297,12 @@ $SLANG = array( 'ExportImageFiles' => 'Exporter fichiers images', 'ExportLog' => 'Exporter fichiers journaux', // Added - 2011-06-17 'ExportMiscFiles' => 'Exporter autres fichiers', - 'ExportOptions' => 'Export Options', - 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 - 'ExportVideoFiles' => 'Export Video Files (if present)', + 'ExportOptions' => 'Options d\'exportation', + 'ExportSucceeded' => 'Exportation réussie', // Added - 2009-02-08 + 'ExportVideoFiles' => 'Exporter fichiers vidéo', 'Exporting' => 'Exportation', - 'FPS' => 'IPS', - 'FPSReportInterval' => 'FPS Report Interval', + 'FPS' => 'i/s', + 'FPSReportInterval' => 'Interv. de rafraîch. i/s', 'FTP' => 'FTP', 'Far' => 'Loin', 'FastForward' => 'Avance rapide', @@ -361,7 +361,7 @@ $SLANG = array( 'High' => 'Haut', 'HighBW' => 'Haut N/B', 'Home' => 'Home', - 'Hour' => 'Dans l\'heure', + 'Hour' => 'Heure', 'Hue' => 'Teinte', 'Id' => 'N°', 'Idle' => 'Vide', @@ -424,16 +424,16 @@ $SLANG = array( 'MaxZoomRange' => 'Max Zoom Range', 'MaxZoomSpeed' => 'Max Zoom Speed', 'MaxZoomStep' => 'Max Zoom Step', - 'MaximumFPS' => 'IPS maximum', + 'MaximumFPS' => 'i/s maximum', 'Medium' => 'Moyen', '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', + 'MinBlobAreaLtMax' => 'Aire blob min. doit être < aire blob maximum', 'MinBlobAreaUnset' => 'You must specify the minimum blob pixel count', 'MinBlobLtMinFilter' => 'Minimum blob area should be less than or equal to minimum filter area', - 'MinBlobsLtMax' => 'Blobs min. doit ê < blobs max.', + 'MinBlobsLtMax' => 'Blobs min. doit être < blobs max.', 'MinBlobsUnset' => 'You must specify the minimum blob count', 'MinFilterAreaLtMax' => 'Minimum filter area should be less than maximum', 'MinFilterAreaUnset' => 'You must specify the minimum filter pixel count', @@ -450,7 +450,7 @@ $SLANG = array( 'MinPanRange' => 'Min Pan Range', 'MinPanSpeed' => 'Min Pan Speed', 'MinPanStep' => 'Min Pan Step', - 'MinPixelThresLtMax' => 'Seuil pixel min. doit ê < seuil pixel max.', + 'MinPixelThresLtMax' => 'Seuil pixel min. doit être < seuil pixel max.', 'MinPixelThresUnset' => 'You must specify a minimum pixel threshold', 'MinTiltRange' => 'Min Tilt Range', 'MinTiltSpeed' => 'Min Tilt Speed', @@ -584,7 +584,7 @@ $SLANG = array( 'RotateRight' => 'Rotation d.', 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 'RunMode' => 'Mode de lancement', - 'RunState' => 'Changer d\état', + 'RunState' => 'Changer d\'état', 'Running' => 'En marche', 'Save' => 'Sauvegarder', 'SaveAs' => 'Sauvegarder sous', @@ -664,7 +664,7 @@ $SLANG = array( 'TurboPanSpeed' => 'Turbo Pan Speed', 'TurboTiltSpeed' => 'Turbo Tilt Speed', 'Type' => 'Type', - 'Unarchive' => 'Désarchiv.', + 'Unarchive' => 'Désarchiver', 'Undefined' => 'Indéfini', // Added - 2009-02-08 'Units' => 'Unités', 'Unknown' => 'Inconnu', From 0669b2416508c5c40a50db45cb089745b625313c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 31 Mar 2015 11:06:14 -0400 Subject: [PATCH 018/154] this was moved to m4 --- ac_check_sendfile.m4 | 63 -------------------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 ac_check_sendfile.m4 diff --git a/ac_check_sendfile.m4 b/ac_check_sendfile.m4 deleted file mode 100644 index 12605d588..000000000 --- a/ac_check_sendfile.m4 +++ /dev/null @@ -1,63 +0,0 @@ -AC_DEFUN([AC_CHECK_SENDFILE],[ -AC_MSG_CHECKING([whether sendfile() is supported and what prototype it has]) - -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -Werror-implicit-function-declaration" -ac_sendfile_supported=no -AC_TRY_LINK([#include - #include ], - [sendfile(1, 1, NULL, 0);], - [ - AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, - [Define this if Linux/Solaris sendfile() is supported]) - AC_MSG_RESULT([Linux sendfile()]) - ac_sendfile_supported=yes - ], []) - -if test x$ac_sendfile_supported = xno; then - dnl Checking wether we need libsendfile - dnl Presumably on Solaris - AC_CHECK_LIB(sendfile, sendfile, - [ - AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, - [Define this if Linux/Solaris sendfile() is supported]) - SENDFILE_LIBS="-lsendfile" - AC_SUBST(SENDFILE_LIBS) - AC_MSG_RESULT([Solaris sendfile()]) - ac_sendfile_supported=yes - ], []) -fi - -if test x$ac_sendfile_supported = xno; then - dnl Checking wether we have FreeBSD-like sendfile() support. - AC_TRY_LINK([#include - #include ], - [sendfile(1, 1, 0, 0, NULL, NULL, 0);], - [ - AC_DEFINE(HAVE_SENDFILE7_SUPPORT, 1, - [Define this if FreeBSD sendfile() is supported]) - AC_MSG_RESULT([FreeBSD sendfile()]) - ac_sendfile_supported=yes - ], []) -fi - -if test x$ac_sendfile_supported = xno; then - dnl Checking wether we have MacOS-like sendfile() support. - AC_TRY_LINK([#include - #include - #include ], - [sendfile(1, 1, 0, NULL, NULL, 0);], - [ - AC_DEFINE(HAVE_SENDFILE6_SUPPORT, 1, - [Define this if MacOS sendfile() is supported]) - AC_MSG_RESULT([MacOS sendfile()]) - ac_sendfile_supported=yes - ], []) -fi - -CFLAGS="$saved_CFLAGS" - -if test x$ac_sendfile_supported = xno; then - AC_MSG_RESULT([no sendfile() support, using read/send]) -fi -]) From e4e2160bf6005b73f368e3e0665c84e9d5686e9d Mon Sep 17 00:00:00 2001 From: balr0g Date: Tue, 31 Mar 2015 13:22:02 -0400 Subject: [PATCH 019/154] Don't trigger linked cameras on new events --- src/zm_monitor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index a61e7cfa5..2696c5cf5 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -251,7 +251,6 @@ bool Monitor::MonitorLink::hasAlarmed() else if( shared_data->last_event != (unsigned int)last_event ) { last_event = shared_data->last_event; - return( true ); } return( false ); } From 7802089b82f29930fdd1c27a71609ba5d572a2d4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 31 Mar 2015 20:30:27 -0500 Subject: [PATCH 020/154] Use tmpfiles.d to manage tmpdir and sockdir --- INSTALL | 16 +++++++++++++--- distros/fedora/CMakeLists.txt | 2 +- distros/redhat/CMakeLists.txt | 2 +- misc/zoneminder-tmpfiles.conf.in | 5 ++++- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/INSTALL b/INSTALL index 6d329bcd4..8b4f22c4b 100644 --- a/INSTALL +++ b/INSTALL @@ -93,9 +93,19 @@ NOTE: The database server, database name, user and password can be different and 8) Create an apache virtual host for ZoneMinder. Make sure to use the same paths as ZM_WEBDIR and ZM_CGIDIR in /etc/zm.conf 9) Create other config if desired (e.g. rsyslog, logrotate and such). Some of this can be found in /share/zoneminder/misc or project/misc directory -10) Setup an appropriate startup script for your system. A generic sys v init script is here: /scripts/zm while a generic systemd service file is here: /misc/zoneminder.service -You must determine which file to use, verify it is correct, and then copy it to the correct location. Consult your distro's documentation. Note that distros using systemd also -require /misc/zoneminder-tmpfiles.conf to be copied into the system's tmpfiles.d folder. +10) Setup an appropriate startup script for your system. Two generic startup scripts have been provided, a legacy Sys V Init script and a Systemd service file. + +*Sys V Init Setup* +- Copy the sys v init script /scripts/zm from the build folder to /etc/init. +- Inspect the contents to make sure they apply to your distro. + +*SystemD Setup* +- Copy the zoneminder systemd service file /misc/zoneminder.service from the build folder to the systemd service file location. + For Redhat based distros, that folder is /usr/lib/systemd/system. +- Inspect the contents to make sure they apply to your distro. +- Tell systemd to load the new service file: "sudo systemctl daemon-reload". +- Copy /misc/zoneminder-tmpfiles.conf to /etc/tmpfiles.d +- Tell systemd to process this file: "sudo /usr/bin/systemd-tmpfiles --create /etc/tmpfiles.d/zoneminder.conf". Basic steps for upgrading ZoneMinder ------------------------------------ diff --git a/distros/fedora/CMakeLists.txt b/distros/fedora/CMakeLists.txt index 7409a2e39..058d604a5 100644 --- a/distros/fedora/CMakeLists.txt +++ b/distros/fedora/CMakeLists.txt @@ -32,7 +32,7 @@ install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DE # Install auxillary files required to run zoneminder on Fedora install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -install(FILES zoneminder.tmpfiles DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index 7422be107..f68add4f6 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -58,7 +58,7 @@ if(ZM_TARGET_DISTRO STREQUAL "el7") install(FILES zoneminder.el7.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.el7.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) - install(FILES zoneminder.tmpfiles DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) else(ZM_TARGET_DISTRO STREQUAL "el7") install(FILES zoneminder.el6.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.el6.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/misc/zoneminder-tmpfiles.conf.in b/misc/zoneminder-tmpfiles.conf.in index 8f55ce295..79b27f909 100644 --- a/misc/zoneminder-tmpfiles.conf.in +++ b/misc/zoneminder-tmpfiles.conf.in @@ -1 +1,4 @@ -d @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@ + From c0af30bdf1b8ddbecfe126c6d6997ec736d74bc4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 31 Mar 2015 20:45:12 -0500 Subject: [PATCH 021/154] fix permissions on config file --- distros/fedora/CMakeLists.txt | 2 +- distros/redhat/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/fedora/CMakeLists.txt b/distros/fedora/CMakeLists.txt index 058d604a5..deec840f7 100644 --- a/distros/fedora/CMakeLists.txt +++ b/distros/fedora/CMakeLists.txt @@ -32,7 +32,7 @@ install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DE # Install auxillary files required to run zoneminder on Fedora install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index f68add4f6..129d666d4 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -58,7 +58,7 @@ if(ZM_TARGET_DISTRO STREQUAL "el7") install(FILES zoneminder.el7.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.el7.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) - install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) else(ZM_TARGET_DISTRO STREQUAL "el7") install(FILES zoneminder.el6.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.el6.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) From 199c94e7db35c1576fd7f0a2151ae4a15afcf200 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 31 Mar 2015 23:07:19 -0400 Subject: [PATCH 022/154] Add Sendfile checks for cmake --- CMakeLists.txt | 1 + cmake/Modules/CheckSendfile.cmake | 58 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 cmake/Modules/CheckSendfile.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index ef04e1fba..558c5c8d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ include (CheckFunctionExists) include (CheckPrototypeDefinition_fixed) include (CheckTypeSize) include (CheckStructHasMember) +include (CheckSendfile) # Configuration options mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP CMAKE_INSTALL_FULL_BINDIR ZM_PERL_SUBPREFIX ZM_PERL_USE_PATH ZM_TARGET_DISTRO ZM_CONFIG_DIR) diff --git a/cmake/Modules/CheckSendfile.cmake b/cmake/Modules/CheckSendfile.cmake new file mode 100644 index 000000000..1796b92e3 --- /dev/null +++ b/cmake/Modules/CheckSendfile.cmake @@ -0,0 +1,58 @@ +# Check whether sendfile() is supported and what prototype it has +include(CheckCSourceCompiles) +if (UNIX OR MINGW) +SET(CMAKE_REQUIRED_DEFINITIONS -Werror-implicit-function-declaration) +endif() +check_c_source_compiles("#include +#include +int main() +{ +sendfile(1, 1, NULL, 0); +return 0; +}" HAVE_SENDFILE4_SUPPORT) +if(HAVE_SENDFILE4_SUPPORT) +add_definitions(-DHAVE_SENDFILE4_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: Linux/Solaris sendfile()") +return() +endif() +find_library(SENDFILE_LIBRARIES NAMES sendfile) +if(SENDFILE_LIBRARIES) +include(CheckLibraryExists) +check_library_exists(sendfile sendfile ${SENDFILE_LIBRARIES} HAVE_SENDFILE4_SUPPORT) +if(HAVE_SENDFILE4_SUPPORT) +add_definitions(-DHAVE_SENDFILE4_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: Solaris sendfile()") +return() +endif() +endif() +set(SENDFILE_LIBRARIES "") +check_c_source_compiles("#include +#include +int main() +{ +sendfile(1, 1, 0, 0, NULL, NULL, 0); +return 0; +}" HAVE_SENDFILE7_SUPPORT) +if(HAVE_SENDFILE7_SUPPORT) +add_definitions(-DHAVE_SENDFILE7_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: FreeBSD sendfile()") +return() +endif() +check_c_source_compiles("#include +#include +#include +int main() +{ +sendfile(1, 1, 0, NULL, NULL, 0); +return 0; +}" HAVE_SENDFILE6_SUPPORT) +if(HAVE_SENDFILE6_SUPPORT) +add_definitions(-DHAVE_SENDFILE6_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: MacOS sendfile()") +return() +endif() + From 648a05a40603d0e7feba7df58ddc0c44c5923c79 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 31 Mar 2015 23:20:39 -0400 Subject: [PATCH 023/154] have to include the m4 dir apparently --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index f6d46bc3d..62f767e75 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,5 @@ AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 # And these to the user and group of your webserver webuser = @WEB_USER@ From bf3efa7a7aec16c0d6ee877dfb280767f776dfbe Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 31 Mar 2015 23:31:05 -0400 Subject: [PATCH 024/154] allow AC_CHECK_SENDFILE because travis is complaining --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 4bb17ae79..c65931705 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,7 @@ AC_FUNC_VPRINTF AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strspn strstr strtol strtoull]) AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction]) # this is required for freebsd to compile +m4_pattern_allow(AC_CHECK_SENDFILE) AC_CHECK_SENDFILE # Other programs AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no) From c2c130df37dc6c1f798fc3fdfdd44790cf4f386b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 10:14:02 -0400 Subject: [PATCH 025/154] try out the new AC_CONFIG_MACRO_DIRS feature. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index c65931705..be6b4dec9 100644 --- a/configure.ac +++ b/configure.ac @@ -4,6 +4,7 @@ AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_MACRO_DIRS([m4]) AC_SUBST([AM_CXXFLAGS], [-D__STDC_CONSTANT_MACROS]) From b0e6ed1d4af7bef3a5bd2af7f76620aa24c1c9f0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 11:05:11 -0400 Subject: [PATCH 026/154] check cwd and cat out the resulting aclocal.m4 in order to debug the lack of including our ac_check_sendfile macros. Also be more verbose from libtoolize --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index da5bf96b4..965f79fec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,9 @@ install: - sudo make install-libs before_script: - cd $TRAVIS_BUILD_DIR - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize --force; fi + - pwd + - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi + - cat aclocal.m4 - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi From 59fbb4d0b531d73d07cd35209ecb05e805afa5c1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 11:16:05 -0400 Subject: [PATCH 027/154] ahem: only cat aclocal.m4 if using autotools --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 965f79fec..05ad96674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ before_script: - cd $TRAVIS_BUILD_DIR - pwd - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi - - cat aclocal.m4 + - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then cat aclocal.m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi From fd62b1a71c9b59eadb17dbb73e2681c0c5363189 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 11:26:23 -0400 Subject: [PATCH 028/154] show directory listing to see what's in the build dir. cat aclocal.m4 after it has actually been created. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 05ad96674..2d8927bb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,10 +32,10 @@ install: - sudo make install-libs before_script: - cd $TRAVIS_BUILD_DIR - - pwd + - ls -l - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then cat aclocal.m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi + - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then cat aclocal.m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoconf; fi From 1b8554fad24edfaec0c9232da57b76a0cd842944 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 12:17:23 -0400 Subject: [PATCH 029/154] cleanup. --- configure.ac | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index be6b4dec9..e8bc904bd 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,6 @@ AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_MACRO_DIRS([m4]) AC_SUBST([AM_CXXFLAGS], [-D__STDC_CONSTANT_MACROS]) @@ -323,8 +322,7 @@ AC_FUNC_STRTOD AC_FUNC_VPRINTF AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strspn strstr strtol strtoull]) AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction]) -# this is required for freebsd to compile -m4_pattern_allow(AC_CHECK_SENDFILE) +# this is required for freebsd to compile. Look for it in m4/ac_check_sendfile.m4 AC_CHECK_SENDFILE # Other programs AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no) From 5592f52cf86c9ee7b65b5c3df738b0369bbc3a91 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 12:18:45 -0400 Subject: [PATCH 030/154] add -I to aclocal command line since it is ignoring all other include directives --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2d8927bb6..df9637261 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ before_script: - cd $TRAVIS_BUILD_DIR - ls -l - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi + - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal -I m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then cat aclocal.m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi From 2591e946afc38fa87e77c5809a64e51afbc2c06e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 12:19:27 -0400 Subject: [PATCH 031/154] old versions ignore other efforts to include our own m4 directory, so spceify it on the command line --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index 681d5b319..0bc041f18 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,5 +1,5 @@ #!/bin/bash -aclocal +aclocal -I m4 autoheader automake --add-missing autoconf From 64d7a53cf6dede97ac54eb3326e5659c6bc711f6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Apr 2015 12:53:06 -0400 Subject: [PATCH 032/154] remove lines I used for debugging. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index df9637261..f51d80cbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,10 +32,8 @@ install: - sudo make install-libs before_script: - cd $TRAVIS_BUILD_DIR - - ls -l - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal -I m4; fi - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then cat aclocal.m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoconf; fi From 0a010a69bdad40ec2420ea8fd0b10c4b99fd8dd3 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 3 Apr 2015 17:36:09 -0500 Subject: [PATCH 033/154] autotools - update v4l header file check --- configure.ac | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index c42847877..a73821150 100644 --- a/configure.ac +++ b/configure.ac @@ -368,14 +368,26 @@ AC_CHECK_HEADERS(execinfo.h,,,) AC_CHECK_HEADERS(ucontext.h,,,) AC_CHECK_HEADERS(sys/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),) + +# Check for Video for Linux 1 Header Files +ZM_HAS_V4L1=0 +AC_CHECK_HEADERS([libv4l1-videodev.h linux/videodev.h],[ZM_HAS_V4L1=1; break;],,) +AC_SUBST(ZM_HAS_V4L1) + +# Check for Video for Linux 2 Header Files +ZM_HAS_V4L2=0 +AC_CHECK_HEADERS(linux/videodev2.h,ZM_HAS_V4L2=1,,) +AC_SUBST(ZM_HAS_V4L2) + +# Set global Video for Linux flag +ZM_HAS_V4L=0 if test "$ZM_HAS_V4L1" == "1" || test "$ZM_HAS_V4L2" == "1"; then -AC_SUBST(ZM_HAS_V4L,1) +ZM_HAS_V4L=1 else -AC_SUBST(ZM_HAS_V4L,0) AC_MSG_WARN(zm requires Video4Linux or Video4Linux2 to be installed for analog or USB camera support) fi +AC_SUBST(ZM_HAS_V4L) + AC_CHECK_HEADERS(jpeglib.h,,AC_MSG_ERROR(zm requires libjpeg headers to be installed),) AC_CHECK_HEADERS(mysql/mysql.h,,AC_MSG_ERROR(zm requires MySQL headers - check that MySQL development packages are installed),) AC_LANG_PUSH([C]) From a3637b9eed34a58ad812490eb5877debb59060a4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 3 Apr 2015 17:41:46 -0500 Subject: [PATCH 034/154] Add libv4l-devel as a build req for el7, f20, & f21 --- distros/fedora/zoneminder.f20.spec | 2 +- distros/fedora/zoneminder.f21.spec | 2 +- distros/redhat/zoneminder.el7.spec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/distros/fedora/zoneminder.f20.spec b/distros/fedora/zoneminder.f20.spec index a49361ef3..4d9c629d1 100644 --- a/distros/fedora/zoneminder.f20.spec +++ b/distros/fedora/zoneminder.f20.spec @@ -31,7 +31,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite) BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel +BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel %{!?_without_ffmpeg:BuildRequires: ffmpeg-devel} %{!?_without_x10:BuildRequires: perl(X10::ActiveHome) perl(Astro::SunTime)} # cmake needs the following installed at build time due to the way it auto-detects certain parameters diff --git a/distros/fedora/zoneminder.f21.spec b/distros/fedora/zoneminder.f21.spec index 31afc0417..de97aea94 100644 --- a/distros/fedora/zoneminder.f21.spec +++ b/distros/fedora/zoneminder.f21.spec @@ -31,7 +31,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite) BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel +BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel %{!?_without_ffmpeg:BuildRequires: ffmpeg-devel} %{!?_without_x10:BuildRequires: perl(X10::ActiveHome) perl(Astro::SunTime)} # cmake needs the following installed at build time due to the way it auto-detects certain parameters diff --git a/distros/redhat/zoneminder.el7.spec b/distros/redhat/zoneminder.el7.spec index b21a3901d..ebd22aa00 100644 --- a/distros/redhat/zoneminder.el7.spec +++ b/distros/redhat/zoneminder.el7.spec @@ -27,7 +27,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite) BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel +BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel BuildRequires: ffmpeg ffmpeg-devel perl(X10::ActiveHome) perl(Astro::SunTime) # cmake needs the following installed at build time due to the way it auto-detects certain parameters BuildRequires: httpd polkit-devel From 2331d731d16863545b1341ecee9824f672ab84cf Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 3 Apr 2015 18:21:28 -0500 Subject: [PATCH 035/154] cmake - update v4l header file check --- CMakeLists.txt | 13 ++++++++----- zoneminder-config.cmake | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef04e1fba..c475bafbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,10 @@ include_directories("${CMAKE_BINARY_DIR}") set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON) # System checks -check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H) +check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H) +if(NOT HAVE_LIBV4L1_VIDEODEV_H) + check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H) +endif(NOT HAVE_LIBV4L1_VIDEODEV_H) check_include_file("linux/videodev2.h" HAVE_LINUX_VIDEODEV2_H) check_include_file("execinfo.h" HAVE_EXECINFO_H) check_include_file("ucontext.h" HAVE_UCONTEXT_H) @@ -413,17 +416,17 @@ endif((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS)) set(ZM_HAS_V4L 0) set(ZM_HAS_V4L1 0) set(ZM_HAS_V4L2 0) -if(HAVE_LINUX_VIDEODEV_H) +if(HAVE_LINUX_VIDEODEV_H OR HAVE_LIBV4L1_VIDEODEV_H) set(ZM_HAS_V4L 1) set(ZM_HAS_V4L1 1) -endif(HAVE_LINUX_VIDEODEV_H) +endif(HAVE_LINUX_VIDEODEV_H OR HAVE_LIBV4L1_VIDEODEV_H) if(HAVE_LINUX_VIDEODEV2_H) set(ZM_HAS_V4L 1) set(ZM_HAS_V4L2 1) endif(HAVE_LINUX_VIDEODEV2_H) -if((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H)) +if((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LIBV4L1_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H)) message(AUTHOR_WARNING " Video 4 Linux headers weren't found - Analog and USB camera support will not be available") -endif((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H)) +endif((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LIBV4L1_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H)) # Check for PCRE and enable ZM_PCRE accordingly set(ZM_PCRE 0) if(HAVE_LIBPCRE AND HAVE_PCRE_H) diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index 90759c1b6..3854dfe31 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -5,6 +5,7 @@ /* General system checks */ #cmakedefine HAVE_LINUX_VIDEODEV_H 1 +#cmakedefine HAVE_LIBV4L1_VIDEODEV_H 1 #cmakedefine HAVE_LINUX_VIDEODEV2_H 1 #cmakedefine HAVE_EXECINFO_H 1 #cmakedefine HAVE_UCONTEXT_H 1 From 549d7fd4265844fbfc7f7f10705eb5e653b05cda Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 3 Apr 2015 18:24:51 -0500 Subject: [PATCH 036/154] include libv4l1-videodev headers --- src/zm_local_camera.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index 0dbe44c21..89c6799ca 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -29,6 +29,9 @@ #ifdef HAVE_LINUX_VIDEODEV_H #include #endif // HAVE_LINUX_VIDEODEV_H +#ifdef HAVE_LIBV4L1_VIDEODEV_H +#include +#endif // HAVE_LIB4VL1_VIDEODEV_H #ifdef HAVE_LINUX_VIDEODEV2_H #include #endif // HAVE_LINUX_VIDEODEV2_H From d1f00f02c2770c0fec1280af45b804fc47b6f82f Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 4 Apr 2015 20:37:27 +1100 Subject: [PATCH 037/154] skins/classic: fix HTML export with USE_DEEP_STORAGE (Closes: #506). Use mygetEventPath() to get valid path. Signed-off-by: Dmitry Smirnov --- .../classic/includes/export_functions.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 42b03a8da..1eddd54f6 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -181,7 +181,7 @@ function exportEventFrames( $event, $exportDetail, $exportImages ) -
+
@@ -660,7 +664,7 @@ function exportEventImagesMaster( $eids ) if ($eventMonitorId[$eid] == $monitor) { ?> -
+
Date: Sat, 4 Apr 2015 09:20:21 -0500 Subject: [PATCH 038/154] Update ConfigData.pm.in --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index ac64d46ff..f3c53dac3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -181,7 +181,7 @@ our @options = name => "ZM_USE_DEEP_STORAGE", default => "yes", description => "Use a deep filesystem hierarchy for events", - help => "Traditionally ZoneMinder stores all events for a monitor in one directory for that monitor. This is simple and efficient except when you have very large amounts of events. Some filesystems are unable to store more than 32k files in one directory and even without this limitation, large numbers of files in a directory can slow creation and deletion of files. This option allows you to select an alternate method of storing events by year/month/day/hour/min/second which has the effect of separating events out into more directories, resulting in less per directory, and also making it easier to manually navigate to any events that may have happened at a particular time or date.", + help => "This option is now the default for new ZoneMinder systems and should not be changed. Previous versions of ZoneMinder stored all events for a monitor under one folder. Enabling USE_DEEP_STORAGE causes ZoneMinder to store events under a folder structure that follows year/month/day/hour/min/second. Storing events this way avoids the limitation of storing more than 32k files in a single folder inherent in some filesystems. If you are upgrading from a previous version of ZoneMinder, it is important to note that you cannot simply enable this option. You must stop zoneminder, enable USE_DEEP_STORAGE, and then run \"sudo zmupdate.pl --migrate-events\". FAILURE TO DO SO WILL RESULT IN LOSS OF YOUR DATA! Consult the ZoneMinder WiKi for further details.", type => $types{boolean}, category => "paths", }, From 078c5aa14b97c26754c37862b8ea331aa84c9c89 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Mon, 6 Apr 2015 18:29:48 +1000 Subject: [PATCH 039/154] Briefly document "--migrate-events" option in zmupdate.pl (#783). Signed-off-by: Dmitry Smirnov --- scripts/zmupdate.pl.in | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 2650ba812..522f211ec 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -39,6 +39,7 @@ configuring upgrades etc, including on the fly upgrades. -c, --check - Check for updated versions of ZoneMinder -f, --freshen - Freshen the configuration in the database. Equivalent of old zmconfig.pl -noi + --migrate-events - Update database structures as per USE_DEEP_STORAGE setting. -v, --version= - Force upgrade to the current version from -u, --user= - Alternate DB user with privileges to alter DB -p, --pass= - Password of alternate DB user with privileges to alter DB From 904f2989ed44e12a2aa854edfd12bb6cb838a019 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Mon, 6 Apr 2015 18:16:02 +1000 Subject: [PATCH 040/154] Improving ZM_USE_DEEP_STORAGE description (#783): Removed "If you are upgrading from a previous version of ZoneMinder" from description. From data loss prospective it is irrelevant whether database is upgraded or not as fresh install is just as vulnerable. Changed "enable" to "change" to emphasize the above. Signed-off-by: Dmitry Smirnov --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index f3c53dac3..4235a1398 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -181,7 +181,7 @@ our @options = name => "ZM_USE_DEEP_STORAGE", default => "yes", description => "Use a deep filesystem hierarchy for events", - help => "This option is now the default for new ZoneMinder systems and should not be changed. Previous versions of ZoneMinder stored all events for a monitor under one folder. Enabling USE_DEEP_STORAGE causes ZoneMinder to store events under a folder structure that follows year/month/day/hour/min/second. Storing events this way avoids the limitation of storing more than 32k files in a single folder inherent in some filesystems. If you are upgrading from a previous version of ZoneMinder, it is important to note that you cannot simply enable this option. You must stop zoneminder, enable USE_DEEP_STORAGE, and then run \"sudo zmupdate.pl --migrate-events\". FAILURE TO DO SO WILL RESULT IN LOSS OF YOUR DATA! Consult the ZoneMinder WiKi for further details.", + help => "This option is now the default for new ZoneMinder systems and should not be changed. Previous versions of ZoneMinder stored all events for a monitor under one folder. Enabling USE_DEEP_STORAGE causes ZoneMinder to store events under a folder structure that follows year/month/day/hour/min/second. Storing events this way avoids the limitation of storing more than 32k files in a single folder inherent in some filesystems. It is important to note that you cannot simply change this option. You must stop zoneminder, enable USE_DEEP_STORAGE, and then run \"sudo zmupdate.pl --migrate-events\". FAILURE TO DO SO WILL RESULT IN LOSS OF YOUR DATA! Consult the ZoneMinder WiKi for further details.", type => $types{boolean}, category => "paths", }, From e895fd26f756b6fb7ebdd9973e313c13dd8ab976 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 7 Apr 2015 08:19:21 -0500 Subject: [PATCH 041/154] cmake - use perl INSTALLDIRS --- scripts/ZoneMinder/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/CMakeLists.txt b/scripts/ZoneMinder/CMakeLists.txt index 61bee83af..df7dffc63 100644 --- a/scripts/ZoneMinder/CMakeLists.txt +++ b/scripts/ZoneMinder/CMakeLists.txt @@ -24,10 +24,11 @@ else(CMAKE_VERBOSE_MAKEFILE) endif(CMAKE_VERBOSE_MAKEFILE) # Add build target for the perl modules -add_custom_target(zmperlmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +#add_custom_target(zmperlmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmperlmodules ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") # Add install target for the perl modules -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") # Add additional files and directories to make clean set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl") From 45fd7f1eca225b5721a88496facda32aa2bd157a Mon Sep 17 00:00:00 2001 From: SteveGilvarry Date: Wed, 8 Apr 2015 20:11:26 +1000 Subject: [PATCH 042/154] Found some old open tags left over --- web/skins/classic/views/plugin.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/plugin.php b/web/skins/classic/views/plugin.php index b93a639cf..f4a5fd765 100644 --- a/web/skins/classic/views/plugin.php +++ b/web/skins/classic/views/plugin.php @@ -116,12 +116,12 @@ function pLang($name)
- $popt) { ?> - $popt) ?> - $popt) } ?> - From 98d91ded9065b8e4d28af74c94317396490b6221 Mon Sep 17 00:00:00 2001 From: SteveGilvarry Date: Wed, 8 Apr 2015 20:13:27 +1000 Subject: [PATCH 043/154] Found some introduced short tags --- web/skins/classic/views/onvifprobe.php | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/web/skins/classic/views/onvifprobe.php b/web/skins/classic/views/onvifprobe.php index 22c365296..a129b2dba 100644 --- a/web/skins/classic/views/onvifprobe.php +++ b/web/skins/classic/views/onvifprobe.php @@ -177,33 +177,33 @@ if( !isset($_REQUEST['step']) || ($_REQUEST['step'] == "1")) {
-
+ - +

- +

- +

- +

- +

- +

- - + +
@@ -257,23 +257,23 @@ else if($_REQUEST['step'] == "2")
-
+ - +

- +

- +

- - - + + +
From a2d9c0c042cf03ab83ec330d5d4bfc0d85293cb7 Mon Sep 17 00:00:00 2001 From: abauer Date: Wed, 8 Apr 2015 12:22:46 -0500 Subject: [PATCH 044/154] Don't copy .in files into staging --- scripts/ZoneMinder/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/ZoneMinder/CMakeLists.txt b/scripts/ZoneMinder/CMakeLists.txt index df7dffc63..003e4a616 100644 --- a/scripts/ZoneMinder/CMakeLists.txt +++ b/scripts/ZoneMinder/CMakeLists.txt @@ -2,13 +2,13 @@ # If this is an out-of-source build, copy the files we need to the binary directory if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Changes" "${CMAKE_CURRENT_BINARY_DIR}/Changes") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.PL") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST" "${CMAKE_CURRENT_BINARY_DIR}/MANIFEST") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/META.yml" "${CMAKE_CURRENT_BINARY_DIR}/META.yml") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/README" "${CMAKE_CURRENT_BINARY_DIR}/README") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/t" "${CMAKE_CURRENT_BINARY_DIR}/t") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/lib" "${CMAKE_CURRENT_BINARY_DIR}/lib") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Changes" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/META.yml" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/README" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/t" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) # Create files from the .in files From 81860d99a624469a7d812dad78e39bdb03b2c32b Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Thu, 9 Apr 2015 03:29:38 +1000 Subject: [PATCH 045/154] zmdc.pl: PBP/5 + reformatting --- scripts/zmdc.pl.in | 104 +++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 32 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index c209ae63f..8f0810d8c 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -73,14 +73,14 @@ my @daemons = ( ); sub Usage -{ +{ print( " Usage: zmdc.pl [daemon [options]] Parameters are :- - One of 'startup|shutdown|status|check|logrot' or 'start|stop|restart|reload|version'. [daemon [options]] - Daemon name and options, required for second group of commands -"); +"); exit( -1 ); } @@ -91,8 +91,8 @@ if( !$command ) Usage(); } if ( $command eq 'version' ) { - print ZoneMinder::Base::ZM_VERSION."\n"; - exit( 0 ); + print ZoneMinder::Base::ZM_VERSION."\n"; + exit( 0 ); } my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/; my $daemon = shift( @ARGV ); @@ -152,7 +152,7 @@ if ( !$server_up ) print( "Unable to connect to server\n" ); exit( -1 ); } - # The server isn't there + # The server isn't there print( "Starting server\n" ); close( CLIENT ); @@ -235,12 +235,15 @@ sub run logInit(); - dPrint( ZoneMinder::Logger::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 ) ) + if ( open( my $PID, '>', ZM_PID ) ) { - print( PID $$ ); - close( PID ); + print( $PID $$ ); + close( $PID ); } killAll( 1 ); @@ -354,7 +357,10 @@ sub run restartPending(); } } - dPrint( ZoneMinder::Logger::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(); @@ -413,7 +419,10 @@ sub start } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { - dPrint( ZoneMinder::Logger::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(); } @@ -428,7 +437,10 @@ sub start $process->{started} = time(); delete( $process->{pending} ); - dPrint( ZoneMinder::Logger::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: $!" ); @@ -437,7 +449,11 @@ sub start { logReinit(); - dPrint( ZoneMinder::Logger::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}$/ ) { @@ -501,7 +517,10 @@ sub _stop elsif ( $process->{pending} ) { delete( $cmd_hash{$command} ); - dPrint( ZoneMinder::Logger::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(); } @@ -512,7 +531,11 @@ sub _stop return(); } - dPrint( ZoneMinder::Logger::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} ); @@ -694,7 +717,10 @@ sub shutdownAll stop( $process->{daemon}, @{$process->{args}} ); } killAll( 5 ); - dPrint( ZoneMinder::Logger::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 ); @@ -750,7 +776,10 @@ sub status if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::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 { @@ -761,13 +790,19 @@ sub status return(); } } - dPrint( ZoneMinder::Logger::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 { foreach my $process ( values(%pid_hash) ) { - my $out_str = "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}"; + 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( ZoneMinder::Logger::DEBUG, $out_str ); @@ -776,7 +811,10 @@ sub status { if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::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" + ); } } } @@ -786,19 +824,21 @@ sub killAll { my $delay = shift; sleep( $delay ); - my $killall; - if ( '@HOST_OS@' eq 'BSD' ) { - $killall = 'killall -'; - } else { - $killall = 'killall -q -s '; - } - foreach my $daemon ( @daemons ) { + my $killall; + if ( '@HOST_OS@' eq 'BSD' ) + { + $killall = 'killall -'; + } else { + $killall = 'killall -q -s '; + } + foreach my $daemon ( @daemons ) + { - my $cmd = $killall ."TERM $daemon"; - Debug( $cmd ); - qx( $cmd ); - } - sleep( $delay ); + my $cmd = $killall ."TERM $daemon"; + Debug( $cmd ); + qx( $cmd ); + } + sleep( $delay ); foreach my $daemon ( @daemons ) { my $cmd = $killall."KILL $daemon"; From 373b53f8f33e97e5d3da5dba82fd530079f50ed0 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Thu, 9 Apr 2015 03:41:20 +1000 Subject: [PATCH 046/154] zmdc.pl: Usage() --> pod2usage() --- scripts/zmdc.pl.in | 50 ++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 8f0810d8c..5a0ce9eef 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -20,13 +20,30 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is the gateway for controlling the various ZoneMinder -# daemons. All starting, stopping and restarting goes through here. -# On the first invocation it starts up a server which subsequently -# records what's running and what's not. Other invocations just -# connect to the server and pass instructions to it. -# + +=head1 NAME + +zmdc.pl - ZoneMinder Daemon Control script + +=head1 SYNOPSIS + + zmdc.pl {command} [daemon [options]] + +=head1 DESCRIPTION + +This script is the gateway for controlling the various ZoneMinder +daemons. All starting, stopping and restarting goes through here. +On the first invocation it starts up a server which subsequently +records what's running and what's not. Other invocations just +connect to the server and pass instructions to it. + +=head1 OPTIONS + + {command} - One of 'startup|shutdown|status|check|logrot' or + 'start|stop|restart|reload|version'. + [daemon [options]] - Daemon name and options, required for second group of commands + +=cut use strict; use bytes; @@ -49,6 +66,7 @@ use ZoneMinder; use POSIX; use Socket; use IO::Handle; +use autouse 'Pod::Usage'=>qw(pod2usage); #use Data::Dumper; use constant SOCK_FILE => $Config{ZM_PATH_SOCKS}.'/zmdc.sock'; @@ -72,23 +90,11 @@ my @daemons = ( 'zmtrack.pl' ); -sub Usage -{ - print( " -Usage: zmdc.pl [daemon [options]] -Parameters are :- - - One of 'startup|shutdown|status|check|logrot' or - 'start|stop|restart|reload|version'. -[daemon [options]] - Daemon name and options, required for second group of commands -"); - exit( -1 ); -} - my $command = shift @ARGV; if( !$command ) { print( STDERR "No command given\n" ); - Usage(); + pod2usage(-exitstatus => -1); } if ( $command eq 'version' ) { print ZoneMinder::Base::ZM_VERSION."\n"; @@ -99,7 +105,7 @@ my $daemon = shift( @ARGV ); if( $needs_daemon && !$daemon ) { print( STDERR "No daemon given\n" ); - Usage(); + pod2usage(-exitstatus => -1); } my @args; @@ -113,7 +119,7 @@ if ( $needs_daemon ) else { print( STDERR "Invalid daemon '$daemon' specified" ); - Usage(); + pod2usage(-exitstatus => -1); } } From 5779b2e20fe7d5e43a5a38ab289e45fc0ffc9545 Mon Sep 17 00:00:00 2001 From: Sune1337 Date: Wed, 8 Apr 2015 22:15:54 +0200 Subject: [PATCH 047/154] * use pthread_join instead of pthread_tryjoin_np --- src/zm_ffmpeg_camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 9a4ea5fcb..5ae1e4a37 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -120,7 +120,7 @@ int FfmpegCamera::Capture( Image &image ) void *retval = 0; int ret; - ret = pthread_tryjoin_np(mReopenThread, &retval); + ret = pthread_join(mReopenThread, &retval); if (ret != 0){ Error("Could not join reopen thread."); } From ef21d08dd351920a4f67d69d80c52f5c815aa5cb Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 9 Apr 2015 10:44:16 -0500 Subject: [PATCH 048/154] Update CMakeLists.txt typo --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef04e1fba..9fa6ccb59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -540,9 +540,9 @@ add_subdirectory(web) add_subdirectory(misc) # Enable ONVIF support -if (ZM_ONVIF) +if(ZM_ONVIF) add_subdirectory(onvif) -endif (ZM_ONVIF) +endif(ZM_ONVIF) # Process distro subdirectories if((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20")) From e6631ebaf12d0c63ce6b4fef444f1f8d1125dd64 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 9 Apr 2015 20:11:32 -0500 Subject: [PATCH 049/154] Propagate new perl changes to the ONVIF perl modules --- onvif/modules/CMakeLists.txt | 12 ++++++++++-- onvif/proxy/CMakeLists.txt | 12 ++++++++++-- scripts/ZoneMinder/CMakeLists.txt | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/onvif/modules/CMakeLists.txt b/onvif/modules/CMakeLists.txt index 5e3a878bb..9e94f3f7b 100644 --- a/onvif/modules/CMakeLists.txt +++ b/onvif/modules/CMakeLists.txt @@ -1,10 +1,18 @@ +# CMakeLists.txt for the ZoneMinder ONVIF modules. +# If this is an out-of-source build, copy the files we need to the binary directory +if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) +endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + +# MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt # Add build target for the perl modules -add_custom_target(zmonvifmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmonvifmodules ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") # Add install target for the perl modules -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") # Add additional files and directories to make clean set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl") diff --git a/onvif/proxy/CMakeLists.txt b/onvif/proxy/CMakeLists.txt index fece81d11..77201b1e1 100644 --- a/onvif/proxy/CMakeLists.txt +++ b/onvif/proxy/CMakeLists.txt @@ -1,10 +1,18 @@ +# CMakeLists.txt for the ZoneMinder ONVIF proxy module. +# If this is an out-of-source build, copy the files we need to the binary directory +if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) +endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + +# MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt # Add build target for the perl modules -add_custom_target(zmonvifproxy ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmonvifproxy ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") # Add install target for the perl modules -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") # Add additional files and directories to make clean set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl") diff --git a/scripts/ZoneMinder/CMakeLists.txt b/scripts/ZoneMinder/CMakeLists.txt index 003e4a616..cfbb993e4 100644 --- a/scripts/ZoneMinder/CMakeLists.txt +++ b/scripts/ZoneMinder/CMakeLists.txt @@ -25,7 +25,7 @@ endif(CMAKE_VERBOSE_MAKEFILE) # Add build target for the perl modules #add_custom_target(zmperlmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") -add_custom_target(zmperlmodules ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmperlmodules ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") # Add install target for the perl modules install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") From aeb348632234417530440e6fb06c7ea96843ab2e Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Fri, 10 Apr 2015 19:27:45 +1000 Subject: [PATCH 050/154] zmaudit.pl: convert to pod2usage --- scripts/zmaudit.pl.in | 62 ++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index f7bd18540..17fe93879 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -20,15 +20,33 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script checks for consistency between the event filesystem and -# the database. If events are found in one and not the other they are -# deleted (optionally). Additionally any monitor event directories that -# do not correspond to a database monitor are similarly disposed of. -# However monitors in the database that don't have a directory are left -# alone as this is valid if they are newly created and have no events -# yet. -# + +=head1 NAME + +zmaudit.pl - ZoneMinder event file system and database consistency checker + +=head1 SYNOPSIS + + zmaudit.pl [-r,-report|-i,-interactive] + +=head1 DESCRIPTION + +This script checks for consistency between the event filesystem and +the database. If events are found in one and not the other they are +deleted (optionally). Additionally any monitor event directories that +do not correspond to a database monitor are similarly disposed of. +However monitors in the database that don't have a directory are left +alone as this is valid if they are newly created and have no events +yet. + +=head1 OPTIONS + + -r, --report - Just report don't actually do anything + -i, --interactive - Ask before applying any changes + -c, --continuous - Run continuously + -v, --version - Print the installed version of ZoneMinder + +=cut use strict; use bytes; @@ -56,6 +74,7 @@ use POSIX; use File::Find; use Time::HiRes qw/gettimeofday/; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use constant IMAGE_PATH => $Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_IMAGES}; use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); @@ -71,19 +90,6 @@ my $interactive = 0; my $continuous = 0; my $version; -sub usage -{ - 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 --v, --version - Print the installed version of ZoneMinder -"); - exit( -1 ); -} - sub aud_print( $ ); sub confirm( ;$$ ); sub deleteSwapImage(); @@ -91,10 +97,12 @@ sub deleteSwapImage(); logInit(); logSetSignal(); -if ( !GetOptions( report=>\$report, interactive=>\$interactive, continuous=>\$continuous, version=>\$version ) ) -{ - usage(); -} +GetOptions( + 'report' =>\$report, + 'interactive' =>\$interactive, + 'continuous' =>\$continuous, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); if ( $version ) { print( ZoneMinder::Base::ZM_VERSION . "\n"); @@ -103,7 +111,7 @@ if ( $version ) { if ( ($report + $interactive + $continuous) > 1 ) { print( STDERR "Error, only one option may be specified\n" ); - usage(); + pod2usage(-exitstatus => -1); } my $dbh = zmDbConnect(); From 4bb8043fe5836ad34183804090f28b62fe87b040 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Fri, 10 Apr 2015 20:20:05 +1000 Subject: [PATCH 051/154] zmaudit.pl: PBP/5 + readability --- scripts/zmaudit.pl.in | 239 +++++++++++++++++++++++++++++------------- 1 file changed, 168 insertions(+), 71 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 17fe93879..2b05d5361 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -77,7 +77,10 @@ use Getopt::Long; use autouse 'Pod::Usage'=>qw(pod2usage); use constant IMAGE_PATH => $Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_IMAGES}; -use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); +use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|) + ? $Config{ZM_DIR_EVENTS} + : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) +; $| = 1; @@ -90,10 +93,6 @@ my $interactive = 0; my $continuous = 0; my $version; -sub aud_print( $ ); -sub confirm( ;$$ ); -sub deleteSwapImage(); - logInit(); logSetSignal(); @@ -105,8 +104,8 @@ GetOptions( ) or pod2usage(-exitstatus => -1); if ( $version ) { - print( ZoneMinder::Base::ZM_VERSION . "\n"); - exit(0); + print( ZoneMinder::Base::ZM_VERSION . "\n"); + exit(0); } if ( ($report + $interactive + $continuous) > 1 ) { @@ -126,31 +125,38 @@ my $swap_image_path = $Config{ZM_PATH_SWAP}; my $loop = 1; my $cleaned = 0; MAIN: while( $loop ) { - while ( ! ( $dbh and $dbh->ping() ) ) { - $dbh = zmDbConnect(); + while ( ! ( $dbh and $dbh->ping() ) ) { + $dbh = zmDbConnect(); - last if $dbh; - if ( $continuous ) { - # if we are running continuously, then just skip to the next interval, otherwise we are a one off run, so wait a second and retry until someone kills us. - sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); - } else { - sleep 1; - } # end if - } # end while can't connect to the db + last if $dbh; + if ( $continuous ) { + # if we are running continuously, then just skip to the next + # interval, otherwise we are a one off run, so wait a second and + # retry until someone kills us. + sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); + } else { + sleep 1; + } # end if + } # end while can't connect to the db - my $db_monitors; + 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 $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() ); $cleaned = 0; - my $res = $monitorSelectSth->execute() or Fatal( "Can't execute: ".$monitorSelectSth->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() ); + 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}; @@ -159,7 +165,7 @@ MAIN: while( $loop ) { } my $fs_monitors; - foreach my $monitor ( <[0-9]*> ) + foreach my $monitor ( glob("[0-9]*") ) { Debug( "Found filesystem monitor '$monitor'" ); my $fs_events = $fs_monitors->{$monitor} = {}; @@ -167,12 +173,13 @@ MAIN: while( $loop ) { if ( $Config{ZM_USE_DEEP_STORAGE} ) { - foreach my $day_dir ( <$monitor_dir/*/*/*> ) + foreach my $day_dir ( glob("$monitor_dir/*/*/*") ) { Debug( "Checking $day_dir" ); ( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint chdir( $day_dir ); - opendir( DIR, "." ) or Fatal( "Can't open directory '$day_dir': $!" ); + opendir( DIR, "." ) + or Fatal( "Can't open directory '$day_dir': $!" ); my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR ); closedir( DIR ); my $count = 0; @@ -264,7 +271,7 @@ MAIN: while( $loop ) { } my $monitor_links; - foreach my $link ( <*> ) + foreach my $link ( glob("*") ) { next if ( !-l $link ); next if ( -e $link ); @@ -282,13 +289,17 @@ MAIN: while( $loop ) { $cleaned = 0; my $deleteMonitorSql = "delete low_priority from Monitors where Id = ?"; - my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() ); + my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) + or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() ); my $deleteEventSql = "delete low_priority from Events where Id = ?"; - my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() ); + my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) + or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() ); my $deleteFramesSql = "delete low_priority from Frames where EventId = ?"; - my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() ); + my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) + or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() ); my $deleteStatsSql = "delete low_priority from Stats where EventId = ?"; - my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql ) or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() ); + 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} ) @@ -302,9 +313,12 @@ MAIN: while( $loop ) { 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 $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; } } @@ -317,7 +331,8 @@ MAIN: while( $loop ) { #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() ); + #my $res = $deleteMonitorSth->execute( $db_monitor ) + # or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() ); #$cleaned = 1; #} } @@ -326,15 +341,20 @@ MAIN: while( $loop ) { # 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() ); + 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() ); + $res = $deleteEventSth->execute( $event->{Id} ) + or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); $cleaned = 1; } } @@ -342,15 +362,19 @@ MAIN: while( $loop ) { # 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() ); + 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() ); + $res = $deleteEventSth->execute( $event->{Id} ) + or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); $cleaned = 1; } } @@ -358,15 +382,19 @@ MAIN: while( $loop ) { # 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() ); + 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() ); + $res = $deleteFramesSth->execute( $frame->{EventId} ) + or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); $cleaned = 1; } } @@ -374,32 +402,84 @@ MAIN: while( $loop ) { # 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() ); + 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() ); + $res = $deleteStatsSth->execute( $stat->{EventId} ) + or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); $cleaned = 1; } } 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 low_priority 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() ); + 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 low_priority 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() ); + $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() ); } } @@ -422,26 +502,43 @@ MAIN: while( $loop ) { if ( $Config{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 $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}; if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) { - my $deleteLogByRowsSql = "delete low_priority 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 - $Config{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() ); + my $deleteLogByRowsSql = "DELETE low_priority 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 - $Config{ZM_LOG_DATABASE_LIMIT} ) + or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() ); + if ( $deleteLogByRowsSth->rows() ) + { + aud_print( "Deleted ".$deleteLogByRowsSth->rows() + ." log table entries by count\n" ) + ; + } } } else { # Time of record - my $deleteLogByTimeSql = "delete low_priority from Logs where TimeKey < unix_timestamp(now() - interval ".$Config{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() ); + my $deleteLogByTimeSql = + "DELETE low_priority FROM Logs + WHERE TimeKey < unix_timestamp(now() - interval ".$Config{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() ); + if ( $deleteLogByTimeSth->rows() ){ + aud_print( "Deleted ".$deleteLogByTimeSth->rows() + ." log table entries by time\n" ) + ; + } } } $loop = $continuous; @@ -451,7 +548,7 @@ MAIN: while( $loop ) { exit( 0 ); -sub aud_print( $ ) +sub aud_print { my $string = shift; if ( !$continuous ) @@ -464,7 +561,7 @@ sub aud_print( $ ) } } -sub confirm( ;$$ ) +sub confirm { my $prompt = shift || "delete"; my $action = shift || "deleting"; @@ -504,7 +601,7 @@ sub confirm( ;$$ ) return( $yesno ); } -sub deleteSwapImage() +sub deleteSwapImage { my $file = $_; From 4dee542e99e13d9c5e61c4034a73f9469ba67b3a Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 00:07:36 +1000 Subject: [PATCH 052/154] zmcamtool.pl: tabs-to-spaces --- scripts/zmcamtool.pl.in | 424 ++++++++++++++++++++-------------------- 1 file changed, 212 insertions(+), 212 deletions(-) diff --git a/scripts/zmcamtool.pl.in b/scripts/zmcamtool.pl.in index cb4e036a9..d20fc9331 100644 --- a/scripts/zmcamtool.pl.in +++ b/scripts/zmcamtool.pl.in @@ -59,50 +59,50 @@ my $version = 0; # Process commandline parameters with getopt long if ( !GetOptions( 'export'=>\$export, 'import'=>\$import, 'overwrite'=>\$overwrite, 'help'=>\$help, 'topreset'=>\$topreset, 'noregex'=>\$noregex, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'version'=>\$version ) ) { - Usage(); + Usage(); } $Config{ZM_DB_USER} = $dbUser; $Config{ZM_DB_PASS} = $dbPass; if ( $version ) { - print( ZoneMinder::Base::ZM_VERSION . "\n"); - exit(0); + print( ZoneMinder::Base::ZM_VERSION . "\n"); + exit(0); } # Check to make sure commandline params make sense if ( ((!$help) && ($import + $export + $topreset) != 1 )) { - print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); - Usage(); + print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); + Usage(); } if ( ($export)&&($overwrite) ) { - print( "Warning: Overwrite parameter ignored during an export.\n"); + print( "Warning: Overwrite parameter ignored during an export.\n"); } if ( ($noregex)&&(!$topreset) ) { - print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/); + print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/); } if ( ($topreset)&&($ARGV[0] !~ /\d\d*/) ) { - print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); - Usage(); + print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); + Usage(); } # Call the appropriate subroutine based on the params given on the commandline if ($help) { - Usage(); + Usage(); } if ($export) { - exportsql(); + exportsql(); } if ($import) { - importsql(); + importsql(); } if ($topreset) { - toPreset(); + toPreset(); } ############### @@ -115,23 +115,23 @@ sub Usage die(" USAGE: zmcamtool.pl [--user= --pass=] - [--import [file.sql] [--overwrite]] - [--export [name]] - [--topreset id [--noregex]] + [--import [file.sql] [--overwrite]] + [--export [name]] + [--topreset id [--noregex]] PARAMETERS: --export - Export all camera controls and presets to STDOUT. - Optionally specify a control or preset name. + Optionally specify a control or preset name. --import [file.sql] - Import new camera controls and presets found in - zm_create.sql into the ZoneMinder dB. - Optionally specify an alternate sql file to read from. + zm_create.sql into the ZoneMinder dB. + Optionally specify an alternate sql file to read from. --overwrite - Overwrite any existing controls or presets. - with the same name as the new controls or presets. + with the same name as the new controls or presets. --topreset id - Copy a monitor to a Camera Preset given the monitor id. ---noregex - Do not try to find and replace fields such as usernames, - passwords, ip addresses, etc with generic placeholders - when converting a monitor to a preset. ---help - Print usage information. +--noregex - Do not try to find and replace fields such as usernames, + passwords, ip addresses, etc with generic placeholders + when converting a monitor to a preset. +--help - Print usage information. --user= - Alternate dB user with privileges to alter dB. --pass= - Password of alternate dB user with privileges to alter dB. \n"); @@ -140,173 +140,173 @@ PARAMETERS: # Execute a pre-built sql select query sub selectQuery { - my $dbh = shift; - my $sql = shift; - my $monitorid = shift; + my $dbh = shift; + my $sql = shift; + my $monitorid = shift; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($monitorid) or die( "Can't execute: ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($monitorid) or die( "Can't execute: ".$sth->errstr() ); - my @data = $sth->fetchrow_array(); - $sth->finish(); + my @data = $sth->fetchrow_array(); + $sth->finish(); - return @data; + return @data; } # Exectute a pre-built sql query sub runQuery { - my $dbh = shift; - my $sql = shift; - 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() ); - $sth->finish(); + my $dbh = shift; + my $sql = shift; + 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() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql insert query sub insertQuery { - my $dbh = shift; - my $tablename = shift; - my @data = @_; + my $dbh = shift; + my $tablename = shift; + my @data = @_; - my $sql = "insert into $tablename values (NULL,".(join ", ", ("?") x @data).")"; # Add "?" for each array element + my $sql = "insert into $tablename values (NULL,".(join ", ", ("?") x @data).")"; # Add "?" for each array element - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute(@data) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute(@data) or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql delete query sub deleteQuery { - my $dbh = shift; - my $sqltable = shift; - my $sqlname = shift; + my $dbh = shift; + my $sqltable = shift; + my $sqlname = shift; - my $sql = "delete from $sqltable where Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + my $sql = "delete from $sqltable where Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql select count query sub checkExists { - my $dbh = shift; - my $sqltable = shift; - my $sqlname = shift; - my $result = 0; + my $dbh = shift; + my $sqltable = shift; + my $sqlname = shift; + my $result = 0; - my $sql = "select count(*) from $sqltable where Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); + my $sql = "select count(*) from $sqltable where Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); - my $rows = $sth->fetchrow_arrayref(); - $sth->finish(); + my $rows = $sth->fetchrow_arrayref(); + $sth->finish(); - if ($rows->[0] > 0) { - $result = 1; - } + if ($rows->[0] > 0) { + $result = 1; + } - return $result; + return $result; } # Import camera control & presets into the zoneminder dB sub importsql { - my @newcontrols; - my @overwritecontrols; - my @skippedcontrols; - my @newpresets; - my @overwritepresets; - my @skippedpresets; - my %controls; - my %monitorpresets; + my @newcontrols; + my @overwritecontrols; + my @skippedcontrols; + my @newpresets; + my @overwritepresets; + my @skippedpresets; + my %controls; + my %monitorpresets; - if ($ARGV[0]) { - $sqlfile = $ARGV[0]; - } else { - $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; - } + if ($ARGV[0]) { + $sqlfile = $ARGV[0]; + } else { + $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; + } - open(my $SQLFILE,"<",$sqlfile) or die( "Can't Open file: $!\n" ); + open(my $SQLFILE,"<",$sqlfile) or die( "Can't Open file: $!\n" ); - # Find and extract ptz control and monitor preset records - while (<$SQLFILE>) { - # Our regex replaces the primary key with NULL - if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { - $controls{$3} = $_; - } elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { - $monitorpresets{$3} = $_; - } - } - close $SQLFILE; + # Find and extract ptz control and monitor preset records + while (<$SQLFILE>) { + # Our regex replaces the primary key with NULL + if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { + $controls{$3} = $_; + } elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { + $monitorpresets{$3} = $_; + } + } + close $SQLFILE; - if ( ! (%controls || %monitorpresets) ) { - die( "Error: No relevant data found in $sqlfile.\n" ); - } + if ( ! (%controls || %monitorpresets) ) { + die( "Error: No relevant data found in $sqlfile.\n" ); + } - # Now that we've got what we were looking for, compare to what is already in the dB + # Now that we've got what we were looking for, compare to what is already in the dB - my $dbh = zmDbConnect(); - foreach (keys %controls) { - if (!checkExists($dbh,"Controls",$_)) { - # No existing Control was found. Add new control to dB. - runQuery($dbh,$controls{$_}); - push @newcontrols, $_; - } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. Overwrite the control. - deleteQuery($dbh,"Controls",$_); - runQuery($dbh,$controls{$_}); - push @overwritecontrols, $_; - } else { - # An existing Control was found and the overwrite flag was not set. Do nothing. - push @skippedcontrols, $_; - } - } + my $dbh = zmDbConnect(); + foreach (keys %controls) { + if (!checkExists($dbh,"Controls",$_)) { + # No existing Control was found. Add new control to dB. + runQuery($dbh,$controls{$_}); + push @newcontrols, $_; + } elsif ($overwrite) { + # An existing Control was found and the overwrite flag is set. Overwrite the control. + deleteQuery($dbh,"Controls",$_); + runQuery($dbh,$controls{$_}); + push @overwritecontrols, $_; + } else { + # An existing Control was found and the overwrite flag was not set. Do nothing. + push @skippedcontrols, $_; + } + } - foreach (keys %monitorpresets) { - if (!checkExists($dbh,"MonitorPresets",$_)) { - # No existing MonitorPreset was found. Add new MonitorPreset to dB. - runQuery($dbh,$monitorpresets{$_}); - push @newpresets, $_; - } elsif ($overwrite) { - # An existing MonitorPreset was found and the overwrite flag is set. Overwrite the MonitorPreset. - deleteQuery($dbh,"MonitorPresets",$_); - runQuery($dbh,$monitorpresets{$_}); - push @overwritepresets, $_; - } else { - # An existing MonitorPreset was found and the overwrite flag was not set. Do nothing. - push @skippedpresets, $_; - } - } + foreach (keys %monitorpresets) { + if (!checkExists($dbh,"MonitorPresets",$_)) { + # No existing MonitorPreset was found. Add new MonitorPreset to dB. + runQuery($dbh,$monitorpresets{$_}); + push @newpresets, $_; + } elsif ($overwrite) { + # An existing MonitorPreset was found and the overwrite flag is set. Overwrite the MonitorPreset. + deleteQuery($dbh,"MonitorPresets",$_); + runQuery($dbh,$monitorpresets{$_}); + push @overwritepresets, $_; + } else { + # An existing MonitorPreset was found and the overwrite flag was not set. Do nothing. + push @skippedpresets, $_; + } + } - if (@newcontrols) { - print "Number of ptz camera controls added: ".scalar(@newcontrols)."\n"; - } - if (@overwritecontrols) { - print "Number of existing ptz camera controls overwritten: ".scalar(@overwritecontrols)."\n"; - } - if (@skippedcontrols) { - print "Number of existing ptz camera controls skipped: ".scalar(@skippedcontrols)."\n"; - } + if (@newcontrols) { + print "Number of ptz camera controls added: ".scalar(@newcontrols)."\n"; + } + if (@overwritecontrols) { + print "Number of existing ptz camera controls overwritten: ".scalar(@overwritecontrols)."\n"; + } + if (@skippedcontrols) { + print "Number of existing ptz camera controls skipped: ".scalar(@skippedcontrols)."\n"; + } - if (@newpresets) { - print "Number of monitor presets added: ".scalar(@newpresets)."\n"; - } - if (@overwritepresets) { - print "Number of existing monitor presets overwritten: ".scalar(@overwritepresets)."\n"; - } - if (@skippedpresets) { - print "Number of existing presets skipped: ".scalar(@skippedpresets)."\n"; - } + if (@newpresets) { + print "Number of monitor presets added: ".scalar(@newpresets)."\n"; + } + if (@overwritepresets) { + print "Number of existing monitor presets overwritten: ".scalar(@overwritepresets)."\n"; + } + if (@skippedpresets) { + print "Number of existing presets skipped: ".scalar(@skippedpresets)."\n"; + } } # Export camera controls & presets from the zoneminder dB to STDOUT @@ -317,14 +317,14 @@ my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my $command = "mysqldump -t --skip-opt --compact -h".$host; $command .= " -P".$port if defined($port); if ( $dbUser ) { - $command .= " -u".$dbUser; - if ( $dbPass ) { - $command .= " -p".$dbPass; - } - } + $command .= " -u".$dbUser; + if ( $dbPass ) { + $command .= " -p".$dbPass; + } + } if ($ARGV[0]) { - $command .= qq( --where="Name = '$ARGV[0]'"); + $command .= qq( --where="Name = '$ARGV[0]'"); } $command .= " zm Controls MonitorPresets"; @@ -332,78 +332,78 @@ $command .= " zm Controls MonitorPresets"; my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { - chomp( $output ); - print( "Output: $output\n" ); + chomp( $output ); + print( "Output: $output\n" ); } if ( $status ) { - die( "Command '$command' exited with status: $status\n" ); + die( "Command '$command' exited with status: $status\n" ); } else { - # NULLify the primary keys before printing the output to STDOUT - $output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig; - print $output; - } + # NULLify the primary keys before printing the output to STDOUT + $output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig; + print $output; + } } sub toPreset { - my $dbh = zmDbConnect(); - my $monitorid = $ARGV[0]; + my $dbh = zmDbConnect(); + my $monitorid = $ARGV[0]; - # Grap the following fields from the Monitors table - my $sql = "select - Name, - Type, - Device, - Channel, - Format, - Protocol, - Method, - Host, - Port, - Path, - SubPath, - Width, - Height, - Palette, - MaxFPS, - Controllable, - ControlId, - ControlDevice, - ControlAddress, - DefaultRate, - DefaultScale - from Monitors where Id = ?"; - my @data = selectQuery($dbh,$sql,$monitorid); + # Grap the following fields from the Monitors table + my $sql = "select + Name, + Type, + Device, + Channel, + Format, + Protocol, + Method, + Host, + Port, + Path, + SubPath, + Width, + Height, + Palette, + MaxFPS, + Controllable, + ControlId, + ControlDevice, + ControlAddress, + DefaultRate, + DefaultScale + from Monitors where Id = ?"; + my @data = selectQuery($dbh,$sql,$monitorid); - if (!@data) { - die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); - } + if (!@data) { + die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); + } - # Attempt to search for and replace system specific values such as ip addresses, ports, usernames, etc. with generic placeholders - if (!$noregex) { - foreach (@data) { - s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address - s/:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/:/; # tcpip port - s/\/\/.*:.*@/\/\/:@/; # user & pwd preceeding an ip address - s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=$3/i; # username embeded in url - s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=$3/i; # password embeded in url - s/\w\w*:\w\w*/:/; # user & pwd in their own field - s/\/dev\/video\d\d*/\/dev\/video/; # local video devices - } - } + # Attempt to search for and replace system specific values such as ip addresses, ports, usernames, etc. with generic placeholders + if (!$noregex) { + foreach (@data) { + s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address + s/:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/:/; # tcpip port + s/\/\/.*:.*@/\/\/:@/; # user & pwd preceeding an ip address + s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=$3/i; # username embeded in url + s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=$3/i; # password embeded in url + s/\w\w*:\w\w*/:/; # user & pwd in their own field + s/\/dev\/video\d\d*/\/dev\/video/; # local video devices + } + } - if (!checkExists($dbh,"MonitorPresets",$data[0])) { - # No existing Preset was found. Add new Preset to dB. - print "Adding new preset: $data[0]\n"; - insertQuery($dbh,"MonitorPresets",@data); - } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. Overwrite the control. - print "Existing preset $data[0] detected.\nOverwriting...\n"; - deleteQuery($dbh,"MonitorPresets",$data[0]); - insertQuery($dbh,"MonitorPresets",@data); - } else { - # An existing Control was found and the overwrite flag was not set. Do nothing. - print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; - } + if (!checkExists($dbh,"MonitorPresets",$data[0])) { + # No existing Preset was found. Add new Preset to dB. + print "Adding new preset: $data[0]\n"; + insertQuery($dbh,"MonitorPresets",@data); + } elsif ($overwrite) { + # An existing Control was found and the overwrite flag is set. Overwrite the control. + print "Existing preset $data[0] detected.\nOverwriting...\n"; + deleteQuery($dbh,"MonitorPresets",$data[0]); + insertQuery($dbh,"MonitorPresets",@data); + } else { + # An existing Control was found and the overwrite flag was not set. Do nothing. + print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; + } } From 90fa57788ae2a21eda5a5591feae519b2c2c611f Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 00:23:43 +1000 Subject: [PATCH 053/154] zmcamtool.pl: pod2usage --- scripts/zmcamtool.pl.in | 93 +++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/scripts/zmcamtool.pl.in b/scripts/zmcamtool.pl.in index d20fc9331..71e45362e 100644 --- a/scripts/zmcamtool.pl.in +++ b/scripts/zmcamtool.pl.in @@ -20,12 +20,43 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script provides a way to import new ptz camera controls & camera presets -# into existing zoneminder systems. This script also provides a way to export -# ptz camera controls & camera presets from an existing zoneminder system into -# a sql file, which can then be easily imported to another zoneminder system. -# + +=head1 NAME + +zmcamtool.pl - ZoneMinder tool to import camera controls and presets + +=head1 SYNOPSIS + + zmcamtool.pl [--user= --pass=] + [--import [file.sql] [--overwrite]] + [--export [name]] + [--topreset id [--noregex]] + +=head1 DESCRIPTION + +This script provides a way to import new ptz camera controls & camera presets +into existing zoneminder systems. This script also provides a way to export +ptz camera controls & camera presets from an existing zoneminder system into +a sql file, which can then be easily imported to another zoneminder system. + +=head1 OPTIONS + + --export - Export all camera controls and presets to STDOUT. + Optionally specify a control or preset name. + --import [file.sql] - Import new camera controls and presets found in + zm_create.sql into the ZoneMinder dB. + Optionally specify an alternate sql file to read from. + --overwrite - Overwrite any existing controls or presets. + with the same name as the new controls or presets. + --topreset id - Copy a monitor to a Camera Preset given the monitor id. + --noregex - Do not try to find and replace fields such as usernames, + passwords, IP addresses, etc with generic placeholders + when converting a monitor to a preset. + --help - Print usage information. + --user= - Alternate dB user with privileges to alter dB. + --pass= - Password of alternate dB user with privileges to alter dB. + +=cut use strict; use bytes; @@ -35,6 +66,7 @@ use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); use DBI; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; @@ -57,10 +89,17 @@ my $dbUser = $Config{ZM_DB_USER}; my $dbPass = $Config{ZM_DB_PASS}; my $version = 0; -# Process commandline parameters with getopt long -if ( !GetOptions( 'export'=>\$export, 'import'=>\$import, 'overwrite'=>\$overwrite, 'help'=>\$help, 'topreset'=>\$topreset, 'noregex'=>\$noregex, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'version'=>\$version ) ) { - Usage(); -} +GetOptions( + 'export' =>\$export, + 'import' =>\$import, + 'overwrite' =>\$overwrite, + 'help' =>\$help, + 'topreset' =>\$topreset, + 'noregex' =>\$noregex, + 'user:s' =>\$dbUser, + 'pass:s' =>\$dbPass, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); $Config{ZM_DB_USER} = $dbUser; $Config{ZM_DB_PASS} = $dbPass; @@ -72,7 +111,7 @@ if ( $version ) { # Check to make sure commandline params make sense if ( ((!$help) && ($import + $export + $topreset) != 1 )) { print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); - Usage(); + pod2usage(-exitstatus => -1); } if ( ($export)&&($overwrite) ) { @@ -85,12 +124,12 @@ if ( ($noregex)&&(!$topreset) ) { if ( ($topreset)&&($ARGV[0] !~ /\d\d*/) ) { print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); - Usage(); + pod2usage(-exitstatus => -1); } # Call the appropriate subroutine based on the params given on the commandline if ($help) { - Usage(); + pod2usage(-exitstatus => -1); } if ($export) { @@ -109,34 +148,6 @@ if ($topreset) { # SUBROUTINES # ############### -# Usage subroutine help text -sub Usage -{ -die(" -USAGE: -zmcamtool.pl [--user= --pass=] - [--import [file.sql] [--overwrite]] - [--export [name]] - [--topreset id [--noregex]] - -PARAMETERS: ---export - Export all camera controls and presets to STDOUT. - Optionally specify a control or preset name. ---import [file.sql] - Import new camera controls and presets found in - zm_create.sql into the ZoneMinder dB. - Optionally specify an alternate sql file to read from. ---overwrite - Overwrite any existing controls or presets. - with the same name as the new controls or presets. ---topreset id - Copy a monitor to a Camera Preset given the monitor id. ---noregex - Do not try to find and replace fields such as usernames, - passwords, ip addresses, etc with generic placeholders - when converting a monitor to a preset. ---help - Print usage information. ---user= - Alternate dB user with privileges to alter dB. ---pass= - Password of alternate dB user with privileges to alter dB. -\n"); -} - # Execute a pre-built sql select query sub selectQuery { From 53907eeba18264917f0b6ddb488708609096fbee Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 00:34:46 +1000 Subject: [PATCH 054/154] zmcamtool.pl: readability --- scripts/zmcamtool.pl.in | 88 ++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/scripts/zmcamtool.pl.in b/scripts/zmcamtool.pl.in index 71e45362e..eaa32edef 100644 --- a/scripts/zmcamtool.pl.in +++ b/scripts/zmcamtool.pl.in @@ -155,8 +155,10 @@ sub selectQuery my $sql = shift; my $monitorid = shift; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($monitorid) or die( "Can't execute: ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($monitorid) + or die( "Can't execute: ".$sth->errstr() ); my @data = $sth->fetchrow_array(); $sth->finish(); @@ -169,8 +171,10 @@ sub runQuery { my $dbh = shift; my $sql = shift; - 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 $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); return $res; @@ -183,10 +187,13 @@ sub insertQuery my $tablename = shift; my @data = @_; - my $sql = "insert into $tablename values (NULL,".(join ", ", ("?") x @data).")"; # Add "?" for each array element + my $sql = "INSERT INTO $tablename VALUES (NULL," + .(join ", ", ("?") x @data).")"; # Add "?" for each array element - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute(@data) or die( "Can't execute: ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute(@data) + or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); return $res; @@ -199,9 +206,11 @@ sub deleteQuery my $sqltable = shift; my $sqlname = shift; - my $sql = "delete from $sqltable where Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); + my $sql = "DELETE FROM $sqltable WHERE Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) + or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); return $res; @@ -215,9 +224,11 @@ sub checkExists my $sqlname = shift; my $result = 0; - my $sql = "select count(*) from $sqltable where Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); + my $sql = "SELECT count(*) FROM $sqltable WHERE Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) + or die( "Can't execute: ".$sth->errstr() ); my $rows = $sth->fetchrow_arrayref(); $sth->finish(); @@ -247,7 +258,8 @@ sub importsql $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; } - open(my $SQLFILE,"<",$sqlfile) or die( "Can't Open file: $!\n" ); + open(my $SQLFILE,"<",$sqlfile) + or die( "Can't Open file: $!\n" ); # Find and extract ptz control and monitor preset records while (<$SQLFILE>) { @@ -264,21 +276,24 @@ sub importsql die( "Error: No relevant data found in $sqlfile.\n" ); } - # Now that we've got what we were looking for, compare to what is already in the dB + # Now that we've got what we were looking for, + # compare to what is already in the dB my $dbh = zmDbConnect(); foreach (keys %controls) { if (!checkExists($dbh,"Controls",$_)) { - # No existing Control was found. Add new control to dB. + # No existing Control was found. Add new control to dB. runQuery($dbh,$controls{$_}); push @newcontrols, $_; } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. Overwrite the control. + # An existing Control was found and the overwrite flag is set. + # Overwrite the control. deleteQuery($dbh,"Controls",$_); runQuery($dbh,$controls{$_}); push @overwritecontrols, $_; } else { - # An existing Control was found and the overwrite flag was not set. Do nothing. + # An existing Control was found and the overwrite flag was not set. + # Do nothing. push @skippedcontrols, $_; } } @@ -289,34 +304,42 @@ sub importsql runQuery($dbh,$monitorpresets{$_}); push @newpresets, $_; } elsif ($overwrite) { - # An existing MonitorPreset was found and the overwrite flag is set. Overwrite the MonitorPreset. + # An existing MonitorPreset was found and the overwrite flag is set. + # Overwrite the MonitorPreset. deleteQuery($dbh,"MonitorPresets",$_); runQuery($dbh,$monitorpresets{$_}); push @overwritepresets, $_; } else { - # An existing MonitorPreset was found and the overwrite flag was not set. Do nothing. + # An existing MonitorPreset was found and the overwrite flag was + # not set. Do nothing. push @skippedpresets, $_; } } if (@newcontrols) { - print "Number of ptz camera controls added: ".scalar(@newcontrols)."\n"; + print "Number of ptz camera controls added: " + .scalar(@newcontrols)."\n"; } if (@overwritecontrols) { - print "Number of existing ptz camera controls overwritten: ".scalar(@overwritecontrols)."\n"; + print "Number of existing ptz camera controls overwritten: " + .scalar(@overwritecontrols)."\n"; } if (@skippedcontrols) { - print "Number of existing ptz camera controls skipped: ".scalar(@skippedcontrols)."\n"; + print "Number of existing ptz camera controls skipped: " + .scalar(@skippedcontrols)."\n"; } if (@newpresets) { - print "Number of monitor presets added: ".scalar(@newpresets)."\n"; + print "Number of monitor presets added: " + .scalar(@newpresets)."\n"; } if (@overwritepresets) { - print "Number of existing monitor presets overwritten: ".scalar(@overwritepresets)."\n"; + print "Number of existing monitor presets overwritten: " + .scalar(@overwritepresets)."\n"; } if (@skippedpresets) { - print "Number of existing presets skipped: ".scalar(@skippedpresets)."\n"; + print "Number of existing presets skipped: " + .scalar(@skippedpresets)."\n"; } } @@ -361,7 +384,7 @@ sub toPreset my $monitorid = $ARGV[0]; # Grap the following fields from the Monitors table - my $sql = "select + my $sql = "SELECT Name, Type, Device, @@ -383,14 +406,15 @@ sub toPreset ControlAddress, DefaultRate, DefaultScale - from Monitors where Id = ?"; + FROM Monitors WHERE Id = ?"; my @data = selectQuery($dbh,$sql,$monitorid); if (!@data) { die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); } - # Attempt to search for and replace system specific values such as ip addresses, ports, usernames, etc. with generic placeholders + # Attempt to search for and replace system specific values such as + # ip addresses, ports, usernames, etc. with generic placeholders if (!$noregex) { foreach (@data) { s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address @@ -408,12 +432,14 @@ sub toPreset print "Adding new preset: $data[0]\n"; insertQuery($dbh,"MonitorPresets",@data); } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. Overwrite the control. + # An existing Control was found and the overwrite flag is set. + # Overwrite the control. print "Existing preset $data[0] detected.\nOverwriting...\n"; deleteQuery($dbh,"MonitorPresets",$data[0]); insertQuery($dbh,"MonitorPresets",@data); } else { - # An existing Control was found and the overwrite flag was not set. Do nothing. + # An existing Control was found and the overwrite flag was not set. + # Do nothing. print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; } } From 0cf82a0b71cd2ada18b2e388cc3ee62fc0beacf9 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 10 Apr 2015 12:09:01 -0500 Subject: [PATCH 055/154] Allow user to override perl installation. Replace old perl cmake vars with new. --- CMakeLists.txt | 12 ++++++++---- INSTALL | 4 ++-- distros/debian_cmake/rules | 1 - distros/fedora/archive/zoneminder.cmake.f19.spec | 1 - distros/fedora/zoneminder.f20.spec | 1 - distros/fedora/zoneminder.f21.spec | 1 - distros/redhat/zoneminder.el6.spec | 2 +- distros/redhat/zoneminder.el7.spec | 1 - onvif/modules/CMakeLists.txt | 2 +- onvif/proxy/CMakeLists.txt | 2 +- scripts/ZoneMinder/CMakeLists.txt | 3 +-- 11 files changed, 14 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef04e1fba..1296d6cc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ include (CheckTypeSize) include (CheckStructHasMember) # Configuration options -mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP CMAKE_INSTALL_FULL_BINDIR ZM_PERL_SUBPREFIX ZM_PERL_USE_PATH ZM_TARGET_DISTRO ZM_CONFIG_DIR) +mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP CMAKE_INSTALL_FULL_BINDIR ZM_PERL_MM_PARMS ZM_PERL_SEARCH_PATH ZM_TARGET_DISTRO ZM_CONFIG_DIR) set(ZM_RUNDIR "/var/run/zm" CACHE PATH "Location of transient process files, default: /var/run/zm") set(ZM_SOCKDIR "/var/run/zm" CACHE PATH "Location of Unix domain socket files, default /var/run/zm") set(ZM_TMPDIR "/var/tmp/zm" CACHE PATH "Location of temporary files, default: /tmp/zm") @@ -68,8 +68,8 @@ set(ZM_NO_LIBVLC "OFF" CACHE BOOL "Set to ON to skip libvlc checks and force bui set(ZM_NO_CURL "OFF" CACHE BOOL "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF") set(ZM_NO_X10 "OFF" CACHE BOOL "Set to ON to build ZoneMinder without X10 support. default: OFF") set(ZM_ONVIF "OFF" CACHE BOOL "Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not work with all cameras claiming to be ONVIF compliant. default: OFF") -set(ZM_PERL_SUBPREFIX "${CMAKE_INSTALL_LIBDIR}/perl5" CACHE PATH "Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. lib will be turned into /lib, default: /perl5") -set(ZM_PERL_USE_PATH "${CMAKE_INSTALL_PREFIX}/${ZM_PERL_SUBPREFIX}" CACHE PATH "Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: /") +set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING "By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal serach path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly.") +set(ZM_PERL_SEARCH_PATH "" CACHE PATH "Used to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path.") set(ZM_TARGET_DISTRO "" CACHE STRING "Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f20, el6, OS13") # Reassign some variables if a target distro has been specified @@ -524,7 +524,11 @@ set(CGI_PREFIX "${ZM_CGIDIR}") set(WEB_USER "${ZM_WEB_USER}") set(WEB_GROUP "${ZM_WEB_GROUP}") set(ZM_DB_TYPE "mysql") -set(EXTRA_PERL_LIB "use lib '${ZM_PERL_USE_PATH}';") +if(ZM_PERL_SEARCH_PATH) + set(EXTRA_PERL_LIB "use lib '${ZM_PERL_SEARCH_PATH}'; # Include custom perl install path") +else(ZM_PERL_SEARCH_PATH) + set(EXTRA_PERL_LIB "# Include from system perl paths only") +endif(ZM_PERL_SEARCH_PATH) # Generate files from the .in files configure_file(zm.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" @ONLY) diff --git a/INSTALL b/INSTALL index 6d329bcd4..b6c231c4a 100644 --- a/INSTALL +++ b/INSTALL @@ -53,8 +53,8 @@ Advanced: ZM_NO_MMAP Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF ZM_NO_FFMPEG Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF ZM_NO_X10 Set to ON to build ZoneMinder without X10 support. default: OFF - ZM_PERL_SUBPREFIX Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. /lib will be turned into /lib, default: /perl5 - ZM_PERL_USE_PATH Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: / + ZM_PERL_MM_PARMS By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal serach path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly. default: "INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1" + ZM_PERL_SEARCH_PATH Use to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path. default: "" Useful configuration options provided by cmake: CMAKE_VERBOSE_MAKEFILE - Set this to ON (default OFF) to see what cmake is doing. Very useful for troubleshooting. diff --git a/distros/debian_cmake/rules b/distros/debian_cmake/rules index 0bf0f3362..aa0501ab1 100755 --- a/distros/debian_cmake/rules +++ b/distros/debian_cmake/rules @@ -22,7 +22,6 @@ override_dh_auto_configure: -DZM_CGIDIR=/usr/lib/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ - -DZM_PERL_SUBPREFIX=/share/perl5 \ -DCMAKE_INSTALL_SYSCONFDIR=etc/zm override_dh_auto_install: diff --git a/distros/fedora/archive/zoneminder.cmake.f19.spec b/distros/fedora/archive/zoneminder.cmake.f19.spec index a7aee3265..771209247 100644 --- a/distros/fedora/archive/zoneminder.cmake.f19.spec +++ b/distros/fedora/archive/zoneminder.cmake.f19.spec @@ -72,7 +72,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="f19" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ %{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \ %{?_without_x10:-DZM_NO_X10=ON} \ . diff --git a/distros/fedora/zoneminder.f20.spec b/distros/fedora/zoneminder.f20.spec index a49361ef3..17023fb7b 100644 --- a/distros/fedora/zoneminder.f20.spec +++ b/distros/fedora/zoneminder.f20.spec @@ -76,7 +76,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="f20" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ %{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \ %{?_without_x10:-DZM_NO_X10=ON} \ . diff --git a/distros/fedora/zoneminder.f21.spec b/distros/fedora/zoneminder.f21.spec index 31afc0417..e2fb17ec3 100644 --- a/distros/fedora/zoneminder.f21.spec +++ b/distros/fedora/zoneminder.f21.spec @@ -76,7 +76,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="f21" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ %{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \ %{?_without_x10:-DZM_NO_X10=ON} \ . diff --git a/distros/redhat/zoneminder.el6.spec b/distros/redhat/zoneminder.el6.spec index 8ca8415dd..e50db96e7 100644 --- a/distros/redhat/zoneminder.el6.spec +++ b/distros/redhat/zoneminder.el6.spec @@ -73,7 +73,7 @@ too much degradation of performance. %build # Have to override CMAKE_INSTALL_LIBDIR for cmake < 2.8.7 due to this bug: # https://bugzilla.redhat.com/show_bug.cgi?id=795542 -%cmake -DZM_TARGET_DISTRO="el6" -DCMAKE_INSTALL_LIBDIR:PATH=%{_lib} -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` . +%cmake -DZM_TARGET_DISTRO="el6" -DCMAKE_INSTALL_LIBDIR:PATH=%{_lib} . make %{?_smp_mflags} diff --git a/distros/redhat/zoneminder.el7.spec b/distros/redhat/zoneminder.el7.spec index b21a3901d..158c044a4 100644 --- a/distros/redhat/zoneminder.el7.spec +++ b/distros/redhat/zoneminder.el7.spec @@ -69,7 +69,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="el7" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ . make %{?_smp_mflags} diff --git a/onvif/modules/CMakeLists.txt b/onvif/modules/CMakeLists.txt index 9e94f3f7b..9e46ef9f7 100644 --- a/onvif/modules/CMakeLists.txt +++ b/onvif/modules/CMakeLists.txt @@ -9,7 +9,7 @@ endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) # MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt # Add build target for the perl modules -add_custom_target(zmonvifmodules ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") +add_custom_target(zmonvifmodules ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") # Add install target for the perl modules install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") diff --git a/onvif/proxy/CMakeLists.txt b/onvif/proxy/CMakeLists.txt index 77201b1e1..0051bf2b1 100644 --- a/onvif/proxy/CMakeLists.txt +++ b/onvif/proxy/CMakeLists.txt @@ -9,7 +9,7 @@ endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) # MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt # Add build target for the perl modules -add_custom_target(zmonvifproxy ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") +add_custom_target(zmonvifproxy ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") # Add install target for the perl modules install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") diff --git a/scripts/ZoneMinder/CMakeLists.txt b/scripts/ZoneMinder/CMakeLists.txt index cfbb993e4..09c02b816 100644 --- a/scripts/ZoneMinder/CMakeLists.txt +++ b/scripts/ZoneMinder/CMakeLists.txt @@ -24,8 +24,7 @@ else(CMAKE_VERBOSE_MAKEFILE) endif(CMAKE_VERBOSE_MAKEFILE) # Add build target for the perl modules -#add_custom_target(zmperlmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") -add_custom_target(zmperlmodules ALL perl Makefile.PL INSTALLDIRS=vendor FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" NO_PACKLIST=1 NO_PERLLOCAL=1 ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmperlmodules ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") # Add install target for the perl modules install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") From fa633bff922aaeec36fe5fb74328ebcbb8ed1090 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 10 Apr 2015 12:17:06 -0500 Subject: [PATCH 056/154] spelling --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1296d6cc8..a76f8fbb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,8 +68,8 @@ set(ZM_NO_LIBVLC "OFF" CACHE BOOL "Set to ON to skip libvlc checks and force bui set(ZM_NO_CURL "OFF" CACHE BOOL "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF") set(ZM_NO_X10 "OFF" CACHE BOOL "Set to ON to build ZoneMinder without X10 support. default: OFF") set(ZM_ONVIF "OFF" CACHE BOOL "Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not work with all cameras claiming to be ONVIF compliant. default: OFF") -set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING "By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal serach path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly.") -set(ZM_PERL_SEARCH_PATH "" CACHE PATH "Used to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path.") +set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING "By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal search path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly.") +set(ZM_PERL_SEARCH_PATH "" CACHE PATH "Use to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path.") set(ZM_TARGET_DISTRO "" CACHE STRING "Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f20, el6, OS13") # Reassign some variables if a target distro has been specified From 065a372678015750b483afa0d689d916bf453c29 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2015 13:26:17 -0400 Subject: [PATCH 057/154] one small fix for a log line where the 4th parameter wasn't included. The rest are very small optimisations. --- src/zm_image.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index be5a50ce3..956da6f08 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -104,13 +104,13 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin pixels = width*height; colours = p_colours; subpixelorder = p_subpixelorder; - size = (width*height)*colours; + size = pixels*colours; buffer = 0; holdbuffer = 0; if ( p_buffer ) { - allocation = size; - buffertype = ZM_BUFTYPE_DONTFREE; + allocation = size; + buffertype = ZM_BUFTYPE_DONTFREE; buffer = p_buffer; } else @@ -129,10 +129,10 @@ Image::Image( const Image &p_image ) pixels = p_image.pixels; colours = p_image.colours; subpixelorder = p_image.subpixelorder; - size = allocation = p_image.size; + size = p_image.size; // allocation is set in AllocImgBuffer buffer = 0; holdbuffer = 0; - AllocImgBuffer(allocation); + AllocImgBuffer(size); (*fptr_imgbufcpy)(buffer, p_image.buffer, size); strncpy( text, p_image.text, sizeof(text) ); } @@ -331,7 +331,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei return NULL; } else { /* Replace buffer with a bigger one */ - DumpImgBuffer(); + //DumpImgBuffer(); // Done in AllocImgBuffer too AllocImgBuffer(newsize); } } @@ -369,12 +369,12 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh unsigned int new_buffer_size = ((p_width*p_height)*p_colours); if(buffer_size < new_buffer_size) { - Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours ); + Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours, new_buffer_size ); return; } if(holdbuffer && buffer) { - if((unsigned int)((p_height*p_width)*p_colours) > allocation) { + if(new_buffer_size > allocation) { Error("Held buffer is undersized for assigned buffer"); return; } else { @@ -482,7 +482,7 @@ void Image::Assign( const Image &image ) { } } else { if(new_size > allocation || !buffer) { - DumpImgBuffer(); + // DumpImgBuffer(); This is also done in AllocImgBuffer AllocImgBuffer(new_size); } } From 0eeba1c514eac831faff67f445b60ea699831618 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 10 Apr 2015 15:36:57 -0500 Subject: [PATCH 058/154] don't check for perl packlist in f21 specfile --- distros/fedora/zoneminder.f21.spec | 2 -- 1 file changed, 2 deletions(-) diff --git a/distros/fedora/zoneminder.f21.spec b/distros/fedora/zoneminder.f21.spec index e2fb17ec3..5340ca5d5 100644 --- a/distros/fedora/zoneminder.f21.spec +++ b/distros/fedora/zoneminder.f21.spec @@ -154,8 +154,6 @@ fi %{!?_without_x10:%{_bindir}/zmx10.pl} %{perl_vendorlib}/ZoneMinder* -%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder* -#%{perl_archlib}/ZoneMinder* %{_mandir}/man*/* %dir %{_libexecdir}/zoneminder %{_libexecdir}/zoneminder/cgi-bin From fba085a1c5b09f49717183299c2a6b17b873ef98 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 04:30:21 +1000 Subject: [PATCH 059/154] zmcontrol.pl: pod2usage (draft) + minor readability improvements. Looks like "zmcontrol.pl" was based upon "zmfilter.pl" so it inherited commented description of the latter. Therefore "zmcontrol.pl" needs a description... --- scripts/zmcontrol.pl.in | 106 +++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index 817b80cf6..ee078f9a0 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -20,16 +20,39 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script continuously monitors the recorded events for the given -# monitor and applies any filters which would delete and/or upload -# matching events -# + +=head1 NAME + +zmcontrol.pl - ZoneMinder control script + +=head1 SYNOPSIS + + zmcontrol.pl --id {monitor_id} --command={command} [various options] + +=head1 DESCRIPTION + +FIXME FIXME + +=head1 OPTIONS + + --autostop - + --xcoord [ arg ] - X-coord + --ycoord [ arg ] - Y-coord + --speed [ arg ] - Speed + --step [ arg ] - + --panspeed [ arg ] - + --panstep [ arg ] - + --tiltspeed [ arg ] - + --tiltstep [ arg ] - + --preset [ arg ] - + +=cut use strict; @EXTRA_PERL_LIB@ use ZoneMinder; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use POSIX qw/strftime EPIPE/; use Socket; #use Data::Dumper; @@ -44,14 +67,6 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -sub Usage -{ - print( " -Usage: zmcontrol.pl --id --command= -"); - exit(); -} - logInit(); my $arg_string = join( " ", @ARGV ); @@ -59,29 +74,25 @@ my $arg_string = join( " ", @ARGV ); my $id; my %options; -if ( !GetOptions( - 'id=i'=>\$id, - 'command=s'=>\$options{command}, - 'xcoord=i'=>\$options{xcoord}, - 'ycoord=i'=>\$options{ycoord}, - 'speed=i'=>\$options{speed}, - 'step=i'=>\$options{step}, - 'panspeed=i'=>\$options{panspeed}, - 'tiltspeed=i'=>\$options{tiltspeed}, - 'panstep=i'=>\$options{panstep}, - 'tiltstep=i'=>\$options{tiltstep}, - 'preset=i'=>\$options{preset}, - 'autostop'=>\$options{autostop}, - ) -) -{ - Usage(); -} +GetOptions( + 'id=i' =>\$id, + 'command=s' =>\$options{command}, + 'xcoord=i' =>\$options{xcoord}, + 'ycoord=i' =>\$options{ycoord}, + 'speed=i' =>\$options{speed}, + 'step=i' =>\$options{step}, + 'panspeed=i' =>\$options{panspeed}, + 'tiltspeed=i' =>\$options{tiltspeed}, + 'panstep=i' =>\$options{panstep}, + 'tiltstep=i' =>\$options{tiltstep}, + 'preset=i' =>\$options{preset}, + 'autostop' =>\$options{autostop}, +) or pod2usage(-exitstatus => -1); if ( !$id || !$options{command} ) { print( STDERR "Please give a valid monitor id and command\n" ); - Usage(); + pod2usage(-exitstatus => -1); } ( $id ) = $id =~ /^(\w+)$/; @@ -90,13 +101,14 @@ Debug( $arg_string ); my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock'; -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); +socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); my $saddr = sockaddr_un( $sock_file ); my $server_up = connect( CLIENT, $saddr ); if ( !$server_up ) { - # The server isn't there + # The server isn't there my $monitor = zmDbGetMonitorAndControl( $id ); if ( !$monitor ) { @@ -129,16 +141,17 @@ if ( !$server_up ) Info( "Starting control server $id/$protocol" ); close( CLIENT ); - if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) { - Fatal("Can't load ZoneMinder::Control::$protocol"); - } + if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) { + Fatal("Can't load ZoneMinder::Control::$protocol"); + } if ( my $cpid = fork() ) { logReinit(); # Parent process just sleep and fall through - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" ); + socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or die( "Can't open socket: $!" ); my $attempts = 0; while (!connect( CLIENT, $saddr )) { @@ -156,7 +169,9 @@ if ( !$server_up ) logReinit(); - Info( "Control server $id/$protocol starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) ); + Info( "Control server $id/$protocol starting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ); $0 = $0." --id $id"; @@ -166,7 +181,8 @@ if ( !$server_up ) $control->open(); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); + socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); unlink( $sock_file ); bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); @@ -193,9 +209,9 @@ if ( !$server_up ) my $command = $params->{command}; close( CLIENT ); - if ( $command eq 'quit' ) { - last; - } + if ( $command eq 'quit' ) { + last; + } $control->$command( $params ); } else @@ -220,7 +236,9 @@ if ( !$server_up ) last; } } - Info( "Control server $id/$protocol exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) ); + Info( "Control server $id/$protocol exiting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ); unlink( $sock_file ); $control->close(); exit( 0 ); From ac685fd247a45b3d83f83c31a8d21d5ef96cf7ca Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 11:14:29 +1000 Subject: [PATCH 060/154] zmfilter.pl: pod2usage + beautification --- scripts/zmfilter.pl.in | 331 ++++++++++++++++++++++++++++++----------- 1 file changed, 242 insertions(+), 89 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index e8f8d998f..54f372262 100755 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -20,11 +20,27 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script continuously monitors the recorded events for the given -# monitor and applies any filters which would delete and/or upload -# matching events -# + +=head1 NAME + +zmfilter.pl - ZoneMinder tool to filter events + +=head1 SYNOPSIS + + zmfilter.pl [-f ,--filter=] | -v, --version + +=head1 DESCRIPTION + +This script continuously monitors the recorded events for the given +monitor and applies any filters which would delete and/or upload +matching events. + +=head1 OPTIONS + + -f{filter name}, --filter={filter name} - The name of a specific filter to run + -v, --version - Print ZoneMinder version + +=cut use strict; use bytes; @@ -49,9 +65,13 @@ use POSIX; use Time::HiRes qw/gettimeofday/; use Date::Manip; use Getopt::Long; -use Data::Dumper; +use autouse 'Pod::Usage'=>qw(pod2usage); +use autouse 'Data::Dumper'=>qw(Dumper); -use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); +use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|) + ? $Config{ZM_DIR_EVENTS} + : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) +; logInit(); logSetSignal(); @@ -105,7 +125,6 @@ if ( $Config{ZM_OPT_MESSAGE} ) } } - $| = 1; $ENV{PATH} = '/bin:/usr/bin'; @@ -117,16 +136,6 @@ my $event_id = 0; my $filter_parm = ""; my $version = 0; -sub Usage -{ - print( " -Usage: zmfilter.pl [-f ,--filter=] | -v, --version -Parameters are :- --f, --filter= - The name of a specific filter to run -"); - exit( -1 ); -} - # # More or less replicates the equivalent PHP function # @@ -159,13 +168,14 @@ sub DateTimeToSQL return( strftime( "%Y-%m-%d %H:%M:%S", localtime( $dt_val ) ) ); } -if ( !GetOptions( 'filter=s'=>\$filter_parm, version=>\$version ) ) -{ - Usage(); -} +GetOptions( + 'filter=s' =>\$filter_parm, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); + if ( $version ) { - print ZoneMinder::Base::ZM_VERSION . "\n"; - exit(0); + print ZoneMinder::Base::ZM_VERSION . "\n"; + exit(0); } if ( ! EVENT_PATH ) { @@ -196,7 +206,7 @@ my $last_action = 0; while( 1 ) { - my $now = time; + my $now = time; if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) { Debug( "Reloading filters\n" ); @@ -257,7 +267,7 @@ sub getFilters my $filter_name = shift; my @filters; - my $sql = "select * from Filters where"; + my $sql = "SELECT * FROM Filters WHERE"; if ( $filter_name ) { $sql .= " Name = ? and"; @@ -266,22 +276,56 @@ sub getFilters { $sql .= " Background = 1 and"; } - $sql .= " (AutoArchive = 1 or AutoVideo = 1 or AutoUpload = 1 or AutoEmail = 1 or AutoMessage = 1 or AutoExecute = 1 or AutoDelete = 1) order by Name"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $sql .= "( AutoArchive = 1 + or AutoVideo = 1 + or AutoUpload = 1 + or AutoEmail = 1 + or AutoMessage = 1 + or AutoExecute = 1 + or AutoDelete = 1 + ) ORDER BY Name"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $res; if ( $filter_name ) { - $res = $sth->execute( $filter_name ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + $res = $sth->execute( $filter_name ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } else { - $res = $sth->execute() or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + $res = $sth->execute() + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { Debug( "Found filter '$db_filter->{Name}'\n" ); my $filter_expr = jsonDecode( $db_filter->{Query} ); - my $sql = "select E.Id,E.MonitorId,M.Name as MonitorName,M.DefaultRate,M.DefaultScale,E.Name,E.Cause,E.Notes,E.StartTime,unix_timestamp(E.StartTime) as Time,E.Length,E.Frames,E.AlarmFrames,E.TotScore,E.AvgScore,E.MaxScore,E.Archived,E.Videoed,E.Uploaded,E.Emailed,E.Messaged,E.Executed from Events as E inner join Monitors as M on M.Id = E.MonitorId"; + my $sql = "SELECT E.Id, + E.MonitorId, + M.Name as MonitorName, + M.DefaultRate, + M.DefaultScale, + E.Name, + E.Cause, + E.Notes, + E.StartTime, + unix_timestamp(E.StartTime) as Time, + E.Length, + E.Frames, + E.AlarmFrames, + E.TotScore, + E.AvgScore, + E.MaxScore, + E.Archived, + E.Videoed, + E.Uploaded, + E.Emailed, + E.Messaged, + E.Executed + FROM Events as E + INNER JOIN Monitors as M on M.Id = E.MonitorId + "; $db_filter->{Sql} = ''; if ( $filter_expr->{terms} ) @@ -348,7 +392,10 @@ sub getFilters { $value = "'$temp_value'"; } - elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name' || $filter_expr->{terms}[$i]->{attr} eq 'Cause' || $filter_expr->{terms}[$i]->{attr} eq 'Notes' ) + elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name' + || $filter_expr->{terms}[$i]->{attr} eq 'Cause' + || $filter_expr->{terms}[$i]->{attr} eq 'Notes' + ) { $value = "'$temp_value'"; } @@ -357,7 +404,8 @@ sub getFilters $value = DateTimeToSQL( $temp_value ); if ( !$value ) { - Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" ); + Error( "Error parsing date/time '$temp_value', " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } $value = "'$value'"; @@ -367,7 +415,8 @@ sub getFilters $value = DateTimeToSQL( $temp_value ); if ( !$value ) { - Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" ); + Error( "Error parsing date/time '$temp_value', " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } $value = "to_days( '$value' )"; @@ -377,7 +426,8 @@ sub getFilters $value = DateTimeToSQL( $temp_value ); if ( !$value ) { - Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" ); + Error( "Error parsing date/time '$temp_value', " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } $value = "extract( hour_second from '$value' )"; @@ -469,7 +519,7 @@ sub getFilters my $sort_column = ''; if ( $filter_expr->{sort_field} eq 'Id' ) { - $sort_column = "E.Id"; + $sort_column = "E.Id"; } elsif ( $filter_expr->{sort_field} eq 'MonitorName' ) { @@ -525,13 +575,15 @@ sub getFilters $script =~ s/\s.*$//; if ( !-e $script ) { - Error( "Auto execute script '$script' not found, skipping filter '$db_filter->{Name}'\n" ); + Error( "Auto execute script '$script' not found, " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } elsif ( !-x $script ) { - Error( "Auto execute script '$script' not executable, skipping filter '$db_filter->{Name}'\n" ); + Error( "Auto execute script '$script' not executable, " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } } @@ -557,7 +609,7 @@ sub checkFilter "\n" ); my $sql = $filter->{Sql}; - + if ( $filter->{HasDiskPercent} ) { my $disk_percent = getDiskPercent(); @@ -574,7 +626,8 @@ sub checkFilter $sql =~ s/zmSystemLoad/$load/g; } - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute(); if ( !$res ) { @@ -591,8 +644,10 @@ sub checkFilter Info( "Archiving event $event->{Id}\n" ); # Do it individually to avoid locking up the table for new events my $sql = "update Events set Archived = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) { @@ -636,18 +691,24 @@ sub checkFilter Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId}\n" ); # Do it individually to avoid locking up the table for new events my $sql = "delete from Events where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); if ( ! $Config{ZM_OPT_FAST_DELETE} ) { my $sql = "delete from Frames where EventId = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); $sql = "delete from Stats where EventId = ?"; - $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); deleteEventFiles( $event->{Id}, $event->{MonitorId} ); } @@ -699,7 +760,8 @@ sub generateVideo $format = $ffmpeg_formats[0]; } - my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e ".$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format; + my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e " + .$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format; my $output = qx($command); chomp( $output ); my $status = $? >> 8; @@ -719,11 +781,13 @@ sub generateVideo else { my $sql = "update Events set Videoed = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); if ( wantarray() ) { - return( $format, sprintf( "%s/%s", getEventPath( $event ), $output ) ); + return( $format, sprintf( "%s/%s", getEventPath( $event ), $output ) ); } } return( 1 ); @@ -741,7 +805,15 @@ sub uploadArchFile } my $archFile = $event->{MonitorName}.'-'.$event->{Id}; - my $archImagePath = getEventPath( $event )."/".(( $Config{ZM_UPLOAD_ARCH_ANALYSE} )?'{*analyse,*capture}':'*capture').".jpg"; + my $archImagePath = getEventPath( $event ) + ."/" + .( + ( $Config{ZM_UPLOAD_ARCH_ANALYSE} ) + ? '{*analyse,*capture}' + : '*capture' + ) + .".jpg" + ; my @archImageFiles = glob($archImagePath); my $archLocPath; @@ -764,7 +836,10 @@ sub uploadArchFile $archError = 1; last; } - $member->desiredCompressionMethod( $Config{ZM_UPLOAD_ARCH_COMPRESS} ? &COMPRESSION_DEFLATED : &COMPRESSION_STORED ); + $member->desiredCompressionMethod( $Config{ZM_UPLOAD_ARCH_COMPRESS} + ? &COMPRESSION_DEFLATED + : &COMPRESSION_STORED + ); } if ( !$archError ) { @@ -793,7 +868,12 @@ sub uploadArchFile $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" ); - if ( $archError = !Archive::Tar->create_archive( $archLocPath, $Config{ZM_UPLOAD_ARCH_COMPRESS}, @archImageFiles ) ) + if ( $archError = !Archive::Tar->create_archive( + $archLocPath, + $Config{ZM_UPLOAD_ARCH_COMPRESS}, + @archImageFiles + ) + ) { Error( "Tar error: ".Archive::Tar->error()."\n " ); } @@ -808,42 +888,63 @@ sub uploadArchFile if ( $Config{ZM_UPLOAD_PROTOCOL} eq "ftp" ) { Info( "Uploading to ".$Config{ZM_UPLOAD_HOST}." using FTP\n" ); - my $ftp = Net::FTP->new( $Config{ZM_UPLOAD_HOST}, Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE}, Debug=>$Config{ZM_UPLOAD_DEBUG} ); + my $ftp = Net::FTP->new( + $Config{ZM_UPLOAD_HOST}, + Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, + Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE}, + Debug=>$Config{ZM_UPLOAD_DEBUG} + ); if ( !$ftp ) { Error( "Can't create FTP connection: $@" ); return( 0 ); } - $ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) or Error( "FTP - Can't login" ); - $ftp->binary() or Error( "FTP - Can't go binary" ); - $ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) or Error( "FTP - Can't cwd" ) if ( $Config{ZM_UPLOAD_REM_DIR} ); - $ftp->put( $archLocPath ) or Error( "FTP - Can't upload '$archLocPath'" ); - $ftp->quit() or Error( "FTP - Can't quit" ); + $ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) + or Error( "FTP - Can't login" ); + $ftp->binary() + or Error( "FTP - Can't go binary" ); + $ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) + or Error( "FTP - Can't cwd" ) + if ( $Config{ZM_UPLOAD_REM_DIR} ); + $ftp->put( $archLocPath ) + or Error( "FTP - Can't upload '$archLocPath'" ); + $ftp->quit() + or Error( "FTP - Can't quit" ); } else { my $host = $Config{ZM_UPLOAD_HOST}; - $host .= ":".$Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT}; + $host .= ":".$Config{ZM_UPLOAD_PORT} + if $Config{ZM_UPLOAD_PORT}; Info( "Uploading to ".$host." using SFTP\n" ); my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} ); - $sftpOptions{password} = $Config{ZM_UPLOAD_PASS} if $Config{ZM_UPLOAD_PASS}; - $sftpOptions{port} = $Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT}; - $sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} if $Config{ZM_UPLOAD_TIMEOUT}; + $sftpOptions{password} = $Config{ZM_UPLOAD_PASS} + if $Config{ZM_UPLOAD_PASS}; + $sftpOptions{port} = $Config{ZM_UPLOAD_PORT} + if $Config{ZM_UPLOAD_PORT}; + $sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} + if $Config{ZM_UPLOAD_TIMEOUT}; $sftpOptions{more} = [ '-o'=>'StrictHostKeyChecking=no' ]; - $Net::SFTP::Foreign::debug = -1 if $Config{ZM_UPLOAD_DEBUG}; + $Net::SFTP::Foreign::debug = -1 + if $Config{ZM_UPLOAD_DEBUG}; my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions ); if ( $sftp->error ) { Error( "Can't create SFTP connection: ".$sftp->error ); return( 0 ); } - $sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) or Error( "SFTP - Can't setcwd: ".$sftp->error ) if $Config{ZM_UPLOAD_REM_DIR}; - $sftp->put( $archLocPath, $archFile ) or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error ); + $sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) + or Error( "SFTP - Can't setcwd: ".$sftp->error ) + if $Config{ZM_UPLOAD_REM_DIR}; + $sftp->put( $archLocPath, $archFile ) + or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error ); } unlink( $archLocPath ); my $sql = "update Events set Uploaded = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } return( 1 ); } @@ -864,9 +965,28 @@ sub substituteTags if ( $need_monitor ) { my $db_now = strftime( "%Y-%m-%d %H:%M:%S", localtime() ); - my $sql = "select M.Id, count(E.Id) as EventCount, count(if(E.Archived,1,NULL)) as ArchEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL)) as HourEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL)) as DayEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL)) as WeekEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL)) as MonthEventCount from Monitors as M left join Events as E on E.MonitorId = M.Id where MonitorId = ? group by E.MonitorId order by Id"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{MonitorId} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sql = "SELECT + M.Id, + count(E.Id) as EventCount, + count(if(E.Archived,1,NULL)) + as ArchEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL)) + as HourEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL)) + as DayEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL)) + as WeekEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL)) + as MonthEventCount + FROM Monitors as M LEFT JOIN Events as E on E.MonitorId = M.Id + WHERE MonitorId = ? + GROUP BY E.MonitorId + ORDER BY Id" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{MonitorId} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); $monitor = $sth->fetchrow_hashref(); $sth->finish(); return() if ( !$monitor ); @@ -879,9 +999,14 @@ sub substituteTags my $max_alarm_score = 0; if ( $need_images ) { - my $sql = "select * from Frames where EventId = ? and Type = 'Alarm' order by FrameId"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sql = "SELECT * FROM Frames + WHERE EventId = ? AND Type = 'Alarm' + ORDER BY FrameId" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); while( my $frame = $sth->fetchrow_hashref() ) { if ( !$first_alarm_frame ) @@ -929,14 +1054,34 @@ sub substituteTags $text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g; if ( $attachments_ref && $text =~ s/%EI1%//g ) { - push( @$attachments_ref, { type=>"image/jpeg", path=>sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath( $event ), $first_alarm_frame->{FrameId} ) } ); + push( @$attachments_ref, + { + type=>"image/jpeg", + path=>sprintf( + "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", + getEventPath( $event ), + $first_alarm_frame->{FrameId} + ) + } + ); } if ( $attachments_ref && $text =~ s/%EIM%//g ) { # Don't attach the same image twice - if ( !@$attachments_ref || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) ) + if ( !@$attachments_ref + || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) + ) { - push( @$attachments_ref, { type=>"image/jpeg", path=>sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath( $event ), $max_alarm_frame->{FrameId} ) } ); + push( @$attachments_ref, + { + type=>"image/jpeg", + path=>sprintf( + "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", + getEventPath( $event ), + $max_alarm_frame->{FrameId} + ) + } + ); } } } @@ -964,7 +1109,7 @@ sub substituteTags $text =~ s/%FN%/$filter->{Name}/g; ( my $filter_name = $filter->{Name} ) =~ s/ /+/g; $text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g; - + return( $text ); } @@ -1023,7 +1168,7 @@ sub sendEmail ### Send the Message MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); $mail->send(); - } + } else { my $mail = MIME::Entity->build( @@ -1056,8 +1201,10 @@ sub sendEmail Info( "Notification email sent\n" ); } my $sql = "update Events set Emailed = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); return( 1 ); } @@ -1117,7 +1264,7 @@ sub sendMessage ### Send the Message MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); $mail->send(); - } + } else { my $mail = MIME::Entity->build( @@ -1137,7 +1284,9 @@ sub sendMessage Encoding => "base64" ); } - $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} ); + $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, + MailFrom => $Config{ZM_FROM_EMAIL} + ); } }; if ( $@ ) @@ -1150,8 +1299,10 @@ sub sendMessage Info( "Notification message sent\n" ); } my $sql = "update Events set Messaged = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); return( 1 ); } @@ -1182,8 +1333,10 @@ sub executeCommand else { my $sql = "update Events set Executed = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } return( 1 ); } From fa97348535662576cf7324320b9ea3cf8f53cc9b Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 22:39:32 +1000 Subject: [PATCH 061/154] zmpkg.pl: pod2usage, tabs-to-spaces + readability --- scripts/zmpkg.pl.in | 379 ++++++++++++++++++++++++-------------------- 1 file changed, 209 insertions(+), 170 deletions(-) diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 084747bad..c3c621da1 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -20,10 +20,21 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to start and stop the ZoneMinder package primarily to -# allow command line control for automatic restart on reboot (see zm script) -# + +=head1 NAME + +zmpkg.pl - ZoneMinder Package Control Script + +=head1 SYNOPSIS + + zmpkg.pl {start|stop|restart|status|logrot|'state'|version} + +=head1 DESCRIPTION + +This script is used to start and stop the ZoneMinder package primarily to +allow command line control for automatic restart on reboot (see zm script) + +=cut use strict; use bytes; @@ -38,6 +49,7 @@ use ZoneMinder; use DBI; use POSIX; use Time::HiRes qw/gettimeofday/; +use autouse 'Pod::Usage'=>qw(pod2usage); # Detaint our environment $ENV{PATH} = '/bin:/usr/bin'; @@ -48,8 +60,8 @@ logInit(); my $command = $ARGV[0]; if ( $command eq 'version' ) { - print ZoneMinder::Base::ZM_VERSION . "\n"; - exit(0); + print ZoneMinder::Base::ZM_VERSION . "\n"; + exit(0); } my $state; @@ -58,39 +70,43 @@ my $dbh; if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) { - if ( $command ) - { - $dbh = zmDbConnect(); - # Check to see if it's a valid run state - my $sql = 'select * from States where Name = ?'; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $command ) or Fatal( "Can't execute: ".$sth->errstr() ); - if ( $state = $sth->fetchrow_hashref() ) - { - $state->{Name} = $command; - $state->{Definitions} = []; - foreach( split( /,/, $state->{Definition} ) ) - { - my ( $id, $function, $enabled ) = split( /:/, $_ ); - push( @{$state->{Definitions}}, { Id=>$id, Function=>$function, Enabled=>$enabled } ); - } - $command = 'state'; - } - else - { - $command = undef; - } - } - if ( !$command ) - { - print( "Usage: zmpkg.pl \n" ); - exit( -1 ); - } + if ( $command ) + { + $dbh = zmDbConnect(); + # Check to see if it's a valid run state + my $sql = 'select * from States where Name = ?'; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $command ) + or Fatal( "Can't execute: ".$sth->errstr() ); + if ( $state = $sth->fetchrow_hashref() ) + { + $state->{Name} = $command; + $state->{Definitions} = []; + foreach( split( /,/, $state->{Definition} ) ) + { + my ( $id, $function, $enabled ) = split( /:/, $_ ); + push( @{$state->{Definitions}}, + { Id=>$id, Function=>$function, Enabled=>$enabled } + ); + } + $command = 'state'; + } + else + { + $command = undef; + } + } + if ( !$command ) + { + pod2usage(-exitstatus => -1); + } } $dbh = zmDbConnect() if ! $dbh; # Move to the right place -chdir( $Config{ZM_PATH_WEB} ) or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" ); +chdir( $Config{ZM_PATH_WEB} ) + or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" ); my $dbg_id = ""; @@ -100,209 +116,232 @@ my $retval = 0; if ( $command eq "state" ) { - Info( "Updating DB: $state->{Name}\n" ); - my $sql = "select * from Monitors order by Id asc"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - foreach my $definition ( @{$state->{Definitions}} ) - { - if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) - { - $monitor->{NewFunction} = $definition->{Function}; - $monitor->{NewEnabled} = $definition->{Enabled}; - } - } - #next if ( !$monitor->{NewFunction} ); - $monitor->{NewFunction} = 'None' if ( !$monitor->{NewFunction} ); - $monitor->{NewEnabled} = 0 if ( !$monitor->{NewEnabled} ); - if ( $monitor->{Function} ne $monitor->{NewFunction} || $monitor->{Enabled} ne $monitor->{NewEnabled} ) - { - my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} ) or Fatal( "Can't execute: ".$sth->errstr() ); - } - } - $sth->finish(); + Info( "Updating DB: $state->{Name}\n" ); + my $sql = "select * from Monitors order by Id asc"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + foreach my $definition ( @{$state->{Definitions}} ) + { + if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) + { + $monitor->{NewFunction} = $definition->{Function}; + $monitor->{NewEnabled} = $definition->{Enabled}; + } + } + #next if ( !$monitor->{NewFunction} ); + $monitor->{NewFunction} = 'None' + if ( !$monitor->{NewFunction} ); + $monitor->{NewEnabled} = 0 + if ( !$monitor->{NewEnabled} ); + if ( $monitor->{Function} ne $monitor->{NewFunction} + || $monitor->{Enabled} ne $monitor->{NewEnabled} + ) + { + my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} ) + or Fatal( "Can't execute: ".$sth->errstr() ); + } + } + $sth->finish(); - $command = "restart"; + $command = "restart"; } # Check if we are running systemd and if we have been called by the system if ( $command =~ /^(start|stop|restart)$/ ) { - # We have to detaint to keep perl from complaining - $command = $1; + # We have to detaint to keep perl from complaining + $command = $1; - if ( systemdRunning() && !calledBysystem() ) { - qx(@BINDIR@/zmsystemctl.pl $command); - $command = ""; - } + if ( systemdRunning() && !calledBysystem() ) { + qx(@BINDIR@/zmsystemctl.pl $command); + $command = ""; + } } if ( $command =~ /^(?:stop|restart)$/ ) { - my $status = runCommand( "zmdc.pl check" ); + my $status = runCommand( "zmdc.pl check" ); - if ( $status eq "running" ) - { - runCommand( "zmdc.pl shutdown" ); - zmMemTidy(); - } - else - { - $retval = 1; - } + if ( $status eq "running" ) + { + runCommand( "zmdc.pl shutdown" ); + zmMemTidy(); + } + else + { + $retval = 1; + } } #runCommand( "zmupdate.pl -f" ); if ( $command =~ /^(?:start|restart)$/ ) { - my $status = runCommand( "zmdc.pl check" ); + my $status = runCommand( "zmdc.pl check" ); - if ( $status eq "stopped" ) - { - if ( $Config{ZM_DYN_DB_VERSION} and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) ) + if ( $status eq "stopped" ) + { + if ( $Config{ZM_DYN_DB_VERSION} + and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) + ) { - Fatal( "Version mismatch, system is version ".ZM_VERSION.", database is ".$Config{ZM_DYN_DB_VERSION}.", please run zmupdate.pl to update." ); + Fatal( "Version mismatch, system is version ".ZM_VERSION + .", database is ".$Config{ZM_DYN_DB_VERSION} + .", please run zmupdate.pl to update." + ); exit( -1 ); } # Recreate the temporary directory if it's been wiped - verifyFolder("@ZM_TMPDIR@"); + verifyFolder("@ZM_TMPDIR@"); # Recreate the run directory if it's been wiped - verifyFolder("@ZM_RUNDIR@"); + verifyFolder("@ZM_RUNDIR@"); # Recreate the sock directory if it's been wiped - verifyFolder("@ZM_SOCKDIR@"); + verifyFolder("@ZM_SOCKDIR@"); - zmMemTidy(); - runCommand( "zmdc.pl startup" ); + zmMemTidy(); + runCommand( "zmdc.pl startup" ); - my $sql = "select * from Monitors"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - if ( $monitor->{Function} ne 'None' ) - { - if ( $monitor->{Type} eq 'Local' ) - { - runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); - } - else - { - runCommand( "zmdc.pl start zmc -m $monitor->{Id}" ); - } - if ( $monitor->{Function} ne 'Monitor' ) - { - if ( $Config{ZM_OPT_FRAME_SERVER} ) - { - runCommand( "zmdc.pl start zmf -m $monitor->{Id}" ); - } - runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); - } - if ( $Config{ZM_OPT_CONTROL} ) - { - if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) - { - if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) - { - runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" ); - } - } - } - } - } - $sth->finish(); + my $sql = "select * from Monitors"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + if ( $monitor->{Function} ne 'None' ) + { + if ( $monitor->{Type} eq 'Local' ) + { + runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); + } + else + { + runCommand( "zmdc.pl start zmc -m $monitor->{Id}" ); + } + if ( $monitor->{Function} ne 'Monitor' ) + { + if ( $Config{ZM_OPT_FRAME_SERVER} ) + { + runCommand( "zmdc.pl start zmf -m $monitor->{Id}" ); + } + runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); + } + if ( $Config{ZM_OPT_CONTROL} ) + { + if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) + { + if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) + { + runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" ); + } + } + } + } + } + $sth->finish(); - # This is now started unconditionally - runCommand( "zmdc.pl start zmfilter.pl" ); - if ( $Config{ZM_RUN_AUDIT} ) - { - runCommand( "zmdc.pl start zmaudit.pl -c" ); - } - if ( $Config{ZM_OPT_TRIGGERS} ) - { - runCommand( "zmdc.pl start zmtrigger.pl" ); - } - if ( $Config{ZM_OPT_X10} ) - { - runCommand( "zmdc.pl start zmx10.pl -c start" ); - } - runCommand( "zmdc.pl start zmwatch.pl" ); - if ( $Config{ZM_CHECK_FOR_UPDATES} ) - { - runCommand( "zmdc.pl start zmupdate.pl -c" ); - } - } - else - { - $retval = 1; - } + # This is now started unconditionally + runCommand( "zmdc.pl start zmfilter.pl" ); + if ( $Config{ZM_RUN_AUDIT} ) + { + runCommand( "zmdc.pl start zmaudit.pl -c" ); + } + if ( $Config{ZM_OPT_TRIGGERS} ) + { + runCommand( "zmdc.pl start zmtrigger.pl" ); + } + if ( $Config{ZM_OPT_X10} ) + { + runCommand( "zmdc.pl start zmx10.pl -c start" ); + } + runCommand( "zmdc.pl start zmwatch.pl" ); + if ( $Config{ZM_CHECK_FOR_UPDATES} ) + { + runCommand( "zmdc.pl start zmupdate.pl -c" ); + } + } + else + { + $retval = 1; + } } if ( $command eq "status" ) { - my $status = runCommand( "zmdc.pl check" ); + my $status = runCommand( "zmdc.pl check" ); - print( STDOUT $status."\n" ); + print( STDOUT $status."\n" ); } if ( $command eq "logrot" ) { - runCommand( "zmdc.pl logrot" ); + runCommand( "zmdc.pl logrot" ); } exit( $retval ); sub systemdRunning { - my $result = 0; + my $result = 0; - my $output = qx(ps -o comm="" 1); - chomp( $output ); + my $output = qx(ps -o comm="" 1); + chomp( $output ); - if ($output =~ /systemd/) { - $result = 1; - } + if ($output =~ /systemd/) { + $result = 1; + } - return $result; + return $result; } sub calledBysystem { - my $result = 0; - my $ppid = getppid(); + my $result = 0; + my $ppid = getppid(); - my $output = qx(ps -o comm="" $ppid); - chomp( $output ); + my $output = qx(ps -o comm="" $ppid); + chomp( $output ); - if ($output =~ /^(?:systemd|init)$/) { - $result = 1; - } + if ($output =~ /^(?:systemd|init)$/) { + $result = 1; + } - return $result; + return $result; } sub verifyFolder { - my $folder = shift; + my $folder = shift; # Recreate the temporary directory if it's been wiped if ( !-e $folder ) { Debug( "Recreating directory '$folder'" ); - mkdir( "$folder", 0774 ) or Fatal( "Can't create missing temporary directory '$folder': $!" ); + mkdir( "$folder", 0774 ) + or Fatal( "Can't create missing temporary directory '$folder': $!" ); my ( $runName ) = getpwuid( $> ); if ( $runName ne $Config{ZM_WEB_USER} ) { - # Not running as web user, so should be root in which case chown the directory - my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} ) or Fatal( "Can't get user details for web user '".$Config{ZM_WEB_USER}."': $!" ); - chown( $webUid, $webGid, "$folder" ) or Fatal( "Can't change ownership of directory '$folder' to '".$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" ); + # Not running as web user, so should be root in which case + # chown the directory + my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} ) + or Fatal( "Can't get user details for web user '" + .$Config{ZM_WEB_USER}."': $!" + ); + chown( $webUid, $webGid, "$folder" ) + or Fatal( "Can't change ownership of directory '$folder' to '" + .$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" + ); } } } From afb127125df6fc7748567cac7a957d69831f0f4f Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Sat, 11 Apr 2015 22:41:07 +1000 Subject: [PATCH 062/154] zmpkg.pl: correction for "Use of uninitialized value $command in string eq at zmpkg.pl line 62" --- scripts/zmpkg.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index c3c621da1..5686f2596 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -58,7 +58,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; logInit(); -my $command = $ARGV[0]; +my $command = $ARGV[0]||''; if ( $command eq 'version' ) { print ZoneMinder::Base::ZM_VERSION . "\n"; exit(0); From 3108fd21094afe465c31535ffc9e76a36b3558cf Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 12 Apr 2015 11:00:43 -0500 Subject: [PATCH 063/154] link nph-zms rather than build --- src/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0fedc2af9..97f9ee3cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ add_executable(zma zma.cpp) add_executable(zmu zmu.cpp) add_executable(zmf zmf.cpp) add_executable(zms zms.cpp) -add_executable(nph-zms zms.cpp) +#add_executable(nph-zms zms.cpp) add_executable(zmstreamer zmstreamer.cpp) target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) @@ -22,10 +22,10 @@ target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) -target_link_libraries(nph-zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) +#target_link_libraries(nph-zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmstreamer zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) install(TARGETS zmc zma zmu zmf zmstreamer RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(TARGETS zms nph-zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - +install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY "${ZM_CGIDIR}")") From 8f337999d4c3b85683b04a99c6878d6878b4925b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 12 Apr 2015 11:47:28 -0500 Subject: [PATCH 064/154] remove nph-zms target --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97f9ee3cb..accc7984c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,6 @@ target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmstreamer zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) install(TARGETS zmc zma zmu zmf zmstreamer RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -install(TARGETS zms nph-zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY "${ZM_CGIDIR}")") From 3a3f186e74b6f67d8b0aa29cbc8958d33af2df4d Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 12 Apr 2015 11:48:18 -0500 Subject: [PATCH 065/154] update working_directory --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index accc7984c..a0ad9f3bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,5 +27,5 @@ target_link_libraries(zmstreamer zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) install(TARGETS zmc zma zmu zmf zmstreamer RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY "${ZM_CGIDIR}")") +install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY \"\$ENV{DESTDIR}${ZM_CGIDIR}\")") From 4cb8cf8681d6e85779c494c0348074ede0be8c8d Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 12 Apr 2015 11:48:49 -0500 Subject: [PATCH 066/154] remove commented commands --- src/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a0ad9f3bb..f55967015 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,6 @@ add_executable(zma zma.cpp) add_executable(zmu zmu.cpp) add_executable(zmf zmf.cpp) add_executable(zms zms.cpp) -#add_executable(nph-zms zms.cpp) add_executable(zmstreamer zmstreamer.cpp) target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) @@ -22,7 +21,6 @@ target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) -#target_link_libraries(nph-zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmstreamer zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) install(TARGETS zmc zma zmu zmf zmstreamer RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) From 30765fdedf4dfdf61ae57e8bccf3b11b0ca4cf96 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 12 Apr 2015 12:20:20 -0500 Subject: [PATCH 067/154] hide USE_DEEP_STORAGE --- db/zm_update-1.28.99.sql | 5 +++++ scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/db/zm_update-1.28.99.sql b/db/zm_update-1.28.99.sql index 5c2c9aeff..660b19db4 100644 --- a/db/zm_update-1.28.99.sql +++ b/db/zm_update-1.28.99.sql @@ -108,4 +108,9 @@ SELECT * FROM (SELECT NULL as Id, WHERE NOT EXISTS ( SELECT Name FROM Controls WHERE name = 'ONVIF Camera' ) LIMIT 1; +-- +-- Hide USE_DEEP_STORAGE from user to prevent accidental event loss +-- +UPDATE `zm`.`Config` SET `Category`='hidden' WHERE `Name`='ZM_USE_DEEP_STORAGE'; + diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 4235a1398..3993d7379 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -183,7 +183,7 @@ our @options = description => "Use a deep filesystem hierarchy for events", help => "This option is now the default for new ZoneMinder systems and should not be changed. Previous versions of ZoneMinder stored all events for a monitor under one folder. Enabling USE_DEEP_STORAGE causes ZoneMinder to store events under a folder structure that follows year/month/day/hour/min/second. Storing events this way avoids the limitation of storing more than 32k files in a single folder inherent in some filesystems. It is important to note that you cannot simply change this option. You must stop zoneminder, enable USE_DEEP_STORAGE, and then run \"sudo zmupdate.pl --migrate-events\". FAILURE TO DO SO WILL RESULT IN LOSS OF YOUR DATA! Consult the ZoneMinder WiKi for further details.", type => $types{boolean}, - category => "paths", + category => "hidden", }, { name => "ZM_DIR_IMAGES", From 38f6eb8b5fd830687dd5d4b7265d2cde8c7516dd Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 12 Apr 2015 17:52:01 -0500 Subject: [PATCH 068/154] Update mootools to 1.5.1 --- web/tools/mootools/Makefile.am | 10 +- web/tools/mootools/mootools-core-1.3.2-yc.js | 450 - ...ore-1.3.2-nc.js => mootools-core-1.5.1.js} | 3531 ++-- .../mootools/mootools-more-1.3.2.1-yc.js | 742 - ...e-1.3.2.1-nc.js => mootools-more-1.5.1.js} | 17119 ++++++++++------ 5 files changed, 12757 insertions(+), 9095 deletions(-) delete mode 100644 web/tools/mootools/mootools-core-1.3.2-yc.js rename web/tools/mootools/{mootools-core-1.3.2-nc.js => mootools-core-1.5.1.js} (74%) delete mode 100644 web/tools/mootools/mootools-more-1.3.2.1-yc.js rename web/tools/mootools/{mootools-more-1.3.2.1-nc.js => mootools-more-1.5.1.js} (57%) diff --git a/web/tools/mootools/Makefile.am b/web/tools/mootools/Makefile.am index 958647796..8b31023a8 100644 --- a/web/tools/mootools/Makefile.am +++ b/web/tools/mootools/Makefile.am @@ -3,16 +3,14 @@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/tools/mootools dist_web_DATA = \ - mootools-core-1.3.2-nc.js \ - mootools-core-1.3.2-yc.js \ - mootools-more-1.3.2.1-nc.js \ - mootools-more-1.3.2.1-yc.js + mootools-core-1.5.1.js \ + mootools-more-1.5.1.js # Yes, you are correct. This is a HACK! install-data-hook: ( cd $(DESTDIR)$(webdir); rm -f mootools-core.js mootools-more.js ) - ( cd $(DESTDIR)$(webdir); ln -s mootools-core-1.3.2-yc.js mootools-core.js ) - ( cd $(DESTDIR)$(webdir); ln -s mootools-more-1.3.2.1-yc.js mootools-more.js ) + ( cd $(DESTDIR)$(webdir); ln -s mootools-core-1.5.1.js mootools-core.js ) + ( cd $(DESTDIR)$(webdir); ln -s mootools-more-1.5.1.js mootools-more.js ) uninstall-hook: @-( cd $(DESTDIR)$(webdir); rm -f mootools-* ) diff --git a/web/tools/mootools/mootools-core-1.3.2-yc.js b/web/tools/mootools/mootools-core-1.3.2-yc.js deleted file mode 100644 index 71a263b81..000000000 --- a/web/tools/mootools/mootools-core-1.3.2-yc.js +++ /dev/null @@ -1,450 +0,0 @@ -/* ---- -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-core-1.3.2-nc.js b/web/tools/mootools/mootools-core-1.5.1.js similarity index 74% rename from web/tools/mootools/mootools-core-1.3.2-nc.js rename to web/tools/mootools/mootools-core-1.5.1.js index cba97ef7f..e0bea6df6 100644 --- a/web/tools/mootools/mootools-core-1.3.2-nc.js +++ b/web/tools/mootools/mootools-core-1.5.1.js @@ -1,13 +1,7 @@ +/* MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2015 [Valerio Proietti](http://mad4milk.net/).*/ /* ---- -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 - +Web Build: http://mootools.net/core/builder/e426a9ae7167c5807b173d5deff673fc +*/ /* --- @@ -17,7 +11,7 @@ description: The heart of MooTools. license: MIT-style license. -copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). +copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/). authors: The MooTools production team (http://mootools.net/developers/) @@ -29,25 +23,25 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native] ... */ - +/*! MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/).*/ (function(){ this.MooTools = { - version: '1.3.2', - build: 'c9f1ff10e9e7facb65e9481049ed1b450959d587' + version: '1.5.1', + build: '0542c135fdeb7feed7d9917e01447a408f22c876' }; // typeOf, instanceOf var typeOf = this.typeOf = function(item){ if (item == null) return 'null'; - if (item.$family) return item.$family(); + if (item.$family != null) 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 ('callee' in item) return 'arguments'; if ('item' in item) return 'collection'; } @@ -61,6 +55,9 @@ var instanceOf = this.instanceOf = function(item, object){ if (constructor === object) return true; constructor = constructor.parent; } + /**/ + if (!item.hasOwnProperty) return false; + /**/ return item instanceof object; }; @@ -93,8 +90,9 @@ Function.prototype.overloadGetter = function(usePlural){ var self = this; return function(a){ var args, result; - if (usePlural || typeof a != 'string') args = a; + if (typeof a != 'string') args = a; else if (arguments.length > 1) args = arguments; + else if (usePlural) args = [a]; if (args){ result = {}; for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]); @@ -203,7 +201,7 @@ var implement = function(name, method){ 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; @@ -251,21 +249,25 @@ var force = function(name, object, methods){ proto = prototype[key]; if (generic) generic.protect(); - - if (isType && proto){ - delete prototype[key]; - prototype[key] = proto.protect(); - } + if (isType && proto) object.implement(key, proto.protect()); } - if (isType) object.implement(prototype); + if (isType){ + var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]); + object.forEachMethod = function(fn){ + if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){ + fn.call(prototype, prototype[methods[i]], methods[i]); + } + for (var key in prototype) fn.call(prototype, prototype[key], key); + }; + } return force; }; force('String', String, [ - 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', - 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase' + 'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', + 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase' ])('Array', Array, [ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight' @@ -314,11 +316,13 @@ 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); @@ -400,7 +404,6 @@ String.extend('uniqueID', function(){ })(); - /* --- @@ -410,7 +413,7 @@ description: Contains Array Prototypes like each, contains, and erase. license: MIT-style license. -requires: Type +requires: [Type] provides: Array @@ -421,7 +424,7 @@ Array.implement({ /**/ every: function(fn, bind){ - for (var i = 0, l = this.length; i < l; i++){ + for (var i = 0, l = this.length >>> 0; i < l; i++){ if ((i in this) && !fn.call(bind, this[i], i, this)) return false; } return true; @@ -429,30 +432,31 @@ Array.implement({ 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]); + for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){ + value = this[i]; + if (fn.call(bind, value, i, this)) results.push(value); } 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++){ + var length = this.length >>> 0; + for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; 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++){ + var length = this.length >>> 0, results = Array(length); + for (var i = 0; i < length; 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++){ + for (var i = 0, l = this.length >>> 0; i < l; i++){ if ((i in this) && fn.call(bind, this[i], i, this)) return true; } return false; @@ -552,7 +556,7 @@ Array.implement({ if (this.length != 3) return null; var rgb = this.map(function(value){ if (value.length == 1) value += value; - return value.toInt(16); + return parseInt(value, 16); }); return (array) ? rgb : 'rgb(' + rgb + ')'; }, @@ -572,90 +576,85 @@ Array.implement({ - /* --- -name: String +name: Function -description: Contains String Prototypes like camelCase, capitalize, test, and toInt. +description: Contains Function Prototypes like create, bind, pass, and delay. license: MIT-style license. requires: Type -provides: String +provides: Function ... */ -String.implement({ +Function.extend({ - 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] : ''; - }); + 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(that){ + var self = this, + args = arguments.length > 1 ? Array.slice(arguments, 1) : null, + F = function(){}; + + var bound = function(){ + var context = that, length = arguments.length; + if (this instanceof bound){ + F.prototype = self.prototype; + context = new F; + } + var result = (!args && !length) + ? self.call(context) + : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments); + return context == that ? result : context; + }; + return bound; + }, + /**/ + + 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); + } + +}); + + /* --- @@ -710,79 +709,522 @@ Number.alias('each', 'times'); Number.implement(methods); })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); - /* --- -name: Function +name: String -description: Contains Function Prototypes like create, bind, pass, and delay. +description: Contains String Prototypes like camelCase, capitalize, test, and toInt. license: MIT-style license. -requires: Type +requires: [Type, Array] -provides: Function +provides: String ... */ -Function.extend({ +String.implement({ - attempt: function(){ - for (var i = 0, l = arguments.length; i < l; i++){ - try { - return arguments[i](); - } catch (e){} + // + contains: function(string, index){ + return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1; + }, + // + + test: function(regex, params){ + return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this); + }, + + trim: function(){ + return String(this).replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return String(this).replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return String(this).replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return String(this).replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return String(this).replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = String(this).match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + substitute: function(object, regexp){ + return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + if (match.charAt(0) == '\\') return match.slice(1); + return (object[name] != null) ? object[name] : ''; + }); + } + +}); + + + +/* +--- + +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 parse = function(ua, platform){ + ua = ua.toLowerCase(); + platform = (platform ? platform.toLowerCase() : ''); + + var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0]; + + if (UA[1] == 'trident'){ + UA[1] = 'ie'; + if (UA[4]) UA[2] = UA[4]; + } else if (UA[1] == 'crios'){ + UA[1] = 'chrome'; + } + + platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]; + if (platform == 'win') platform = 'windows'; + + return { + extend: Function.prototype.extend, + name: (UA[1] == 'version') ? UA[3] : UA[1], + version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]), + platform: platform + }; +}; + +var Browser = this.Browser = parse(navigator.userAgent, navigator.platform); + +if (Browser.name == 'ie'){ + Browser.version = document.documentMode; +} + +Browser.extend({ + Features: { + xpath: !!(document.evaluate), + air: !!(window.runtime), + query: !!(document.querySelector), + json: !!(window.JSON) + }, + parseUA: parse +}); + + + +// 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); + + + +// 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; + window = this.Window = document = 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 null; + 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: 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; } }); -Function.implement({ +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); - attempt: function(args, bind){ - try { - return this.apply(bind, Array.from(args)); - } catch (e){} - return null; + + this.$events[type] = (this.$events[type] || []).include(fn); + if (internal) fn.internal = true; + return this; }, - /**/ - 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); - }; + addEvents: function(events){ + for (var type in events) this.addEvent(type, events[type]); + return this; }, - delay: function(delay, bind, args){ - return setTimeout(this.pass((args == null ? [] : args), bind), delay); + 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; }, - periodical: function(periodical, bind, args){ - return setInterval(this.pass((args == null ? [] : args), bind), periodical); + 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; + } +}); + +})(); /* --- @@ -906,584 +1348,6 @@ Object.extend({ - -/* ---- - -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 @@ -1715,7 +1579,6 @@ if (!this.Slick) this.Slick = Slick; }).apply(/**/(typeof exports != 'undefined') ? exports : /**/this); - /* --- name: Slick.Finder @@ -1792,7 +1655,7 @@ local.setDocument = function(document){ var selected, id = 'slick_uniqueid'; var testNode = document.createElement('div'); - + var testRoot = document.body || document.getElementsByTagName('body')[0] || root; testRoot.appendChild(testNode); @@ -1843,7 +1706,7 @@ local.setDocument = function(document){ features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN; } - + if (testNode.querySelectorAll){ // IE 8 returns closed nodes (EG:"") for querySelectorAll('*') for some documents try { @@ -1880,7 +1743,7 @@ local.setDocument = function(document){ // native matchesSelector function - features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector; + features.nativeMatchesSelector = root.matches || /*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'); @@ -1893,7 +1756,7 @@ local.setDocument = function(document){ root.slick_expando = 1; delete root.slick_expando; features.getUID = this.getUIDHTML; - } catch(e) { + } catch(e){ features.getUID = this.getUIDXML; } @@ -1914,17 +1777,23 @@ local.setDocument = function(document){ // hasAttribute - features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) { + features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute){ return node.hasAttribute(attribute); - } : function(node, 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){ + var nativeRootContains = root && this.isNativeCode(root.contains), + nativeDocumentContains = document && this.isNativeCode(document.contains); + + features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){ return context.contains(node); + } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){ + // IE8 does not have .contains on document. + return context === node || ((context === document) ? document.documentElement : context).contains(node); } : (root && root.compareDocumentPosition) ? function(context, node){ return context === node || !!(context.compareDocumentPosition(node) & 16); } : function(context, node){ @@ -1969,7 +1838,7 @@ var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/, 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; @@ -1992,7 +1861,7 @@ local.search = function(context, expression, append, first){ /**/ var simpleSelector = expression.match(reSimpleSelector); - simpleSelectors: if (simpleSelector) { + simpleSelectors: if (simpleSelector){ var symbol = simpleSelector[1], name = simpleSelector[2], @@ -2045,7 +1914,7 @@ local.search = function(context, expression, append, first){ /**/ /**/ - querySelector: if (context.querySelectorAll) { + querySelector: if (context.querySelectorAll){ if (!this.isHTMLDocument || qsaFailExpCache[expression] @@ -2074,7 +1943,7 @@ local.search = function(context, expression, append, first){ try { if (first) return context.querySelector(_expression) || null; else nodes = context.querySelectorAll(_expression); - } catch(e) { + } catch(e){ qsaFailExpCache[expression] = 1; break querySelector; } finally { @@ -2273,14 +2142,14 @@ 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) {} + } catch(matchError){} } - + var parsed = this.Slick.parse(selector); if (!parsed) return true; // simple (single) selectors - var expressions = parsed.expressions, reversedExpressions, simpleExpCounter = 0, i; + var expressions = parsed.expressions, simpleExpCounter = 0, i, currentExpression; for (i = 0; (currentExpression = expressions[i]); i++){ if (currentExpression.length == 1){ var exp = currentExpression[0]; @@ -2319,7 +2188,7 @@ local.matchSelector = function(node, tag, id, classes, attributes, pseudos){ var i, part, cls; if (classes) for (i = classes.length; i--;){ - cls = node.getAttribute('class') || node.className; + cls = this.getAttribute(node, 'class'); if (!(cls && classes[i].regexp.test(cls))) return false; } if (attributes) for (i = attributes.length; i--;){ @@ -2354,7 +2223,7 @@ var combinators = { this.push(item, tag, null, classes, attributes, pseudos); break; } - } + } return; } if (!item){ @@ -2505,7 +2374,7 @@ var pseudos = { 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true), 'index': function(node, index){ - return this['pseudo:nth-child'](node, '' + index + 1); + return this['pseudo:nth-child'](node, '' + (index + 1)); }, 'even': function(node){ @@ -2563,7 +2432,7 @@ var pseudos = { 'root': function(node){ return (node === this.root); }, - + 'selected': function(node){ return node.selected; } @@ -2575,11 +2444,7 @@ for (var p in pseudos) local['pseudo:' + p] = pseudos[p]; // attributes methods -local.attributeGetters = { - - 'class': function(){ - return this.getAttribute('class') || this.className; - }, +var attributeGetters = local.attributeGetters = { 'for': function(){ return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for'); @@ -2592,7 +2457,7 @@ local.attributeGetters = { '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; @@ -2600,15 +2465,22 @@ local.attributeGetters = { 'type': function(){ return this.getAttribute('type'); + }, + + 'maxlength': function(){ + var attributeNode = this.getAttributeNode('maxLength'); + return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; } }; +attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength; + // Slick var Slick = local.Slick = (this.Slick || {}); -Slick.version = '1.1.5'; +Slick.version = '1.1.7'; // Slick finder @@ -2630,9 +2502,15 @@ Slick.contains = function(container, node){ // Slick attribute getter Slick.getAttribute = function(node, name){ + local.setDocument(node); return local.getAttribute(node, name); }; +Slick.hasAttribute = function(node, name){ + local.setDocument(node); + return local.hasAttribute(node, name); +}; + // Slick matcher Slick.match = function(node, selector){ @@ -2687,7 +2565,6 @@ if (!this.Slick) this.Slick = Slick; }).apply(/**/(typeof exports != 'undefined') ? exports : /**/this); - /* --- @@ -2697,14 +2574,14 @@ description: One of the most important items in MooTools. Contains the dollar fu license: MIT-style license. -requires: [Window, Document, Array, String, Function, Number, Slick.Parser, Slick.Finder] +requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder] -provides: [Element, Elements, $, $$, Iframe, Selectors] +provides: [Element, Elements, $, $$, IFrame, Selectors] ... */ -var Element = function(tag, props){ +var Element = this.Element = function(tag, props){ var konstructor = Element.Constructors[tag]; if (konstructor) return konstructor(props); if (typeof tag != 'string') return document.id(tag).set(props); @@ -2717,8 +2594,8 @@ var Element = function(tag, props){ 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 (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){ + attr = attributes[i]; if (props[attr.key] != null) continue; if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value; @@ -2731,7 +2608,16 @@ var Element = function(tag, props){ return document.newElement(tag, props); }; -if (Browser.Element) Element.prototype = Browser.Element.prototype; + +if (Browser.Element){ + Element.prototype = Browser.Element.prototype; + // IE8 and IE9 require the wrapping. + Element.prototype._fireEvent = (function(fireEvent){ + return function(type, event){ + return fireEvent.call(this, type, event); + }; + })(Element.prototype.fireEvent); +} new Type('Element', Element).mirror(function(name){ if (Array.prototype[name]) return; @@ -2752,7 +2638,10 @@ new Type('Element', Element).mirror(function(name){ if (!Browser.Element){ Element.parent = Object; - Element.Prototype = {'$family': Function.from('element').hide()}; + Element.Prototype = { + '$constructor': Element, + '$family': Function.from('element').hide() + }; Element.mirror(function(name, method){ Element.Prototype[name] = method; @@ -2862,41 +2751,66 @@ 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); + var result = splice.apply(this, arguments); while (length >= this.length) delete this[length--]; - return this; + return result; }.protect()); -Elements.implement(Array.prototype); +Array.forEachMethod(function(method, name){ + Elements.implement(name, method); +}); Array.mirror(Elements); /**/ var createElementAcceptsHTML; try { - var x = document.createElement(''); - createElementAcceptsHTML = (x.name == 'x'); -} catch(e){} + createElementAcceptsHTML = (document.createElement('').name == 'x'); +} catch (e){} var escapeQuotes = function(html){ return ('' + html).replace(/&/g, '&').replace(/"/g, '"'); }; /**/ +/**/ +// #2479 - IE8 Cannot set HTML of style element +var canChangeStyleHTML = (function(){ + var div = document.createElement('style'), + flag = false; + try { + div.innerHTML = '#justTesing{margin: 0px;}'; + flag = !!div.innerHTML; + } catch(e){} + return flag; +})(); +/**/ + 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; + if (props){ + if (props.checked != null) props.defaultChecked = props.checked; + if ((props.type == 'checkbox' || props.type == 'radio') && props.value == null) props.value = 'on'; + /**/ // IE needs the type to be set before changing content of style element + if (!canChangeStyleHTML && tag == 'style'){ + var styleElement = document.createElement('style'); + styleElement.setAttribute('type', 'text/css'); + if (props.type) delete props.type; + return this.id(styleElement).set(props); + } + /**/ + /**/// Fix for readonly name and type properties in IE < 8 + if (createElementAcceptsHTML){ + 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); } @@ -2904,6 +2818,11 @@ Document.implement({ })(); +(function(){ + +Slick.uidOf(window); +Slick.uidOf(document); + Document.implement({ newTextNode: function(text){ @@ -2928,8 +2847,13 @@ Document.implement({ }, element: function(el, nocash){ - $uid(el); + Slick.uidOf(el); if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){ + var fireEvent = el.fireEvent; + // wrapping needed in IE7, or else crash + el._fireEvent = function(type, event){ + return fireEvent(type, event); + }; Object.append(el, Element.Prototype); } return el; @@ -2947,7 +2871,7 @@ Document.implement({ }; return function(el, nocash, doc){ - if (el && el.$family && el.uid) return el; + if (el && el.$family && el.uniqueNumber) return el; var type = typeOf(el); return (types[type]) ? types[type](el, nocash, doc || document) : null; }; @@ -2984,6 +2908,79 @@ Window.implement({ }); +var contains = {contains: function(element){ + return Slick.contains(this, element); +}}; + +if (!document.contains) Document.implement(contains); +if (!document.createElement('div').contains) Element.implement(contains); + + + +// tree walking + +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; +}; + +Object.forEach({ + getNext: '~', + getPrevious: '!~', + getParent: '!' +}, function(combinator, method){ + Element.implement(method, function(expression){ + return this.getElement(injectCombinator(expression, combinator)); + }); +}); + +Object.forEach({ + getAllNext: '~', + getAllPrevious: '!~', + getSiblings: '~~', + getChildren: '>', + getParents: '!' +}, function(combinator, method){ + Element.implement(method, function(expression){ + return this.getElements(injectCombinator(expression, combinator)); + }); +}); + +Element.implement({ + + getFirst: function(expression){ + return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]); + }, + + getLast: function(expression){ + return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast()); + }, + + 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'))); + }, + + match: function(expression){ + return !expression || Slick.match(this, expression); + } + +}); + if (window.$$ == null) Window.implement('$$', function(selector){ @@ -2994,50 +2991,7 @@ if (window.$$ == null) Window.implement('$$', function(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)); +// Inserters var inserters = { @@ -3065,20 +3019,239 @@ inserters.inside = inserters.bottom; -var injectCombinator = function(expression, combinator){ - if (!expression) return combinator; +// getProperty / setProperty - expression = Object.clone(Slick.parse(expression)); +var propertyGetters = {}, propertySetters = {}; - var expressions = expression.expressions; - for (var i = expressions.length; i--;) - expressions[i][0].combinator = combinator; +// properties - return expression; +var properties = {}; +Array.forEach([ + 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', + 'frameBorder', 'rowSpan', 'tabIndex', 'useMap' +], function(property){ + properties[property.toLowerCase()] = property; +}); + +properties.html = 'innerHTML'; +properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent'; + +Object.forEach(properties, function(real, key){ + propertySetters[key] = function(node, value){ + node[real] = value; + }; + propertyGetters[key] = function(node){ + return node[real]; + }; +}); + +/**/ +propertySetters.text = (function(setter){ + return function(node, value){ + if (node.get('tag') == 'style') node.set('html', value); + else node[properties.text] = value; + }; +})(propertySetters.text); + +propertyGetters.text = (function(getter){ + return function(node){ + return (node.get('tag') == 'style') ? node.innerHTML : getter(node); + }; +})(propertyGetters.text); +/**/ + +// Booleans + +var bools = [ + 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', + 'disabled', 'readOnly', 'multiple', 'selected', 'noresize', + 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay', + 'loop' +]; + +var booleans = {}; +Array.forEach(bools, function(bool){ + var lower = bool.toLowerCase(); + booleans[lower] = bool; + propertySetters[lower] = function(node, value){ + node[bool] = !!value; + }; + propertyGetters[lower] = function(node){ + return !!node[bool]; + }; +}); + +// Special cases + +Object.append(propertySetters, { + + 'class': function(node, value){ + ('className' in node) ? node.className = (value || '') : node.setAttribute('class', value); + }, + + 'for': function(node, value){ + ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value); + }, + + 'style': function(node, value){ + (node.style) ? node.style.cssText = value : node.setAttribute('style', value); + }, + + 'value': function(node, value){ + node.value = (value != null) ? value : ''; + } + +}); + +propertyGetters['class'] = function(node){ + return ('className' in node) ? node.className || null : node.getAttribute('class'); +}; + +/* */ +var el = document.createElement('button'); +// IE sets type as readonly and throws +try { el.type = 'button'; } catch(e){} +if (el.type != 'button') propertySetters.type = function(node, value){ + node.setAttribute('type', value); +}; +el = null; +/* */ + +/**/ + +/**/ +// #2479 - IE8 Cannot set HTML of style element +var canChangeStyleHTML = (function(){ + var div = document.createElement('style'), + flag = false; + try { + div.innerHTML = '#justTesing{margin: 0px;}'; + flag = !!div.innerHTML; + } catch(e){} + return flag; +})(); +/**/ + +var input = document.createElement('input'), volatileInputValue, html5InputSupport; + +// #2178 +input.value = 't'; +input.type = 'submit'; +volatileInputValue = input.value != 't'; + +// #2443 - IE throws "Invalid Argument" when trying to use html5 input types +try { + input.type = 'email'; + html5InputSupport = input.type == 'email'; +} catch(e){} + +input = null; + +if (volatileInputValue || !html5InputSupport) propertySetters.type = function(node, type){ + try { + var value = node.value; + node.type = type; + node.value = value; + } catch (e){} +}; +/**/ + +/* getProperty, setProperty */ + +/* */ +var pollutesGetAttribute = (function(div){ + div.random = 'attribute'; + return (div.getAttribute('random') == 'attribute'); +})(document.createElement('div')); + +var hasCloneBug = (function(test){ + test.innerHTML = ''; + return test.cloneNode(true).firstChild.childNodes.length != 1; +})(document.createElement('div')); +/* */ + +var hasClassList = !!document.createElement('div').classList; + +var classes = function(className){ + var classNames = (className || '').clean().split(" "), uniques = {}; + return classNames.filter(function(className){ + if (className !== "" && !uniques[className]) return uniques[className] = className; + }); +}; + +var addToClassList = function(name){ + this.classList.add(name); +}; + +var removeFromClassList = function(name){ + this.classList.remove(name); }; Element.implement({ + setProperty: function(name, value){ + var setter = propertySetters[name.toLowerCase()]; + if (setter){ + setter(this, value); + } else { + /* */ + var attributeWhiteList; + if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {}); + /* */ + + if (value == null){ + this.removeAttribute(name); + /* */ + if (pollutesGetAttribute) delete attributeWhiteList[name]; + /* */ + } else { + this.setAttribute(name, '' + value); + /* */ + if (pollutesGetAttribute) attributeWhiteList[name] = true; + /* */ + } + } + return this; + }, + + setProperties: function(attributes){ + for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); + return this; + }, + + getProperty: function(name){ + var getter = propertyGetters[name.toLowerCase()]; + if (getter) return getter(this); + /* */ + if (pollutesGetAttribute){ + var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {}); + if (!attr) return null; + if (attr.expando && !attributeWhiteList[name]){ + var outer = this.outerHTML; + // segment by the opening tag and find mention of attribute name + if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null; + attributeWhiteList[name] = true; + } + } + /* */ + var result = Slick.getAttribute(this, name); + return (!result && !Slick.hasAttribute(this, name)) ? null : result; + }, + + getProperties: function(){ + var args = Array.from(arguments); + return args.map(this.getProperty, this).associate(args); + }, + + removeProperty: function(name){ + return this.setProperty(name, null); + }, + + removeProperties: function(){ + Array.each(arguments, this.removeProperty, this); + return this; + }, + set: function(prop, value){ var property = Element.Properties[prop]; (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value); @@ -3095,58 +3268,27 @@ Element.implement({ 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); + hasClass: hasClassList ? function(className){ + return this.classList.contains(className); + } : function(className){ + return classes(this.className).contains(className); + }, + + addClass: hasClassList ? function(className){ + classes(className).forEach(addToClassList, this); + return this; + } : function(className){ + this.className = classes(className + ' ' + this.className).join(' '); return this; }, - setProperties: function(attributes){ - for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); + removeClass: hasClassList ? function(className){ + classes(className).forEach(removeFromClassList, this); 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'); + } : function(className){ + var classNames = classes(this.className); + classes(className).forEach(classNames.erase, classNames); + this.className = classNames.join(' '); return this; }, @@ -3194,58 +3336,6 @@ Element.implement({ 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){ @@ -3269,7 +3359,61 @@ Element.implement({ }); }); return queryString.join('&'); - }, + } + +}); + + +// appendHTML + +var appendInserters = { + before: 'beforeBegin', + after: 'afterEnd', + bottom: 'beforeEnd', + top: 'afterBegin', + inside: 'beforeEnd' +}; + +Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){ + this.insertAdjacentHTML(appendInserters[where || 'bottom'], html); + return this; +} : function(html, where){ + var temp = new Element('div', {html: html}), + children = temp.childNodes, + fragment = temp.firstChild; + + if (!fragment) return this; + if (children.length > 1){ + fragment = document.createDocumentFragment(); + for (var i = 0, l = children.length; i < l; i++){ + fragment.appendChild(children[i]); + } + } + + inserters[where || 'bottom'](fragment, this); + return this; +}); + +var collected = {}, storage = {}; + +var get = function(uid){ + return (storage[uid] || (storage[uid] = {})); +}; + +var clean = function(item){ + var uid = item.uniqueNumber; + if (item.removeEvents) item.removeEvents(); + if (item.clearAttributes) item.clearAttributes(); + if (uid != null){ + delete collected[uid]; + delete storage[uid]; + } + return item; +}; + +var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; + +Element.implement({ destroy: function(){ var children = clean(this).getElementsByTagName('*'); @@ -3287,66 +3431,49 @@ Element.implement({ return (this.parentNode) ? this.parentNode.removeChild(this) : this; }, - match: function(expression){ - return !expression || Slick.match(this, expression); - } + clone: function(contents, keepid){ + contents = contents !== false; + var clone = this.cloneNode(contents), ce = [clone], te = [this], i; -}); - -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; + if (contents){ + ce.append(Array.from(clone.getElementsByTagName('*'))); + te.append(Array.from(this.getElementsByTagName('*'))); } + + for (i = ce.length; i--;){ + var node = ce[i], element = te[i]; + if (!keepid) node.removeAttribute('id'); + /**/ + if (node.clearAttributes){ + node.clearAttributes(); + node.mergeAttributes(element); + node.removeAttribute('uniqueNumber'); + if (node.options){ + var no = node.options, eo = element.options; + for (var j = no.length; j--;) no[j].selected = eo[j].selected; + } + } + /**/ + var prop = formProps[element.tagName.toLowerCase()]; + if (prop && element[prop]) node[prop] = element[prop]; + } + + /**/ + if (hasCloneBug){ + 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 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 (window.attachEvent && !window.addEventListener){ + collected[Slick.uidOf(this)] = this; } if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]); else this.attachEvent('on' + type, fn); @@ -3360,19 +3487,19 @@ if (!document.createElement('div').contains) Element.implement(contains); }, retrieve: function(property, dflt){ - var storage = get($uid(this)), prop = storage[property]; + var storage = get(Slick.uidOf(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)); + var storage = get(Slick.uidOf(this)); storage[property] = value; return this; }, eliminate: function(property){ - var storage = get($uid(this)); + var storage = get(Slick.uidOf(this)); delete storage[property]; return this; } @@ -3380,14 +3507,16 @@ if (!document.createElement('div').contains) Element.implement(contains); }); /**/ -if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){ - Object.each(collected, clean); - if (window.CollectGarbage) CollectGarbage(); -}); +if (window.attachEvent && !window.addEventListener){ + var gc = function(){ + Object.each(collected, clean); + if (window.CollectGarbage) CollectGarbage(); + window.removeListener('unload', gc); + } + window.addListener('unload', gc); +} /**/ -})(); - Element.Properties = {}; @@ -3416,245 +3545,269 @@ Element.Properties.tag = { }; +Element.Properties.html = { + + set: function(html){ + if (html == null) html = ''; + else if (typeOf(html) == 'array') html = html.join(''); + + /**/ + if (this.styleSheet && !canChangeStyleHTML) this.styleSheet.cssText = html; + else /**/this.innerHTML = html; + }, + erase: function(){ + this.set('html', ''); + } + +}; + +var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true; + /**/ -(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')); +// technique by jdbarlett - http://jdbartlett.com/innershiv/ +var div = document.createElement('div'); +div.innerHTML = ''; +supportsHTML5Elements = (div.childNodes.length == 1); +if (!supportsHTML5Elements){ + var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '), + fragment = document.createDocumentFragment(), l = tags.length; + while (l--) fragment.createElement(tags[l]); +} +div = null; /**/ -/**/ -Element.Properties.html = (function(){ +/**/ +supportsTableInnerHTML = Function.attempt(function(){ + var table = document.createElement('table'); + table.innerHTML = ''; + return true; +}); - var tableTest = Function.attempt(function(){ - var table = document.createElement('table'); - table.innerHTML = ''; - }); +/**/ +var tr = document.createElement('tr'), html = ''; +tr.innerHTML = html; +supportsTRInnerHTML = (tr.innerHTML == html); +tr = null; +/**/ - var wrapper = document.createElement('div'); +if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){ - var translations = { - table: [1, '', '
'], - select: [1, ''], - tbody: [2, '', '
'], - tr: [3, '', '
'] - }; - translations.thead = translations.tfoot = translations.tbody; + Element.Properties.html.set = (function(set){ - 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; - } + var translations = { + table: [1, '', '
'], + select: [1, ''], + tbody: [2, '', '
'], + tr: [3, '', '
'] + }; + + translations.thead = translations.tfoot = translations.tbody; + + return function(html){ + + /**/ + if (this.styleSheet) return set.call(this, html); + /**/ + var wrap = translations[this.get('tag')]; + if (!wrap && !supportsHTML5Elements) wrap = [0, '', '']; + if (!wrap) return set.call(this, html); + + var level = wrap[0], wrapper = document.createElement('div'), target = wrapper; + if (!supportsHTML5Elements) fragment.appendChild(wrapper); + wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join(''); + while (level--) target = target.firstChild; + this.empty().adopt(target.childNodes); + if (!supportsHTML5Elements) fragment.removeChild(wrapper); + wrapper = null; + }; + + })(Element.Properties.html.set); +} +/*
*/ + +/**/ +var testForm = document.createElement('form'); +testForm.innerHTML = ''; + +if (testForm.firstChild.value != 's') Element.Properties.value = { + + set: function(value){ + var tag = this.get('tag'); + if (tag != 'select') return this.setProperty('value', value); + var options = this.getElements('option'); + value = String(value); + for (var i = 0; i < options.length; i++){ + var option = options[i], + attr = option.getAttributeNode('value'), + optionValue = (attr && attr.specified) ? option.value : option.get('text'); + if (optionValue === value) return option.selected = true; } - }; + }, - html.erase = html.set; + get: function(){ + var option = this, tag = option.get('tag'); + + if (tag != 'select' && tag != 'option') return this.getProperty('value'); + + if (tag == 'select' && !(option = option.getSelected()[0])) return ''; + + var attr = option.getAttributeNode('value'); + return (attr && attr.specified) ? option.value : option.get('text'); + } + +}; +testForm = null; +/**/ + +/**/ +if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = { + set: function(id){ + this.id = this.getAttributeNode('id').value = id; + }, + get: function(){ + return this.id || null; + }, + erase: function(){ + this.id = this.getAttributeNode('id').value = ''; + } +}; +/**/ - return html; })(); -/**/ - /* --- -name: Element.Style +name: Event -description: Contains methods for interacting with the styles of Elements in a fashionable way. +description: Contains the Event Type, to make the event object cross-browser. license: MIT-style license. -requires: Element +requires: [Window, Document, Array, Function, String, Object] -provides: Element.Style +provides: Event ... */ (function(){ -var html = document.html; +var _keys = {}; +var normalizeWheelSpeed = function(event){ + var normalized; + if (event.wheelDelta){ + normalized = event.wheelDelta % 120 == 0 ? event.wheelDelta / 120 : event.wheelDelta / 12; + } else { + var rawAmount = event.deltaY || event.detail || 0; + normalized = -(rawAmount % 3 == 0 ? rawAmount / 3 : rawAmount * 10); + } + return normalized; +} -Element.Properties.styles = {set: function(styles){ - this.setStyles(styles); -}}; +var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ + if (!win) win = window; + event = event || win.event; + if (event.$extended) return event; + this.event = event; + this.$extended = true; + this.shift = event.shiftKey; + this.control = event.ctrlKey; + this.alt = event.altKey; + this.meta = event.metaKey; + var type = this.type = event.type; + var target = event.target || event.srcElement; + while (target && target.nodeType == 3) target = target.parentNode; + this.target = document.id(target); -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); + if (type.indexOf('key') == 0){ + var code = this.code = (event.which || event.keyCode); + this.key = _keys[code]; + if (type == 'keydown' || type == 'keyup'){ + if (code > 111 && code < 124) this.key = 'f' + (code - 111); + else if (code > 95 && code < 106) this.key = code - 96; + } + if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); + } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'wheel' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ + var doc = win.document; + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + this.page = { + x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, + y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop + }; + this.client = { + x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY + }; + if (type == 'DOMMouseScroll' || type == 'wheel' || type == 'mousewheel') this.wheel = normalizeWheelSpeed(event); + this.rightClick = (event.which == 3 || event.button == 2); + if (type == 'mouseover' || type == 'mouseout'){ + var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; + while (related && related.nodeType == 3) related = related.parentNode; + this.relatedTarget = document.id(related); + } + } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ + 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]; + this.page = {x: touch.pageX, y: touch.pageY}; + this.client = {x: touch.clientX, y: touch.clientY}; + } } -}; + if (!this.client) this.client = {}; + if (!this.page) this.page = {}; +}); -var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat'; +DOMEvent.implement({ -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; + stop: function(){ + return this.preventDefault().stopPropagation(); }, - setOpacity: function(value){ - setOpacity(this, value); + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; 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; + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; 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: '@' +DOMEvent.defineKey = function(code, key){ + _keys[code] = key; + return this; }; +DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); - -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(@, @, @)'; +DOMEvent.defineKeys({ + '38': 'up', '40': 'down', '37': 'left', '39': 'right', + '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', + '46': 'delete', '13': 'enter' }); })(); + + + /* --- name: Element.Event -description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. +description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary. license: MIT-style license. @@ -3683,14 +3836,14 @@ Element.Properties.events = {set: function(events){ condition = fn, self = this; if (custom){ - if (custom.onAdd) custom.onAdd.call(this, fn); + if (custom.onAdd) custom.onAdd.call(this, fn, type); if (custom.condition){ condition = function(event){ - if (custom.condition.call(this, event)) return fn.call(this, event); + if (custom.condition.call(this, event, type)) return fn.call(this, event); return true; }; } - realType = custom.base || realType; + if (custom.base) realType = Function.from(custom.base).call(this, type); } var defn = function(){ return fn.call(self); @@ -3699,7 +3852,7 @@ Element.Properties.events = {set: function(events){ if (nativeEvent){ if (nativeEvent == 2){ defn = function(event){ - event = new Event(event, self.getWindow()); + event = new DOMEvent(event, self.getWindow()); if (condition.call(self, event) === false) event.stop(); }; } @@ -3720,8 +3873,8 @@ Element.Properties.events = {set: function(events){ delete list.values[index]; var custom = Element.Events[type]; if (custom){ - if (custom.onRemove) custom.onRemove.call(this, fn); - type = custom.base || type; + if (custom.onRemove) custom.onRemove.call(this, fn, type); + if (custom.base) type = Function.from(custom.base).call(this, type); } return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this; }, @@ -3781,15 +3934,22 @@ Element.Properties.events = {set: function(events){ Element.NativeEvents = { click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons - mousewheel: 2, DOMMouseScroll: 2, //mouse wheel + wheel: 2, 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 + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 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 + hashchange: 1, popstate: 2, // history + error: 1, abort: 1, scroll: 1, message: 2 //misc +}; + +Element.Events = { + mousewheel: { + base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll' + } }; var check = function(event){ @@ -3799,28 +3959,476 @@ var check = function(event){ return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related)); }; -Element.Events = { - - mouseenter: { +if ('onmouseenter' in document.documentElement){ + Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2; + Element.MouseenterCheck = check; +} else { + Element.Events.mouseenter = { base: 'mouseover', condition: check - }, + }; - mouseleave: { + Element.Events.mouseleave = { base: 'mouseout', condition: check - }, + }; +} - mousewheel: { - base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel' - } - -}; +/**/ +if (!window.addEventListener){ + Element.NativeEvents.propertychange = 2; + Element.Events.change = { + base: function(){ + var type = this.type; + return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'; + }, + condition: function(event){ + return event.type != 'propertychange' || event.event.propertyName == 'checked'; + } + }; +} +/**/ })(); +/* +--- + +name: Element.Delegation + +description: Extends the Element native object to include the delegate method for more efficient event management. + +license: MIT-style license. + +requires: [Element.Event] + +provides: [Element.Delegation] + +... +*/ + +(function(){ + +var eventListenerSupport = !!window.addEventListener; + +Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2; + +var bubbleUp = function(self, match, fn, event, target){ + while (target && target != self){ + if (match(target, event)) return fn.call(target, event, target); + target = document.id(target.parentNode); + } +}; + +var map = { + mouseenter: { + base: 'mouseover', + condition: Element.MouseenterCheck + }, + mouseleave: { + base: 'mouseout', + condition: Element.MouseenterCheck + }, + focus: { + base: 'focus' + (eventListenerSupport ? '' : 'in'), + capture: true + }, + blur: { + base: eventListenerSupport ? 'blur' : 'focusout', + capture: true + } +}; + +/**/ +var _key = '$delegation:'; +var formObserver = function(type){ + + return { + + base: 'focusin', + + remove: function(self, uid){ + var list = self.retrieve(_key + type + 'listeners', {})[uid]; + if (list && list.forms) for (var i = list.forms.length; i--;){ + // the form may have been destroyed, so it won't have the + // removeEvent method anymore. In that case the event was + // removed as well. + if (list.forms[i].removeEvent) list.forms[i].removeEvent(type, list.fns[i]); + } + }, + + listen: function(self, match, fn, event, target, uid){ + var form = (target.get('tag') == 'form') ? target : event.target.getParent('form'); + if (!form) return; + + var listeners = self.retrieve(_key + type + 'listeners', {}), + listener = listeners[uid] || {forms: [], fns: []}, + forms = listener.forms, fns = listener.fns; + + if (forms.indexOf(form) != -1) return; + forms.push(form); + + var _fn = function(event){ + bubbleUp(self, match, fn, event, target); + }; + form.addEvent(type, _fn); + fns.push(_fn); + + listeners[uid] = listener; + self.store(_key + type + 'listeners', listeners); + } + }; +}; + +var inputObserver = function(type){ + return { + base: 'focusin', + listen: function(self, match, fn, event, target){ + var events = {blur: function(){ + this.removeEvents(events); + }}; + events[type] = function(event){ + bubbleUp(self, match, fn, event, target); + }; + event.target.addEvents(events); + } + }; +}; + +if (!eventListenerSupport) Object.append(map, { + submit: formObserver('submit'), + reset: formObserver('reset'), + change: inputObserver('change'), + select: inputObserver('select') +}); +/**/ + +var proto = Element.prototype, + addEvent = proto.addEvent, + removeEvent = proto.removeEvent; + +var relay = function(old, method){ + return function(type, fn, useCapture){ + if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture); + var parsed = Slick.parse(type).expressions[0][0]; + if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture); + var newType = parsed.tag; + parsed.pseudos.slice(1).each(function(pseudo){ + newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : ''); + }); + old.call(this, type, fn); + return method.call(this, newType, parsed.pseudos[0].value, fn); + }; +}; + +var delegation = { + + addEvent: function(type, match, fn){ + var storage = this.retrieve('$delegates', {}), stored = storage[type]; + if (stored) for (var _uid in stored){ + if (stored[_uid].fn == fn && stored[_uid].match == match) return this; + } + + var _type = type, _match = match, _fn = fn, _map = map[type] || {}; + type = _map.base || _type; + + match = function(target){ + return Slick.match(target, _match); + }; + + var elementEvent = Element.Events[_type]; + if (_map.condition || elementEvent && elementEvent.condition){ + var __match = match, condition = _map.condition || elementEvent.condition; + match = function(target, event){ + return __match(target, event) && condition.call(target, event, type); + }; + } + + var self = this, uid = String.uniqueID(); + var delegator = _map.listen ? function(event, target){ + if (!target && event && event.target) target = event.target; + if (target) _map.listen(self, match, fn, event, target, uid); + } : function(event, target){ + if (!target && event && event.target) target = event.target; + if (target) bubbleUp(self, match, fn, event, target); + }; + + if (!stored) stored = {}; + stored[uid] = { + match: _match, + fn: _fn, + delegator: delegator + }; + storage[_type] = stored; + return addEvent.call(this, type, delegator, _map.capture); + }, + + removeEvent: function(type, match, fn, _uid){ + var storage = this.retrieve('$delegates', {}), stored = storage[type]; + if (!stored) return this; + + if (_uid){ + var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {}; + type = _map.base || _type; + if (_map.remove) _map.remove(this, _uid); + delete stored[_uid]; + storage[_type] = stored; + return removeEvent.call(this, type, delegator, _map.capture); + } + + var __uid, s; + if (fn) for (__uid in stored){ + s = stored[__uid]; + if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid); + } else for (__uid in stored){ + s = stored[__uid]; + if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid); + } + return this; + } + +}; + +[Element, Window, Document].invoke('implement', { + addEvent: relay(addEvent, delegation.addEvent), + removeEvent: relay(removeEvent, delegation.removeEvent) +}); + +})(); + +/* +--- + +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, el; + +// +// Check for oldIE, which does not remove styles when they're set to null +el = document.createElement('div'); +el.style.color = 'red'; +el.style.color = null; +var doesNotRemoveStyles = el.style.color == 'red'; + +// check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color) +var border = '1px solid #123abc'; +el.style.border = border; +var returnsBordersInWrongOrder = el.style.border != border; +el = null; +// + +var hasGetComputedStyle = !!window.getComputedStyle, + supportBorderRadius = document.createElement('div').style.borderRadius != null; + +Element.Properties.styles = {set: function(styles){ + this.setStyles(styles); +}}; + +var hasOpacity = (html.style.opacity != null), + hasFilter = (html.style.filter != null), + reAlpha = /alpha\(opacity=([\d.]+)\)/i; + +var setVisibility = function(element, opacity){ + element.store('$opacity', opacity); + element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden'; +}; + +// +var setFilter = function(element, regexp, value){ + var style = element.style, + filter = style.filter || element.getComputedStyle('filter') || ''; + style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim(); + if (!style.filter) style.removeAttribute('filter'); +}; +// + +var setOpacity = (hasOpacity ? function(element, opacity){ + element.style.opacity = opacity; +} : (hasFilter ? function(element, opacity){ + if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; + if (opacity == null || opacity == 1){ + setFilter(element, reAlpha, ''); + if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)'); + } else { + setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')'); + } +} : setVisibility)); + +var getOpacity = (hasOpacity ? function(element){ + var opacity = element.style.opacity || element.getComputedStyle('opacity'); + return (opacity == '') ? 1 : opacity.toFloat(); +} : (hasFilter ? function(element){ + var filter = (element.style.filter || element.getComputedStyle('filter')), + opacity; + if (filter) opacity = filter.match(reAlpha); + return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); +} : function(element){ + var opacity = element.retrieve('$opacity'); + if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); + return opacity; +})); + +var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat', + namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'}, + hasBackgroundPositionXY = (html.style.backgroundPositionX != null); + +// +var removeStyle = function(style, property){ + if (property == 'backgroundPosition'){ + style.removeAttribute(property + 'X'); + property += 'Y'; + } + style.removeAttribute(property); +}; +// + +Element.implement({ + + getComputedStyle: function(property){ + if (!hasGetComputedStyle && 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()) : ''; + }, + + setStyle: function(property, value){ + if (property == 'opacity'){ + if (value != null) value = parseFloat(value); + setOpacity(this, value); + return this; + } + property = (property == 'float' ? floatName : 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; + // + if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){ + removeStyle(this.style, property); + } + // + return this; + }, + + getStyle: function(property){ + if (property == 'opacity') return getOpacity(this); + property = (property == 'float' ? floatName : property).camelCase(); + if (supportBorderRadius && property.indexOf('borderRadius') != -1){ + return ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'].map(function(corner){ + return this.style[corner] || '0px'; + }, this).join(' '); + } + var result = this.style[property]; + if (!result || property == 'zIndex'){ + if (Element.ShortStyles.hasOwnProperty(property)){ + result = []; + for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s)); + return result.join(' '); + } + result = this.getComputedStyle(property); + } + if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){ + return result.replace(/(top|right|bottom|left)/g, function(position){ + return namedPositions[position]; + }) || '0px'; + } + if (!result && property == 'backgroundPosition') return '0px 0px'; + if (result){ + result = String(result); + var color = result.match(/rgba?\([\d\s,]+\)/); + if (color) result = result.replace(color[0], color[0].rgbToHex()); + } + if (!hasGetComputedStyle && !this.style[property]){ + if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){ + 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 ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){ + return '0px'; + } + } + // + if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){ + return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1'); + } + // + + 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(@, @, @)', backgroundSize: '@px', 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: '@', borderRadius: '@px @px @px @px' +}; + + + + + +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(@, @, @)'; +}); + +if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'}; +})(); /* --- @@ -3851,6 +4459,23 @@ element.appendChild(child); var brokenOffsetParent = (child.offsetParent === element); element = child = null; +var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'], + widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth']; + +var svgCalculateSize = function(el){ + + var gCS = window.getComputedStyle(el), + bounds = {x: 0, y: 0}; + + heightComponents.each(function(css){ + bounds.y += parseFloat(gCS[css]); + }); + widthComponents.each(function(css){ + bounds.x += parseFloat(gCS[css]); + }); + return bounds; +}; + var isOffset = function(el){ return styleString(el, 'position') != 'static' || isBody(el); }; @@ -3873,7 +4498,18 @@ Element.implement({ getSize: function(){ if (isBody(this)) return this.getWindow().getSize(); - return {x: this.offsetWidth, y: this.offsetHeight}; + + // + // This if clause is because IE8- cannot calculate getBoundingClientRect of elements with visibility hidden. + if (!window.getComputedStyle) return {x: this.offsetWidth, y: this.offsetHeight}; + // + + // This svg section under, calling `svgCalculateSize()`, can be removed when FF fixed the svg size bug. + // Bug info: https://bugzilla.mozilla.org/show_bug.cgi?id=530985 + if (this.get('tag') == 'svg') return svgCalculateSize(this); + + var bounds = this.getBoundingClientRect(); + return {x: bounds.width, y: bounds.height}; }, getScrollSize: function(){ @@ -3911,12 +4547,14 @@ Element.implement({ try { return element.offsetParent; - } catch(e) {} + } catch(e){} return null; }, getOffsets: function(){ - if (this.getBoundingClientRect && !Browser.Platform.ios){ + var hasGetBoundingClientRect = this.getBoundingClientRect; + + if (hasGetBoundingClientRect){ var bound = this.getBoundingClientRect(), html = document.id(this.getDocument().documentElement), htmlScroll = html.getScroll(), @@ -3925,7 +4563,7 @@ Element.implement({ 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 + y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop }; } @@ -3936,39 +4574,20 @@ Element.implement({ 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)}; @@ -4106,7 +4725,6 @@ Element.alias({position: 'setPosition'}); //compatability }); - /* --- @@ -4162,7 +4780,7 @@ var Fx = this.Fx = new Class({ } 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)); @@ -4205,7 +4823,7 @@ var Fx = this.Fx = new Class({ pushInstance.call(this, fps); return this; }, - + stop: function(){ if (this.isRunning()){ this.time = null; @@ -4219,7 +4837,7 @@ var Fx = this.Fx = new Class({ } return this; }, - + cancel: function(){ if (this.isRunning()){ this.time = null; @@ -4229,7 +4847,7 @@ var Fx = this.Fx = new Class({ } return this; }, - + pause: function(){ if (this.isRunning()){ this.time = null; @@ -4237,15 +4855,19 @@ var Fx = this.Fx = new Class({ } return this; }, - + resume: function(){ - if ((this.frame < this.frames) && !this.isRunning()) pushInstance.call(this, this.options.fps); + if (this.isPaused()) pushInstance.call(this, this.options.fps); return this; }, - + isRunning: function(){ var list = instances[this.options.fps]; return list && list.contains(this); + }, + + isPaused: function(){ + return (this.frame < this.frames) && !this.isRunning(); } }); @@ -4287,7 +4909,6 @@ var pullInstance = function(fps){ })(); - /* --- @@ -4312,12 +4933,31 @@ Fx.CSS = new Class({ prepare: function(element, property, values){ values = Array.from(values); - if (values[1] == null){ - values[1] = values[0]; - values[0] = element.getStyle(property); + var from = values[0], to = values[1]; + if (to == null){ + to = from; + from = element.getStyle(property); + var unit = this.options.unit; + // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299 + if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){ + element.setStyle(property, to + unit); + var value = element.getComputedStyle(property); + // IE and Opera support pixelLeft or pixelWidth + if (!(/px$/.test(value))){ + value = element.style[('pixel-' + property).camelCase()]; + if (value == null){ + // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + var left = element.style.left; + element.style.left = to + unit; + value = element.style.pixelLeft; + element.style.left = left; + } + } + from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0); + element.setStyle(property, from + unit); + } } - var parsed = values.map(this.parse); - return {from: parsed[0], to: parsed[1]}; + return {from: this.parse(from), to: this.parse(to)}; }, //parses a value into an array @@ -4371,11 +5011,13 @@ Fx.CSS = new Class({ 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; + + var searchStyles = function(rules){ Array.each(rules, function(rule, i){ + if (rule.media){ + searchStyles(rule.rules || rule.cssRules); + return; + } if (!rule.style) return; var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ return m.toLowerCase(); @@ -4387,6 +5029,13 @@ Fx.CSS = new Class({ to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value; }); }); + }; + + Array.each(document.styleSheets, function(sheet, j){ + var href = sheet.href; + if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return; + var rules = sheet.rules || sheet.cssRules; + searchStyles(rules); }); return Fx.CSS.Cache[selector] = to; } @@ -4434,112 +5083,6 @@ Fx.CSS.Parsers = { - -/* ---- - -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; - } - -}); - - /* --- @@ -4618,7 +5161,6 @@ Element.implement({ }); - /* --- @@ -4729,6 +5271,117 @@ Fx.Transitions.extend({ }); }); +/* +--- + +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(property, from, to); + return this; + }, + + fade: function(how){ + var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle; + if (args[1] == null) args[1] = 'toggle'; + switch (args[1]){ + case 'in': method = 'start'; args[1] = 1; break; + case 'out': method = 'start'; args[1] = 0; break; + case 'show': method = 'set'; args[1] = 1; break; + case 'hide': method = 'set'; args[1] = 0; break; + case 'toggle': + var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1); + method = 'start'; + args[1] = flag ? 0 : 1; + this.store('fade:flag', !flag); + toggle = true; + break; + default: method = 'start'; + } + if (!toggle) this.eliminate('fade:flag'); + fade[method].apply(fade, args); + var to = args[args.length - 1]; + if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible'); + else fade.chain(function(){ + this.element.setStyle('visibility', 'hidden'); + this.callChain(); + }); + 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; + } + +}); /* --- @@ -4766,7 +5419,8 @@ var Request = this.Request = new Class({ onException: function(headerName, value){}, onTimeout: function(){}, user: '', - password: '',*/ + password: '', + withCredentials: false,*/ url: '', data: '', headers: { @@ -4804,8 +5458,11 @@ var Request = this.Request = new Class({ }.bind(this)); xhr.onreadystatechange = empty; if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; - clearTimeout(this.timer); - + if (this.timer){ + clearTimeout(this.timer); + delete 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); @@ -4842,15 +5499,15 @@ var Request = this.Request = new Class({ 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); }, @@ -4874,7 +5531,7 @@ var Request = this.Request = new Class({ } return false; }, - + send: function(options){ if (!this.check(options)) return this; @@ -4910,15 +5567,15 @@ var Request = this.Request = new Class({ } 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(); + url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID(); - if (data && method == 'get'){ - url += (url.contains('?') ? '&' : '?') + data; + if (data && (method == 'get' || method == 'delete')){ + url += (url.indexOf('?') > -1 ? '&' : '?') + data; data = null; } @@ -4929,8 +5586,8 @@ var Request = this.Request = new Class({ } xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password); - if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true; - + if ((this.options.withCredentials) && 'withCredentials' in xhr) xhr.withCredentials = true; + xhr.onreadystatechange = this.onStateChange.bind(this); Object.each(this.headers, function(value, key){ @@ -4944,7 +5601,7 @@ var Request = this.Request = new Class({ 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); + else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this); return this; }, @@ -4953,7 +5610,10 @@ var Request = this.Request = new Class({ this.running = false; var xhr = this.xhr; xhr.abort(); - clearTimeout(this.timer); + if (this.timer){ + clearTimeout(this.timer); + delete this.timer; + } xhr.onreadystatechange = empty; if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; this.xhr = new Browser.Request(); @@ -4964,7 +5624,7 @@ var Request = this.Request = new Class({ }); var methods = {}; -['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ +['get', 'post', 'put', 'delete', 'patch', 'head', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'].each(function(method){ methods[method] = function(data){ var object = { method: method @@ -5051,11 +5711,18 @@ Request.HTML = new Class({ var temp = new Element('div').set('html', response.html); response.tree = temp.childNodes; - response.elements = temp.getElements('*'); + response.elements = temp.getElements(options.filter || '*'); - 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.filter) response.tree = response.elements; + if (options.update){ + var update = document.id(options.update).empty(); + if (options.filter) update.adopt(response.elements); + else update.set('html', response.html); + } else if (options.append){ + var append = document.id(options.append); + if (options.filter) response.elements.reverse().inject(append); + else append.adopt(temp.getChildren()); + } if (options.evalScripts) Browser.exec(response.javascript); this.onSuccess(response.tree, response.elements, response.html, response.javascript); @@ -5091,7 +5758,6 @@ Element.implement({ }); - /* --- @@ -5101,7 +5767,7 @@ description: JSON encoder and decoder. license: MIT-style license. -See Also: +SeeAlso: requires: [Array, String, Number, Function] @@ -5154,10 +5820,14 @@ JSON.encode = JSON.stringify ? function(obj){ return null; }; +JSON.secure = true; + + JSON.decode = function(string, secure){ if (!string || typeOf(string) != 'string') return null; - - if (secure || JSON.secure){ + + if (secure == null) secure = JSON.secure; + if (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.'); } @@ -5167,7 +5837,6 @@ JSON.decode = function(string, secure){ })(); - /* --- @@ -5215,7 +5884,6 @@ Request.JSON = new Class({ }); - /* --- @@ -5291,7 +5959,6 @@ Cookie.dispose = function(key, options){ return new Cookie(key, options).dispose(); }; - /* --- @@ -5319,12 +5986,14 @@ var ready, 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'); + if (!ready) { + Browser.loaded = ready = true; + document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check); + document.fireEvent('domready'); + window.fireEvent('domready'); + } + // cleanup scope vars + document = window = testElement = null; }; var check = function(){ @@ -5351,7 +6020,7 @@ var doScrollWorks = function(){ 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()){ @@ -5397,119 +6066,3 @@ window.addEvent('load', function(){ }); })(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-more-1.3.2.1-yc.js b/web/tools/mootools/mootools-more-1.3.2.1-yc.js deleted file mode 100644 index 807e27ecf..000000000 --- a/web/tools/mootools/mootools-more-1.3.2.1-yc.js +++ /dev/null @@ -1,742 +0,0 @@ -// 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/tools/mootools/mootools-more-1.3.2.1-nc.js b/web/tools/mootools/mootools-more-1.5.1.js similarity index 57% rename from web/tools/mootools/mootools-more-1.3.2.1-nc.js rename to web/tools/mootools/mootools-more-1.5.1.js index 4bf490e79..15a277029 100644 --- a/web/tools/mootools/mootools-more-1.3.2.1-nc.js +++ b/web/tools/mootools/mootools-more-1.5.1.js @@ -1,6 +1,7 @@ -// 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 +/* MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2015 [Valerio Proietti](http://mad4milk.net/).*/ +/* +Web Build: http://mootools.net/more/builder/a3048f4bfdf603b22a69c141dbd0fca9 +*/ /* --- @@ -31,11 +32,10 @@ provides: [MooTools.More] */ MooTools.More = { - 'version': '1.3.2.1', - 'build': 'e586bcd2496e9b22acfde32e12f84d49ce09e59d' + version: '1.5.1', + build: '2dd695ba957196ae4b0275a690765d6636a61ccd' }; - /* --- @@ -54,7 +54,7 @@ requires: - Core/Chain - Core/Element - Core/Fx - - /MooTools.More + - MooTools.More provides: [Chain.Wait] @@ -100,87 +100,3495 @@ provides: [Chain.Wait] })(); - /* --- -script: Array.Extras.js +script: Class.Binds.js -name: Array.Extras +name: Class.Binds -description: Extends the Array native object to include useful methods to work with arrays. +description: Automagically binds specified methods in a class to the instance of the class. license: MIT-style license authors: - - Christoph Pojer - - Sebastian Markbåge + - Aaron Newton requires: - - Core/Array + - Core/Class - MooTools.More -provides: [Array.Extras] +provides: [Class.Binds] ... */ -(function(nil){ +Class.Mutators.Binds = function(binds){ + if (!this.prototype.initialize) this.implement('initialize', function(){}); + return Array.from(binds).concat(this.prototype.Binds || []); +}; -Array.implement({ +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); + }; +}; - min: function(){ - return Math.min.apply(null, this); - }, +/* +--- - max: function(){ - return Math.max.apply(null, this); - }, +script: Class.Occlude.js - average: function(){ - return this.length ? this.sum() / this.length : 0; - }, +name: Class.Occlude - sum: function(){ - var result = 0, l = this.length; - if (l){ - while (l--) result += this[l]; +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: 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; + +}; + +/* +--- + +name: Events.Pseudos + +description: Adds the functionality to add pseudo events + +license: MIT-style license + +authors: + - Arian Stolwijk + +requires: [Core/Class.Extras, Core/Slick.Parser, MooTools.More] + +provides: [Events.Pseudos] + +... +*/ + +(function(){ + +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; + } + }; + }; + + var splitType = function(type){ + if (type.indexOf(':') == -1 || !pseudos) return null; + + var parsed = Slick.parse(type).expressions[0][0], + parsedPseudos = parsed.pseudos, + l = parsedPseudos.length, + splits = []; + + while (l--){ + var pseudo = parsedPseudos[l].key, + listener = pseudos[pseudo]; + if (listener != null) splits.push({ + event: parsed.tag, + value: parsedPseudos[l].value, + pseudo: pseudo, + original: type, + listener: listener + }); } - return result; - }, + return splits.length ? splits : null; + }; - unique: function(){ - return [].combine(this); - }, + return { - shuffle: function(){ - for (var i = this.length; i && --i;){ - var temp = this[i], r = Math.floor(Math.random() * ( i + 1 )); - this[i] = this[r]; - this[r] = temp; + addEvent: function(type, fn, internal){ + var split = splitType(type); + if (!split) return addEvent.call(this, type, fn, internal); + + var storage = storageOf(this), + events = storage.retrieve(type, []), + eventType = split[0].event, + args = Array.slice(arguments, 2), + stack = fn, + self = this; + + split.each(function(item){ + var listener = item.listener, + stackFn = stack; + if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')'; + else stack = function(){ + listener.call(self, item, stackFn, arguments, stack); + }; + }); + + events.include({type: eventType, event: fn, monitor: stack}); + storage.store(type, events); + + if (type != eventType) addEvent.apply(this, [type, fn].concat(args)); + return addEvent.apply(this, [eventType, stack].concat(args)); + }, + + removeEvent: function(type, fn){ + var split = splitType(type); + if (!split) return removeEvent.call(this, type, fn); + + var storage = storageOf(this), + events = storage.retrieve(type); + if (!events) return this; + + var args = Array.slice(arguments, 2); + + removeEvent.apply(this, [type, fn].concat(args)); + events.each(function(monitor, i){ + if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args)); + delete events[i]; + }, this); + + storage.store(type, events); + return this; } + + }; + +}; + +var pseudos = { + + once: function(split, fn, args, monitor){ + fn.apply(this, args); + this.removeEvent(split.event, monitor) + .removeEvent(split.original, fn); + }, + + throttle: function(split, fn, args){ + if (!fn._throttled){ + fn.apply(this, args); + fn._throttled = setTimeout(function(){ + fn._throttled = false; + }, split.value || 250); + } + }, + + pause: function(split, fn, args){ + clearTimeout(fn._pause); + fn._pause = fn.delay(split.value || 250, this, args); + } + +}; + +Events.definePseudo = function(key, listener){ + pseudos[key] = 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: Drag.js + +name: Drag + +description: The base Drag Class. Can be used to drag and resize Elements using mouse events. + +license: MIT-style license + +authors: + - Valerio Proietti + - Tom Occhinno + - Jan Kassens + +requires: + - Core/Events + - Core/Options + - Core/Element.Event + - Core/Element.Style + - Core/Element.Dimensions + - MooTools.More + +provides: [Drag] +... + +*/ + +var Drag = new Class({ + + Implements: [Events, Options], + + options: {/* + 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, + style: true, + limit: false, + handle: false, + invert: false, + preventDefault: false, + stopPropagation: false, + compensateScroll: false, + modifiers: {x: 'left', y: 'top'} + }, + + initialize: function(){ + 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 = 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.offsetParent = (function(el){ + var offsetParent = el.getOffsetParent(); + var isBody = !offsetParent || (/^(?:body|html)$/i).test(offsetParent.tagName); + return isBody ? window : document.id(offsetParent); + })(this.element); + this.selection = 'selectstart' in document ? 'selectstart' : 'mousedown'; + + this.compensateScroll = {start: {}, diff: {}, last: {}}; + + if ('ondragstart' in document && !('FileReader' in window) && !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), + scrollListener: this.scrollListener.bind(this) + }; + this.attach(); + }, + + attach: function(){ + this.handles.addEvent('mousedown', this.bound.start); + if (this.options.compensateScroll) this.offsetParent.addEvent('scroll', this.bound.scrollListener); 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; + detach: function(){ + this.handles.removeEvent('mousedown', this.bound.start); + if (this.options.compensateScroll) this.offsetParent.removeEvent('scroll', this.bound.scrollListener); + return this; }, - 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); + scrollListener: function(){ + + if (!this.mouse.start) return; + var newScrollValue = this.offsetParent.getScroll(); + + if (this.element.getStyle('position') == 'absolute'){ + var scrollDiff = this.sumValues(newScrollValue, this.compensateScroll.last, -1); + this.mouse.now = this.sumValues(this.mouse.now, scrollDiff, 1); + } else { + this.compensateScroll.diff = this.sumValues(newScrollValue, this.compensateScroll.start, -1); } - return value; + if (this.offsetParent != window) this.compensateScroll.diff = this.sumValues(this.compensateScroll.start, newScrollValue, -1); + this.compensateScroll.last = newScrollValue; + this.render(this.options); + }, + + sumValues: function(alpha, beta, op){ + var sum = {}, options = this.options; + for (z in options.modifiers){ + if (!options.modifiers[z]) continue; + sum[z] = alpha[z] + beta[z] * op; + } + return sum; + }, + + start: function(event){ + var options = this.options; + + if (event.rightClick) return; + + if (options.preventDefault) event.preventDefault(); + if (options.stopPropagation) event.stopPropagation(); + this.compensateScroll.start = this.compensateScroll.last = this.offsetParent.getScroll(); + this.compensateScroll.diff = {x: 0, y: 0}; + this.mouse.start = event.page; + this.fireEvent('beforeStart', this.element); + + var limit = options.limit; + this.limit = {x: [], y: []}; + + var z, coordinates, offsetParent = this.offsetParent == window ? null : this.offsetParent; + for (z in options.modifiers){ + if (!options.modifiers[z]) continue; + + 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(offsetParent); + style = coordinates[options.modifiers[z]]; + } + + if (options.style) this.value.now[z] = (style || 0).toInt(); + else this.value.now[z] = this.element[options.modifiers[z]]; + + if (options.invert) this.value.now[z] *= -1; + + this.mouse.pos[z] = event.page[z] - this.value.now[z]; + + if (limit && limit[z]){ + var i = 2; + while (i--){ + var limitZI = limit[z][i]; + if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI; + } + } + } + + 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){ + if (this.options.preventDefault) event.preventDefault(); + var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); + if (distance > this.options.snap){ + this.cancel(); + this.document.addEvents({ + mousemove: this.bound.drag, + mouseup: this.bound.stop + }); + this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element); + } + }, + + drag: function(event){ + var options = this.options; + if (options.preventDefault) event.preventDefault(); + this.mouse.now = this.sumValues(event.page, this.compensateScroll.diff, -1); + + this.render(options); + this.fireEvent('drag', [this.element, event]); + }, + + render: function(options){ + for (var z in options.modifiers){ + if (!options.modifiers[z]) continue; + this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; + + 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 ((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 (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]; + } + }, + + cancel: function(event){ + 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); + } + }, + + stop: function(event){ + var events = { + mousemove: this.bound.drag, + mouseup: this.bound.stop + }; + events[this.selection] = this.bound.eventStop; + this.document.removeEvents(events); + this.mouse.start = null; + if (event) this.fireEvent('complete', [this.element, event]); + } + +}); + +Element.implement({ + + makeResizable: function(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); + }.bind(this)); + } + +}); + +/* +--- + +script: Drag.Move.js + +name: Drag.Move + +description: A Drag extension that provides support for the constraining of draggables to containers and droppables. + +license: MIT-style license + +authors: + - Valerio Proietti + - Tom Occhinno + - Jan Kassens + - Aaron Newton + - Scott Kyle + +requires: + - Core/Element.Dimensions + - Drag + +provides: [Drag.Move] + +... +*/ + +Drag.Move = new Class({ + + Extends: Drag, + + options: {/* + onEnter: function(thisElement, overed){}, + onLeave: function(thisElement, overed){}, + onDrop: function(thisElement, overed, event){},*/ + droppables: [], + container: false, + precalculate: false, + includeMargins: true, + checkDroppables: true + }, + + initialize: function(element, options){ + this.parent(element, options); + element = this.element; + + this.droppables = $$(this.options.droppables); + this.setContainer(this.options.container); + + if (this.options.style){ + 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')){ + element.setPosition(element.getPosition(parent)); + } + } + + if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute'); + } + + this.addEvent('start', this.checkDroppables, true); + this.overed = null; + }, + + setContainer: function(container) { + this.container = document.id(container); + if (this.container && typeOf(this.container) != 'element'){ + this.container = document.id(this.container.getDocument().body); + } + }, + + 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 element = this.element, + container = this.container, + + offsetParent = document.id(element.getOffsetParent()) || document.body, + containerCoordinates = container.getCoordinates(offsetParent), + elementMargin = {}, + elementBorder = {}, + containerMargin = {}, + containerBorder = {}, + offsetParentPadding = {}, + offsetScroll = offsetParent.getScroll(); + + ['top', 'right', 'bottom', 'left'].each(function(pad){ + 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(); + }, this); + + var width = element.offsetWidth + elementMargin.left + elementMargin.right, + height = element.offsetHeight + elementMargin.top + elementMargin.bottom, + left = 0 + offsetScroll.x, + top = 0 + offsetScroll.y, + right = containerCoordinates.right - containerBorder.right - width + offsetScroll.x, + bottom = containerCoordinates.bottom - containerBorder.bottom - height + offsetScroll.y; + + if (this.options.includeMargins){ + left += elementMargin.left; + top += elementMargin.top; + } else { + right += elementMargin.right; + bottom += elementMargin.bottom; + } + + 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 (container != offsetParent){ + left += containerMargin.left + offsetParentPadding.left; + if (!offsetParentPadding.left && left < 0) left = 0; + top += offsetParent == document.body ? 0 : containerMargin.top + offsetParentPadding.top; + if (!offsetParentPadding.top && top < 0) top = 0; + } + } else { + left -= elementMargin.left; + top -= elementMargin.top; + if (container != offsetParent){ + left += containerCoordinates.left + containerBorder.left; + top += containerCoordinates.top + containerBorder.top; + } + } + + return { + x: [left, right], + y: [top, bottom] + }; + }, + + 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(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]); + this.overed = overed; + } + }, + + drag: function(event){ + this.parent(event); + if (this.options.checkDroppables && this.droppables.length) this.checkDroppables(); + }, + + stop: function(event){ + this.checkDroppables(); + this.fireEvent('drop', [this.element, this.overed, event]); + this.overed = null; + return this.parent(event); + } + +}); + +Element.implement({ + + makeDraggable: function(options){ + var drag = new Drag.Move(this, options); + this.store('dragger', drag); + return drag; + } + +}); + +/* +--- + +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); } }); })(); +/* +--- + +script: Slider.js + +name: Slider + +description: Class for creating horizontal and vertical slider controls. + +license: MIT-style license + +authors: + - Valerio Proietti + +requires: + - Core/Element.Dimensions + - Core/Number + - Class.Binds + - Drag + - Element.Measure + +provides: [Slider] + +... +*/ + +var Slider = new Class({ + + Implements: [Events, Options], + + Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'], + + options: {/* + onTick: function(intPosition){}, + onMove: function(){}, + onChange: function(intStep){}, + onComplete: function(strStep){},*/ + onTick: function(position){ + this.setKnobPosition(position); + }, + initialStep: 0, + snap: false, + offset: 0, + range: false, + wheel: false, + steps: 100, + mode: 'horizontal' + }, + + initialize: function(element, knob, options){ + this.setOptions(options); + options = this.options; + this.element = document.id(element); + knob = this.knob = document.id(knob); + this.previousChange = this.previousEnd = this.step = options.initialStep ? options.initialStep : options.range ? options.range[0] : 0; + + var limit = {}, + modifiers = {x: false, y: false}; + + switch (options.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(options.range, null, true); + + if (knob.getStyle('position') == 'static') knob.setStyle('position', 'relative'); + knob.setStyle(this.property, -options.offset); + modifiers[this.axis] = this.property; + limit[this.axis] = [-options.offset, this.full - options.offset]; + + var dragOptions = { + snap: 0, + limit: limit, + modifiers: modifiers, + 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 (options.snap) this.setSnap(dragOptions); + + this.drag = new Drag(knob, dragOptions); + if (options.initialStep != null) this.set(options.initialStep, true); + this.attach(); + }, + + 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(options){ + if (!options) options = this.drag.options; + options.grid = Math.ceil(this.stepWidth); + options.limit[this.axis][1] = this.element[this.offset]; + 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, silently){ + if (!((this.range > 0) ^ (step < this.min))) step = this.min; + if (!((this.range > 0) ^ (step > this.max))) step = this.max; + + this.step = (step).round(this.modulus.decimalLength); + if (silently) this.checkStep().setKnobPosition(this.toPosition(this.step)); + else this.checkStep().fireEvent('tick', this.toPosition(this.step)).fireEvent('move').end(); + return this; + }, + + setRange: function(range, pos, silently){ + 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; + var stepSize = this.stepSize = Math.abs(this.range) / this.steps; + this.stepWidth = this.stepSize * this.full / Math.abs(this.range); + this.setModulus(); + + if (range) this.set(Array.pick([pos, this.step]).limit(this.min,this.max), silently); + return this; + }, + + setModulus: function(){ + var decimals = ((this.stepSize + '').split('.')[1] || []).length, + modulus = 1 + ''; + while (decimals--) modulus += '0'; + this.modulus = {multiplier: (modulus).toInt(10), decimalLength: modulus.length - 1}; + }, + + clickedElement: function(event){ + if (this.isDragging || event.target == this.knob) return; + + 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 = (this.min + dir * this.toStep(position)).round(this.modulus.decimalLength); + + this.checkStep() + .fireEvent('tick', position) + .fireEvent('move') + .end(); + }, + + scrolledElement: function(event){ + var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0); + this.set(this.step + (mode ? -1 : 1) * this.stepSize); + event.stop(); + }, + + draggedKnob: function(){ + 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 = (this.min + dir * this.toStep(position)).round(this.modulus.decimalLength); + this.checkStep(); + this.fireEvent('move'); + }, + + checkStep: function(){ + var step = this.step; + if (this.previousChange != step){ + this.previousChange = step; + this.fireEvent('change', step); + } + return this; + }, + + end: function(){ + var step = this.step; + if (this.previousEnd !== step){ + this.previousEnd = step; + this.fireEvent('complete', step + ''); + } + return this; + }, + + toStep: function(position){ + var step = (position + this.options.offset) * this.stepSize / this.full * this.steps; + return this.options.steps ? (step - (step * this.modulus.multiplier) % (this.stepSize * this.modulus.multiplier) / this.modulus.multiplier).round(this.modulus.decimalLength) : step; + }, + + toPosition: function(step){ + return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset || 0; + } + +}); + +/* +--- + +script: Sortables.js + +name: Sortables + +description: Class for creating a drag and drop sorting interface for lists of items. + +license: MIT-style license + +authors: + - Tom Occhino + +requires: + - Core/Fx.Morph + - Drag.Move + +provides: [Sortables] + +... +*/ + +var Sortables = new Class({ + + Implements: [Events, Options], + + options: {/* + onSort: function(element, clone){}, + onStart: function(element, clone){}, + onComplete: function(element){},*/ + opacity: 1, + clone: false, + revert: false, + handle: false, + dragOptions: {}, + unDraggableTags: ['button', 'input', 'a', 'textarea', 'select', 'option'] + }, + + 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, 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(element){ + this.elements.push(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; + }, + + addLists: function(){ + Array.flatten(arguments).each(function(list){ + this.lists.include(list); + this.addItems(list.getChildren()); + }, this); + return this; + }, + + removeItems: function(){ + return $$(Array.flatten(arguments).map(function(element){ + 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)); + }, + + removeLists: function(){ + return $$(Array.flatten(arguments).map(function(list){ + this.lists.erase(list); + this.removeItems(list.getChildren()); + + return list; + }, this)); + }, + + getDroppableCoordinates: function (element){ + var offsetParent = element.getOffsetParent(); + var position = element.getPosition(offsetParent); + var scroll = { + w: window.getScroll(), + offsetParent: offsetParent.getScroll() + }; + position.x += scroll.offsetParent.x; + position.y += scroll.offsetParent.y; + + if (offsetParent.getStyle('position') == 'fixed'){ + position.x -= scroll.w.x; + position.y -= scroll.w.y; + } + + return position; + }, + + getClone: function(event, element){ + if (!this.options.clone) return new Element(element.tagName).inject(document.body); + if (typeOf(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list); + var clone = element.clone(true).setStyles({ + margin: 0, + position: 'absolute', + visibility: 'hidden', + 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){ + input.set('name', 'clone_' + i); + if (input.get('checked')) element.getElements('input[type=radio]')[i].set('checked', true); + }); + } + + return clone.inject(this.list).setPosition(this.getDroppableCoordinates(this.element)); + }, + + getDroppables: function(){ + 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){ + var where = 'inside'; + if (this.lists.contains(element)){ + this.list = element; + this.drag.droppables = this.getDroppables(); + } else { + where = this.element.getAllPrevious().contains(element) ? 'before' : 'after'; + } + this.element.inject(element, where); + this.fireEvent('sort', [this.element, this.clone]); + }, + + start: function(event, element){ + if ( + !this.idle || + event.rightClick || + (!this.options.handle && this.options.unDraggableTags.contains(event.target.get('tag'))) + ) return; + + this.idle = false; + this.element = element; + this.opacity = element.getStyle('opacity'); + this.list = element.getParent(); + this.clone = this.getClone(event, element); + + 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'); + this.element.setStyle('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(event); + }, + + end: function(){ + this.drag.detach(); + this.element.setStyle('opacity', this.opacity); + var self = this; + if (this.effect){ + var dim = this.element.getStyles('width', 'height'), + clone = this.clone, + pos = clone.computePosition(this.getDroppableCoordinates(clone)); + + var destroy = function(){ + this.removeEvent('cancel', destroy); + clone.destroy(); + self.reset(); + }; + + this.effect.element = clone; + this.effect.start({ + top: pos.top, + left: pos.left, + width: dim.width, + height: dim.height, + opacity: 0.25 + }).addEvent('cancel', destroy).chain(destroy); + } else { + this.clone.destroy(); + self.reset(); + } + + }, + + reset: function(){ + this.idle = true; + this.fireEvent('complete', this.element); + }, + + serialize: function(){ + 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'); + }, this); + }, this); + + var index = params.index; + if (this.lists.length == 1) index = 0; + return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial; + } + +}); + +/* +--- + +name: Element.Event.Pseudos + +description: Adds the functionality to add pseudo events for Elements + +license: MIT-style license + +authors: + - Arian Stolwijk + +requires: [Core/Element.Event, Core/Element.Delegation, Events.Pseudos] + +provides: [Element.Event.Pseudos, Element.Delegation.Pseudo] + +... +*/ + +(function(){ + +var pseudos = {relay: false}, + copyFromEvents = ['once', 'throttle', 'pause'], + count = copyFromEvents.length; + +while (count--) pseudos[copyFromEvents[count]] = Events.lookupPseudo(copyFromEvents[count]); + +DOMEvent.definePseudo = function(key, listener){ + pseudos[key] = 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'; + + +DOMEvent.definePseudo('keys', function(split, fn, args){ + + var event = args[0], + keys = [], + pressed = this.retrieve(keysStoreKey, []), + value = split.value; + + if (value != '+') keys.append(value.replace('++', function(){ + keys.push('+'); // shift++ and shift+++a + return ''; + }).split('+')); + else keys = ['+']; + + 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 + }; + this.store(keysKeyupStoreKey, keyup).addEvent('keyup', keyup); + } + +}); + +DOMEvent.defineKeys({ + '16': 'shift', + '17': 'control', + '18': 'alt', + '20': 'capslock', + '33': 'pageup', + '34': 'pagedown', + '35': 'end', + '36': 'home', + '144': 'numlock', + '145': 'scrolllock', + '186': ';', + '187': '=', + '188': ',', + '190': '.', + '191': '/', + '192': '`', + '219': '[', + '220': '\\', + '221': ']', + '222': "'", + '107': '+', + '109': '-', // subtract + '189': '-' // dash +}) + +})(); + +/* +--- + +script: String.Extras.js + +name: String.Extras + +description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc). + +license: MIT-style license + +authors: + - Aaron Newton + - Guillermo Rauch + - Christopher Pitt + +requires: + - Core/String + - Core/Array + - MooTools.More + +provides: [String.Extras] + +... +*/ + +(function(){ + +var special = { + '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, + '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]/g, + '*': /[\xb7]/g, + '\'': /[\u2018\u2019]/g, + '"': /[\u201c\u201d]/g, + '...': /[\u2026]/g, + '-': /[\u2013]/g, +// '--': /[\u2014]/g, + '»': /[\uFFFD]/g +}, + +conversions = { + ms: 1, + s: 1000, + m: 6e4, + h: 36e5 +}, + +findUnits = /(\d*.?\d+)([msh]+)/; + +var walk = function(string, replacements){ + var result = string, key; + for (key in replacements) result = result.replace(replacements[key], key); + return result; +}; + +var getRegexForTag = function(tag, contents){ + tag = tag || ''; + var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>", + reg = new RegExp(regstr, "gi"); + return reg; +}; + +String.implement({ + + standardize: function(){ + return walk(this, special); + }, + + repeat: function(times){ + return new Array(times + 1).join(this); + }, + + 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 (!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(getRegexForTag(tag, contents)) || []; + }, + + stripTags: function(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; + }, + + ms: function(){ + // "Borrowed" from https://gist.github.com/1503944 + var units = findUnits.exec(this); + if (units == null) return Number(this); + return Number(units[1]) * conversions[units[2]]; + } + +}); + +})(); + +/* +--- + +script: Element.Forms.js + +name: Element.Forms + +description: Extends the Element native object to include methods useful in managing inputs. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Element + - String.Extras + - MooTools.More + +provides: [Element.Forms] + +... +*/ + +Element.implement({ + + tidy: function(){ + this.set('value', this.get('value').tidy()); + }, + + getTextInRange: function(start, end){ + return this.get('value').substring(start, end); + }, + + getSelectedText: function(){ + if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd()); + return document.selection.createRange().text; + }, + + 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 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; + 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; + }, + + getSelectionStart: function(){ + return this.getSelectedRange().start; + }, + + getSelectionEnd: function(){ + return this.getSelectedRange().end; + }, + + setCaretPosition: function(pos){ + if (pos == 'end') pos = this.get('value').length; + this.selectRange(pos, pos); + return this; + }, + + getCaretPosition: function(){ + return this.getSelectedRange().start; + }, + + selectRange: function(start, end){ + if (this.setSelectionRange){ + this.focus(); + this.setSelectionRange(start, end); + } else { + var value = this.get('value'); + var diff = value.substr(start, end - start).replace(/\r/g, '').length; + start = value.substr(0, start).replace(/\r/g, '').length; + var range = this.createTextRange(); + range.collapse(true); + range.moveEnd('character', start + diff); + range.moveStart('character', start); + range.select(); + } + return this; + }, + + insertAtCursor: function(value, select){ + 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 (select !== false) this.selectRange(pos.start, pos.start + value.length); + else this.setCaretPosition(pos.start + value.length); + return this; + }, + + insertAroundCursor: function(options, select){ + 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); + } else { + 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 (select !== false) this.selectRange(selStart, selStart + current.length); + else this.setCaretPosition(selStart + text.length); + } + return this; + } + +}); + +/* +--- + +script: Element.Pin.js + +name: Element.Pin + +description: Extends the Element native object to include the pin method useful for fixed positioning for elements. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Element.Event + - Core/Element.Dimensions + - Core/Element.Style + - MooTools.More + +provides: [Element.Pin] + +... +*/ + +(function(){ + var supportsPositionFixed = false, + supportTested = false; + + var testPositionFixed = function(){ + var test = new Element('div').setStyles({ + position: 'fixed', + top: 0, + right: 0 + }).inject(document.body); + supportsPositionFixed = (test.offsetTop === 0); + test.dispose(); + supportTested = true; + }; + + Element.implement({ + + pin: function(enable, forceScroll){ + if (!supportTested) testPositionFixed(); + if (this.getStyle('display') == 'none') return this; + + var pinnedPosition, + scroll = window.getScroll(), + parent, + scrollFixer; + + if (enable !== false){ + pinnedPosition = this.getPosition(); + if (!this.retrieve('pin:_pinned')) { + var currentPosition = { + top: pinnedPosition.y - scroll.y, + left: pinnedPosition.x - scroll.x, + margin: '0px', + padding: '0px' + }; + + if (supportsPositionFixed && !forceScroll){ + this.setStyle('position', 'fixed').setStyles(currentPosition); + } else { + + parent = this.getOffsetParent(); + var position = this.getPosition(parent), + styles = this.getStyles('left', 'top'); + + if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position); + if (this.getStyle('position') == 'static') this.setStyle('position', 'absolute'); + + position = { + x: styles.left.toInt() - scroll.x, + y: styles.top.toInt() - scroll.y + }; + + scrollFixer = function(){ + if (!this.retrieve('pin:_pinned')) return; + var scroll = window.getScroll(); + this.setStyles({ + left: position.x + scroll.x, + top: position.y + scroll.y + }); + }.bind(this); + + this.store('pin:_scrollFixer', scrollFixer); + window.addEvent('scroll', scrollFixer); + } + this.store('pin:_pinned', true); + } + + } else { + if (!this.retrieve('pin:_pinned')) return this; + + parent = this.getParent(); + var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent()); + + pinnedPosition = this.getPosition(); + + this.store('pin:_pinned', false); + scrollFixer = this.retrieve('pin:_scrollFixer'); + if (!scrollFixer){ + this.setStyles({ + position: 'absolute', + top: pinnedPosition.y + scroll.y, + left: pinnedPosition.x + scroll.x + }); + } else { + this.store('pin:_scrollFixer', null); + window.removeEvent('scroll', scrollFixer); + } + this.removeClass('isPinned'); + } + return this; + }, + + unpin: function(){ + return this.pin(false); + }, + + togglePin: function(){ + return this.pin(!this.retrieve('pin:_pinned')); + } + + }); + + + +})(); + +/* +--- + +script: Element.Position.js + +name: Element.Position + +description: Extends the Element native object to include methods useful positioning elements relative to others. + +license: MIT-style license + +authors: + - Aaron Newton + - Jacob Thornton + +requires: + - Core/Options + - Core/Element.Dimensions + - Element.Measure + +provides: [Element.Position] + +... +*/ + +(function(original){ + +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}; + var parentScroll = {x: 0, y: 0}; + var offsetParent = element.measure(function(){ + return document.id(this.getOffsetParent()); + }); + + if (!offsetParent || offsetParent == element.getDocument().body) return; + + parentScroll = offsetParent.getScroll(); + 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){ + 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); + }, + + calculatePosition: function(options){ + return local.getPosition(this, options); + } + +}); + +})(Element.prototype.position); + +/* +--- + +script: Element.Shortcuts.js + +name: Element.Shortcuts + +description: Extends the Element native object to include some shortcut methods. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Element.Style + - MooTools.More + +provides: [Element.Shortcuts] + +... +*/ + +Element.implement({ + + isDisplayed: function(){ + return this.getStyle('display') != 'none'; + }, + + isVisible: function(){ + var w = this.offsetWidth, + h = this.offsetHeight; + return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none'; + }, + + toggle: function(){ + return this[this.isDisplayed() ? 'hide' : 'show'](); + }, + + hide: function(){ + var d; + try { + //IE fails here if the element is not in the dom + d = this.getStyle('display'); + } catch(e){} + if (d == 'none') return this; + return this.store('element:_originalDisplay', d || '').setStyle('display', 'none'); + }, + + show: function(display){ + if (!display && this.isDisplayed()) return this; + display = display || this.retrieve('element:_originalDisplay') || 'block'; + return this.setStyle('display', (display == 'none') ? 'block' : display); + }, + + swapClass: function(remove, add){ + return this.removeClass(remove).addClass(add); + } + +}); + +Document.implement({ + + clearSelection: function(){ + 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: Elements.From.js + +name: Elements.From + +description: Returns a collection of elements from a string of html. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/String + - Core/Element + - MooTools.More + +provides: [Elements.from, Elements.From] + +... +*/ + +Elements.from = function(text, excludeScripts){ + if (excludeScripts || excludeScripts == null) text = text.stripScripts(); + + var container, match = text.match(/^\s*(?:\s*)*<(t[dhr]|tbody|tfoot|thead)/i); + + if (match){ + container = new Element('table'); + var tag = match[1].toLowerCase(); + if (['td', 'th', 'tr'].contains(tag)){ + container = new Element('tbody').inject(container); + if (tag != 'tr') container = new Element('tr').inject(container); + } + } + + return (container || new Element('div')).set('html', text).getChildren(); +}; + +/* +--- + +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] + +... +*/ + +(function(){ + +var browsers = false; + + +this.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: browsers + }, + + 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.target.set('aria-busy', 'true'); + 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.target.set('aria-busy', 'false'); + 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: String.QueryString.js + +name: String.QueryString + +description: Methods for dealing with URI query strings. + +license: MIT-style license + +authors: + - Sebastian Markbåge + - Aaron Newton + - Lennart Pilon + - Valerio Proietti + +requires: + - Core/Array + - Core/String + - MooTools.More + +provides: [String.QueryString] + +... +*/ + +String.implement({ + + parseQueryString: function(decodeKeys, decodeValues){ + if (decodeKeys == null) decodeKeys = true; + if (decodeValues == null) decodeValues = true; + + 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 (typeOf(current) == 'array') current.push(value); + else obj[key] = current != null ? [current, value] : value; + }); + }); + + 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.call(null, key, value) : (value || value === 0); + }).join('&'); + } + +}); + +/* +--- + +script: Form.Request.js + +name: Form.Request + +description: Handles the basic functionality of submitting a form and updating a dom element with the result. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Request.HTML + - Class.Binds + - Class.Occlude + - Spinner + - String.QueryString + - Element.Delegation.Pseudo + +provides: [Form.Request] + +... +*/ + +if (!window.Form) window.Form = {}; + +(function(){ + + Form.Request = new Class({ + + Binds: ['onSubmit', 'onFormValidate'], + + Implements: [Options, Events, Class.Occlude], + + options: {/* + onFailure: function(){}, + onSuccess: function(){}, // aliased to onComplete, + onSend: function(){}*/ + requestOptions: { + evalScripts: true, + useSpinner: true, + emulation: false, + link: 'ignore' + }, + sendButtonClicked: true, + extraData: {}, + resetForm: true + }, + + property: 'form.request', + + initialize: function(form, target, options){ + this.element = document.id(form); + if (this.occlude()) return this.occluded; + this.setOptions(options) + .setTarget(target) + .attach(); + }, + + 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(){ + 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){ + self.fireEvent(evt, [self.target, tree, elements, html, javascript]); + }); + }, + failure: function(){ + self.fireEvent('complete', arguments).fireEvent('failure', arguments); + }, + exception: function(){ + 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){ + 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(){ + return this.attach(false); + }, + + //public method + enable: function(){ + return this.attach(); + }, + + //public method + disable: function(){ + return this.detach(); + }, + + onFormValidate: function(valid, form, event){ + //if there's no event, then this wasn't a submit event + if (!event) return; + var fv = this.element.retrieve('validator'); + if (valid || (fv && !fv.options.stopOnFailure)){ + event.stop(); + this.send(); + } + }, + + onSubmit: function(event){ + var fv = this.element.retrieve('validator'); + if (fv){ + //form validator was created after Form.Request + this.element.removeEvent('submit', this.onSubmit); + fv.addEvent('onFormValidate', this.onFormValidate); + fv.validate(event); + return; + } + if (event) event.stop(); + this.send(); + }, + + 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[targetName]; + this.clickedCleaner = function(){}; + }.bind(this); + }, + + clickedCleaner: function(){}, + + send: function(){ + 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.options.requestOptions.url || this.element.get('action') + }); + this.clickedCleaner(); + return this; + } + + }); + + 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(); + } + 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: 'opacity' in document.documentElement, + mode: 'vertical', + display: function(){ + return this.element.get('tag') != 'tr' ? 'block' : 'table-row'; + }, + opacity: 1, + hideInputs: !('opacity' in document.documentElement) ? '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); + }); + } + +}); + +})(); + +/* +--- + +script: Form.Request.Append.js + +name: Form.Request.Append + +description: Handles the basic functionality of submitting a form and updating a dom element with the result. The result is appended to the DOM element instead of replacing its contents. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Form.Request + - Fx.Reveal + - Elements.from + +provides: [Form.Request.Append] + +... +*/ + +Form.Request.Append = new Class({ + + Extends: Form.Request, + + options: { + //onBeforeEffect: function(){}, + useReveal: true, + revealOptions: {}, + inject: 'bottom' + }, + + makeRequest: function(){ + this.request = new Request.HTML(Object.merge({ + url: this.element.get('action'), + method: this.element.get('method') || 'post', + spinnerTarget: this.element + }, this.options.requestOptions, { + evalScripts: false + }) + ).addEvents({ + success: function(tree, elements, html, javascript){ + var container; + var kids = Elements.from(html); + if (kids.length == 1){ + container = kids[0]; + } else { + container = new Element('div', { + styles: { + display: 'none' + } + }).adopt(kids); + } + 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.target, tree, elements, html, javascript]); + }.bind(this); + if (this.options.useReveal){ + container.set('reveal', this.options.revealOptions).get('reveal').chain(finish); + container.reveal(); + } else { + finish(); + } + }.bind(this), + failure: function(xhr){ + this.fireEvent('failure', xhr); + }.bind(this) + }); + this.attachReset(); + } + +}); /* --- @@ -198,7 +3606,7 @@ authors: requires: - Core/Object - - /MooTools.More + - MooTools.More provides: [Object.Extras] @@ -249,7 +3657,6 @@ Object.extend({ })(); - /* --- @@ -267,8 +3674,8 @@ authors: requires: - Core/Events - - /Object.Extras - - /MooTools.More + - Object.Extras + - MooTools.More provides: [Locale, Lang] @@ -417,7 +3824,6 @@ Locale.Set = new Class({ })(); - /* --- @@ -431,7 +3837,7 @@ authors: - Aaron Newton requires: - - /Locale + - Locale provides: [Locale.en-US.Date] @@ -489,7 +3895,6 @@ Locale.define('en-US', 'Date', { }); - /* --- @@ -697,19 +4102,19 @@ Date.implement({ }, isValid: function(date){ - return !isNaN((date || this).valueOf()); + if (!date) date = this; + return typeOf(date) == 'date' && !isNaN(date.valueOf()); }, - format: function(f){ + format: function(format){ if (!this.isValid()) return 'invalid date'; - 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 + if (!format) format = '%x %X'; + if (typeof format == 'string') format = formats[format.toLowerCase()] || format; + if (typeof format == 'function') return format(this); var d = this; - return f.replace(/%([a-z%])/gi, + return format.replace(/%([a-z%])/gi, function($0, $1){ switch ($1){ case 'a': return Date.getMsg('days_abbr')[d.get('day')]; @@ -756,18 +4161,15 @@ Date.implement({ strftime: 'format' }); -var formats = { - 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' -}; - // 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 = { +var formats = { + 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', rfc822: function(date){ return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z'); }, @@ -787,7 +4189,6 @@ var formatters = { } }; - var parsePatterns = [], nativeParse = Date.parse; @@ -899,11 +4300,6 @@ Date.extend({ return this; }, - defineFormats: function(formats){ - for (var name in formats) Date.defineFormat(name, formats[name]); - return this; - }, - defineParser: function(pattern){ @@ -922,6 +4318,8 @@ Date.extend({ return this; } +}).extend({ + defineFormats: Date.defineFormat.overloadSetter() }); var regexOf = function(type){ @@ -1056,3384 +4454,6 @@ Locale.addEvent('change', function(language){ })(); - -/* ---- - -script: Date.Extras.js - -name: Date.Extras - -description: Extends the Date native object to include extra methods (on top of those in Date.js). - -license: MIT-style license - -authors: - - Aaron Newton - - Scott Kyle - -requires: - - /Date - -provides: [Date.Extras] - -... -*/ - -Date.implement({ - - timeDiffInWords: function(to){ - return Date.distanceOfTimeInWords(this, to || new Date); - }, - - timeDiff: function(to, separator){ - if (to == null) to = new Date; - 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(separator || ':'); - } - -}).extend({ - - distanceOfTimeInWords: function(from, to){ - return Date.getTimePhrase(((to - from) / 1000).toInt()); - }, - - getTimePhrase: function(delta){ - var suffix = (delta < 0) ? 'Until' : 'Ago'; - if (delta < 0) delta *= -1; - - var units = { - minute: 60, - hour: 60, - day: 24, - week: 7, - month: 52 / 12, - year: 12, - eon: Infinity - }; - - var msg = 'lessThanMinute'; - - for (var unit in units){ - var interval = units[unit]; - if (delta < 1.5 * interval){ - if (delta > 0.75 * interval) msg = unit; - break; - } - delta /= interval; - msg = unit + 's'; - } - - delta = delta.round(); - return Date.getMsg(msg + suffix, delta).substitute({delta: delta}); - } - -}).defineParsers( - - { - // "today", "tomorrow", "yesterday" - re: /^(?:tod|tom|yes)/i, - handler: function(bits){ - var d = new Date().clearTime(); - switch (bits[0]){ - case 'tom': return d.increment(); - case 'yes': return d.decrement(); - default: return d; - } - } - }, - - { - // "next Wednesday", "last Thursday" - re: /^(next|last) ([a-z]+)$/i, - handler: function(bits){ - var d = new Date().clearTime(); - var day = d.getDay(); - var newDay = Date.parseDay(bits[2], true); - var addDays = newDay - day; - if (newDay <= day) addDays += 7; - if (bits[1] == 'last') addDays -= 7; - return d.set('date', d.getDate() + addDays); - } - } - -).alias('timeAgoInWords', 'timeDiffInWords'); - - -/* ---- - -name: Locale.en-US.Number - -description: Number messages for US English. - -license: MIT-style license - -authors: - - Arian Stolwijk - -requires: - - /Locale - -provides: [Locale.en-US.Number] - -... -*/ - -Locale.define('en-US', 'Number', { - - 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; - }, - - 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); - }, - - 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); - } - -}); - - -/* ---- - -script: String.Extras.js - -name: String.Extras - -description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc). - -license: MIT-style license - -authors: - - Aaron Newton - - Guillermo Rauch - - Christopher Pitt - -requires: - - Core/String - - Core/Array - - MooTools.More - -provides: [String.Extras] - -... -*/ - -(function(){ - -var special = { - '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]/g, - '*': /[\xb7]/g, - '\'': /[\u2018\u2019]/g, - '"': /[\u201c\u201d]/g, - '...': /[\u2026]/g, - '-': /[\u2013]/g, -// '--': /[\u2014]/g, - '»': /[\uFFFD]/g -}; - -var walk = function(string, replacements){ - var result = string, key; - for (key in replacements) result = result.replace(replacements[key], key); - return result; -}; - -var getRegexForTag = function(tag, contents){ - tag = tag || ''; - var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>", - reg = new RegExp(regstr, "gi"); - return reg; -}; - -String.implement({ - - standardize: function(){ - return walk(this, special); - }, - - repeat: function(times){ - return new Array(times + 1).join(this); - }, - - 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 (!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(getRegexForTag(tag, contents)) || []; - }, - - stripTags: function(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; - } - -}); - -})(); - - -/* ---- - -script: String.QueryString.js - -name: String.QueryString - -description: Methods for dealing with URI query strings. - -license: MIT-style license - -authors: - - Sebastian Markbåge - - Aaron Newton - - Lennart Pilon - - Valerio Proietti - -requires: - - Core/Array - - Core/String - - /MooTools.More - -provides: [String.QueryString] - -... -*/ - -String.implement({ - - parseQueryString: function(decodeKeys, decodeValues){ - if (decodeKeys == null) decodeKeys = true; - if (decodeValues == null) decodeValues = true; - - 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 (typeOf(current) == 'array') current.push(value); - else obj[key] = current != null ? [current, value] : value; - }); - }); - - 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.call(null, key, value) : (value || value === 0); - }).join('&'); - } - -}); - - -/* ---- - -script: URI.js - -name: URI - -description: Provides methods useful in managing the window location and uris. - -license: MIT-style license - -authors: - - Sebastian Markbåge - - Aaron Newton - -requires: - - Core/Object - - Core/Class - - Core/Class.Extras - - Core/Element - - /String.QueryString - -provides: [URI] - -... -*/ - -(function(){ - -var toString = function(){ - return this.get('value'); -}; - -var URI = this.URI = new Class({ - - Implements: Options, - - options: { - /*base: false*/ - }, - - regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/, - parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'], - schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0}, - - initialize: function(uri, options){ - this.setOptions(options); - var base = this.options.base || URI.base; - 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); - }, - - parse: function(value, base){ - var bits = value.match(this.regex); - if (!bits) return false; - bits.shift(); - return this.merge(bits.associate(this.parts), base); - }, - - merge: function(bits, base){ - if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false; - if (base){ - this.parts.every(function(part){ - if (bits[part]) return false; - bits[part] = base[part] || ''; - return true; - }); - } - bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()]; - bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/'; - return bits; - }, - - parseDirectory: function(directory, baseDirectory){ - directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory; - if (!directory.test(URI.regs.directoryDot)) return directory; - var result = []; - directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){ - if (dir == '..' && result.length > 0) result.pop(); - else if (dir != '.') result.push(dir); - }); - return result.join('/') + '/'; - }, - - combine: function(bits){ - return bits.value || bits.scheme + '://' + - (bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') + - (bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') + - (bits.directory || '/') + (bits.file || '') + - (bits.query ? '?' + bits.query : '') + - (bits.fragment ? '#' + bits.fragment : ''); - }, - - set: function(part, value, base){ - if (part == 'value'){ - var scheme = value.match(URI.regs.scheme); - if (scheme) scheme = scheme[1]; - 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'){ - this.setData(value); - } else { - this.parsed[part] = value; - } - return this; - }, - - get: function(part, base){ - switch (part){ - case 'value': return this.combine(this.parsed, base ? base.parsed : false); - case 'data' : return this.getData(); - } - return this.parsed[part] || ''; - }, - - go: function(){ - document.location.href = this.toString(); - }, - - toURI: function(){ - return this; - }, - - getData: function(key, part){ - var qs = this.get(part || 'query'); - 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'){ - var data = this.getData(); - data[arguments[0]] = arguments[1]; - values = data; - } else if (merge){ - values = Object.merge(this.getData(), values); - } - return this.set(part || 'query', Object.toQueryString(values)); - }, - - clearData: function(part){ - return this.set(part || 'query', ''); - }, - - toString: toString, - valueOf: toString - -}); - -URI.regs = { - endSlash: /\/$/, - scheme: /^(\w+):/, - directoryDot: /\.\/|\.$/ -}; - -URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location}); - -String.implement({ - - toURI: function(options){ - return new URI(this, options); - } - -}); - -})(); - - -/* ---- - -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; - -}; - - -/* ---- - -script: URI.Relative.js - -name: URI.Relative - -description: Extends the URI class to add methods for computing relative and absolute urls. - -license: MIT-style license - -authors: - - Sebastian Markbåge - - -requires: - - /Class.refactor - - /URI - -provides: [URI.Relative] - -... -*/ - -URI = Class.refactor(URI, { - - combine: function(bits, base){ - if (!base || bits.scheme != base.scheme || bits.host != base.host || bits.port != base.port) - return this.previous.apply(this, arguments); - var end = bits.file + (bits.query ? '?' + bits.query : '') + (bits.fragment ? '#' + bits.fragment : ''); - - if (!base.directory) return (bits.directory || (bits.file ? '' : './')) + end; - - var baseDir = base.directory.split('/'), - relDir = bits.directory.split('/'), - path = '', - 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] + '/'; - - return (path || (bits.file ? '' : './')) + end; - }, - - toAbsolute: function(base){ - base = new URI(base); - if (base) base.set('directory', '').set('file', ''); - return this.toRelative(base); - }, - - toRelative: function(base){ - return this.get('value', new URI(base)); - } - -}); - - -/* ---- - -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); - } - -}); - - -/* ---- - -script: Element.Forms.js - -name: Element.Forms - -description: Extends the Element native object to include methods useful in managing inputs. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Element - - /String.Extras - - /MooTools.More - -provides: [Element.Forms] - -... -*/ - -Element.implement({ - - tidy: function(){ - this.set('value', this.get('value').tidy()); - }, - - getTextInRange: function(start, end){ - return this.get('value').substring(start, end); - }, - - getSelectedText: function(){ - if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd()); - return document.selection.createRange().text; - }, - - 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 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; - 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; - }, - - getSelectionStart: function(){ - return this.getSelectedRange().start; - }, - - getSelectionEnd: function(){ - return this.getSelectedRange().end; - }, - - setCaretPosition: function(pos){ - if (pos == 'end') pos = this.get('value').length; - this.selectRange(pos, pos); - return this; - }, - - getCaretPosition: function(){ - return this.getSelectedRange().start; - }, - - selectRange: function(start, end){ - if (this.setSelectionRange){ - this.focus(); - this.setSelectionRange(start, end); - } else { - var value = this.get('value'); - var diff = value.substr(start, end - start).replace(/\r/g, '').length; - start = value.substr(0, start).replace(/\r/g, '').length; - var range = this.createTextRange(); - range.collapse(true); - range.moveEnd('character', start + diff); - range.moveStart('character', start); - range.select(); - } - return this; - }, - - insertAtCursor: function(value, select){ - 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 (select !== false) this.selectRange(pos.start, pos.start + value.length); - else this.setCaretPosition(pos.start + value.length); - return this; - }, - - insertAroundCursor: function(options, select){ - 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); - } else { - 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 (select !== false) this.selectRange(selStart, selStart + current.length); - else this.setCaretPosition(selStart + text.length); - } - return this; - } - -}); - - -/* ---- - -script: Elements.From.js - -name: Elements.From - -description: Returns a collection of elements from a string of html. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/String - - Core/Element - - /MooTools.More - -provides: [Elements.from, Elements.From] - -... -*/ - -Elements.from = function(text, excludeScripts){ - if (excludeScripts || excludeScripts == null) text = text.stripScripts(); - - var container, match = text.match(/^\s*<(t[dhr]|tbody|tfoot|thead)/i); - - if (match){ - container = new Element('table'); - var tag = match[1].toLowerCase(); - if (['td', 'th', 'tr'].contains(tag)){ - container = new Element('tbody').inject(container); - if (tag != 'tr') container = new Element('tr').inject(container); - } - } - - return (container || new Element('div')).set('html', text).getChildren(); -}; - - -/* ---- - -name: Events.Pseudos - -description: Adds the functionality to add pseudo events - -license: MIT-style license - -authors: - - Arian Stolwijk - -requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More] - -provides: [Events.Pseudos] - -... -*/ - -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; - } - }; - }; - - var splitType = function(type){ - if (type.indexOf(':') == -1 || !pseudos) return null; - - 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) 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) return removeEvent.call(this, type, fn); - - var storage = storageOf(this), - events = storage.retrieve(type); - if (!events) return this; - - var eventType = split[0].event, - options = mergePseudoOptions(split), - eventOptions = options[eventType] || {}, - args = Array.slice(arguments, 2); - - 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; - } - - }; - -}; - -(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); -}); - -})(); - - -/* ---- - -name: Element.Event.Pseudos - -description: Adds the functionality to add pseudo events for Elements - -license: MIT-style license - -authors: - - Arian Stolwijk - -requires: [Core/Element.Event, Events.Pseudos] - -provides: [Element.Event.Pseudos] - -... -*/ - -(function(){ - -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 - }; - 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 -}); - -})(); - - -/* ---- - -script: Element.Pin.js - -name: Element.Pin - -description: Extends the Element native object to include the pin method useful for fixed positioning for elements. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Element.Event - - Core/Element.Dimensions - - Core/Element.Style - - /MooTools.More - -provides: [Element.Pin] - -... -*/ - -(function(){ - var supportsPositionFixed = false, - supportTested = false; - - var testPositionFixed = function(){ - var test = new Element('div').setStyles({ - position: 'fixed', - top: 0, - right: 0 - }).inject(document.body); - supportsPositionFixed = (test.offsetTop === 0); - test.dispose(); - supportTested = true; - }; - - Element.implement({ - - pin: function(enable, forceScroll){ - if (!supportTested) testPositionFixed(); - if (this.getStyle('display') == 'none') return this; - - var pinnedPosition, - scroll = window.getScroll(), - parent, - scrollFixer; - - if (enable !== false){ - pinnedPosition = this.getPosition(supportsPositionFixed ? document.body : this.getOffsetParent()); - if (!this.retrieve('pin:_pinned')){ - var currentPosition = { - top: pinnedPosition.y - scroll.y, - left: pinnedPosition.x - scroll.x - }; - - if (supportsPositionFixed && !forceScroll){ - this.setStyle('position', 'fixed').setStyles(currentPosition); - } else { - - parent = this.getOffsetParent(); - var position = this.getPosition(parent), - styles = this.getStyles('left', 'top'); - - if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position); - if (this.getStyle('position') == 'static') this.setStyle('position', 'absolute'); - - position = { - x: styles.left.toInt() - scroll.x, - y: styles.top.toInt() - scroll.y - }; - - scrollFixer = function(){ - if (!this.retrieve('pin:_pinned')) return; - var scroll = window.getScroll(); - this.setStyles({ - left: position.x + scroll.x, - top: position.y + scroll.y - }); - }.bind(this); - - this.store('pin:_scrollFixer', scrollFixer); - window.addEvent('scroll', scrollFixer); - } - this.store('pin:_pinned', true); - } - - } else { - if (!this.retrieve('pin:_pinned')) return this; - - parent = this.getParent(); - var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent()); - - pinnedPosition = this.getPosition(offsetParent); - - this.store('pin:_pinned', false); - scrollFixer = this.retrieve('pin:_scrollFixer'); - if (!scrollFixer){ - this.setStyles({ - position: 'absolute', - top: pinnedPosition.y + scroll.y, - left: pinnedPosition.x + scroll.x - }); - } else { - this.store('pin:_scrollFixer', null); - window.removeEvent('scroll', scrollFixer); - } - this.removeClass('isPinned'); - } - return this; - }, - - unpin: function(){ - return this.pin(false); - }, - - 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); - } - -}); - -})(); - - -/* ---- - -script: Element.Position.js - -name: Element.Position - -description: Extends the Element native object to include methods useful positioning elements relative to others. - -license: MIT-style license - -authors: - - Aaron Newton - - Jacob Thornton - -requires: - - Core/Options - - Core/Element.Dimensions - - Element.Measure - -provides: [Element.Position] - -... -*/ - -(function(original){ - -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){ - 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); - }, - - calculatePosition: function(options){ - return local.getPosition(this, options); - } - -}); - -})(Element.prototype.position); - - -/* ---- - -script: Element.Shortcuts.js - -name: Element.Shortcuts - -description: Extends the Element native object to include some shortcut methods. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Element.Style - - /MooTools.More - -provides: [Element.Shortcuts] - -... -*/ - -Element.implement({ - - isDisplayed: function(){ - return this.getStyle('display') != 'none'; - }, - - isVisible: function(){ - var w = this.offsetWidth, - h = this.offsetHeight; - return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none'; - }, - - toggle: function(){ - return this[this.isDisplayed() ? 'hide' : 'show'](); - }, - - hide: function(){ - var d; - try { - //IE fails here if the element is not in the dom - d = this.getStyle('display'); - } catch(e){} - if (d == 'none') return this; - return this.store('element:_originalDisplay', d || '').setStyle('display', 'none'); - }, - - show: function(display){ - if (!display && this.isDisplayed()) return this; - display = display || this.retrieve('element:_originalDisplay') || 'block'; - return this.setStyle('display', (display == 'none') ? 'block' : display); - }, - - swapClass: function(remove, add){ - return this.removeClass(remove).addClass(add); - } - -}); - -Document.implement({ - - clearSelection: function(){ - 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 -}); - -})(); - - -/* ---- - -script: Form.Request.js - -name: Form.Request - -description: Handles the basic functionality of submitting a form and updating a dom element with the result. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Request.HTML - - /Class.Binds - - /Class.Occlude - - /Spinner - - /String.QueryString - - /Element.Delegation - -provides: [Form.Request] - -... -*/ - -if (!window.Form) window.Form = {}; - -(function(){ - - Form.Request = new Class({ - - Binds: ['onSubmit', 'onFormValidate'], - - Implements: [Options, Events, Class.Occlude], - - options: {/* - onFailure: function(){}, - onSuccess: function(){}, // aliased to onComplete, - onSend: function(){}*/ - requestOptions: { - evalScripts: true, - useSpinner: true, - emulation: false, - link: 'ignore' - }, - sendButtonClicked: true, - extraData: {}, - resetForm: true - }, - - property: 'form.request', - - initialize: function(form, target, options){ - this.element = document.id(form); - if (this.occlude()) return this.occluded; - this.setOptions(options) - .setTarget(target) - .attach(); - }, - - 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(){ - 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){ - self.fireEvent(evt, [self.target, tree, elements, html, javascript]); - }); - }, - failure: function(){ - self.fireEvent('complete', arguments).fireEvent('failure', arguments); - }, - exception: function(){ - 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){ - 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(){ - return this.attach(false); - }, - - //public method - enable: function(){ - return this.attach(); - }, - - //public method - disable: function(){ - return this.detach(); - }, - - onFormValidate: function(valid, form, event){ - //if there's no event, then this wasn't a submit event - if (!event) return; - var fv = this.element.retrieve('validator'); - if (valid || (fv && !fv.options.stopOnFailure)){ - event.stop(); - this.send(); - } - }, - - onSubmit: function(event){ - var fv = this.element.retrieve('validator'); - 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 (event) event.stop(); - this.send(); - }, - - 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[targetName]; - this.clickedCleaner = function(){}; - }.bind(this); - }, - - clickedCleaner: function(){}, - - send: function(){ - 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.options.requestOptions.url || this.element.get('action') - }); - this.clickedCleaner(); - return this; - } - - }); - - 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(); - } - 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); - }); - } - -}); - -})(); - - -/* ---- - -script: Form.Request.Append.js - -name: Form.Request.Append - -description: Handles the basic functionality of submitting a form and updating a dom element with the result. The result is appended to the DOM element instead of replacing its contents. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - /Form.Request - - /Fx.Reveal - - /Elements.from - -provides: [Form.Request.Append] - -... -*/ - -Form.Request.Append = new Class({ - - Extends: Form.Request, - - options: { - //onBeforeEffect: function(){}, - useReveal: true, - revealOptions: {}, - inject: 'bottom' - }, - - makeRequest: function(){ - this.request = new Request.HTML(Object.merge({ - url: this.element.get('action'), - method: this.element.get('method') || 'post', - spinnerTarget: this.element - }, this.options.requestOptions, { - evalScripts: false - }) - ).addEvents({ - success: function(tree, elements, html, javascript){ - var container; - var kids = Elements.from(html); - if (kids.length == 1){ - container = kids[0]; - } else { - container = new Element('div', { - styles: { - display: 'none' - } - }).adopt(kids); - } - 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.target, tree, elements, html, javascript]); - }.bind(this); - if (this.options.useReveal){ - container.set('reveal', this.options.revealOptions).get('reveal').chain(finish); - container.reveal(); - } else { - finish(); - } - }.bind(this), - failure: function(xhr){ - this.fireEvent('failure', xhr); - }.bind(this) - }); - this.attachReset(); - } - -}); - - /* --- @@ -4447,7 +4467,7 @@ authors: - Aaron Newton requires: - - /Locale + - Locale provides: [Locale.en-US.Form.Validator] @@ -4457,6 +4477,7 @@ provides: [Locale.en-US.Form.Validator] Locale.define('en-US', 'FormValidator', { required: 'This field is required.', + length: 'Please enter {length} characters (you entered {elLength} characters)', 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.', @@ -4481,7 +4502,7 @@ Locale.define('en-US', 'FormValidator', { match: 'This field needs to match the {matchName} field', startDate: 'the start date', endDate: 'the end date', - currendDate: 'the current date', + currentDate: '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', @@ -4490,7 +4511,6 @@ Locale.define('en-US', 'FormValidator', { }); - /* --- @@ -4508,16 +4528,17 @@ authors: requires: - Core/Options - Core/Events + - Core/Element.Delegation - Core/Slick.Finder - Core/Element.Event - Core/Element.Style - Core/JSON - - /Locale - - /Class.Binds - - /Date - - /Element.Forms - - /Locale.en-US.Form.Validator - - /Element.Shortcuts + - Locale + - Class.Binds + - Date + - Element.Forms + - Locale.en-US.Form.Validator + - Element.Shortcuts provides: [Form.Validator, InputValidator, FormValidator.BaseValidators] @@ -4577,7 +4598,7 @@ Element.Properties.validatorProps = { if (this.retrieve('$moo:validatorProps')) return this.retrieve('$moo:validatorProps'); if (this.getProperty('data-validator-properties') || this.getProperty('validatorProps')){ try { - this.store('$moo:validatorProps', JSON.decode(this.getProperty('validatorProps') || this.getProperty('data-validator-properties'))); + this.store('$moo:validatorProps', JSON.decode(this.getProperty('validatorProps') || this.getProperty('data-validator-properties'), false)); }catch(e){ return {}; } @@ -4593,7 +4614,7 @@ Element.Properties.validatorProps = { var split = cls.split(':'); if (split[1]){ try { - props[split[0]] = JSON.decode(split[1]); + props[split[0]] = JSON.decode(split[1], false); } catch(e){} } }); @@ -4609,8 +4630,6 @@ Form.Validator = new Class({ Implements: [Options, Events], - Binds: ['onSubmit'], - options: {/* onFormValidate: function(isValid, form, event){}, onElementValidate: function(isValid, field, className, warn){}, @@ -4636,11 +4655,15 @@ Form.Validator = new Class({ initialize: function(form, options){ this.setOptions(options); this.element = document.id(form); - this.element.store('validator', this); 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()); + this._bound = { + onSubmit: this.onSubmit.bind(this), + blurOrChange: function(event, field){ + this.validationMonitor(field, true); + }.bind(this) + }; + this.enable(); }, toElement: function(){ @@ -4651,13 +4674,24 @@ Form.Validator = new Class({ return (this.fields = this.element.getElements(this.options.fieldSelectors)); }, - watchFields: function(fields){ - fields.each(function(el){ - if (this.options.evaluateFieldsOnBlur) - el.addEvent('blur', this.validationMonitor.pass([el, false], this)); - if (this.options.evaluateFieldsOnChange) - el.addEvent('change', this.validationMonitor.pass([el, true], this)); - }, this); + enable: function(){ + this.element.store('validator', this); + if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this._bound.onSubmit); + if (this.options.evaluateFieldsOnBlur){ + this.element.addEvent('blur:relay(input,select,textarea)', this._bound.blurOrChange); + } + if (this.options.evaluateFieldsOnChange){ + this.element.addEvent('change:relay(input,select,textarea)', this._bound.blurOrChange); + } + }, + + disable: function(){ + this.element.eliminate('validator'); + this.element.removeEvents({ + submit: this._bound.onSubmit, + 'blur:relay(input,select,textarea)': this._bound.blurOrChange, + 'change:relay(input,select,textarea)': this._bound.blurOrChange + }); }, validationMonitor: function(){ @@ -4736,8 +4770,8 @@ Form.Validator = new Class({ var validator = this.getValidator(className); 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]); + var isValid = field.hasClass('ignoreValidation') || (validator ? validator.test(field) : true); + if (validator) this.fireEvent('elementValidate', [isValid, field, className, warn]); if (warn) return true; return isValid; }, @@ -4846,10 +4880,22 @@ Form.Validator.addAllThese([ } }], + ['length', { + errorMsg: function(element, props){ + if (typeOf(props.length) != 'null') + return Form.Validator.getMsg('length').substitute({length: props.length, elLength: element.get('value').length}); + else return ''; + }, + test: function(element, props){ + if (typeOf(props.length) != 'null') return (element.get('value').length == props.length || element.get('value').length == 0); + else return true; + } + }], + ['minLength', { errorMsg: function(element, props){ if (typeOf(props.minLength) != 'null') - return Form.Validator.getMsg('minLength').substitute({minLength:props.minLength,length:element.get('value').length }); + return Form.Validator.getMsg('minLength').substitute({minLength: props.minLength, length: element.get('value').length}); else return ''; }, test: function(element, props){ @@ -4862,7 +4908,7 @@ Form.Validator.addAllThese([ errorMsg: function(element, props){ //props is {maxLength:10} if (typeOf(props.maxLength) != 'null') - return Form.Validator.getMsg('maxLength').substitute({maxLength:props.maxLength,length:element.get('value').length }); + return Form.Validator.getMsg('maxLength').substitute({maxLength: props.maxLength, length: element.get('value').length}); else return ''; }, test: function(element, props){ @@ -4917,19 +4963,20 @@ Form.Validator.addAllThese([ }, test: function(element, props){ if (Form.Validator.getValidator('IsEmpty').test(element)) return true; - var dateLocale = Locale.getCurrent().sets.Date, - dateNouns = new RegExp([dateLocale.days, dateLocale.days_abbr, dateLocale.months, dateLocale.months_abbr].flatten().join('|'), 'i'), + var dateLocale = Locale.get('Date'), + dateNouns = new RegExp([dateLocale.days, dateLocale.days_abbr, dateLocale.months, dateLocale.months_abbr, dateLocale.AM, dateLocale.PM].flatten().join('|'), 'i'), value = element.get('value'), wordsInValue = value.match(/[a-z]+/gi); - if (wordsInValue && !wordsInValue.every(dateNouns.exec, dateNouns)) return false; + if (wordsInValue && !wordsInValue.every(dateNouns.exec, dateNouns)) return false; - var date = Date.parse(value), - format = props.dateFormat || '%x', - formatted = date.format(format); + var date = Date.parse(value); + if (!date) return false; - if (formatted != 'invalid date') element.set('value', formatted); - return date.isValid(); + var format = props.dateFormat || '%x', + formatted = date.format(format); + if (formatted != 'invalid date') element.set('value', formatted); + return date.isValid(); } }], @@ -5012,199 +5059,6 @@ Element.implement({ - -/* ---- - -script: Form.Validator.Inline.js - -name: Form.Validator.Inline - -description: Extends Form.Validator to add inline messages. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - /Form.Validator - -provides: [Form.Validator.Inline] - -... -*/ - -Form.Validator.Inline = new Class({ - - Extends: Form.Validator, - - options: { - showError: function(errorElement){ - if (errorElement.reveal) errorElement.reveal(); - else errorElement.setStyle('display', 'block'); - }, - hideError: function(errorElement){ - if (errorElement.dissolve) errorElement.dissolve(); - else errorElement.setStyle('display', 'none'); - }, - scrollToErrorsOnSubmit: true, - scrollToErrorsOnBlur: false, - scrollToErrorsOnChange: false, - scrollFxOptions: { - transition: 'quad:out', - offset: { - y: -20 - } - } - }, - - initialize: function(form, options){ - this.parent(form, options); - this.addEvent('onElementValidate', function(isValid, field, className, warn){ - var validator = this.getValidator(className); - if (!isValid && validator.getError(field)){ - if (warn) field.addClass('warning'); - var advice = this.makeAdvice(className, field, validator.getError(field), warn); - this.insertAdvice(advice, field); - this.showAdvice(className, field); - } else { - this.hideAdvice(className, field); - } - }); - }, - - makeAdvice: function(className, field, error, warn){ - 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){ - advice = advice.set('html', errorMsg); - } else { - advice = new Element('div', { - html: errorMsg, - styles: { display: 'none' }, - id: 'advice-' + className.split(':')[0] + '-' + this.getFieldId(field) - }).addClass(cssClass); - } - field.store('$moo:advice-' + className, advice); - return advice; - }, - - getFieldId : function(field){ - return field.id ? field.id : field.id = 'input_' + field.name; - }, - - showAdvice: function(className, field){ - var advice = this.getAdvice(className, field); - 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]); - } - }, - - hideAdvice: function(className, field){ - var advice = this.getAdvice(className, field); - 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]); - } - }, - - getPropName: function(className){ - return 'advice' + className; - }, - - resetField: function(field){ - field = document.id(field); - if (!field) return this; - this.parent(field); - field.get('validators').each(function(className){ - this.hideAdvice(className, field); - }, this); - return this; - }, - - getAllAdviceMessages: function(field, force){ - var advice = []; - if (field.hasClass('ignoreValidation') && !force) return advice; - 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); - if (!validator) return; - advice.push({ - message: validator.getError(field), - warnOnly: warner, - passed: validator.test(), - validator: validator - }); - }, this); - return advice; - }, - - getAdvice: function(className, field){ - return field.retrieve('$moo:advice-' + className); - }, - - insertAdvice: function(advice, field){ - //Check for error position prop - var props = field.get('validatorProps'); - //Build advice - if (!props.msgPos || !document.id(props.msgPos)){ - 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); - } - }, - - validateField: function(field, force, scroll){ - var result = this.parent(field, force); - 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('$moo:fvScroller'); - if (!fx && window.Fx && Fx.Scroll){ - fx = new Fx.Scroll(par, this.options.scrollFxOptions); - par.store('$moo:fvScroller', fx); - } - if (failed){ - if (fx) fx.toElement(failed); - else par.scrollTo(par.getScroll().x, failed.getPosition(par).y - 20); - } - } - return result; - }, - - 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){ - el.addEvent('change', this.validationMonitor.pass([el, true, this.options.scrollToErrorsOnChange], this)); - } - }, this); - } - -}); - - /* --- @@ -5220,7 +5074,7 @@ authors: - Aaron Newton requires: - - /Form.Validator + - Form.Validator provides: [Form.Validator.Extras] @@ -5401,7 +5255,8 @@ Form.Validator.addAllThese([ if (ccNum.test(/^4[0-9]{12}([0-9]{3})?$/)) valid_type = 'Visa'; else if (ccNum.test(/^5[1-5]([0-9]{14})$/)) valid_type = 'Master Card'; else if (ccNum.test(/^3[47][0-9]{13}$/)) valid_type = 'American Express'; - else if (ccNum.test(/^6011[0-9]{12}$/)) valid_type = 'Discover'; + else if (ccNum.test(/^6(?:011|5[0-9]{2})[0-9]{12}$/)) valid_type = 'Discover'; + else if (ccNum.test(/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/)) valid_type = 'Diners Club'; if (valid_type){ var sum = 0; @@ -5437,6 +5292,196 @@ Form.Validator.addAllThese([ ]); +/* +--- + +script: Form.Validator.Inline.js + +name: Form.Validator.Inline + +description: Extends Form.Validator to add inline messages. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Form.Validator + +provides: [Form.Validator.Inline] + +... +*/ + +Form.Validator.Inline = new Class({ + + Extends: Form.Validator, + + options: { + showError: function(errorElement){ + if (errorElement.reveal) errorElement.reveal(); + else errorElement.setStyle('display', 'block'); + }, + hideError: function(errorElement){ + if (errorElement.dissolve) errorElement.dissolve(); + else errorElement.setStyle('display', 'none'); + }, + scrollToErrorsOnSubmit: true, + scrollToErrorsOnBlur: false, + scrollToErrorsOnChange: false, + scrollFxOptions: { + transition: 'quad:out', + offset: { + y: -20 + } + } + }, + + initialize: function(form, options){ + this.parent(form, options); + this.addEvent('onElementValidate', function(isValid, field, className, warn){ + var validator = this.getValidator(className); + if (!isValid && validator.getError(field)){ + if (warn) field.addClass('warning'); + var advice = this.makeAdvice(className, field, validator.getError(field), warn); + this.insertAdvice(advice, field); + this.showAdvice(className, field); + } else { + this.hideAdvice(className, field); + } + }); + }, + + makeAdvice: function(className, field, error, warn){ + 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){ + advice = advice.set('html', errorMsg); + } else { + advice = new Element('div', { + html: errorMsg, + styles: { display: 'none' }, + id: 'advice-' + className.split(':')[0] + '-' + this.getFieldId(field) + }).addClass(cssClass); + } + field.store('$moo:advice-' + className, advice); + return advice; + }, + + getFieldId : function(field){ + return field.id ? field.id : field.id = 'input_' + field.name; + }, + + showAdvice: function(className, field){ + var advice = this.getAdvice(className, field); + if ( + advice && + !field.retrieve('$moo:' + this.getPropName(className)) && + ( + advice.getStyle('display') == 'none' || + advice.getStyle('visibility') == 'hidden' || + advice.getStyle('opacity') == 0 + ) + ){ + field.store('$moo:' + this.getPropName(className), true); + this.options.showError(advice); + this.fireEvent('showAdvice', [field, advice, className]); + } + }, + + hideAdvice: function(className, field){ + var advice = this.getAdvice(className, field); + 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]); + } + }, + + getPropName: function(className){ + return 'advice' + className; + }, + + resetField: function(field){ + field = document.id(field); + if (!field) return this; + this.parent(field); + field.get('validators').each(function(className){ + this.hideAdvice(className, field); + }, this); + return this; + }, + + getAllAdviceMessages: function(field, force){ + var advice = []; + if (field.hasClass('ignoreValidation') && !force) return advice; + 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); + if (!validator) return; + advice.push({ + message: validator.getError(field), + warnOnly: warner, + passed: validator.test(), + validator: validator + }); + }, this); + return advice; + }, + + getAdvice: function(className, field){ + return field.retrieve('$moo:advice-' + className); + }, + + insertAdvice: function(advice, field){ + //Check for error position prop + var props = field.get('validatorProps'); + //Build advice + if (!props.msgPos || !document.id(props.msgPos)){ + 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); + } + }, + + validateField: function(field, force, scroll){ + var result = this.parent(field, force); + 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('$moo:fvScroller'); + if (!fx && window.Fx && Fx.Scroll){ + fx = new Fx.Scroll(par, this.options.scrollFxOptions); + par.store('$moo:fvScroller', fx); + } + if (failed){ + if (fx) fx.toElement(failed); + else par.scrollTo(par.getScroll().x, failed.getPosition(par).y - 20); + } + } + return result; + }, + + 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){ + el.addEvent('change', this.validationMonitor.pass([el, true, this.options.scrollToErrorsOnChange], this)); + } + }, this); + } + +}); /* --- @@ -5573,7 +5618,6 @@ var OverText = new Class({ change: this.assert }); window.addEvent('resize', this.reposition); - this.assert(true); this.reposition(); return this; }, @@ -5632,7 +5676,7 @@ var OverText = new Class({ }, show: function(){ - if (this.text && !this.text.isDisplayed()){ + if (document.id(this.text) && !this.text.isDisplayed()){ this.text.show(); this.reposition(); this.fireEvent('textShow', [this.text, this.element]); @@ -5697,7 +5741,6 @@ Object.append(OverText, { }); - /* --- @@ -5714,7 +5757,7 @@ authors: requires: - Core/Fx.CSS - - /MooTools.More + - MooTools.More provides: [Fx.Elements] @@ -5773,7 +5816,6 @@ Fx.Elements = new Class({ }); - /* --- @@ -5790,7 +5832,7 @@ authors: requires: - Core/Element.Event - - /Fx.Elements + - Fx.Elements provides: [Fx.Accordion] @@ -5940,18 +5982,19 @@ Fx.Accordion = new Class({ if (useFx == null) useFx = true; if (typeOf(index) == 'element') index = elements.indexOf(index); - if (index == this.previous && !options.alwaysHide) return this; + if (index == this.current && !options.alwaysHide) return this; if (options.resetHeight){ - var prev = elements[this.previous]; + var prev = elements[this.current]; if (prev && !this.selfHidden){ for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]); } } - if ((this.timer && options.link == 'chain') || (index === this.previous && !options.alwaysHide)) return this; + if ((this.timer && options.link == 'chain') || (index === this.current && !options.alwaysHide)) return this; - this.previous = index; + if (this.current != null) this.previous = this.current; + this.current = index; this.selfHidden = false; elements.each(function(el, i){ @@ -5983,7 +6026,6 @@ Fx.Accordion = new Class({ - /* --- @@ -6000,7 +6042,7 @@ authors: requires: - Core/Fx.Morph - - /Element.Position + - Element.Position provides: [Fx.Move] @@ -6056,6 +6098,176 @@ 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); + 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); +} + +})(); /* --- @@ -6074,7 +6286,7 @@ authors: requires: - Core/Fx - Core/Element.Style - - /MooTools.More + - MooTools.More provides: [Fx.Slide] @@ -6228,180 +6440,6 @@ 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); -} - -})(); - - /* --- @@ -6418,7 +6456,7 @@ authors: requires: - Core/Slick.Finder - - /Fx.Scroll + - Fx.Scroll provides: [Fx.SmoothScroll] @@ -6473,7 +6511,6 @@ Fx.SmoothScroll = new Class({ } }); - /* --- @@ -6490,8 +6527,8 @@ authors: requires: - Core/Element.Dimensions - - /Fx.Elements - - /Element.Measure + - Fx.Elements + - Element.Measure provides: [Fx.Sort] @@ -6647,895 +6684,5928 @@ Fx.Sort = new Class({ }); - /* --- -script: Drag.js +script: Keyboard.js -name: Drag +name: Keyboard -description: The base Drag Class. Can be used to drag and resize Elements using mouse events. +description: KeyboardEvents used to intercept events on a class for keyboard and format modifiers in a specific order so as to make alt+shift+c the same as shift+alt+c. license: MIT-style license authors: - - Valerio Proietti - - Tom Occhinno - - Jan Kassens + - Perrin Westrich + - Aaron Newton + - Scott Kyle requires: - Core/Events - Core/Options - Core/Element.Event - - Core/Element.Style - - Core/Element.Dimensions - - /MooTools.More + - Element.Event.Pseudos.Keys + +provides: [Keyboard] -provides: [Drag] ... - */ -var Drag = new Class({ +(function(){ + + var Keyboard = this.Keyboard = new Class({ + + Extends: Events, + + Implements: [Options], + + options: {/* + onActivate: function(){}, + onDeactivate: function(){},*/ + defaultEventType: 'keydown', + active: false, + manager: null, + events: {}, + nonParsedEvents: ['activate', 'deactivate', 'onactivate', 'ondeactivate', 'changed', 'onchanged'] + }, + + initialize: function(options){ + if (options && options.manager){ + this._manager = options.manager; + delete options.manager; + } + this.setOptions(options); + this._setup(); + }, + + addEvent: function(type, fn, internal){ + return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn, internal); + }, + + removeEvent: function(type, fn){ + return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn); + }, + + toggleActive: function(){ + return this[this.isActive() ? 'deactivate' : 'activate'](); + }, + + activate: function(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; + 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'); + Keyboard.manager.fireEvent('changed'); + } else if (this._manager){ + //else we're enabling ourselves, we must ask our parent to do it for us + this._manager.activate(this); + } + return this; + }, + + isActive: function(){ + return this._manager ? (this._manager._activeKB == this) : (Keyboard.manager == this); + }, + + deactivate: function(instance){ + if (instance){ + if (instance === this._activeKB){ + this._activeKB = null; + instance.fireEvent('deactivate'); + Keyboard.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); + else this.deactivate(); + return this; + }, + + //management logic + manage: function(instance){ + 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){ + 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; + }, + + 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 ''; + }); + + if (!parsed[type]){ + if (type != '+'){ + var key, mods = {}; + type.split('+').each(function(part){ + if (regex.test(part)) mods[part] = true; + else key = part; + }); + + 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('+'); + } else { + parsed[type] = type; + } + } + + return eventType + ':keys(' + parsed[type] + ')'; + }; + + Keyboard.each = function(keyboard, fn){ + var current = keyboard || Keyboard.manager; + while (current){ + fn(current); + current = current._activeKB; + } + }; + + Keyboard.stop = function(event){ + event.preventKeyboardPropagation = true; + }; + + Keyboard.manager = new Keyboard({ + active: true + }); + + Keyboard.trace = function(keyboard){ + keyboard = keyboard || Keyboard.manager; + var hasConsole = window.console && console.log; + if (hasConsole) console.log('the following items have focus: '); + Keyboard.each(keyboard, function(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(' + keys.join('+') + ')'); + }; + + document.addEvents({ + 'keyup': handler, + 'keydown': handler + }); + +})(); + +/* +--- + +script: Keyboard.Extras.js + +name: Keyboard.Extras + +description: Enhances Keyboard by adding the ability to name and describe keyboard shortcuts, and the ability to grab shortcuts by name and bind the shortcut to different keys. + +license: MIT-style license + +authors: + - Perrin Westrich + +requires: + - Keyboard + - MooTools.More + +provides: [Keyboard.Extras] + +... +*/ +Keyboard.prototype.options.nonParsedEvents.combine(['rebound', 'onrebound']); + +Keyboard.implement({ + + /* + shortcut should be in the format of: + { + 'keys': 'shift+s', // the default to add as an event. + 'description': 'blah blah blah', // a brief description of the functionality. + '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 = Function.from(this); + shortcut.name = name; + 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]); + return this; + }, + + removeShortcut: function(name){ + var shortcut = this.getShortcut(name); + if (shortcut && shortcut.keys){ + this.removeEvent(shortcut.keys, shortcut.handler); + delete this._shortcutIndex[name]; + this._shortcuts.erase(shortcut); + } + return this; + }, + + removeShortcuts: function(names){ + names.each(this.removeShortcut, this); + return this; + }, + + getShortcuts: function(){ + return this._shortcuts || []; + }, + + getShortcut: function(name){ + return (this._shortcutIndex || {})[name]; + } + +}); + +Keyboard.rebind = function(newKeys, shortcuts){ + Array.from(shortcuts).each(function(shortcut){ + shortcut.getKeyboard().removeEvent(shortcut.keys, shortcut.handler); + shortcut.getKeyboard().addEvent(newKeys, shortcut.handler); + shortcut.keys = newKeys; + shortcut.getKeyboard().fireEvent('rebound'); + }); +}; + + +Keyboard.getActiveShortcuts = function(keyboard){ + var activeKBS = [], activeSCS = []; + Keyboard.each(keyboard, [].push.bind(activeKBS)); + activeKBS.each(function(kb){ activeSCS.extend(kb.getShortcuts()); }); + return activeSCS; +}; + +Keyboard.getShortcut = function(name, keyboard, opts){ + opts = 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); + }; + Keyboard.each(keyboard, set); + return shortcuts; +}; + +Keyboard.getShortcuts = function(name, keyboard){ + return Keyboard.getShortcut(name, keyboard, { many: true }); +}; + +/* +--- + +script: HtmlTable.js + +name: HtmlTable + +description: Builds table elements with methods to add rows. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Core/Options + - Core/Events + - Class.Occlude + +provides: [HtmlTable] + +... +*/ + +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 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(); + }, + + 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 = 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); + }, + + toElement: function(){ + return this.element; + }, + + empty: function(){ + this.body.empty(); + return this; + }, + + 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; + }, + + setFooters: function(footers){ + this.set('footers', footers); + return this; + }, + + update: function(tr, row, tag){ + var tds = tr.getChildren(tag || 'td'), last = tds.length - 1; + + row.each(function(data, index){ + var td = tds[index] || new Element(tag || 'td').inject(tr), + content = ((data && Object.prototype.hasOwnProperty.call(data, 'content')) ? data.content : '') || data, + type = typeOf(content); + + if (data && Object.prototype.hasOwnProperty.call(data, 'properties')) td.set(data.properties); + if (/(element(s?)|array|collection)/.test(type)) td.empty().adopt(content); + else td.set('html', content); + + if (index > last) tds.push(td); + else tds[index] = td; + }); + + return { + tr: tr, + tds: tds + }; + }, + + 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') + }; + } + return this.update(new Element('tr', rowProperties).inject(target || this.body, where), row, tag); + }, + + pushMany: function(rows, rowProperties, target, tag, where){ + return rows.map(function(row){ + return this.push(row, rowProperties, target, tag, where); + }, this); + } + +}); + + +['adopt', 'inject', 'wraps', 'grab', 'replaces', 'dispose'].each(function(method){ + HtmlTable.implement(method, function(){ + this.element[method].apply(this.element, arguments); + return this; + }); +}); + + + +/* +--- + +script: HtmlTable.Select.js + +name: HtmlTable.Select + +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: + - Keyboard + - Keyboard.Extras + - HtmlTable + - Class.refactor + - Element.Delegation.Pseudo + - Element.Shortcuts + +provides: [HtmlTable.Select] + +... +*/ + +HtmlTable = Class.refactor(HtmlTable, { + + options: { + /*onRowFocus: function(){}, + onRowUnfocus: function(){},*/ + useKeyboard: true, + classRowSelected: 'table-tr-selected', + classRowHovered: 'table-tr-hovered', + classSelectable: 'table-selectable', + shiftForMultiSelect: true, + allowMultiSelect: true, + selectable: false, + selectHiddenRows: false + }, + + initialize: function(){ + this.previous.apply(this, arguments); + if (this.occluded) return this.occluded; + + this.selectedRows = new Elements(); + + if (!this.bound) this.bound = {}; + this.bound.mouseleave = this.mouseleave.bind(this); + this.bound.clickRow = this.clickRow.bind(this); + this.bound.activateKeyboard = function(){ + if (this.keyboard && this.selectEnabled) this.keyboard.activate(); + }.bind(this); + + if (this.options.selectable) this.enableSelect(); + }, + + empty: function(){ + if (this.body.rows.length) 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; + }, + + 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.focused = row; + document.clearSelection(); + + return this; + }, + + isSelected: function(row){ + return this.selectedRows.contains(row); + }, + + 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++){ + if (this.options.selectHiddenRows || rows[i].isDisplayed()) this[method](rows[i], true); + } + + return this; + }, + + deselectRange: function(startRow, endRow){ + this.selectRange(startRow, endRow, true); + }, + +/* + 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, this.options.selectHiddenRows); + 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, includeHiddenRows){ + if (!this.focused) return 0; + var index = Array.indexOf(this.body.rows, this.focused); + if ((index == 0 && offset < 0) || (index == this.body.rows.length -1 && offset > 0)) return null; + if (includeHiddenRows){ + index += offset; + } else { + var limit = 0, + count = 0; + if (offset > 0){ + while (count < offset && index < this.body.rows.length -1){ + if (this.body.rows[++index].isDisplayed()) count++; + } + } else { + while (count > offset && index > 0){ + if (this.body.rows[--index].isDisplayed()) count--; + } + } + } + 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 + }); + + this.body[method]({ + '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 timer, held; + + var move = function(offset){ + var mover = function(e){ + clearTimeout(timer); + e.preventDefault(); + var to = this.body.rows[this.getRowByOffset(offset, this.options.selectHiddenRows)]; + 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(){ + 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)."; + } + + 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); + } + +}); + +/* +--- + +script: HtmlTable.Sort.js + +name: HtmlTable.Sort + +description: Builds a stripy, sortable table with methods to add rows. + +license: MIT-style license + +authors: + - Harald Kirschner + - Aaron Newton + - Jacob Thornton + +requires: + - Core/Hash + - HtmlTable + - Class.refactor + - Element.Delegation.Pseudo + - String.Extras + - Date + +provides: [HtmlTable.Sort] + +... +*/ +(function(){ + +var readOnlyNess = document.createElement('table'); +try { + readOnlyNess.innerHTML = ''; + readOnlyNess = readOnlyNess.childNodes.length === 0; +} catch (e){ + readOnlyNess = true; +} + +HtmlTable = Class.refactor(HtmlTable, { + + options: {/* + onSort: function(){}, */ + 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}; + if (!this.bound) this.bound = {}; + 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(attach){ + 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.sortable) 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(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; + }, + + 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); + + for (rowIndex = 0; rowIndex < count; rowIndex++){ + if (data[rowIndex].position > position) data[rowIndex].position--; + } + } + }, + + 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, sortFunction){ + if (!this.head) return; + + if (!pre){ + this.clearSort(); + this.setSortedState(index, reverse); + this.setHeadSort(true); + } + + var parser = this.getParser(); + if (!parser) return; + + var rel; + if (!readOnlyNess){ + rel = this.body.getParent(); + this.body.dispose(); + } + + var data = this.parseData(parser).sort(sortFunction ? sortFunction : function(a, b){ + if (a.value === b.value) return 0; + return a.value > b.value ? 1 : -1; + }); + + if (this.sorted.reverse == (parser == HtmlTable.Parsers['input-checked'])) data.reverse(true); + this.setRowSort(data, pre); + + if (rel) rel.grab(this.body); + this.fireEvent('stateChanged'); + return this.fireEvent('sort', [this.body, this.sorted.index]); + }, + + 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); + }, + + clearSort: function(){ + this.setHeadSort(false); + this.body.getElements('td').removeClass(this.options.classCellSort); + }, + + reSort: function(){ + if (this.sortable) 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.sortable = true; + return this; + }, + + disableSort: function(){ + this.element.removeClass(this.options.classSortable); + this.attachSorts(false); + this.sortSpans.each(function(span){ + span.destroy(); + }); + this.sortSpans.empty(); + this.sortable = 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 d = Date.parse(this.get('text').stripTags()); + return (typeOf(d) == 'date') ? d.format('db') : ''; + }, + type: 'date' + }, + 'input-checked': { + match: / type="(radio|checkbox)"/, + convert: function(){ + return this.getElement('input').checked; + } + }, + 'input-value': { + match: / (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(); + } + if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]); + } + +}); + +/* +--- + +script: Tips.js + +name: Tips + +description: Class for creating nice tips that follow the mouse cursor when hovering an element. + +license: MIT-style license + +authors: + - Valerio Proietti + - Christoph Pojer + - Luis Merino + +requires: + - Core/Options + - Core/Events + - Core/Element.Event + - Core/Element.Style + - Core/Element.Dimensions + - MooTools.More + +provides: [Tips] + +... +*/ + +(function(){ + +var read = function(option, element){ + return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : ''; +}; + +this.Tips = new Class({ Implements: [Events, Options], options: {/* - 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, - style: true, - limit: false, - handle: false, - invert: false, - preventDefault: false, - stopPropagation: false, - modifiers: {x: 'left', y: 'top'} + id: null, + onAttach: function(element){}, + onDetach: function(element){}, + onBound: function(coords){},*/ + onShow: function(){ + this.tip.setStyle('display', 'block'); + }, + onHide: function(){ + this.tip.setStyle('display', 'none'); + }, + title: 'title', + text: function(element){ + return element.get('rel') || element.get('href'); + }, + showDelay: 100, + hideDelay: 100, + className: 'tip-wrap', + offset: {x: 16, y: 16}, + windowPadding: {x:0, y:0}, + fixed: false, + waiAria: true }, initialize: function(){ var params = Array.link(arguments, { - 'options': Type.isObject, - 'element': function(obj){ + 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'}); - this.element = document.id(params.element); - this.document = this.element.getDocument(); - this.setOptions(params.options || {}); - 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.ie) ? 'selectstart' : 'mousedown'; - - - if (Browser.ie && !Drag.ondragstartFixed){ - document.ondragstart = Function.from(false); - Drag.ondragstartFixed = true; + if (this.options.id){ + this.container.set('id', this.options.id); + if (this.options.waiAria) this.attachWaiAria(); } - - 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; - }, + toElement: function(){ + if (this.tip) return this.tip; - detach: function(){ - this.handles.removeEvent('mousedown', this.bound.start); - return this; - }, - - start: function(event){ - var options = this.options; - - if (event.rightClick) return; - - if (options.preventDefault) event.preventDefault(); - if (options.stopPropagation) event.stopPropagation(); - this.mouse.start = event.page; - - this.fireEvent('beforeStart', this.element); - - var limit = options.limit; - this.limit = {x: [], y: []}; - - var z, coordinates; - for (z in options.modifiers){ - if (!options.modifiers[z]) continue; - - 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[options.modifiers[z]]; + 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'}) + ); - if (options.style) this.value.now[z] = (style || 0).toInt(); - else this.value.now[z] = this.element[options.modifiers[z]]; + return this.tip; + }, - if (options.invert) this.value.now[z] *= -1; + attachWaiAria: function(){ + var id = this.options.id; + this.container.set('role', 'tooltip'); - this.mouse.pos[z] = event.page[z] - this.value.now[z]; - - if (limit && limit[z]){ - var i = 2; - while (i--){ - var limitZI = limit[z][i]; - if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI; + if (!this.waiAria){ + this.waiAria = { + show: function(element){ + if (id) element.set('aria-describedby', id); + this.container.set('aria-hidden', 'false'); + }, + hide: function(element){ + if (id) element.erase('aria-describedby'); + this.container.set('aria-hidden', 'true'); } - } - } - - 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){ - if (this.options.preventDefault) event.preventDefault(); - var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); - if (distance > this.options.snap){ - this.cancel(); - this.document.addEvents({ - mousemove: this.bound.drag, - mouseup: this.bound.stop - }); - this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element); - } - }, - - drag: function(event){ - var options = this.options; - - if (options.preventDefault) event.preventDefault(); - this.mouse.now = event.page; - - for (var z in options.modifiers){ - if (!options.modifiers[z]) continue; - this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; - - 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 ((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 (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.removeEvents({ - mousemove: this.bound.check, - mouseup: this.bound.cancel - }); - if (event){ - this.document.removeEvent(this.selection, this.bound.eventStop); - this.fireEvent('cancel', this.element); - } - }, - - stop: function(event){ - 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]); - } - -}); - -Element.implement({ - - makeResizable: function(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); - }.bind(this)); - } - -}); - - -/* ---- - -script: Drag.Move.js - -name: Drag.Move - -description: A Drag extension that provides support for the constraining of draggables to containers and droppables. - -license: MIT-style license - -authors: - - Valerio Proietti - - Tom Occhinno - - Jan Kassens - - Aaron Newton - - Scott Kyle - -requires: - - Core/Element.Dimensions - - /Drag - -provides: [Drag.Move] - -... -*/ - -Drag.Move = new Class({ - - Extends: Drag, - - options: {/* - onEnter: function(thisElement, overed){}, - onLeave: function(thisElement, overed){}, - onDrop: function(thisElement, overed, event){},*/ - droppables: [], - container: false, - precalculate: false, - includeMargins: true, - checkDroppables: true - }, - - 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 && 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 parent = element.getOffsetParent(), - styles = element.getStyles('left', 'top'); - if (parent && (styles.left == 'auto' || styles.top == 'auto')){ - 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 element = this.element, - container = this.container, - - offsetParent = document.id(element.getOffsetParent()) || document.body, - containerCoordinates = container.getCoordinates(offsetParent), - elementMargin = {}, - elementBorder = {}, - containerMargin = {}, - containerBorder = {}, - offsetParentPadding = {}; - - ['top', 'right', 'bottom', 'left'].each(function(pad){ - 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(); - }, this); - - 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, - bottom = containerCoordinates.bottom - containerBorder.bottom - height; - - if (this.options.includeMargins){ - left += elementMargin.left; - top += elementMargin.top; - } else { - right += elementMargin.right; - bottom += elementMargin.bottom; - } - - 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 (container != offsetParent){ - left += containerMargin.left + offsetParentPadding.left; - top += ((Browser.ie6 || Browser.ie7) ? 0 : containerMargin.top) + offsetParentPadding.top; - } - } else { - left -= elementMargin.left; - top -= elementMargin.top; - if (container != offsetParent){ - left += containerCoordinates.left + containerBorder.left; - top += containerCoordinates.top + containerBorder.top; - } - } - - return { - x: [left, right], - y: [top, bottom] - }; - }, - - 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(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]); - this.overed = overed; - } - }, - - drag: function(event){ - this.parent(event); - if (this.options.checkDroppables && this.droppables.length) this.checkDroppables(); - }, - - stop: function(event){ - this.checkDroppables(); - this.fireEvent('drop', [this.element, this.overed, event]); - this.overed = null; - return this.parent(event); - } - -}); - -Element.implement({ - - makeDraggable: function(options){ - var drag = new Drag.Move(this, options); - this.store('dragger', drag); - return drag; - } - -}); - - -/* ---- - -script: Slider.js - -name: Slider - -description: Class for creating horizontal and vertical slider controls. - -license: MIT-style license - -authors: - - Valerio Proietti - -requires: - - Core/Element.Dimensions - - /Class.Binds - - /Drag - - /Element.Measure - -provides: [Slider] - -... -*/ - -var Slider = new Class({ - - Implements: [Events, Options], - - Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'], - - options: {/* - onTick: function(intPosition){}, - onChange: function(intStep){}, - onComplete: function(strStep){},*/ - onTick: function(position){ - this.setKnobPosition(position); - }, - initialStep: 0, - snap: false, - offset: 0, - range: false, - wheel: false, - steps: 100, - mode: 'horizontal' - }, - - initialize: function(element, knob, options){ - this.setOptions(options); - options = this.options; - this.element = document.id(element); - knob = this.knob = document.id(knob); - this.previousChange = this.previousEnd = this.step = -1; - - var limit = {}, - modifiers = {x: false, y: false}; - - switch (options.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(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] = [-options.offset, this.full - options.offset]; - - var dragOptions = { - snap: 0, - limit: limit, - modifiers: modifiers, - 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 (options.snap) this.setSnap(dragOptions); - - this.drag = new Drag(knob, dragOptions); - this.attach(); - if (options.initialStep != null) this.set(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) - .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); - return this.checkStep() - .fireEvent('tick', this.toPosition(this.step)) - .end(); - }, - - setRange: function(range, pos){ - 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); - 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, - 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() - .fireEvent('tick', position) - .end(); - }, - - scrolledElement: function(event){ - var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0); - this.set(this.step + (mode ? -1 : 1) * this.stepSize); - event.stop(); - }, - - draggedKnob: function(){ - 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(){ - var step = this.step; - if (this.previousChange != step){ - this.previousChange = step; - this.fireEvent('change', step); - } - return this; - }, - - end: function(){ - var step = this.step; - if (this.previousEnd !== step){ - this.previousEnd = step; - this.fireEvent('complete', step + ''); - } - return this; - }, - - toStep: function(position){ - var step = (position + this.options.offset) * this.stepSize / this.full * this.steps; - return this.options.steps ? Math.round(step -= step % this.stepSize) : step; - }, - - toPosition: function(step){ - return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset; - } - -}); - - -/* ---- - -script: Sortables.js - -name: Sortables - -description: Class for creating a drag and drop sorting interface for lists of items. - -license: MIT-style license - -authors: - - Tom Occhino - -requires: - - Core/Fx.Morph - - /Drag.Move - -provides: [Sortables] - -... -*/ - -var Sortables = new Class({ - - Implements: [Events, Options], - - options: {/* - onSort: function(element, clone){}, - onStart: function(element, clone){}, - onComplete: function(element){},*/ - opacity: 1, - clone: false, - revert: false, - handle: 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, 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(element){ - this.elements.push(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; - }, - - addLists: function(){ - Array.flatten(arguments).each(function(list){ - this.lists.include(list); - this.addItems(list.getChildren()); - }, this); - return this; - }, - - removeItems: function(){ - return $$(Array.flatten(arguments).map(function(element){ - 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)); - }, - - removeLists: function(){ - 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 (typeOf(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list); - var clone = element.clone(true).setStyles({ - margin: 0, - position: 'absolute', - visibility: 'hidden', - 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){ - 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().erase(this.clone).erase(this.element); - if (!this.options.constrain) droppables.append(this.lists).erase(this.list); - return droppables; - }, - - insert: function(dragging, element){ - var where = 'inside'; - if (this.lists.contains(element)){ - this.list = element; - this.drag.droppables = this.getDroppables(); - } else { - where = this.element.getAllPrevious().contains(element) ? 'before' : 'after'; - } - this.element.inject(element, where); - this.fireEvent('sort', [this.element, this.clone]); - }, - - start: function(event, element){ - if ( - !this.idle || - event.rightClick || - ['button', 'input', 'a'].contains(event.target.get('tag')) - ) return; - - this.idle = false; - this.element = element; - this.opacity = element.get('opacity'); - this.list = element.getParent(); - this.clone = this.getClone(event, element); - - 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'); - 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(event); - }, - - end: function(){ - this.drag.detach(); - this.element.set('opacity', this.opacity); - if (this.effect){ - 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 - }).addEvent('cancel', destroy).chain(destroy); - } else { - this.clone.destroy(); } - this.reset(); + this.addEvents(this.waiAria); }, - reset: function(){ - this.idle = true; - this.fireEvent('complete', this.element); + detachWaiAria: function(){ + if (this.waiAria){ + this.container.erase('role'); + this.container.erase('aria-hidden'); + this.removeEvents(this.waiAria); + } }, - serialize: function(){ - 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'); + attach: function(elements){ + $$(elements).each(function(element){ + var title = read(this.options.title, element), + text = read(this.options.text, element); + + 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 = function(event){ + this['element' + value.capitalize()].apply(this, [event, element]); + }.bind(this); + + element.store('tip:' + value, event).addEvent('mouse' + value, event); }, this); }, this); - var index = params.index; - if (this.lists.length == 1) index = 0; - return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial; + return this; + }, + + detach: function(elements){ + $$(elements).each(function(element){ + ['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){ + 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){ + 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; + if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event); + else this.fireForParent(event, element); + }, + + elementMove: function(event, element){ + this.position(event); + }, + + position: function(event){ + if (!this.tip) document.id(this); + + 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]] < 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); + else element.adopt(contents); + }, + + show: function(element){ + if (!this.tip) document.id(this); + if (!this.tip.getParent()) this.tip.inject(document.body); + this.fireEvent('show', [this.tip, element]); + }, + + hide: function(element){ + if (!this.tip) document.id(this); + this.fireEvent('hide', [this.tip, element]); } }); +})(); + +/* +--- + +name: Locale.EU.Number + +description: Number messages for Europe. + +license: MIT-style license + +authors: + - Arian Stolwijk + +requires: + - Locale + +provides: [Locale.EU.Number] + +... +*/ + +Locale.define('EU', 'Number', { + + decimal: ',', + group: '.', + + currency: { + prefix: '€ ' + } + +}); + +/* +--- + +script: Locale.Set.From.js + +name: Locale.Set.From + +description: Provides an alternative way to create Locale.Set objects. + +license: MIT-style license + +authors: + - Tim Wienk + +requires: + - Core/JSON + - Locale + +provides: Locale.Set.From + +... +*/ + +(function(){ + +var parsers = { + 'json': JSON.decode +}; + +Locale.Set.defineParser = function(name, fn){ + parsers[name] = fn; +}; + +Locale.Set.from = function(set, type){ + if (instanceOf(set, Locale.Set)) return set; + + if (!type && typeOf(set) == 'string') type = 'json'; + if (parsers[type]) set = parsers[type](set); + + var locale = new Locale.Set; + + locale.sets = set.sets || {}; + + if (set.inherits){ + locale.inherits.locales = Array.from(set.inherits.locales); + locale.inherits.sets = set.inherits.sets || {}; + } + + return locale; +}; + +})(); + +/* +--- + +name: Locale.ZA.Number + +description: Number messages for ZA. + +license: MIT-style license + +authors: + - Werner Mollentze + +requires: + - Locale + +provides: [Locale.ZA.Number] + +... +*/ + +Locale.define('ZA', 'Number', { + + decimal: '.', + group: ',', + + currency: { + prefix: 'R ' + } + +}); + + + +/* +--- + +name: Locale.af-ZA.Date + +description: Date messages for ZA Afrikaans. + +license: MIT-style license + +authors: + - Werner Mollentze + +requires: + - Locale + +provides: [Locale.af-ZA.Date] + +... +*/ + +Locale.define('af-ZA', 'Date', { + + months: ['Januarie', 'Februarie', 'Maart', 'April', 'Mei', 'Junie', 'Julie', 'Augustus', 'September', 'Oktober', 'November', 'Desember'], + months_abbr: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'], + days: ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'], + days_abbr: ['Son', 'Maa', 'Din', 'Woe', 'Don', 'Vry', 'Sat'], + + // Culture's date order: MM/DD/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d-%m-%Y', + shortTime: '%H:%M', + AM: 'VM', + PM: 'NM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: function(dayOfMonth){ + return ((dayOfMonth > 1 && dayOfMonth < 20 && dayOfMonth != 8) || (dayOfMonth > 100 && dayOfMonth.toString().substr(-2, 1) == '1')) ? 'de' : 'ste'; + }, + + lessThanMinuteAgo: 'minder as \'n minuut gelede', + minuteAgo: 'ongeveer \'n minuut gelede', + minutesAgo: '{delta} minute gelede', + hourAgo: 'omtret \'n uur gelede', + hoursAgo: 'ongeveer {delta} ure gelede', + dayAgo: '1 dag gelede', + daysAgo: '{delta} dae gelede', + weekAgo: '1 week gelede', + weeksAgo: '{delta} weke gelede', + monthAgo: '1 maand gelede', + monthsAgo: '{delta} maande gelede', + yearAgo: '1 jaar gelede', + yearsAgo: '{delta} jare gelede', + + lessThanMinuteUntil: 'oor minder as \'n minuut', + minuteUntil: 'oor ongeveer \'n minuut', + minutesUntil: 'oor {delta} minute', + hourUntil: 'oor ongeveer \'n uur', + hoursUntil: 'oor {delta} uur', + dayUntil: 'oor ongeveer \'n dag', + daysUntil: 'oor {delta} dae', + weekUntil: 'oor \'n week', + weeksUntil: 'oor {delta} weke', + monthUntil: 'oor \'n maand', + monthsUntil: 'oor {delta} maande', + yearUntil: 'oor \'n jaar', + yearsUntil: 'oor {delta} jaar' + +}); + +/* +--- + +name: Locale.af-ZA.Form.Validator + +description: Form Validator messages for Afrikaans. + +license: MIT-style license + +authors: + - Werner Mollentze + +requires: + - Locale + +provides: [Locale.af-ZA.Form.Validator] + +... +*/ + +Locale.define('af-ZA', 'FormValidator', { + + required: 'Hierdie veld word vereis.', + length: 'Voer asseblief {length} karakters in (u het {elLength} karakters ingevoer)', + minLength: 'Voer asseblief ten minste {minLength} karakters in (u het {length} karakters ingevoer).', + maxLength: 'Moet asseblief nie meer as {maxLength} karakters invoer nie (u het {length} karakters ingevoer).', + integer: 'Voer asseblief \'n heelgetal in hierdie veld in. Getalle met desimale (bv. 1.25) word nie toegelaat nie.', + numeric: 'Voer asseblief slegs numeriese waardes in hierdie veld in (bv. "1" of "1.1" of "-1" of "-1.1").', + digits: 'Gebruik asseblief slegs nommers en punktuasie in hierdie veld. (by voorbeeld, \'n telefoon nommer wat koppeltekens en punte bevat is toelaatbaar).', + alpha: 'Gebruik asseblief slegs letters (a-z) binne-in hierdie veld. Geen spasies of ander karakters word toegelaat nie.', + alphanum: 'Gebruik asseblief slegs letters (a-z) en nommers (0-9) binne-in hierdie veld. Geen spasies of ander karakters word toegelaat nie.', + dateSuchAs: 'Voer asseblief \'n geldige datum soos {date} in', + dateInFormatMDY: 'Voer asseblief \'n geldige datum soos MM/DD/YYYY in (bv. "12/31/1999")', + email: 'Voer asseblief \'n geldige e-pos adres in. Byvoorbeeld "fred@domain.com".', + url: 'Voer asseblief \'n geldige bronadres (URL) soos http://www.example.com in.', + currencyDollar: 'Voer asseblief \'n geldige $ bedrag in. Byvoorbeeld $100.00 .', + oneRequired: 'Voer asseblief iets in vir ten minste een van hierdie velde.', + errorPrefix: 'Fout: ', + warningPrefix: 'Waarskuwing: ', + + // Form.Validator.Extras + noSpace: 'Daar mag geen spasies in hierdie toevoer wees nie.', + reqChkByNode: 'Geen items is gekies nie.', + requiredChk: 'Hierdie veld word vereis.', + reqChkByName: 'Kies asseblief \'n {label}.', + match: 'Hierdie veld moet by die {matchName} veld pas', + startDate: 'die begin datum', + endDate: 'die eind datum', + currentDate: 'die huidige datum', + afterDate: 'Die datum moet dieselfde of na {label} wees.', + beforeDate: 'Die datum moet dieselfde of voor {label} wees.', + startMonth: 'Kies asseblief \'n begin maand', + sameMonth: 'Hierdie twee datums moet in dieselfde maand wees - u moet een of beide verander.', + creditcard: 'Die ingevoerde kredietkaart nommer is ongeldig. Bevestig asseblief die nommer en probeer weer. {length} syfers is ingevoer.' + +}); + +/* +--- + +name: Locale.af-ZA.Number + +description: Number messages for ZA Afrikaans. + +license: MIT-style license + +authors: + - Werner Mollentze + +requires: + - Locale + - Locale.ZA.Number + +provides: [Locale.af-ZA.Number] + +... +*/ + +Locale.define('af-ZA').inherit('ZA', 'Number'); + +/* +--- + +name: Locale.ar.Date + +description: Date messages for Arabic. + +license: MIT-style license + +authors: + - Chafik Barbar + +requires: + - Locale + +provides: [Locale.ar.Date] + +... +*/ + +Locale.define('ar', 'Date', { + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M' + +}); + +/* +--- + +name: Locale.ar.Form.Validator + +description: Form Validator messages for Arabic. + +license: MIT-style license + +authors: + - Chafik Barbar + +requires: + - Locale + +provides: [Locale.ar.Form.Validator] + +... +*/ + +Locale.define('ar', 'FormValidator', { + + required: 'هذا الحقل مطلوب.', + minLength: 'رجاءً إدخال {minLength} أحرف على الأقل (تم إدخال {length} أحرف).', + maxLength: 'الرجاء عدم إدخال أكثر من {maxLength} أحرف (تم إدخال {length} أحرف).', + integer: 'الرجاء إدخال عدد صحيح في هذا الحقل. أي رقم ذو كسر عشري أو مئوي (مثال 1.25 ) غير مسموح.', + numeric: 'الرجاء إدخال قيم رقمية في هذا الحقل (مثال "1" أو "1.1" أو "-1" أو "-1.1").', + digits: 'الرجاء أستخدام قيم رقمية وعلامات ترقيمية فقط في هذا الحقل (مثال, رقم هاتف مع نقطة أو شحطة)', + alpha: 'الرجاء أستخدام أحرف فقط (ا-ي) في هذا الحقل. أي فراغات أو علامات غير مسموحة.', + alphanum: 'الرجاء أستخدام أحرف فقط (ا-ي) أو أرقام (0-9) فقط في هذا الحقل. أي فراغات أو علامات غير مسموحة.', + dateSuchAs: 'الرجاء إدخال تاريخ صحيح كالتالي {date}', + dateInFormatMDY: 'الرجاء إدخال تاريخ صحيح (مثال, 31-12-1999)', + email: 'الرجاء إدخال بريد إلكتروني صحيح.', + url: 'الرجاء إدخال عنوان إلكتروني صحيح مثل http://www.example.com', + currencyDollar: 'الرجاء إدخال قيمة $ صحيحة. مثال, 100.00$', + oneRequired: 'الرجاء إدخال قيمة في أحد هذه الحقول على الأقل.', + errorPrefix: 'خطأ: ', + warningPrefix: 'تحذير: ' + +}); + +/* +--- + +name: Locale.ca-CA.Date + +description: Date messages for Catalan. + +license: MIT-style license + +authors: + - Ãlfons Sanchez + +requires: + - Locale + +provides: [Locale.ca-CA.Date] + +... +*/ + +Locale.define('ca-CA', 'Date', { + + months: ['Gener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juli', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Desembre'], + months_abbr: ['gen.', 'febr.', 'març', 'abr.', 'maig', 'juny', 'jul.', 'ag.', 'set.', 'oct.', 'nov.', 'des.'], + days: ['Diumenge', 'Dilluns', 'Dimarts', 'Dimecres', 'Dijous', 'Divendres', 'Dissabte'], + days_abbr: ['dg', 'dl', 'dt', 'dc', 'dj', 'dv', 'ds'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 0, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'fa menys d`un minut', + minuteAgo: 'fa un minut', + minutesAgo: 'fa {delta} minuts', + hourAgo: 'fa un hora', + hoursAgo: 'fa unes {delta} hores', + dayAgo: 'fa un dia', + daysAgo: 'fa {delta} dies', + + lessThanMinuteUntil: 'menys d`un minut des d`ara', + minuteUntil: 'un minut des d`ara', + minutesUntil: '{delta} minuts des d`ara', + hourUntil: 'un hora des d`ara', + hoursUntil: 'unes {delta} hores des d`ara', + dayUntil: '1 dia des d`ara', + daysUntil: '{delta} dies des d`ara' + +}); + +/* +--- + +name: Locale.ca-CA.Form.Validator + +description: Form Validator messages for Catalan. + +license: MIT-style license + +authors: + - Miquel Hudin + - Ãlfons Sanchez + +requires: + - Locale + +provides: [Locale.ca-CA.Form.Validator] + +... +*/ + +Locale.define('ca-CA', 'FormValidator', { + + required: 'Aquest camp es obligatori.', + minLength: 'Per favor introdueix al menys {minLength} caracters (has introduit {length} caracters).', + maxLength: 'Per favor introdueix no mes de {maxLength} caracters (has introduit {length} caracters).', + integer: 'Per favor introdueix un nombre enter en aquest camp. Nombres amb decimals (p.e. 1,25) no estan permesos.', + numeric: 'Per favor introdueix sols valors numerics en aquest camp (p.e. "1" o "1,1" o "-1" o "-1,1").', + digits: 'Per favor usa sols numeros i puntuacio en aquest camp (per exemple, un nombre de telefon amb guions i punts no esta permes).', + alpha: 'Per favor utilitza lletres nomes (a-z) en aquest camp. No s´admiteixen espais ni altres caracters.', + alphanum: 'Per favor, utilitza nomes lletres (a-z) o numeros (0-9) en aquest camp. No s´admiteixen espais ni altres caracters.', + dateSuchAs: 'Per favor introdueix una data valida com {date}', + dateInFormatMDY: 'Per favor introdueix una data valida com DD/MM/YYYY (p.e. "31/12/1999")', + email: 'Per favor, introdueix una adreça de correu electronic valida. Per exemple, "fred@domain.com".', + url: 'Per favor introdueix una URL valida com http://www.example.com.', + currencyDollar: 'Per favor introdueix una quantitat valida de €. Per exemple €100,00 .', + oneRequired: 'Per favor introdueix alguna cosa per al menys una d´aquestes entrades.', + errorPrefix: 'Error: ', + warningPrefix: 'Avis: ', + + // Form.Validator.Extras + noSpace: 'No poden haver espais en aquesta entrada.', + reqChkByNode: 'No hi han elements seleccionats.', + requiredChk: 'Aquest camp es obligatori.', + reqChkByName: 'Per favor selecciona una {label}.', + match: 'Aquest camp necessita coincidir amb el camp {matchName}', + startDate: 'la data de inici', + endDate: 'la data de fi', + currentDate: 'la data actual', + afterDate: 'La data deu ser igual o posterior a {label}.', + beforeDate: 'La data deu ser igual o anterior a {label}.', + startMonth: 'Per favor selecciona un mes d´orige', + sameMonth: 'Aquestes dos dates deuen estar dins del mateix mes - deus canviar una o altra.' + +}); + +/* +--- + +name: Locale.cs-CZ.Date + +description: Date messages for Czech. + +license: MIT-style license + +authors: + - Jan Černý chemiX + - Christopher Zukowski + +requires: + - Locale + +provides: [Locale.cs-CZ.Date] + +... +*/ +(function(){ + +// Czech language pluralization rules, see http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html +// one -> n is 1; 1 +// few -> n in 2..4; 2-4 +// other -> everything else 0, 5-999, 1.31, 2.31, 5.31... +var pluralize = function (n, one, few, other){ + if (n == 1) return one; + else if (n == 2 || n == 3 || n == 4) return few; + else return other; +}; + +Locale.define('cs-CZ', 'Date', { + + months: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'], + months_abbr: ['ledna', 'února', 'března', 'dubna', 'května', 'června', 'července', 'srpna', 'září', 'října', 'listopadu', 'prosince'], + days: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'], + days_abbr: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], + + // Culture's date order: DD.MM.YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H:%M', + AM: 'dop.', + PM: 'odp.', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'před chvílí', + minuteAgo: 'přibližně před minutou', + minutesAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'minutou', 'minutami', 'minutami'); }, + hourAgo: 'přibližně před hodinou', + hoursAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'hodinou', 'hodinami', 'hodinami'); }, + dayAgo: 'před dnem', + daysAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'dnem', 'dny', 'dny'); }, + weekAgo: 'před týdnem', + weeksAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'týdnem', 'týdny', 'týdny'); }, + monthAgo: 'před měsícem', + monthsAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'měsícem', 'měsíci', 'měsíci'); }, + yearAgo: 'před rokem', + yearsAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'rokem', 'lety', 'lety'); }, + + lessThanMinuteUntil: 'za chvíli', + minuteUntil: 'přibližně za minutu', + minutesUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'minutu', 'minuty', 'minut'); }, + hourUntil: 'přibližně za hodinu', + hoursUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'hodinu', 'hodiny', 'hodin'); }, + dayUntil: 'za den', + daysUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'den', 'dny', 'dnů'); }, + weekUntil: 'za týden', + weeksUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'týden', 'týdny', 'týdnů'); }, + monthUntil: 'za měsíc', + monthsUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'měsíc', 'měsíce', 'měsíců'); }, + yearUntil: 'za rok', + yearsUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'rok', 'roky', 'let'); } +}); + +})(); + +/* +--- + +name: Locale.cs-CZ.Form.Validator + +description: Form Validator messages for Czech. + +license: MIT-style license + +authors: + - Jan Černý chemiX + +requires: + - Locale + +provides: [Locale.cs-CZ.Form.Validator] + +... +*/ + +Locale.define('cs-CZ', 'FormValidator', { + + required: 'Tato položka je povinná.', + minLength: 'Zadejte prosím alespoň {minLength} znaků (napsáno {length} znaků).', + maxLength: 'Zadejte prosím méně než {maxLength} znaků (nápsáno {length} znaků).', + integer: 'Zadejte prosím celé číslo. Desetinná čísla (např. 1.25) nejsou povolena.', + numeric: 'Zadejte jen číselné hodnoty (tj. "1" nebo "1.1" nebo "-1" nebo "-1.1").', + digits: 'Zadejte prosím pouze čísla a interpunkční znaménka(například telefonní číslo s pomlčkami nebo tečkami je povoleno).', + alpha: 'Zadejte prosím pouze písmena (a-z). Mezery nebo jiné znaky nejsou povoleny.', + alphanum: 'Zadejte prosím pouze písmena (a-z) nebo číslice (0-9). Mezery nebo jiné znaky nejsou povoleny.', + dateSuchAs: 'Zadejte prosím platné datum jako {date}', + dateInFormatMDY: 'Zadejte prosím platné datum jako MM / DD / RRRR (tj. "12/31/1999")', + email: 'Zadejte prosím platnou e-mailovou adresu. Například "fred@domain.com".', + url: 'Zadejte prosím platnou URL adresu jako http://www.example.com.', + currencyDollar: 'Zadejte prosím platnou částku. Například $100.00.', + oneRequired: 'Zadejte prosím alespoň jednu hodnotu pro tyto položky.', + errorPrefix: 'Chyba: ', + warningPrefix: 'Upozornění: ', + + // Form.Validator.Extras + noSpace: 'V této položce nejsou povoleny mezery', + reqChkByNode: 'Nejsou vybrány žádné položky.', + requiredChk: 'Tato položka je vyžadována.', + reqChkByName: 'Prosím vyberte {label}.', + match: 'Tato položka se musí shodovat s položkou {matchName}', + startDate: 'datum zahájení', + endDate: 'datum ukončení', + currentDate: 'aktuální datum', + afterDate: 'Datum by mělo být stejné nebo větší než {label}.', + beforeDate: 'Datum by mělo být stejné nebo menší než {label}.', + startMonth: 'Vyberte počáteční měsíc.', + sameMonth: 'Tyto dva datumy musí být ve stejném měsíci - změňte jeden z nich.', + creditcard: 'Zadané číslo kreditní karty je neplatné. Prosím opravte ho. Bylo zadáno {length} čísel.' + +}); + +/* +--- + +name: Locale.da-DK.Date + +description: Date messages for Danish. + +license: MIT-style license + +authors: + - Martin Overgaard + - Henrik Hansen + +requires: + - Locale + +provides: [Locale.da-DK.Date] + +... +*/ + +Locale.define('da-DK', 'Date', { + + months: ['Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December'], + months_abbr: ['jan.', 'feb.', 'mar.', 'apr.', 'maj.', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'], + days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'], + days_abbr: ['søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør'], + + // Culture's date order: DD-MM-YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d-%m-%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'mindre end et minut siden', + minuteAgo: 'omkring et minut siden', + minutesAgo: '{delta} minutter siden', + hourAgo: 'omkring en time siden', + hoursAgo: 'omkring {delta} timer siden', + dayAgo: '1 dag siden', + daysAgo: '{delta} dage siden', + weekAgo: '1 uge siden', + weeksAgo: '{delta} uger siden', + monthAgo: '1 måned siden', + monthsAgo: '{delta} måneder siden', + yearAgo: '1 år siden', + yearsAgo: '{delta} år siden', + + lessThanMinuteUntil: 'mindre end et minut fra nu', + minuteUntil: 'omkring et minut fra nu', + minutesUntil: '{delta} minutter fra nu', + hourUntil: 'omkring en time fra nu', + hoursUntil: 'omkring {delta} timer fra nu', + dayUntil: '1 dag fra nu', + daysUntil: '{delta} dage fra nu', + weekUntil: '1 uge fra nu', + weeksUntil: '{delta} uger fra nu', + monthUntil: '1 måned fra nu', + monthsUntil: '{delta} måneder fra nu', + yearUntil: '1 år fra nu', + yearsUntil: '{delta} år fra nu' + +}); + +/* +--- + +name: Locale.da-DK.Form.Validator + +description: Form Validator messages for Danish. + +license: MIT-style license + +authors: + - Martin Overgaard + +requires: + - Locale + +provides: [Locale.da-DK.Form.Validator] + +... +*/ + +Locale.define('da-DK', 'FormValidator', { + + required: 'Feltet skal udfyldes.', + minLength: 'Skriv mindst {minLength} tegn (du skrev {length} tegn).', + maxLength: 'Skriv maksimalt {maxLength} tegn (du skrev {length} tegn).', + integer: 'Skriv et tal i dette felt. Decimal tal (f.eks. 1.25) er ikke tilladt.', + numeric: 'Skriv kun tal i dette felt (i.e. "1" eller "1.1" eller "-1" eller "-1.1").', + digits: 'Skriv kun tal og tegnsætning i dette felt (eksempel, et telefon nummer med bindestreg eller punktum er tilladt).', + alpha: 'Skriv kun bogstaver (a-z) i dette felt. Mellemrum og andre tegn er ikke tilladt.', + alphanum: 'Skriv kun bogstaver (a-z) eller tal (0-9) i dette felt. Mellemrum og andre tegn er ikke tilladt.', + dateSuchAs: 'Skriv en gyldig dato som {date}', + dateInFormatMDY: 'Skriv dato i formatet DD-MM-YYYY (f.eks. "31-12-1999")', + email: 'Skriv en gyldig e-mail adresse. F.eks "fred@domain.com".', + url: 'Skriv en gyldig URL adresse. F.eks "http://www.example.com".', + currencyDollar: 'Skriv et gldigt beløb. F.eks Kr.100.00 .', + oneRequired: 'Et eller flere af felterne i denne formular skal udfyldes.', + errorPrefix: 'Fejl: ', + warningPrefix: 'Advarsel: ', + + // Form.Validator.Extras + noSpace: 'Der må ikke benyttes mellemrum i dette felt.', + reqChkByNode: 'Foretag et valg.', + requiredChk: 'Dette felt skal udfyldes.', + reqChkByName: 'Vælg en {label}.', + match: 'Dette felt skal matche {matchName} feltet', + startDate: 'start dato', + endDate: 'slut dato', + currentDate: 'dags dato', + afterDate: 'Datoen skal være større end eller lig med {label}.', + beforeDate: 'Datoen skal være mindre end eller lig med {label}.', + startMonth: 'Vælg en start måned', + sameMonth: 'De valgte datoer skal være i samme måned - skift en af dem.' + +}); + +/* +--- + +name: Locale.de-DE.Date + +description: Date messages for German. + +license: MIT-style license + +authors: + - Christoph Pojer + - Frank Rossi + - Ulrich Petri + - Fabian Beiner + +requires: + - Locale + +provides: [Locale.de-DE.Date] + +... +*/ + +Locale.define('de-DE', 'Date', { + + months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], + months_abbr: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], + days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], + days_abbr: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], + + // Culture's date order: DD.MM.YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H:%M', + AM: 'vormittags', + PM: 'nachmittags', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'vor weniger als einer Minute', + minuteAgo: 'vor einer Minute', + minutesAgo: 'vor {delta} Minuten', + hourAgo: 'vor einer Stunde', + hoursAgo: 'vor {delta} Stunden', + dayAgo: 'vor einem Tag', + daysAgo: 'vor {delta} Tagen', + weekAgo: 'vor einer Woche', + weeksAgo: 'vor {delta} Wochen', + monthAgo: 'vor einem Monat', + monthsAgo: 'vor {delta} Monaten', + yearAgo: 'vor einem Jahr', + yearsAgo: 'vor {delta} Jahren', + + lessThanMinuteUntil: 'in weniger als einer Minute', + minuteUntil: 'in einer Minute', + minutesUntil: 'in {delta} Minuten', + hourUntil: 'in ca. einer Stunde', + hoursUntil: 'in ca. {delta} Stunden', + dayUntil: 'in einem Tag', + daysUntil: 'in {delta} Tagen', + weekUntil: 'in einer Woche', + weeksUntil: 'in {delta} Wochen', + monthUntil: 'in einem Monat', + monthsUntil: 'in {delta} Monaten', + yearUntil: 'in einem Jahr', + yearsUntil: 'in {delta} Jahren' + +}); + +/* +--- + +name: Locale.de-CH.Date + +description: Date messages for German (Switzerland). + +license: MIT-style license + +authors: + - Michael van der Weg + +requires: + - Locale + - Locale.de-DE.Date + +provides: [Locale.de-CH.Date] + +... +*/ + +Locale.define('de-CH').inherit('de-DE', 'Date'); + +/* +--- + +name: Locale.de-CH.Form.Validator + +description: Form Validator messages for German (Switzerland). + +license: MIT-style license + +authors: + - Michael van der Weg + +requires: + - Locale + +provides: [Locale.de-CH.Form.Validator] + +... +*/ + +Locale.define('de-CH', 'FormValidator', { + + required: 'Dieses Feld ist obligatorisch.', + minLength: 'Geben Sie bitte mindestens {minLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).', + maxLength: 'Bitte geben Sie nicht mehr als {maxLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).', + integer: 'Geben Sie bitte eine ganze Zahl ein. Dezimalzahlen (z.B. 1.25) sind nicht erlaubt.', + numeric: 'Geben Sie bitte nur Zahlenwerte in dieses Eingabefeld ein (z.B. "1", "1.1", "-1" oder "-1.1").', + digits: 'Benutzen Sie bitte nur Zahlen und Satzzeichen in diesem Eingabefeld (erlaubt ist z.B. eine Telefonnummer mit Bindestrichen und Punkten).', + alpha: 'Benutzen Sie bitte nur Buchstaben (a-z) in diesem Feld. Leerzeichen und andere Zeichen sind nicht erlaubt.', + alphanum: 'Benutzen Sie bitte nur Buchstaben (a-z) und Zahlen (0-9) in diesem Eingabefeld. Leerzeichen und andere Zeichen sind nicht erlaubt.', + dateSuchAs: 'Geben Sie bitte ein gültiges Datum ein. Wie zum Beispiel {date}', + dateInFormatMDY: 'Geben Sie bitte ein gültiges Datum ein. Wie zum Beispiel TT.MM.JJJJ (z.B. "31.12.1999")', + email: 'Geben Sie bitte eine gültige E-Mail Adresse ein. Wie zum Beispiel "maria@bernasconi.ch".', + url: 'Geben Sie bitte eine gültige URL ein. Wie zum Beispiel http://www.example.com.', + currencyDollar: 'Geben Sie bitte einen gültigen Betrag in Schweizer Franken ein. Wie zum Beispiel 100.00 CHF .', + oneRequired: 'Machen Sie für mindestens eines der Eingabefelder einen Eintrag.', + errorPrefix: 'Fehler: ', + warningPrefix: 'Warnung: ', + + // Form.Validator.Extras + noSpace: 'In diesem Eingabefeld darf kein Leerzeichen sein.', + reqChkByNode: 'Es wurden keine Elemente gewählt.', + requiredChk: 'Dieses Feld ist obligatorisch.', + reqChkByName: 'Bitte wählen Sie ein {label}.', + match: 'Dieses Eingabefeld muss mit dem Feld {matchName} übereinstimmen.', + startDate: 'Das Anfangsdatum', + endDate: 'Das Enddatum', + currentDate: 'Das aktuelle Datum', + afterDate: 'Das Datum sollte zur gleichen Zeit oder später sein {label}.', + beforeDate: 'Das Datum sollte zur gleichen Zeit oder früher sein {label}.', + startMonth: 'Wählen Sie bitte einen Anfangsmonat', + sameMonth: 'Diese zwei Datumsangaben müssen im selben Monat sein - Sie müssen eine von beiden verändern.', + creditcard: 'Die eingegebene Kreditkartennummer ist ungültig. Bitte überprüfen Sie diese und versuchen Sie es erneut. {length} Zahlen eingegeben.' + +}); + +/* +--- + +name: Locale.de-DE.Form.Validator + +description: Form Validator messages for German. + +license: MIT-style license + +authors: + - Frank Rossi + - Ulrich Petri + - Fabian Beiner + +requires: + - Locale + +provides: [Locale.de-DE.Form.Validator] + +... +*/ + +Locale.define('de-DE', 'FormValidator', { + + required: 'Dieses Eingabefeld muss ausgefüllt werden.', + minLength: 'Geben Sie bitte mindestens {minLength} Zeichen ein (Sie haben nur {length} Zeichen eingegeben).', + maxLength: 'Geben Sie bitte nicht mehr als {maxLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).', + integer: 'Geben Sie in diesem Eingabefeld bitte eine ganze Zahl ein. Dezimalzahlen (z.B. "1.25") sind nicht erlaubt.', + numeric: 'Geben Sie in diesem Eingabefeld bitte nur Zahlenwerte (z.B. "1", "1.1", "-1" oder "-1.1") ein.', + digits: 'Geben Sie in diesem Eingabefeld bitte nur Zahlen und Satzzeichen ein (z.B. eine Telefonnummer mit Bindestrichen und Punkten ist erlaubt).', + alpha: 'Geben Sie in diesem Eingabefeld bitte nur Buchstaben (a-z) ein. Leerzeichen und andere Zeichen sind nicht erlaubt.', + alphanum: 'Geben Sie in diesem Eingabefeld bitte nur Buchstaben (a-z) und Zahlen (0-9) ein. Leerzeichen oder andere Zeichen sind nicht erlaubt.', + dateSuchAs: 'Geben Sie bitte ein gültiges Datum ein (z.B. "{date}").', + dateInFormatMDY: 'Geben Sie bitte ein gültiges Datum im Format TT.MM.JJJJ ein (z.B. "31.12.1999").', + email: 'Geben Sie bitte eine gültige E-Mail-Adresse ein (z.B. "max@mustermann.de").', + url: 'Geben Sie bitte eine gültige URL ein (z.B. "http://www.example.com").', + currencyDollar: 'Geben Sie bitte einen gültigen Betrag in EURO ein (z.B. 100.00€).', + oneRequired: 'Bitte füllen Sie mindestens ein Eingabefeld aus.', + errorPrefix: 'Fehler: ', + warningPrefix: 'Warnung: ', + + // Form.Validator.Extras + noSpace: 'Es darf kein Leerzeichen in diesem Eingabefeld sein.', + reqChkByNode: 'Es wurden keine Elemente gewählt.', + requiredChk: 'Dieses Feld muss ausgefüllt werden.', + reqChkByName: 'Bitte wählen Sie ein {label}.', + match: 'Dieses Eingabefeld muss mit dem {matchName} Eingabefeld übereinstimmen.', + startDate: 'Das Anfangsdatum', + endDate: 'Das Enddatum', + currentDate: 'Das aktuelle Datum', + afterDate: 'Das Datum sollte zur gleichen Zeit oder später sein als {label}.', + beforeDate: 'Das Datum sollte zur gleichen Zeit oder früher sein als {label}.', + startMonth: 'Wählen Sie bitte einen Anfangsmonat', + sameMonth: 'Diese zwei Datumsangaben müssen im selben Monat sein - Sie müssen eines von beiden verändern.', + creditcard: 'Die eingegebene Kreditkartennummer ist ungültig. Bitte überprüfen Sie diese und versuchen Sie es erneut. {length} Zahlen eingegeben.' + +}); + +/* +--- + +name: Locale.de-DE.Number + +description: Number messages for German. + +license: MIT-style license + +authors: + - Christoph Pojer + +requires: + - Locale + - Locale.EU.Number + +provides: [Locale.de-DE.Number] + +... +*/ + +Locale.define('de-DE').inherit('EU', 'Number'); + +/* +--- + +name: Locale.el-GR.Date + +description: Date messages for Greek language. + +license: MIT-style license + +authors: + - Periklis Argiriadis + +requires: + - Locale + +provides: [Locale.el-GR.Date] + +... +*/ + +Locale.define('el-GR', 'Date', { + + months: ['Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος'], + months_abbr: ['Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μάι', 'Ιουν', 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'], + days: ['Κυριακή', 'Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο'], + days_abbr: ['Κυρ', 'Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%I:%M%p', + AM: 'πμ', + PM: 'μμ', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: function(dayOfMonth){ + // 1st, 2nd, 3rd, etc. + return (dayOfMonth > 3 && dayOfMonth < 21) ? 'ος' : ['ος'][Math.min(dayOfMonth % 10, 4)]; + }, + + lessThanMinuteAgo: 'λιγότερο από ένα λεπτό πριν', + minuteAgo: 'περίπου ένα λεπτό πριν', + minutesAgo: '{delta} λεπτά πριν', + hourAgo: 'περίπου μια ώρα πριν', + hoursAgo: 'περίπου {delta} ώρες πριν', + dayAgo: '1 ημέρα πριν', + daysAgo: '{delta} ημέρες πριν', + weekAgo: '1 εβδομάδα πριν', + weeksAgo: '{delta} εβδομάδες πριν', + monthAgo: '1 μήνα πριν', + monthsAgo: '{delta} μήνες πριν', + yearAgo: '1 χρόνο πριν', + yearsAgo: '{delta} χρόνια πριν', + + lessThanMinuteUntil: 'λιγότερο από λεπτό από τώρα', + minuteUntil: 'περίπου ένα λεπτό από τώρα', + minutesUntil: '{delta} λεπτά από τώρα', + hourUntil: 'περίπου μια ώρα από τώρα', + hoursUntil: 'περίπου {delta} ώρες από τώρα', + dayUntil: '1 ημέρα από τώρα', + daysUntil: '{delta} ημέρες από τώρα', + weekUntil: '1 εβδομάδα από τώρα', + weeksUntil: '{delta} εβδομάδες από τώρα', + monthUntil: '1 μήνας από τώρα', + monthsUntil: '{delta} μήνες από τώρα', + yearUntil: '1 χρόνος από τώρα', + yearsUntil: '{delta} χρόνια από τώρα' + +}); + +/* +--- + +name: Locale.el-GR.Form.Validator + +description: Form Validator messages for Greek language. + +license: MIT-style license + +authors: + - Dimitris Tsironis + +requires: + - Locale + +provides: [Locale.el-GR.Form.Validator] + +... +*/ + +Locale.define('el-GR', 'FormValidator', { + + required: 'Αυτό το πεδίο είναι απαραίτητο.', + length: 'Παρακαλούμε, εισάγετε {length} χαρακτήρες (έχετε ήδη εισάγει {elLength} χαρακτήρες).', + minLength: 'Παρακαλούμε, εισάγετε τουλάχιστον {minLength} χαρακτήρες (έχετε ήδη εισάγε {length} χαρακτήρες).', + maxlength: 'Παρακαλούμε, εισάγετε εώς {maxlength} χαρακτήρες (έχετε ήδη εισάγε {length} χαρακτήρες).', + integer: 'Παρακαλούμε, εισάγετε έναν ακέραιο αριθμό σε αυτό το πεδίο. Οι αριθμοί με δεκαδικά ψηφία (π.χ. 1.25) δεν επιτρέπονται.', + numeric: 'Παρακαλούμε, εισάγετε μόνο αριθμητικές τιμές σε αυτό το πεδίο (π.χ." 1 " ή " 1.1 " ή " -1 " ή " -1.1 " ).', + digits: 'Παρακαλούμε, χρησιμοποιήστε μόνο αριθμούς και σημεία στίξης σε αυτόν τον τομέα (π.χ. επιτρέπεται αριθμός τηλεφώνου με παύλες ή τελείες).', + alpha: 'Παρακαλούμε, χρησιμοποιήστε μόνο γράμματα (a-z) σε αυτό το πεδίο. Δεν επιτρέπονται κενά ή άλλοι χαρακτήρες.', + alphanum: 'Παρακαλούμε, χρησιμοποιήστε μόνο γράμματα (a-z) ή αριθμούς (0-9) σε αυτόν τον τομέα. Δεν επιτρέπονται κενά ή άλλοι χαρακτήρες.', + dateSuchAs: 'Παρακαλούμε, εισάγετε μια έγκυρη ημερομηνία, όπως {date}', + dateInFormatMDY: 'Παρακαλώ εισάγετε μια έγκυρη ημερομηνία, όπως ΜΜ/ΗΗ/ΕΕΕΕ (π.χ. "12/31/1999").', + email: 'Παρακαλούμε, εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου (π.χ. "fred@domain.com").', + url: 'Παρακαλούμε, εισάγετε μια έγκυρη URL διεύθυνση, όπως http://www.example.com', + currencyDollar: 'Παρακαλούμε, εισάγετε ένα έγκυρο ποσό σε δολλάρια (π.χ. $100.00).', + oneRequired: 'Παρακαλούμε, εισάγετε κάτι για τουλάχιστον ένα από αυτά τα πεδία.', + errorPrefix: 'Σφάλμα: ', + warningPrefix: 'Προσοχή: ', + + // Form.Validator.Extras + noSpace: 'Δεν επιτρέπονται τα κενά σε αυτό το πεδίο.', + reqChkByNode: 'Δεν έχει επιλεγεί κάποιο αντικείμενο', + requiredChk: 'Αυτό το πεδίο είναι απαραίτητο.', + reqChkByName: 'Παρακαλούμε, επιλέξτε μια ετικέτα {label}.', + match: 'Αυτό το πεδίο πρέπει να ταιριάζει με το πεδίο {matchName}.', + startDate: 'η ημερομηνία έναρξης', + endDate: 'η ημερομηνία λήξης', + currentDate: 'η τρέχουσα ημερομηνία', + afterDate: 'Η ημερομηνία πρέπει να είναι η ίδια ή μετά από την {label}.', + beforeDate: 'Η ημερομηνία πρέπει να είναι η ίδια ή πριν από την {label}.', + startMonth: 'Παρακαλώ επιλέξτε ένα μήνα αρχής.', + sameMonth: 'Αυτές οι δύο ημερομηνίες πρέπει να έχουν τον ίδιο μήνα - θα πρέπει να αλλάξετε ή το ένα ή το άλλο', + creditcard: 'Ο αριθμός της πιστωτικής κάρτας δεν είναι έγκυρος. Παρακαλούμε ελέγξτε τον αριθμό και δοκιμάστε ξανά. {length} μήκος ψηφίων.' + +}); + +/* +--- + +name: Locale.en-GB.Date + +description: Date messages for British English. + +license: MIT-style license + +authors: + - Aaron Newton + +requires: + - Locale + - Locale.en-US.Date + +provides: [Locale.en-GB.Date] + +... +*/ + +Locale.define('en-GB', 'Date', { + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M' + +}).inherit('en-US', 'Date'); + +/* +--- + +name: Locale.en-US.Number + +description: Number messages for US English. + +license: MIT-style license + +authors: + - Arian Stolwijk + +requires: + - Locale + +provides: [Locale.en-US.Number] + +... +*/ + +Locale.define('en-US', 'Number', { + + 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: Locale.es-ES.Date + +description: Date messages for Spanish. + +license: MIT-style license + +authors: + - Ãlfons Sanchez + +requires: + - Locale + +provides: [Locale.es-ES.Date] + +... +*/ + +Locale.define('es-ES', 'Date', { + + months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], + months_abbr: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'], + days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], + days_abbr: ['dom', 'lun', 'mar', 'mié', 'juv', 'vie', 'sáb'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'hace menos de un minuto', + minuteAgo: 'hace un minuto', + minutesAgo: 'hace {delta} minutos', + hourAgo: 'hace una hora', + hoursAgo: 'hace unas {delta} horas', + dayAgo: 'hace un día', + daysAgo: 'hace {delta} días', + weekAgo: 'hace una semana', + weeksAgo: 'hace unas {delta} semanas', + monthAgo: 'hace un mes', + monthsAgo: 'hace {delta} meses', + yearAgo: 'hace un año', + yearsAgo: 'hace {delta} años', + + lessThanMinuteUntil: 'menos de un minuto desde ahora', + minuteUntil: 'un minuto desde ahora', + minutesUntil: '{delta} minutos desde ahora', + hourUntil: 'una hora desde ahora', + hoursUntil: 'unas {delta} horas desde ahora', + dayUntil: 'un día desde ahora', + daysUntil: '{delta} días desde ahora', + weekUntil: 'una semana desde ahora', + weeksUntil: 'unas {delta} semanas desde ahora', + monthUntil: 'un mes desde ahora', + monthsUntil: '{delta} meses desde ahora', + yearUntil: 'un año desde ahora', + yearsUntil: '{delta} años desde ahora' + +}); + +/* +--- + +name: Locale.es-AR.Date + +description: Date messages for Spanish (Argentina). + +license: MIT-style license + +authors: + - Ãlfons Sanchez + - Diego Massanti + +requires: + - Locale + - Locale.es-ES.Date + +provides: [Locale.es-AR.Date] + +... +*/ + +Locale.define('es-AR').inherit('es-ES', 'Date'); + +/* +--- + +name: Locale.es-AR.Form.Validator + +description: Form Validator messages for Spanish (Argentina). + +license: MIT-style license + +authors: + - Diego Massanti + +requires: + - Locale + +provides: [Locale.es-AR.Form.Validator] + +... +*/ + +Locale.define('es-AR', 'FormValidator', { + + required: 'Este campo es obligatorio.', + minLength: 'Por favor ingrese al menos {minLength} caracteres (ha ingresado {length} caracteres).', + maxLength: 'Por favor no ingrese más de {maxLength} caracteres (ha ingresado {length} caracteres).', + integer: 'Por favor ingrese un número entero en este campo. Números con decimales (p.e. 1,25) no se permiten.', + numeric: 'Por favor ingrese solo valores numéricos en este campo (p.e. "1" o "1,1" o "-1" o "-1,1").', + digits: 'Por favor use sólo números y puntuación en este campo (por ejemplo, un número de teléfono con guiones y/o puntos no está permitido).', + alpha: 'Por favor use sólo letras (a-z) en este campo. No se permiten espacios ni otros caracteres.', + alphanum: 'Por favor, usa sólo letras (a-z) o números (0-9) en este campo. No se permiten espacios u otros caracteres.', + dateSuchAs: 'Por favor ingrese una fecha válida como {date}', + dateInFormatMDY: 'Por favor ingrese una fecha válida, utulizando el formato DD/MM/YYYY (p.e. "31/12/1999")', + email: 'Por favor, ingrese una dirección de e-mail válida. Por ejemplo, "fred@dominio.com".', + url: 'Por favor ingrese una URL válida como http://www.example.com.', + currencyDollar: 'Por favor ingrese una cantidad válida de pesos. Por ejemplo $100,00 .', + oneRequired: 'Por favor ingrese algo para por lo menos una de estas entradas.', + errorPrefix: 'Error: ', + warningPrefix: 'Advertencia: ', + + // Form.Validator.Extras + noSpace: 'No se permiten espacios en este campo.', + reqChkByNode: 'No hay elementos seleccionados.', + requiredChk: 'Este campo es obligatorio.', + reqChkByName: 'Por favor selecciona una {label}.', + match: 'Este campo necesita coincidir con el campo {matchName}', + startDate: 'la fecha de inicio', + endDate: 'la fecha de fin', + currentDate: 'la fecha actual', + afterDate: 'La fecha debe ser igual o posterior a {label}.', + beforeDate: 'La fecha debe ser igual o anterior a {label}.', + startMonth: 'Por favor selecciona un mes de origen', + sameMonth: 'Estas dos fechas deben estar en el mismo mes - debes cambiar una u otra.' + +}); + +/* +--- + +name: Locale.es-ES.Form.Validator + +description: Form Validator messages for Spanish. + +license: MIT-style license + +authors: + - Ãlfons Sanchez + +requires: + - Locale + +provides: [Locale.es-ES.Form.Validator] + +... +*/ + +Locale.define('es-ES', 'FormValidator', { + + required: 'Este campo es obligatorio.', + minLength: 'Por favor introduce al menos {minLength} caracteres (has introducido {length} caracteres).', + maxLength: 'Por favor introduce no más de {maxLength} caracteres (has introducido {length} caracteres).', + integer: 'Por favor introduce un número entero en este campo. Números con decimales (p.e. 1,25) no se permiten.', + numeric: 'Por favor introduce solo valores numéricos en este campo (p.e. "1" o "1,1" o "-1" o "-1,1").', + digits: 'Por favor usa solo números y puntuación en este campo (por ejemplo, un número de teléfono con guiones y puntos no esta permitido).', + alpha: 'Por favor usa letras solo (a-z) en este campo. No se admiten espacios ni otros caracteres.', + alphanum: 'Por favor, usa solo letras (a-z) o números (0-9) en este campo. No se admiten espacios ni otros caracteres.', + dateSuchAs: 'Por favor introduce una fecha válida como {date}', + dateInFormatMDY: 'Por favor introduce una fecha válida como DD/MM/YYYY (p.e. "31/12/1999")', + email: 'Por favor, introduce una dirección de email válida. Por ejemplo, "fred@domain.com".', + url: 'Por favor introduce una URL válida como http://www.example.com.', + currencyDollar: 'Por favor introduce una cantidad válida de €. Por ejemplo €100,00 .', + oneRequired: 'Por favor introduce algo para por lo menos una de estas entradas.', + errorPrefix: 'Error: ', + warningPrefix: 'Aviso: ', + + // Form.Validator.Extras + noSpace: 'No pueden haber espacios en esta entrada.', + reqChkByNode: 'No hay elementos seleccionados.', + requiredChk: 'Este campo es obligatorio.', + reqChkByName: 'Por favor selecciona una {label}.', + match: 'Este campo necesita coincidir con el campo {matchName}', + startDate: 'la fecha de inicio', + endDate: 'la fecha de fin', + currentDate: 'la fecha actual', + afterDate: 'La fecha debe ser igual o posterior a {label}.', + beforeDate: 'La fecha debe ser igual o anterior a {label}.', + startMonth: 'Por favor selecciona un mes de origen', + sameMonth: 'Estas dos fechas deben estar en el mismo mes - debes cambiar una u otra.' + +}); + +/* +--- + +name: Locale.es-VE.Date + +description: Date messages for Spanish (Venezuela). + +license: MIT-style license + +authors: + - Daniel Barreto + +requires: + - Locale + - Locale.es-ES.Date + +provides: [Locale.es-VE.Date] + +... +*/ + +Locale.define('es-VE').inherit('es-ES', 'Date'); + +/* +--- + +name: Locale.es-VE.Form.Validator + +description: Form Validator messages for Spanish (Venezuela). + +license: MIT-style license + +authors: + - Daniel Barreto + +requires: + - Locale + - Locale.es-ES.Form.Validator + +provides: [Locale.es-VE.Form.Validator] + +... +*/ + +Locale.define('es-VE', 'FormValidator', { + + digits: 'Por favor usa solo números y puntuación en este campo. Por ejemplo, un número de teléfono con guiones y puntos no esta permitido.', + alpha: 'Por favor usa solo letras (a-z) en este campo. No se admiten espacios ni otros caracteres.', + currencyDollar: 'Por favor introduce una cantidad válida de Bs. Por ejemplo Bs. 100,00 .', + oneRequired: 'Por favor introduce un valor para por lo menos una de estas entradas.', + + // Form.Validator.Extras + startDate: 'La fecha de inicio', + endDate: 'La fecha de fin', + currentDate: 'La fecha actual' + +}).inherit('es-ES', 'FormValidator'); + +/* +--- + +name: Locale.es-VE.Number + +description: Number messages for Spanish (Venezuela). + +license: MIT-style license + +authors: + - Daniel Barreto + +requires: + - Locale + +provides: [Locale.es-VE.Number] + +... +*/ + +Locale.define('es-VE', 'Number', { + + decimal: ',', + group: '.', +/* + decimals: 0, + precision: 0, +*/ + // Negative/Currency/percentage will mixin Number + negative: { + prefix: '-' + }, + + currency: { + decimals: 2, + prefix: 'Bs. ' + }, + + percentage: { + decimals: 2, + suffix: '%' + } + +}); + +/* +--- + +name: Locale.et-EE.Date + +description: Date messages for Estonian. + +license: MIT-style license + +authors: + - Kevin Valdek + +requires: + - Locale + +provides: [Locale.et-EE.Date] + +... +*/ + +Locale.define('et-EE', 'Date', { + + months: ['jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember'], + months_abbr: ['jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets'], + days: ['pühapäev', 'esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev'], + days_abbr: ['pühap', 'esmasp', 'teisip', 'kolmap', 'neljap', 'reede', 'laup'], + + // Culture's date order: MM.DD.YYYY + dateOrder: ['month', 'date', 'year'], + shortDate: '%m.%d.%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'vähem kui minut aega tagasi', + minuteAgo: 'umbes minut aega tagasi', + minutesAgo: '{delta} minutit tagasi', + hourAgo: 'umbes tund aega tagasi', + hoursAgo: 'umbes {delta} tundi tagasi', + dayAgo: '1 päev tagasi', + daysAgo: '{delta} päeva tagasi', + weekAgo: '1 nädal tagasi', + weeksAgo: '{delta} nädalat tagasi', + monthAgo: '1 kuu tagasi', + monthsAgo: '{delta} kuud tagasi', + yearAgo: '1 aasta tagasi', + yearsAgo: '{delta} aastat tagasi', + + lessThanMinuteUntil: 'vähem kui minuti aja pärast', + minuteUntil: 'umbes minuti aja pärast', + minutesUntil: '{delta} minuti pärast', + hourUntil: 'umbes tunni aja pärast', + hoursUntil: 'umbes {delta} tunni pärast', + dayUntil: '1 päeva pärast', + daysUntil: '{delta} päeva pärast', + weekUntil: '1 nädala pärast', + weeksUntil: '{delta} nädala pärast', + monthUntil: '1 kuu pärast', + monthsUntil: '{delta} kuu pärast', + yearUntil: '1 aasta pärast', + yearsUntil: '{delta} aasta pärast' + +}); + +/* +--- + +name: Locale.et-EE.Form.Validator + +description: Form Validator messages for Estonian. + +license: MIT-style license + +authors: + - Kevin Valdek + +requires: + - Locale + +provides: [Locale.et-EE.Form.Validator] + +... +*/ + +Locale.define('et-EE', 'FormValidator', { + + required: 'Väli peab olema täidetud.', + minLength: 'Palun sisestage vähemalt {minLength} tähte (te sisestasite {length} tähte).', + maxLength: 'Palun ärge sisestage rohkem kui {maxLength} tähte (te sisestasite {length} tähte).', + integer: 'Palun sisestage väljale täisarv. Kümnendarvud (näiteks 1.25) ei ole lubatud.', + numeric: 'Palun sisestage ainult numbreid väljale (näiteks "1", "1.1", "-1" või "-1.1").', + digits: 'Palun kasutage ainult numbreid ja kirjavahemärke (telefoninumbri sisestamisel on lubatud kasutada kriipse ja punkte).', + alpha: 'Palun kasutage ainult tähti (a-z). Tühikud ja teised sümbolid on keelatud.', + alphanum: 'Palun kasutage ainult tähti (a-z) või numbreid (0-9). Tühikud ja teised sümbolid on keelatud.', + dateSuchAs: 'Palun sisestage kehtiv kuupäev kujul {date}', + dateInFormatMDY: 'Palun sisestage kehtiv kuupäev kujul MM.DD.YYYY (näiteks: "12.31.1999").', + email: 'Palun sisestage kehtiv e-maili aadress (näiteks: "fred@domain.com").', + url: 'Palun sisestage kehtiv URL (näiteks: http://www.example.com).', + currencyDollar: 'Palun sisestage kehtiv $ summa (näiteks: $100.00).', + oneRequired: 'Palun sisestage midagi vähemalt ühele antud väljadest.', + errorPrefix: 'Viga: ', + warningPrefix: 'Hoiatus: ', + + // Form.Validator.Extras + noSpace: 'Väli ei tohi sisaldada tühikuid.', + reqChkByNode: 'Ükski väljadest pole valitud.', + requiredChk: 'Välja täitmine on vajalik.', + reqChkByName: 'Palun valige üks {label}.', + match: 'Väli peab sobima {matchName} väljaga', + startDate: 'algkuupäev', + endDate: 'lõppkuupäev', + currentDate: 'praegune kuupäev', + afterDate: 'Kuupäev peab olema võrdne või pärast {label}.', + beforeDate: 'Kuupäev peab olema võrdne või enne {label}.', + startMonth: 'Palun valige algkuupäev.', + sameMonth: 'Antud kaks kuupäeva peavad olema samas kuus - peate muutma ühte kuupäeva.' + +}); + +/* +--- + +name: Locale.fa.Date + +description: Date messages for Persian. + +license: MIT-style license + +authors: + - Amir Hossein Hodjaty Pour + +requires: + - Locale + +provides: [Locale.fa.Date] + +... +*/ + +Locale.define('fa', 'Date', { + + months: ['ژانویه', 'فوریه', 'مارس', 'آپریل', 'مه', 'ژوئن', 'ژوئیه', 'آگوست', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'], + months_abbr: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], + days: ['یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'], + days_abbr: ['ي', 'د', 'س', 'چ', 'پ', 'ج', 'ش'], + + // Culture's date order: MM/DD/YYYY + dateOrder: ['month', 'date', 'year'], + shortDate: '%m/%d/%Y', + shortTime: '%I:%M%p', + AM: 'ق.ظ', + PM: 'ب.ظ', + + // Date.Extras + ordinal: 'ام', + + lessThanMinuteAgo: 'کمتر از یک دقیقه پیش', + minuteAgo: 'حدود یک دقیقه پیش', + minutesAgo: '{delta} دقیقه پیش', + hourAgo: 'حدود یک ساعت پیش', + hoursAgo: 'حدود {delta} ساعت پیش', + dayAgo: '1 روز پیش', + daysAgo: '{delta} روز پیش', + weekAgo: '1 هفته پیش', + weeksAgo: '{delta} هفته پیش', + monthAgo: '1 ماه پیش', + monthsAgo: '{delta} ماه پیش', + yearAgo: '1 سال پیش', + yearsAgo: '{delta} سال پیش', + + lessThanMinuteUntil: 'کمتر از یک دقیقه از حالا', + minuteUntil: 'حدود یک دقیقه از حالا', + minutesUntil: '{delta} دقیقه از حالا', + hourUntil: 'حدود یک ساعت از حالا', + hoursUntil: 'حدود {delta} ساعت از حالا', + dayUntil: '1 روز از حالا', + daysUntil: '{delta} روز از حالا', + weekUntil: '1 هفته از حالا', + weeksUntil: '{delta} هفته از حالا', + monthUntil: '1 ماه از حالا', + monthsUntil: '{delta} ماه از حالا', + yearUntil: '1 سال از حالا', + yearsUntil: '{delta} سال از حالا' + +}); + +/* +--- + +name: Locale.fa.Form.Validator + +description: Form Validator messages for Persian. + +license: MIT-style license + +authors: + - Amir Hossein Hodjaty Pour + +requires: + - Locale + +provides: [Locale.fa.Form.Validator] + +... +*/ + +Locale.define('fa', 'FormValidator', { + + required: 'این فیلد الزامی است.', + minLength: 'شما باید حداقل {minLength} حرف وارد کنید ({length} حرف وارد کرده اید).', + maxLength: 'لطفا حداکثر {maxLength} حرف وارد کنید (شما {length} حرف وارد کرده اید).', + integer: 'لطفا از عدد صحیح استفاده کنید. اعداد اعشاری (مانند 1.25) مجاز نیستند.', + numeric: 'لطفا فقط داده عددی وارد کنید (مانند "1" یا "1.1" یا "1-" یا "1.1-").', + digits: 'لطفا فقط از اعداد و علامتها در این فیلد استفاده کنید (برای مثال شماره تلفن با خط تیره و نقطه قابل قبول است).', + alpha: 'لطفا فقط از حروف الفباء برای این بخش استفاده کنید. کاراکترهای دیگر و فاصله مجاز نیستند.', + alphanum: 'لطفا فقط از حروف الفباء و اعداد در این بخش استفاده کنید. کاراکترهای دیگر و فاصله مجاز نیستند.', + dateSuchAs: 'لطفا یک تاریخ معتبر مانند {date} وارد کنید.', + dateInFormatMDY: 'لطفا یک تاریخ معتبر به شکل MM/DD/YYYY وارد کنید (مانند "12/31/1999").', + email: 'لطفا یک آدرس ایمیل معتبر وارد کنید. برای مثال "fred@domain.com".', + url: 'لطفا یک URL معتبر مانند http://www.example.com وارد کنید.', + currencyDollar: 'لطفا یک محدوده معتبر برای این بخش وارد کنید مانند 100.00$ .', + oneRequired: 'لطفا حداقل یکی از فیلدها را پر کنید.', + errorPrefix: 'خطا: ', + warningPrefix: 'هشدار: ', + + // Form.Validator.Extras + noSpace: 'استفاده از فاصله در این بخش مجاز نیست.', + reqChkByNode: 'موردی انتخاب نشده است.', + requiredChk: 'این فیلد الزامی است.', + reqChkByName: 'لطفا یک {label} را انتخاب کنید.', + match: 'این فیلد باید با فیلد {matchName} مطابقت داشته باشد.', + startDate: 'تاریخ شروع', + endDate: 'تاریخ پایان', + currentDate: 'تاریخ کنونی', + afterDate: 'تاریخ میبایست برابر یا بعد از {label} باشد', + beforeDate: 'تاریخ میبایست برابر یا قبل از {label} باشد', + startMonth: 'لطفا ماه شروع را انتخاب کنید', + sameMonth: 'این دو تاریخ باید در یک ماه باشند - شما باید یکی یا هر دو را تغییر دهید.', + creditcard: 'شماره کارت اعتباری که وارد کرده اید معتبر نیست. لطفا شماره را بررسی کنید و مجددا تلاش کنید. {length} رقم وارد شده است.' + +}); + +/* +--- + +name: Locale.fi-FI.Date + +description: Date messages for Finnish. + +license: MIT-style license + +authors: + - ksel + +requires: + - Locale + +provides: [Locale.fi-FI.Date] + +... +*/ + +Locale.define('fi-FI', 'Date', { + + // NOTE: months and days are not capitalized in finnish + months: ['tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'heinäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu'], + + // these abbreviations are really not much used in finnish because they obviously won't abbreviate very much. ;) + // NOTE: sometimes one can see forms such as "tammi", "helmi", etc. but that is not proper finnish. + months_abbr: ['tammik.', 'helmik.', 'maalisk.', 'huhtik.', 'toukok.', 'kesäk.', 'heinäk.', 'elok.', 'syysk.', 'lokak.', 'marrask.', 'jouluk.'], + + days: ['sunnuntai', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai'], + days_abbr: ['su', 'ma', 'ti', 'ke', 'to', 'pe', 'la'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'vajaa minuutti sitten', + minuteAgo: 'noin minuutti sitten', + minutesAgo: '{delta} minuuttia sitten', + hourAgo: 'noin tunti sitten', + hoursAgo: 'noin {delta} tuntia sitten', + dayAgo: 'päivä sitten', + daysAgo: '{delta} päivää sitten', + weekAgo: 'viikko sitten', + weeksAgo: '{delta} viikkoa sitten', + monthAgo: 'kuukausi sitten', + monthsAgo: '{delta} kuukautta sitten', + yearAgo: 'vuosi sitten', + yearsAgo: '{delta} vuotta sitten', + + lessThanMinuteUntil: 'vajaan minuutin kuluttua', + minuteUntil: 'noin minuutin kuluttua', + minutesUntil: '{delta} minuutin kuluttua', + hourUntil: 'noin tunnin kuluttua', + hoursUntil: 'noin {delta} tunnin kuluttua', + dayUntil: 'päivän kuluttua', + daysUntil: '{delta} päivän kuluttua', + weekUntil: 'viikon kuluttua', + weeksUntil: '{delta} viikon kuluttua', + monthUntil: 'kuukauden kuluttua', + monthsUntil: '{delta} kuukauden kuluttua', + yearUntil: 'vuoden kuluttua', + yearsUntil: '{delta} vuoden kuluttua' + +}); + +/* +--- + +name: Locale.fi-FI.Form.Validator + +description: Form Validator messages for Finnish. + +license: MIT-style license + +authors: + - ksel + +requires: + - Locale + +provides: [Locale.fi-FI.Form.Validator] + +... +*/ + +Locale.define('fi-FI', 'FormValidator', { + + required: 'Tämä kenttä on pakollinen.', + minLength: 'Ole hyvä ja anna vähintään {minLength} merkkiä (annoit {length} merkkiä).', + maxLength: 'Älä anna enempää kuin {maxLength} merkkiä (annoit {length} merkkiä).', + integer: 'Ole hyvä ja anna kokonaisluku. Luvut, joissa on desimaaleja (esim. 1.25) eivät ole sallittuja.', + numeric: 'Anna tähän kenttään lukuarvo (kuten "1" tai "1.1" tai "-1" tai "-1.1").', + digits: 'Käytä pelkästään numeroita ja välimerkkejä tässä kentässä (syötteet, kuten esim. puhelinnumero, jossa on väliviivoja, pilkkuja tai pisteitä, kelpaa).', + alpha: 'Anna tähän kenttään vain kirjaimia (a-z). Välilyönnit tai muut merkit eivät ole sallittuja.', + alphanum: 'Anna tähän kenttään vain kirjaimia (a-z) tai numeroita (0-9). Välilyönnit tai muut merkit eivät ole sallittuja.', + dateSuchAs: 'Ole hyvä ja anna kelvollinen päivmäärä, kuten esimerkiksi {date}', + dateInFormatMDY: 'Ole hyvä ja anna kelvollinen päivämäärä muodossa pp/kk/vvvv (kuten "12/31/1999")', + email: 'Ole hyvä ja anna kelvollinen sähköpostiosoite (kuten esimerkiksi "matti@meikalainen.com").', + url: 'Ole hyvä ja anna kelvollinen URL, kuten esimerkiksi http://www.example.com.', + currencyDollar: 'Ole hyvä ja anna kelvollinen eurosumma (kuten esimerkiksi 100,00 EUR) .', + oneRequired: 'Ole hyvä ja syötä jotakin ainakin johonkin näistä kentistä.', + errorPrefix: 'Virhe: ', + warningPrefix: 'Varoitus: ', + + // Form.Validator.Extras + noSpace: 'Tässä syötteessä ei voi olla välilyöntejä', + reqChkByNode: 'Ei valintoja.', + requiredChk: 'Tämä kenttä on pakollinen.', + reqChkByName: 'Ole hyvä ja valitse {label}.', + match: 'Tämän kentän tulee vastata kenttää {matchName}', + startDate: 'alkupäivämäärä', + endDate: 'loppupäivämäärä', + currentDate: 'nykyinen päivämäärä', + afterDate: 'Päivämäärän tulisi olla sama tai myöhäisempi ajankohta kuin {label}.', + beforeDate: 'Päivämäärän tulisi olla sama tai aikaisempi ajankohta kuin {label}.', + startMonth: 'Ole hyvä ja valitse aloituskuukausi', + sameMonth: 'Näiden kahden päivämäärän tulee olla saman kuun sisällä -- sinun pitää muuttaa jompaa kumpaa.', + creditcard: 'Annettu luottokortin numero ei kelpaa. Ole hyvä ja tarkista numero sekä yritä uudelleen. {length} numeroa syötetty.' + +}); + +/* +--- + +name: Locale.fi-FI.Number + +description: Finnish number messages + +license: MIT-style license + +authors: + - ksel + +requires: + - Locale + - Locale.EU.Number + +provides: [Locale.fi-FI.Number] + +... +*/ + +Locale.define('fi-FI', 'Number', { + + group: ' ' // grouped by space + +}).inherit('EU', 'Number'); + +/* +--- + +name: Locale.fr-FR.Date + +description: Date messages for French. + +license: MIT-style license + +authors: + - Nicolas Sorosac + - Antoine Abt + +requires: + - Locale + +provides: [Locale.fr-FR.Date] + +... +*/ + +Locale.define('fr-FR', 'Date', { + + months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'], + months_abbr: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'], + days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'], + days_abbr: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: function(dayOfMonth){ + return (dayOfMonth > 1) ? '' : 'er'; + }, + + lessThanMinuteAgo: "il y a moins d'une minute", + minuteAgo: 'il y a une minute', + minutesAgo: 'il y a {delta} minutes', + hourAgo: 'il y a une heure', + hoursAgo: 'il y a {delta} heures', + dayAgo: 'il y a un jour', + daysAgo: 'il y a {delta} jours', + weekAgo: 'il y a une semaine', + weeksAgo: 'il y a {delta} semaines', + monthAgo: 'il y a 1 mois', + monthsAgo: 'il y a {delta} mois', + yearthAgo: 'il y a 1 an', + yearsAgo: 'il y a {delta} ans', + + lessThanMinuteUntil: "dans moins d'une minute", + minuteUntil: 'dans une minute', + minutesUntil: 'dans {delta} minutes', + hourUntil: 'dans une heure', + hoursUntil: 'dans {delta} heures', + dayUntil: 'dans un jour', + daysUntil: 'dans {delta} jours', + weekUntil: 'dans 1 semaine', + weeksUntil: 'dans {delta} semaines', + monthUntil: 'dans 1 mois', + monthsUntil: 'dans {delta} mois', + yearUntil: 'dans 1 an', + yearsUntil: 'dans {delta} ans' + +}); + +/* +--- + +name: Locale.fr-FR.Form.Validator + +description: Form Validator messages for French. + +license: MIT-style license + +authors: + - Miquel Hudin + - Nicolas Sorosac + +requires: + - Locale + +provides: [Locale.fr-FR.Form.Validator] + +... +*/ + +Locale.define('fr-FR', 'FormValidator', { + + required: 'Ce champ est obligatoire.', + length: 'Veuillez saisir {length} caractère(s) (vous avez saisi {elLength} caractère(s)', + minLength: 'Veuillez saisir un minimum de {minLength} caractère(s) (vous avez saisi {length} caractère(s)).', + maxLength: 'Veuillez saisir un maximum de {maxLength} caractère(s) (vous avez saisi {length} caractère(s)).', + integer: 'Veuillez saisir un nombre entier dans ce champ. Les nombres décimaux (ex : "1,25") ne sont pas autorisés.', + numeric: 'Veuillez saisir uniquement des chiffres dans ce champ (ex : "1" ou "1,1" ou "-1" ou "-1,1").', + digits: "Veuillez saisir uniquement des chiffres et des signes de ponctuation dans ce champ (ex : un numéro de téléphone avec des traits d'union est autorisé).", + alpha: 'Veuillez saisir uniquement des lettres (a-z) dans ce champ. Les espaces ou autres caractères ne sont pas autorisés.', + alphanum: 'Veuillez saisir uniquement des lettres (a-z) ou des chiffres (0-9) dans ce champ. Les espaces ou autres caractères ne sont pas autorisés.', + dateSuchAs: 'Veuillez saisir une date correcte comme {date}', + dateInFormatMDY: 'Veuillez saisir une date correcte, au format JJ/MM/AAAA (ex : "31/11/1999").', + email: 'Veuillez saisir une adresse de courrier électronique. Par exemple "fred@domaine.com".', + url: 'Veuillez saisir une URL, comme http://www.exemple.com.', + currencyDollar: 'Veuillez saisir une quantité correcte. Par exemple 100,00€.', + oneRequired: 'Veuillez sélectionner au moins une de ces options.', + errorPrefix: 'Erreur : ', + warningPrefix: 'Attention : ', + + // Form.Validator.Extras + noSpace: "Ce champ n'accepte pas les espaces.", + reqChkByNode: "Aucun élément n'est sélectionné.", + requiredChk: 'Ce champ est obligatoire.', + reqChkByName: 'Veuillez sélectionner un(e) {label}.', + match: 'Ce champ doit correspondre avec le champ {matchName}.', + startDate: 'date de début', + endDate: 'date de fin', + currentDate: 'date actuelle', + afterDate: 'La date doit être identique ou postérieure à {label}.', + beforeDate: 'La date doit être identique ou antérieure à {label}.', + startMonth: 'Veuillez sélectionner un mois de début.', + sameMonth: 'Ces deux dates doivent être dans le même mois - vous devez en modifier une.', + creditcard: 'Le numéro de carte de crédit est invalide. Merci de vérifier le numéro et de réessayer. Vous avez entré {length} chiffre(s).' + +}); + +/* +--- + +name: Locale.fr-FR.Number + +description: Number messages for French. + +license: MIT-style license + +authors: + - Arian Stolwijk + - sv1l + +requires: + - Locale + - Locale.EU.Number + +provides: [Locale.fr-FR.Number] + +... +*/ + +Locale.define('fr-FR', 'Number', { + + group: ' ' // In fr-FR localization, group character is a blank space + +}).inherit('EU', 'Number'); + +/* +--- + +name: Locale.he-IL.Date + +description: Date messages for Hebrew. + +license: MIT-style license + +authors: + - Elad Ossadon + +requires: + - Locale + +provides: [Locale.he-IL.Date] + +... +*/ + +Locale.define('he-IL', 'Date', { + + months: ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'], + months_abbr: ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'], + days: ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'], + days_abbr: ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'], + + // Culture's date order: MM/DD/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 0, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'לפני פחות מדקה', + minuteAgo: 'לפני כדקה', + minutesAgo: 'לפני {delta} דקות', + hourAgo: 'לפני כשעה', + hoursAgo: 'לפני {delta} שעות', + dayAgo: 'לפני יום', + daysAgo: 'לפני {delta} ימים', + weekAgo: 'לפני שבוע', + weeksAgo: 'לפני {delta} שבועות', + monthAgo: 'לפני חודש', + monthsAgo: 'לפני {delta} חודשים', + yearAgo: 'לפני שנה', + yearsAgo: 'לפני {delta} שנים', + + lessThanMinuteUntil: 'בעוד פחות מדקה', + minuteUntil: 'בעוד כדקה', + minutesUntil: 'בעוד {delta} דקות', + hourUntil: 'בעוד כשעה', + hoursUntil: 'בעוד {delta} שעות', + dayUntil: 'בעוד יום', + daysUntil: 'בעוד {delta} ימים', + weekUntil: 'בעוד שבוע', + weeksUntil: 'בעוד {delta} שבועות', + monthUntil: 'בעוד חודש', + monthsUntil: 'בעוד {delta} חודשים', + yearUntil: 'בעוד שנה', + yearsUntil: 'בעוד {delta} שנים' + +}); + +/* +--- + +name: Locale.he-IL.Form.Validator + +description: Form Validator messages for Hebrew. + +license: MIT-style license + +authors: + - Elad Ossadon + +requires: + - Locale + +provides: [Locale.he-IL.Form.Validator] + +... +*/ + +Locale.define('he-IL', 'FormValidator', { + + required: 'נא למלא שדה זה.', + minLength: 'נא להזין לפחות {minLength} תווים (הזנת {length} תווים).', + maxLength: 'נא להזין עד {maxLength} תווים (הזנת {length} תווים).', + integer: 'נא להזין מספר שלם לשדה זה. מספרים עשרוניים (כמו 1.25) אינם חוקיים.', + numeric: 'נא להזין ערך מספרי בלבד בשדה זה (כמו "1", "1.1", "-1" או "-1.1").', + digits: 'נא להזין רק ספרות וסימני הפרדה בשדה זה (למשל, מספר טלפון עם מקפים או נקודות הוא חוקי).', + alpha: 'נא להזין רק אותיות באנגלית (a-z) בשדה זה. רווחים או תווים אחרים אינם חוקיים.', + alphanum: 'נא להזין רק אותריות באנגלית (a-z) או ספרות (0-9) בשדה זה. אווחרים או תווים אחרים אינם חוקיים.', + dateSuchAs: 'נא להזין תאריך חוקי, כמו {date}', + dateInFormatMDY: 'נא להזין תאריך חוקי בפורמט MM/DD/YYYY (כמו "12/31/1999")', + email: 'נא להזין כתובת אימייל חוקית. לדוגמה: "fred@domain.com".', + url: 'נא להזין כתובת אתר חוקית, כמו http://www.example.com.', + currencyDollar: 'נא להזין סכום דולרי חוקי. לדוגמה $100.00.', + oneRequired: 'נא לבחור לפחות בשדה אחד.', + errorPrefix: 'שגיאה: ', + warningPrefix: 'אזהרה: ', + + // Form.Validator.Extras + noSpace: 'אין להזין רווחים בשדה זה.', + reqChkByNode: 'נא לבחור אחת מהאפשרויות.', + requiredChk: 'שדה זה נדרש.', + reqChkByName: 'נא לבחור {label}.', + match: 'שדה זה צריך להתאים לשדה {matchName}', + startDate: 'תאריך ההתחלה', + endDate: 'תאריך הסיום', + currentDate: 'התאריך הנוכחי', + afterDate: 'התאריך צריך להיות זהה או אחרי {label}.', + beforeDate: 'התאריך צריך להיות זהה או לפני {label}.', + startMonth: 'נא לבחור חודש התחלה', + sameMonth: 'שני תאריכים אלה צריכים להיות באותו חודש - נא לשנות אחד התאריכים.', + creditcard: 'מספר כרטיס האשראי שהוזן אינו חוקי. נא לבדוק שנית. הוזנו {length} ספרות.' + +}); + +/* +--- + +name: Locale.he-IL.Number + +description: Number messages for Hebrew. + +license: MIT-style license + +authors: + - Elad Ossadon + +requires: + - Locale + +provides: [Locale.he-IL.Number] + +... +*/ + +Locale.define('he-IL', 'Number', { + + decimal: '.', + group: ',', + + currency: { + suffix: ' ₪' + } + +}); + +/* +--- + +name: Locale.hu-HU.Date + +description: Date messages for Hungarian. + +license: MIT-style license + +authors: + - Zsolt Szegheő + +requires: + - Locale + +provides: [Locale.hu-HU.Date] + +... +*/ + +Locale.define('hu-HU', 'Date', { + + months: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], + months_abbr: ['jan.', 'febr.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'], + days: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], + days_abbr: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], + + // Culture's date order: YYYY.MM.DD. + dateOrder: ['year', 'month', 'date'], + shortDate: '%Y.%m.%d.', + shortTime: '%I:%M', + AM: 'de.', + PM: 'du.', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'alig egy perce', + minuteAgo: 'egy perce', + minutesAgo: '{delta} perce', + hourAgo: 'egy órája', + hoursAgo: '{delta} órája', + dayAgo: '1 napja', + daysAgo: '{delta} napja', + weekAgo: '1 hete', + weeksAgo: '{delta} hete', + monthAgo: '1 hónapja', + monthsAgo: '{delta} hónapja', + yearAgo: '1 éve', + yearsAgo: '{delta} éve', + + lessThanMinuteUntil: 'alig egy perc múlva', + minuteUntil: 'egy perc múlva', + minutesUntil: '{delta} perc múlva', + hourUntil: 'egy óra múlva', + hoursUntil: '{delta} óra múlva', + dayUntil: '1 nap múlva', + daysUntil: '{delta} nap múlva', + weekUntil: '1 hét múlva', + weeksUntil: '{delta} hét múlva', + monthUntil: '1 hónap múlva', + monthsUntil: '{delta} hónap múlva', + yearUntil: '1 év múlva', + yearsUntil: '{delta} év múlva' + +}); + +/* +--- + +name: Locale.hu-HU.Form.Validator + +description: Form Validator messages for Hungarian. + +license: MIT-style license + +authors: + - Zsolt Szegheő + +requires: + - Locale + +provides: [Locale.hu-HU.Form.Validator] + +... +*/ + +Locale.define('hu-HU', 'FormValidator', { + + required: 'A mező kitöltése kötelező.', + minLength: 'Legalább {minLength} karakter megadása szükséges (megadva {length} karakter).', + maxLength: 'Legfeljebb {maxLength} karakter megadása lehetséges (megadva {length} karakter).', + integer: 'Egész szám megadása szükséges. A tizedesjegyek (pl. 1.25) nem engedélyezettek.', + numeric: 'Szám megadása szükséges (pl. "1" vagy "1.1" vagy "-1" vagy "-1.1").', + digits: 'Csak számok és írásjelek megadása lehetséges (pl. telefonszám kötőjelek és/vagy perjelekkel).', + alpha: 'Csak betűk (a-z) megadása lehetséges. Szóköz és egyéb karakterek nem engedélyezettek.', + alphanum: 'Csak betűk (a-z) vagy számok (0-9) megadása lehetséges. Szóköz és egyéb karakterek nem engedélyezettek.', + dateSuchAs: 'Valós dátum megadása szükséges (pl. {date}).', + dateInFormatMDY: 'Valós dátum megadása szükséges ÉÉÉÉ.HH.NN. formában. (pl. "1999.12.31.")', + email: 'Valós e-mail cím megadása szükséges (pl. "fred@domain.hu").', + url: 'Valós URL megadása szükséges (pl. http://www.example.com).', + currencyDollar: 'Valós pénzösszeg megadása szükséges (pl. 100.00 Ft.).', + oneRequired: 'Az alábbi mezők legalább egyikének kitöltése kötelező.', + errorPrefix: 'Hiba: ', + warningPrefix: 'Figyelem: ', + + // Form.Validator.Extras + noSpace: 'A mező nem tartalmazhat szóközöket.', + reqChkByNode: 'Nincs egyetlen kijelölt elem sem.', + requiredChk: 'A mező kitöltése kötelező.', + reqChkByName: 'Egy {label} kiválasztása szükséges.', + match: 'A mezőnek egyeznie kell a(z) {matchName} mezővel.', + startDate: 'a kezdet dátuma', + endDate: 'a vég dátuma', + currentDate: 'jelenlegi dátum', + afterDate: 'A dátum nem lehet kisebb, mint {label}.', + beforeDate: 'A dátum nem lehet nagyobb, mint {label}.', + startMonth: 'Kezdeti hónap megadása szükséges.', + sameMonth: 'A két dátumnak ugyanazon hónapban kell lennie.', + creditcard: 'A megadott bankkártyaszám nem valódi (megadva {length} számjegy).' + +}); + +/* +--- + +name: Locale.it-IT.Date + +description: Date messages for Italian. + +license: MIT-style license. + +authors: + - Andrea Novero + - Valerio Proietti + +requires: + - Locale + +provides: [Locale.it-IT.Date] + +... +*/ + +Locale.define('it-IT', 'Date', { + + months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'], + months_abbr: ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'], + days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'], + days_abbr: ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H.%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: 'º', + + lessThanMinuteAgo: 'meno di un minuto fa', + minuteAgo: 'circa un minuto fa', + minutesAgo: 'circa {delta} minuti fa', + hourAgo: "circa un'ora fa", + hoursAgo: 'circa {delta} ore fa', + dayAgo: 'circa 1 giorno fa', + daysAgo: 'circa {delta} giorni fa', + weekAgo: 'una settimana fa', + weeksAgo: '{delta} settimane fa', + monthAgo: 'un mese fa', + monthsAgo: '{delta} mesi fa', + yearAgo: 'un anno fa', + yearsAgo: '{delta} anni fa', + + lessThanMinuteUntil: 'tra meno di un minuto', + minuteUntil: 'tra circa un minuto', + minutesUntil: 'tra circa {delta} minuti', + hourUntil: "tra circa un'ora", + hoursUntil: 'tra circa {delta} ore', + dayUntil: 'tra circa un giorno', + daysUntil: 'tra circa {delta} giorni', + weekUntil: 'tra una settimana', + weeksUntil: 'tra {delta} settimane', + monthUntil: 'tra un mese', + monthsUntil: 'tra {delta} mesi', + yearUntil: 'tra un anno', + yearsUntil: 'tra {delta} anni' + +}); + +/* +--- + +name: Locale.it-IT.Form.Validator + +description: Form Validator messages for Italian. + +license: MIT-style license + +authors: + - Leonardo Laureti + - Andrea Novero + +requires: + - Locale + +provides: [Locale.it-IT.Form.Validator] + +... +*/ + +Locale.define('it-IT', 'FormValidator', { + + required: 'Il campo è obbligatorio.', + minLength: 'Inserire almeno {minLength} caratteri (ne sono stati inseriti {length}).', + maxLength: 'Inserire al massimo {maxLength} caratteri (ne sono stati inseriti {length}).', + integer: 'Inserire un numero intero. Non sono consentiti decimali (es.: 1.25).', + numeric: 'Inserire solo valori numerici (es.: "1" oppure "1.1" oppure "-1" oppure "-1.1").', + digits: 'Inserire solo numeri e caratteri di punteggiatura. Per esempio è consentito un numero telefonico con trattini o punti.', + alpha: 'Inserire solo lettere (a-z). Non sono consentiti spazi o altri caratteri.', + alphanum: 'Inserire solo lettere (a-z) o numeri (0-9). Non sono consentiti spazi o altri caratteri.', + dateSuchAs: 'Inserire una data valida del tipo {date}', + dateInFormatMDY: 'Inserire una data valida nel formato MM/GG/AAAA (es.: "12/31/1999")', + email: 'Inserire un indirizzo email valido. Per esempio "nome@dominio.com".', + url: 'Inserire un indirizzo valido. Per esempio "http://www.example.com".', + currencyDollar: 'Inserire un importo valido. Per esempio "$100.00".', + oneRequired: 'Completare almeno uno dei campi richiesti.', + errorPrefix: 'Errore: ', + warningPrefix: 'Attenzione: ', + + // Form.Validator.Extras + noSpace: 'Non sono consentiti spazi.', + reqChkByNode: 'Nessuna voce selezionata.', + requiredChk: 'Il campo è obbligatorio.', + reqChkByName: 'Selezionare un(a) {label}.', + match: 'Il valore deve corrispondere al campo {matchName}', + startDate: "data d'inizio", + endDate: 'data di fine', + currentDate: 'data attuale', + afterDate: 'La data deve corrispondere o essere successiva al {label}.', + beforeDate: 'La data deve corrispondere o essere precedente al {label}.', + startMonth: "Selezionare un mese d'inizio", + sameMonth: 'Le due date devono essere dello stesso mese - occorre modificarne una.' + +}); + +/* +--- + +name: Locale.ja-JP.Date + +description: Date messages for Japanese. + +license: MIT-style license + +authors: + - Noritaka Horio + +requires: + - Locale + +provides: [Locale.ja-JP.Date] + +... +*/ + +Locale.define('ja-JP', 'Date', { + + months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], + months_abbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], + days: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'], + days_abbr: ['日', '月', '火', '水', '木', '金', '土'], + + // Culture's date order: YYYY/MM/DD + dateOrder: ['year', 'month', 'date'], + shortDate: '%Y/%m/%d', + shortTime: '%H:%M', + AM: '午前', + PM: '午後', + firstDayOfWeek: 0, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: '1分以内前', + minuteAgo: '約1分前', + minutesAgo: '約{delta}分前', + hourAgo: '約1時間前', + hoursAgo: '約{delta}時間前', + dayAgo: '1日前', + daysAgo: '{delta}日前', + weekAgo: '1週間前', + weeksAgo: '{delta}週間前', + monthAgo: '1ヶ月前', + monthsAgo: '{delta}ヶ月前', + yearAgo: '1年前', + yearsAgo: '{delta}年前', + + lessThanMinuteUntil: '今から約1分以内', + minuteUntil: '今から約1分', + minutesUntil: '今から約{delta}分', + hourUntil: '今から約1時間', + hoursUntil: '今から約{delta}時間', + dayUntil: '今から1日間', + daysUntil: '今から{delta}日間', + weekUntil: '今から1週間', + weeksUntil: '今から{delta}週間', + monthUntil: '今から1ヶ月', + monthsUntil: '今から{delta}ヶ月', + yearUntil: '今から1年', + yearsUntil: '今から{delta}年' + +}); + +/* +--- + +name: Locale.ja-JP.Form.Validator + +description: Form Validator messages for Japanese. + +license: MIT-style license + +authors: + - Noritaka Horio + +requires: + - Locale + +provides: [Locale.ja-JP.Form.Validator] + +... +*/ + +Locale.define("ja-JP", "FormValidator", { + + required: '入力は必須です。', + minLength: '入力文字数は{minLength}以上にしてください。({length}文字)', + maxLength: '入力文字数は{maxLength}以下にしてください。({length}文字)', + integer: '整数を入力してください。', + numeric: '入力できるのは数値だけです。(例: "1", "1.1", "-1", "-1.1"....)', + digits: '入力できるのは数値と句読記号です。 (例: -や+を含む電話番号など).', + alpha: '入力できるのは半角英字だけです。それ以外の文字は入力できません。', + alphanum: '入力できるのは半角英数字だけです。それ以外の文字は入力できません。', + dateSuchAs: '有効な日付を入力してください。{date}', + dateInFormatMDY: '日付の書式に誤りがあります。YYYY/MM/DD (i.e. "1999/12/31")', + email: 'メールアドレスに誤りがあります。', + url: 'URLアドレスに誤りがあります。', + currencyDollar: '金額に誤りがあります。', + oneRequired: 'ひとつ以上入力してください。', + errorPrefix: 'エラー: ', + warningPrefix: '警告: ', + + // FormValidator.Extras + noSpace: 'スペースは入力できません。', + reqChkByNode: '選択されていません。', + requiredChk: 'この項目は必須です。', + reqChkByName: '{label}を選択してください。', + match: '{matchName}が入力されている場合必須です。', + startDate: '開始日', + endDate: '終了日', + currentDate: '今日', + afterDate: '{label}以降の日付にしてください。', + beforeDate: '{label}以前の日付にしてください。', + startMonth: '開始月を選択してください。', + sameMonth: '日付が同一です。どちらかを変更してください。' + +}); + +/* +--- + +name: Locale.ja-JP.Number + +description: Number messages for Japanese. + +license: MIT-style license + +authors: + - Noritaka Horio + +requires: + - Locale + +provides: [Locale.ja-JP.Number] + +... +*/ + +Locale.define('ja-JP', 'Number', { + + decimal: '.', + group: ',', + + currency: { + decimals: 0, + prefix: '\\' + } + +}); + +/* +--- + +name: Locale.nl-NL.Date + +description: Date messages for Dutch. + +license: MIT-style license + +authors: + - Lennart Pilon + - Tim Wienk + +requires: + - Locale + +provides: [Locale.nl-NL.Date] + +... +*/ + +Locale.define('nl-NL', 'Date', { + + months: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], + months_abbr: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], + days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], + days_abbr: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + + // Culture's date order: DD-MM-YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d-%m-%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: 'e', + + lessThanMinuteAgo: 'minder dan een minuut geleden', + minuteAgo: 'ongeveer een minuut geleden', + minutesAgo: '{delta} minuten geleden', + hourAgo: 'ongeveer een uur geleden', + hoursAgo: 'ongeveer {delta} uur geleden', + dayAgo: 'een dag geleden', + daysAgo: '{delta} dagen geleden', + weekAgo: 'een week geleden', + weeksAgo: '{delta} weken geleden', + monthAgo: 'een maand geleden', + monthsAgo: '{delta} maanden geleden', + yearAgo: 'een jaar geleden', + yearsAgo: '{delta} jaar geleden', + + lessThanMinuteUntil: 'over minder dan een minuut', + minuteUntil: 'over ongeveer een minuut', + minutesUntil: 'over {delta} minuten', + hourUntil: 'over ongeveer een uur', + hoursUntil: 'over {delta} uur', + dayUntil: 'over ongeveer een dag', + daysUntil: 'over {delta} dagen', + weekUntil: 'over een week', + weeksUntil: 'over {delta} weken', + monthUntil: 'over een maand', + monthsUntil: 'over {delta} maanden', + yearUntil: 'over een jaar', + yearsUntil: 'over {delta} jaar' + +}); + +/* +--- + +name: Locale.nl-NL.Form.Validator + +description: Form Validator messages for Dutch. + +license: MIT-style license + +authors: + - Lennart Pilon + - Arian Stolwijk + - Tim Wienk + +requires: + - Locale + +provides: [Locale.nl-NL.Form.Validator] + +... +*/ + +Locale.define('nl-NL', 'FormValidator', { + + required: 'Dit veld is verplicht.', + length: 'Vul precies {length} karakters in (je hebt {elLength} karakters ingevoerd).', + minLength: 'Vul minimaal {minLength} karakters in (je hebt {length} karakters ingevoerd).', + maxLength: 'Vul niet meer dan {maxLength} karakters in (je hebt {length} karakters ingevoerd).', + integer: 'Vul een getal in. Getallen met decimalen (bijvoorbeeld 1.25) zijn niet toegestaan.', + numeric: 'Vul alleen numerieke waarden in (bijvoorbeeld "1" of "1.1" of "-1" of "-1.1").', + digits: 'Vul alleen nummers en leestekens in (bijvoorbeeld een telefoonnummer met streepjes is toegestaan).', + alpha: 'Vul alleen letters in (a-z). Spaties en andere karakters zijn niet toegestaan.', + alphanum: 'Vul alleen letters (a-z) of nummers (0-9) in. Spaties en andere karakters zijn niet toegestaan.', + dateSuchAs: 'Vul een geldige datum in, zoals {date}', + dateInFormatMDY: 'Vul een geldige datum, in het formaat MM/DD/YYYY (bijvoorbeeld "12/31/1999")', + email: 'Vul een geldig e-mailadres in. Bijvoorbeeld "fred@domein.nl".', + url: 'Vul een geldige URL in, zoals http://www.example.com.', + currencyDollar: 'Vul een geldig $ bedrag in. Bijvoorbeeld $100.00 .', + oneRequired: 'Vul iets in bij in ieder geval een van deze velden.', + warningPrefix: 'Waarschuwing: ', + errorPrefix: 'Fout: ', + + // Form.Validator.Extras + noSpace: 'Spaties zijn niet toegestaan in dit veld.', + reqChkByNode: 'Er zijn geen items geselecteerd.', + requiredChk: 'Dit veld is verplicht.', + reqChkByName: 'Selecteer een {label}.', + match: 'Dit veld moet overeen komen met het {matchName} veld', + startDate: 'de begin datum', + endDate: 'de eind datum', + currentDate: 'de huidige datum', + afterDate: 'De datum moet hetzelfde of na {label} zijn.', + beforeDate: 'De datum moet hetzelfde of voor {label} zijn.', + startMonth: 'Selecteer een begin maand', + sameMonth: 'Deze twee data moeten in dezelfde maand zijn - u moet een van beide aanpassen.', + creditcard: 'Het ingevulde creditcardnummer is niet geldig. Controleer het nummer en probeer opnieuw. {length} getallen ingevuld.' + +}); + +/* +--- + +name: Locale.nl-NL.Number + +description: Number messages for Dutch. + +license: MIT-style license + +authors: + - Arian Stolwijk + +requires: + - Locale + - Locale.EU.Number + +provides: [Locale.nl-NL.Number] + +... +*/ + +Locale.define('nl-NL').inherit('EU', 'Number'); + + + + +/* +--- + +name: Locale.no-NO.Date + +description: Date messages for Norwegian. + +license: MIT-style license + +authors: + - Espen 'Rexxars' Hovlandsdal + - Ole Tøsse Kolvik +requires: + - Locale + +provides: [Locale.no-NO.Date] + +... +*/ + +Locale.define('no-NO', 'Date', { + months: ['Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Desember'], + months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'], + days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'], + days_abbr: ['Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'], + + // Culture's date order: DD.MM.YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + lessThanMinuteAgo: 'mindre enn et minutt siden', + minuteAgo: 'omtrent et minutt siden', + minutesAgo: '{delta} minutter siden', + hourAgo: 'omtrent en time siden', + hoursAgo: 'omtrent {delta} timer siden', + dayAgo: '{delta} dag siden', + daysAgo: '{delta} dager siden', + weekAgo: 'en uke siden', + weeksAgo: '{delta} uker siden', + monthAgo: 'en måned siden', + monthsAgo: '{delta} måneder siden', + yearAgo: 'ett år siden', + yearsAgo: '{delta} år siden', + + lessThanMinuteUntil: 'mindre enn et minutt til', + minuteUntil: 'omtrent et minutt til', + minutesUntil: '{delta} minutter til', + hourUntil: 'omtrent en time til', + hoursUntil: 'omtrent {delta} timer til', + dayUntil: 'en dag til', + daysUntil: '{delta} dager til', + weekUntil: 'en uke til', + weeksUntil: '{delta} uker til', + monthUntil: 'en måned til', + monthsUntil: '{delta} måneder til', + yearUntil: 'et år til', + yearsUntil: '{delta} år til' +}); + +/* +--- + +name: Locale.no-NO.Form.Validator + +description: Form Validator messages for Norwegian. + +license: MIT-style license + +authors: + - Espen 'Rexxars' Hovlandsdal + +requires: + - Locale + +provides: [Locale.no-NO.Form.Validator] + +... +*/ + +Locale.define('no-NO', 'FormValidator', { + + required: 'Dette feltet er pÃ¥krevd.', + minLength: 'Vennligst skriv inn minst {minLength} tegn (du skrev {length} tegn).', + maxLength: 'Vennligst skriv inn maksimalt {maxLength} tegn (du skrev {length} tegn).', + integer: 'Vennligst skriv inn et tall i dette feltet. Tall med desimaler (for eksempel 1,25) er ikke tillat.', + numeric: 'Vennligst skriv inn kun numeriske verdier i dette feltet (for eksempel "1", "1.1", "-1" eller "-1.1").', + digits: 'Vennligst bruk kun nummer og skilletegn i dette feltet.', + alpha: 'Vennligst bruk kun bokstaver (a-z) i dette feltet. Ingen mellomrom eller andre tegn er tillat.', + alphanum: 'Vennligst bruk kun bokstaver (a-z) eller nummer (0-9) i dette feltet. Ingen mellomrom eller andre tegn er tillat.', + dateSuchAs: 'Vennligst skriv inn en gyldig dato, som {date}', + dateInFormatMDY: 'Vennligst skriv inn en gyldig dato, i formatet MM/DD/YYYY (for eksempel "12/31/1999")', + email: 'Vennligst skriv inn en gyldig epost-adresse. For eksempel "espen@domene.no".', + url: 'Vennligst skriv inn en gyldig URL, for eksempel http://www.example.com.', + currencyDollar: 'Vennligst fyll ut et gyldig $ beløp. For eksempel $100.00 .', + oneRequired: 'Vennligst fyll ut noe i minst ett av disse feltene.', + errorPrefix: 'Feil: ', + warningPrefix: 'Advarsel: ' + +}); + +/* +--- + +name: Locale.pl-PL.Date + +description: Date messages for Polish. + +license: MIT-style license + +authors: + - Oskar Krawczyk + +requires: + - Locale + +provides: [Locale.pl-PL.Date] + +... +*/ + +Locale.define('pl-PL', 'Date', { + + months: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'], + months_abbr: ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru'], + days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'], + days_abbr: ['niedz.', 'pon.', 'wt.', 'śr.', 'czw.', 'pt.', 'sob.'], + + // Culture's date order: YYYY-MM-DD + dateOrder: ['year', 'month', 'date'], + shortDate: '%Y-%m-%d', + shortTime: '%H:%M', + AM: 'nad ranem', + PM: 'po południu', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: function(dayOfMonth){ + return (dayOfMonth > 3 && dayOfMonth < 21) ? 'ty' : ['ty', 'szy', 'gi', 'ci', 'ty'][Math.min(dayOfMonth % 10, 4)]; + }, + + lessThanMinuteAgo: 'mniej niż minute temu', + minuteAgo: 'około minutę temu', + minutesAgo: '{delta} minut temu', + hourAgo: 'około godzinę temu', + hoursAgo: 'około {delta} godzin temu', + dayAgo: 'Wczoraj', + daysAgo: '{delta} dni temu', + + lessThanMinuteUntil: 'za niecałą minutę', + minuteUntil: 'za około minutę', + minutesUntil: 'za {delta} minut', + hourUntil: 'za około godzinę', + hoursUntil: 'za około {delta} godzin', + dayUntil: 'za 1 dzień', + daysUntil: 'za {delta} dni' + +}); + +/* +--- + +name: Locale.pl-PL.Form.Validator + +description: Form Validator messages for Polish. + +license: MIT-style license + +authors: + - Oskar Krawczyk + +requires: + - Locale + +provides: [Locale.pl-PL.Form.Validator] + +... +*/ + +Locale.define('pl-PL', 'FormValidator', { + + required: 'To pole jest wymagane.', + minLength: 'Wymagane jest przynajmniej {minLength} znaków (wpisanych zostało tylko {length}).', + maxLength: 'Dozwolone jest nie więcej niż {maxLength} znaków (wpisanych zostało {length})', + integer: 'To pole wymaga liczb całych. Liczby dziesiętne (np. 1.25) są niedozwolone.', + numeric: 'Prosimy używać tylko numerycznych wartości w tym polu (np. "1", "1.1", "-1" lub "-1.1").', + digits: 'Prosimy używać liczb oraz zankow punktuacyjnych w typ polu (dla przykładu, przy numerze telefonu myślniki i kropki są dozwolone).', + alpha: 'Prosimy używać tylko liter (a-z) w tym polu. Spacje oraz inne znaki są niedozwolone.', + alphanum: 'Prosimy używać tylko liter (a-z) lub liczb (0-9) w tym polu. Spacje oraz inne znaki są niedozwolone.', + dateSuchAs: 'Prosimy podać prawidłową datę w formacie: {date}', + dateInFormatMDY: 'Prosimy podać poprawną date w formacie DD.MM.RRRR (i.e. "12.01.2009")', + email: 'Prosimy podać prawidłowy adres e-mail, np. "jan@domena.pl".', + url: 'Prosimy podać prawidłowy adres URL, np. http://www.example.com.', + currencyDollar: 'Prosimy podać prawidłową sumę w PLN. Dla przykładu: 100.00 PLN.', + oneRequired: 'Prosimy wypełnić chociaż jedno z pól.', + errorPrefix: 'Błąd: ', + warningPrefix: 'Uwaga: ', + + // Form.Validator.Extras + noSpace: 'W tym polu nie mogą znajdować się spacje.', + reqChkByNode: 'Brak zaznaczonych elementów.', + requiredChk: 'To pole jest wymagane.', + reqChkByName: 'Prosimy wybrać z {label}.', + match: 'To pole musi być takie samo jak {matchName}', + startDate: 'data początkowa', + endDate: 'data końcowa', + currentDate: 'aktualna data', + afterDate: 'Podana data poinna być taka sama lub po {label}.', + beforeDate: 'Podana data poinna być taka sama lub przed {label}.', + startMonth: 'Prosimy wybrać początkowy miesiąc.', + sameMonth: 'Te dwie daty muszą być w zakresie tego samego miesiąca - wymagana jest zmiana któregoś z pól.' + +}); + +/* +--- + +name: Locale.pt-PT.Date + +description: Date messages for Portuguese. + +license: MIT-style license + +authors: + - Fabio Miranda Costa + +requires: + - Locale + +provides: [Locale.pt-PT.Date] + +... +*/ + +Locale.define('pt-PT', 'Date', { + + months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], + months_abbr: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], + days: ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'], + days_abbr: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'], + + // Culture's date order: DD-MM-YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d-%m-%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: 'º', + + lessThanMinuteAgo: 'há menos de um minuto', + minuteAgo: 'há cerca de um minuto', + minutesAgo: 'há {delta} minutos', + hourAgo: 'há cerca de uma hora', + hoursAgo: 'há cerca de {delta} horas', + dayAgo: 'há um dia', + daysAgo: 'há {delta} dias', + weekAgo: 'há uma semana', + weeksAgo: 'há {delta} semanas', + monthAgo: 'há um mês', + monthsAgo: 'há {delta} meses', + yearAgo: 'há um ano', + yearsAgo: 'há {delta} anos', + + lessThanMinuteUntil: 'em menos de um minuto', + minuteUntil: 'em um minuto', + minutesUntil: 'em {delta} minutos', + hourUntil: 'em uma hora', + hoursUntil: 'em {delta} horas', + dayUntil: 'em um dia', + daysUntil: 'em {delta} dias', + weekUntil: 'em uma semana', + weeksUntil: 'em {delta} semanas', + monthUntil: 'em um mês', + monthsUntil: 'em {delta} meses', + yearUntil: 'em um ano', + yearsUntil: 'em {delta} anos' + +}); + +/* +--- + +name: Locale.pt-BR.Date + +description: Date messages for Portuguese (Brazil). + +license: MIT-style license + +authors: + - Fabio Miranda Costa + +requires: + - Locale + - Locale.pt-PT.Date + +provides: [Locale.pt-BR.Date] + +... +*/ + +Locale.define('pt-BR', 'Date', { + + // Culture's date order: DD/MM/YYYY + shortDate: '%d/%m/%Y' + +}).inherit('pt-PT', 'Date'); + +/* +--- + +name: Locale.pt-BR.Form.Validator + +description: Form Validator messages for Portuguese (Brazil). + +license: MIT-style license + +authors: + - Fábio Miranda Costa + +requires: + - Locale + +provides: [Locale.pt-BR.Form.Validator] + +... +*/ + +Locale.define('pt-BR', 'FormValidator', { + + required: 'Este campo é obrigatório.', + minLength: 'Digite pelo menos {minLength} caracteres (tamanho atual: {length}).', + maxLength: 'Não digite mais de {maxLength} caracteres (tamanho atual: {length}).', + integer: 'Por favor digite apenas um número inteiro neste campo. Não são permitidos números decimais (por exemplo, 1,25).', + numeric: 'Por favor digite apenas valores numéricos neste campo (por exemplo, "1" ou "1.1" ou "-1" ou "-1,1").', + digits: 'Por favor use apenas números e pontuação neste campo (por exemplo, um número de telefone com traços ou pontos é permitido).', + alpha: 'Por favor use somente letras (a-z). Espaço e outros caracteres não são permitidos.', + alphanum: 'Use somente letras (a-z) ou números (0-9) neste campo. Espaço e outros caracteres não são permitidos.', + dateSuchAs: 'Digite uma data válida, como {date}', + dateInFormatMDY: 'Digite uma data válida, como DD/MM/YYYY (por exemplo, "31/12/1999")', + email: 'Digite um endereço de email válido. Por exemplo "nome@dominio.com".', + url: 'Digite uma URL válida. Exemplo: http://www.example.com.', + currencyDollar: 'Digite um valor em dinheiro válido. Exemplo: R$100,00 .', + oneRequired: 'Digite algo para pelo menos um desses campos.', + errorPrefix: 'Erro: ', + warningPrefix: 'Aviso: ', + + // Form.Validator.Extras + noSpace: 'Não é possível digitar espaços neste campo.', + reqChkByNode: 'Não foi selecionado nenhum item.', + requiredChk: 'Este campo é obrigatório.', + reqChkByName: 'Por favor digite um {label}.', + match: 'Este campo deve ser igual ao campo {matchName}.', + startDate: 'a data inicial', + endDate: 'a data final', + currentDate: 'a data atual', + afterDate: 'A data deve ser igual ou posterior a {label}.', + beforeDate: 'A data deve ser igual ou anterior a {label}.', + startMonth: 'Por favor selecione uma data inicial.', + sameMonth: 'Estas duas datas devem ter o mesmo mês - você deve modificar uma das duas.', + creditcard: 'O número do cartão de crédito informado é inválido. Por favor verifique o valor e tente novamente. {length} números informados.' + +}); + +/* +--- + +name: Locale.pt-BR.Number + +description: Number messages for PT Brazilian. + +license: MIT-style license + +authors: + - Arian Stolwijk + - Danillo César + +requires: + - Locale + +provides: [Locale.pt-BR.Number] + +... +*/ + +Locale.define('pt-BR', 'Number', { + + decimal: ',', + group: '.', + + currency: { + prefix: 'R$ ' + } + +}); + + + +/* +--- + +name: Locale.pt-PT.Form.Validator + +description: Form Validator messages for Portuguese. + +license: MIT-style license + +authors: + - Miquel Hudin + +requires: + - Locale + +provides: [Locale.pt-PT.Form.Validator] + +... +*/ + +Locale.define('pt-PT', 'FormValidator', { + + required: 'Este campo é necessário.', + minLength: 'Digite pelo menos{minLength} caracteres (comprimento {length} caracteres).', + maxLength: 'Não insira mais de {maxLength} caracteres (comprimento {length} caracteres).', + integer: 'Digite um número inteiro neste domínio. Com números decimais (por exemplo, 1,25), não são permitidas.', + numeric: 'Digite apenas valores numéricos neste domínio (p.ex., "1" ou "1.1" ou "-1" ou "-1,1").', + digits: 'Por favor, use números e pontuação apenas neste campo (p.ex., um número de telefone com traços ou pontos é permitida).', + alpha: 'Por favor use somente letras (a-z), com nesta área. Não utilize espaços nem outros caracteres são permitidos.', + alphanum: 'Use somente letras (a-z) ou números (0-9) neste campo. Não utilize espaços nem outros caracteres são permitidos.', + dateSuchAs: 'Digite uma data válida, como {date}', + dateInFormatMDY: 'Digite uma data válida, como DD/MM/YYYY (p.ex. "31/12/1999")', + email: 'Digite um endereço de email válido. Por exemplo "fred@domain.com".', + url: 'Digite uma URL válida, como http://www.example.com.', + currencyDollar: 'Digite um valor válido $. Por exemplo $ 100,00. ', + oneRequired: 'Digite algo para pelo menos um desses insumos.', + errorPrefix: 'Erro: ', + warningPrefix: 'Aviso: ' + +}); + +/* +--- + +name: Locale.ru-RU-unicode.Date + +description: Date messages for Russian (utf-8). + +license: MIT-style license + +authors: + - Evstigneev Pavel + - Kuryanovich Egor + +requires: + - Locale + +provides: [Locale.ru-RU.Date] + +... +*/ + +(function(){ + +// Russian language pluralization rules, taken from CLDR project, http://unicode.org/cldr/ +// one -> n mod 10 is 1 and n mod 100 is not 11; +// few -> n mod 10 in 2..4 and n mod 100 not in 12..14; +// many -> n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14; +// other -> everything else (example 3.14) +var pluralize = function (n, one, few, many, other){ + var modulo10 = n % 10, + modulo100 = n % 100; + + if (modulo10 == 1 && modulo100 != 11){ + return one; + } else if ((modulo10 == 2 || modulo10 == 3 || modulo10 == 4) && !(modulo100 == 12 || modulo100 == 13 || modulo100 == 14)){ + return few; + } else if (modulo10 == 0 || (modulo10 == 5 || modulo10 == 6 || modulo10 == 7 || modulo10 == 8 || modulo10 == 9) || (modulo100 == 11 || modulo100 == 12 || modulo100 == 13 || modulo100 == 14)){ + return many; + } else { + return other; + } +}; + +Locale.define('ru-RU', 'Date', { + + months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], + months_abbr: ['янв', 'февр', 'март', 'апр', 'май','июнь','июль','авг','сент','окт','нояб','дек'], + days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], + days_abbr: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], + + // Culture's date order: DD.MM.YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H:%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'меньше минуты назад', + minuteAgo: 'минуту назад', + minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'минуту', 'минуты', 'минут') + ' назад'; }, + hourAgo: 'час назад', + hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ' назад'; }, + dayAgo: 'вчера', + daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'день', 'дня', 'дней') + ' назад'; }, + weekAgo: 'неделю назад', + weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'неделя', 'недели', 'недель') + ' назад'; }, + monthAgo: 'месяц назад', + monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'месяц', 'месяца', 'месяцев') + ' назад'; }, + yearAgo: 'год назад', + yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'год', 'года', 'лет') + ' назад'; }, + + lessThanMinuteUntil: 'меньше чем через минуту', + minuteUntil: 'через минуту', + minutesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'минуту', 'минуты', 'минут') + ''; }, + hourUntil: 'через час', + hoursUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ''; }, + dayUntil: 'завтра', + daysUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'день', 'дня', 'дней') + ''; }, + weekUntil: 'через неделю', + weeksUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'неделю', 'недели', 'недель') + ''; }, + monthUntil: 'через месяц', + monthsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'месяц', 'месяца', 'месяцев') + ''; }, + yearUntil: 'через', + yearsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'год', 'года', 'лет') + ''; } + +}); + + + +})(); + +/* +--- + +name: Locale.ru-RU-unicode.Form.Validator + +description: Form Validator messages for Russian (utf-8). + +license: MIT-style license + +authors: + - Chernodarov Egor + +requires: + - Locale + +provides: [Locale.ru-RU.Form.Validator] + +... +*/ + +Locale.define('ru-RU', 'FormValidator', { + + required: 'Это поле обязательно к заполнению.', + minLength: 'Пожалуйста, введите хотя бы {minLength} символов (Вы ввели {length}).', + maxLength: 'Пожалуйста, введите не больше {maxLength} символов (Вы ввели {length}).', + integer: 'Пожалуйста, введите в это поле число. Дробные числа (например 1.25) тут не разрешены.', + numeric: 'Пожалуйста, введите в это поле число (например "1" или "1.1", или "-1", или "-1.1").', + digits: 'В этом поле Вы можете использовать только цифры и знаки пунктуации (например, телефонный номер со знаками дефиса или с точками).', + alpha: 'В этом поле можно использовать только латинские буквы (a-z). Пробелы и другие символы запрещены.', + alphanum: 'В этом поле можно использовать только латинские буквы (a-z) и цифры (0-9). Пробелы и другие символы запрещены.', + dateSuchAs: 'Пожалуйста, введите корректную дату {date}', + dateInFormatMDY: 'Пожалуйста, введите дату в формате ММ/ДД/ГГГГ (например "12/31/1999")', + email: 'Пожалуйста, введите корректный емейл-адрес. Для примера "fred@domain.com".', + url: 'Пожалуйста, введите правильную ссылку вида http://www.example.com.', + currencyDollar: 'Пожалуйста, введите сумму в долларах. Например: $100.00 .', + oneRequired: 'Пожалуйста, выберите хоть что-нибудь в одном из этих полей.', + errorPrefix: 'Ошибка: ', + warningPrefix: 'Внимание: ' + +}); + + + +/* +--- + +name: Locale.sk-SK.Date + +description: Date messages for Slovak. + +license: MIT-style license + +authors: + - Ivan Masár + +requires: + - Locale + +provides: [Locale.sk-SK.Date] + +... +*/ +(function(){ + +// Slovak language pluralization rules, see http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html +// one -> n is 1; 1 +// few -> n in 2..4; 2-4 +// other -> everything else 0, 5-999, 1.31, 2.31, 5.31... +var pluralize = function (n, one, few, other){ + if (n == 1) return one; + else if (n == 2 || n == 3 || n == 4) return few; + else return other; +}; + +Locale.define('sk-SK', 'Date', { + + months: ['Január', 'Február', 'Marec', 'Apríl', 'Máj', 'Jún', 'Júl', 'August', 'September', 'Október', 'November', 'December'], + months_abbr: ['januára', 'februára', 'marca', 'apríla', 'mája', 'júna', 'júla', 'augusta', 'septembra', 'októbra', 'novembra', 'decembra'], + days: ['Nedele', 'Pondelí', 'Úterý', 'Streda', 'Čtvrtek', 'Pátek', 'Sobota'], + days_abbr: ['ne', 'po', 'ut', 'st', 'št', 'pi', 'so'], + + // Culture's date order: DD.MM.YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H:%M', + AM: 'dop.', + PM: 'pop.', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'pred chvíľou', + minuteAgo: 'približne pred minútou', + minutesAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'minútou', 'minútami', 'minútami'); }, + hourAgo: 'približne pred hodinou', + hoursAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'hodinou', 'hodinami', 'hodinami'); }, + dayAgo: 'pred dňom', + daysAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'dňom', 'dňami', 'dňami'); }, + weekAgo: 'pred týždňom', + weeksAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'týždňom', 'týždňami', 'týždňami'); }, + monthAgo: 'pred mesiacom', + monthsAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'mesiacom', 'mesiacmi', 'mesiacmi'); }, + yearAgo: 'pred rokom', + yearsAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'rokom', 'rokmi', 'rokmi'); }, + + lessThanMinuteUntil: 'o chvíľu', + minuteUntil: 'približne o minútu', + minutesUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'minútu', 'minúty', 'minúty'); }, + hourUntil: 'približne o hodinu', + hoursUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'hodinu', 'hodiny', 'hodín'); }, + dayUntil: 'o deň', + daysUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'deň', 'dni', 'dní'); }, + weekUntil: 'o týždeň', + weeksUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'týždeň', 'týždne', 'týždňov'); }, + monthUntil: 'o mesiac', + monthsUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'mesiac', 'mesiace', 'mesiacov'); }, + yearUntil: 'o rok', + yearsUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'rok', 'roky', 'rokov'); } +}); + +})(); + +/* +--- + +name: Locale.sk-SK.Form.Validator + +description: Form Validator messages for Czech. + +license: MIT-style license + +authors: + - Ivan Masár + +requires: + - Locale + +provides: [Locale.sk-SK.Form.Validator] + +... +*/ + +Locale.define('sk-SK', 'FormValidator', { + + required: 'Táto položka je povinná.', + minLength: 'Zadajte prosím aspoň {minLength} znakov (momentálne {length} znakov).', + maxLength: 'Zadajte prosím menej ako {maxLength} znakov (momentálne {length} znakov).', + integer: 'Zadajte prosím celé číslo. Desetinné čísla (napr. 1.25) nie sú povolené.', + numeric: 'Zadajte len číselné hodnoty (t.j. „1“ alebo „1.1“ alebo „-1“ alebo „-1.1“).', + digits: 'Zadajte prosím len čísla a interpunkčné znamienka (napríklad telefónne číslo s pomlčkami albo bodkami je povolené).', + alpha: 'Zadajte prosím len písmená (a-z). Medzery alebo iné znaky nie sú povolené.', + alphanum: 'Zadajte prosím len písmená (a-z) alebo číslice (0-9). Medzery alebo iné znaky nie sú povolené.', + dateSuchAs: 'Zadajte prosím platný dátum v tvare {date}', + dateInFormatMDY: 'Zadajte prosím platný datum v tvare MM / DD / RRRR (t.j. „12/31/1999“)', + email: 'Zadajte prosím platnú emailovú adresu. Napríklad „fred@domain.com“.', + url: 'Zadajte prosím platnoú adresu URL v tvare http://www.example.com.', + currencyDollar: 'Zadajte prosím platnú čiastku. Napríklad $100.00.', + oneRequired: 'Zadajte prosím aspoň jednu hodnotu z týchto položiek.', + errorPrefix: 'Chyba: ', + warningPrefix: 'Upozornenie: ', + + // Form.Validator.Extras + noSpace: 'V tejto položle nie sú povolené medzery', + reqChkByNode: 'Nie sú vybrané žiadne položky.', + requiredChk: 'Táto položka je povinná.', + reqChkByName: 'Prosím vyberte {label}.', + match: 'Táto položka sa musí zhodovať s položkou {matchName}', + startDate: 'dátum začiatku', + endDate: 'dátum ukončenia', + currendDate: 'aktuálny dátum', + afterDate: 'Dátum by mal býť rovnaký alebo väčší ako {label}.', + beforeDate: 'Dátum by mal byť rovnaký alebo menší ako {label}.', + startMonth: 'Vyberte počiatočný mesiac.', + sameMonth: 'Tieto dva dátumy musia býť v rovnakom mesiaci - zmeňte jeden z nich.', + creditcard: 'Zadané číslo kreditnej karty je neplatné. Prosím, opravte ho. Bolo zadaných {length} číslic.' + +}); + +/* +--- + +name: Locale.si-SI.Date + +description: Date messages for Slovenian. + +license: MIT-style license + +authors: + - Radovan Lozej + +requires: + - Locale + +provides: [Locale.si-SI.Date] + +... +*/ + +(function(){ + +var pluralize = function(n, one, two, three, other){ + return (n >= 1 && n <= 3) ? arguments[n] : other; +}; + +Locale.define('sl-SI', 'Date', { + + months: ['januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december'], + months_abbr: ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sep', 'okt', 'nov', 'dec'], + days: ['nedelja', 'ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota'], + days_abbr: ['ned', 'pon', 'tor', 'sre', 'čet', 'pet', 'sob'], + + // Culture's date order: DD.MM.YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d.%m.%Y', + shortTime: '%H.%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '.', + + lessThanMinuteAgo: 'manj kot minuto nazaj', + minuteAgo: 'minuto nazaj', + minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'minuto', 'minuti', 'minute', 'minut') + ' nazaj'; }, + hourAgo: 'uro nazaj', + hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'uro', 'uri', 'ure', 'ur') + ' nazaj'; }, + dayAgo: 'dan nazaj', + daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'dan', 'dneva', 'dni', 'dni') + ' nazaj'; }, + weekAgo: 'teden nazaj', + weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'teden', 'tedna', 'tedne', 'tednov') + ' nazaj'; }, + monthAgo: 'mesec nazaj', + monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'mesec', 'meseca', 'mesece', 'mesecov') + ' nazaj'; }, + yearthAgo: 'leto nazaj', + yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'leto', 'leti', 'leta', 'let') + ' nazaj'; }, + + lessThanMinuteUntil: 'še manj kot minuto', + minuteUntil: 'še minuta', + minutesUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'minuta', 'minuti', 'minute', 'minut'); }, + hourUntil: 'še ura', + hoursUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'ura', 'uri', 'ure', 'ur'); }, + dayUntil: 'še dan', + daysUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'dan', 'dneva', 'dnevi', 'dni'); }, + weekUntil: 'še tedn', + weeksUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'teden', 'tedna', 'tedni', 'tednov'); }, + monthUntil: 'še mesec', + monthsUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'mesec', 'meseca', 'meseci', 'mesecov'); }, + yearUntil: 'še leto', + yearsUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'leto', 'leti', 'leta', 'let'); } + +}); + +})(); + +/* +--- + +name: Locale.si-SI.Form.Validator + +description: Form Validator messages for Slovenian. + +license: MIT-style license + +authors: + - Radovan Lozej + +requires: + - Locale + +provides: [Locale.si-SI.Form.Validator] + +... +*/ + +Locale.define('sl-SI', 'FormValidator', { + + required: 'To polje je obvezno', + minLength: 'Prosim, vnesite vsaj {minLength} znakov (vnesli ste {length} znakov).', + maxLength: 'Prosim, ne vnesite več kot {maxLength} znakov (vnesli ste {length} znakov).', + integer: 'Prosim, vnesite celo število. Decimalna števila (kot 1,25) niso dovoljena.', + numeric: 'Prosim, vnesite samo numerične vrednosti (kot "1" ali "1.1" ali "-1" ali "-1.1").', + digits: 'Prosim, uporabite številke in ločila le na tem polju (na primer, dovoljena je telefonska številka z pomišlaji ali pikami).', + alpha: 'Prosim, uporabite le črke v tem plju. Presledki in drugi znaki niso dovoljeni.', + alphanum: 'Prosim, uporabite samo črke ali številke v tem polju. Presledki in drugi znaki niso dovoljeni.', + dateSuchAs: 'Prosim, vnesite pravilen datum kot {date}', + dateInFormatMDY: 'Prosim, vnesite pravilen datum kot MM.DD.YYYY (primer "12.31.1999")', + email: 'Prosim, vnesite pravilen email naslov. Na primer "fred@domain.com".', + url: 'Prosim, vnesite pravilen URL kot http://www.example.com.', + currencyDollar: 'Prosim, vnesit epravilno vrednost €. Primer 100,00€ .', + oneRequired: 'Prosimo, vnesite nekaj za vsaj eno izmed teh polj.', + errorPrefix: 'Napaka: ', + warningPrefix: 'Opozorilo: ', + + // Form.Validator.Extras + noSpace: 'To vnosno polje ne dopušča presledkov.', + reqChkByNode: 'Nič niste izbrali.', + requiredChk: 'To polje je obvezno', + reqChkByName: 'Prosim, izberite {label}.', + match: 'To polje se mora ujemati z poljem {matchName}', + startDate: 'datum začetka', + endDate: 'datum konca', + currentDate: 'trenuten datum', + afterDate: 'Datum bi moral biti isti ali po {label}.', + beforeDate: 'Datum bi moral biti isti ali pred {label}.', + startMonth: 'Prosim, vnesite začetni datum', + sameMonth: 'Ta dva datuma morata biti v istem mesecu - premeniti morate eno ali drugo.', + creditcard: 'Številka kreditne kartice ni pravilna. Preverite številko ali poskusite še enkrat. Vnešenih {length} znakov.' + +}); + +/* +--- + +name: Locale.sv-SE.Date + +description: Date messages for Swedish. + +license: MIT-style license + +authors: + - Martin Lundgren + +requires: + - Locale + +provides: [Locale.sv-SE.Date] + +... +*/ + +Locale.define('sv-SE', 'Date', { + + months: ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'], + months_abbr: ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], + days: ['söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag'], + days_abbr: ['sön', 'mån', 'tis', 'ons', 'tor', 'fre', 'lör'], + + // Culture's date order: YYYY-MM-DD + dateOrder: ['year', 'month', 'date'], + shortDate: '%Y-%m-%d', + shortTime: '%H:%M', + AM: '', + PM: '', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'mindre än en minut sedan', + minuteAgo: 'ungefär en minut sedan', + minutesAgo: '{delta} minuter sedan', + hourAgo: 'ungefär en timme sedan', + hoursAgo: 'ungefär {delta} timmar sedan', + dayAgo: '1 dag sedan', + daysAgo: '{delta} dagar sedan', + + lessThanMinuteUntil: 'mindre än en minut sedan', + minuteUntil: 'ungefär en minut sedan', + minutesUntil: '{delta} minuter sedan', + hourUntil: 'ungefär en timme sedan', + hoursUntil: 'ungefär {delta} timmar sedan', + dayUntil: '1 dag sedan', + daysUntil: '{delta} dagar sedan' + +}); + +/* +--- + +name: Locale.sv-SE.Form.Validator + +description: Form Validator messages for Swedish. + +license: MIT-style license + +authors: + - Martin Lundgren + +requires: + - Locale + +provides: [Locale.sv-SE.Form.Validator] + +... +*/ + +Locale.define('sv-SE', 'FormValidator', { + + required: 'Fältet är obligatoriskt.', + minLength: 'Ange minst {minLength} tecken (du angav {length} tecken).', + maxLength: 'Ange högst {maxLength} tecken (du angav {length} tecken). ', + integer: 'Ange ett heltal i fältet. Tal med decimaler (t.ex. 1,25) är inte tillåtna.', + numeric: 'Ange endast numeriska värden i detta fält (t.ex. "1" eller "1.1" eller "-1" eller "-1,1").', + digits: 'Använd endast siffror och skiljetecken i detta fält (till exempel ett telefonnummer med bindestreck tillåtet).', + alpha: 'Använd endast bokstäver (a-ö) i detta fält. Inga mellanslag eller andra tecken är tillåtna.', + alphanum: 'Använd endast bokstäver (a-ö) och siffror (0-9) i detta fält. Inga mellanslag eller andra tecken är tillåtna.', + dateSuchAs: 'Ange ett giltigt datum som t.ex. {date}', + dateInFormatMDY: 'Ange ett giltigt datum som t.ex. YYYY-MM-DD (i.e. "1999-12-31")', + email: 'Ange en giltig e-postadress. Till exempel "erik@domain.com".', + url: 'Ange en giltig webbadress som http://www.example.com.', + currencyDollar: 'Ange en giltig belopp. Exempelvis 100,00.', + oneRequired: 'Vänligen ange minst ett av dessa alternativ.', + errorPrefix: 'Fel: ', + warningPrefix: 'Varning: ', + + // Form.Validator.Extras + noSpace: 'Det får inte finnas några mellanslag i detta fält.', + reqChkByNode: 'Inga objekt är valda.', + requiredChk: 'Detta är ett obligatoriskt fält.', + reqChkByName: 'Välj en {label}.', + match: 'Detta fält måste matcha {matchName}', + startDate: 'startdatumet', + endDate: 'slutdatum', + currentDate: 'dagens datum', + afterDate: 'Datumet bör vara samma eller senare än {label}.', + beforeDate: 'Datumet bör vara samma eller tidigare än {label}.', + startMonth: 'Välj en start månad', + sameMonth: 'Dessa två datum måste vara i samma månad - du måste ändra det ena eller det andra.' + +}); + +/* +--- + +name: Locale.sv-SE.Number + +description: Number messages for Swedish. + +license: MIT-style license + +authors: + - Arian Stolwijk + - Martin Lundgren + +requires: + - Locale + - Locale.EU.Number + +provides: [Locale.sv-SE.Number] + +... +*/ + +Locale.define('sv-SE', 'Number', { + + currency: { + prefix: 'SEK ' + } + +}).inherit('EU', 'Number'); + +/* +--- + +name: Locale.tr-TR.Date + +description: Date messages for Turkish. + +license: MIT-style license + +authors: + - Faruk Can Bilir + +requires: + - Locale + +provides: [Locale.tr-TR.Date] + +... +*/ + +Locale.define('tr-TR', 'Date', { + + months: ['Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'], + months_abbr: ['Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara'], + days: ['Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'], + days_abbr: ['Pa', 'Pzt', 'Sa', 'Ça', 'Pe', 'Cu', 'Cmt'], + + // Culture's date order: MM/DD/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H.%M', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'bir dakikadan önce', + minuteAgo: 'yaklaşık bir dakika önce', + minutesAgo: '{delta} dakika önce', + hourAgo: 'bir saat kadar önce', + hoursAgo: '{delta} saat kadar önce', + dayAgo: 'bir gün önce', + daysAgo: '{delta} gün önce', + weekAgo: 'bir hafta önce', + weeksAgo: '{delta} hafta önce', + monthAgo: 'bir ay önce', + monthsAgo: '{delta} ay önce', + yearAgo: 'bir yıl önce', + yearsAgo: '{delta} yıl önce', + + lessThanMinuteUntil: 'bir dakikadan az sonra', + minuteUntil: 'bir dakika kadar sonra', + minutesUntil: '{delta} dakika sonra', + hourUntil: 'bir saat kadar sonra', + hoursUntil: '{delta} saat kadar sonra', + dayUntil: 'bir gün sonra', + daysUntil: '{delta} gün sonra', + weekUntil: 'bir hafta sonra', + weeksUntil: '{delta} hafta sonra', + monthUntil: 'bir ay sonra', + monthsUntil: '{delta} ay sonra', + yearUntil: 'bir yıl sonra', + yearsUntil: '{delta} yıl sonra' + +}); + +/* +--- + +name: Locale.tr-TR.Form.Validator + +description: Form Validator messages for Turkish. + +license: MIT-style license + +authors: + - Faruk Can Bilir + +requires: + - Locale + +provides: [Locale.tr-TR.Form.Validator] + +... +*/ + +Locale.define('tr-TR', 'FormValidator', { + + required: 'Bu alan zorunlu.', + minLength: 'Lütfen en az {minLength} karakter girin (siz {length} karakter girdiniz).', + maxLength: 'Lütfen en fazla {maxLength} karakter girin (siz {length} karakter girdiniz).', + integer: 'Lütfen bu alana sadece tamsayı girin. Ondalıklı sayılar (ör: 1.25) kullanılamaz.', + numeric: 'Lütfen bu alana sadece sayısal değer girin (ör: "1", "1.1", "-1" ya da "-1.1").', + digits: 'Lütfen bu alana sadece sayısal değer ve noktalama işareti girin (örneğin, nokta ve tire içeren bir telefon numarası kullanılabilir).', + alpha: 'Lütfen bu alanda yalnızca harf kullanın. Boşluk ve diğer karakterler kullanılamaz.', + alphanum: 'Lütfen bu alanda sadece harf ve rakam kullanın. Boşluk ve diğer karakterler kullanılamaz.', + dateSuchAs: 'Lütfen geçerli bir tarih girin (Ör: {date})', + dateInFormatMDY: 'Lütfen geçerli bir tarih girin (GG/AA/YYYY, ör: "31/12/1999")', + email: 'Lütfen geçerli bir email adresi girin. Ör: "kemal@etikan.com".', + url: 'Lütfen geçerli bir URL girin. Ör: http://www.example.com.', + currencyDollar: 'Lütfen geçerli bir TL miktarı girin. Ör: 100,00 TL .', + oneRequired: 'Lütfen en az bir tanesini doldurun.', + errorPrefix: 'Hata: ', + warningPrefix: 'Uyarı: ', + + // Form.Validator.Extras + noSpace: 'Bu alanda boşluk kullanılamaz.', + reqChkByNode: 'Hiçbir öğe seçilmemiş.', + requiredChk: 'Bu alan zorunlu.', + reqChkByName: 'Lütfen bir {label} girin.', + match: 'Bu alan, {matchName} alanıyla uyuşmalı', + startDate: 'başlangıç tarihi', + endDate: 'bitiş tarihi', + currentDate: 'bugünün tarihi', + afterDate: 'Tarih, {label} tarihiyle aynı gün ya da ondan sonra olmalıdır.', + beforeDate: 'Tarih, {label} tarihiyle aynı gün ya da ondan önce olmalıdır.', + startMonth: 'Lütfen bir başlangıç ayı seçin', + sameMonth: 'Bu iki tarih aynı ayda olmalı - bir tanesini değiştirmeniz gerekiyor.', + creditcard: 'Girdiğiniz kredi kartı numarası geçersiz. Lütfen kontrol edip tekrar deneyin. {length} hane girildi.' + +}); + +/* +--- + +name: Locale.tr-TR.Number + +description: Number messages for Turkish. + +license: MIT-style license + +authors: + - Faruk Can Bilir + +requires: + - Locale + - Locale.EU.Number + +provides: [Locale.tr-TR.Number] + +... +*/ + +Locale.define('tr-TR', 'Number', { + + currency: { + decimals: 0, + suffix: ' TL' + } + +}).inherit('EU', 'Number'); + +/* +--- + +name: Locale.uk-UA.Date + +description: Date messages for Ukrainian (utf-8). + +license: MIT-style license + +authors: + - Slik + +requires: + - Locale + +provides: [Locale.uk-UA.Date] + +... +*/ + +(function(){ + +var pluralize = function(n, one, few, many, other){ + var d = (n / 10).toInt(), + z = n % 10, + s = (n / 100).toInt(); + + if (d == 1 && n > 10) return many; + if (z == 1) return one; + if (z > 0 && z < 5) return few; + return many; +}; + +Locale.define('uk-UA', 'Date', { + + months: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень'], + months_abbr: ['Січ', 'Лют', 'Бер', 'Квіт', 'Трав', 'Черв', 'Лип', 'Серп', 'Вер', 'Жовт', 'Лист', 'Груд' ], + days: ['Неділя', 'Понеділок', 'Вівторок', 'Середа', 'Четвер', "П'ятниця", 'Субота'], + days_abbr: ['Нд', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], + + // Culture's date order: DD/MM/YYYY + dateOrder: ['date', 'month', 'year'], + shortDate: '%d/%m/%Y', + shortTime: '%H:%M', + AM: 'до полудня', + PM: 'по полудню', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: 'меньше хвилини тому', + minuteAgo: 'хвилину тому', + minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'хвилину', 'хвилини', 'хвилин') + ' тому'; }, + hourAgo: 'годину тому', + hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'годину', 'години', 'годин') + ' тому'; }, + dayAgo: 'вчора', + daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'день', 'дня', 'днів') + ' тому'; }, + weekAgo: 'тиждень тому', + weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'тиждень', 'тижні', 'тижнів') + ' тому'; }, + monthAgo: 'місяць тому', + monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'місяць', 'місяці', 'місяців') + ' тому'; }, + yearAgo: 'рік тому', + yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'рік', 'роки', 'років') + ' тому'; }, + + lessThanMinuteUntil: 'за мить', + minuteUntil: 'через хвилину', + minutesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'хвилину', 'хвилини', 'хвилин'); }, + hourUntil: 'через годину', + hoursUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'годину', 'години', 'годин'); }, + dayUntil: 'завтра', + daysUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'день', 'дня', 'днів'); }, + weekUntil: 'через тиждень', + weeksUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'тиждень', 'тижні', 'тижнів'); }, + monthUntil: 'через місяць', + monthesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'місяць', 'місяці', 'місяців'); }, + yearUntil: 'через рік', + yearsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'рік', 'роки', 'років'); } + +}); + +})(); + +/* +--- + +name: Locale.uk-UA.Form.Validator + +description: Form Validator messages for Ukrainian (utf-8). + +license: MIT-style license + +authors: + - Slik + +requires: + - Locale + +provides: [Locale.uk-UA.Form.Validator] + +... +*/ + +Locale.define('uk-UA', 'FormValidator', { + + required: 'Це поле повинне бути заповненим.', + minLength: 'Введіть хоча б {minLength} символів (Ви ввели {length}).', + maxLength: 'Кількість символів не може бути більше {maxLength} (Ви ввели {length}).', + integer: 'Введіть в це поле число. Дробові числа (наприклад 1.25) не дозволені.', + numeric: 'Введіть в це поле число (наприклад "1" або "1.1", або "-1", або "-1.1").', + digits: 'В цьому полі ви можете використовувати лише цифри і знаки пунктіації (наприклад, телефонний номер з знаками дефізу або з крапками).', + alpha: 'В цьому полі можна використовувати лише латинські літери (a-z). Пробіли і інші символи заборонені.', + alphanum: 'В цьому полі можна використовувати лише латинські літери (a-z) і цифри (0-9). Пробіли і інші символи заборонені.', + dateSuchAs: 'Введіть коректну дату {date}.', + dateInFormatMDY: 'Введіть дату в форматі ММ/ДД/РРРР (наприклад "12/31/2009").', + email: 'Введіть коректну адресу електронної пошти (наприклад "name@domain.com").', + url: 'Введіть коректне інтернет-посилання (наприклад http://www.example.com).', + currencyDollar: 'Введіть суму в доларах (наприклад "$100.00").', + oneRequired: 'Заповніть одне з полів.', + errorPrefix: 'Помилка: ', + warningPrefix: 'Увага: ', + + noSpace: 'Пробіли заборонені.', + reqChkByNode: 'Не відмічено жодного варіанту.', + requiredChk: 'Це поле повинне бути віміченим.', + reqChkByName: 'Будь ласка, відмітьте {label}.', + match: 'Це поле повинно відповідати {matchName}', + startDate: 'початкова дата', + endDate: 'кінцева дата', + currentDate: 'сьогоднішня дата', + afterDate: 'Ця дата повинна бути такою ж, або пізнішою за {label}.', + beforeDate: 'Ця дата повинна бути такою ж, або ранішою за {label}.', + startMonth: 'Будь ласка, виберіть початковий місяць', + sameMonth: 'Ці дати повинні відноситись одного і того ж місяця. Будь ласка, змініть одну з них.', + creditcard: 'Номер кредитної карти введений неправильно. Будь ласка, перевірте його. Введено {length} символів.' + +}); + +/* +--- + +name: Locale.zh-CH.Date + +description: Date messages for Chinese (simplified and traditional). + +license: MIT-style license + +authors: + - YMind Chan + +requires: + - Locale + +provides: [Locale.zh-CH.Date] + +... +*/ + +// Simplified Chinese +Locale.define('zh-CHS', 'Date', { + + months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], + days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], + days_abbr: ['日', '一', '二', '三', '四', '五', '六'], + + // Culture's date order: YYYY-MM-DD + dateOrder: ['year', 'month', 'date'], + shortDate: '%Y-%m-%d', + shortTime: '%I:%M%p', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: '不到1分钟前', + minuteAgo: '大约1分钟前', + minutesAgo: '{delta}分钟之前', + hourAgo: '大约1小时前', + hoursAgo: '大约{delta}小时前', + dayAgo: '1天前', + daysAgo: '{delta}天前', + weekAgo: '1星期前', + weeksAgo: '{delta}星期前', + monthAgo: '1个月前', + monthsAgo: '{delta}个月前', + yearAgo: '1年前', + yearsAgo: '{delta}年前', + + lessThanMinuteUntil: '从现在开始不到1分钟', + minuteUntil: '从现在开始約1分钟', + minutesUntil: '从现在开始约{delta}分钟', + hourUntil: '从现在开始1小时', + hoursUntil: '从现在开始约{delta}小时', + dayUntil: '从现在开始1天', + daysUntil: '从现在开始{delta}天', + weekUntil: '从现在开始1星期', + weeksUntil: '从现在开始{delta}星期', + monthUntil: '从现在开始一个月', + monthsUntil: '从现在开始{delta}个月', + yearUntil: '从现在开始1年', + yearsUntil: '从现在开始{delta}年' + +}); + +// Traditional Chinese +Locale.define('zh-CHT', 'Date', { + + months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], + days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], + days_abbr: ['日', '一', '二', '三', '四', '五', '六'], + + // Culture's date order: YYYY-MM-DD + dateOrder: ['year', 'month', 'date'], + shortDate: '%Y-%m-%d', + shortTime: '%I:%M%p', + AM: 'AM', + PM: 'PM', + firstDayOfWeek: 1, + + // Date.Extras + ordinal: '', + + lessThanMinuteAgo: '不到1分鐘前', + minuteAgo: '大約1分鐘前', + minutesAgo: '{delta}分鐘之前', + hourAgo: '大約1小時前', + hoursAgo: '大約{delta}小時前', + dayAgo: '1天前', + daysAgo: '{delta}天前', + weekAgo: '1星期前', + weeksAgo: '{delta}星期前', + monthAgo: '1个月前', + monthsAgo: '{delta}个月前', + yearAgo: '1年前', + yearsAgo: '{delta}年前', + + lessThanMinuteUntil: '從現在開始不到1分鐘', + minuteUntil: '從現在開始約1分鐘', + minutesUntil: '從現在開始約{delta}分鐘', + hourUntil: '從現在開始1小時', + hoursUntil: '從現在開始約{delta}小時', + dayUntil: '從現在開始1天', + daysUntil: '從現在開始{delta}天', + weekUntil: '從現在開始1星期', + weeksUntil: '從現在開始{delta}星期', + monthUntil: '從現在開始一個月', + monthsUntil: '從現在開始{delta}個月', + yearUntil: '從現在開始1年', + yearsUntil: '從現在開始{delta}年' + +}); + +/* +--- + +name: Locale.zh-CH.Form.Validator + +description: Form Validator messages for Chinese (simplified and traditional). + +license: MIT-style license + +authors: + - YMind Chan + +requires: + - Locale + - Form.Validator + +provides: [Form.zh-CH.Form.Validator, Form.Validator.CurrencyYuanValidator] + +... +*/ + +// Simplified Chinese +Locale.define('zh-CHS', 'FormValidator', { + + required: '此项必填。', + minLength: '请至少输入 {minLength} 个字符 (已输入 {length} 个)。', + maxLength: '最多只能输入 {maxLength} 个字符 (已输入 {length} 个)。', + integer: '请输入一个整数,不能包含小数点。例如:"1", "200"。', + numeric: '请输入一个数字,例如:"1", "1.1", "-1", "-1.1"。', + digits: '请输入由数字和标点符号组成的内容。例如电话号码。', + alpha: '请输入 A-Z 的 26 个字母,不能包含空格或任何其他字符。', + alphanum: '请输入 A-Z 的 26 个字母或 0-9 的 10 个数字,不能包含空格或任何其他字符。', + dateSuchAs: '请输入合法的日期格式,如:{date}。', + dateInFormatMDY: '请输入合法的日期格式,例如:YYYY-MM-DD ("2010-12-31")。', + email: '请输入合法的电子信箱地址,例如:"fred@domain.com"。', + url: '请输入合法的 Url 地址,例如:http://www.example.com。', + currencyDollar: '请输入合法的货币符号,例如:¥100.0', + oneRequired: '请至少选择一项。', + errorPrefix: '错误:', + warningPrefix: '警告:', + + // Form.Validator.Extras + noSpace: '不能包含空格。', + reqChkByNode: '未选择任何内容。', + requiredChk: '此项必填。', + reqChkByName: '请选择 {label}.', + match: '必须与{matchName}相匹配', + startDate: '起始日期', + endDate: '结束日期', + currentDate: '当前日期', + afterDate: '日期必须等于或晚于 {label}.', + beforeDate: '日期必须早于或等于 {label}.', + startMonth: '请选择起始月份', + sameMonth: '您必须修改两个日期中的一个,以确保它们在同一月份。', + creditcard: '您输入的信用卡号码不正确。当前已输入{length}个字符。' + +}); + +// Traditional Chinese +Locale.define('zh-CHT', 'FormValidator', { + + required: '此項必填。 ', + minLength: '請至少輸入{minLength} 個字符(已輸入{length} 個)。 ', + maxLength: '最多只能輸入{maxLength} 個字符(已輸入{length} 個)。 ', + integer: '請輸入一個整數,不能包含小數點。例如:"1", "200"。 ', + numeric: '請輸入一個數字,例如:"1", "1.1", "-1", "-1.1"。 ', + digits: '請輸入由數字和標點符號組成的內容。例如電話號碼。 ', + alpha: '請輸入AZ 的26 個字母,不能包含空格或任何其他字符。 ', + alphanum: '請輸入AZ 的26 個字母或0-9 的10 個數字,不能包含空格或任何其他字符。 ', + dateSuchAs: '請輸入合法的日期格式,如:{date}。 ', + dateInFormatMDY: '請輸入合法的日期格式,例如:YYYY-MM-DD ("2010-12-31")。 ', + email: '請輸入合法的電子信箱地址,例如:"fred@domain.com"。 ', + url: '請輸入合法的Url 地址,例如:http://www.example.com。 ', + currencyDollar: '請輸入合法的貨幣符號,例如:¥100.0', + oneRequired: '請至少選擇一項。 ', + errorPrefix: '錯誤:', + warningPrefix: '警告:', + + // Form.Validator.Extras + noSpace: '不能包含空格。 ', + reqChkByNode: '未選擇任何內容。 ', + requiredChk: '此項必填。 ', + reqChkByName: '請選擇 {label}.', + match: '必須與{matchName}相匹配', + startDate: '起始日期', + endDate: '結束日期', + currentDate: '當前日期', + afterDate: '日期必須等於或晚於{label}.', + beforeDate: '日期必須早於或等於{label}.', + startMonth: '請選擇起始月份', + sameMonth: '您必須修改兩個日期中的一個,以確保它們在同一月份。 ', + creditcard: '您輸入的信用卡號碼不正確。當前已輸入{length}個字符。 ' + +}); + +Form.Validator.add('validate-currency-yuan', { + + errorMsg: function(){ + return Form.Validator.getMsg('currencyYuan'); + }, + + 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')); + } + +}); + +/* +--- + +name: Locale.zh-CH.Number + +description: Number messages for for Chinese (simplified and traditional). + +license: MIT-style license + +authors: + - YMind Chan + +requires: + - Locale + - Locale.en-US.Number + +provides: [Locale.zh-CH.Number] + +... +*/ + +// Simplified Chinese +Locale.define('zh-CHS', 'Number', { + + currency: { + prefix: '¥ ' + } + +}).inherit('en-US', 'Number'); + +// Traditional Chinese +Locale.define('zh-CHT').inherit('zh-CHS', 'Number'); /* --- @@ -7680,6 +12750,57 @@ Request.JSONP = new Class({ Request.JSONP.counter = 0; Request.JSONP.request_map = {}; +/* +--- + +script: Request.Periodical.js + +name: Request.Periodical + +description: Requests the same URL to pull data from a server but increases the intervals if no data is returned to reduce the load + +license: MIT-style license + +authors: + - Christoph Pojer + +requires: + - Core/Request + - MooTools.More + +provides: [Request.Periodical] + +... +*/ + +Request.implement({ + + options: { + initialDelay: 5000, + delay: 5000, + limit: 60000 + }, + + startTimer: function(data){ + var fn = function(){ + if (!this.running) this.send({data: data}); + }; + this.lastDelay = this.options.initialDelay; + this.timer = fn.delay(this.lastDelay, this); + this.completeCheck = function(response){ + 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); + }; + return this.addEvent('complete', this.completeCheck); + }, + + stopTimer: function(){ + clearTimeout(this.timer); + return this.removeEvent('complete', this.completeCheck); + } + +}); /* --- @@ -7698,7 +12819,7 @@ authors: requires: - Core/Element - Core/Request - - /Class.Binds + - Class.Binds provides: [Request.Queue] @@ -7894,59 +13015,732 @@ Request.Queue = new Class({ }); - /* --- -script: Request.Periodical.js +script: Array.Extras.js -name: Request.Periodical +name: Array.Extras -description: Requests the same URL to pull data from a server but increases the intervals if no data is returned to reduce the load +description: Extends the Array native object to include useful methods to work with arrays. license: MIT-style license authors: - Christoph Pojer + - Sebastian Markbåge requires: - - Core/Request - - /MooTools.More + - Core/Array + - MooTools.More -provides: [Request.Periodical] +provides: [Array.Extras] ... */ -Request.implement({ +(function(nil){ - options: { - initialDelay: 5000, - delay: 5000, - limit: 60000 +Array.implement({ + + min: function(){ + return Math.min.apply(null, this); }, - startTimer: function(data){ - var fn = function(){ - if (!this.running) this.send({data: data}); - }; - this.lastDelay = this.options.initialDelay; - this.timer = fn.delay(this.lastDelay, this); - this.completeCheck = function(response){ - 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); - }; - return this.addEvent('complete', this.completeCheck); + max: function(){ + return Math.max.apply(null, this); }, - stopTimer: function(){ - clearTimeout(this.timer); - return this.removeEvent('complete', this.completeCheck); + average: function(){ + return this.length ? this.sum() / this.length : 0; + }, + + sum: function(){ + var result = 0, l = this.length; + if (l){ + while (l--){ + if (this[l] != null) result += parseFloat(this[l]); + } + } + return result; + }, + + unique: function(){ + return [].combine(this); + }, + + shuffle: function(){ + for (var i = this.length; i && --i;){ + var temp = this[i], r = Math.floor(Math.random() * ( i + 1 )); + this[i] = this[r]; + 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; + }, + + pluck: function(prop){ + return this.map(function(item){ + return item[prop]; + }); } }); +})(); + +/* +--- + +script: Date.Extras.js + +name: Date.Extras + +description: Extends the Date native object to include extra methods (on top of those in Date.js). + +license: MIT-style license + +authors: + - Aaron Newton + - Scott Kyle + +requires: + - Date + +provides: [Date.Extras] + +... +*/ + +Date.implement({ + + timeDiffInWords: function(to){ + return Date.distanceOfTimeInWords(this, to || new Date); + }, + + timeDiff: function(to, separator){ + if (to == null) to = new Date; + 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(separator || ':'); + } + +}).extend({ + + distanceOfTimeInWords: function(from, to){ + return Date.getTimePhrase(((to - from) / 1000).toInt()); + }, + + getTimePhrase: function(delta){ + var suffix = (delta < 0) ? 'Until' : 'Ago'; + if (delta < 0) delta *= -1; + + var units = { + minute: 60, + hour: 60, + day: 24, + week: 7, + month: 52 / 12, + year: 12, + eon: Infinity + }; + + var msg = 'lessThanMinute'; + + for (var unit in units){ + var interval = units[unit]; + if (delta < 1.5 * interval){ + if (delta > 0.75 * interval) msg = unit; + break; + } + delta /= interval; + msg = unit + 's'; + } + + delta = delta.round(); + return Date.getMsg(msg + suffix, delta).substitute({delta: delta}); + } + +}).defineParsers( + + { + // "today", "tomorrow", "yesterday" + re: /^(?:tod|tom|yes)/i, + handler: function(bits){ + var d = new Date().clearTime(); + switch (bits[0]){ + case 'tom': return d.increment(); + case 'yes': return d.decrement(); + default: return d; + } + } + }, + + { + // "next Wednesday", "last Thursday" + re: /^(next|last) ([a-z]+)$/i, + handler: function(bits){ + var d = new Date().clearTime(); + var day = d.getDay(); + var newDay = Date.parseDay(bits[2], true); + var addDays = newDay - day; + if (newDay <= day) addDays += 7; + if (bits[1] == 'last') addDays -= 7; + return d.set('date', d.getDate() + addDays); + } + } + +).alias('timeAgoInWords', 'timeDiffInWords'); + +/* +--- + +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); + } + +}); + +/* +--- +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; + }, + + formatCurrency: function(decimals){ + var locale = Locale.get('Number.currency') || {}; + if (locale.scientific == null) locale.scientific = false; + locale.decimals = decimals != null ? decimals + : (locale.decimals == null ? 2 : locale.decimals); + + return this.format(locale); + }, + + formatPercentage: function(decimals){ + var locale = Locale.get('Number.percentage') || {}; + if (locale.suffix == null) locale.suffix = '%'; + locale.decimals = decimals != null ? decimals + : (locale.decimals == null ? 2 : locale.decimals); + + return this.format(locale); + } + +}); + +/* +--- + +script: URI.js + +name: URI + +description: Provides methods useful in managing the window location and uris. + +license: MIT-style license + +authors: + - Sebastian Markbåge + - Aaron Newton + +requires: + - Core/Object + - Core/Class + - Core/Class.Extras + - Core/Element + - String.QueryString + +provides: [URI] + +... +*/ + +(function(){ + +var toString = function(){ + return this.get('value'); +}; + +var URI = this.URI = new Class({ + + Implements: Options, + + options: { + /*base: false*/ + }, + + regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/, + parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'], + schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0}, + + initialize: function(uri, options){ + this.setOptions(options); + var base = this.options.base || URI.base; + 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); + }, + + parse: function(value, base){ + var bits = value.match(this.regex); + if (!bits) return false; + bits.shift(); + return this.merge(bits.associate(this.parts), base); + }, + + merge: function(bits, base){ + if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false; + if (base){ + this.parts.every(function(part){ + if (bits[part]) return false; + bits[part] = base[part] || ''; + return true; + }); + } + bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()]; + bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/'; + return bits; + }, + + parseDirectory: function(directory, baseDirectory){ + directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory; + if (!directory.test(URI.regs.directoryDot)) return directory; + var result = []; + directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){ + if (dir == '..' && result.length > 0) result.pop(); + else if (dir != '.') result.push(dir); + }); + return result.join('/') + '/'; + }, + + combine: function(bits){ + return bits.value || bits.scheme + '://' + + (bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') + + (bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') + + (bits.directory || '/') + (bits.file || '') + + (bits.query ? '?' + bits.query : '') + + (bits.fragment ? '#' + bits.fragment : ''); + }, + + set: function(part, value, base){ + if (part == 'value'){ + var scheme = value.match(URI.regs.scheme); + if (scheme) scheme = scheme[1]; + 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'){ + this.setData(value); + } else { + this.parsed[part] = value; + } + return this; + }, + + get: function(part, base){ + switch (part){ + case 'value': return this.combine(this.parsed, base ? base.parsed : false); + case 'data' : return this.getData(); + } + return this.parsed[part] || ''; + }, + + go: function(){ + document.location.href = this.toString(); + }, + + toURI: function(){ + return this; + }, + + getData: function(key, part){ + var qs = this.get(part || 'query'); + 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'){ + var data = this.getData(); + data[arguments[0]] = arguments[1]; + values = data; + } else if (merge){ + values = Object.merge(this.getData(null, part), values); + } + return this.set(part || 'query', Object.toQueryString(values)); + }, + + clearData: function(part){ + return this.set(part || 'query', ''); + }, + + toString: toString, + valueOf: toString + +}); + +URI.regs = { + endSlash: /\/$/, + scheme: /^(\w+):/, + directoryDot: /\.\/|\.$/ +}; + +URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location}); + +String.implement({ + + toURI: function(options){ + return new URI(this, options); + } + +}); + +})(); + +/* +--- + +script: URI.Relative.js + +name: URI.Relative + +description: Extends the URI class to add methods for computing relative and absolute urls. + +license: MIT-style license + +authors: + - Sebastian Markbåge + + +requires: + - Class.refactor + - URI + +provides: [URI.Relative] + +... +*/ + +URI = Class.refactor(URI, { + + combine: function(bits, base){ + if (!base || bits.scheme != base.scheme || bits.host != base.host || bits.port != base.port) + return this.previous.apply(this, arguments); + var end = bits.file + (bits.query ? '?' + bits.query : '') + (bits.fragment ? '#' + bits.fragment : ''); + + if (!base.directory) return (bits.directory || (bits.file ? '' : './')) + end; + + var baseDir = base.directory.split('/'), + relDir = bits.directory.split('/'), + path = '', + 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] + '/'; + + return (path || (bits.file ? '' : './')) + end; + }, + + toAbsolute: function(base){ + base = new URI(base); + if (base) base.set('directory', '').set('file', ''); + return this.toRelative(base); + }, + + toRelative: function(base){ + return this.get('value', new URI(base)); + } + +}); /* --- @@ -7964,7 +13758,7 @@ authors: requires: - Core/Element.Event - - /MooTools.More + - MooTools.More provides: [Assets] @@ -7978,44 +13772,62 @@ var Asset = { 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(){}; + load = properties.onload || properties.onLoad; delete properties.onload; delete properties.onLoad; delete properties.document; - return script.addEvents({ - load: load, - readystatechange: function(){ - if (['loaded', 'complete'].contains(this.readyState)) load.call(this); + if (load){ + if (!script.addEventListener){ + script.addEvent('readystatechange', function(){ + if (['loaded', 'complete'].contains(this.readyState)) load.call(this); + }); + } else { + script.addEvent('load', load); } - }).set(properties).inject(doc.head); + } + + return script.set(properties).inject(doc.head); }, css: function(source, properties){ if (!properties) properties = {}; - var link = new Element('link', { - rel: 'stylesheet', - media: 'screen', - type: 'text/css', - href: source + var load = properties.onload || properties.onLoad, + doc = properties.document || document, + timeout = properties.timeout || 3000; + + ['onload', 'onLoad', 'document'].each(function(prop){ + delete properties[prop]; }); - var load = properties.onload || properties.onLoad, - doc = properties.document || document; + var link = new Element('link', { + type: 'text/css', + rel: 'stylesheet', + media: 'screen', + href: source + }).setProperties(properties).inject(doc.head); - delete properties.onload; - delete properties.onLoad; - delete properties.document; - - if (load) link.addEvent('load', load); - return link.set(properties).inject(doc.head); + if (load){ + // based on article at http://www.yearofmoo.com/2011/03/cross-browser-stylesheet-preloading.html + var loaded = false, retries = 0; + var check = function(){ + var stylesheets = document.styleSheets; + for (var i = 0; i < stylesheets.length; i++){ + var file = stylesheets[i]; + var owner = file.ownerNode ? file.ownerNode : file.owningElement; + if (owner && owner == link){ + loaded = true; + return load.call(link); + } + } + retries++; + if (!loaded && retries < timeout / 50) return setTimeout(check, 50); + } + setTimeout(check, 0); + } + return link; }, image: function(source, properties){ @@ -8080,7 +13892,6 @@ var Asset = { }; - /* --- @@ -8244,7 +14055,6 @@ String.implement({ })(); - /* --- @@ -8261,7 +14071,7 @@ authors: requires: - Core/Events - - /MooTools.More + - MooTools.More provides: [Group] @@ -8274,39 +14084,32 @@ this.Group = new Class({ initialize: function(){ this.instances = Array.flatten(arguments); - this.events = {}; - this.checker = {}; }, addEvent: function(type, fn){ - this.checker[type] = this.checker[type] || {}; - this.events[type] = this.events[type] || []; - 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.pass([type, instance, i], this)); - }, this); - return this; - }, + var instances = this.instances, + len = instances.length, + togo = len, + args = new Array(len), + self = this; - check: function(type, instance, i){ - this.checker[type][i] = true; - var every = this.instances.every(function(current, j){ - return this.checker[type][j] || false; - }, this); - if (!every) return; - this.checker[type] = {}; - this.events[type].each(function(event){ - event.call(this, this.instances, instance); - }, this); + instances.each(function(instance, i){ + instance.addEvent(type, function(){ + if (!args[i]) togo--; + args[i] = arguments; + if (!togo){ + fn.call(self, instances, instance, args); + togo = len; + args = new Array(len); + } + }); + }); } }); })(); - - /* --- @@ -8325,8 +14128,8 @@ authors: requires: - Core/Cookie - Core/JSON - - /MooTools.More - - /Hash + - MooTools.More + - Hash provides: [Hash.Cookie] @@ -8369,6 +14172,119 @@ Hash.each(Hash.prototype, function(method, name){ }); }); +/* +--- + +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: [Core/Options, Core/Object, Core/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 ('ActiveXObject' in window){ + 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); +}; + +})(); /* --- @@ -8427,1616 +14343,3 @@ var Table = this.Table = function(){ if (this.Type) new Type('Table', Table); })(); - - -/* ---- - -script: HtmlTable.js - -name: HtmlTable - -description: Builds table elements with methods to add rows. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - Core/Options - - Core/Events - - /Class.Occlude - -provides: [HtmlTable] - -... -*/ - -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 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(); - }, - - 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 = 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); - }, - - toElement: function(){ - return this.element; - }, - - empty: function(){ - this.body.empty(); - return this; - }, - - 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; - }, - - setFooters: function(footers){ - this.set('footers', footers); - return this; - }, - - 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 : {}), - 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, where).adopt(tds), - tds: tds - }; - } - -}); - - -['adopt', 'inject', 'wraps', 'grab', 'replaces', 'dispose'].each(function(method){ - HtmlTable.implement(method, function(){ - this.element[method].apply(this.element, arguments); - return this; - }); -}); - - - - -/* ---- - -script: HtmlTable.Zebra.js - -name: HtmlTable.Zebra - -description: Builds a stripy table with methods to add rows. - -license: MIT-style license - -authors: - - Harald Kirschner - - Aaron Newton - -requires: - - /HtmlTable - - /Class.refactor - -provides: [HtmlTable.Zebra] - -... -*/ - -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(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); - }, - - push: function(){ - var pushed = this.previous.apply(this, arguments); - if (this.options.zebra) this.updateZebras(); - return pushed; - } - -}); - - -/* ---- - -script: HtmlTable.Sort.js - -name: HtmlTable.Sort - -description: Builds a stripy, sortable table with methods to add rows. - -license: MIT-style license - -authors: - - Harald Kirschner - - Aaron Newton - - Jacob Thornton - -requires: - - Core/Hash - - /HtmlTable - - /Class.refactor - - /Element.Delegation - - /String.Extras - - /Date - -provides: [HtmlTable.Sort] - -... -*/ - -HtmlTable = Class.refactor(HtmlTable, { - - options: {/* - onSort: function(){}, */ - 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(attach){ - 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.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(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; - }, - - 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); - - for (rowIndex = 0; rowIndex < count; rowIndex++){ - if (data[rowIndex].position > position) data[rowIndex].position--; - } - } - }, - - 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.getParser(); - if (!parser) return; - - var rel; - if (!Browser.ie){ - rel = this.body.getParent(); - this.body.dispose(); - } - - 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 == (parser == HtmlTable.Parsers['input-checked'])) data.reverse(true); - this.setRowSort(data, pre); - - if (rel) rel.grab(this.body); - this.fireEvent('stateChanged'); - return this.fireEvent('sort', [this.body, this.sorted.index]); - }, - - 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); - }, - - 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(span){ - span.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 d = Date.parse(this.get('text').stripTags()); - return (typeOf(d) == 'date') ? d.format('db') : ''; - }, - type: 'date' - }, - 'input-checked': { - match: / type="(radio|checkbox)" /, - convert: function(){ - return this.getElement('input').checked; - } - }, - 'input-value': { - match: /= 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 - }); - - this.body[method]({ - '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 timer, held; - - var move = function(offset){ - var mover = function(e){ - clearTimeout(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(){ - 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)."; - } - - 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); - } - -}); - - -/* ---- - -script: Scroller.js - -name: Scroller - -description: Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries. - -license: MIT-style license - -authors: - - Valerio Proietti - -requires: - - Core/Events - - Core/Options - - Core/Element.Event - - Core/Element.Dimensions - - MooTools.More - -provides: [Scroller] - -... -*/ - -var Scroller = new Class({ - - Implements: [Events, Options], - - options: { - area: 20, - velocity: 1, - onChange: function(x, y){ - this.element.scrollTo(x, y); - }, - fps: 50 - }, - - initialize: function(element, options){ - this.setOptions(options); - this.element = document.id(element); - 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(event){ - this.page = (this.listener.get('tag') == 'body') ? event.client : event.page; - if (!this.timer) this.timer = this.scroll.periodical(Math.round(1000 / this.options.fps), this); - }, - - 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(), - change = {x: 0, y: 0}, - top = this.options.area.top || 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){ - 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]){ - change[z] = (this.page[z] - size[z] + bottom - pos[z]) * this.options.velocity; - } - change[z] = change[z].round(); - } - if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]); - } - -}); - - -/* ---- - -script: Tips.js - -name: Tips - -description: Class for creating nice tips that follow the mouse cursor when hovering an element. - -license: MIT-style license - -authors: - - Valerio Proietti - - Christoph Pojer - - Luis Merino - -requires: - - Core/Options - - Core/Events - - Core/Element.Event - - Core/Element.Style - - Core/Element.Dimensions - - /MooTools.More - -provides: [Tips] - -... -*/ - -(function(){ - -var read = function(option, element){ - return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : ''; -}; - -this.Tips = new Class({ - - Implements: [Events, Options], - - options: {/* - onAttach: function(element){}, - onDetach: function(element){}, - onBound: function(coords){},*/ - onShow: function(){ - this.tip.setStyle('display', 'block'); - }, - onHide: function(){ - this.tip.setStyle('display', 'none'); - }, - title: 'title', - text: function(element){ - return element.get('rel') || element.get('href'); - }, - showDelay: 100, - hideDelay: 100, - className: 'tip-wrap', - offset: {x: 16, y: 16}, - windowPadding: {x:0, y:0}, - fixed: false - }, - - initialize: function(){ - 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'}); - }, - - 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(elements){ - $$(elements).each(function(element){ - var title = read(this.options.title, element), - text = read(this.options.text, element); - - 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 = 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; - }, - - detach: function(elements){ - $$(elements).each(function(element){ - ['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){ - 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){ - 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; - if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event); - else this.fireForParent(event, element); - }, - - elementMove: function(event, element){ - this.position(event); - }, - - position: function(event){ - if (!this.tip) document.id(this); - - 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]] < 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); - else element.adopt(contents); - }, - - show: function(element){ - if (!this.tip) document.id(this); - if (!this.tip.getParent()) this.tip.inject(document.body); - this.fireEvent('show', [this.tip, element]); - }, - - hide: function(element){ - if (!this.tip) document.id(this); - this.fireEvent('hide', [this.tip, element]); - } - -}); - -})(); - - -/* ---- - -name: Locale.en-GB.Date - -description: Date messages for British English. - -license: MIT-style license - -authors: - - Aaron Newton - -requires: - - /Locale - - /Locale.en-US.Date - -provides: [Locale.en-GB.Date] - -... -*/ - -Locale.define('en-GB', 'Date', { - - // Culture's date order: DD/MM/YYYY - dateOrder: ['date', 'month', 'year'], - shortDate: '%d/%m/%Y', - shortTime: '%H:%M' - -}).inherit('en-US', 'Date'); - From b2f6bfb5fc9c951bf4d68e9505e19388ade2f9bf Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Wed, 15 Apr 2015 11:39:05 +1000 Subject: [PATCH 069/154] upgrade bundled jQuery (Closes: #785) Signed-off-by: Dmitry Smirnov --- .../classic/includes/export_functions.php | 2 +- web/skins/classic/js/jquery-1.4.2.min.js | 154 - web/skins/classic/js/jquery-1.7.2.js | 9404 +++++++++++++++++ web/skins/classic/js/jquery.js | 1 + web/skins/classic/js/jquery.url | 1 + 5 files changed, 9407 insertions(+), 155 deletions(-) delete mode 100644 web/skins/classic/js/jquery-1.4.2.min.js create mode 100644 web/skins/classic/js/jquery-1.7.2.js create mode 120000 web/skins/classic/js/jquery.js create mode 100644 web/skins/classic/js/jquery.url diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 1eddd54f6..76d079014 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -71,7 +71,7 @@ html ul.tabs li.active, html ul.tabs li.active a:hover { } --> - + + + Date: Fri, 1 May 2015 16:50:29 -0400 Subject: [PATCH 103/154] fix the css .js file name --- web/skins/classic/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index f13d0f77e..683f1a270 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -26,7 +26,7 @@ function xhtmlHeaders( $file, $title ) $skinJsFile = getSkinFile( 'js/skin.js' ); $skinJsPhpFile = getSkinFile( 'js/skin.js.php' ); - $cssJsFile = getSkinFile( 'js/'.$css.'/skin.js' ); + $cssJsFile = getSkinFile( 'js/'.$css.'.js' ); $basename = basename( $file, '.php' ); $viewCssFile = getSkinFile( '/css/'.$css.'/views/'.$basename.'.css' ); From 9ecc9349273184a3a892fb510524843217c67808 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 May 2015 16:50:44 -0400 Subject: [PATCH 104/154] add the new js files for classic flat skins --- web/skins/classic/js/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/skins/classic/js/Makefile.am b/web/skins/classic/js/Makefile.am index 22f944d9e..8ae05c93b 100644 --- a/web/skins/classic/js/Makefile.am +++ b/web/skins/classic/js/Makefile.am @@ -4,4 +4,6 @@ webdir = @WEB_PREFIX@/skins/classic/js dist_web_DATA = \ skin.js \ + classic.js \ + flat.js \ skin.js.php From cbbe40ea1cc5dc90a01dc523f59472b243edb5a2 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 7 May 2015 17:56:04 -0500 Subject: [PATCH 105/154] Update zoneminder.el7.spec Recent perl changes place the .packlist file under a different folder on CentOS 7 --- distros/redhat/zoneminder.el7.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.el7.spec b/distros/redhat/zoneminder.el7.spec index 33a9c3f30..31aabf6a7 100644 --- a/distros/redhat/zoneminder.el7.spec +++ b/distros/redhat/zoneminder.el7.spec @@ -156,7 +156,8 @@ fi %{_bindir}/zmx10.pl %{perl_vendorlib}/ZoneMinder* -%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder* +%{perl_vendorarch}/auto/ZoneMinder/.packlist +#%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder* #%{perl_archlib}/ZoneMinder* %{_mandir}/man*/* %dir %{_libexecdir}/zoneminder From e127228233262d5549591435ad80d5d80399eb53 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 7 May 2015 18:13:33 -0500 Subject: [PATCH 106/154] Update zoneminder.el7.spec some documentation was not being packaged and neither was the selinux policy file --- distros/redhat/zoneminder.el7.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.el7.spec b/distros/redhat/zoneminder.el7.spec index 31aabf6a7..63d7fe920 100644 --- a/distros/redhat/zoneminder.el7.spec +++ b/distros/redhat/zoneminder.el7.spec @@ -107,6 +107,8 @@ if [ $1 -eq 0 ] ; then # Package removal, not upgrade /bin/systemctl --no-reload disable zoneminder.service > /dev/null 2>&1 || : /bin/systemctl stop zoneminder.service > /dev/null 2>&1 || : + echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n" + /usr/sbin/semodule -r local_zoneminder.pp fi %postun @@ -128,7 +130,8 @@ fi %files %defattr(-,root,root,-) -%doc AUTHORS COPYING README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc +%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc +%doc distros/redhat/cambozola-doc distros/redhat/local_zoneminder.te %config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf %config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf %config(noreplace) /etc/tmpfiles.d/zoneminder.conf From c7c062267378c7fe7ee640fd10bcb74251e784dc Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 9 May 2015 12:10:12 -0500 Subject: [PATCH 107/154] rpmbuild incorrectly interprets the text "use standard" as a Perl module dependency. --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index a7f430aa2..2203570cd 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -725,8 +725,8 @@ our @options = calculation is extremely fast, however it limits the possible blend percentages to 50%, 25%, 12.5%, 6.25%, 3.25% and 1.5%. Any other blend percentage will be rounded to the nearest - possible one. The alternative is to switch this option off and - use standard blending instead, which is slower. + possible one. The alternative is to switch this option off + and use standard blending instead, which is slower. "), type => $types{boolean}, category => "config", From c7a50a7cbca3cd7cef4dd4ffd0600b7ffef6d4d7 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 9 May 2015 12:13:38 -0500 Subject: [PATCH 108/154] Replace newlines with a space --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 2203570cd..233d61948 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -173,8 +173,8 @@ our %types = ); sub qqq { ## Un-pad paragraph of text. - local $_=shift; - s{\n?^\s*}{}mg; + local $_ = shift; + s{\n?^\s*}{ }mg; return $_; } From 69ccd536536ce0bf81627c4bce5534110f397da6 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 9 May 2015 17:23:01 -0500 Subject: [PATCH 109/154] rollback mootools-core to 1.4.5-compat --- web/tools/mootools/Makefile.am | 6 +- ...1.5.1.js => mootools-core-1.4.5-compat.js} | 3157 +++++++++-------- 2 files changed, 1771 insertions(+), 1392 deletions(-) rename web/tools/mootools/{mootools-core-1.5.1.js => mootools-core-1.4.5-compat.js} (87%) diff --git a/web/tools/mootools/Makefile.am b/web/tools/mootools/Makefile.am index 8b31023a8..89b17ab8d 100644 --- a/web/tools/mootools/Makefile.am +++ b/web/tools/mootools/Makefile.am @@ -3,14 +3,14 @@ AUTOMAKE_OPTIONS = gnu webdir = @WEB_PREFIX@/tools/mootools dist_web_DATA = \ - mootools-core-1.5.1.js \ + mootools-core-1.4.5-compat.js \ mootools-more-1.5.1.js # Yes, you are correct. This is a HACK! install-data-hook: ( cd $(DESTDIR)$(webdir); rm -f mootools-core.js mootools-more.js ) - ( cd $(DESTDIR)$(webdir); ln -s mootools-core-1.5.1.js mootools-core.js ) - ( cd $(DESTDIR)$(webdir); ln -s mootools-more-1.5.1.js mootools-more.js ) + ( cd $(DESTDIR)$(webdir); ln -sf mootools-core-1.4.5-compat.js mootools-core.js ) + ( cd $(DESTDIR)$(webdir); ln -sf mootools-more-1.5.1.js mootools-more.js ) uninstall-hook: @-( cd $(DESTDIR)$(webdir); rm -f mootools-* ) diff --git a/web/tools/mootools/mootools-core-1.5.1.js b/web/tools/mootools/mootools-core-1.4.5-compat.js similarity index 87% rename from web/tools/mootools/mootools-core-1.5.1.js rename to web/tools/mootools/mootools-core-1.4.5-compat.js index e0bea6df6..574c9411a 100644 --- a/web/tools/mootools/mootools-core-1.5.1.js +++ b/web/tools/mootools/mootools-core-1.4.5-compat.js @@ -1,7 +1,16 @@ -/* MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2015 [Valerio Proietti](http://mad4milk.net/).*/ /* -Web Build: http://mootools.net/core/builder/e426a9ae7167c5807b173d5deff673fc +--- +MooTools: the javascript framework + +web build: + - http://mootools.net/core/76bf47062d6c1983d66ce47ad66aa0e0 + +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.Delegation 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 + +... */ + /* --- @@ -11,7 +20,7 @@ description: The heart of MooTools. license: MIT-style license. -copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/). +copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/). authors: The MooTools production team (http://mootools.net/developers/) @@ -23,12 +32,12 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native] ... */ -/*! MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/).*/ + (function(){ this.MooTools = { - version: '1.5.1', - build: '0542c135fdeb7feed7d9917e01447a408f22c876' + version: '1.4.5', + build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0' }; // typeOf, instanceOf @@ -41,7 +50,7 @@ var typeOf = this.typeOf = function(item){ if (item.nodeType == 1) return 'element'; if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace'; } else if (typeof item.length == 'number'){ - if ('callee' in item) return 'arguments'; + if (item.callee) return 'arguments'; if ('item' in item) return 'collection'; } @@ -165,7 +174,9 @@ var Type = this.Type = function(name, object){ object.prototype.$family = (function(){ return lower; }).hide(); - + //<1.2compat> + object.type = typeCheck; + // } } @@ -258,7 +269,7 @@ var force = function(name, object, methods){ if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){ fn.call(prototype, prototype[methods[i]], methods[i]); } - for (var key in prototype) fn.call(prototype, prototype[key], key); + for (var key in prototype) fn.call(prototype, prototype[key], key) }; } @@ -266,7 +277,7 @@ var force = function(name, object, methods){ }; force('String', String, [ - 'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', + 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase' ])('Array', Array, [ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', @@ -316,13 +327,11 @@ 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); @@ -400,10 +409,129 @@ String.extend('uniqueID', function(){ return (UID++).toString(36); }); +//<1.2compat> +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; +}); + +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'); + +Object.type = Type.isObject; + +var Native = this.Native = function(properties){ + return new Type(properties.name, properties.initialize); +}; + +Native.type = Type.type; + +Native.implement = function(objects, methods){ + for (var i = 0; i < objects.length; i++) objects[i].implement(methods); + return Native; +}; + +var arrayType = Array.type; +Array.type = function(item){ + return instanceOf(item, Array) || arrayType(item); +}; + +this.$A = function(item){ + return Array.from(item).slice(); +}; + +this.$arguments = function(i){ + return function(){ + return arguments[i]; + }; +}; + +this.$chk = function(obj){ + return !!(obj || obj === 0); +}; + +this.$clear = function(timer){ + clearTimeout(timer); + clearInterval(timer); + return null; +}; + +this.$defined = function(obj){ + return (obj != null); +}; + +this.$each = function(iterable, fn, bind){ + var type = typeOf(iterable); + ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind); +}; + +this.$empty = function(){}; + +this.$extend = function(original, extended){ + return Object.append(original, extended); +}; + +this.$H = function(object){ + return new Hash(object); +}; + +this.$merge = function(){ + var args = Array.slice(arguments); + args.unshift({}); + return Object.merge.apply(null, args); +}; + +this.$lambda = Function.from; +this.$mixin = Object.merge; +this.$random = Number.random; +this.$splat = Array.from; +this.$time = Date.now; + +this.$type = function(object){ + var type = typeOf(object); + if (type == 'elements') return 'array'; + return (type == 'null') ? false : type; +}; + +this.$unlink = function(object){ + switch (typeOf(object)){ + case 'object': return Object.clone(object); + case 'array': return Array.clone(object); + case 'hash': return new Hash(object); + default: return object; + } +}; + +// })(); + /* --- @@ -413,7 +541,7 @@ description: Contains Array Prototypes like each, contains, and erase. license: MIT-style license. -requires: [Type] +requires: Type provides: Array @@ -556,7 +684,7 @@ Array.implement({ if (this.length != 3) return null; var rgb = this.map(function(value){ if (value.length == 1) value += value; - return parseInt(value, 16); + return value.toInt(16); }); return (array) ? rgb : 'rgb(' + rgb + ')'; }, @@ -574,6 +702,153 @@ Array.implement({ }); +//<1.2compat> + +Array.alias('extend', 'append'); + +var $pick = function(){ + return Array.from(arguments).pick(); +}; + +// + + +/* +--- + +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 : String(this).indexOf(string) > -1; + }, + + trim: function(){ + return String(this).replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return String(this).replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return String(this).replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return String(this).replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return String(this).replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = String(this).match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + substitute: function(object, regexp){ + return String(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']); /* @@ -654,577 +929,57 @@ Function.implement({ }); +//<1.2compat> +delete Function.prototype.bind; -/* ---- +Function.implement({ -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))); + create: function(options){ + var self = this; + options = options || {}; + return function(event){ + var args = options.arguments; + args = (args != null) ? Array.from(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 Function.attempt(returns); + return returns(); }; - }); - Number.implement(methods); -})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); - -/* ---- - -name: String - -description: Contains String Prototypes like camelCase, capitalize, test, and toInt. - -license: MIT-style license. - -requires: [Type, Array] - -provides: String - -... -*/ - -String.implement({ - - // - contains: function(string, index){ - return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1; - }, - // - - test: function(regex, params){ - return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this); }, - trim: function(){ - return String(this).replace(/^\s+|\s+$/g, ''); - }, - - clean: function(){ - return String(this).replace(/\s+/g, ' ').trim(); - }, - - camelCase: function(){ - return String(this).replace(/-\D/g, function(match){ - return match.charAt(1).toUpperCase(); - }); - }, - - hyphenate: function(){ - return String(this).replace(/[A-Z]/g, function(match){ - return ('-' + match.charAt(0).toLowerCase()); - }); - }, - - capitalize: function(){ - return String(this).replace(/\b[a-z]/g, function(match){ - return match.toUpperCase(); - }); - }, - - escapeRegExp: function(){ - return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); - }, - - toInt: function(base){ - return parseInt(this, base || 10); - }, - - toFloat: function(){ - return parseFloat(this); - }, - - hexToRgb: function(array){ - var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - return (hex) ? hex.slice(1).hexToRgb(array) : null; - }, - - rgbToHex: function(array){ - var rgb = String(this).match(/\d{1,3}/g); - return (rgb) ? rgb.rgbToHex(array) : null; - }, - - substitute: function(object, regexp){ - return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ - if (match.charAt(0) == '\\') return match.slice(1); - return (object[name] != null) ? object[name] : ''; - }); - } - -}); - - - -/* ---- - -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 parse = function(ua, platform){ - ua = ua.toLowerCase(); - platform = (platform ? platform.toLowerCase() : ''); - - var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0]; - - if (UA[1] == 'trident'){ - UA[1] = 'ie'; - if (UA[4]) UA[2] = UA[4]; - } else if (UA[1] == 'crios'){ - UA[1] = 'chrome'; - } - - platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]; - if (platform == 'win') platform = 'windows'; - - return { - extend: Function.prototype.extend, - name: (UA[1] == 'version') ? UA[3] : UA[1], - version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]), - platform: platform - }; -}; - -var Browser = this.Browser = parse(navigator.userAgent, navigator.platform); - -if (Browser.name == 'ie'){ - Browser.version = document.documentMode; -} - -Browser.extend({ - Features: { - xpath: !!(document.evaluate), - air: !!(window.runtime), - query: !!(document.querySelector), - json: !!(window.JSON) - }, - parseUA: parse -}); - - - -// 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); - - - -// 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; - window = this.Window = document = 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)); + bind: function(bind, args){ + var self = this; + if (args != null) args = Array.from(args); + return function(){ + return self.apply(bind, args || arguments); }; - }); -} -/**/ - - - -})(); - -/* ---- - -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; + bindWithEvent: function(bind, args){ + var self = this; + if (args != null) args = Array.from(args); + return function(event){ + return self.apply(bind, (args == null) ? arguments : [event].concat(args)); + }; }, - callChain: function(){ - return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; - }, - - clearChain: function(){ - this.$chain.empty(); - return this; + run: function(args, bind){ + return this.apply(bind, Array.from(args)); } }); -var removeOn = function(string){ - return string.replace(/^on([A-Z])/, function(full, first){ - return first.toLowerCase(); - }); -}; +if (Object.create == Function.prototype.create) Object.create = null; -this.Events = new Class({ +var $try = Function.attempt; - $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; - } - -}); - -})(); /* --- @@ -1346,6 +1101,717 @@ Object.extend({ })(); +//<1.2compat> + +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] == null) 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.extend = Object.append; + +Hash.alias({indexOf: 'keyOf', contains: 'hasValue'}); + +// + + +/* +--- + +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 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)); + }; + }); +} +/**/ + +//<1.2compat> + +if (Browser.Platform.ios) Browser.Platform.ipod = true; + +Browser.Engine = {}; + +var setEngine = function(name, version){ + Browser.Engine.name = name; + Browser.Engine[name + version] = true; + Browser.Engine.version = version; +}; + +if (Browser.ie){ + Browser.Engine.trident = true; + + switch (Browser.version){ + case 6: setEngine('trident', 4); break; + case 7: setEngine('trident', 5); break; + case 8: setEngine('trident', 6); + } +} + +if (Browser.firefox){ + Browser.Engine.gecko = true; + + if (Browser.version >= 3) setEngine('gecko', 19); + else setEngine('gecko', 18); +} + +if (Browser.safari || Browser.chrome){ + Browser.Engine.webkit = true; + + switch (Browser.version){ + case 2: setEngine('webkit', 419); break; + case 3: setEngine('webkit', 420); break; + case 4: setEngine('webkit', 525); + } +} + +if (Browser.opera){ + Browser.Engine.presto = true; + + if (Browser.version >= 9.6) setEngine('presto', 960); + else if (Browser.version >= 9.5) setEngine('presto', 950); + else setEngine('presto', 925); +} + +if (Browser.name == 'unknown'){ + switch ((ua.match(/(?:webkit|khtml|gecko)/) || [])[0]){ + case 'webkit': + case 'khtml': + Browser.Engine.webkit = true; + break; + case 'gecko': + Browser.Engine.gecko = true; + } +} + +this.$exec = Browser.exec; + +// + +})(); + + +/* +--- + +name: Event + +description: Contains the Event Type, to make the event object cross-browser. + +license: MIT-style license. + +requires: [Window, Document, Array, Function, String, Object] + +provides: Event + +... +*/ + +(function() { + +var _keys = {}; + +var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ + if (!win) win = window; + event = event || win.event; + if (event.$extended) return event; + this.event = event; + this.$extended = true; + this.shift = event.shiftKey; + this.control = event.ctrlKey; + this.alt = event.altKey; + this.meta = event.metaKey; + var type = this.type = event.type; + var target = event.target || event.srcElement; + while (target && target.nodeType == 3) target = target.parentNode; + this.target = document.id(target); + + if (type.indexOf('key') == 0){ + var code = this.code = (event.which || event.keyCode); + this.key = _keys[code]/*<1.3compat>*/ || Object.keyOf(Event.Keys, code)/**/; + if (type == 'keydown'){ + if (code > 111 && code < 124) this.key = 'f' + (code - 111); + else if (code > 95 && code < 106) this.key = code - 96; + } + if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); + } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ + var doc = win.document; + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + this.page = { + x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, + y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop + }; + this.client = { + x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY + }; + if (type == 'DOMMouseScroll' || type == 'mousewheel') + this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + + this.rightClick = (event.which == 3 || event.button == 2); + if (type == 'mouseover' || type == 'mouseout'){ + var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; + while (related && related.nodeType == 3) related = related.parentNode; + this.relatedTarget = document.id(related); + } + } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ + 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]; + this.page = {x: touch.pageX, y: touch.pageY}; + this.client = {x: touch.clientX, y: touch.clientY}; + } + } + + if (!this.client) this.client = {}; + if (!this.page) this.page = {}; +}); + +DOMEvent.implement({ + + stop: function(){ + return this.preventDefault().stopPropagation(); + }, + + 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; + } + +}); + +DOMEvent.defineKey = function(code, key){ + _keys[code] = key; + return this; +}; + +DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); + +DOMEvent.defineKeys({ + '38': 'up', '40': 'down', '37': 'left', '39': 'right', + '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', + '46': 'delete', '13': 'enter' +}); + +})(); + +/*<1.3compat>*/ +var Event = DOMEvent; +Event.Keys = {}; +/**/ + +/*<1.2compat>*/ + +Event.Keys = new Hash(Event.Keys); + +/**/ + + +/* +--- + +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); + + /*<1.2compat>*/ + if (fn == $empty) return this; + /**/ + + 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; + } + +}); + +})(); /* @@ -1579,6 +2045,7 @@ if (!this.Slick) this.Slick = Slick; }).apply(/**/(typeof exports != 'undefined') ? exports : /**/this); + /* --- name: Slick.Finder @@ -1743,7 +2210,7 @@ local.setDocument = function(document){ // native matchesSelector function - features.nativeMatchesSelector = root.matches || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector; + 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'); @@ -1756,7 +2223,7 @@ local.setDocument = function(document){ root.slick_expando = 1; delete root.slick_expando; features.getUID = this.getUIDHTML; - } catch(e){ + } catch(e) { features.getUID = this.getUIDXML; } @@ -1777,9 +2244,9 @@ local.setDocument = function(document){ // hasAttribute - features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute){ + features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) { return node.hasAttribute(attribute); - } : function(node, attribute){ + } : function(node, attribute) { node = node.getAttributeNode(attribute); return !!(node && (node.specified || node.nodeValue)); }; @@ -1861,7 +2328,7 @@ local.search = function(context, expression, append, first){ /**/ var simpleSelector = expression.match(reSimpleSelector); - simpleSelectors: if (simpleSelector){ + simpleSelectors: if (simpleSelector) { var symbol = simpleSelector[1], name = simpleSelector[2], @@ -1914,7 +2381,7 @@ local.search = function(context, expression, append, first){ /**/ /**/ - querySelector: if (context.querySelectorAll){ + querySelector: if (context.querySelectorAll) { if (!this.isHTMLDocument || qsaFailExpCache[expression] @@ -1943,7 +2410,7 @@ local.search = function(context, expression, append, first){ try { if (first) return context.querySelector(_expression) || null; else nodes = context.querySelectorAll(_expression); - } catch(e){ + } catch(e) { qsaFailExpCache[expression] = 1; break querySelector; } finally { @@ -2142,14 +2609,14 @@ 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){} + } catch(matchError) {} } var parsed = this.Slick.parse(selector); if (!parsed) return true; // simple (single) selectors - var expressions = parsed.expressions, simpleExpCounter = 0, i, currentExpression; + var expressions = parsed.expressions, simpleExpCounter = 0, i; for (i = 0; (currentExpression = expressions[i]); i++){ if (currentExpression.length == 1){ var exp = currentExpression[0]; @@ -2565,6 +3032,7 @@ if (!this.Slick) this.Slick = Slick; }).apply(/**/(typeof exports != 'undefined') ? exports : /**/this); + /* --- @@ -2576,12 +3044,12 @@ license: MIT-style license. requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder] -provides: [Element, Elements, $, $$, IFrame, Selectors] +provides: [Element, Elements, $, $$, Iframe, Selectors] ... */ -var Element = this.Element = function(tag, props){ +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); @@ -2650,7 +3118,11 @@ if (!Browser.Element){ Element.Constructors = {}; +//<1.2compat> +Element.Constructors = new Hash; + +// var IFrame = new Type('IFrame', function(){ var params = Array.link(arguments, { @@ -2741,7 +3213,11 @@ new Type('Elements', Elements).implement({ }); +//<1.2compat> +Elements.alias('extend', 'append'); + +// (function(){ @@ -2765,7 +3241,7 @@ Array.mirror(Elements); /**/ var createElementAcceptsHTML; try { - createElementAcceptsHTML = (document.createElement('').name == 'x'); + createElementAcceptsHTML = (document.createElement('').name == 'x'); } catch (e){} var escapeQuotes = function(html){ @@ -2773,44 +3249,20 @@ var escapeQuotes = function(html){ }; /**/ -/**/ -// #2479 - IE8 Cannot set HTML of style element -var canChangeStyleHTML = (function(){ - var div = document.createElement('style'), - flag = false; - try { - div.innerHTML = '#justTesing{margin: 0px;}'; - flag = !!div.innerHTML; - } catch(e){} - return flag; -})(); -/**/ - Document.implement({ newElement: function(tag, props){ - if (props){ - if (props.checked != null) props.defaultChecked = props.checked; - if ((props.type == 'checkbox' || props.type == 'radio') && props.value == null) props.value = 'on'; - /**/ // IE needs the type to be set before changing content of style element - if (!canChangeStyleHTML && tag == 'style'){ - var styleElement = document.createElement('style'); - styleElement.setAttribute('type', 'text/css'); - if (props.type) delete props.type; - return this.id(styleElement).set(props); - } - /**/ - /**/// Fix for readonly name and type properties in IE < 8 - if (createElementAcceptsHTML){ - 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; - } - /**/ + 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); } @@ -2915,7 +3367,42 @@ var contains = {contains: function(element){ if (!document.contains) Document.implement(contains); if (!document.createElement('div').contains) Element.implement(contains); +//<1.2compat> +Element.implement('hasChild', function(element){ + return this !== element && this.contains(element); +}); + +(function(search, find, match){ + + this.Selectors = {}; + var pseudos = this.Selectors.Pseudo = new Hash(); + + var addSlickPseudos = function(){ + for (var name in pseudos) if (pseudos.hasOwnProperty(name)){ + Slick.definePseudo(name, pseudos[name]); + delete pseudos[name]; + } + }; + + Slick.search = function(context, expression, append){ + addSlickPseudos(); + return search.call(this, context, expression, append); + }; + + Slick.find = function(context, expression){ + addSlickPseudos(); + return find.call(this, context, expression); + }; + + Slick.match = function(node, selector){ + addSlickPseudos(); + return match.call(this, node, selector); + }; + +})(Slick.search, Slick.find, Slick.match); + +// // tree walking @@ -2981,7 +3468,23 @@ Element.implement({ }); +//<1.2compat> +if (window.$$ == null) Window.implement('$$', function(selector){ + var elements = new Elements; + if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements); + var args = Array.flatten(arguments); + for (var i = 0, l = args.length; i < l; i++){ + var item = args[i]; + switch (typeOf(item)){ + case 'element': elements.push(item); break; + case 'string': Slick.search(this.document, item, elements); + } + } + return elements; +}); + +// if (window.$$ == null) Window.implement('$$', function(selector){ if (arguments.length == 1){ @@ -3017,7 +3520,29 @@ var inserters = { inserters.inside = inserters.bottom; +//<1.2compat> +Object.each(inserters, function(inserter, where){ + + where = where.capitalize(); + + var methods = {}; + + methods['inject' + where] = function(el){ + inserter(this, document.id(el, true)); + return this; + }; + + methods['grab' + where] = function(el){ + inserter(document.id(el, true), this); + return this; + }; + + Element.implement(methods); + +}); + +// // getProperty / setProperty @@ -3045,21 +3570,6 @@ Object.forEach(properties, function(real, key){ }; }); -/**/ -propertySetters.text = (function(setter){ - return function(node, value){ - if (node.get('tag') == 'style') node.set('html', value); - else node[properties.text] = value; - }; -})(propertySetters.text); - -propertyGetters.text = (function(getter){ - return function(node){ - return (node.get('tag') == 'style') ? node.innerHTML : getter(node); - }; -})(propertyGetters.text); -/**/ - // Booleans var bools = [ @@ -3118,42 +3628,15 @@ el = null; /* */ /**/ - -/**/ -// #2479 - IE8 Cannot set HTML of style element -var canChangeStyleHTML = (function(){ - var div = document.createElement('style'), - flag = false; - try { - div.innerHTML = '#justTesing{margin: 0px;}'; - flag = !!div.innerHTML; - } catch(e){} - return flag; -})(); -/**/ - -var input = document.createElement('input'), volatileInputValue, html5InputSupport; - -// #2178 +var input = document.createElement('input'); input.value = 't'; input.type = 'submit'; -volatileInputValue = input.value != 't'; - -// #2443 - IE throws "Invalid Argument" when trying to use html5 input types -try { - input.type = 'email'; - html5InputSupport = input.type == 'email'; -} catch(e){} - -input = null; - -if (volatileInputValue || !html5InputSupport) propertySetters.type = function(node, type){ - try { - var value = node.value; - node.type = type; - node.value = value; - } catch (e){} +if (input.value != 't') propertySetters.type = function(node, type){ + var value = node.value; + node.type = type; + node.value = value; }; +input = null; /**/ /* getProperty, setProperty */ @@ -3164,28 +3647,7 @@ var pollutesGetAttribute = (function(div){ return (div.getAttribute('random') == 'attribute'); })(document.createElement('div')); -var hasCloneBug = (function(test){ - test.innerHTML = ''; - return test.cloneNode(true).firstChild.childNodes.length != 1; -})(document.createElement('div')); -/* */ - -var hasClassList = !!document.createElement('div').classList; - -var classes = function(className){ - var classNames = (className || '').clean().split(" "), uniques = {}; - return classNames.filter(function(className){ - if (className !== "" && !uniques[className]) return uniques[className] = className; - }); -}; - -var addToClassList = function(name){ - this.classList.add(name); -}; - -var removeFromClassList = function(name){ - this.classList.remove(name); -}; +/* */ Element.implement({ @@ -3195,8 +3657,7 @@ Element.implement({ setter(this, value); } else { /* */ - var attributeWhiteList; - if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {}); + if (pollutesGetAttribute) var attributeWhiteList = this.retrieve('$attributeWhiteList', {}); /* */ if (value == null){ @@ -3268,27 +3729,17 @@ Element.implement({ return this; }, - hasClass: hasClassList ? function(className){ - return this.classList.contains(className); - } : function(className){ - return classes(this.className).contains(className); + hasClass: function(className){ + return this.className.clean().contains(className, ' '); }, - addClass: hasClassList ? function(className){ - classes(className).forEach(addToClassList, this); - return this; - } : function(className){ - this.className = classes(className + ' ' + this.className).join(' '); + addClass: function(className){ + if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); return this; }, - removeClass: hasClassList ? function(className){ - classes(className).forEach(removeFromClassList, this); - return this; - } : function(className){ - var classNames = classes(this.className); - classes(className).forEach(classNames.erase, classNames); - this.className = classNames.join(' '); + removeClass: function(className){ + this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); return this; }, @@ -3363,37 +3814,6 @@ Element.implement({ }); - -// appendHTML - -var appendInserters = { - before: 'beforeBegin', - after: 'afterEnd', - bottom: 'beforeEnd', - top: 'afterBegin', - inside: 'beforeEnd' -}; - -Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){ - this.insertAdjacentHTML(appendInserters[where || 'bottom'], html); - return this; -} : function(html, where){ - var temp = new Element('div', {html: html}), - children = temp.childNodes, - fragment = temp.firstChild; - - if (!fragment) return this; - if (children.length > 1){ - fragment = document.createDocumentFragment(); - for (var i = 0, l = children.length; i < l; i++){ - fragment.appendChild(children[i]); - } - } - - inserters[where || 'bottom'](fragment, this); - return this; -}); - var collected = {}, storage = {}; var get = function(uid){ @@ -3459,7 +3879,7 @@ Element.implement({ } /**/ - if (hasCloneBug){ + if (Browser.ie){ var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object'); for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; } @@ -3472,7 +3892,13 @@ Element.implement({ [Element, Window, Document].invoke('implement', { addListener: function(type, fn){ - if (window.attachEvent && !window.addEventListener){ + if (type == 'unload'){ + var old = fn, self = this; + fn = function(){ + self.removeListener('unload', fn); + old(); + }; + } else { collected[Slick.uidOf(this)] = this; } if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]); @@ -3507,19 +3933,19 @@ Element.implement({ }); /**/ -if (window.attachEvent && !window.addEventListener){ - var gc = function(){ - Object.each(collected, clean); - if (window.CollectGarbage) CollectGarbage(); - window.removeListener('unload', gc); - } - window.addListener('unload', gc); -} +if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){ + Object.each(collected, clean); + if (window.CollectGarbage) CollectGarbage(); +}); /**/ Element.Properties = {}; +//<1.2compat> +Element.Properties = new Hash; + +// Element.Properties.style = { @@ -3550,24 +3976,20 @@ Element.Properties.html = { set: function(html){ if (html == null) html = ''; else if (typeOf(html) == 'array') html = html.join(''); - - /**/ - if (this.styleSheet && !canChangeStyleHTML) this.styleSheet.cssText = html; - else /**/this.innerHTML = html; + this.innerHTML = html; }, + erase: function(){ - this.set('html', ''); + this.innerHTML = ''; } }; -var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true; - /**/ // technique by jdbarlett - http://jdbartlett.com/innershiv/ var div = document.createElement('div'); div.innerHTML = ''; -supportsHTML5Elements = (div.childNodes.length == 1); +var supportsHTML5Elements = (div.childNodes.length == 1); if (!supportsHTML5Elements){ var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '), fragment = document.createDocumentFragment(), l = tags.length; @@ -3577,7 +3999,7 @@ div = null; /**/ /**/ -supportsTableInnerHTML = Function.attempt(function(){ +var supportsTableInnerHTML = Function.attempt(function(){ var table = document.createElement('table'); table.innerHTML = ''; return true; @@ -3586,7 +4008,7 @@ supportsTableInnerHTML = Function.attempt(function(){ /**/ var tr = document.createElement('tr'), html = ''; tr.innerHTML = html; -supportsTRInnerHTML = (tr.innerHTML == html); +var supportsTRInnerHTML = (tr.innerHTML == html); tr = null; /**/ @@ -3604,10 +4026,6 @@ if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){ translations.thead = translations.tfoot = translations.tbody; return function(html){ - - /**/ - if (this.styleSheet) return set.call(this, html); - /**/ var wrap = translations[this.get('tag')]; if (!wrap && !supportsHTML5Elements) wrap = [0, '', '']; if (!wrap) return set.call(this, html); @@ -3635,12 +4053,11 @@ if (testForm.firstChild.value != 's') Element.Properties.value = { var tag = this.get('tag'); if (tag != 'select') return this.setProperty('value', value); var options = this.getElements('option'); - value = String(value); for (var i = 0; i < options.length; i++){ var option = options[i], attr = option.getAttributeNode('value'), optionValue = (attr && attr.specified) ? option.value : option.get('text'); - if (optionValue === value) return option.selected = true; + if (optionValue == value) return option.selected = true; } }, @@ -3675,133 +4092,226 @@ if (document.createElement('div').getAttributeNode('id')) Element.Properties.id })(); + /* --- -name: Event +name: Element.Style -description: Contains the Event Type, to make the event object cross-browser. +description: Contains methods for interacting with the styles of Elements in a fashionable way. license: MIT-style license. -requires: [Window, Document, Array, Function, String, Object] +requires: Element -provides: Event +provides: Element.Style ... */ (function(){ -var _keys = {}; -var normalizeWheelSpeed = function(event){ - var normalized; - if (event.wheelDelta){ - normalized = event.wheelDelta % 120 == 0 ? event.wheelDelta / 120 : event.wheelDelta / 12; - } else { - var rawAmount = event.deltaY || event.detail || 0; - normalized = -(rawAmount % 3 == 0 ? rawAmount / 3 : rawAmount * 10); - } - return normalized; -} +var html = document.html; -var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ - if (!win) win = window; - event = event || win.event; - if (event.$extended) return event; - this.event = event; - this.$extended = true; - this.shift = event.shiftKey; - this.control = event.ctrlKey; - this.alt = event.altKey; - this.meta = event.metaKey; - var type = this.type = event.type; - var target = event.target || event.srcElement; - while (target && target.nodeType == 3) target = target.parentNode; - this.target = document.id(target); +// +// Check for oldIE, which does not remove styles when they're set to null +var el = document.createElement('div'); +el.style.color = 'red'; +el.style.color = null; +var doesNotRemoveStyles = el.style.color == 'red'; +el = null; +// - if (type.indexOf('key') == 0){ - var code = this.code = (event.which || event.keyCode); - this.key = _keys[code]; - if (type == 'keydown' || type == 'keyup'){ - if (code > 111 && code < 124) this.key = 'f' + (code - 111); - else if (code > 95 && code < 106) this.key = code - 96; - } - if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); - } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'wheel' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ - var doc = win.document; - doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; - this.page = { - x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, - y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop - }; - this.client = { - x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, - y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY - }; - if (type == 'DOMMouseScroll' || type == 'wheel' || type == 'mousewheel') this.wheel = normalizeWheelSpeed(event); - this.rightClick = (event.which == 3 || event.button == 2); - if (type == 'mouseover' || type == 'mouseout'){ - var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; - while (related && related.nodeType == 3) related = related.parentNode; - this.relatedTarget = document.id(related); - } - } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ - 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]; - this.page = {x: touch.pageX, y: touch.pageY}; - this.client = {x: touch.clientX, y: touch.clientY}; - } - } +Element.Properties.styles = {set: function(styles){ + this.setStyles(styles); +}}; - if (!this.client) this.client = {}; - if (!this.page) this.page = {}; -}); +var hasOpacity = (html.style.opacity != null), + hasFilter = (html.style.filter != null), + reAlpha = /alpha\(opacity=([\d.]+)\)/i; -DOMEvent.implement({ - - stop: function(){ - return this.preventDefault().stopPropagation(); - }, - - 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; - } - -}); - -DOMEvent.defineKey = function(code, key){ - _keys[code] = key; - return this; +var setVisibility = function(element, opacity){ + element.store('$opacity', opacity); + element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden'; }; -DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); +var setOpacity = (hasOpacity ? function(element, opacity){ + element.style.opacity = opacity; +} : (hasFilter ? function(element, opacity){ + var style = element.style; + if (!element.currentStyle || !element.currentStyle.hasLayout) style.zoom = 1; + if (opacity == null || opacity == 1) opacity = ''; + else opacity = 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')'; + var filter = style.filter || element.getComputedStyle('filter') || ''; + style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity; + if (!style.filter) style.removeAttribute('filter'); +} : setVisibility)); -DOMEvent.defineKeys({ - '38': 'up', '40': 'down', '37': 'left', '39': 'right', - '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', - '46': 'delete', '13': 'enter' +var getOpacity = (hasOpacity ? function(element){ + var opacity = element.style.opacity || element.getComputedStyle('opacity'); + return (opacity == '') ? 1 : opacity.toFloat(); +} : (hasFilter ? function(element){ + var filter = (element.style.filter || element.getComputedStyle('filter')), + opacity; + if (filter) opacity = filter.match(reAlpha); + return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); +} : function(element){ + var opacity = element.retrieve('$opacity'); + if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); + return opacity; +})); + +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; + }, + + setStyle: function(property, value){ + if (property == 'opacity'){ + if (value != null) value = parseFloat(value); + setOpacity(this, value); + return this; + } + property = (property == 'float' ? floatName : 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; + // + if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){ + this.style.removeAttribute(property); + } + // + return this; + }, + + getStyle: function(property){ + if (property == 'opacity') return getOpacity(this); + property = (property == 'float' ? floatName : 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){ + if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){ + 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.ie && (/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){ + 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: '@' +}; + +//<1.3compat> + +Element.implement({ + + setOpacity: function(value){ + setOpacity(this, value); + return this; + }, + + getOpacity: function(){ + return getOpacity(this); + } + +}); + +Element.Properties.opacity = { + + set: function(opacity){ + setOpacity(this, opacity); + setVisibility(this, opacity); + }, + + get: function(){ + return getOpacity(this); + } + +}; + +// + +//<1.2compat> + +Element.Styles = new Hash(Element.Styles); + +// + +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(@, @, @)'; }); })(); - - - /* --- @@ -3934,7 +4444,7 @@ Element.Properties.events = {set: function(events){ Element.NativeEvents = { click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons - wheel: 2, mousewheel: 2, DOMMouseScroll: 2, //mouse wheel + 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 @@ -3942,27 +4452,23 @@ Element.NativeEvents = { gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window - hashchange: 1, popstate: 2, // history - error: 1, abort: 1, scroll: 1, message: 2 //misc + error: 1, abort: 1, scroll: 1 //misc }; -Element.Events = { - mousewheel: { - base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll' - } -}; - -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 = {mousewheel: { + base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel' +}}; if ('onmouseenter' in document.documentElement){ Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2; - Element.MouseenterCheck = check; } else { + 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 @@ -3980,19 +4486,24 @@ if (!window.addEventListener){ Element.Events.change = { base: function(){ var type = this.type; - return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'; + return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change' }, condition: function(event){ - return event.type != 'propertychange' || event.event.propertyName == 'checked'; + return this.type != 'radio' || (event.event.propertyName == 'checked' && this.checked); } - }; + } } /**/ +//<1.2compat> +Element.Events = new Hash(Element.Events); + +// })(); + /* --- @@ -4024,12 +4535,10 @@ var bubbleUp = function(self, match, fn, event, target){ var map = { mouseenter: { - base: 'mouseover', - condition: Element.MouseenterCheck + base: 'mouseover' }, mouseleave: { - base: 'mouseout', - condition: Element.MouseenterCheck + base: 'mouseout' }, focus: { base: 'focus' + (eventListenerSupport ? '' : 'in'), @@ -4052,10 +4561,7 @@ var formObserver = function(type){ remove: function(self, uid){ var list = self.retrieve(_key + type + 'listeners', {})[uid]; if (list && list.forms) for (var i = list.forms.length; i--;){ - // the form may have been destroyed, so it won't have the - // removeEvent method anymore. In that case the event was - // removed as well. - if (list.forms[i].removeEvent) list.forms[i].removeEvent(type, list.fns[i]); + list.forms[i].removeEvent(type, list.fns[i]); } }, @@ -4139,8 +4645,8 @@ var delegation = { }; var elementEvent = Element.Events[_type]; - if (_map.condition || elementEvent && elementEvent.condition){ - var __match = match, condition = _map.condition || elementEvent.condition; + if (elementEvent && elementEvent.condition){ + var __match = match, condition = elementEvent.condition; match = function(target, event){ return __match(target, event) && condition.call(target, event, type); }; @@ -4175,7 +4681,7 @@ var delegation = { if (_map.remove) _map.remove(this, _uid); delete stored[_uid]; storage[_type] = stored; - return removeEvent.call(this, type, delegator, _map.capture); + return removeEvent.call(this, type, delegator); } var __uid, s; @@ -4198,237 +4704,6 @@ var delegation = { })(); -/* ---- - -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, el; - -// -// Check for oldIE, which does not remove styles when they're set to null -el = document.createElement('div'); -el.style.color = 'red'; -el.style.color = null; -var doesNotRemoveStyles = el.style.color == 'red'; - -// check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color) -var border = '1px solid #123abc'; -el.style.border = border; -var returnsBordersInWrongOrder = el.style.border != border; -el = null; -// - -var hasGetComputedStyle = !!window.getComputedStyle, - supportBorderRadius = document.createElement('div').style.borderRadius != null; - -Element.Properties.styles = {set: function(styles){ - this.setStyles(styles); -}}; - -var hasOpacity = (html.style.opacity != null), - hasFilter = (html.style.filter != null), - reAlpha = /alpha\(opacity=([\d.]+)\)/i; - -var setVisibility = function(element, opacity){ - element.store('$opacity', opacity); - element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden'; -}; - -// -var setFilter = function(element, regexp, value){ - var style = element.style, - filter = style.filter || element.getComputedStyle('filter') || ''; - style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim(); - if (!style.filter) style.removeAttribute('filter'); -}; -// - -var setOpacity = (hasOpacity ? function(element, opacity){ - element.style.opacity = opacity; -} : (hasFilter ? function(element, opacity){ - if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; - if (opacity == null || opacity == 1){ - setFilter(element, reAlpha, ''); - if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)'); - } else { - setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')'); - } -} : setVisibility)); - -var getOpacity = (hasOpacity ? function(element){ - var opacity = element.style.opacity || element.getComputedStyle('opacity'); - return (opacity == '') ? 1 : opacity.toFloat(); -} : (hasFilter ? function(element){ - var filter = (element.style.filter || element.getComputedStyle('filter')), - opacity; - if (filter) opacity = filter.match(reAlpha); - return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); -} : function(element){ - var opacity = element.retrieve('$opacity'); - if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); - return opacity; -})); - -var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat', - namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'}, - hasBackgroundPositionXY = (html.style.backgroundPositionX != null); - -// -var removeStyle = function(style, property){ - if (property == 'backgroundPosition'){ - style.removeAttribute(property + 'X'); - property += 'Y'; - } - style.removeAttribute(property); -}; -// - -Element.implement({ - - getComputedStyle: function(property){ - if (!hasGetComputedStyle && 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()) : ''; - }, - - setStyle: function(property, value){ - if (property == 'opacity'){ - if (value != null) value = parseFloat(value); - setOpacity(this, value); - return this; - } - property = (property == 'float' ? floatName : 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; - // - if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){ - removeStyle(this.style, property); - } - // - return this; - }, - - getStyle: function(property){ - if (property == 'opacity') return getOpacity(this); - property = (property == 'float' ? floatName : property).camelCase(); - if (supportBorderRadius && property.indexOf('borderRadius') != -1){ - return ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'].map(function(corner){ - return this.style[corner] || '0px'; - }, this).join(' '); - } - var result = this.style[property]; - if (!result || property == 'zIndex'){ - if (Element.ShortStyles.hasOwnProperty(property)){ - result = []; - for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s)); - return result.join(' '); - } - result = this.getComputedStyle(property); - } - if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){ - return result.replace(/(top|right|bottom|left)/g, function(position){ - return namedPositions[position]; - }) || '0px'; - } - if (!result && property == 'backgroundPosition') return '0px 0px'; - if (result){ - result = String(result); - var color = result.match(/rgba?\([\d\s,]+\)/); - if (color) result = result.replace(color[0], color[0].rgbToHex()); - } - if (!hasGetComputedStyle && !this.style[property]){ - if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){ - 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 ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){ - return '0px'; - } - } - // - if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){ - return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1'); - } - // - - 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(@, @, @)', backgroundSize: '@px', 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: '@', borderRadius: '@px @px @px @px' -}; - - - - - -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(@, @, @)'; -}); - -if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'}; -})(); /* --- @@ -4459,23 +4734,6 @@ element.appendChild(child); var brokenOffsetParent = (child.offsetParent === element); element = child = null; -var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'], - widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth']; - -var svgCalculateSize = function(el){ - - var gCS = window.getComputedStyle(el), - bounds = {x: 0, y: 0}; - - heightComponents.each(function(css){ - bounds.y += parseFloat(gCS[css]); - }); - widthComponents.each(function(css){ - bounds.x += parseFloat(gCS[css]); - }); - return bounds; -}; - var isOffset = function(el){ return styleString(el, 'position') != 'static' || isBody(el); }; @@ -4498,18 +4756,7 @@ Element.implement({ getSize: function(){ if (isBody(this)) return this.getWindow().getSize(); - - // - // This if clause is because IE8- cannot calculate getBoundingClientRect of elements with visibility hidden. - if (!window.getComputedStyle) return {x: this.offsetWidth, y: this.offsetHeight}; - // - - // This svg section under, calling `svgCalculateSize()`, can be removed when FF fixed the svg size bug. - // Bug info: https://bugzilla.mozilla.org/show_bug.cgi?id=530985 - if (this.get('tag') == 'svg') return svgCalculateSize(this); - - var bounds = this.getBoundingClientRect(); - return {x: bounds.width, y: bounds.height}; + return {x: this.offsetWidth, y: this.offsetHeight}; }, getScrollSize: function(){ @@ -4547,14 +4794,12 @@ Element.implement({ try { return element.offsetParent; - } catch(e){} + } catch(e) {} return null; }, getOffsets: function(){ - var hasGetBoundingClientRect = this.getBoundingClientRect; - - if (hasGetBoundingClientRect){ + if (this.getBoundingClientRect && !Browser.Platform.ios){ var bound = this.getBoundingClientRect(), html = document.id(this.getDocument().documentElement), htmlScroll = html.getScroll(), @@ -4563,7 +4808,7 @@ Element.implement({ 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 + y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop }; } @@ -4574,9 +4819,27 @@ Element.implement({ 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; }, @@ -4725,6 +4988,7 @@ Element.alias({position: 'setPosition'}); //compatability }); + /* --- @@ -4857,17 +5121,13 @@ var Fx = this.Fx = new Class({ }, resume: function(){ - if (this.isPaused()) pushInstance.call(this, this.options.fps); + 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); - }, - - isPaused: function(){ - return (this.frame < this.frames) && !this.isRunning(); } }); @@ -4909,6 +5169,7 @@ var pullInstance = function(fps){ })(); + /* --- @@ -4939,7 +5200,7 @@ Fx.CSS = new Class({ from = element.getStyle(property); var unit = this.options.unit; // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299 - if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){ + if (unit && from.slice(-unit.length) != unit && parseFloat(from) != 0){ element.setStyle(property, to + unit); var value = element.getComputedStyle(property); // IE and Opera support pixelLeft or pixelWidth @@ -5011,13 +5272,11 @@ Fx.CSS = new Class({ search: function(selector){ if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$'); - - var searchStyles = function(rules){ + 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.media){ - searchStyles(rule.rules || rule.cssRules); - return; - } if (!rule.style) return; var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ return m.toLowerCase(); @@ -5029,13 +5288,6 @@ Fx.CSS = new Class({ to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value; }); }); - }; - - Array.each(document.styleSheets, function(sheet, j){ - var href = sheet.href; - if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return; - var rules = sheet.rules || sheet.cssRules; - searchStyles(rules); }); return Fx.CSS.Cache[selector] = to; } @@ -5081,195 +5333,12 @@ Fx.CSS.Parsers = { }; +//<1.2compat> +Fx.CSS.Parsers = new Hash(Fx.CSS.Parsers); -/* ---- +// -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); - }); -}); /* --- @@ -5383,6 +5452,201 @@ Element.implement({ }); + +/* +--- + +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; + } + +}; + +//<1.2compat> + +Fx.Transitions = new Hash(Fx.Transitions); + +// + +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); + }); +}); + + /* --- @@ -5419,8 +5683,7 @@ var Request = this.Request = new Class({ onException: function(headerName, value){}, onTimeout: function(){}, user: '', - password: '', - withCredentials: false,*/ + password: '',*/ url: '', data: '', headers: { @@ -5458,10 +5721,7 @@ var Request = this.Request = new Class({ }.bind(this)); xhr.onreadystatechange = empty; if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; - if (this.timer){ - clearTimeout(this.timer); - delete this.timer; - } + clearTimeout(this.timer); this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML}; if (this.options.isSuccess.call(this, this.status)) @@ -5572,10 +5832,10 @@ var Request = this.Request = new Class({ if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); if (this.options.noCache) - url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID(); + url += (url.contains('?') ? '&' : '?') + String.uniqueID(); - if (data && (method == 'get' || method == 'delete')){ - url += (url.indexOf('?') > -1 ? '&' : '?') + data; + if (data && method == 'get'){ + url += (url.contains('?') ? '&' : '?') + data; data = null; } @@ -5586,7 +5846,7 @@ var Request = this.Request = new Class({ } xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password); - if ((this.options.withCredentials) && 'withCredentials' in xhr) xhr.withCredentials = true; + if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true; xhr.onreadystatechange = this.onStateChange.bind(this); @@ -5610,10 +5870,7 @@ var Request = this.Request = new Class({ this.running = false; var xhr = this.xhr; xhr.abort(); - if (this.timer){ - clearTimeout(this.timer); - delete this.timer; - } + clearTimeout(this.timer); xhr.onreadystatechange = empty; if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; this.xhr = new Browser.Request(); @@ -5624,7 +5881,7 @@ var Request = this.Request = new Class({ }); var methods = {}; -['get', 'post', 'put', 'delete', 'patch', 'head', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'].each(function(method){ +['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ methods[method] = function(data){ var object = { method: method @@ -5669,6 +5926,7 @@ Element.implement({ })(); + /* --- @@ -5758,6 +6016,7 @@ Element.implement({ }); + /* --- @@ -5778,7 +6037,14 @@ provides: JSON if (typeof JSON == 'undefined') this.JSON = {}; +//<1.2compat> +JSON = new Hash({ + stringify: JSON.stringify, + parse: JSON.parse +}); + +// (function(){ @@ -5820,14 +6086,10 @@ JSON.encode = JSON.stringify ? function(obj){ return null; }; -JSON.secure = true; - - JSON.decode = function(string, secure){ if (!string || typeOf(string) != 'string') return null; - - if (secure == null) secure = JSON.secure; - if (secure){ + + 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.'); } @@ -5837,6 +6099,7 @@ JSON.decode = function(string, secure){ })(); + /* --- @@ -5884,6 +6147,7 @@ Request.JSON = new Class({ }); + /* --- @@ -5959,6 +6223,7 @@ Cookie.dispose = function(key, options){ return new Cookie(key, options).dispose(); }; + /* --- @@ -5986,14 +6251,12 @@ var ready, var domready = function(){ clearTimeout(timer); - if (!ready) { - Browser.loaded = ready = true; - document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check); - document.fireEvent('domready'); - window.fireEvent('domready'); - } - // cleanup scope vars - document = window = testElement = null; + if (ready) return; + Browser.loaded = ready = true; + document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check); + + document.fireEvent('domready'); + window.fireEvent('domready'); }; var check = function(){ @@ -6066,3 +6329,119 @@ window.addEvent('load', function(){ }); })(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); +}; + +})(); + From 3a94712db20ea6e06b9381c05c152f958e235ab2 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 10 May 2015 08:10:30 -0500 Subject: [PATCH 110/154] add translate function --- web/ajax/log.php | 14 +- web/ajax/status.php | 2 +- web/includes/lang.php | 9 + web/skins/classic/includes/config.php | 10 +- .../classic/includes/control_functions.php | 56 ++--- .../classic/includes/export_functions.php | 68 +++--- web/skins/classic/views/bandwidth.php | 8 +- web/skins/classic/views/console.php | 54 ++--- web/skins/classic/views/control.php | 6 +- web/skins/classic/views/controlcap.php | 218 +++++++++--------- web/skins/classic/views/controlcaps.php | 38 +-- web/skins/classic/views/controlpreset.php | 10 +- web/skins/classic/views/cycle.php | 10 +- web/skins/classic/views/device.php | 10 +- web/skins/classic/views/devices.php | 14 +- web/skins/classic/views/donate.php | 26 +-- web/skins/classic/views/error.php | 10 +- web/skins/classic/views/event.php | 78 +++---- web/skins/classic/views/eventdetail.php | 14 +- web/skins/classic/views/events.php | 50 ++-- web/skins/classic/views/export.php | 30 +-- web/skins/classic/views/filter.php | 138 +++++------ web/skins/classic/views/filtersave.php | 12 +- web/skins/classic/views/frame.php | 18 +- web/skins/classic/views/frames.php | 18 +- web/skins/classic/views/function.php | 10 +- web/skins/classic/views/group.php | 12 +- web/skins/classic/views/groups.php | 24 +- web/skins/classic/views/js/event.js.php | 4 +- web/skins/classic/views/js/events.js.php | 2 +- web/skins/classic/views/js/export.js.php | 2 +- web/skins/classic/views/js/filter.js.php | 6 +- web/skins/classic/views/js/monitor.js.php | 66 +++--- web/skins/classic/views/js/montage.js.php | 10 +- web/skins/classic/views/js/options.js.php | 2 +- web/skins/classic/views/js/timeline.js.php | 2 +- web/skins/classic/views/js/video.js.php | 6 +- web/skins/classic/views/js/watch.js.php | 12 +- web/skins/classic/views/js/zone.js.php | 30 +-- web/skins/classic/views/log.php | 72 +++--- web/skins/classic/views/login.php | 10 +- web/skins/classic/views/logout.php | 10 +- web/skins/classic/views/monitor.php | 208 ++++++++--------- web/skins/classic/views/monitorpreset.php | 12 +- web/skins/classic/views/monitorprobe.php | 18 +- web/skins/classic/views/montage.php | 24 +- web/skins/classic/views/onvifprobe.php | 38 +-- web/skins/classic/views/optionhelp.php | 6 +- web/skins/classic/views/options.php | 80 +++---- web/skins/classic/views/plugin.php | 6 +- web/skins/classic/views/postlogin.php | 6 +- web/skins/classic/views/settings.php | 14 +- web/skins/classic/views/state.php | 24 +- web/skins/classic/views/stats.php | 26 +-- web/skins/classic/views/status.php | 4 +- web/skins/classic/views/timeline.php | 28 +-- web/skins/classic/views/user.php | 38 +-- web/skins/classic/views/version.php | 32 +-- web/skins/classic/views/video.php | 36 +-- web/skins/classic/views/watch.php | 56 ++--- web/skins/classic/views/zone.php | 48 ++-- web/skins/classic/views/zones.php | 18 +- web/skins/mobile/includes/config.php | 4 +- web/skins/mobile/views/console.php | 8 +- web/skins/mobile/views/devices.php | 10 +- web/skins/mobile/views/error.php | 8 +- web/skins/mobile/views/event.php | 4 +- web/skins/mobile/views/eventdetails.php | 22 +- web/skins/mobile/views/events.php | 16 +- web/skins/mobile/views/filter.php | 8 +- web/skins/mobile/views/frame.php | 4 +- web/skins/mobile/views/function.php | 6 +- web/skins/mobile/views/login.php | 10 +- web/skins/mobile/views/montage.php | 6 +- web/skins/mobile/views/state.php | 12 +- web/skins/mobile/views/video.php | 30 +-- web/skins/mobile/views/watch.php | 18 +- web/skins/xml/includes/config.php | 10 +- web/skins/xml/views/console.php | 14 +- 79 files changed, 1061 insertions(+), 1052 deletions(-) diff --git a/web/ajax/log.php b/web/ajax/log.php index 3dc3072ea..3decbd124 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -212,7 +212,7 @@ switch ( $_REQUEST['task'] ) } 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" ); + fprintf( $exportFP, translate('DateTime')."\t".translate('Component')."\t".translate('Pid')."\t".translate('Level')."\t".translate('Message')."\t".translate('File')."\t".translate('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'] ); @@ -225,7 +225,7 @@ switch ( $_REQUEST['task'] ) ' - '.$SLANG['ZoneMinderLog'].' + '.translate('ZoneMinderLog').' -

'.$SLANG['ZoneMinderLog'].'

+

'.translate('ZoneMinderLog').'

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

-

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

+

'.count($logs).' '.translate('Logs').'

- + ' ); foreach ( $logs as $log ) { @@ -288,7 +288,7 @@ tr.log-dbg td { { fwrite( $exportFP, ' - + '.$_POST['selector'].'' ); foreach ( $filter as $field=>$value ) if ( $value != '' ) @@ -298,7 +298,7 @@ tr.log-dbg td { ' ); fwrite( $exportFP, ' - '.$SLANG['DateTime'].''.$SLANG['Component'].''.$SLANG['Pid'].''.$SLANG['Level'].''.$SLANG['Message'].''.$SLANG['File'].''.$SLANG['Line'].' + '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' ' ); diff --git a/web/ajax/status.php b/web/ajax/status.php index b29460365..1cd5c766b 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -8,7 +8,7 @@ $statusData = array( "elements" => array( "MonitorCount" => array( "sql" => "count(*)" ), "ActiveMonitorCount" => array( "sql" => "count(if(Function != 'None',1,NULL))" ), - "State" => array( "func" => "daemonCheck()?".$SLANG['Running'].":".$SLANG['Stopped'] ), + "State" => array( "func" => "daemonCheck()?".translate('Running').":".translate('Stopped') ), "Load" => array( "func" => "getLoad()" ), "Disk" => array( "func" => "getDiskPercent()" ), ), diff --git a/web/includes/lang.php b/web/includes/lang.php index 94ebba530..30af6f4c0 100644 --- a/web/includes/lang.php +++ b/web/includes/lang.php @@ -18,6 +18,15 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +function translate( $name ) +{ + global $SLANG; + if ( array_key_exists( $name, $SLANG ) ) + return $SLANG[$name]; + else + return $name; +} + function loadLanguage( $prefix="" ) { global $user; diff --git a/web/skins/classic/includes/config.php b/web/skins/classic/includes/config.php index 9599c6112..d586f90c8 100644 --- a/web/skins/classic/includes/config.php +++ b/web/skins/classic/includes/config.php @@ -25,7 +25,7 @@ $rates = array( "1000" => "10x", "400" => "4x", "200" => "2x", - "100" => $SLANG['Real'], + "100" => translate('Real'), "50" => "1/2x", "25" => "1/4x", ); @@ -35,7 +35,7 @@ $scales = array( "300" => "3x", "200" => "2x", "150" => "1.5x", - "100" => $SLANG['Actual'], + "100" => translate('Actual'), "75" => "3/4x", "50" => "1/2x", "33" => "1/3x", @@ -43,9 +43,9 @@ $scales = array( ); $bwArray = array( - "high" => $SLANG['High'], - "medium" => $SLANG['Medium'], - "low" => $SLANG['Low'] + "high" => translate('High'), + "medium" => translate('Medium'), + "low" => translate('Low') ); switch ( $_COOKIE['zmBandwidth'] ) diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index 6fc2cd72b..02da3db17 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -142,17 +142,17 @@ function controlFocus( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -168,17 +168,17 @@ function controlZoom( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -193,17 +193,17 @@ function controlIris( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -219,17 +219,17 @@ function controlWhite( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -245,7 +245,7 @@ function controlPanTilt( $monitor, $cmds ) ob_start(); ?>
-
+
- +
- + - + @@ -326,25 +326,25 @@ function controlPower( $monitor, $cmds ) ob_start(); ?>
-
+
- + - + - + diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 76d079014..8d40d9ce0 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -106,11 +106,11 @@ function exportEventDetail( $event, $exportFrames, $exportImages ) global $SLANG; ob_start(); - exportHeader( $SLANG['Event']." ".$event['Id'] ); + exportHeader( translate('Event')." ".$event['Id'] ); $otherlinks = ''; - if( $exportFrames ) $otherlinks .= ''.$SLANG['Frames'].','; - if( $exportImages ) $otherlinks .= ''.$SLANG['Images'].','; + if( $exportFrames ) $otherlinks .= ''.translate('Frames').','; + if( $exportImages ) $otherlinks .= ''.translate('Images').','; $otherlinks = substr($otherlinks,0,-1); @@ -118,21 +118,21 @@ function exportEventDetail( $event, $exportFrames, $exportImages )
-

: ()

+

: ()

'.$SLANG['DateTime'].''.$SLANG['Component'].''.$SLANG['Pid'].''.$SLANG['Level'].''.$SLANG['Message'].''.$SLANG['File'].''.$SLANG['Line'].'
'.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
- - - - - - - - - - - - - + + + + + + + + + + + + +
()
()
@@ -150,30 +150,30 @@ function exportEventFrames( $event, $exportDetail, $exportImages ) $frames = dbFetchAll( $sql, NULL, array( $event['Id'] ) ); ob_start(); - exportHeader( $SLANG['Frames']." ".$event['Id'] ); + exportHeader( translate('Frames')." ".$event['Id'] ); $otherlinks = ''; - if( $exportDetail ) $otherlinks .= ''.$SLANG['Event'].','; - if( $exportImages ) $otherlinks .= ''.$SLANG['Images'].','; + if( $exportDetail ) $otherlinks .= ''.translate('Event').','; + if( $exportImages ) $otherlinks .= ''.translate('Images').','; $otherlinks = substr($otherlinks,0,-1); ?>
-

: ()

+

: ()

- - - - - + + + + + - + @@ -216,7 +216,7 @@ function exportEventFrames( $event, $exportDetail, $exportImages ) { ?> - + '.$SLANG['Event'].','; - if( $exportFrames ) $otherlinks .= ''.$SLANG['Frames'].','; + if( $exportDetail ) $otherlinks .= ''.translate('Event').','; + if( $exportFrames ) $otherlinks .= ''.translate('Frames').','; $otherlinks = substr($otherlinks,0,-1); $filelist = array_keys($myfilelist); @@ -259,7 +259,7 @@ function exportEventImages( $event, $exportDetail, $exportFrames, $myfilelist ) .value_display {background-color: #bbb;color: #333;width: 30px;margin: 0 2px;text-align: right;font-size: 8pt;font-face: verdana, arial, helvetica, sans-serif;font-weight: bold;line-height: 12px;border: 0;cursor: default;} -

: ()

+

: ()

@@ -593,10 +593,10 @@ function exportEventImagesMaster( $eids ) { global $SLANG; ob_start(); - exportHeader( $SLANG['Images'].' Master' ); + exportHeader( translate('Images').' Master' ); ?> -

Master

+

Master

-

+

- +
diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 048c9b772..67080b185 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -20,14 +20,14 @@ $eventCounts = array( array( - "title" => $SLANG['Events'], + "title" => translate('Events'), "filter" => array( "terms" => array( ) ), ), array( - "title" => $SLANG['Hour'], + "title" => translate('Hour'), "filter" => array( "terms" => array( array( "attr" => "DateTime", "op" => ">=", "val" => "-1 hour" ), @@ -35,7 +35,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Day'], + "title" => translate('Day'), "filter" => array( "terms" => array( array( "attr" => "DateTime", "op" => ">=", "val" => "-1 day" ), @@ -43,7 +43,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Week'], + "title" => translate('Week'), "filter" => array( "terms" => array( array( "attr" => "DateTime", "op" => ">=", "val" => "-7 day" ), @@ -51,7 +51,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Month'], + "title" => translate('Month'), "filter" => array( "terms" => array( array( "attr" => "DateTime", "op" => ">=", "val" => "-1 month" ), @@ -59,7 +59,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Archived'], + "title" => translate('Archived'), "filter" => array( "terms" => array( array( "attr" => "Archived", "op" => "=", "val" => "1" ), @@ -69,7 +69,7 @@ $eventCounts = array( ); $running = daemonCheck(); -$status = $running?$SLANG['Running']:$SLANG['Stopped']; +$status = $running?translate('Running'):translate('Stopped'); $group = NULL; if ( ! empty($_COOKIE['zmGroup']) ) { @@ -178,7 +178,7 @@ $seqDownFile = getSkinFile( 'graphics/seq-d.gif' ); $versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText':''; -xhtmlHeaders( __FILE__, $SLANG['Console'] ); +xhtmlHeaders( __FILE__, translate('Console') ); ?>
@@ -187,28 +187,28 @@ xhtmlHeaders( __FILE__, $SLANG['Console'] );
- - - + + + - + - + - + - + diff --git a/web/skins/classic/views/control.php b/web/skins/classic/views/control.php index 91a6654f1..4b979543c 100644 --- a/web/skins/classic/views/control.php +++ b/web/skins/classic/views/control.php @@ -53,15 +53,15 @@ $monitor = dbFetchOne( $sql, NULL, array( $mid ) ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Control'] ); +xhtmlHeaders(__FILE__, translate('Control') ); ?>
+ $SLANG['Local'], 'Remote'=>$SLANG['Remote'], 'Ffmpeg'=>$SLANG['Ffmpeg'], 'Libvlc'=>$SLANG['Libvlc'], 'cURL'=>"cURL"); + $types = array( 'Local'=>translate('Local'), 'Remote'=>translate('Remote'), 'Ffmpeg'=>translate('Ffmpeg'), 'Libvlc'=>translate('Libvlc'), 'cURL'=>"cURL"); ?> - - - - - + + + + + - - - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + +
- - - + + +
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked">
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
- disabled="disabled"/> + disabled="disabled"/>
diff --git a/web/skins/classic/views/controlcaps.php b/web/skins/classic/views/controlcaps.php index 560efc432..517f8141e 100644 --- a/web/skins/classic/views/controlcaps.php +++ b/web/skins/classic/views/controlcaps.php @@ -28,15 +28,15 @@ $controls = dbFetchAll( 'SELECT * FROM Controls ORDER BY Id' ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['ControlCaps'] ); +xhtmlHeaders(__FILE__, translate('ControlCaps') ); ?>
@@ -45,16 +45,16 @@ xhtmlHeaders(__FILE__, $SLANG['ControlCaps'] ); - - - - - - - - - - + + + + + + + + + + @@ -66,11 +66,11 @@ foreach( $controls as $control ) - - - - - + + + + + @@ -80,7 +80,7 @@ foreach( $controls as $control )
disabled="disabled"/>
- disabled="disabled"/> + disabled="disabled"/>
diff --git a/web/skins/classic/views/controlpreset.php b/web/skins/classic/views/controlpreset.php index 59c96db66..a36d03db9 100644 --- a/web/skins/classic/views/controlpreset.php +++ b/web/skins/classic/views/controlpreset.php @@ -34,7 +34,7 @@ foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, a $presets = array(); for ( $i = 1; $i <= $monitor['NumPresets']; $i++ ) { - $presets[$i] = $SLANG['Preset']." ".$i; + $presets[$i] = translate('Preset')." ".$i; if ( !empty($labels[$i]) ) { $presets[$i] .= " (".validHtmlStr($labels[$i]).")"; @@ -44,12 +44,12 @@ for ( $i = 1; $i <= $monitor['NumPresets']; $i++ ) $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['SetPreset'] ); +xhtmlHeaders(__FILE__, translate('SetPreset') ); ?>
@@ -59,9 +59,9 @@ xhtmlHeaders(__FILE__, $SLANG['SetPreset'] );

-

+

- +
diff --git a/web/skins/classic/views/cycle.php b/web/skins/classic/views/cycle.php index b574925e7..a49e43953 100644 --- a/web/skins/classic/views/cycle.php +++ b/web/skins/classic/views/cycle.php @@ -87,20 +87,20 @@ noCacheHeaders(); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['CycleWatch'] ); +xhtmlHeaders(__FILE__, translate('CycleWatch') ); ?>
diff --git a/web/skins/classic/views/device.php b/web/skins/classic/views/device.php index 41096fd72..4b58d3e5f 100644 --- a/web/skins/classic/views/device.php +++ b/web/skins/classic/views/device.php @@ -33,12 +33,12 @@ if ( !empty($_REQUEST['did']) ) { ); } -xhtmlHeaders( __FILE__, $SLANG['Device']." - ".$newDevice['Name'] ); +xhtmlHeaders( __FILE__, translate('Device')." - ".$newDevice['Name'] ); ?>
@@ -48,17 +48,17 @@ xhtmlHeaders( __FILE__, $SLANG['Device']." - ".$newDevice['Name'] ); - + - +
- disabled="disabled"/> + disabled="disabled"/>
diff --git a/web/skins/classic/views/devices.php b/web/skins/classic/views/devices.php index 90efca19d..c2f7a384f 100644 --- a/web/skins/classic/views/devices.php +++ b/web/skins/classic/views/devices.php @@ -32,12 +32,12 @@ foreach( dbFetchAll( $sql ) as $row ) $devices[] = $row; } -xhtmlHeaders(__FILE__, $SLANG['Devices'] ); +xhtmlHeaders(__FILE__, translate('Devices') ); ?>
@@ -65,8 +65,8 @@ foreach( $devices as $device ) ?> '.validHtmlStr($device['Name']).' ('.validHtmlStr($device['KeyString']).')', canEdit( 'Devices' ) ) ?> - onclick="switchDeviceOn( this, '' )"/> - onclick="switchDeviceOff( this, '' )"/> + onclick="switchDeviceOn( this, '' )"/> + onclick="switchDeviceOff( this, '' )"/> disabled="disabled"/>
- /> - - + /> + +
diff --git a/web/skins/classic/views/donate.php b/web/skins/classic/views/donate.php index ce37ee0bf..35dd002a1 100644 --- a/web/skins/classic/views/donate.php +++ b/web/skins/classic/views/donate.php @@ -25,38 +25,38 @@ if ( !canEdit( 'System' ) ) } $options = array( - "go" => $SLANG['DonateYes'], - "hour" => $SLANG['DonateRemindHour'], - "day" => $SLANG['DonateRemindDay'], - "week" => $SLANG['DonateRemindWeek'], - "month" => $SLANG['DonateRemindMonth'], - "never" => $SLANG['DonateRemindNever'], - "already" => $SLANG['DonateAlready'], + "go" => translate('DonateYes'), + "hour" => translate('DonateRemindHour'), + "day" => translate('DonateRemindDay'), + "week" => translate('DonateRemindWeek'), + "month" => translate('DonateRemindMonth'), + "never" => translate('DonateRemindNever'), + "already" => translate('DonateAlready'), ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Donate'] ); +xhtmlHeaders(__FILE__, translate('Donate') ); ?>

- +

- - + +
diff --git a/web/skins/classic/views/error.php b/web/skins/classic/views/error.php index c2d2a3009..21741c557 100644 --- a/web/skins/classic/views/error.php +++ b/web/skins/classic/views/error.php @@ -20,22 +20,22 @@ $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Error'] ); +xhtmlHeaders(__FILE__, translate('Error') ); ?>

- +

- +

- +

diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index bc01267f1..a0b97e35e 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -47,9 +47,9 @@ else $scale = reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); $replayModes = array( - 'single' => $SLANG['ReplaySingle'], - 'all' => $SLANG['ReplayAll'], - 'gapless' => $SLANG['ReplayGapless'], + 'single' => translate('ReplaySingle'), + 'all' => translate('ReplayAll'), + 'gapless' => translate('ReplayGapless'), ); if ( isset( $_REQUEST['streamMode'] ) ) @@ -78,7 +78,7 @@ $connkey = generateConnKey(); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Event'] ); +xhtmlHeaders(__FILE__, translate('Event') ); ?>
@@ -86,52 +86,52 @@ xhtmlHeaders(__FILE__, $SLANG['Event'] );
- - - - - - + + + + + +
s">/">//s">/">//

- - - - - - - - - + + + + + + + + +

- :   - : x - : s - : x + :   + : x + : s + : x
diff --git a/web/skins/classic/views/eventdetail.php b/web/skins/classic/views/eventdetail.php index e3a1bcd94..e6b02aec5 100644 --- a/web/skins/classic/views/eventdetail.php +++ b/web/skins/classic/views/eventdetail.php @@ -61,9 +61,9 @@ else $focusWindow = true; if ( $mode == 'single' ) - xhtmlHeaders(__FILE__, $SLANG['Event']." - ".$eid ); + xhtmlHeaders(__FILE__, translate('Event')." - ".$eid ); else - xhtmlHeaders(__FILE__, $SLANG['Events'] ); + xhtmlHeaders(__FILE__, translate('Events') ); ?>
@@ -72,13 +72,13 @@ else if ( $mode == 'single' ) { ?> -

+

-

+

@@ -112,17 +112,17 @@ elseif ( $mode = 'multi' ) - + - +
- disabled="disabled"/> + disabled="disabled"/>
diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 59403c76b..7d0669177 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -114,7 +114,7 @@ $pagination = getPagination( $pages, $page, $maxShortcuts, $filterQuery.$sortQue $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Events'] ); +xhtmlHeaders(__FILE__, translate('Events') ); ?> @@ -127,18 +127,18 @@ if ( $pages > 1 ) if ( !empty($page) ) { ?> - + - + - +

@@ -160,9 +160,9 @@ if ( $pagination ) } ?>

- - - + + +

@@ -174,22 +174,22 @@ foreach ( $events as $event ) { ?> - - - - - - - - - - - + + + + + + + + + + + - + @@ -246,12 +246,12 @@ if ( true || canEdit( 'Events' ) ) { ?>
- - - - - - + + + + + +
@@ -78,54 +78,54 @@ elseif ( !empty($_REQUEST['eids']) )
- + - + - + - + - + - +
checked="checked" onclick="configureExportButton( this )"/>
checked="checked" onclick="configureExportButton( this )"/>
checked="checked" onclick="configureExportButton( this )"/>
checked="checked" onclick="configureExportButton( this )"/>
checked="checked" onclick="configureExportButton( this )"/>
- checked="checked" onclick="configureExportButton( this )"/> - checked="checked" onclick="configureExportButton( this )"/> + checked="checked" onclick="configureExportButton( this )"/> + checked="checked" onclick="configureExportButton( this )"/>
- +
-

+

- + - + diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 9fadd1a4c..1c7c6e270 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -24,7 +24,7 @@ if ( !canView( 'Events' ) ) return; } $selectName = "filterName"; -$filterNames = array( ''=>$SLANG['ChooseFilter'] ); +$filterNames = array( ''=>translate('ChooseFilter') ); foreach ( dbFetchAll( "select * from Filters order by Name" ) as $row ) { $filterNames[$row['Name']] = $row['Name']; @@ -38,7 +38,7 @@ $backgroundStr = ""; if ( isset($dbFilter) ) { if ( $dbFilter['Background'] ) - $backgroundStr = '['.strtolower($SLANG['Background']).']'; + $backgroundStr = '['.strtolower(translate('Background')).']'; $_REQUEST['filter'] = jsonDecode( $dbFilter['Query'] ); $_REQUEST['sort_field'] = isset($_REQUEST['filter']['sort_field'])?$_REQUEST['filter']['sort_field']:"DateTime"; $_REQUEST['sort_asc'] = isset($_REQUEST['filter']['sort_asc'])?$_REQUEST['filter']['sort_asc']:"1"; @@ -49,8 +49,8 @@ if ( isset($dbFilter) ) } $conjunctionTypes = array( - 'and' => $SLANG['ConjAnd'], - 'or' => $SLANG['ConjOr'] + 'and' => translate('ConjAnd'), + 'or' => translate('ConjOr') ); $obracketTypes = array(); $cbracketTypes = array(); @@ -64,42 +64,42 @@ if ( isset($_REQUEST['filter']['terms']) ) } $attrTypes = array( - 'MonitorId' => $SLANG['AttrMonitorId'], - 'MonitorName' => $SLANG['AttrMonitorName'], - 'Id' => $SLANG['AttrId'], - 'Name' => $SLANG['AttrName'], - 'Cause' => $SLANG['AttrCause'], - 'Notes' => $SLANG['AttrNotes'], - 'DateTime' => $SLANG['AttrDateTime'], - 'Date' => $SLANG['AttrDate'], - 'Time' => $SLANG['AttrTime'], - 'Weekday' => $SLANG['AttrWeekday'], - 'Length' => $SLANG['AttrDuration'], - 'Frames' => $SLANG['AttrFrames'], - 'AlarmFrames' => $SLANG['AttrAlarmFrames'], - 'TotScore' => $SLANG['AttrTotalScore'], - 'AvgScore' => $SLANG['AttrAvgScore'], - 'MaxScore' => $SLANG['AttrMaxScore'], - 'Archived' => $SLANG['AttrArchiveStatus'], - 'DiskPercent' => $SLANG['AttrDiskPercent'], - 'DiskBlocks' => $SLANG['AttrDiskBlocks'], - 'SystemLoad' => $SLANG['AttrSystemLoad'], + 'MonitorId' => translate('AttrMonitorId'), + 'MonitorName' => translate('AttrMonitorName'), + 'Id' => translate('AttrId'), + 'Name' => translate('AttrName'), + 'Cause' => translate('AttrCause'), + 'Notes' => translate('AttrNotes'), + 'DateTime' => translate('AttrDateTime'), + 'Date' => translate('AttrDate'), + 'Time' => translate('AttrTime'), + 'Weekday' => translate('AttrWeekday'), + 'Length' => translate('AttrDuration'), + 'Frames' => translate('AttrFrames'), + 'AlarmFrames' => translate('AttrAlarmFrames'), + 'TotScore' => translate('AttrTotalScore'), + 'AvgScore' => translate('AttrAvgScore'), + 'MaxScore' => translate('AttrMaxScore'), + 'Archived' => translate('AttrArchiveStatus'), + 'DiskPercent' => translate('AttrDiskPercent'), + 'DiskBlocks' => translate('AttrDiskBlocks'), + 'SystemLoad' => translate('AttrSystemLoad'), ); $opTypes = array( - '=' => $SLANG['OpEq'], - '!=' => $SLANG['OpNe'], - '>=' => $SLANG['OpGtEq'], - '>' => $SLANG['OpGt'], - '<' => $SLANG['OpLt'], - '<=' => $SLANG['OpLtEq'], - '=~' => $SLANG['OpMatches'], - '!~' => $SLANG['OpNotMatches'], - '=[]' => $SLANG['OpIn'], - '![]' => $SLANG['OpNotIn'], + '=' => translate('OpEq'), + '!=' => translate('OpNe'), + '>=' => translate('OpGtEq'), + '>' => translate('OpGt'), + '<' => translate('OpLt'), + '<=' => translate('OpLtEq'), + '=~' => translate('OpMatches'), + '!~' => translate('OpNotMatches'), + '=[]' => translate('OpIn'), + '![]' => translate('OpNotIn'), ); $archiveTypes = array( - '0' => $SLANG['ArchUnarchived'], - '1' => $SLANG['ArchArchived'] + '0' => translate('ArchUnarchived'), + '1' => translate('ArchArchived') ); $weekdays = array(); for ( $i = 0; $i < 7; $i++ ) @@ -107,22 +107,22 @@ for ( $i = 0; $i < 7; $i++ ) $weekdays[$i] = strftime( "%A", mktime( 12, 0, 0, 1, $i+1, 2001 ) ); } $sort_fields = array( - 'Id' => $SLANG['AttrId'], - 'Name' => $SLANG['AttrName'], - 'Cause' => $SLANG['AttrCause'], - 'Notes' => $SLANG['AttrNotes'], - 'MonitorName' => $SLANG['AttrMonitorName'], - 'DateTime' => $SLANG['AttrDateTime'], - 'Length' => $SLANG['AttrDuration'], - 'Frames' => $SLANG['AttrFrames'], - 'AlarmFrames' => $SLANG['AttrAlarmFrames'], - 'TotScore' => $SLANG['AttrTotalScore'], - 'AvgScore' => $SLANG['AttrAvgScore'], - 'MaxScore' => $SLANG['AttrMaxScore'], + 'Id' => translate('AttrId'), + 'Name' => translate('AttrName'), + 'Cause' => translate('AttrCause'), + 'Notes' => translate('AttrNotes'), + 'MonitorName' => translate('AttrMonitorName'), + 'DateTime' => translate('AttrDateTime'), + 'Length' => translate('AttrDuration'), + 'Frames' => translate('AttrFrames'), + 'AlarmFrames' => translate('AttrAlarmFrames'), + 'TotScore' => translate('AttrTotalScore'), + 'AvgScore' => translate('AttrAvgScore'), + 'MaxScore' => translate('AttrMaxScore'), ); $sort_dirns = array( - '1' => $SLANG['SortAsc'], - '0' => $SLANG['SortDesc'] + '1' => translate('SortAsc'), + '0' => translate('SortDesc') ); if ( empty($_REQUEST['sort_field']) ) { @@ -134,15 +134,15 @@ $hasCal = file_exists( 'tools/jscalendar/calendar.js' ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['EventFilter'] ); +xhtmlHeaders(__FILE__, translate('EventFilter') ); ?>
@@ -155,7 +155,7 @@ xhtmlHeaders(__FILE__, $SLANG['EventFilter'] );
-
1 ) { echo buildSelect( $selectName, $filterNames, "submitToFilter( this, 1 );" ); } else { ?>
+
1 ) { echo buildSelect( $selectName, $filterNames, "submitToFilter( this, 1 );" ); } else { ?>

@@ -186,7 +186,7 @@ for ( $i = 0; isset($_REQUEST['filter']) && $i < count($_REQUEST['filter']['term if ( $_REQUEST['filter']['terms'][$i]['attr'] == "Archived" ) { ?> - + - - + +
"/>"/>
@@ -263,7 +263,7 @@ for ( $i = 0; isset($_REQUEST['filter']) && $i < count($_REQUEST['filter']['term - + - + - + - + - + - + - +
checked="checked" onclick="updateButtons( this )"/>
checked="checked" onclick="updateButtons( this )"/>
checked="checked" onclick="updateButtons( this )"/>
checked="checked" onclick="updateButtons( this )"/>
checked="checked" onclick="updateButtons( this )"/>
checked="checked"/>" size="32" maxlength="255" onchange="updateButtons( this )"/>
checked="checked" onclick="updateButtons( this )"/>

- - + + - + - - + +
diff --git a/web/skins/classic/views/filtersave.php b/web/skins/classic/views/filtersave.php index e8d1ec625..83c803485 100644 --- a/web/skins/classic/views/filtersave.php +++ b/web/skins/classic/views/filtersave.php @@ -41,12 +41,12 @@ $filter = $_REQUEST['filter']; parseFilter( $filter ); -xhtmlHeaders(__FILE__, $SLANG['SaveFilter'] ); +xhtmlHeaders(__FILE__, translate('SaveFilter') ); ?>
@@ -66,18 +66,18 @@ xhtmlHeaders(__FILE__, $SLANG['SaveFilter'] );

- +

- +

- checked="checked"/> + checked="checked"/>

- disabled="disabled"/> + disabled="disabled"/>
diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index 3ffc93319..9edaa0371 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -62,29 +62,29 @@ $rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Frame']." - ".$event['Id']." - ".$frame['FrameId'] ); +xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame['FrameId'] ); ?>

"><?php echo $frame['EventId']." class=""/>

1 ) { ?> - + 1 ) { ?> - + - + - +

diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index a6318c35f..148457e49 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -31,13 +31,13 @@ $frames = dbFetchAll( $sql, NULL, array( $_REQUEST['eid'] ) ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Frames']." - ".$event['Id'] ); +xhtmlHeaders(__FILE__, translate('Frames')." - ".$event['Id'] ); ?>
@@ -45,11 +45,11 @@ xhtmlHeaders(__FILE__, $SLANG['Frames']." - ".$event['Id'] ); - - - - - + + + + + @@ -87,7 +87,7 @@ else { ?> - +
@@ -51,11 +51,11 @@ foreach ( getEnumValues( 'Monitors', 'Function' ) as $optFunction ) } ?> - checked="checked"/> + checked="checked"/>

- - + +
diff --git a/web/skins/classic/views/group.php b/web/skins/classic/views/group.php index 229c8cc68..ce50cc875 100644 --- a/web/skins/classic/views/group.php +++ b/web/skins/classic/views/group.php @@ -37,12 +37,12 @@ else ); } -xhtmlHeaders( __FILE__, $SLANG['Group']." - ".$newGroup['Name'] ); +xhtmlHeaders( __FILE__, translate('Group')." - ".$newGroup['Name'] ); ?>
@@ -52,11 +52,11 @@ xhtmlHeaders( __FILE__, $SLANG['Group']." - ".$newGroup['Name'] );
- + - +
- disabled="disabled"/> - + disabled="disabled"/> +
diff --git a/web/skins/classic/views/groups.php b/web/skins/classic/views/groups.php index 3db497501..2e957fbc9 100644 --- a/web/skins/classic/views/groups.php +++ b/web/skins/classic/views/groups.php @@ -36,12 +36,12 @@ foreach( dbFetchAll( $sql ) as $row ) $groups[] = $row; } -xhtmlHeaders(__FILE__, $SLANG['Groups'] ); +xhtmlHeaders(__FILE__, translate('Groups') ); ?>
@@ -50,15 +50,15 @@ xhtmlHeaders(__FILE__, $SLANG['Groups'] ); - - - + + + - - + + @@ -71,11 +71,11 @@ xhtmlHeaders(__FILE__, $SLANG['Groups'] );
onclick="configureButtons( this );"/>
- - /> - /> - /> - + + /> + /> + /> +
diff --git a/web/skins/classic/views/js/event.js.php b/web/skins/classic/views/js/event.js.php index bbde397e1..7415e2c72 100644 --- a/web/skins/classic/views/js/event.js.php +++ b/web/skins/classic/views/js/event.js.php @@ -44,5 +44,5 @@ var canStreamNative = ; // // Strings // -var deleteString = ""; -var causeString = ""; +var deleteString = ""; +var causeString = ""; diff --git a/web/skins/classic/views/js/events.js.php b/web/skins/classic/views/js/events.js.php index 4548da91c..647515a7e 100644 --- a/web/skins/classic/views/js/events.js.php +++ b/web/skins/classic/views/js/events.js.php @@ -10,4 +10,4 @@ var sortQuery = ''; var maxWidth = ; var maxHeight = ; -var confirmDeleteEventsString = ""; +var confirmDeleteEventsString = ""; diff --git a/web/skins/classic/views/js/export.js.php b/web/skins/classic/views/js/export.js.php index 4bdbf4dcd..a251f92ca 100644 --- a/web/skins/classic/views/js/export.js.php +++ b/web/skins/classic/views/js/export.js.php @@ -19,4 +19,4 @@ var eidParm = 'eid='; var exportReady = ; var exportFile = ''; -var exportProgressString = ''; +var exportProgressString = ''; diff --git a/web/skins/classic/views/js/filter.js.php b/web/skins/classic/views/js/filter.js.php index 9c2a631b5..29eef084b 100644 --- a/web/skins/classic/views/js/filter.js.php +++ b/web/skins/classic/views/js/filter.js.php @@ -1,4 +1,4 @@ -var deleteSavedFilterString = ""; +var deleteSavedFilterString = ""; function validateForm( form ) { if ( bracket_count ) { - alert( "" ); + alert( "" ); return( false ); } ][val]']; if ( val.value == '' ) { - alert( "" ); + alert( "" ); return( false ); } $SLANG['None'] ); + $controlTypes = array( ''=>translate('None') ); # Temporary workaround to show all ptz control types regardless of monitor source type # $sql = "select * from Controls where Type = '".$newMonitor['Type']."'"; $sql = "select * from Controls"; @@ -21,7 +21,7 @@ controlOptions[] = new Array(); if ( $row['HasHomePreset'] ) { ?> -controlOptions[][0] = ''; +controlOptions[][0] = ''; ][0] = null; for ( $i = 1; $i <= $row['NumPresets']; $i++ ) { ?> -controlOptions[][] = ''; +controlOptions[][] = ''; = 0 ) - errors[errors.length] = ""; + errors[errors.length] = ""; else if ( form.elements.mid.value == 0 && monitorNames[form.elements['newMonitor[Name]'].value] ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( form.elements['newMonitor[AlarmMaxFPS]'].value && !(parseFloat(form.elements['newMonitor[AlarmMaxFPS]'].value) > 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[RefBlendPerc]'].value || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) > 100 ) || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) < 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( form.elements['newMonitor[Type]'].value == 'Local' ) { if ( !form.elements['newMonitor[Palette]'].value || !form.elements['newMonitor[Palette]'].value.match( /^\d+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[Device]'].value ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[Channel]'].value || !form.elements['newMonitor[Channel]'].value.match( /^\d+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[Format]'].value || !form.elements['newMonitor[Format]'].value.match( /^\d+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; } else if ( form.elements['newMonitor[Type]'].value == 'Remote' ) { if ( !form.elements['newMonitor[Host]'].value || !form.elements['newMonitor[Host]'].value.match( /^[0-9a-zA-Z_.:@-]+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( form.elements['newMonitor[Port]'].value && !form.elements['newMonitor[Port]'].value.match( /^\d+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; //if ( !form.elements['newMonitor[Path]'].value ) - //errors[errors.length] = ""; + //errors[errors.length] = ""; } else if ( form.elements['newMonitor[Type]'].value == 'File' ) { if ( !form.elements['newMonitor[Path]'].value ) - errors[errors.length] = ""; + errors[errors.length] = ""; } if ( !form.elements['newMonitor[Colours]'].value || (parseInt(form.elements['newMonitor[Colours]'].value) != 1 && parseInt(form.elements['newMonitor[Colours]'].value) != 3 && parseInt(form.elements['newMonitor[Colours]'].value) != 4 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[Width]'].value || !(parseInt(form.elements['newMonitor[Width]'].value) > 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[Height]'].value || !(parseInt(form.elements['newMonitor[Height]'].value) > 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[LabelX]'].value || !(parseInt(form.elements['newMonitor[LabelX]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[LabelY]'].value || !(parseInt(form.elements['newMonitor[LabelY]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[ImageBufferCount]'].value || !(parseInt(form.elements['newMonitor[ImageBufferCount]'].value) >= 10 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) > 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[StreamReplayBuffer]'].value || !(parseInt(form.elements['newMonitor[StreamReplayBuffer]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[AlarmFrameCount]'].value || !(parseInt(form.elements['newMonitor[AlarmFrameCount]'].value) > 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[SectionLength]'].value || !(parseInt(form.elements['newMonitor[SectionLength]'].value) >= 30 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[FPSReportInterval]'].value || !(parseInt(form.elements['newMonitor[FPSReportInterval]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[FrameSkip]'].value || !(parseInt(form.elements['newMonitor[FrameSkip]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[MotionFrameSkip]'].value || !(parseInt(form.elements['newMonitor[MotionFrameSkip]'].value) >= 0 ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( form.elements['newMonitor[Type]'].value == 'Local' ) if ( !form.elements['newMonitor[SignalCheckColour]'].value || !form.elements['newMonitor[SignalCheckColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( !form.elements['newMonitor[WebColour]'].value || !form.elements['newMonitor[WebColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) ) - errors[errors.length] = ""; + errors[errors.length] = ""; if ( errors.length ) { diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index b952fb3f7..655f993ff 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -8,11 +8,11 @@ var STATE_ALERT = ; var STATE_TAPE = ; var stateStrings = new Array(); -stateStrings[STATE_IDLE] = ""; -stateStrings[STATE_PREALARM] = ""; -stateStrings[STATE_ALARM] = ""; -stateStrings[STATE_ALERT] = ""; -stateStrings[STATE_TAPE] = ""; +stateStrings[STATE_IDLE] = ""; +stateStrings[STATE_PREALARM] = ""; +stateStrings[STATE_ALARM] = ""; +stateStrings[STATE_ALERT] = ""; +stateStrings[STATE_TAPE] = ""; var CMD_QUERY = ; diff --git a/web/skins/classic/views/js/options.js.php b/web/skins/classic/views/js/options.js.php index 5c86a78eb..6d9d18312 100644 --- a/web/skins/classic/views/js/options.js.php +++ b/web/skins/classic/views/js/options.js.php @@ -1,5 +1,5 @@ var restartWarning = ; if ( restartWarning ) { - alert( "" ); + alert( "" ); } diff --git a/web/skins/classic/views/js/timeline.js.php b/web/skins/classic/views/js/timeline.js.php index 4ec23432f..c5852a6ea 100644 --- a/web/skins/classic/views/js/timeline.js.php +++ b/web/skins/classic/views/js/timeline.js.php @@ -13,4 +13,4 @@ monitorNames[] = ' -var archivedString = ""; +var archivedString = ""; diff --git a/web/skins/classic/views/js/video.js.php b/web/skins/classic/views/js/video.js.php index dd1dd2b01..cd12fef7b 100644 --- a/web/skins/classic/views/js/video.js.php +++ b/web/skins/classic/views/js/video.js.php @@ -1,5 +1,5 @@ var eventId = ''; -var videoGenSuccessString = ''; -var videoGenFailedString = ''; -var videoGenProgressString = ''; +var videoGenSuccessString = ''; +var videoGenFailedString = ''; +var videoGenProgressString = ''; diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index 79641d4f6..f33983d9f 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -8,13 +8,13 @@ var STATE_ALERT = ; var STATE_TAPE = ; var stateStrings = new Array(); -stateStrings[STATE_IDLE] = ""; -stateStrings[STATE_PREALARM] = ""; -stateStrings[STATE_ALARM] = ""; -stateStrings[STATE_ALERT] = ""; -stateStrings[STATE_TAPE] = ""; +stateStrings[STATE_IDLE] = ""; +stateStrings[STATE_PREALARM] = ""; +stateStrings[STATE_ALARM] = ""; +stateStrings[STATE_ALERT] = ""; +stateStrings[STATE_TAPE] = ""; -var deleteString = ""; +var deleteString = ""; var CMD_NONE = ; var CMD_PAUSE = ; diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php index 73bd92dd6..7e3145378 100644 --- a/web/skins/classic/views/js/zone.js.php +++ b/web/skins/classic/views/js/zone.js.php @@ -50,18 +50,18 @@ var maxX = ; var maxY = ; var selfIntersecting = ; -var selfIntersectingString = ''; -var alarmRGBUnsetString = ''; -var minPixelThresUnsetString = ''; -var minPixelThresLtMaxString = ''; -var filterUnsetString = ''; -var minAlarmAreaUnsetString = ''; -var minAlarmAreaLtMaxString = ''; -var minFilterAreaUnsetString = ''; -var minFilterAreaLtMaxString = ''; -var minFilterLtMinAlarmString = ''; -var minBlobAreaUnsetString = ''; -var minBlobAreaLtMaxString = ''; -var minBlobLtMinFilterString = ''; -var minBlobsUnsetString = ''; -var minBlobsLtMaxString = ''; +var selfIntersectingString = ''; +var alarmRGBUnsetString = ''; +var minPixelThresUnsetString = ''; +var minPixelThresLtMaxString = ''; +var filterUnsetString = ''; +var minAlarmAreaUnsetString = ''; +var minAlarmAreaLtMaxString = ''; +var minFilterAreaUnsetString = ''; +var minFilterAreaLtMaxString = ''; +var minFilterLtMinAlarmString = ''; +var minBlobAreaUnsetString = ''; +var minBlobAreaLtMaxString = ''; +var minBlobLtMinFilterString = ''; +var minBlobsUnsetString = ''; +var minBlobsLtMaxString = ''; diff --git a/web/skins/classic/views/log.php b/web/skins/classic/views/log.php index a4178e513..06e3d9a68 100644 --- a/web/skins/classic/views/log.php +++ b/web/skins/classic/views/log.php @@ -26,52 +26,52 @@ if ( !canView( 'System' ) ) $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['SystemLog'] ); +xhtmlHeaders(__FILE__, translate('SystemLog') ); ?>
-
- - - - - - - +
- + + + + + +
- - - - - - - + + + + + + + @@ -84,29 +84,29 @@ xhtmlHeaders(__FILE__, $SLANG['SystemLog'] );
-
+
- - - - + + + +
- + - +
- : + :
- - + +
diff --git a/web/skins/classic/views/login.php b/web/skins/classic/views/login.php index a7562e5fa..d89a94319 100644 --- a/web/skins/classic/views/login.php +++ b/web/skins/classic/views/login.php @@ -18,12 +18,12 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // -xhtmlHeaders(__FILE__, $SLANG['Login'] ); +xhtmlHeaders(__FILE__, translate('Login') ); ?>
@@ -33,16 +33,16 @@ xhtmlHeaders(__FILE__, $SLANG['Login'] );
- + - +
" size="12"/>
- +
diff --git a/web/skins/classic/views/logout.php b/web/skins/classic/views/logout.php index 4b65d9c60..f8b83157b 100644 --- a/web/skins/classic/views/logout.php +++ b/web/skins/classic/views/logout.php @@ -20,12 +20,12 @@ $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Logout'] ); +xhtmlHeaders(__FILE__, translate('Logout') ); ?>
@@ -33,16 +33,16 @@ xhtmlHeaders(__FILE__, $SLANG['Logout'] );

- + - + - +

diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 3b7547479..cb81789ea 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -25,15 +25,15 @@ if ( !canView( 'Monitors' ) ) } $tabs = array(); -$tabs["general"] = $SLANG['General']; -$tabs["source"] = $SLANG['Source']; -$tabs["timestamp"] = $SLANG['Timestamp']; -$tabs["buffers"] = $SLANG['Buffers']; +$tabs["general"] = translate('General'); +$tabs["source"] = translate('Source'); +$tabs["timestamp"] = translate('Timestamp'); +$tabs["buffers"] = translate('Buffers'); if ( ZM_OPT_CONTROL && canView( 'Control' ) ) - $tabs["control"] = $SLANG['Control']; + $tabs["control"] = translate('Control'); if ( ZM_OPT_X10 ) - $tabs["x10"] = $SLANG['X10']; -$tabs["misc"] = $SLANG['Misc']; + $tabs["x10"] = translate('X10'); +$tabs["misc"] = translate('Misc'); if ( isset($_REQUEST['tab']) ) $tab = validHtmlStr($_REQUEST['tab']); @@ -48,7 +48,7 @@ if ( ! empty($_REQUEST['mid']) ) { $nextId = getTableAutoInc( 'Monitors' ); $monitor = array( 'Id' => 0, - 'Name' => $SLANG['Monitor'].'-'.$nextId, + 'Name' => translate('Monitor').'-'.$nextId, 'Function' => "Monitor", 'Enabled' => true, 'LinkedMonitors' => "", @@ -174,11 +174,11 @@ if ( !empty($_REQUEST['probe']) ) } $sourceTypes = array( - 'Local' => $SLANG['Local'], - 'Remote' => $SLANG['Remote'], - 'File' => $SLANG['File'], - 'Ffmpeg' => $SLANG['Ffmpeg'], - 'Libvlc' => $SLANG['Libvlc'], + 'Local' => translate('Local'), + 'Remote' => translate('Remote'), + 'File' => translate('File'), + 'Ffmpeg' => translate('Ffmpeg'), + 'Libvlc' => translate('Libvlc'), 'cURL' => "cURL (HTTP(S) only)" ); if ( !ZM_HAS_V4L ) @@ -234,7 +234,7 @@ if ( ZM_HAS_V4L1 ) $v4l1DeviceChannels["$i"] = $i; $v4l1LocalPalettes = array( - $SLANG['Grey'] => 1, + translate('Grey') => 1, "BGR32" => 5, "BGR24" => 4, "*YUYV" => 8, @@ -288,7 +288,7 @@ if ( ZM_HAS_V4L2 ) "Auto" => 0, /* Automatic palette selection */ /* Pixel format FOURCC depth Description */ - $SLANG['Grey'] => fourcc('G','R','E','Y'), /* 8 Greyscale */ + translate('Grey') => fourcc('G','R','E','Y'), /* 8 Greyscale */ "BGR32" => fourcc('B','G','R','4'), /* 32 BGR-8-8-8-8 */ "RGB32" => fourcc('R','G','B','4'), /* 32 RGB-8-8-8-8 */ "BGR24" => fourcc('B','G','R','3'), /* 24 BGR-8-8-8 */ @@ -354,18 +354,18 @@ if ( ZM_HAS_V4L2 ) } $Colours = array( - $SLANG['8BitGrey'] => 1, - $SLANG['24BitColour'] => 3, - $SLANG['32BitColour'] => 4 + translate('8BitGrey') => 1, + translate('24BitColour') => 3, + translate('32BitColour') => 4 ); $orientations = array( - $SLANG['Normal'] => '0', - $SLANG['RotateRight'] => '90', - $SLANG['Inverted'] => '180', - $SLANG['RotateLeft'] => '270', - $SLANG['FlippedHori'] => 'hori', - $SLANG['FlippedVert'] => 'vert' + translate('Normal') => '0', + translate('RotateRight') => '90', + translate('Inverted') => '180', + translate('RotateLeft') => '270', + translate('FlippedHori') => 'hori', + translate('FlippedVert') => 'vert' ); $deinterlaceopts = array( @@ -415,7 +415,7 @@ $fastblendopts_alarm = array( "50% (Alarm lasts a moment)" => 50 ); -xhtmlHeaders(__FILE__, $SLANG['Monitor']." - ".validHtmlStr($monitor['Name']) ); +xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor['Name']) ); ?>
@@ -425,21 +425,21 @@ if ( canEdit( 'Monitors' ) ) { ?>
- + - + - +
-

- ()

+

- ()

    @@ -611,9 +611,9 @@ switch ( $tab ) case 'general' : { ?> - - - + + - checked="checked"/> + checked="checked"/> - + - + + - - + + - - + + - + - + @@ -696,27 +696,27 @@ switch ( $tab ) if ( ZM_HAS_V4L && $newMonitor['Type'] == "Local" ) { ?> - - + + - - - + + + - - - + + + - + /> /> @@ -724,36 +724,36 @@ switch ( $tab ) /> - + - + - + - + - - - + + + - + - - -  () + + +  () - - () - () - - + + () + () + + - + - + @@ -796,64 +796,64 @@ switch ( $tab ) case 'timestamp' : { ?> - - - + + + - - - - - - + + + + + + - checked="checked"/> -   - - - - checked="checked"/> + checked="checked"/> +   + + + + checked="checked"/> $SLANG['None'], - '0' => $SLANG['Home'], - '1' => $SLANG['Preset']." 1", + '-1' => translate('None'), + '0' => translate('Home'), + '1' => translate('Preset')." 1", ); ?> - - - + + + - - - + + + - - - - - - + + + + + - - + + -      +      -      +     
    - disabled="disabled"/> + disabled="disabled"/>
diff --git a/web/skins/classic/views/monitorpreset.php b/web/skins/classic/views/monitorpreset.php index 0c78899f0..db2c06252 100644 --- a/web/skins/classic/views/monitorpreset.php +++ b/web/skins/classic/views/monitorpreset.php @@ -25,7 +25,7 @@ if ( !canEdit( 'Monitors' ) ) } $sql = "select Id,Name from MonitorPresets"; $presets = array(); -$presets[0] = $SLANG['ChoosePreset']; +$presets[0] = translate('ChoosePreset'); foreach( dbFetchAll( $sql ) as $preset ) { $presets[$preset['Id']] = htmlentities( $preset['Name'] ); @@ -33,25 +33,25 @@ foreach( dbFetchAll( $sql ) as $preset ) $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['MonitorPreset'] ); +xhtmlHeaders(__FILE__, translate('MonitorPreset') ); ?>

- +

- +

- +
diff --git a/web/skins/classic/views/monitorprobe.php b/web/skins/classic/views/monitorprobe.php index 8ae592440..8714383fc 100644 --- a/web/skins/classic/views/monitorprobe.php +++ b/web/skins/classic/views/monitorprobe.php @@ -25,7 +25,7 @@ if ( !canEdit( 'Monitors' ) ) } $cameras = array(); -$cameras[0] = $SLANG['ChooseDetectedCamera']; +$cameras[0] = translate('ChooseDetectedCamera'); if ( ZM_HAS_V4L2 ) { @@ -103,7 +103,7 @@ if ( ZM_HAS_V4L2 ) $inputMonitor['SignalCheckColour'] = '#000023'; } $inputDesc = base64_encode(serialize($inputMonitor)); - $inputString = $deviceMatches[1].', chan '.$i.($input['free']?(" - ".$SLANG['Available']):(" (".$monitors[$input['id']]['Name'].")")); + $inputString = $deviceMatches[1].', chan '.$i.($input['free']?(" - ".translate('Available')):(" (".$monitors[$input['id']]['Name'].")")); $inputs[] = $input; $cameras[$inputDesc] = $inputString; } @@ -341,36 +341,36 @@ foreach ( $output as $line ) } else { - $sourceString .= " - ".$SLANG['Available']; + $sourceString .= " - ".translate('Available'); } $cameras[$sourceDesc] = $sourceString; } } if ( count($cameras) <= 0 ) - $cameras[0] = $SLANG['NoDetectedCameras']; + $cameras[0] = translate('NoDetectedCameras'); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['MonitorProbe'] ); +xhtmlHeaders(__FILE__, translate('MonitorProbe') ); ?>

- +

- +

- +
diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index f8a8a9554..d9f92805a 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -70,17 +70,17 @@ foreach( dbFetchAll( $sql ) as $row ) $focusWindow = true; $layouts = array( - 'montage_freeform.css' => $SLANG['MtgDefault'], - 'montage_2wide.css' => $SLANG['Mtg2widgrd'], - 'montage_3wide.css' => $SLANG['Mtg3widgrd'], - 'montage_4wide.css' => $SLANG['Mtg4widgrd'], - 'montage_3wide50enlarge.css' => $SLANG['Mtg3widgrx'], + 'montage_freeform.css' => translate('MtgDefault'), + 'montage_2wide.css' => translate('Mtg2widgrd'), + 'montage_3wide.css' => translate('Mtg3widgrd'), + 'montage_4wide.css' => translate('Mtg4widgrd'), + 'montage_3wide50enlarge.css' => translate('Mtg3widgrx'), ); if ( isset($_COOKIE['zmMontageLayout']) ) $layout = $_COOKIE['zmMontageLayout']; -xhtmlHeaders(__FILE__, $SLANG['Montage'] ); +xhtmlHeaders(__FILE__, translate('Montage') ); ?>
@@ -90,16 +90,16 @@ xhtmlHeaders(__FILE__, $SLANG['Montage'] ); if ( $showControl ) { ?> - + - +
-

+

- : - + : +
@@ -138,7 +138,7 @@ else if ( !ZM_WEB_COMPACT_MONTAGE ) { ?> -
 -  fps
+
 -  fps
diff --git a/web/skins/classic/views/onvifprobe.php b/web/skins/classic/views/onvifprobe.php index a129b2dba..c15568eaf 100644 --- a/web/skins/classic/views/onvifprobe.php +++ b/web/skins/classic/views/onvifprobe.php @@ -25,7 +25,7 @@ if ( !canEdit( 'Monitors' ) ) } $cameras = array(); -$cameras[0] = $SLANG['ChooseDetectedCamera']; +$cameras[0] = translate('ChooseDetectedCamera'); function execONVIF( $cmd ) @@ -124,7 +124,7 @@ function probeProfiles( $device_ep, $soapversion, $username, $password ) $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['MonitorProbe'] ); +xhtmlHeaders(__FILE__, translate('MonitorProbe') ); if( !isset($_REQUEST['step']) || ($_REQUEST['step'] == "1")) { @@ -159,7 +159,7 @@ if( !isset($_REQUEST['step']) || ($_REQUEST['step'] == "1")) { } else { - $sourceString .= " - ".$SLANG['Available']; + $sourceString .= " - ".translate('Available'); } $cameras[$sourceDesc] = $sourceString; } @@ -171,13 +171,13 @@ if( !isset($_REQUEST['step']) || ($_REQUEST['step'] == "1")) { } if ( count($cameras) <= 0 ) - $cameras[0] = $SLANG['NoDetectedCameras']; + $cameras[0] = translate('NoDetectedCameras'); ?>
@@ -185,25 +185,25 @@ if( !isset($_REQUEST['step']) || ($_REQUEST['step'] == "1")) {

- +

- +

- +

- +

- +

- - + +
@@ -251,13 +251,13 @@ else if($_REQUEST['step'] == "2") } if ( count($cameras) <= 0 ) - $cameras[0] = $SLANG['NoDetectedCameras']; + $cameras[0] = translate('NoDetectedCameras'); ?>
@@ -265,15 +265,15 @@ else if($_REQUEST['step'] == "2")

- +

- +

- - - + + +
diff --git a/web/skins/classic/views/optionhelp.php b/web/skins/classic/views/optionhelp.php index 2aa5a4e40..fbfd3be69 100644 --- a/web/skins/classic/views/optionhelp.php +++ b/web/skins/classic/views/optionhelp.php @@ -25,15 +25,15 @@ $optionHelpText = preg_replace( "/~~/", "
", $optionHelpText ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['OptionHelp'] ); +xhtmlHeaders(__FILE__, translate('OptionHelp') ); ?>

diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 9f8ef86e9..02f5cdffd 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -27,23 +27,23 @@ if ( !canView( 'System' ) ) $canEdit = canEdit( 'System' ); $tabs = array(); -$tabs['skins'] = $SLANG['Display']; // change me to be supported by SLANG... -$tabs['system'] = $SLANG['System']; -$tabs['config'] = $SLANG['Config']; -$tabs['paths'] = $SLANG['Paths']; -$tabs['web'] = $SLANG['Web']; -$tabs['images'] = $SLANG['Images']; -$tabs['logging'] = $SLANG['Logging']; -$tabs['network'] = $SLANG['Network']; -$tabs['mail'] = $SLANG['Email']; -$tabs['upload'] = $SLANG['Upload']; -$tabs['x10'] = $SLANG['X10']; -$tabs['highband'] = $SLANG['HighBW']; -$tabs['medband'] = $SLANG['MediumBW']; -$tabs['lowband'] = $SLANG['LowBW']; -$tabs['phoneband'] = $SLANG['PhoneBW']; +$tabs['skins'] = translate('Display'); // change me to be supported by SLANG... +$tabs['system'] = translate('System'); +$tabs['config'] = translate('Config'); +$tabs['paths'] = translate('Paths'); +$tabs['web'] = translate('Web'); +$tabs['images'] = translate('Images'); +$tabs['logging'] = translate('Logging'); +$tabs['network'] = translate('Network'); +$tabs['mail'] = translate('Email'); +$tabs['upload'] = translate('Upload'); +$tabs['x10'] = translate('X10'); +$tabs['highband'] = translate('HighBW'); +$tabs['medband'] = translate('MediumBW'); +$tabs['lowband'] = translate('LowBW'); +$tabs['phoneband'] = translate('PhoneBW'); $tabs['eyeZm'] = "eyeZm"; -$tabs['users'] = $SLANG['Users']; +$tabs['users'] = translate('Users'); if ( isset($_REQUEST['tab']) ) $tab = validHtmlStr($_REQUEST['tab']); @@ -52,12 +52,12 @@ else $focusWindow = true; -xhtmlHeaders( __FILE__, $SLANG['Options'] ); +xhtmlHeaders( __FILE__, translate('Options') ); ?>
    @@ -105,11 +105,11 @@ if($tab == 'skins') { - + - + - +
    ZM_SKIN
    ZM_CSS
    - /> - + /> +
    @@ -151,17 +151,17 @@ elseif ( $tab == "users" ) - - - - - - - - - - - + + + + + + + + + + + @@ -188,7 +188,7 @@ elseif ( $tab == "users" ) - + @@ -204,7 +204,7 @@ elseif ( $tab == "users" )
    - disabled="disabled"/> + disabled="disabled"/>
    - - - + + + @@ -336,7 +336,7 @@ elseif ( $tab == "users" )
    - /> + />
    @@ -158,7 +158,7 @@ foreach($pluginOptions as $name => $popt) ?> - disabled="disabled"/> + disabled="disabled"/>
    diff --git a/web/skins/classic/views/postlogin.php b/web/skins/classic/views/postlogin.php index b08bc77fe..c27b773c8 100644 --- a/web/skins/classic/views/postlogin.php +++ b/web/skins/classic/views/postlogin.php @@ -18,15 +18,15 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // -xhtmlHeaders(__FILE__, $SLANG['LoggingIn'] ); +xhtmlHeaders(__FILE__, translate('LoggingIn') ); ?>
    -

    +

    diff --git a/web/skins/classic/views/settings.php b/web/skins/classic/views/settings.php index 14d635178..3302d2063 100644 --- a/web/skins/classic/views/settings.php +++ b/web/skins/classic/views/settings.php @@ -36,12 +36,12 @@ $monitor['Colour'] = $colour; $focusWindow = true; -xhtmlHeaders(__FILE__, validHtmlStr($monitor['Name'])." - ".$SLANG['Settings'] ); +xhtmlHeaders(__FILE__, validHtmlStr($monitor['Name'])." - ".translate('Settings') ); ?>
    @@ -51,25 +51,25 @@ xhtmlHeaders(__FILE__, validHtmlStr($monitor['Name'])." - ".$SLANG['Settings'] ) - + - + - + - +
    disabled="disabled"/>
    disabled="disabled"/>
    disabled="disabled"/>
    disabled="disabled"/>
    - disabled="disabled"/> + disabled="disabled"/>
    diff --git a/web/skins/classic/views/state.php b/web/skins/classic/views/state.php index 66c9ef9c1..84ffb954d 100644 --- a/web/skins/classic/views/state.php +++ b/web/skins/classic/views/state.php @@ -29,12 +29,12 @@ $states = dbFetchAll( "select * from States" ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['RunState'] ); +xhtmlHeaders(__FILE__, translate('RunState') ); ?>
    @@ -51,14 +51,14 @@ if ( empty($_REQUEST['apply']) ) if ( $running ) { ?> - - + + - + @@ -75,16 +75,16 @@ if ( empty($_REQUEST['apply']) ) - +
    - - - - + + + +
    -

    -

    +

    +

    diff --git a/web/skins/classic/views/stats.php b/web/skins/classic/views/stats.php index 42c069ffb..55a9fab6e 100644 --- a/web/skins/classic/views/stats.php +++ b/web/skins/classic/views/stats.php @@ -32,15 +32,15 @@ $stats = dbFetchAll( $sql, NULL, array( $eid, $fid ) ); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Stats']." - ".$eid." - ".$fid ); +xhtmlHeaders(__FILE__, translate('Stats')." - ".$eid." - ".$fid ); ?>
    @@ -48,15 +48,15 @@ xhtmlHeaders(__FILE__, $SLANG['Stats']." - ".$eid." - ".$fid ); - - - - - - - - - + + + + + + + + + @@ -97,7 +97,7 @@ else { ?> - +
    diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index eefa830d5..853a76def 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -725,7 +725,7 @@ function drawXGrid( $chart, $scale, $labelClass, $tickClass, $gridClass, $zoomCl $zoomMinTime = strftime( STRF_FMT_DATETIME_DB, (int)($chart['data']['x']['lo'] + ($lastTick * $chart['data']['x']['density'])) ); $zoomMaxTime = strftime( STRF_FMT_DATETIME_DB, (int)($chart['data']['x']['lo'] + ($i * $chart['data']['x']['density'])) ); ?> -
    +
    -
    +
    @@ -799,37 +799,37 @@ function getSlotShowEventBehaviour( $slot ) $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Timeline'] ); +xhtmlHeaders(__FILE__, translate('Timeline') ); ?>
    -
    <?php echo $SLANG['ViewEvent'] ?>
    +
    <?php echo translate('ViewEvent') ?>
    -

    -

    -

    -

    +

    +

    +

    +

    diff --git a/web/skins/classic/views/user.php b/web/skins/classic/views/user.php index 74d85471d..274fd2fc5 100644 --- a/web/skins/classic/views/user.php +++ b/web/skins/classic/views/user.php @@ -33,16 +33,16 @@ if ( $_REQUEST['uid'] ) { } } else { $newUser = array(); - $newUser['Username'] = $SLANG['NewUser']; + $newUser['Username'] = translate('NewUser'); $newUser['Enabled'] = 1; $newUser['MonitorIds'] = ''; } $monitorIds = array_flip(explode( ',', $newUser['MonitorIds'] )); -$yesno = array( 0=>$SLANG['No'], 1=>$SLANG['Yes'] ); -$nv = array( 'None'=>$SLANG['None'], 'View'=>$SLANG['View'] ); -$nve = array( 'None'=>$SLANG['None'], 'View'=>$SLANG['View'], 'Edit'=>$SLANG['Edit'] ); +$yesno = array( 0=>translate('No'), 1=>translate('Yes') ); +$nv = array( 'None'=>translate('None'), 'View'=>translate('View') ); +$nve = array( 'None'=>translate('None'), 'View'=>translate('View'), 'Edit'=>translate('Edit') ); $bandwidths = array_merge( array( ""=>"" ), $bwArray ); $langs = array_merge( array( ""=>"" ), getLanguages() ); @@ -55,12 +55,12 @@ foreach( dbFetchAll( $sql ) as $monitor ) $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['User']." - ".$newUser['Username'] ); +xhtmlHeaders(__FILE__, translate('User')." - ".$newUser['Username'] ); ?>
    @@ -75,22 +75,22 @@ if ( canEdit( 'System' ) ) { ?>
    - + - + - + - + - + - + - + - + - + - + - + - +
    - +
    diff --git a/web/skins/classic/views/version.php b/web/skins/classic/views/version.php index e56b040c4..dca598b7c 100644 --- a/web/skins/classic/views/version.php +++ b/web/skins/classic/views/version.php @@ -24,28 +24,28 @@ if ( !canEdit( 'System' ) ) return; } $options = array( - "go" => $SLANG['GoToZoneMinder'] + "go" => translate('GoToZoneMinder') ); if ( verNum( ZM_DYN_CURR_VERSION ) != verNum( ZM_DYN_LAST_VERSION ) ) { $options = array_merge( $options, array( - "ignore" => $SLANG['VersionIgnore'], - "hour" => $SLANG['VersionRemindHour'], - "day" => $SLANG['VersionRemindDay'], - "week" => $SLANG['VersionRemindWeek'], - "never" => $SLANG['VersionRemindNever'] + "ignore" => translate('VersionIgnore'), + "hour" => translate('VersionRemindHour'), + "day" => translate('VersionRemindDay'), + "week" => translate('VersionRemindWeek'), + "never" => translate('VersionRemindNever') ) ); } $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Version'] ); +xhtmlHeaders(__FILE__, translate('Version') ); ?>

    -

    +

    - +

    -

    -

    +

    +

    - +
    "> -

    +

    - - + +
    - + - + - + - + checked="checked"/> - disabled="disabled"/> + disabled="disabled"/> -

    +

    - + -

    +

    -

    +

    - - - - - + + + + + @@ -226,7 +226,7 @@ else -  /  /  +  /  / 
    @@ -127,34 +127,34 @@ else if ( canEdit( 'Monitors' ) ) { ?> -
    +
    -
    +
    -
     -  fps
    +
     -  fps
    - - - - - - + + + + + +   diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index 121835913..69c0919e9 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -33,7 +33,7 @@ $hicolor = "0x00ff00"; // Green $presets = array(); $presetNames = array(); -$presetNames[0] = $SLANG['ChoosePreset']; +$presetNames[0] = translate('ChoosePreset'); $sql = "select *, Units-1 as UnitsIndex, CheckMethod-1 as CheckMethodIndex from ZonePresets order by Id asc"; foreach( dbFetchAll( $sql ) as $preset ) { @@ -75,7 +75,7 @@ if ( !isset($newZone) ) else { $zone = array( - 'Name' => $SLANG['New'], + 'Name' => translate('New'), 'Id' => 0, 'MonitorId' => $monitor['Id'], 'NumCoords' => 4, @@ -126,12 +126,12 @@ $zoneImage = ZM_DIR_IMAGES.'/Zones'.$monitor['Id'].'.jpg?'.time(); $focusWindow = true; -xhtmlHeaders(__FILE__, $SLANG['Zone'] ); +xhtmlHeaders(__FILE__, translate('Zone') ); ?>
    @@ -147,69 +147,69 @@ xhtmlHeaders(__FILE__, $SLANG['Zone'] ); - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -233,10 +233,10 @@ for ( $i = 0; $i < $pointCols; $i++ )
    "applyPreset()", "onblur"=>"this.selectedIndex=0" ) ) ?>
     /  / 
    - - - - + + + + @@ -269,7 +269,7 @@ for ( $i = 0; $i < $pointCols; $i++ )
    - disabled="disabled"/> + disabled="disabled"/>
    diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index a8b0eea2d..9182dc98f 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -44,13 +44,13 @@ foreach( dbFetchAll( 'select * from Zones where MonitorId = ? order by Area desc $image = 'Zones'.$monitor['Id'].'.jpg'; -xhtmlHeaders(__FILE__, $SLANG['Zones'] ); +xhtmlHeaders(__FILE__, translate('Zones') ); ?>
    @@ -72,10 +72,10 @@ foreach( array_reverse($zones) as $zone ) - - - - + + + + @@ -95,8 +95,8 @@ foreach( $zones as $zone )
    - disabled="disabled"/> - + disabled="disabled"/> +
    diff --git a/web/skins/mobile/includes/config.php b/web/skins/mobile/includes/config.php index 956c36bcc..fc1eba9bb 100644 --- a/web/skins/mobile/includes/config.php +++ b/web/skins/mobile/includes/config.php @@ -27,7 +27,7 @@ $rates = array( "2000" => "20x", "500" => "5x", "200" => "2x", - "100" => $SLANG['Real'], + "100" => translate('Real'), "50" => "1/2x", ); @@ -36,7 +36,7 @@ $scales = array( "300" => "3x", "200" => "2x", "150" => "1.5x", - "100" => $SLANG['Actual'], + "100" => translate('Actual'), "75" => "3/4x", "50" => "1/2x", "33" => "1/3x", diff --git a/web/skins/mobile/views/console.php b/web/skins/mobile/views/console.php index 1c4fcb912..50b5f4775 100644 --- a/web/skins/mobile/views/console.php +++ b/web/skins/mobile/views/console.php @@ -40,7 +40,7 @@ $eventCounts = array( ); $running = daemonCheck(); -$status = $running?$SLANG['Running']:$SLANG['Stopped']; +$status = $running?translate('Running'):translate('Stopped'); if ( $group = dbFetchOne( "select * from Groups where Name = 'Mobile'" ) ) $groupIds = array_flip(explode( ',', $group['MonitorIds'] )); @@ -81,7 +81,7 @@ for ( $i = 0; $i < count($monitors); $i++ ) $monitors[$i] = array_merge( $monitors[$i], $counts ); } -xhtmlHeaders( __FILE__, $SLANG['Console'] ); +xhtmlHeaders( __FILE__, translate('Console') ); ?>
    @@ -146,7 +146,7 @@ for ( $i = 0; $i < count($eventCounts); $i++ ) - + @@ -155,7 +155,7 @@ if ( ZM_OPT_X10 ) { } if ( $cycleCount > 1 ) { ?> - + diff --git a/web/skins/mobile/views/devices.php b/web/skins/mobile/views/devices.php index 08d2cd25c..add0a6bc5 100644 --- a/web/skins/mobile/views/devices.php +++ b/web/skins/mobile/views/devices.php @@ -32,12 +32,12 @@ foreach ( dbFetchAll( $sql ) as $row ) $devices[] = $row; } -xhtmlHeaders( __FILE__, $SLANG['Devices'] ); +xhtmlHeaders( __FILE__, translate('Devices') ); ?>
    @@ -59,14 +59,14 @@ foreach( $devices as $device ) ?> - - + +
    -

    +

    diff --git a/web/skins/mobile/views/error.php b/web/skins/mobile/views/error.php index 00876b7a2..33e99f09a 100644 --- a/web/skins/mobile/views/error.php +++ b/web/skins/mobile/views/error.php @@ -18,16 +18,16 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // -xhtmlHeaders( __FILE__, $SLANG['Error'] ); +xhtmlHeaders( __FILE__, translate('Error') ); ?>
    -

    -

    +

    +

    diff --git a/web/skins/mobile/views/event.php b/web/skins/mobile/views/event.php index d79ba3de0..ead6b6eae 100644 --- a/web/skins/mobile/views/event.php +++ b/web/skins/mobile/views/event.php @@ -104,7 +104,7 @@ if ( !empty($_REQUEST['fid']) ) $pagination = getPagination( $pages, $_REQUEST['page'], $maxShortcuts, '&eid='.$_REQUEST['eid'].$filterQuery.$sortQuery, '&' ); -xhtmlHeaders( __FILE__, $SLANG['Event'].' - '.$event['Name'] ); +xhtmlHeaders( __FILE__, translate('Event').' - '.$event['Name'] ); ?>
    @@ -114,7 +114,7 @@ if ( canEdit( 'Events' ) ) { ?>
    - +
    - - + + - + - + - + - + - + - +
    s
    ()
    //
    @@ -77,8 +77,8 @@ xhtmlHeaders( __FILE__, $SLANG['Event'].' - '.$_REQUEST['eid'] ); <?php echo $frame['FrameId'] ?>
    - - + +
    diff --git a/web/skins/mobile/views/events.php b/web/skins/mobile/views/events.php index 3bf25b1ed..40dd6eff8 100644 --- a/web/skins/mobile/views/events.php +++ b/web/skins/mobile/views/events.php @@ -104,12 +104,12 @@ $pages = (int)ceil($nEvents/$deviceLines); $maxShortcuts = 3; $pagination = getPagination( $pages, $_REQUEST['page'], $maxShortcuts, $filterQuery.$sortQuery.'&limit='.$_REQUEST['limit'], '&' ); -xhtmlHeaders( __FILE__, $SLANG['Events'] ); +xhtmlHeaders( __FILE__, translate('Events') ); ?>
    @@ -130,11 +130,11 @@ if ( $pagination ) { ?> - - - - - + + + + + -

    +

    diff --git a/web/skins/mobile/views/filter.php b/web/skins/mobile/views/filter.php index 13deffcba..4613f3c3c 100644 --- a/web/skins/mobile/views/filter.php +++ b/web/skins/mobile/views/filter.php @@ -31,7 +31,7 @@ foreach( dbFetchAll( $sql ) as $row ) $filterNames[$row['Name']] = $row['Name']; } -xhtmlHeaders( __FILE__, $SLANG['EventFilter'] ); +xhtmlHeaders( __FILE__, translate('EventFilter') ); ?>
    @@ -50,17 +50,17 @@ if ( count($filterNames) > 0 ) { ?>
    - +
    - +
    -

    +

    diff --git a/web/skins/mobile/views/frame.php b/web/skins/mobile/views/frame.php index 1ce591078..f9bb41633 100644 --- a/web/skins/mobile/views/frame.php +++ b/web/skins/mobile/views/frame.php @@ -47,12 +47,12 @@ $scale = getDeviceScale( $event['Width'], $event['Height'], 1.1 ); $imageData = getImageSrc( $event, $frame, $scale, (isset($_REQUEST['show'])&&$_REQUEST['show']=="capt") ); -xhtmlHeaders( __FILE__, $SLANG['Frame'].' - '.$_REQUEST['eid'].'-'.$frame['FrameId'] ); +xhtmlHeaders( __FILE__, translate('Frame').' - '.$_REQUEST['eid'].'-'.$frame['FrameId'] ); ?>
    "> diff --git a/web/skins/mobile/views/function.php b/web/skins/mobile/views/function.php index 3c06062c9..421d91063 100644 --- a/web/skins/mobile/views/function.php +++ b/web/skins/mobile/views/function.php @@ -25,7 +25,7 @@ if ( !canEdit( 'Monitors' ) ) } $monitor = dbFetchMonitor( $_REQUEST['mid'] ); -xhtmlHeaders( __FILE__, $SLANG['Function'].' - '.$monitor['Name'] ); +xhtmlHeaders( __FILE__, translate('Function').' - '.$monitor['Name'] ); ?>
    @@ -54,10 +54,10 @@ foreach ( getEnumValues( 'Monitors', 'Function' ) as $optFunction )
    - checked="checked"/> + checked="checked"/>
    - +
    diff --git a/web/skins/mobile/views/login.php b/web/skins/mobile/views/login.php index 4054432ba..6eb0b7db9 100644 --- a/web/skins/mobile/views/login.php +++ b/web/skins/mobile/views/login.php @@ -19,12 +19,12 @@ // -xhtmlHeaders( __FILE__, $SLANG['Login'] ); +xhtmlHeaders( __FILE__, translate('Login') ); ?>
    @@ -36,16 +36,16 @@ xhtmlHeaders( __FILE__, $SLANG['Login'] );
    - + - +
    " size="12"/>
    - +
    diff --git a/web/skins/mobile/views/montage.php b/web/skins/mobile/views/montage.php index c15f2d3ab..347436a46 100644 --- a/web/skins/mobile/views/montage.php +++ b/web/skins/mobile/views/montage.php @@ -46,13 +46,13 @@ foreach( dbFetchAll( $sql ) as $row ) $monitors[] = $row; } -xhtmlHeaders( __FILE__, $SLANG['Montage'] ); +xhtmlHeaders( __FILE__, translate('Montage') ); ?>
    @@ -68,7 +68,7 @@ foreach( $monitors as $monitor ) } ?>
    -
    +
    diff --git a/web/skins/mobile/views/state.php b/web/skins/mobile/views/state.php index dad01f4ca..51cf71624 100644 --- a/web/skins/mobile/views/state.php +++ b/web/skins/mobile/views/state.php @@ -27,12 +27,12 @@ $running = daemonCheck(); $states = dbFetchAll( "select * from States" ); -xhtmlHeaders( __FILE__, $SLANG['State'] ); +xhtmlHeaders( __FILE__, translate('State') ); ?>
    @@ -47,14 +47,14 @@ xhtmlHeaders( __FILE__, $SLANG['State'] ); if ( $running ) { ?> - - + + - + @@ -68,7 +68,7 @@ foreach ( $states as $state ) ?>
    - +
    diff --git a/web/skins/mobile/views/video.php b/web/skins/mobile/views/video.php index 6291b9972..8f7ac8654 100644 --- a/web/skins/mobile/views/video.php +++ b/web/skins/mobile/views/video.php @@ -105,7 +105,7 @@ if ( isset($_REQUEST['download']) ) exit; } -xhtmlHeaders( __FILE__, $SLANG['Video'].' - '.$event['Name'] ); +xhtmlHeaders( __FILE__, translate('Video').' - '.$event['Name'] ); ?>
    @@ -120,19 +120,19 @@ xhtmlHeaders( __FILE__, $SLANG['Video'].' - '.$event['Name'] );
    - + - + - +
    checked="checked"/>
    -
    +
    -

    +

    -

    +

    -

    +

    - - - - - + + + + + 0 ) @@ -203,7 +203,7 @@ xhtmlHeaders( __FILE__, $SLANG['Video'].' - '.$event['Name'] ); - + -

    +

    diff --git a/web/skins/mobile/views/watch.php b/web/skins/mobile/views/watch.php index 40849bd07..b61001db9 100644 --- a/web/skins/mobile/views/watch.php +++ b/web/skins/mobile/views/watch.php @@ -32,26 +32,26 @@ $showPtzControls = ( ZM_OPT_CONTROL && $monitor['Controllable'] && canView( 'Con $zmuCommand = getZmuCommand( " -m ".$_REQUEST['mid']." -s -f" ); $zmuOutput = exec( escapeshellcmd( $zmuCommand ) ); list( $status, $fps ) = explode( ' ', $zmuOutput ); -$statusString = $SLANG['Unknown']; +$statusString = translate('Unknown'); $fpsString = "--.--"; $class = "infoText"; if ( $status <= STATE_PREALARM ) { - $statusString = $SLANG['Idle']; + $statusString = translate('Idle'); } elseif ( $status == STATE_ALARM ) { - $statusString = $SLANG['Alarm']; + $statusString = translate('Alarm'); $class = "errorText"; } elseif ( $status == STATE_ALERT ) { - $statusString = $SLANG['Alert']; + $statusString = translate('Alert'); $class = "warnText"; } elseif ( $status == STATE_TAPE ) { - $statusString = $SLANG['Record']; + $statusString = translate('Record'); } $fpsString = sprintf( "%.2f", $fps ); @@ -99,7 +99,7 @@ else $streamSrc = getStreamSrc( array( "mode=".$streamMode, "monitor=".$monitor['Id'], "scale=".$scale ) ); } -xhtmlHeaders( __FILE__, $monitor['Name'].' - '.$SLANG['Watch'] ); +xhtmlHeaders( __FILE__, $monitor['Name'].' - '.translate('Watch') ); ?>
    @@ -141,9 +141,9 @@ if ( $nextMid != $monitor['Id'] || $prevMid != $monitor['Id'] ) { ?>
    - - - + + +
    "10x", "400" => "4x", "200" => "2x", - "100" => $SLANG['Real'], + "100" => translate('Real'), "50" => "1/2x", "25" => "1/4x", ); @@ -66,7 +66,7 @@ $scales = array( "300" => "3x", "200" => "2x", "150" => "1.5x", - "100" => $SLANG['Actual'], + "100" => translate('Actual'), "75" => "3/4x", "50" => "1/2x", "33" => "1/3x", @@ -74,9 +74,9 @@ $scales = array( ); $bwArray = array( - "high" => $SLANG['High'], - "medium" => $SLANG['Medium'], - "low" => $SLANG['Low'] + "high" => translate('High'), + "medium" => translate('Medium'), + "low" => translate('Low') ); /* Check if ZM_WEB_L_CAN_STREAM and ZM_WEB_L_STREAM_METHOD are defined */ diff --git a/web/skins/xml/views/console.php b/web/skins/xml/views/console.php index 86cf78768..b512bc13a 100644 --- a/web/skins/xml/views/console.php +++ b/web/skins/xml/views/console.php @@ -28,14 +28,14 @@ */ $eventCounts = array( array( - "title" => $SLANG['Events'], + "title" => translate('Events'), "filter" => array( "terms" => array( ) ), ), array( - "title" => $SLANG['Hour'], + "title" => translate('Hour'), "filter" => array( "terms" => array( array( "attr" => "Archived", "op" => "=", "val" => "0" ), @@ -44,7 +44,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Day'], + "title" => translate('Day'), "filter" => array( "terms" => array( array( "attr" => "Archived", "op" => "=", "val" => "0" ), @@ -53,7 +53,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Week'], + "title" => translate('Week'), "filter" => array( "terms" => array( array( "attr" => "Archived", "op" => "=", "val" => "0" ), @@ -62,7 +62,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Month'], + "title" => translate('Month'), "filter" => array( "terms" => array( array( "attr" => "Archived", "op" => "=", "val" => "0" ), @@ -71,7 +71,7 @@ $eventCounts = array( ), ), array( - "title" => $SLANG['Archived'], + "title" => translate('Archived'), "filter" => array( "terms" => array( array( "attr" => "Archived", "op" => "=", "val" => "1" ), @@ -81,7 +81,7 @@ $eventCounts = array( ); $running = daemonCheck(); -$status = $running?$SLANG['Running']:$SLANG['Stopped']; +$status = $running?translate('Running'):translate('Stopped'); if ( $group = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array(empty($_COOKIE['zmGroup'])?0:$_COOKIE['zmGroup']) ) ) $groupIds = array_flip(split( ',', $group['MonitorIds'] )); From 82f5ab5175c73c84653d13c0bbc0c9b31c60f052 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 May 2015 16:22:14 -0400 Subject: [PATCH 111/154] Fix use of DEFINED. It takes a string not a constant. When COOKIE is not set or has changed, set it --- web/index.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/index.php b/web/index.php index 1eff72974..6167dc4dc 100644 --- a/web/index.php +++ b/web/index.php @@ -63,30 +63,30 @@ if ( isset($_GET['skin']) ) $skin = $_GET['skin']; elseif ( isset($_COOKIE['zmSkin']) ) $skin = $_COOKIE['zmSkin']; -elseif ( defined(ZM_SKIN_DEFAULT) ) +elseif ( defined('ZM_SKIN_DEFAULT') ) $skin = ZM_SKIN_DEFAULT; else $skin = "classic"; $skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) ); if ( ! in_array( $skin, $skins ) ) { - Error( "Invalid skin '$skin'" ); - $skin = 'classic'; + Error( "Invalid skin '$skin' setting to " . $skins[0] ); + $skin = $skins[0]; } if ( isset($_GET['css']) ) $css = $_GET['css']; elseif ( isset($_COOKIE['zmCSS']) ) $css = $_COOKIE['zmCSS']; -elseif (defined(ZM_CSS_DEFAULT)) +elseif (defined('ZM_CSS_DEFAULT')) $css = ZM_CSS_DEFAULT; else $css = "classic"; $css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) ); if ( ! in_array( $css, $css_skins ) ) { - Error( "Invalid skin css '$css'" ); - $css = 'classic'; + Error( "Invalid skin css '$css' setting to " . $css_skins[0] ); + $css = $css_skins[0]; } define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) ); @@ -102,13 +102,13 @@ ini_set( "session.name", "ZMSESSID" ); session_start(); -if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) ) +if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin ) { $_SESSION['skin'] = $skin; setcookie( "zmSkin", $skin, time()+3600*24*30*12*10 ); } -if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) ) { +if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) { $_SESSION['css'] = $css; setcookie( "zmCSS", $css, time()+3600*24*30*12*10 ); } From e8114c90bb81d6898d67e8a26b6babc1a5379c55 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 May 2015 17:08:55 -0400 Subject: [PATCH 112/154] Fix printMsg. We don't use it as an object method. Update to parse a user:password out of ControlAddress which is what a lot of other scripts do. --- .../lib/ZoneMinder/Control/FI9821W_Y2k.pm | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm index 275ed0c37..9a275fda9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm @@ -102,7 +102,6 @@ sub close sub printMsg { - my $self = shift; my $msg = shift; my $msg_len = length($msg); Debug( $msg."[".$msg_len."]" ); @@ -113,9 +112,24 @@ sub sendCmd my $self = shift; my $cmd = shift; my $result = undef; + + my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice}; + $user = 'admin' if ! $user; + $password = 'pwd' if ! $password; + + $cmd .= "&usr=$user&pwd=$password"; + printMsg( $cmd, "Tx" ); - my $temps = time(); - my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/CGIProxy.fcgi?usr%3Dadmin%26pwd%3D".$self->{Monitor}->{ControlDevice}."%26cmd%3D".$cmd."%26".$temps ); + my $url; + if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) { + $url = $self->{Monitor}->{ControlAddress}; + } else { + $url = "http://".$self->{Monitor}->{ControlAddress}; + } + $url .= "/cgi-bin/CGIProxy.fcgi?cmd=$cmd%26".time; + printMsg( $url, "Tx" ); + + my $req = HTTP::Request->new( GET=>$url ); my $res = $self->{ua}->request($req); if ( $res->is_success ) { From 246fadb097f0394ab0ea10dd72d170f156db1af2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2015 08:23:16 -0400 Subject: [PATCH 113/154] support the old use of just putting the password in the control field --- scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm index 9a275fda9..dd73a04e6 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm @@ -114,6 +114,10 @@ sub sendCmd my $result = undef; my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice}; + if ( ! $password ) { + $password = $user; + $user = 'admin'; + } $user = 'admin' if ! $user; $password = 'pwd' if ! $password; From a5fed0352457aebbee05fcd8f76312410e28d480 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2015 11:33:22 -0400 Subject: [PATCH 114/154] Switch from a MIN_AGE constant in zmaudit.pl to using a ZM_AUDIT_MIN_AGE Config setting --- .../lib/ZoneMinder/ConfigData.pm.in | 14 ++++++- scripts/zmaudit.pl.in | 37 ++++++++++--------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 233d61948..e55e856e4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2368,7 +2368,6 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s category => "system", }, { - name => "ZM_AUDIT_CHECK_INTERVAL", default => "900", description => "How often to check database and filesystem consistency", @@ -2390,6 +2389,19 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s type => $types{integer}, category => "system", }, + { + name => "ZM_AUDIT_MIN_AGE", + default => "86400", + description => "The minimum age in seconds event data must be in order to be deleted.", + help => qqq(" + The zmaudit daemon exists to check that the saved information + in the database and on the filesystem match and are consistent + with each other. Event files or db records that are younger than + this setting will not be deleted and a warning will be given. + "), + type => $types{integer}, + category => "system", + }, { name => "ZM_FORCED_ALARM_SCORE", default => "255", diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 2b05d5361..2cae2cb2f 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -56,7 +56,6 @@ use bytes; # # ========================================================================== -use constant MIN_AGE => 300; # Minimum age when we will delete anything 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 @@ -246,7 +245,7 @@ MAIN: while( $loop ) { { while ( my ( $fs_event, $age ) = each(%$fs_events ) ) { - if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > MIN_AGE)) ) + if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) ) { aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" ); if ( confirm() ) @@ -308,26 +307,28 @@ MAIN: while( $loop ) { { 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; - } + if ( !defined($fs_events->{$db_event}) ) { + if ( $age > $Config{ZM_AUDIT_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 event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." ); + } } } } } else { - #aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); + aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); #if ( confirm() ) #{ # We don't actually do this in case it's new @@ -363,7 +364,7 @@ MAIN: while( $loop ) { # 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"; + WHERE isnull(F.EventId) AND now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime"; my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); $res = $selectEmptyEventsSth->execute() @@ -434,7 +435,7 @@ MAIN: while( $loop ) { 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)" + GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)" ; my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); From 9c73b7247c5d24d648c5c3128aadda3ccea19bcc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2015 11:37:13 -0400 Subject: [PATCH 115/154] Revert "Switch from a MIN_AGE constant in zmaudit.pl to using a ZM_AUDIT_MIN_AGE Config setting" This reverts commit a5fed0352457aebbee05fcd8f76312410e28d480. --- .../lib/ZoneMinder/ConfigData.pm.in | 14 +------ scripts/zmaudit.pl.in | 37 +++++++++---------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index e55e856e4..233d61948 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2368,6 +2368,7 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s category => "system", }, { + name => "ZM_AUDIT_CHECK_INTERVAL", default => "900", description => "How often to check database and filesystem consistency", @@ -2389,19 +2390,6 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s type => $types{integer}, category => "system", }, - { - name => "ZM_AUDIT_MIN_AGE", - default => "86400", - description => "The minimum age in seconds event data must be in order to be deleted.", - help => qqq(" - The zmaudit daemon exists to check that the saved information - in the database and on the filesystem match and are consistent - with each other. Event files or db records that are younger than - this setting will not be deleted and a warning will be given. - "), - type => $types{integer}, - category => "system", - }, { name => "ZM_FORCED_ALARM_SCORE", default => "255", diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 2cae2cb2f..2b05d5361 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -56,6 +56,7 @@ use bytes; # # ========================================================================== +use constant MIN_AGE => 300; # Minimum age when we will delete anything 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 @@ -245,7 +246,7 @@ MAIN: while( $loop ) { { while ( my ( $fs_event, $age ) = each(%$fs_events ) ) { - if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) ) + 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() ) @@ -307,28 +308,26 @@ MAIN: while( $loop ) { { while ( my ( $db_event, $age ) = each(%$db_events ) ) { - if ( !defined($fs_events->{$db_event}) ) { - if ( $age > $Config{ZM_AUDIT_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 event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." ); - } + 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" ); + #aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); #if ( confirm() ) #{ # We don't actually do this in case it's new @@ -364,7 +363,7 @@ MAIN: while( $loop ) { # 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 ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime"; + 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() @@ -435,7 +434,7 @@ MAIN: while( $loop ) { 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 ".$Config{ZM_AUDIT_MIN_AGE}." second)" + 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() ); From 950cd0653566294fad789ee3e14aeac5757e72fc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2015 11:38:55 -0400 Subject: [PATCH 116/154] Revert "Revert "Switch from a MIN_AGE constant in zmaudit.pl to using a ZM_AUDIT_MIN_AGE Config setting"" This reverts commit 9c73b7247c5d24d648c5c3128aadda3ccea19bcc. --- .../lib/ZoneMinder/ConfigData.pm.in | 14 ++++++- scripts/zmaudit.pl.in | 37 ++++++++++--------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 233d61948..e55e856e4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2368,7 +2368,6 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s category => "system", }, { - name => "ZM_AUDIT_CHECK_INTERVAL", default => "900", description => "How often to check database and filesystem consistency", @@ -2390,6 +2389,19 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s type => $types{integer}, category => "system", }, + { + name => "ZM_AUDIT_MIN_AGE", + default => "86400", + description => "The minimum age in seconds event data must be in order to be deleted.", + help => qqq(" + The zmaudit daemon exists to check that the saved information + in the database and on the filesystem match and are consistent + with each other. Event files or db records that are younger than + this setting will not be deleted and a warning will be given. + "), + type => $types{integer}, + category => "system", + }, { name => "ZM_FORCED_ALARM_SCORE", default => "255", diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 2b05d5361..2cae2cb2f 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -56,7 +56,6 @@ use bytes; # # ========================================================================== -use constant MIN_AGE => 300; # Minimum age when we will delete anything 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 @@ -246,7 +245,7 @@ MAIN: while( $loop ) { { while ( my ( $fs_event, $age ) = each(%$fs_events ) ) { - if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > MIN_AGE)) ) + if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) ) { aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" ); if ( confirm() ) @@ -308,26 +307,28 @@ MAIN: while( $loop ) { { 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; - } + if ( !defined($fs_events->{$db_event}) ) { + if ( $age > $Config{ZM_AUDIT_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 event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." ); + } } } } } else { - #aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); + aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); #if ( confirm() ) #{ # We don't actually do this in case it's new @@ -363,7 +364,7 @@ MAIN: while( $loop ) { # 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"; + WHERE isnull(F.EventId) AND now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime"; my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); $res = $selectEmptyEventsSth->execute() @@ -434,7 +435,7 @@ MAIN: while( $loop ) { 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)" + GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)" ; my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); From 3709ac411d6818f330e2fd7296d31316bd845cc2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2015 12:36:35 -0400 Subject: [PATCH 117/154] Not having ZM_AUDIT_MIN_AGE should be fatal --- scripts/zmaudit.pl.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 2cae2cb2f..8aec72bb7 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -138,6 +138,10 @@ MAIN: while( $loop ) { } # end if } # end while can't connect to the db + if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) { + Fatal("ZM_AUDIT_MIN_AGE is not set in config."); + } + my $db_monitors; my $monitorSelectSql = "select Id from Monitors order by Id"; my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) From 691fbbb0a6c6736d1d84c1f5e340f66937bdecb7 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 14 May 2015 09:06:42 -0500 Subject: [PATCH 118/154] Update README.md --- README.md | 58 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e43da4ccc..a8fa57e24 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,46 @@ All documentation for ZoneMinder is now online at http://www.zoneminder.com/wiki ZoneMinder is an integrated set of applications which provide a complete surveillance solution allowing capture, analysis, recording and monitoring of any CCTV or security cameras attached to a Linux based machine. It is designed to run on distributions which support the Video For Linux (V4L) interface and has been tested with video cameras attached to BTTV cards, various USB cameras and also supports most IP network cameras. -## Requirements +## Installation Methods -If you are installing ZoneMinder from a package, that package should provide all of the needed core components. +### Building from Source is Discouraged -### Packages +Historically, installing ZoneMinder onto your system required building from source code by issuing the traditional configure, make, make install commands. To get ZoneMinder to build, all of its dependencies had to be determined and installed beforehand. Init and logrotate scripts had to be manually copied into place following the build. Optional packages such as jscalendar and Cambozola had to be manually installed. Uninstalls could leave stale files around, which could cause problems during an upgrade. Speaking of upgrades, when it comes time to upgrade all these manual steps must be repeated again. -If you are compiling ZoneMinder from source, the below list contains the packages needed to get ZoneMinder built: +Better methods exist today that do much of this for you. The current development team has taken great strides in providing the resources necessary to avoid building from source. + +### Install from a Package Repository + +This is the recommended method to install ZoneMinder onto your system. ZoneMinder packages are maintained for the following distros: + +- Ubuntu via Iconnor's PPA: https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder +- Debian from their default repository: https://packages.debian.org/search?searchon=names&keywords=zoneminder +- RHEL/CentOS and clones: http://zmrepo.zoneminder.com/ +- Fedora: http://zmrepo.zoneminder.com/ +- OpenSuse via third party repository: http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE +- Maegia from their default repository + +If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own. + +### Building a ZoneMinder Package + +Building ZoneMinder into a package is not any harder than building from source. As a matter of fact, if you have successfully built ZoneMinder from source in the past, then you may find these steps to be easier. + +When building a package, it is best to do this work in a separate environment, dedicated to development purposes. This could be as simple as creating a virtual machine, using Docker, or using mock. All it takes is one “Oops” to regret doing this work on your production server. + +Lastly, if you desire to build a development snapshot from the master branch, it is recommended you first build your package using an official release of ZoneMinder. This will help identify whether any problems you may encounter are caused by the build process or is a new issue in the master branch. + +What follows are instructions for various distros to build ZoneMinder into a package. + +### Package Maintainters +Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source. + +For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script: +```bash +./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes +``` + +Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure. #### Ubuntu @@ -103,6 +136,8 @@ root@host:~# gdebi /root/zoneminder_1.26.4-1_amd64.deb; #### CentOS / RHEL +DEPRECIATED. The steps below are depreciated. I am in the middle of rewriting this entire section. + Additional repositories must be added before one can build zoneminder on CentOS or RHEL: 1. Zmrepo [ZoneMinder WiKi](http://www.zoneminder.com/wiki/index.php/CentOS#Zmrepo_-_A_ZoneMinder_repository_for_RPM_based_distros) @@ -144,11 +179,6 @@ Docker is a system to run applications inside isolated containers. ZoneMinder, a Dockerfile contained in this repository. However, there is still work needed to ensure that the main ZM features work properly and are documented. -### ffmpeg - -This release of ZoneMinder has been tested on and works with ffmpeg version N-55540-g93f4277. - - ## Contribution Model and Development * Source hosted at [GitHub](https://github.com/ZoneMinder/ZoneMinder/) @@ -169,14 +199,4 @@ the following steps. 6. Create new Pull Request 7. The team will then review, discuss and hopefully merge your changes. -### Package Maintainters -Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source. - -For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script: -```bash -./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes -``` - -Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure. - [![Analytics](https://ga-beacon.appspot.com/UA-15147273-6/ZoneMinder/README.md)](https://github.com/igrigorik/ga-beacon) From 8eb5e53aad4e9739e3f86a84d31a231fc8625004 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 May 2015 10:27:11 -0400 Subject: [PATCH 119/154] Remove with {ZM_PATH_SWAP} --- scripts/zmaudit.pl.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 8aec72bb7..7a74303fc 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -119,7 +119,6 @@ chdir( EVENT_PATH ); my $max_image_age = 6/24; # 6 hours my $max_swap_age = 24/24; # 24 hours my $image_path = IMAGE_PATH; -my $swap_image_path = $Config{ZM_PATH_SWAP}; my $loop = 1; my $cleaned = 0; @@ -498,7 +497,7 @@ MAIN: while( $loop ) { } # Now delete any old swap files - ( my $swap_image_root ) = ( $swap_image_path =~ /^(.*)$/ ); # De-taint + ( my $swap_image_root ) = ( $Config{ZM_PATH_SWAP} =~ /^(.*)$/ ); # De-taint File::Find::find( { wanted=>\&deleteSwapImage, untaint=>1 }, $swap_image_root ); # Prune the Logs table if required From a1ca1a8af5aa53f4ba987cea70d138c90410cc0a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 14 May 2015 10:02:35 -0500 Subject: [PATCH 120/154] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8fa57e24..c5893a4a8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ZoneMinder is an integrated set of applications which provide a complete surveil Historically, installing ZoneMinder onto your system required building from source code by issuing the traditional configure, make, make install commands. To get ZoneMinder to build, all of its dependencies had to be determined and installed beforehand. Init and logrotate scripts had to be manually copied into place following the build. Optional packages such as jscalendar and Cambozola had to be manually installed. Uninstalls could leave stale files around, which could cause problems during an upgrade. Speaking of upgrades, when it comes time to upgrade all these manual steps must be repeated again. -Better methods exist today that do much of this for you. The current development team has taken great strides in providing the resources necessary to avoid building from source. +Better methods exist today that do much of this for you. The current development team, along with other volunteers, have taken great strides in providing the resources necessary to avoid building from source. ### Install from a Package Repository From a03f3f39b56af9b48f082f4e165b44808d6215df Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 14 May 2015 10:06:16 -0500 Subject: [PATCH 121/154] Update README.md Better http link formatting --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c5893a4a8..c7a76a8b7 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ Better methods exist today that do much of this for you. The current development This is the recommended method to install ZoneMinder onto your system. ZoneMinder packages are maintained for the following distros: -- Ubuntu via Iconnor's PPA: https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder -- Debian from their default repository: https://packages.debian.org/search?searchon=names&keywords=zoneminder -- RHEL/CentOS and clones: http://zmrepo.zoneminder.com/ -- Fedora: http://zmrepo.zoneminder.com/ -- OpenSuse via third party repository: http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE +- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder) +- Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder) +- RHEL/CentOS and clones via [zmrepo](http://zmrepo.zoneminder.com/) +- Fedora via [zmrepo](http://zmrepo.zoneminder.com/) +- OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE) - Maegia from their default repository If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own. From d8cd6abc063595d2837a6c8b6784e17334643a9a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:00:39 -0500 Subject: [PATCH 122/154] Update README.md One of may commits to update build instructions for Redhat based distros --- README.md | 92 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c7a76a8b7..14c5e1a0b 100644 --- a/README.md +++ b/README.md @@ -134,44 +134,84 @@ root@host:~# aptitude install -y gdebi; root@host:~# gdebi /root/zoneminder_1.26.4-1_amd64.deb; ``` -#### CentOS / RHEL +#### Fedora / CentOS / RHEL -DEPRECIATED. The steps below are depreciated. I am in the middle of rewriting this entire section. +***DRAFT* ** Needs Testing -Additional repositories must be added before one can build zoneminder on CentOS or RHEL: +##### Background +The following method documents how to build ZoneMinder into an RPM package, compatible with Fedora, Redhat, CentOS, and other compatible clones. This is exactly how the RPMS in zmrepo are built. -1. Zmrepo [ZoneMinder WiKi](http://www.zoneminder.com/wiki/index.php/CentOS#Zmrepo_-_A_ZoneMinder_repository_for_RPM_based_distros) -2. EPEL https://fedoraproject.org/wiki/EPEL -3. RPMFusion: http://rpmfusion.org/ +The method documented below was chosen because: +- All of ZoneMinder's dependencies are downloaded and installed automatically +- Cross platform capable. The build host does not have to be the same distro or release version as the target. +- Once your build environment is set up, very few steps are required to run the build again in the future. -When adding third party repositories, it is highly recommended that the user also install and configure yum priorities as documented in the [CentOS WiKi](http://wiki.centos.org/PackageManagement/Yum/Priorities) +***IMPORTANT*** +Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build. -Prioritize the repositories: +##### Set Up Your Environment +Before you begin, set up an rpmbuild environment by following [this guide](http://wiki.centos.org/HowTos/SetupRpmBuildEnvironment) by the CentOS developers. -1. Base -2. EPEL -3. RPMFusion -4. Zmrepo +Next, navigate to [Zmrepo](http://zmrepo.zoneminder.com/), and follow the instructions to enable zmrepo on your system. -Once your repos are in order, install the following: -```bash -sudo yum install cmake bzip2-devel ffmpeg ffmpeg-devel gnutls-devel httpd libjpeg-turbo libjpeg-turbo-devel mysql-devel mysql-server pcre-devel \ -perl-Archive-Tar perl-Archive-Zip perl-Convert-BinHex perl-Date-Manip perl-DBD-MySQL perl-DBI perl-Device-SerialPort perl-Email-Date-Format perl-IO-stringy \ -perl-IO-Zlib perl-MailTools perl-MIME-Lite perl-MIME-tools perl-MIME-Types perl-Module-Load perl-Package-Constants perl-Sys-Mmap perl-Time-HiRes \ -perl-TimeDate perl-YAML-Syck perl-X10 perl-URI-Encode php php-cli php-mysql x264 vlc-devel vlc-core \ -libcurl libcurl-devel polkit-devel git +With zmrepo enabled, issue the following command: +````bash +sudo yum install zmrepo-mock-configs mock ``` -To build from the master branch: +As an alternative to enabling zmrepo, you may simply browse for and download the latest version of the “zmrepo-mock-configs” rpm. + +On CentOS 7 for example: ```bash -git clone https://github.com/ZoneMinder/ZoneMinder.git -cd ZoneMinder -cmake . -make -sudo make install +wget http://zmrepo.zoneminder.com/el/7/x86_64/zmrepo-mock-configs-1.0-1.el7.centos.noarch.rpm +``` +Then install it: +```bash +sudo yum install zmrepo-mock-configs-1.0-1.el7.centos.noarch.rpm +``` +Add your user account to the group mock: +```bash +sudo gpasswd -a {your account name} mock ``` -IMPORTANT: Don't forget the trailing "." when calling cmake +Your build is environment is now set up. + +##### Build from SRPM +To continue, you need a ZoneMinder SRPM. For starters, let's use one of the SRPMS from zmrepo. Go browse the [Zmrepo](http://zmrepo.zoneminder.com/) site and choose an appropriate SRPM and place it into the ~/rpmbuild/SRPMS folder. + +For CentOS 7, I have chosen the following SRPM: +```bash +wget -P ~/rpmbuild/SRPMS http://zmrepo.zoneminder.com/el/7/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm +``` + +Now comes the fun part. To build ZoneMinder, issue the following command: +```bash +buildzm.sh zmrepo-el7-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm +``` + +Want to build ZoneMinder for Fedora, instead of CentOS, from the same host? Once you download the Fedora SRPM, issue the following: +```bash +buildzm.sh zmrepo-f21-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-1.fc21.src.rpm +``` +Notice that the buildzm.sh tool requires the following parameters: +```bash +buildzm.sh MOCKCONFIG ZONEMINDER_SRPM +``` +The list of available Mock config files are available here: +```bash +ls /etc/mock/zmrepo*.cfg +``` + +You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). + +##### Installation +Once the build completes, you will get a folder listing of the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo, and then install the rpm by issuing the appropriate yum install command. + +Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. + +##### How to Modify the Source Prior to Build +UP NEXT (TO-DO) +How to modify the source files before building #### Docker From 134b6b1dbb6b8d74d39439aaaccd87b00b56a89b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:22:02 -0500 Subject: [PATCH 123/154] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14c5e1a0b..5b9fd30fe 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,8 @@ The method documented below was chosen because: - Cross platform capable. The build host does not have to be the same distro or release version as the target. - Once your build environment is set up, very few steps are required to run the build again in the future. +The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. It's goal is simply to make the process a littel easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire. + ***IMPORTANT*** Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build. @@ -205,7 +207,7 @@ ls /etc/mock/zmrepo*.cfg You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). ##### Installation -Once the build completes, you will get a folder listing of the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo, and then install the rpm by issuing the appropriate yum install command. +Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo, and then install the rpm by issuing the appropriate yum install command. Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. From 04f698824f46ed033b27a5b9d5196fa8b2b7df33 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:23:14 -0500 Subject: [PATCH 124/154] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b9fd30fe..bc2ea5cad 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ The method documented below was chosen because: - Cross platform capable. The build host does not have to be the same distro or release version as the target. - Once your build environment is set up, very few steps are required to run the build again in the future. -The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. It's goal is simply to make the process a littel easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire. +The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. The goal of the script is to simply make the process a little easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire. ***IMPORTANT*** Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build. From 3c5e05d1f46a33148b100ee950cb1cd942c53fd9 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:24:35 -0500 Subject: [PATCH 125/154] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bc2ea5cad..35a629972 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,8 @@ The following method documents how to build ZoneMinder into an RPM package, comp The method documented below was chosen because: - All of ZoneMinder's dependencies are downloaded and installed automatically - Cross platform capable. The build host does not have to be the same distro or release version as the target. -- Once your build environment is set up, very few steps are required to run the build again in the future. +- Once your build environment is set up, few steps are required to run the build again in the future. +- Troubleshooting becomes easier if we are all building ZoneMinder the same way. The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. The goal of the script is to simply make the process a little easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire. From 9d4916ad49872be6833236d9a6441cd8fafe092c Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:27:46 -0500 Subject: [PATCH 126/154] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35a629972..41561cca0 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ The list of available Mock config files are available here: ls /etc/mock/zmrepo*.cfg ``` -You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). +You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). Notice that, when specifying the Mock config as a commandline parameter, you should leave off the ".cfg" filename extension. ##### Installation Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo, and then install the rpm by issuing the appropriate yum install command. From 8545f30d727409003fc81d5339b6944e025c6ad8 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:30:07 -0500 Subject: [PATCH 127/154] Update README.md typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 41561cca0..b26082290 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ Add your user account to the group mock: sudo gpasswd -a {your account name} mock ``` -Your build is environment is now set up. +Your build environment is now set up. ##### Build from SRPM To continue, you need a ZoneMinder SRPM. For starters, let's use one of the SRPMS from zmrepo. Go browse the [Zmrepo](http://zmrepo.zoneminder.com/) site and choose an appropriate SRPM and place it into the ~/rpmbuild/SRPMS folder. From 466c6d9dd8a03d3f47714b9255d4dc0fd37fced2 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 15:35:49 -0500 Subject: [PATCH 128/154] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b26082290..a7a2c4040 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ ls /etc/mock/zmrepo*.cfg You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). Notice that, when specifying the Mock config as a commandline parameter, you should leave off the ".cfg" filename extension. ##### Installation -Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo, and then install the rpm by issuing the appropriate yum install command. +Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo per the instruction on the [Zmrepo](http://zmrepo.zoneminder.com/) website, and then install the rpm by issuing the appropriate yum install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder. Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. From 9bd4fa6c8aab9d53a29cea5b23fad4c31b203ccc Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 16:20:37 -0500 Subject: [PATCH 129/154] Update README.md --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a7a2c4040..789ad9378 100644 --- a/README.md +++ b/README.md @@ -213,8 +213,48 @@ Once the build completes, you will be presented with a folder containing the RPM Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. ##### How to Modify the Source Prior to Build -UP NEXT (TO-DO) -How to modify the source files before building +** UNFINISHED ** + +Before attempting this part of the instructions, make sure and follow the previous instructions for building one of the unmodified SRPMS from zmrepo. Knowing this part works will assist in troubleshooting should somethint go wrong. + +These instructions may vary depending on what exactly you want to do. The following example assumes you want to build a development snapshot from the master branch. + +From the previous instructions, we downloaded a CentOS 7 ZoneMinder SRPM and placed it into ~/rpmbuild/SRPMS. For this example, install it onto your system: +```bash +rpm -Uvh ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm +``` + +IMPORTANT: This operation must be done with your normal user account. Do *not* perform this command as root. + +Make sure you have git installed: +```bash +sudo yum install git +``` + +Now clone the ZoneMinder git repository: +```bash +git clone https://github.com/ZoneMinder/ZoneMinder +``` +This will create a sub-folder called ZoneMinder, which will contain the latest developement. + +We want to turn this into a tarball, but first we need to figure out what to name it. Look here: +```bash +ls ~/rpmbuild/SOURCES +``` +The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From one folder above the local ZoneMinder git repository, execute the following: +```bash +mv ZoneMinder ZoneMinder-1.28.1 +tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1 +``` +Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball. + +Now build a new src.rpm: +```bash +rpmbuild -bs --nodeps ~/rpmbuild/SPECS/zoneminder.el7.spec +``` +This step will overwrite the SRPM you originally downloaded, so you may want to back it up prior to completing this step. Note that the name of the specfile will vary slightly depending on what distro you are building for. + +You should now have a a new SRPM under ~/rpmbuild/SRPMS. In our example, the SRPM is called zoneminder-1.28.1-2.el7.centos.src.rpm. Now follow the previous instructions that describe how to use the buildzm script, using ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm as the path to your SRPM. #### Docker From b65d08b4455f7b4703c47293473b99f0ac78d15a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 16:21:22 -0500 Subject: [PATCH 130/154] Update README.md typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 789ad9378..c0ba12f99 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Finally, you may want to consider editing the zmrepo repo file under /etc/yum.re ##### How to Modify the Source Prior to Build ** UNFINISHED ** -Before attempting this part of the instructions, make sure and follow the previous instructions for building one of the unmodified SRPMS from zmrepo. Knowing this part works will assist in troubleshooting should somethint go wrong. +Before attempting this part of the instructions, make sure and follow the previous instructions for building one of the unmodified SRPMS from zmrepo. Knowing this part works will assist in troubleshooting should something go wrong. These instructions may vary depending on what exactly you want to do. The following example assumes you want to build a development snapshot from the master branch. From ea7c1f68836f474a82bcd32b4ed80a5fdaf2aa7d Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 17 May 2015 16:34:08 -0500 Subject: [PATCH 131/154] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c0ba12f99..e3beca731 100644 --- a/README.md +++ b/README.md @@ -244,8 +244,9 @@ ls ~/rpmbuild/SOURCES The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From one folder above the local ZoneMinder git repository, execute the following: ```bash mv ZoneMinder ZoneMinder-1.28.1 -tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1 +tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1/* ``` +The trailing "/*" leaves off the hidden dot "." file and folders from the git repo, which is what we want. Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball. Now build a new src.rpm: From 12516da3dc01774d029761a5e5efe703ba405897 Mon Sep 17 00:00:00 2001 From: Rick Sayre Date: Sun, 17 May 2015 17:18:54 -0700 Subject: [PATCH 132/154] Patched in changes to 1.28.1 to allow OmniOS/Illumos to build and work haven't attempted to build yet, there are some changes --- configure.ac | 5 +++++ scripts/zmdc.pl.in | 2 ++ scripts/zmpkg.pl.in | 16 +++++++++++++--- scripts/zmupdate.pl.in | 14 +++++++------- src/zm.h | 4 ++++ src/zm_box.h | 4 ++++ src/zm_comms.cpp | 4 ++++ src/zm_ffmpeg_camera.cpp | 6 ++++++ src/zm_image.cpp | 4 ++++ src/zm_logger.cpp | 3 +++ src/zm_monitor.cpp | 5 +++++ src/zm_poly.cpp | 4 ++++ src/zm_remote_camera_http.cpp | 4 ++++ src/zm_thread.h | 15 +++++++++++++++ src/zm_timer.h | 4 ++++ web/includes/config.php.in | 9 +++++++-- zm.conf.in | 3 +++ 17 files changed, 94 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 35e0e7fb9..707cd4629 100644 --- a/configure.ac +++ b/configure.ac @@ -34,6 +34,11 @@ case $host_os in HOST_OS='BSD' AC_DEFINE(BSD,1,"This is a BSD system") ;; + *solaris*) + # Do something specific for Solaris + HOST_OS='solaris' + AC_DEFINE(SOLARIS,1,"We are running a Solaroid OS [tested on OmniOS]") + ;; *) #Default Case AC_MSG_ERROR([Your platform is not currently supported]) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 5a0ce9eef..981f7364e 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -834,6 +834,8 @@ sub killAll if ( '@HOST_OS@' eq 'BSD' ) { $killall = 'killall -'; + } elsif ( '@HOST_OS@' eq 'solaris' ) { + $killall = 'pkill -'; } else { $killall = 'killall -q -s '; } diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 5686f2596..d696bb0d0 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -189,7 +189,7 @@ if ( $command =~ /^(?:start|restart)$/ ) if ( $status eq "stopped" ) { if ( $Config{ZM_DYN_DB_VERSION} - and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) + and ( $Config{ZM_DYN_DB_VERSION} ne $Config{ZM_VERSION} ) ) { Fatal( "Version mismatch, system is version ".ZM_VERSION @@ -294,7 +294,12 @@ sub systemdRunning { my $result = 0; - my $output = qx(ps -o comm="" 1); + my $output; + if ( '@HOST_OS@' eq 'solaris' ) { + $output = qx(ps -o comm="" -p 1); + } else { + $output = qx(ps -o comm="" 1); + } chomp( $output ); if ($output =~ /systemd/) { @@ -309,7 +314,12 @@ sub calledBysystem my $result = 0; my $ppid = getppid(); - my $output = qx(ps -o comm="" $ppid); + my $output; + if ( '@HOST_OS@' eq 'solaris' ) { + $output = qx(ps -o comm="" -p $ppid); + } else { + $output = qx(ps -o comm="" $ppid); + } chomp( $output ); if ($output =~ /^(?:systemd|init)$/) { diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 75ac52fa0..6ffd00e4c 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -82,7 +82,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS} $| = 1; -$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; +$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin:/opt/local/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; @@ -165,7 +165,7 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) use LWP::UserAgent; my $ua = LWP::UserAgent->new; - $ua->agent( "ZoneMinder Update Agent/".ZM_VERSION ); + $ua->agent( "ZoneMinder Update Agent/".$Config{ZM_VERSION} ); if ( $Config{ZM_UPDATE_CHECK_PROXY} ) { $ua->proxy( "http", $Config{ZM_UPDATE_CHECK_PROXY} ); } @@ -374,13 +374,13 @@ if ( $version ) my ( $detaint_version ) = $version =~ /^([\w.]+)$/; $version = $detaint_version; - if ( ZM_VERSION eq $version ) + if ( $Config{ZM_VERSION} eq $version ) { print( "\nDatabase already at version $version, update aborted.\n\n" ); exit( 0 ); } - print( "\nInitiating database upgrade to version ".ZM_VERSION." from version $version\n" ); + print( "\nInitiating database upgrade to version ".$Config{ZM_VERSION}." from version $version\n" ); if ( $interactive ) { if ( $Config{ZM_DYN_DB_VERSION} && $Config{ZM_DYN_DB_VERSION} ne $version ) @@ -489,7 +489,7 @@ if ( $version ) } - print( "\nUpgrading database to version ".ZM_VERSION."\n" ); + print( "\nUpgrading database to version ".$Config{ZM_VERSION}."\n" ); # Update config first of all loadConfigFromDB(); @@ -1050,7 +1050,7 @@ if ( $version ) if ( $cascade ) { - my $installed_version = ZM_VERSION; + my $installed_version = $Config{ZM_VERSION}; my $sql = "update Config set Value = ? where Name = ?"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( "$installed_version", "ZM_DYN_DB_VERSION" ) or die( "Can't execute: ".$sth->errstr() ); @@ -1061,7 +1061,7 @@ if ( $version ) zmDbDisconnect(); die( "Can't find upgrade from version '$version'" ); } - print( "\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n" ); + print( "\nDatabase upgrade to version ".$Config{ZM_VERSION}." successful.\n\n" ); } zmDbDisconnect(); exit( 0 ); diff --git a/src/zm.h b/src/zm.h index 38af33bf6..be2882f8d 100644 --- a/src/zm.h +++ b/src/zm.h @@ -25,6 +25,10 @@ #define ZM_H #include "zm_config.h" +#ifdef SOLARIS +#undef DEFAULT_TYPE // pthread defines this which breaks StreamType DEFAULT_TYPE +#include // define strerror() and friends +#endif #include "zm_logger.h" #include diff --git a/src/zm_box.h b/src/zm_box.h index 8a18b8847..8aa341d73 100644 --- a/src/zm_box.h +++ b/src/zm_box.h @@ -23,7 +23,11 @@ #include "zm.h" #include "zm_coord.h" +#ifndef SOLARIS #include +#else +#include +#endif // // Class used for storing a box, which is defined as a region diff --git a/src/zm_comms.cpp b/src/zm_comms.cpp index c42b7bd17..a109019bd 100644 --- a/src/zm_comms.cpp +++ b/src/zm_comms.cpp @@ -36,6 +36,10 @@ #include #include +#ifdef SOLARIS +#include // define FIONREAD +#endif + int CommsBase::readV( int iovcnt, /* const void *, int, */ ... ) { va_list arg_ptr; diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 225d9ec66..09d39ab53 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -27,6 +27,12 @@ #define AV_ERROR_MAX_STRING_SIZE 64 #endif +#ifdef SOLARIS +#include // for ESRCH +#include +#include +#endif + FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), mPath( p_path ), diff --git a/src/zm_image.cpp b/src/zm_image.cpp index eb7510cf5..21e190ffb 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -1580,7 +1580,11 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres { uint8_t *psrc = images[j]->buffer+c; +#ifndef SOLARIS if ( (unsigned)abs((*psrc)-RGB_VAL(ref_colour,c)) >= RGB_VAL(threshold,c) ) +#else + if ( (unsigned)std::abs((*psrc)-RGB_VAL(ref_colour,c)) >= RGB_VAL(threshold,c) ) +#endif { count++; } diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index df3bdde4d..f6cc9523b 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -542,7 +542,10 @@ void Logger::logPrint( bool hex, const char * const file, const int line, const if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id # else + // SOLARIS doesn't have SYS_gettid; don't assume + #ifdef SYS_gettid if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id + #endif // SYS_gettid #endif #endif // HAVE_SYSCALL #endif diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index f2ae97215..f990bf320 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -55,6 +55,11 @@ #include #endif // ZM_MEM_MAPPED +// SOLARIS - we don't have MAP_LOCKED on openSolaris/illumos +#ifndef MAP_LOCKED +#define MAP_LOCKED 0 +#endif + //============================================================================= std::vector split(const std::string &s, char delim) { std::vector elems; diff --git a/src/zm_poly.cpp b/src/zm_poly.cpp index eef5dd56a..4eee73f46 100644 --- a/src/zm_poly.cpp +++ b/src/zm_poly.cpp @@ -20,7 +20,11 @@ #include "zm.h" #include "zm_poly.h" +#ifndef SOLARIS #include +#else +#include +#endif void Polygon::calcArea() { diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index fdbfd69a6..c6de64aed 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -26,6 +26,10 @@ #include #include +#ifdef SOLARIS +#include // FIONREAD and friends +#endif + RemoteCameraHttp::RemoteCameraHttp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : RemoteCamera( p_id, "http", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture ) { diff --git a/src/zm_thread.h b/src/zm_thread.h index 54190547c..615bec6aa 100644 --- a/src/zm_thread.h +++ b/src/zm_thread.h @@ -35,6 +35,7 @@ class ThreadException : public Exception { private: +#ifndef SOLARIS pid_t pid() { pid_t tid; #ifdef __FreeBSD__ @@ -50,6 +51,9 @@ pid_t pid() { #endif return tid; } +#else +pthread_t pid() { return( pthread_self() ); } +#endif public: ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { } @@ -213,7 +217,11 @@ protected: Mutex mThreadMutex; Condition mThreadCondition; +#ifndef SOLARIS pid_t mPid; +#else + pthread_t mPid; +#endif bool mStarted; bool mRunning; @@ -221,6 +229,7 @@ protected: Thread(); virtual ~Thread(); +#ifndef SOLARIS pid_t id() const { pid_t tid; @@ -238,6 +247,12 @@ protected: #endif return tid; } +#else + pthread_t id() const + { + return( pthread_self() ); + } +#endif void exit( int status = 0 ) { //INFO( "Exiting" ); diff --git a/src/zm_timer.h b/src/zm_timer.h index f7f74aa7d..7afe0a647 100644 --- a/src/zm_timer.h +++ b/src/zm_timer.h @@ -33,6 +33,7 @@ private: class TimerException : public Exception { private: +#ifndef SOLARIS pid_t pid() { pid_t tid; #ifdef __FreeBSD__ @@ -48,6 +49,9 @@ private: #endif return tid; } +#else + pthread_t pid() { return( pthread_self() ); } +#endif public: TimerException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { diff --git a/web/includes/config.php.in b/web/includes/config.php.in index fbcb0e7b3..54257fc16 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -22,8 +22,6 @@ // This section contains options substituted by the zmconfig.pl utility, do not edit these directly // define( "ZM_CONFIG", "@ZM_CONFIG@" ); // Path to config file -// Define, and override any given in config file -define( "ZM_VERSION", "@VERSION@" ); // Version $configFile = ZM_CONFIG; $localConfigFile = basename($configFile); @@ -48,6 +46,13 @@ while ( !feof($cfg) ) define( $matches[1], $matches[2] ); } fclose( $cfg ); + +// Define, and override any given in config file +// to override, must be done AFTER asignment, cripes +// @VERSION@ hasn't been defined in tests, perhaps configure.ac needs fix? +if (!defined("ZM_VERSION")) { // avoid double definition warning + define( "ZM_VERSION", "@VERSION@" ); // Version +} // // This section is options normally derived from other options or configuration diff --git a/zm.conf.in b/zm.conf.in index 9cc3d42de..f3bdb0471 100644 --- a/zm.conf.in +++ b/zm.conf.in @@ -48,3 +48,6 @@ ZM_DB_PASS=@ZM_DB_PASS@ # Host of this machine ZM_SERVER_HOST= + +# Version of zoneminder - must be set +ZM_VERSION=1.28.1 From b52b7ea89bb4ec3b0def246dd805cee2e17a6bd3 Mon Sep 17 00:00:00 2001 From: Rick Sayre Date: Sun, 17 May 2015 17:34:52 -0700 Subject: [PATCH 133/154] Added OmniOS/Solaris info --- README-OmniOS.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 README-OmniOS.txt diff --git a/README-OmniOS.txt b/README-OmniOS.txt new file mode 100644 index 000000000..de2f2f6bd --- /dev/null +++ b/README-OmniOS.txt @@ -0,0 +1,17 @@ +The following has worked [with newest patches] with buildtools and gcc48 from pkg, +and ffmpeg2, LAMP and libjpeg-turbo from pkgin for OmniOS r151012 and r151014 + +./bootstrap.sh +# omnios default is 32bit, -m64 is unneeded if perl/libs versions match +export CXXFLAGS=-m64 +export CFLAGS=-m64 +export PERL=/usr/perl5/5.16.1/bin/amd64/perl +export CPPFLAGS="-I/opt/local/include/ffmpeg2 -I/opt/local/include/mysql +-I/opt/local/include" +# need the -R for runtime load library +export LDFLAGS="-L/opt/local/lib/ffmpeg2 -L/opt/local/lib -R/opt/local/lib +-R/opt/local/lib/ffmpeg2" +export ZM_SSL_LIB=openssl +# need -lsocket -lnsl for recv/send to work, and latest version needs -lsendfile +./configure --with-webdir=/opt/local/share/httpd/htdocs/zm --with-extralibs="-lsocket -lnsl -lsendfile" --with-cgidir=/opt/local/libexec/cgi-bin --with-webuser=www --with-webgroup=www --with-webhost=MACHINENAME.local + From f638b077fcba402143670b2af3f8f4783d59e585 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 18 May 2015 16:58:11 -0500 Subject: [PATCH 134/154] Update README.md --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index e3beca731..052a0467c 100644 --- a/README.md +++ b/README.md @@ -162,16 +162,6 @@ With zmrepo enabled, issue the following command: sudo yum install zmrepo-mock-configs mock ``` -As an alternative to enabling zmrepo, you may simply browse for and download the latest version of the “zmrepo-mock-configs” rpm. - -On CentOS 7 for example: -```bash -wget http://zmrepo.zoneminder.com/el/7/x86_64/zmrepo-mock-configs-1.0-1.el7.centos.noarch.rpm -``` -Then install it: -```bash -sudo yum install zmrepo-mock-configs-1.0-1.el7.centos.noarch.rpm -``` Add your user account to the group mock: ```bash sudo gpasswd -a {your account name} mock From fb5c1abc878be8d1b9996eb3cdd4a30844a45caf Mon Sep 17 00:00:00 2001 From: Rick Sayre Date: Mon, 18 May 2015 21:44:41 -0700 Subject: [PATCH 135/154] Undid ZM_VERSION hacks --- scripts/zmpkg.pl.in | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index d696bb0d0..362f4f6a6 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -189,7 +189,7 @@ if ( $command =~ /^(?:start|restart)$/ ) if ( $status eq "stopped" ) { if ( $Config{ZM_DYN_DB_VERSION} - and ( $Config{ZM_DYN_DB_VERSION} ne $Config{ZM_VERSION} ) + and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) ) { Fatal( "Version mismatch, system is version ".ZM_VERSION @@ -294,12 +294,7 @@ sub systemdRunning { my $result = 0; - my $output; - if ( '@HOST_OS@' eq 'solaris' ) { - $output = qx(ps -o comm="" -p 1); - } else { - $output = qx(ps -o comm="" 1); - } + my $output = qx(ps -o comm="" -p 1); chomp( $output ); if ($output =~ /systemd/) { @@ -314,12 +309,7 @@ sub calledBysystem my $result = 0; my $ppid = getppid(); - my $output; - if ( '@HOST_OS@' eq 'solaris' ) { - $output = qx(ps -o comm="" -p $ppid); - } else { - $output = qx(ps -o comm="" $ppid); - } + my $output = qx(ps -o comm="" -p $ppid); chomp( $output ); if ($output =~ /^(?:systemd|init)$/) { From ffe46978d268fe7010eb0b6d82b4830bda267ff1 Mon Sep 17 00:00:00 2001 From: Rick Sayre Date: Mon, 18 May 2015 21:49:08 -0700 Subject: [PATCH 136/154] Undid PATH change, needed for mysqldump; which I see is indeed called many other places with incorrect paths. Make macros should be setting all this up correctly! mysqldump is [for example] in /opt/local/bin, not /usr/bin, with pkgin --- scripts/zmupdate.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 6ffd00e4c..e5b8e3d0d 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -82,7 +82,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS} $| = 1; -$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin:/opt/local/bin'; +$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; From 8c7e633d8f70030f2b389f12bc4525c473b64af8 Mon Sep 17 00:00:00 2001 From: Rick Sayre Date: Mon, 18 May 2015 21:55:00 -0700 Subject: [PATCH 137/154] Undo ZM_VERSION changes --- scripts/zmupdate.pl.in | 12 ++++++------ web/includes/config.php.in | 8 +------- zm.conf.in | 3 --- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index e5b8e3d0d..75ac52fa0 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -165,7 +165,7 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) use LWP::UserAgent; my $ua = LWP::UserAgent->new; - $ua->agent( "ZoneMinder Update Agent/".$Config{ZM_VERSION} ); + $ua->agent( "ZoneMinder Update Agent/".ZM_VERSION ); if ( $Config{ZM_UPDATE_CHECK_PROXY} ) { $ua->proxy( "http", $Config{ZM_UPDATE_CHECK_PROXY} ); } @@ -374,13 +374,13 @@ if ( $version ) my ( $detaint_version ) = $version =~ /^([\w.]+)$/; $version = $detaint_version; - if ( $Config{ZM_VERSION} eq $version ) + if ( ZM_VERSION eq $version ) { print( "\nDatabase already at version $version, update aborted.\n\n" ); exit( 0 ); } - print( "\nInitiating database upgrade to version ".$Config{ZM_VERSION}." from version $version\n" ); + print( "\nInitiating database upgrade to version ".ZM_VERSION." from version $version\n" ); if ( $interactive ) { if ( $Config{ZM_DYN_DB_VERSION} && $Config{ZM_DYN_DB_VERSION} ne $version ) @@ -489,7 +489,7 @@ if ( $version ) } - print( "\nUpgrading database to version ".$Config{ZM_VERSION}."\n" ); + print( "\nUpgrading database to version ".ZM_VERSION."\n" ); # Update config first of all loadConfigFromDB(); @@ -1050,7 +1050,7 @@ if ( $version ) if ( $cascade ) { - my $installed_version = $Config{ZM_VERSION}; + my $installed_version = ZM_VERSION; my $sql = "update Config set Value = ? where Name = ?"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( "$installed_version", "ZM_DYN_DB_VERSION" ) or die( "Can't execute: ".$sth->errstr() ); @@ -1061,7 +1061,7 @@ if ( $version ) zmDbDisconnect(); die( "Can't find upgrade from version '$version'" ); } - print( "\nDatabase upgrade to version ".$Config{ZM_VERSION}." successful.\n\n" ); + print( "\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n" ); } zmDbDisconnect(); exit( 0 ); diff --git a/web/includes/config.php.in b/web/includes/config.php.in index 54257fc16..b2adc8969 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -22,6 +22,7 @@ // This section contains options substituted by the zmconfig.pl utility, do not edit these directly // define( "ZM_CONFIG", "@ZM_CONFIG@" ); // Path to config file +define( "ZM_VERSION", "@VERSION@" ); // Version $configFile = ZM_CONFIG; $localConfigFile = basename($configFile); @@ -47,13 +48,6 @@ while ( !feof($cfg) ) } fclose( $cfg ); -// Define, and override any given in config file -// to override, must be done AFTER asignment, cripes -// @VERSION@ hasn't been defined in tests, perhaps configure.ac needs fix? -if (!defined("ZM_VERSION")) { // avoid double definition warning - define( "ZM_VERSION", "@VERSION@" ); // Version -} - // // This section is options normally derived from other options or configuration // diff --git a/zm.conf.in b/zm.conf.in index f3bdb0471..9cc3d42de 100644 --- a/zm.conf.in +++ b/zm.conf.in @@ -48,6 +48,3 @@ ZM_DB_PASS=@ZM_DB_PASS@ # Host of this machine ZM_SERVER_HOST= - -# Version of zoneminder - must be set -ZM_VERSION=1.28.1 From 334584d37fe32a85c7a9c9a7bafae17bce2bed6f Mon Sep 17 00:00:00 2001 From: Rick Sayre Date: Mon, 18 May 2015 22:01:59 -0700 Subject: [PATCH 138/154] exactly rollback web/includes/config.php.in --- web/includes/config.php.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/includes/config.php.in b/web/includes/config.php.in index b2adc8969..fbcb0e7b3 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -22,6 +22,7 @@ // This section contains options substituted by the zmconfig.pl utility, do not edit these directly // define( "ZM_CONFIG", "@ZM_CONFIG@" ); // Path to config file +// Define, and override any given in config file define( "ZM_VERSION", "@VERSION@" ); // Version $configFile = ZM_CONFIG; @@ -47,7 +48,7 @@ while ( !feof($cfg) ) define( $matches[1], $matches[2] ); } fclose( $cfg ); - + // // This section is options normally derived from other options or configuration // From 47012c58dec90015c1295d8f62919e24e5179d56 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 20 May 2015 17:20:44 -0500 Subject: [PATCH 139/154] Check the Host OS, similar to configure.ac --- CMakeLists.txt | 23 ++++++++++++++++++++++- zoneminder-config.cmake | 2 ++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a9b409f3..92a89b5fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,8 +161,29 @@ include_directories("${CMAKE_BINARY_DIR}") # This is required to enable searching in lib64 (if exists), do not change set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON) +# Host OS Check +set(HOST_OS "") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(HOST_OS "linux") +endif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") +if(${CMAKE_SYSTEM_NAME} MATCHES ".*(SunOS|Solaris).*") + set(HOST_OS "solaris") + set(SOLARIS 1) +endif(${CMAKE_SYSTEM_NAME} MATCHES ".*(SunOS|Solaris).*") +if(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD.*") + set(HOST_OS "BSD") + set(BSD 1) +endif(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD.*") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(HOST_OS "darwin") +endif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") +if(NOT HOST_OS) + message(FATAL_ERROR + "ZoneMinder was unable to deterimine the host OS. Please report this. Value of CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") +endif(NOT HOST_OS) + # System checks -check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H) +check_include_file("libv4l1-videodev.h" _H) if(NOT HAVE_LIBV4L1_VIDEODEV_H) check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H) endif(NOT HAVE_LIBV4L1_VIDEODEV_H) diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index 3854dfe31..6dd6fc48a 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -4,6 +4,8 @@ /* This file is used by cmake to create config.h for ZM */ /* General system checks */ +#cmakedefine BSD 1 +#cmakedefine SOLARIS 1 #cmakedefine HAVE_LINUX_VIDEODEV_H 1 #cmakedefine HAVE_LIBV4L1_VIDEODEV_H 1 #cmakedefine HAVE_LINUX_VIDEODEV2_H 1 From e8ecc505ed1842403e6f8ed05ff9fcb44f8c93df Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 20 May 2015 17:23:41 -0500 Subject: [PATCH 140/154] fix error --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92a89b5fa..e74f3b13a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,7 @@ if(NOT HOST_OS) endif(NOT HOST_OS) # System checks -check_include_file("libv4l1-videodev.h" _H) +check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H) if(NOT HAVE_LIBV4L1_VIDEODEV_H) check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H) endif(NOT HAVE_LIBV4L1_VIDEODEV_H) From 4013d2134f19ff7ccce65c7f1872ea76db9aa5ac Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 20 May 2015 17:26:43 -0500 Subject: [PATCH 141/154] Delete README-OmniOS.txt This information is going to change and will be re-added later. --- README-OmniOS.txt | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 README-OmniOS.txt diff --git a/README-OmniOS.txt b/README-OmniOS.txt deleted file mode 100644 index de2f2f6bd..000000000 --- a/README-OmniOS.txt +++ /dev/null @@ -1,17 +0,0 @@ -The following has worked [with newest patches] with buildtools and gcc48 from pkg, -and ffmpeg2, LAMP and libjpeg-turbo from pkgin for OmniOS r151012 and r151014 - -./bootstrap.sh -# omnios default is 32bit, -m64 is unneeded if perl/libs versions match -export CXXFLAGS=-m64 -export CFLAGS=-m64 -export PERL=/usr/perl5/5.16.1/bin/amd64/perl -export CPPFLAGS="-I/opt/local/include/ffmpeg2 -I/opt/local/include/mysql --I/opt/local/include" -# need the -R for runtime load library -export LDFLAGS="-L/opt/local/lib/ffmpeg2 -L/opt/local/lib -R/opt/local/lib --R/opt/local/lib/ffmpeg2" -export ZM_SSL_LIB=openssl -# need -lsocket -lnsl for recv/send to work, and latest version needs -lsendfile -./configure --with-webdir=/opt/local/share/httpd/htdocs/zm --with-extralibs="-lsocket -lnsl -lsendfile" --with-cgidir=/opt/local/libexec/cgi-bin --with-webuser=www --with-webgroup=www --with-webhost=MACHINENAME.local - From bf4038a7249ba7310fea1776fa2e16f605560dbd Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 21 May 2015 12:23:31 -0500 Subject: [PATCH 142/154] followup changes based on comments in #833 --- web/skins/classic/includes/control_functions.php | 2 -- web/skins/classic/includes/export_functions.php | 2 -- web/skins/classic/views/console.php | 2 +- web/skins/classic/views/function.php | 2 +- web/skins/classic/views/options.php | 2 +- web/skins/classic/views/timeline.php | 2 -- web/skins/mobile/includes/control_functions.php | 2 -- 7 files changed, 3 insertions(+), 11 deletions(-) diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index 02da3db17..b09a53138 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -137,8 +137,6 @@ function getControlCommands( $monitor ) function controlFocus( $monitor, $cmds ) { - global $SLANG; - ob_start(); ?>
    diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 8d40d9ce0..e604536e8 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -103,8 +103,6 @@ html ul.tabs li.active, html ul.tabs li.active a:hover { function exportEventDetail( $event, $exportFrames, $exportImages ) { - global $SLANG; - ob_start(); exportHeader( translate('Event')." ".$event['Id'] ); diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 67080b185..bf33802d9 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -302,7 +302,7 @@ foreach( $displayMonitors as $monitor ) $scale = max( reScale( SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); ?>
    - + diff --git a/web/skins/classic/views/function.php b/web/skins/classic/views/function.php index 5960b3290..a52020185 100644 --- a/web/skins/classic/views/function.php +++ b/web/skins/classic/views/function.php @@ -46,7 +46,7 @@ xhtmlHeaders(__FILE__, translate('Function')." - ".validHtmlStr($monitor['Name'] foreach ( getEnumValues( 'Monitors', 'Function' ) as $optFunction ) { ?> - + diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 02f5cdffd..45e6c9ebb 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -27,7 +27,7 @@ if ( !canView( 'System' ) ) $canEdit = canEdit( 'System' ); $tabs = array(); -$tabs['skins'] = translate('Display'); // change me to be supported by SLANG... +$tabs['skins'] = translate('Display'); $tabs['system'] = translate('System'); $tabs['config'] = translate('Config'); $tabs['paths'] = translate('Paths'); diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index 853a76def..fae579546 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -671,8 +671,6 @@ else function drawXGrid( $chart, $scale, $labelClass, $tickClass, $gridClass, $zoomClass=false ) { - global $SLANG; - ob_start(); $labelCount = 0; $lastTick = 0; diff --git a/web/skins/mobile/includes/control_functions.php b/web/skins/mobile/includes/control_functions.php index 918c3ba23..3a12cf467 100644 --- a/web/skins/mobile/includes/control_functions.php +++ b/web/skins/mobile/includes/control_functions.php @@ -135,8 +135,6 @@ function getControlCommands( $monitor ) function controlPresets( $monitor, $cmds ) { - global $SLANG; - define( "MAX_PRESETS", "10" ); $sql = "select * from ControlPresets where MonitorId = '".$monitor['Id']."'"; From f45af0894726e1e3a3fadc66c41fa3d6838a96a1 Mon Sep 17 00:00:00 2001 From: Sebastian Kaminski Date: Sun, 24 May 2015 22:01:51 +0200 Subject: [PATCH 143/154] copy ubutnu1204 without init.d --- distros/ubuntu1504/README.Debian | 51 ++++++++++++++++++ distros/ubuntu1504/apache.conf | 9 ++++ distros/ubuntu1504/changelog | 86 +++++++++++++++++++++++++++++++ distros/ubuntu1504/compat | 1 + distros/ubuntu1504/control | 40 ++++++++++++++ distros/ubuntu1504/copyright | 22 ++++++++ distros/ubuntu1504/dirs | 6 +++ distros/ubuntu1504/docs | 1 + distros/ubuntu1504/install | 12 +++++ distros/ubuntu1504/links | 4 ++ distros/ubuntu1504/patches/series | 0 distros/ubuntu1504/postinst | 53 +++++++++++++++++++ distros/ubuntu1504/postrm | 9 ++++ distros/ubuntu1504/preinst | 32 ++++++++++++ distros/ubuntu1504/rules | 67 ++++++++++++++++++++++++ distros/ubuntu1504/watch | 3 ++ 16 files changed, 396 insertions(+) create mode 100644 distros/ubuntu1504/README.Debian create mode 100644 distros/ubuntu1504/apache.conf create mode 100644 distros/ubuntu1504/changelog create mode 100644 distros/ubuntu1504/compat create mode 100644 distros/ubuntu1504/control create mode 100644 distros/ubuntu1504/copyright create mode 100644 distros/ubuntu1504/dirs create mode 100644 distros/ubuntu1504/docs create mode 100644 distros/ubuntu1504/install create mode 100644 distros/ubuntu1504/links create mode 100644 distros/ubuntu1504/patches/series create mode 100644 distros/ubuntu1504/postinst create mode 100644 distros/ubuntu1504/postrm create mode 100755 distros/ubuntu1504/preinst create mode 100755 distros/ubuntu1504/rules create mode 100644 distros/ubuntu1504/watch diff --git a/distros/ubuntu1504/README.Debian b/distros/ubuntu1504/README.Debian new file mode 100644 index 000000000..b8ea413e3 --- /dev/null +++ b/distros/ubuntu1504/README.Debian @@ -0,0 +1,51 @@ +zoneminder for Debian +--------------------- + +There is one manual step to get the web interface working. +You need to link /etc/zm/apache.conf to /etc/apache2/conf.d/zoneminder.conf, +then reload the apache config (i.e. /etc/init.d/apache2 reload) + +Changing the location for images and events +------------------------------------------- + +Zoneminder, in its upstream form, stores data in /usr/share/zoneminder/. This +package modifies that by changing /usr/share/zoneminder/images and +/usr/share/zoneminder/events to symlinks to directories under +/var/cache/zoneminder. + +There are numerous places these could be put and ways to do it. But, at the +moment, if you change this, an upgrade will fail with a warning about these +locations having changed (the reason for this was that previously, an upgrade +would silently revert the changes and cause event loss - refer +bug #608793). + +If you do want to change the location, here are a couple of suggestions. +(thanks to vagrant@freegeek.org): + +These lines in fstab could allow you to bind-mount an alternate location + + /dev/sdX1 /otherdrive ext3 defaults 0 2 + /otherdrive/zoneminder/images /var/cache/zoneminder/images bind defaults 0 2 + /otherdrive/zoneminder/events /var/cache/zoneminder/events bind defaults 0 2 + + or if you have a separate partition for each: + + /dev/sdX1 /var/cache/zoneminder/images ext3 defaults 0 2 + /dev/sdX2 /var/cache/zoneminder/events ext3 defaults 0 2 + + + + -- Peter Howard , Sun, 16 Jan 2010 01:35:51 +1100 + +Access to /dev/video* +--------------------- + +For cameras which require access to /dev/video*, zoneminder may need the +www-data user added to the video group in order to see those cameras: + + adduser www-data video + +Note that all web applications running on the zoneminder server will then have +access to all video devices on the system. + + -- Vagrant Cascadian Sun, 27 Mar 2011 13:06:56 -0700 diff --git a/distros/ubuntu1504/apache.conf b/distros/ubuntu1504/apache.conf new file mode 100644 index 000000000..92a2b6414 --- /dev/null +++ b/distros/ubuntu1504/apache.conf @@ -0,0 +1,9 @@ +Alias /zm /usr/share/zoneminder + + + php_flag register_globals off + Options Indexes FollowSymLinks + + DirectoryIndex index.php + + diff --git a/distros/ubuntu1504/changelog b/distros/ubuntu1504/changelog new file mode 100644 index 000000000..2dfc8b63c --- /dev/null +++ b/distros/ubuntu1504/changelog @@ -0,0 +1,86 @@ +zoneminder (1.28.1+1-trusty-SNAPSHOT2015030201) trusty; urgency=medium + + * maybe fix for RTSP Basic Auth + * Also remove dependency on netpbm + + -- Isaac Connor Mon, 02 Mar 2015 11:25:59 -0500 + +zoneminder (1.28.1+1-utopic-SNAPSHOT2015022301) utopic; urgency=medium + + * Big merge of onvif support and some fixes. + + -- Isaac Connor Mon, 23 Feb 2015 19:45:45 -0500 + +zoneminder (1.28.0+1-trusty-SNAPSHOT2015021201) trusty; urgency=medium + + * add mysql-client-5.6 as a dependency instaed of mysql-client. + + -- Isaac Connor Fri, 13 Feb 2015 09:35:13 -0500 + +zoneminder (1.28.0+1-trusty-SNAPSHOT2015011101) trusty; urgency=medium + + * small changes + + -- Isaac Connor Fri, 12 Dec 2014 16:38:36 -0500 + +zoneminder (1.28.0+1-utopic-SNAPSHOT2014112001) utopic; urgency=medium + + * Various fixes and developments since 1.28.0. Includes Digest-Auth for HTTP and better for RTSP + + -- Isaac Connor Thu, 20 Nov 2014 10:57:57 -0500 + +zoneminder (1.28.0-trusty) trusty; urgency=medium + + * Release + + -- Isaac Connor Fri, 17 Oct 2014 09:25:55 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014101401) trusty; urgency=medium + + * Several PR merges in big push for 1.28.0 + + -- Isaac Connor Tue, 14 Oct 2014 09:28:29 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014092601) trusty; urgency=medium + + * style updates and db fixes for database logging filters + + -- Isaac Connor Fri, 26 Sep 2014 14:44:45 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014090801) trusty; urgency=medium + + * several segfault fixes for local cameras + + -- Isaac Connor Mon, 08 Sep 2014 16:56:57 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014090701) trusty; urgency=medium + + * Fix segfaults for local cameras, also now includes the systemd support patch + + -- Isaac Connor Sun, 07 Sep 2014 17:19:01 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014082102) trusty; urgency=medium + + * Fix UI inputs for v4l multibuffer and captures per frame + + -- Isaac Connor Thu, 21 Aug 2014 12:03:31 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014082101) trusty; urgency=medium + + * fall back to Config table values for V4l MultiBUffer and Captures Per Frame + * add mention of monitor page settings for thse in the config table + + -- Isaac Connor Thu, 21 Aug 2014 10:04:46 -0400 + +zoneminder (1.27.99+1-precise-SNAPSHOT2014080601) precise; urgency=medium + + * improve error messages + * Make zmupdate re-run the most recent patch so that people running the daily builds get their db updates + + -- Isaac Connor Wed, 06 Aug 2014 20:20:20 -0400 + +zoneminder (1.27.0+1-trusty-v4ltomonitor-1) trusty; urgency=high + + * Snapshot release - + + -- Isaac Connor Wed, 09 Jul 2014 21:35:29 -0400 diff --git a/distros/ubuntu1504/compat b/distros/ubuntu1504/compat new file mode 100644 index 000000000..ec635144f --- /dev/null +++ b/distros/ubuntu1504/compat @@ -0,0 +1 @@ +9 diff --git a/distros/ubuntu1504/control b/distros/ubuntu1504/control new file mode 100644 index 000000000..b1be82b34 --- /dev/null +++ b/distros/ubuntu1504/control @@ -0,0 +1,40 @@ +Source: zoneminder +Section: net +Priority: optional +Maintainer: Isaac Connor +Build-Depends: debhelper (>= 9), autoconf, automake, quilt, libphp-serialization-perl, libgnutls-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev|libjpeg9-dev|libjpeg62-turbo-dev, libpcre3-dev, libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, ffmpeg | libav-tools, libavdevice-dev, libdevice-serialport-perl, libpcre3, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev, libpolkit-gobject-1-dev +Standards-Version: 3.9.4 + +Package: zoneminder +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client|mysql-client-5.6, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg | libav-tools, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, libavdevice53 | libavdevice55, libjpeg8|libjpeg9|libjpeg62-turbo, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl +Recommends: mysql-server|mariadb-server +Description: Video camera security and surveillance solution + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. + +Package: zoneminder-dbg +Section: debug +Priority: extra +Architecture: any +Depends: zoneminder (= ${binary:Version}), ${misc:Depends} +Description: Debugging symbols for zoneminder. + ZoneMinder is a video camera security and surveillance solution. + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. diff --git a/distros/ubuntu1504/copyright b/distros/ubuntu1504/copyright new file mode 100644 index 000000000..a177502a0 --- /dev/null +++ b/distros/ubuntu1504/copyright @@ -0,0 +1,22 @@ +Copyright: + +Copyright 2002 Philip Coombes + +License: + +This package 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 package 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 package; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian GNU/Linux systems, the text of the GPL can be found in +/usr/share/common-licenses/GPL. diff --git a/distros/ubuntu1504/dirs b/distros/ubuntu1504/dirs new file mode 100644 index 000000000..4178482c1 --- /dev/null +++ b/distros/ubuntu1504/dirs @@ -0,0 +1,6 @@ +var/log/zm +var/lib/zm +var/cache/zoneminder/events +var/cache/zoneminder/images +var/cache/zoneminder/temp +usr/share/zoneminder/db diff --git a/distros/ubuntu1504/docs b/distros/ubuntu1504/docs new file mode 100644 index 000000000..b43bf86b5 --- /dev/null +++ b/distros/ubuntu1504/docs @@ -0,0 +1 @@ +README.md diff --git a/distros/ubuntu1504/install b/distros/ubuntu1504/install new file mode 100644 index 000000000..4b0009cea --- /dev/null +++ b/distros/ubuntu1504/install @@ -0,0 +1,12 @@ +usr/bin +usr/lib/cgi-bin +usr/share/man +usr/share/perl5/ZoneMinder +usr/share/perl5/ZoneMinder.pm +usr/share/polkit-1/actions +usr/share/polkit-1/rules.d +usr/share/zoneminder +etc/zm +db/zm_create.sql usr/share/zoneminder/db +db/zm_update-*.sql usr/share/zoneminder/db +debian/apache.conf etc/zm diff --git a/distros/ubuntu1504/links b/distros/ubuntu1504/links new file mode 100644 index 000000000..9715ee428 --- /dev/null +++ b/distros/ubuntu1504/links @@ -0,0 +1,4 @@ +var/cache/zoneminder/events usr/share/zoneminder/events +var/cache/zoneminder/images usr/share/zoneminder/images +var/cache/zoneminder/temp usr/share/zoneminder/temp +usr/lib/cgi-bin usr/share/zoneminder/cgi-bin diff --git a/distros/ubuntu1504/patches/series b/distros/ubuntu1504/patches/series new file mode 100644 index 000000000..e69de29bb diff --git a/distros/ubuntu1504/postinst b/distros/ubuntu1504/postinst new file mode 100644 index 000000000..d06f9c641 --- /dev/null +++ b/distros/ubuntu1504/postinst @@ -0,0 +1,53 @@ +#! /bin/sh + +set -e + +if [ "$1" = "configure" ]; then + if [ -e "/etc/init.d/mysql" ]; then + # + # Get mysql started if it isn't + # + if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then + invoke-rc.d mysql start + fi + if $(/etc/init.d/mysql status >/dev/null 2>&1); then + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload + # test if database if already present... + if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then + cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf + echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + fi + + invoke-rc.d zoneminder stop || true + zmupdate.pl --nointeractive + + else + echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.' + fi + else + echo 'mysql not found, assuming remote server.' + fi + chown www-data:www-data /var/log/zm + chown www-data:www-data /var/lib/zm/ + if [ -z "$2" ]; then + chown www-data:www-data -R /var/cache/zoneminder + fi +fi +# Ensure zoneminder is stopped... +if [ -x "/etc/init.d/zoneminder" ]; then + if invoke-rc.d zoneminder status ; then + invoke-rc.d zoneminder stop || exit $? + fi +fi + +if [ "$1" = "configure" ]; then + if [ -z "$2" ]; then + chown www-data:www-data /var/log/zm + chown www-data:www-data /var/lib/zm/ + chown www-data:www-data -R /var/cache/zoneminder + else + chown www-data:www-data /var/log/zm + zmupdate.pl + fi +fi +#DEBHELPER# diff --git a/distros/ubuntu1504/postrm b/distros/ubuntu1504/postrm new file mode 100644 index 000000000..28a00a7a0 --- /dev/null +++ b/distros/ubuntu1504/postrm @@ -0,0 +1,9 @@ +#! /bin/sh +# set -e # to be reinstated later + +if [ "$1" = "purge" ]; then + echo 'delete from user where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + echo 'delete from db where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm +fi +#DEBHELPER# diff --git a/distros/ubuntu1504/preinst b/distros/ubuntu1504/preinst new file mode 100755 index 000000000..6cd01ba55 --- /dev/null +++ b/distros/ubuntu1504/preinst @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +abort=false +if [ -L /usr/share/zoneminder/events ]; then + l=$(readlink /usr/share/zoneminder/events) + if [ "$l" != "/var/cache/zoneminder/events" ]; then + abort=true + fi +fi +if [ -L /usr/share/zoneminder/images ]; then + l=$(readlink /usr/share/zoneminder/images ) + if [ "$l" != "/var/cache/zoneminder/images" ]; then + abort=true + fi +fi + +if [ "$abort" = "true" ]; then + cat >&2 << EOF +Aborting installation of zoneminder due to non-default symlinks in +/usr/share/zoneminder for the images and/or events directory, which could +result in loss of data. Please move your data in each of these directories to +/var/cache/zoneminder before installing zoneminder from the package. +EOF + exit 1 + +fi + +#DEBHELPER# + +exit 0 diff --git a/distros/ubuntu1504/rules b/distros/ubuntu1504/rules new file mode 100755 index 000000000..e25e5514d --- /dev/null +++ b/distros/ubuntu1504/rules @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +CFLAGS = -Wall -g +CPPFLAGS = -D__STDC_CONSTANT_MACROS +CXXFLAGS = -DHAVE_LIBCRYPTO + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +%: + dh $@ --with quilt,autoreconf + +override_dh_auto_configure: + CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --sysconfdir=/etc/zm --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-mysql=/usr --with-mariadb=/usr --with-webdir=/usr/share/zoneminder --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-crashtrace=no --enable-mmap=yes + +override_dh_clean: + # Add here commands to clean up after the build process. + [ ! -f Makefile ] || $(MAKE) distclean + dh_clean + +override_dh_install: + dh_install --fail-missing + # + # NOTE: This is a short-term kludge; hopefully changes in the next + # upstream version will render this unnecessary. + rm -rf debian/zoneminder/usr/share/zoneminder/events + rm -rf debian/zoneminder/usr/share/zoneminder/images + rm -rf debian/zoneminder/usr/share/zoneminder/temp + dh_link var/cache/zoneminder/events usr/share/zoneminder/events + dh_link var/cache/zoneminder/images usr/share/zoneminder/images + dh_link var/cache/zoneminder/temp usr/share/zoneminder/temp + + # + # This is a slightly lesser kludge; moving the cgi stuff to + # /usr/share/zoneminder/cgi-bin breaks one set of behavior, + # having it just in /usr/lib/cgi-bin breaks another bit of + # behavior. + # + dh_link usr/lib/cgi-bin usr/share/zoneminder/cgi-bin + +override_dh_fixperms: + dh_fixperms + chown root:root debian/zoneminder/etc/zm/zm.conf + +override_dh_auto_test: + # do not run tests... + +.PHONY: override_dh_strip +override_dh_strip: + dh_strip --dbg-package=zoneminder-dbg diff --git a/distros/ubuntu1504/watch b/distros/ubuntu1504/watch new file mode 100644 index 000000000..5a8a9c4d7 --- /dev/null +++ b/distros/ubuntu1504/watch @@ -0,0 +1,3 @@ +version=3 +http://www.zoneminder.com/downloads.html \ + .*/ZoneMinder-(.*).tar.gz From a671b452a8dcbacd23458b046845533e3027f632 Mon Sep 17 00:00:00 2001 From: Sebastian Kaminski Date: Sun, 24 May 2015 22:05:09 +0200 Subject: [PATCH 144/154] change dependencies for ubuntu 15.04 --- distros/ubuntu1504/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/ubuntu1504/control b/distros/ubuntu1504/control index b1be82b34..5b63046c3 100644 --- a/distros/ubuntu1504/control +++ b/distros/ubuntu1504/control @@ -2,12 +2,12 @@ Source: zoneminder Section: net Priority: optional Maintainer: Isaac Connor -Build-Depends: debhelper (>= 9), autoconf, automake, quilt, libphp-serialization-perl, libgnutls-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev|libjpeg9-dev|libjpeg62-turbo-dev, libpcre3-dev, libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, ffmpeg | libav-tools, libavdevice-dev, libdevice-serialport-perl, libpcre3, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev, libpolkit-gobject-1-dev +Build-Depends: debhelper (>= 9), dh-systemd (>= 1.5), autoconf, automake, quilt, libphp-serialization-perl, libgnutls-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev|libjpeg9-dev|libjpeg62-turbo-dev, libpcre3-dev, libavcodec-ffmpeg-dev, libavformat-ffmpeg-dev, libswscale-ffmpeg-dev, libavutil-ffmpeg-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, ffmpeg, libavdevice-ffmpeg-dev, libdevice-serialport-perl, libpcre3, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev, libpolkit-gobject-1-dev Standards-Version: 3.9.4 Package: zoneminder Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client|mysql-client-5.6, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg | libav-tools, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, libavdevice53 | libavdevice55, libjpeg8|libjpeg9|libjpeg62-turbo, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client|mysql-client-5.6, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, libavdevice-ffmpeg56, libjpeg8|libjpeg9|libjpeg62-turbo, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl Recommends: mysql-server|mariadb-server Description: Video camera security and surveillance solution ZoneMinder is intended for use in single or multi-camera video security From 3080ecdb20b8d51d084a9928495c1e782aead28b Mon Sep 17 00:00:00 2001 From: Sebastian Kaminski Date: Sun, 24 May 2015 22:09:43 +0200 Subject: [PATCH 145/154] add service and temp files --- distros/ubuntu1504/zoneminder.service | 16 ++++++++++++++++ distros/ubuntu1504/zoneminder.tmpfile | 2 ++ 2 files changed, 18 insertions(+) create mode 100644 distros/ubuntu1504/zoneminder.service create mode 100644 distros/ubuntu1504/zoneminder.tmpfile diff --git a/distros/ubuntu1504/zoneminder.service b/distros/ubuntu1504/zoneminder.service new file mode 100644 index 000000000..3ce608a49 --- /dev/null +++ b/distros/ubuntu1504/zoneminder.service @@ -0,0 +1,16 @@ +# ZoneMinder systemd unit file + # This file is intended to work with all Linux distributions + [Unit] + Description=ZoneMinder CCTV recording and security system + After=network.target mysql.service apache2.service + Requires=mysql.service apache2.service + [Service] + User=www-data + Type=forking + ExecStart=/usr/bin/zmpkg.pl start + ExecReload=/usr/bin/zmpkg.pl restart + ExecStop=/usr/bin/zmpkg.pl stop + PIDFile="/run/zm/zm.pid" + [Install] + WantedBy=multi-user.target + diff --git a/distros/ubuntu1504/zoneminder.tmpfile b/distros/ubuntu1504/zoneminder.tmpfile new file mode 100644 index 000000000..036883750 --- /dev/null +++ b/distros/ubuntu1504/zoneminder.tmpfile @@ -0,0 +1,2 @@ +d /var/run/zm 0755 www-data www-data + From 3266b0b57ea365f8f9302eb522d6ffd1b88a131a Mon Sep 17 00:00:00 2001 From: Sebastian Kaminski Date: Sun, 24 May 2015 22:13:09 +0200 Subject: [PATCH 146/154] change for systemd --- distros/ubuntu1504/postinst | 16 ++++++++-------- distros/ubuntu1504/rules | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/distros/ubuntu1504/postinst b/distros/ubuntu1504/postinst index d06f9c641..e009a9799 100644 --- a/distros/ubuntu1504/postinst +++ b/distros/ubuntu1504/postinst @@ -3,14 +3,14 @@ set -e if [ "$1" = "configure" ]; then - if [ -e "/etc/init.d/mysql" ]; then + if [ -e "/lib/systemd/system/mysql.service" ]; then # # Get mysql started if it isn't # - if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then - invoke-rc.d mysql start + if ! $(systemctl is-active mysql >/dev/null 2>&1); then + systemctl start mysql fi - if $(/etc/init.d/mysql status >/dev/null 2>&1); then + if $(systemctl is-active mysql >/dev/null 2>&1); then mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload # test if database if already present... if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then @@ -18,7 +18,7 @@ if [ "$1" = "configure" ]; then echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi - invoke-rc.d zoneminder stop || true + systemctl stop zoneminder || true #not sure about "|| true" zmupdate.pl --nointeractive else @@ -34,9 +34,9 @@ if [ "$1" = "configure" ]; then fi fi # Ensure zoneminder is stopped... -if [ -x "/etc/init.d/zoneminder" ]; then - if invoke-rc.d zoneminder status ; then - invoke-rc.d zoneminder stop || exit $? +if [ -e "/lib/systemd/system/zoneminder.service" ]; then #changed from -x to -e, could be wrong + if systemctl is-active zoneminder >/dev/null 2>&1 ; then + systemctl stop zoneminder || exit $? fi fi diff --git a/distros/ubuntu1504/rules b/distros/ubuntu1504/rules index e25e5514d..280d5faef 100755 --- a/distros/ubuntu1504/rules +++ b/distros/ubuntu1504/rules @@ -25,7 +25,7 @@ else endif %: - dh $@ --with quilt,autoreconf + dh $@ --with quilt,autoreconf,systemd override_dh_auto_configure: CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --sysconfdir=/etc/zm --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-mysql=/usr --with-mariadb=/usr --with-webdir=/usr/share/zoneminder --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-crashtrace=no --enable-mmap=yes From ba980ae4aee284e9743dadeb938e2104cd0f1d1f Mon Sep 17 00:00:00 2001 From: Sebastian Kaminski Date: Wed, 27 May 2015 15:38:47 +0200 Subject: [PATCH 147/154] update german translation --- web/lang/de_de.php | 449 +++++++++++++++++++++++---------------------- 1 file changed, 225 insertions(+), 224 deletions(-) diff --git a/web/lang/de_de.php b/web/lang/de_de.php index 19cac833a..9ad642173 100644 --- a/web/lang/de_de.php +++ b/web/lang/de_de.php @@ -19,6 +19,7 @@ // // ZoneMinder german Translation by Robert Schumann (rs at core82 dot de) +// ZoneMinder german Translation by Sebastian Kaminski (github @seeebek) // Notes for Translators // 0. Get some credit, put your name in the line above (optional) @@ -50,7 +51,7 @@ // do this by default, uncomment this if required. // // Example -// header( "Content-Type: text/html; charset=iso-8859-1" ); +header( "Content-Type: text/html; charset=utf-8" ); // You may need to change your locale here if your default one is incorrect for the // language described in this file, or if you have multiple languages supported. @@ -76,7 +77,7 @@ $SLANG = array( '8BitGrey' => '8-Bit-Grau', 'Action' => 'Aktion', 'Actual' => 'Original', - 'AddNewControl' => 'Neues Kontrollelement hinzufügen', + 'AddNewControl' => 'Neues Kontrollelement hinzufügen', 'AddNewMonitor' => 'Neuer Monitor', 'AddNewUser' => 'Neuer Benutzer', 'AddNewZone' => 'Neue Zone', @@ -87,11 +88,11 @@ $SLANG = array( 'AlarmLimits' => 'Alarm-Limits', 'AlarmMaximumFPS' => 'Alarm-Maximum-FPS', 'AlarmPx' => 'Alarm-Pixel', - 'AlarmRGBUnset' => 'Sie müssen eine RGB-Alarmfarbe setzen', + 'AlarmRGBUnset' => 'Sie müssen eine RGB-Alarmfarbe setzen', 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alarm', 'All' => 'Alle', - 'Apply' => 'OK', + 'Apply' => 'Anwenden', 'ApplyingStateChange' => 'Aktiviere neuen Status', 'ArchArchived' => 'Nur Archivierte', 'ArchUnarchived' => 'Nur Nichtarchivierte', @@ -120,163 +121,163 @@ $SLANG = array( 'AttrTotalScore' => 'Totale Punktzahl', 'AttrWeekday' => 'Wochentag', 'Auto' => 'Auto', - 'AutoStopTimeout' => 'Auto-Stopp-Zeitüberschreitung', - 'Available' => 'Available', // Added - 2009-03-31 + 'AutoStopTimeout' => 'Auto-Stopp-Zeitüberschreitung', + 'Available' => 'Vorhanden', // Added - 2009-03-31 'AvgBrScore' => 'Mittlere
    Punktzahl', 'Background' => 'Hintergrund', 'BackgroundFilter' => 'Filter im Hintergrund laufen lassen', - 'BadAlarmFrameCount' => 'Die Bildanzahl muss ganzzahlig 1 oder größer sein', + 'BadAlarmFrameCount' => 'Die Bildanzahl muss ganzzahlig 1 oder größer sein', 'BadAlarmMaxFPS' => 'Alarm-Maximum-FPS muss eine positive Ganzzahl oder eine Gleitkommazahl sein', - 'BadChannel' => 'Der Kanal muss ganzzahlig 0 oder größer sein', - 'BadColours' => 'Target colour must be set to a valid value', // Added - 2011-06-15 - 'BadDevice' => 'Das Gerät muss eine gültige Systemresource sein', - 'BadFPSReportInterval' => 'Der FPS-Intervall-Puffer-Zähler muss ganzzahlig 0 oder größer sein', - 'BadFormat' => 'Das Format muss ganzzahlig 0 oder größer sein', - 'BadFrameSkip' => 'Der Auslasszähler für Frames muss ganzzahlig 0 oder größer sein', - 'BadHeight' => 'Die Höhe muss auf einen gültigen Wert eingestellt sein', - 'BadHost' => 'Der Host muss auf eine gültige IP-Adresse oder einen Hostnamen (ohne http://) eingestellt sein', - 'BadImageBufferCount' => 'Die Größe des Bildpuffers muss ganzzahlig 10 oder größer sein', - 'BadLabelX' => 'Die x-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', - 'BadLabelY' => 'Die y-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', + 'BadChannel' => 'Der Kanal muss ganzzahlig 0 oder größer sein', + 'BadColours' => 'Die Zielfarbe muss eine gültige Farbe sein.', // Added - 2011-06-15 + 'BadDevice' => 'Das Gerät muss eine gültige Systemresource sein', + 'BadFPSReportInterval' => 'Der FPS-Intervall-Puffer-Zähler muss ganzzahlig 0 oder größer sein', + 'BadFormat' => 'Das Format muss ganzzahlig 0 oder größer sein', + 'BadFrameSkip' => 'Der Auslasszähler für Frames muss ganzzahlig 0 oder größer sein', + 'BadHeight' => 'Die Höhe muss auf einen gültigen Wert eingestellt sein', + 'BadHost' => 'Der Host muss auf eine gültige IP-Adresse oder einen Hostnamen (ohne http://) eingestellt sein', + 'BadImageBufferCount' => 'Die Größe des Bildpuffers muss ganzzahlig 10 oder größer sein', + 'BadLabelX' => 'Die x-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', + 'BadLabelY' => 'Die y-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', 'BadMaxFPS' => 'Maximum-FPS muss eine positive Ganzzahl oder eine Gleitkommazahl sein', 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', - 'BadNameChars' => 'Namen dürfen nur aus Buchstaben, Zahlen und Trenn- oder Unterstrichen bestehen', - 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 - 'BadPath' => 'Der Pfad muss auf einen gültigen Wert eingestellt sein', - 'BadPort' => 'Der Port muss auf eine gültige Zahl eingestellt sein', - 'BadPostEventCount' => 'Der Zähler für die Ereignisfolgebilder muss ganzzahlig 0 oder größer sein', - 'BadPreEventCount' => 'Der Zähler für die Ereignisvorlaufbilder muss mindestens ganzzahlig 0 und kleiner als die Bildpuffergröße sein', - 'BadRefBlendPerc' => 'Der Referenz-Blenden-Prozentwert muss ganzzahlig 0 oder größer sein', - 'BadSectionLength' => 'Die Bereichslänge muss ganzzahlig 0 oder größer sein', - 'BadSignalCheckColour' => 'Die Signalprüffarbe muss auf einen gültigen Farbwert eingestellt sein', + 'BadNameChars' => 'Namen dürfen nur aus Buchstaben, Zahlen und Trenn- oder Unterstrichen bestehen', + 'BadPalette' => 'Die Palette muss auf einen gültigen Wert eingestellt sein', // Added - 2009-03-31 + 'BadPath' => 'Der Pfad muss auf einen gültigen Wert eingestellt sein', + 'BadPort' => 'Der Port muss auf eine gültige Zahl eingestellt sein', + 'BadPostEventCount' => 'Der Zähler für die Ereignisfolgebilder muss ganzzahlig 0 oder größer sein', + 'BadPreEventCount' => 'Der Zähler für die Ereignisvorlaufbilder muss mindestens ganzzahlig 0 und kleiner als die Bildpuffergröße sein', + 'BadRefBlendPerc' => 'Der Referenz-Blenden-Prozentwert muss ganzzahlig 0 oder größer sein', + 'BadSectionLength' => 'Die Bereichslänge muss ganzzahlig 0 oder größer sein', + 'BadSignalCheckColour' => 'Die Signalprüffarbe muss auf einen gültigen Farbwert eingestellt sein', 'BadStreamReplayBuffer'=> 'Der Wiedergabestrompuffer tream replay buffer must be an integer of zero or more', - 'BadWarmupCount' => 'Die Anzahl der Vorwrmbilder muss ganzzahlig 0 oder größer sein', - 'BadWebColour' => 'Die Webfarbe muss auf einen gültigen Farbwert eingestellt sein', - 'BadWidth' => 'Die Breite muss auf einen gültigen Wert eingestellt sein', + 'BadWarmupCount' => 'Die Anzahl der Vorwärmbilder muss ganzzahlig 0 oder größer sein', + 'BadWebColour' => 'Die Webfarbe muss auf einen gültigen Farbwert eingestellt sein', + 'BadWidth' => 'Die Breite muss auf einen gültigen Wert eingestellt sein', 'Bandwidth' => 'Bandbreite', - 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'BandwidthHead' => 'Bandbreite', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing 'BlobPx' => 'Blob-Pixel', - 'BlobSizes' => 'Blobgröße', + 'BlobSizes' => 'Blobgröße', 'Blobs' => 'Blobs', 'Brightness' => 'Helligkeit', 'Buffer' => 'Buffer', // Added - 2015-04-18 - 'Buffers' => 'Puffer', - 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 + 'Buffers' => 'Buffer', + 'CSSDescription' => 'Ändere das standard CSS für diesen Computer.', // Added - 2015-04-18 'CanAutoFocus' => 'Kann Autofokus', - 'CanAutoGain' => 'Kann Auto-Verstärkung', + 'CanAutoGain' => 'Kann Auto-Verstärkung', 'CanAutoIris' => 'Kann Auto-Iris', - 'CanAutoWhite' => 'Kann Auto-Weiß-Abgleich', + 'CanAutoWhite' => 'Kann Auto-Weiß-Abgleich', 'CanAutoZoom' => 'Kann Auto-Zoom', - 'CanFocus' => 'Kann Fokus', + 'CanFocus' => 'Kann Fokus', 'CanFocusAbs' => 'Kann absoluten Fokus', 'CanFocusCon' => 'Kann kontinuierlichen Fokus', 'CanFocusRel' => 'Kann relativen Fokus', - 'CanGain' => 'Kann Verstärkung', - 'CanGainAbs' => 'Kann absolute Verstärkung', - 'CanGainCon' => 'Kann kontinuierliche Verstärkung', - 'CanGainRel' => 'Kann relative Verstäkung', - 'CanIris' => 'Kann Iris', + 'CanGain' => 'Kann Verstärkung', + 'CanGainAbs' => 'Kann absolute Verstärkung', + 'CanGainCon' => 'Kann kontinuierliche Verstärkung', + 'CanGainRel' => 'Kann relative Verstäkung', + 'CanIris' => 'Kann Iris', 'CanIrisAbs' => 'Kann absolute Iris', 'CanIrisCon' => 'Kann kontinuierliche Iris', 'CanIrisRel' => 'Kann relative Iris', - 'CanMove' => 'Kann Bewegung', + 'CanMove' => 'Kann Bewegung', 'CanMoveAbs' => 'Kann absolute Bewegung', 'CanMoveCon' => 'Kann kontinuierliche Bewegung', 'CanMoveDiag' => 'Kann diagonale Bewegung', 'CanMoveMap' => 'Kann Mapped-Bewegung', 'CanMoveRel' => 'Kann relative Bewegung', - 'CanPan' => 'Kann Pan' , - 'CanReset' => 'Kann Reset', + 'CanPan' => 'Kann Pan' , + 'CanReset' => 'Kann Reset', 'CanSetPresets' => 'Kann Voreinstellungen setzen', - 'CanSleep' => 'Kann Sleep', - 'CanTilt' => 'Kann Neigung', - 'CanWake' => 'Kann Wake', - 'CanWhite' => 'Kann Weiß-Abgleich', - 'CanWhiteAbs' => 'Kann absoluten Weiß-Abgleich', - 'CanWhiteBal' => 'Kann Weiß-Abgleich', - 'CanWhiteCon' => 'Kann kontinuierlichen Weiß-Abgleich', - 'CanWhiteRel' => 'Kann relativen Weiß-Abgleich', - 'CanZoom' => 'Kann Zoom', + 'CanSleep' => 'Kann Sleep', + 'CanTilt' => 'Kann Neigung', + 'CanWake' => 'Kann Wake', + 'CanWhite' => 'Kann Weiß-Abgleich', + 'CanWhiteAbs' => 'Kann absoluten Weiß-Abgleich', + 'CanWhiteBal' => 'Kann Weiß-Abgleich', + 'CanWhiteCon' => 'Kann kontinuierlichen Weiß-Abgleich', + 'CanWhiteRel' => 'Kann relativen Weiß-Abgleich', + 'CanZoom' => 'Kann Zoom', 'CanZoomAbs' => 'Kann absoluten Zoom', 'CanZoomCon' => 'Kann kontinuierlichen Zoom', 'CanZoomRel' => 'Kann relativen Zoom', 'Cancel' => 'Abbruch', 'CancelForcedAlarm' => 'Abbruch des unbedingten Alarms', - 'CaptureHeight' => 'Erfasse Höhe', - 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 + 'CaptureHeight' => 'Erfasse Höhe', + 'CaptureMethod' => 'Aufnahmemethode', // Added - 2009-02-08 'CapturePalette' => 'Erfasse Farbpalette', - 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 + 'CaptureResolution' => 'Aufnahmeauflösung', // Added - 2015-04-18 'CaptureWidth' => 'Erfasse Breite', 'Cause' => 'Grund', - 'CheckMethod' => 'Alarm-Prüfmethode', - 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 + 'CheckMethod' => 'Alarm-Prüfmethode', + 'ChooseDetectedCamera' => 'Wähle erkannte Kamera', // 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', + 'ChooseLogFormat' => 'Wähle ein Log-Format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Wähle eine Log-Auswahl', // Added - 2011-06-17 + 'ChoosePreset' => 'Voreinstellung auswählen', + 'Clear' => 'Leeren', // Added - 2011-06-16 + 'Close' => 'Schließen', 'Colour' => 'Farbe', 'Command' => 'Kommando', - 'Component' => 'Component', // Added - 2011-06-16 + 'Component' => 'Komponente', // Added - 2011-06-16 'Config' => 'Konfig.', - 'ConfiguredFor' => 'Konfiguriert für', - 'ConfirmDeleteEvents' => 'Sind Sie sicher, dass Sie die ausgewählten Ereignisse löschen wollen?', - 'ConfirmPassword' => 'Passwortbestätigung', + 'ConfiguredFor' => 'Konfiguriert für', + 'ConfirmDeleteEvents' => 'Sind Sie sicher, dass Sie die ausgewählten Ereignisse löschen wollen?', + 'ConfirmPassword' => 'Passwortbestätigung', 'ConjAnd' => 'und', 'ConjOr' => 'oder', 'Console' => 'Konsole', - 'ContactAdmin' => 'Bitte kontaktieren Sie den Administrator für weitere Details', + 'ContactAdmin' => 'Bitte kontaktieren Sie den Administrator für weitere Details', 'Continue' => 'Weiter', 'Contrast' => 'Kontrast', 'Control' => 'Kontrolle', 'ControlAddress' => 'Kontrolladresse', - 'ControlCap' => 'Kontrollmöglichkeit', - 'ControlCaps' => 'Kontrollmöglichkeiten', - 'ControlDevice' => 'Kontrollgerät', + 'ControlCap' => 'Kontrollmöglichkeit', + 'ControlCaps' => 'Kontrollmöglichkeiten', + 'ControlDevice' => 'Kontrollgerät', 'ControlType' => 'Kontrolltyp', 'Controllable' => 'Kontrollierbar', - 'Current' => 'Current', // Added - 2015-04-18 + 'Current' => 'Aktuell', // Added - 2015-04-18 'Cycle' => 'Zyklus', 'CycleWatch' => 'Zeitzyklus', - 'DateTime' => 'Date/Time', // Added - 2011-06-16 + 'DateTime' => 'Datum/Zeit', // Added - 2011-06-16 'Day' => 'Tag', 'Debug' => 'Debug', 'DefaultRate' => 'Standardrate', 'DefaultScale' => 'Standardskalierung', 'DefaultView' => 'Standardansicht', 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 - 'Delay' => 'Delay', // Added - 2015-04-18 - 'Delete' => 'Löschen', - 'DeleteAndNext' => 'Löschen & Nächstes', - 'DeleteAndPrev' => 'Löschen & Vorheriges', - 'DeleteSavedFilter' => 'Lösche gespeichertes Filter', + 'Delay' => 'Verzögerung', // Added - 2015-04-18 + 'Delete' => 'Löschen', + 'DeleteAndNext' => 'Löschen & Nächstes', + 'DeleteAndPrev' => 'Löschen & Vorheriges', + 'DeleteSavedFilter' => 'Lösche gespeichertes Filter', 'Description' => 'Beschreibung', - 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 - 'Device' => 'Device', // Added - 2009-02-08 - 'DeviceChannel' => 'Gerätekanal', - 'DeviceFormat' => 'Geräteformat', - 'DeviceNumber' => 'Gerätenummer', - 'DevicePath' => 'Gerätepfad', - 'Devices' => 'Geräte', + 'DetectedCameras' => 'Erkannte Kameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Erkannte Profile', // Added - 2015-04-18 + 'Device' => 'Gerät', // Added - 2009-02-08 + 'DeviceChannel' => 'Gerätekanal', + 'DeviceFormat' => 'Geräteformat', + 'DeviceNumber' => 'Gerätenummer', + 'DevicePath' => 'Gerätepfad', + 'Devices' => 'Geräte', 'Dimensions' => 'Abmessungen', 'DisableAlarms' => 'Alarme abschalten', 'Disk' => 'Disk', - 'Display' => 'Display', // Added - 2011-01-30 - 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'Display' => 'Anzeige', // Added - 2011-01-30 + 'Displaying' => 'Gezeigt', // Added - 2011-06-16 'DoNativeMotionDetection'=> 'Do Native Motion Detection', '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 fr 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!', + '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!', 'DonateRemindDay' => 'Noch nicht, erinnere mich in einem Tag noch mal.', 'DonateRemindHour' => 'Noch nicht, erinnere mich in einer Stunde noch mal.', 'DonateRemindMonth' => 'Noch nicht, erinnere mich in einem Monat noch mal.', - 'DonateRemindNever' => 'Nein, ich möchte nicht spenden, niemals erinnern.', + 'DonateRemindNever' => 'Nein, ich möchte nicht spenden, niemals erinnern.', 'DonateRemindWeek' => 'Noch nicht, erinnere mich in einer Woche noch mal.', - 'DonateYes' => 'Ja, ich möchte jetzt spenden.', + 'DonateYes' => 'Ja, ich möchte jetzt spenden.', 'Download' => 'Download', - 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 + 'DuplicateMonitorName' => 'Duplizierter Monitorname', // Added - 2009-03-31 'Duration' => 'Dauer', 'Edit' => 'Bearbeiten', 'Email' => 'E-Mail', @@ -285,16 +286,16 @@ $SLANG = array( 'EnterNewFilterName' => 'Neuen Filternamen eingeben', 'Error' => 'Fehler', 'ErrorBrackets' => 'Fehler. Bitte nur gleiche Anzahl offener und geschlossener Klammern.', - 'ErrorValidValue' => 'Fehler. Bitte alle Werte auf richtige Eingabe prüfen', + 'ErrorValidValue' => 'Fehler. Bitte alle Werte auf richtige Eingabe prüfen', 'Etc' => 'etc.', 'Event' => 'Ereignis', 'EventFilter' => 'Ereignisfilter', 'EventId' => 'Ereignis-ID', 'EventName' => 'Ereignisname', - 'EventPrefix' => 'Ereignis-Präfix', + 'EventPrefix' => 'Ereignis-Präfix', 'Events' => 'Ereignisse', 'Exclude' => 'Ausschluss;', - 'Execute' => 'Ausführen', + 'Execute' => 'Ausführen', 'Export' => 'Exportieren', 'ExportDetails' => 'Exportiere Ereignis-Details', 'ExportFailed' => 'Exportieren fehlgeschlagen', @@ -306,28 +307,28 @@ $SLANG = array( 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Exportiere andere Dateien (falls vorhanden)', 'ExportOptions' => 'Exportierungsoptionen', - 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 + 'ExportSucceeded' => 'Export erfolgreich', // Added - 2009-02-08 'ExportVideoFiles' => 'Exportiere Videodateien (falls vorhanden)', 'Exporting' => 'Exportiere', 'FPS' => 'fps', 'FPSReportInterval' => 'fps-Meldeintervall', 'FTP' => 'FTP', 'Far' => 'Weit', - 'FastForward' => 'Schnell vorwärts', + 'FastForward' => 'Schnell vorwärts', 'Feed' => 'Eingabe', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'Datei', 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archivierung aller Treffer', - 'FilterDeleteEvents' => 'Löschen aller Treffer', + 'FilterDeleteEvents' => 'Löschen aller Treffer', 'FilterEmailEvents' => 'Detaillierte E-Mail zu allen Treffern', - 'FilterExecuteEvents' => 'Ausführen bei allen Treffern', - 'FilterLog' => 'Filter log', // Added - 2015-04-18 + 'FilterExecuteEvents' => 'Ausführen bei allen Treffern', + 'FilterLog' => 'Log filtern', // Added - 2015-04-18 'FilterMessageEvents' => 'Detaillierte Nachricht zu allen Treffern', 'FilterPx' => 'Filter-Pixel', - 'FilterUnset' => 'Sie müssen eine Breite und Höhe für das Filter angeben', + 'FilterUnset' => 'Sie müssen eine Breite und Höhe für das Filter angeben', 'FilterUploadEvents' => 'Hochladen aller Treffer', - 'FilterVideoEvents' => 'Video für alle Treffer erstellen', + 'FilterVideoEvents' => 'Video für alle Treffer erstellen', 'Filters' => 'Filter', 'First' => 'Erstes', 'FlippedHori' => 'Horizontal gespiegelt', @@ -336,10 +337,10 @@ $SLANG = array( 'FnModect' => 'Modect', // Added 2013.08.16. 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. - 'FnNone' => 'None', // Added 2013.08.16. + 'FnNone' => 'Keine', // Added 2013.08.16. 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Fokus', - 'ForceAlarm' => 'Unbedingter Alarm', + 'ForceAlarm' => 'Erzwinge Alarm', 'Format' => 'Format', 'Frame' => 'Bild', 'FrameId' => 'Bild-ID', @@ -348,7 +349,7 @@ $SLANG = array( 'Frames' => 'Bilder', 'Func' => 'Fkt.', 'Function' => 'Funktion', - 'Gain' => 'Verstärkung', + 'Gain' => 'Verstärkung', 'General' => 'Allgemeines', 'GenerateVideo' => 'Erzeuge Video', 'GeneratingVideo' => 'Erzeuge Video...', @@ -357,7 +358,7 @@ $SLANG = array( 'Group' => 'Gruppe', 'Groups' => 'Gruppen', 'HasFocusSpeed' => 'Hat Fokus-Geschwindigkeit', - 'HasGainSpeed' => 'Hat Verstäkungs-Geschwindigkeit', + 'HasGainSpeed' => 'Hat Verstäkungs-Geschwindigkeit', 'HasHomePreset' => 'Hat Standardvoreinstellungen', 'HasIrisSpeed' => 'Hat Irisgeschwindigkeit', 'HasPanSpeed' => 'Hat Pan-Geschwindigkeit', @@ -365,10 +366,10 @@ $SLANG = array( 'HasTiltSpeed' => 'Hat Neigungsgeschwindigkeit', 'HasTurboPan' => 'Hat Turbo-Pan', 'HasTurboTilt' => 'Hat Turbo-Neigung', - 'HasWhiteSpeed' => 'Hat Weiß-Abgleichgeschwindigkeit', + 'HasWhiteSpeed' => 'Hat Weiß-Abgleichgeschwindigkeit', 'HasZoomSpeed' => 'Hat Zoom-Geschwindigkeit', 'High' => 'hohe', - 'HighBW' => 'Hohe B/W', + 'HighBW' => 'Hohe B/W', 'Home' => 'Home', 'Hour' => 'Stunde', 'Hue' => 'Farbton', @@ -376,22 +377,22 @@ $SLANG = array( 'Idle' => 'Leerlauf', 'Ignore' => 'Ignoriere', 'Image' => 'Bild', - 'ImageBufferSize' => 'Bildpuffergröße', + 'ImageBufferSize' => 'Bildpuffergröße', 'Images' => 'Bilder', 'In' => 'In', 'Include' => 'Einschluss', 'Inverted' => 'Invertiert', 'Iris' => 'Iris', - 'KeyString' => 'Schlüsselwort', + 'KeyString' => 'Schlüsselwort', 'Label' => 'Bezeichnung', 'Language' => 'Sprache', 'Last' => 'Letztes', 'Layout' => 'Layout', // Added - 2009-02-08 - 'Level' => 'Level', // Added - 2011-06-16 + 'Level' => 'Stufe', // Added - 2011-06-16 'Libvlc' => 'Libvlc', '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 + 'Line' => 'Zeile', // Added - 2011-06-16 'LinkedMonitors' => 'Verbundene Monitore', 'List' => 'Liste', 'Load' => 'Last', @@ -404,7 +405,7 @@ $SLANG = array( 'Logout' => 'Abmelden', 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'niedrige', - 'LowBW' => 'Niedrige B/W', + 'LowBW' => 'Niedrige B/W', 'Main' => 'Haupt', 'Man' => 'Man', 'Manual' => 'Manual', @@ -415,9 +416,9 @@ $SLANG = array( 'MaxFocusRange' => 'Maximaler Fokusbereich', 'MaxFocusSpeed' => 'Maximale Fokusgeschwindigkeit', 'MaxFocusStep' => 'Maximale Fokusstufe', - 'MaxGainRange' => 'Maximaler Verstärkungsbereich', - 'MaxGainSpeed' => 'Maximale Verstärkungsgeschwindigkeit', - 'MaxGainStep' => 'Maximale Verstärkungsstufe', + 'MaxGainRange' => 'Maximaler Verstärkungsbereich', + 'MaxGainSpeed' => 'Maximale Verstärkungsgeschwindigkeit', + 'MaxGainStep' => 'Maximale Verstärkungsstufe', 'MaxIrisRange' => 'Maximaler Irisbereich', 'MaxIrisSpeed' => 'Maximale Irisgeschwindigkeit', 'MaxIrisStep' => 'Maximale Irisstufe', @@ -427,32 +428,32 @@ $SLANG = array( 'MaxTiltRange' => 'Maximaler Neig.-Bereich', 'MaxTiltSpeed' => 'Maximale Neig.-Geschw.', 'MaxTiltStep' => 'Maximale Neig.-Stufe', - 'MaxWhiteRange' => 'Maximaler Weiß-Abgl.bereich', - 'MaxWhiteSpeed' => 'Maximale Weiß-Abgl.geschw.', - 'MaxWhiteStep' => 'Maximale Weiß-Abgl.stufe', + 'MaxWhiteRange' => 'Maximaler Weiß-Abgl.bereich', + 'MaxWhiteSpeed' => 'Maximale Weiß-Abgl.geschw.', + 'MaxWhiteStep' => 'Maximale Weiß-Abgl.stufe', 'MaxZoomRange' => 'Maximaler Zoom-Bereich', 'MaxZoomSpeed' => 'Maximale Zoom-Geschw.', 'MaxZoomStep' => 'Maximale Zoom-Stufe', 'MaximumFPS' => 'Maximale FPS', 'Medium' => 'mittlere', - 'MediumBW' => 'Mittlere B/W', - 'Message' => 'Message', // Added - 2011-06-16 + 'MediumBW' => 'Mittlere B/W', + 'Message' => 'Nachricht', // 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', - 'MinBlobAreaUnset' => 'Sie müssen einen Minimumwert an Blobflächenpixeln angeben', - 'MinBlobLtMinFilter' => 'Die minimale Blob-Fläche sollte kleiner oder gleich der minimalen Filterfläche sein', - 'MinBlobsLtMax' => 'Die minimalen Blobs müssen kleiner sein als die maximalen', - 'MinBlobsUnset' => 'Sie müssen einen Minimumwert an Blobs angeben', - 'MinFilterAreaLtMax' => 'Die minimale Filterfläche sollte kleiner sein als die maximale', - 'MinFilterAreaUnset' => 'Sie müssen einen Minimumwert an Filterpixeln angeben', - 'MinFilterLtMinAlarm' => 'Die minimale Filterfläche sollte kleiner oder gleich der minimalen Alarmfläche sein', + 'MinAlarmAreaUnset' => 'Sie müssen einen Minimumwert an Alarmflächenpixeln angeben', + 'MinBlobAreaLtMax' => 'Die minimale Blob-Fläche muss kleiner sein als die maximale', + 'MinBlobAreaUnset' => 'Sie müssen einen Minimumwert an Blobflächenpixeln angeben', + 'MinBlobLtMinFilter' => 'Die minimale Blob-Fläche sollte kleiner oder gleich der minimalen Filterfläche sein', + 'MinBlobsLtMax' => 'Die minimalen Blobs müssen kleiner sein als die maximalen', + 'MinBlobsUnset' => 'Sie müssen einen Minimumwert an Blobs angeben', + 'MinFilterAreaLtMax' => 'Die minimale Filterfläche sollte kleiner sein als die maximale', + 'MinFilterAreaUnset' => 'Sie müssen einen Minimumwert an Filterpixeln angeben', + 'MinFilterLtMinAlarm' => 'Die minimale Filterfläche sollte kleiner oder gleich der minimalen Alarmfläche sein', 'MinFocusRange' => 'Min. Fokusbereich', 'MinFocusSpeed' => 'Min. Fokusgeschw.', 'MinFocusStep' => 'Min. Fokusstufe', - 'MinGainRange' => 'Min. Verstärkungsbereich', - 'MinGainSpeed' => 'Min. Verstärkungsgeschwindigkeit', - 'MinGainStep' => 'Min. Verstärkungsstufe', + 'MinGainRange' => 'Min. Verstärkungsbereich', + 'MinGainSpeed' => 'Min. Verstärkungsgeschwindigkeit', + 'MinGainStep' => 'Min. Verstärkungsstufe', 'MinIrisRange' => 'Min. Irisbereich', 'MinIrisSpeed' => 'Min. Irisgeschwindigkeit', 'MinIrisStep' => 'Min. Irisstufe', @@ -460,40 +461,40 @@ $SLANG = array( 'MinPanSpeed' => 'Min. Pan-Geschwindigkeit', 'MinPanStep' => 'Min. Pan-Stufe', 'MinPixelThresLtMax' => 'Der minimale Pixelschwellwert muss kleiner sein als der maximale', - 'MinPixelThresUnset' => 'Sie müssen einen minimalen Pixel-Schwellenwert angeben', + 'MinPixelThresUnset' => 'Sie müssen einen minimalen Pixel-Schwellenwert angeben', 'MinTiltRange' => 'Min. Neigungsbereich', 'MinTiltSpeed' => 'Min. Neigungsgeschwindigkeit', 'MinTiltStep' => 'Min. Neigungsstufe', - 'MinWhiteRange' => 'Min. Weiß-Abgleichbereich', - 'MinWhiteSpeed' => 'Min. Weiß-Abgleichgeschwindigkeit', - 'MinWhiteStep' => 'Min. Weiß-Abgleichstufe', + 'MinWhiteRange' => 'Min. Weiß-Abgleichbereich', + 'MinWhiteSpeed' => 'Min. Weiß-Abgleichgeschwindigkeit', + 'MinWhiteStep' => 'Min. Weiß-Abgleichstufe', 'MinZoomRange' => 'Min. Zoom-Bereich', 'MinZoomSpeed' => 'Min. Zoom-Geschwindigkeit', 'MinZoomStep' => 'Min. Zoom-Stufe', 'Misc' => 'Verschiedenes', - 'Mode' => 'Mode', // Added - 2015-04-18 + 'Mode' => 'Modus', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Monitor-ID', 'MonitorPreset' => 'Monitor-Voreinstellung', - 'MonitorPresetIntro' => 'Wählen Sie eine geeignete Voreinstellung aus der folgenden Liste.

    Bitte beachten Sie, dass dies mögliche Einstellungen von Ihnen am Monitor überschreiben kann.

    ', - 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 - 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

    Select the desired entry from the list below.

    Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

    ', // Added - 2009-03-31 + 'MonitorPresetIntro' => 'Wählen Sie eine geeignete Voreinstellung aus der folgenden Liste.

    Bitte beachten Sie, dass dies mögliche Einstellungen von Ihnen am Monitor überschreiben kann.

    ', + 'MonitorProbe' => 'Kamera suche', // Added - 2009-03-31 + 'MonitorProbeIntro' => 'Die nachfolgende Liste zeigt erkannte Analog- und Netzwerkkameras, ob sie bereits genutzt werden und ob sie zur Auswahl verfügbar sind.

    Wähle den gewünschten Eintrag aus der folgenden Liste.

    Bitte Beachten: Nicht alle Kameras können erkannt werden. Die Auswahl einer Kamera kann bereits eingetragene Werte im aktuellen Monitor überschreiben.

    ', // Added - 2009-03-31 'Monitors' => 'Monitore', 'Montage' => 'Montage', 'Month' => 'Monat', - 'More' => 'More', // Added - 2011-06-16 + 'More' => 'Mehr', // Added - 2011-06-16 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Bewegung', - 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. - 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. - 'MtgDefault' => 'Default', // Added 2013.08.15. + 'Mtg2widgrd' => '2 Spalten', // Added 2013.08.15. + 'Mtg3widgrd' => '3 Spalten', // Added 2013.08.15. + 'Mtg3widgrx' => '3 Spalten, skaliert, vergr. bei Alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4 Spalten', // Added 2013.08.15. + 'MtgDefault' => 'Standard', // Added 2013.08.15. 'MustBeGe' => 'muss groesser oder gleich sein wie', 'MustBeLe' => 'muss kleiner oder gleich sein wie', - 'MustConfirmPassword' => 'Sie müssen das Passwort bestätigen.', - 'MustSupplyPassword' => 'Sie müssen ein Passwort vergeben.', - 'MustSupplyUsername' => 'Sie müssen einen Usernamen vergeben.', + 'MustConfirmPassword' => 'Sie müssen das Passwort bestätigen.', + 'MustSupplyPassword' => 'Sie müssen ein Passwort vergeben.', + 'MustSupplyUsername' => 'Sie müssen einen Usernamen vergeben.', 'Name' => 'Name', 'Near' => 'Nah', 'Network' => 'Netzwerk', @@ -503,23 +504,23 @@ $SLANG = array( 'NewPassword' => 'Neues Passwort', 'NewState' => 'Neuer Status', 'NewUser' => 'Neuer Benutzer', - 'Next' => 'Nächstes', + 'Next' => 'Nächstes', 'No' => 'Nein', - 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 + 'NoDetectedCameras' => 'Keine Kameras erkannt', // Added - 2009-03-31 'NoFramesRecorded' => 'Es gibt keine Aufnahmen von diesem Ereignis.', 'NoGroup' => 'Keine Gruppe', 'NoSavedFilters' => 'Keine gespeicherten Filter', - 'NoStatisticsRecorded' => 'Keine Statistik für dieses Ereignis/diese Bilder', + 'NoStatisticsRecorded' => 'Keine Statistik für dieses Ereignis/diese Bilder', 'None' => 'ohne', - 'NoneAvailable' => 'Nichts verfügbar', + 'NoneAvailable' => 'Nichts verfügbar', 'Normal' => 'Normal', 'Notes' => 'Bemerkungen', 'NumPresets' => 'Nummerierte Voreinstellungen', 'Off' => 'Aus', 'On' => 'An', - 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
    If no user has been created for the camera then the user given here will be created with the given password.

    ', // Added - 2015-04-18 + 'OnvifCredentialsIntro'=> 'Bitte den Benutzernamen und das Passwort für die gewählte Kamera eintragen.
    Der hier eingetragene Benutzer wird erstellt mitsamt des Passworts, falls kein Benutzer für diese Kamera erstellt wurde.

    ', // Added - 2015-04-18 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 - 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

    Select the desired entry from the list below.

    Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

    ', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'Die folgende Liste zeigt erkannte ONVIF Kameras, ob sie bereits genutzt werden und ob sie zur Auswahl verfügbar sind.

    Wähle den gewünschten Eintrag aus der folgenden Liste.

    Bitte Beachten: Nicht alle Kameras können erkannt werden. Die Auswahl einer Kamera kann bereits eingetragene Werte im aktuellen Monitor überschreiben.

    ', // Added - 2015-04-18 'OpEq' => 'gleich zu', 'OpGt' => 'groesser als', 'OpGtEq' => 'groesser oder gleich wie', @@ -530,15 +531,15 @@ $SLANG = array( 'OpNe' => 'nicht gleich', 'OpNotIn' => 'nicht im Satz', 'OpNotMatches' => 'nicht zutreffend', - 'Open' => 'Öffnen', + 'Open' => 'öffnen', 'OptionHelp' => 'Hilfe', - 'OptionRestartWarning' => 'Veränderungen werden erst nach einem Neustart des Programms aktiv.\nFür eine sofortige Änderung starten Sie das Programm bitte neu.', + 'OptionRestartWarning' => 'Veränderungen werden erst nach einem Neustart des Programms aktiv.\nFür eine sofortige änderung starten Sie das Programm bitte neu.', 'Options' => 'Optionen', 'OrEnterNewName' => 'oder neuen Namen eingeben', 'Order' => 'Reihenfolge', 'Orientation' => 'Ausrichtung', 'Out' => 'Aus', - 'OverwriteExisting' => 'Überschreibe bestehende', + 'OverwriteExisting' => 'überschreibe bestehende', 'Paged' => 'Seitennummeriert', 'Pan' => 'Pan', 'PanLeft' => 'Pan-Left', @@ -546,11 +547,11 @@ $SLANG = array( 'PanTilt' => 'Pan/Neigung', 'Parameter' => 'Parameter', 'Password' => 'Passwort', - 'PasswordsDifferent' => 'Die Passwörter sind unterschiedlich', + 'PasswordsDifferent' => 'Die Passwörter sind unterschiedlich', 'Paths' => 'Pfade', 'Pause' => 'Pause', 'Phone' => 'Telefon', - 'PhoneBW' => 'Tel. B/W', + 'PhoneBW' => 'Tel. B/W', 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel-Differenz', 'Pixels' => 'Pixel', @@ -561,60 +562,60 @@ $SLANG = array( 'Point' => 'Punkt', 'PostEventImageBuffer' => 'Nachereignispuffer', 'PreEventImageBuffer' => 'Vorereignispuffer', - 'PreserveAspect' => 'Seitenverhältnis beibehalten', + 'PreserveAspect' => 'Seitenverhältnis beibehalten', 'Preset' => 'Voreinstellung', 'Presets' => 'Voreinstellungen', 'Prev' => 'Vorheriges', - 'Probe' => 'Probe', // Added - 2009-03-31 - 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 - 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

    Select the desired entry from the list below.

    Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

    ', // Added - 2015-04-18 - 'Progress' => 'Progress', // Added - 2015-04-18 + 'Probe' => 'Sonde', // Added - 2009-03-31 + 'ProfileProbe' => 'Streamsonde', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'Die folgende Liste zeigt die verfügbaren Streamingprofile der ausgewählten Kamera.

    Wähle den gewünschten Eintrag aus der folgenden Liste.

    Bitte Beachten: Zoneminder kann keine zusätzlichen Profile konfigurieren. Die Auswahl einer Kamera kann bereits eingetragene Werte im aktuellen Monitor überschreiben.

    ', // Added - 2015-04-18 + 'Progress' => 'Fortschritt', // Added - 2015-04-18 'Protocol' => 'Protokoll', 'Rate' => 'Abspielgeschwindigkeit', 'Real' => 'Real', 'Record' => 'Aufnahme', 'RefImageBlendPct' => 'Referenz-Bildblende', 'Refresh' => 'Aktualisieren', - 'Remote' => 'Entfernt', - 'RemoteHostName' => 'Entfernter Hostname', - 'RemoteHostPath' => 'Entfernter Hostpfad', - 'RemoteHostPort' => 'Entfernter Hostport', - 'RemoteHostSubPath' => 'Remote Host SubPath', // Added - 2009-02-08 - 'RemoteImageColours' => 'Entfernte Bildfarbe', - 'RemoteMethod' => 'Remote Method', // Added - 2009-02-08 - 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 + 'Remote' => 'Remote', + 'RemoteHostName' => 'Remote Hostname', + 'RemoteHostPath' => 'Remote Hostpfad', + 'RemoteHostPort' => 'Remote Hostport', + 'RemoteHostSubPath' => 'Remote Hostunterpfad', // Added - 2009-02-08 + 'RemoteImageColours' => 'Remote Bildfarbe', + 'RemoteMethod' => 'Remote Methode', // Added - 2009-02-08 + 'RemoteProtocol' => 'Remote Protokol', // Added - 2009-02-08 'Rename' => 'Umbenennen', 'Replay' => 'Wiederholung', 'ReplayAll' => 'Alle Ereignisse', - 'ReplayGapless' => 'Lückenlose Ereignisse', + 'ReplayGapless' => 'Lückenlose Ereignisse', 'ReplaySingle' => 'Einzelereignis', - 'Reset' => 'Zurücksetzen', - 'ResetEventCounts' => 'Lösche Ereignispunktzahl', + 'Reset' => 'Zurücksetzen', + 'ResetEventCounts' => 'Lösche Ereignispunktzahl', 'Restart' => 'Neustart', 'Restarting' => 'Neustarten', 'RestrictedCameraIds' => 'Verbotene Kamera-ID', - 'RestrictedMonitors' => 'Eingeschränkte Monitore', - 'ReturnDelay' => 'Rückkehr-Verzögerung', - 'ReturnLocation' => 'Rückkehrpunkt', - 'Rewind' => 'Zurückspulen', + 'RestrictedMonitors' => 'Eingeschränkte Monitore', + 'ReturnDelay' => 'Rückkehr-Verzögerung', + 'ReturnLocation' => 'Rückkehrpunkt', + 'Rewind' => 'Zurückspulen', 'RotateLeft' => 'Drehung links', 'RotateRight' => 'Drehung rechts', - 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 + 'RunLocalUpdate' => 'Bitte zmupdate.pl starten um upzudaten.', // Added - 2011-05-25 'RunMode' => 'Betriebsmodus', 'RunState' => 'Laufender Status', 'Running' => 'In Betrieb', - 'Save' => 'OK', + 'Save' => 'Speichern', 'SaveAs' => 'Speichere als', 'SaveFilter' => 'Speichere Filter', 'Scale' => 'Skalierung', 'Score' => 'Punktzahl', 'Secs' => 'Sekunden', - 'Sectionlength' => 'Sektionslänge', + '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.', + 'SelectFormat' => 'Format Auswahl', // Added - 2011-06-17 + 'SelectLog' => 'Log Auswahl', // Added - 2011-06-17 + 'SelectMonitors' => 'Wähle Monitore', + 'SelfIntersecting' => 'Die Polygonränder dürfen sich nicht überschneiden.', 'Set' => 'Setze', 'SetNewBandwidth' => 'Setze neue Bandbreite', 'SetPreset' => 'Setze Voreinstellung', @@ -622,15 +623,15 @@ $SLANG = array( 'ShowFilterWindow' => 'Zeige Filterfenster', 'ShowTimeline' => 'Zeige Zeitlinie', 'SignalCheckColour' => 'Farbe des Signalchecks', - 'Size' => 'Größe', - 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 + 'Size' => 'Größe', + 'SkinDescription' => 'Wähle den standard Skin für diesen Computer.', // Added - 2011-01-30 'Sleep' => 'Schlaf', 'SortAsc' => 'aufsteigend', 'SortBy' => 'Sortieren nach', 'SortDesc' => 'absteigend', 'Source' => 'Quelle', - 'SourceColours' => 'Source Colours', // Added - 2009-02-08 - 'SourcePath' => 'Source Path', // Added - 2009-02-08 + 'SourceColours' => 'Quellenfarben', // Added - 2009-02-08 + 'SourcePath' => 'Quellenpfad', // Added - 2009-02-08 'SourceType' => 'Quellentyp', 'Speed' => 'Geschwindigkeit', 'SpeedHigh' => 'Hohe Geschwindigkeit', @@ -642,9 +643,9 @@ $SLANG = array( 'Stats' => 'Status', 'Status' => 'Status', 'Step' => 'Stufe', - 'StepBack' => 'Einen Schritt rückwärts', - 'StepForward' => 'Einen Schritt vorwärts', - 'StepLarge' => 'Große Stufe', + 'StepBack' => 'Einen Schritt rückwärts', + 'StepForward' => 'Einen Schritt vorwärts', + 'StepLarge' => 'Große Stufe', 'StepMedium' => 'Mittlere Stufe', 'StepNone' => 'Keine Stufe', 'StepSmall' => 'Kleine Stufe', @@ -656,7 +657,7 @@ $SLANG = array( 'Submit' => 'Absenden', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 - 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 + 'TargetColorspace' => 'Zielfarbbereich', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Miniatur', 'Tilt' => 'Neigung', @@ -664,10 +665,10 @@ $SLANG = array( 'TimeDelta' => 'Zeitdifferenz', 'TimeStamp' => 'Zeitstempel', 'Timeline' => 'Zeitlinie', - 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. - 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. - 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. - 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. + 'TimelineTip1' => 'Bewege die Maus über dem Graphen um eine Vorschau und Ereignisdetails zu sehen.', // Added 2013.08.15. + 'TimelineTip2' => 'Clicke auf den farbigen Abschnitt des Graphen oder auf das Bild um den Ereignis zu betrachten', // Added 2013.08.15. + 'TimelineTip3' => 'Clicke auf den Hintergrund, um in den Zeitabschnitt um das Ereignis hereinzuzoomen.', // Added 2013.08.15. + 'TimelineTip4' => 'Benutze die unteren Bedienelemente um herauszuzoomen oder sich in der Zeitleiste zu bewegen.', // Added 2013.08.15. 'Timestamp' => 'Zeitstempel', 'TimestampLabelFormat' => 'Format des Zeitstempels', 'TimestampLabelX' => 'Zeitstempel-X', @@ -676,37 +677,37 @@ $SLANG = array( 'Tools' => 'Werkzeuge', 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Totale
    Punktzahl', - 'TrackDelay' => 'Nachführungsverzögerung', - 'TrackMotion' => 'Bewegungs-Nachführung', - 'Triggers' => 'Auslöser', + 'TrackDelay' => 'Nachführungsverzögerung', + 'TrackMotion' => 'Bewegungs-Nachführung', + 'Triggers' => 'Auslöser', 'TurboPanSpeed' => 'Turbo-Pan-Geschwindigkeit', 'TurboTiltSpeed' => 'Turbo-Neigungsgeschwindigkeit', 'Type' => 'Typ', 'Unarchive' => 'Aus Archiv entfernen', - 'Undefined' => 'Undefined', // Added - 2009-02-08 + 'Undefined' => 'Undefiniert', // Added - 2009-02-08 'Units' => 'Einheiten', 'Unknown' => 'Unbekannt', 'Update' => 'Aktualisieren', - 'UpdateAvailable' => 'Eine Aktualisierung für ZoneMinder ist verfügbar.', - 'UpdateNotNecessary' => 'Es ist keine Aktualisierung verfügbar.', - 'Updated' => 'Updated', // Added - 2011-06-16 - 'Upload' => 'Upload', // Added - 2011-08-23 + 'UpdateAvailable' => 'Eine Aktualisierung für ZoneMinder ist verfügbar.', + 'UpdateNotNecessary' => 'Es ist keine Aktualisierung verfügbar.', + 'Updated' => 'Aktualisiert', // Added - 2011-06-16 + 'Upload' => 'Hochladen', // Added - 2011-08-23 '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' + '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' 'UsedPlugins' => 'Used Plugins', 'User' => 'Benutzer', 'Username' => 'Benutzername', 'Users' => 'Benutzer', 'V4L' => 'V4L', // Added - 2015-04-18 - 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Aufnahmen pro Bild', // Added - 2015-04-18 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Wert', 'Version' => 'Version', 'VersionIgnore' => 'Ignoriere diese Version', 'VersionRemindDay' => 'Erinnere mich wieder in 1 Tag.', 'VersionRemindHour' => 'Erinnere mich wieder in 1 Stunde.', - 'VersionRemindNever' => 'Informiere mich nicht mehr über neue Versionen.', + 'VersionRemindNever' => 'Informiere mich nicht mehr über neue Versionen.', 'VersionRemindWeek' => 'Erinnere mich wieder in 1 Woche.', 'Video' => 'Video', 'VideoFormat' => 'Videoformat', @@ -715,19 +716,19 @@ $SLANG = array( 'VideoGenNoFiles' => 'Keine Videodateien gefunden.', 'VideoGenParms' => 'Parameter der Videoerzeugung', 'VideoGenSucceeded' => 'Videoerzeugung erfolgreich!', - 'VideoSize' => 'Videogröße', + 'VideoSize' => 'Videogröße', 'View' => 'Ansicht', 'ViewAll' => 'Alles ansehen', 'ViewEvent' => 'Zeige Ereignis', 'ViewPaged' => 'Seitenansicht', 'Wake' => 'Aufwachen', - 'WarmupFrames' => 'Aufwärmbilder', + 'WarmupFrames' => 'Aufwärmbilder', 'Watch' => 'Beobachte', 'Web' => 'Web', 'WebColour' => 'Webfarbe', 'Week' => 'Woche', - 'White' => 'Weiß', - 'WhiteBalance' => 'Weiß-Abgleich', + 'White' => 'Weiß', + 'WhiteBalance' => 'Weiß-Abgleich', 'Wide' => 'Weit', 'X' => 'X', 'X10' => 'X10', @@ -738,17 +739,17 @@ $SLANG = array( 'Yes' => 'Ja', 'YouNoPerms' => 'Keine Erlaubnis zum Zugang dieser Resource.', 'Zone' => 'Zone', - 'ZoneAlarmColour' => 'Alarmfarbe (Rot/Grün/Blau)', + 'ZoneAlarmColour' => 'Alarmfarbe (Rot/Grün/Blau)', 'ZoneArea' => 'Zone Area', - 'ZoneExtendAlarmFrames' => 'Alarmstatus nach Ende für Frames aufrechterhalten', - 'ZoneFilterSize' => 'Filter-Breite/-Höhe (Pixel)', - 'ZoneMinMaxAlarmArea' => 'Min./max. Alarmfläche', - 'ZoneMinMaxBlobArea' => 'Min./max. Blobfläche', + 'ZoneExtendAlarmFrames' => 'Alarmstatus nach Ende für Frames aufrechterhalten', + 'ZoneFilterSize' => 'Filter-Breite/-Höhe (Pixel)', + 'ZoneMinMaxAlarmArea' => 'Min./max. Alarmfläche', + 'ZoneMinMaxBlobArea' => 'Min./max. Blobfläche', 'ZoneMinMaxBlobs' => 'Min./max. Blobs', - 'ZoneMinMaxFiltArea' => 'Min./max. Filterfläche', + 'ZoneMinMaxFiltArea' => 'Min./max. Filterfläche', 'ZoneMinMaxPixelThres' => 'Min./max. Pixelschwellwert', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 - 'ZoneOverloadFrames' => 'Bildauslassrate bei Systemüberlastung', + 'ZoneOverloadFrames' => 'Bildauslassrate bei Systemüberlastung', 'Zones' => 'Zonen', 'Zoom' => 'Zoom', 'ZoomIn' => 'Hineinzoomen', From f6a226e70003edc810eed8710da903aac7f6fd09 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 27 May 2015 10:00:24 -0400 Subject: [PATCH 148/154] Correct bareword config entries with newer {} style --- scripts/zmx10.pl.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/zmx10.pl.in b/scripts/zmx10.pl.in index 17d9546b2..d25e74c8a 100644 --- a/scripts/zmx10.pl.in +++ b/scripts/zmx10.pl.in @@ -191,7 +191,7 @@ sub runServer $dbh = zmDbConnect(); - $x10 = new X10::ActiveHome( port=>ZM_X10_DEVICE, house_code=>ZM_X10_HOUSE_CODE, debug=>0 ); + $x10 = new X10::ActiveHome( port=>$Config{ZM_X10_DEVICE}, house_code=>$Config{ZM_X10_HOUSE_CODE}, debug=>0 ); loadTasks(); @@ -204,7 +204,7 @@ sub runServer #print( "F:".fileno(SERVER)."\n" ); my $reload = undef; my $reload_count = 0; - my $reload_limit = &ZM_X10_DB_RELOAD_INTERVAL / $timeout; + my $reload_limit = $Config{ZM_X10_DB_RELOAD_INTERVAL} / $timeout; while( 1 ) { my $nfound = select( my $rout = $rin, undef, undef, $timeout ); @@ -750,7 +750,7 @@ sub x10listen foreach my $event ( @_ ) { #print( Data::Dumper( $_ )."\n" ); - if ( $event->house_code() eq ZM_X10_HOUSE_CODE ) + if ( $event->house_code() eq $Config{ZM_X10_HOUSE_CODE} ) { my $unit_code = $event->unit_code(); my $device = $device_hash{$unit_code}; From a36b4aa65d00bfcad06fc1d0b1f94d8adddb9112 Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Fri, 29 May 2015 17:38:02 +0200 Subject: [PATCH 149/154] Implement version check for ffmpeg and libav (address issue #580) --- src/zm_ffmpeg.cpp | 10 ++++- src/zm_ffmpeg.h | 73 ++++++++++++++++++++++++++++------- src/zm_ffmpeg_camera.cpp | 24 ++++++++---- src/zm_local_camera.cpp | 14 ++++++- src/zm_mpeg.cpp | 50 ++++++++++++++---------- src/zm_remote_camera_rtsp.cpp | 16 ++++++-- src/zm_rtsp.cpp | 4 +- src/zm_sdp.cpp | 22 +++++++++-- src/zm_sdp.h | 4 +- 9 files changed, 161 insertions(+), 56 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 6d08f8576..fbbd23793 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -76,13 +76,21 @@ SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), Debug(4,"SWScale object created"); /* Allocate AVFrame for the input */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + input_avframe = av_frame_alloc(); +#else input_avframe = avcodec_alloc_frame(); +#endif if(input_avframe == NULL) { Fatal("Failed allocating AVFrame for the input"); } /* Allocate AVFrame for the output */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + output_avframe = av_frame_alloc(); +#else output_avframe = avcodec_alloc_frame(); +#endif if(output_avframe == NULL) { Fatal("Failed allocating AVFrame for the output"); } @@ -133,7 +141,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint return -3; } -#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0) +#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) /* Warn if the input or output pixelformat is not supported */ if(!sws_isSupportedInput(in_pf)) { Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff)); diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index fd124ca37..54a323cb6 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -32,7 +32,16 @@ extern "C" { #include #include #include -#if LIBAVUTIL_VERSION_INT > AV_VERSION_INT(50, 28, 0) + +/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVUTIL_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + +#if LIBAVUTIL_VERSION_CHECK(50, 29, 0, 29, 0) #include #else #include @@ -42,43 +51,79 @@ extern "C" { #include #include #include -#endif +#endif /* HAVE_LIBAVUTIL_AVUTIL_H */ // AVCODEC #if HAVE_LIBAVCODEC_AVCODEC_H #include + +/* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVCODEC_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_AVCODEC_H #include -#endif - +#endif /* HAVE_LIBAVCODEC_AVCODEC_H */ + #if defined(HAVE_LIBAVCODEC_AVCODEC_H) -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,25,0) +#if LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) #define _AVCODECID AVCodecID #else #define _AVCODECID CodecID #endif -#endif +#endif /* HAVE_LIBAVCODEC_AVCODEC_H */ // AVFORMAT #if HAVE_LIBAVFORMAT_AVFORMAT_H #include + +/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVFORMAT_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_AVFORMAT_H #include -#endif +#endif /* HAVE_LIBAVFORMAT_AVFORMAT_H */ // AVDEVICE #if HAVE_LIBAVDEVICE_AVDEVICE_H #include + +/* LIBAVDEVICE_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVDEVICE_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVDEVICE_VERSION_MICRO < 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVDEVICE_VERSION_MICRO >= 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_AVDEVICE_H #include -#endif +#endif /* HAVE_LIBAVDEVICE_AVDEVICE_H */ // SWSCALE #if HAVE_LIBSWSCALE_SWSCALE_H #include + +/* LIBSWSCALE_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBSWSCALE_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBSWSCALE_VERSION_MICRO < 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBSWSCALE_VERSION_MICRO >= 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_SWSCALE_H #include -#endif +#endif /* HAVE_LIBSWSCALE_SWSCALE_H */ #ifdef __cplusplus } @@ -86,7 +131,7 @@ extern "C" { #if ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H ) -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(52, 107, 0, 107, 0) #if defined(AVIO_WRONLY) #define AVIO_FLAG_WRITE AVIO_WRONLY #else @@ -129,7 +174,7 @@ protected: }; #endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 25, 0) +#if LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) #define AV_CODEC_ID_NONE CODEC_ID_NONE #define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW #define AV_CODEC_ID_PCM_ALAW CODEC_ID_PCM_ALAW @@ -165,18 +210,18 @@ protected: inline static const std::string av_make_error_string(int errnum) { char errbuf[AV_ERROR_MAX_STRING_SIZE]; -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(50, 12, 13) +#if LIBAVUTIL_VERSION_CHECK(50, 13, 0, 13, 0) av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE); #else snprintf(errbuf, AV_ERROR_MAX_STRING_SIZE, "libav error %d", errnum); #endif return (std::string)errbuf; } - + #undef av_err2str #define av_err2str(errnum) av_make_error_string(errnum).c_str() - #endif // __cplusplus + #endif // __cplusplus #endif // ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H ) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 09d39ab53..59f554325 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -170,7 +170,7 @@ int FfmpegCamera::Capture( Image &image ) Debug( 5, "Got packet from stream %d", packet.stream_index ); if ( packet.stream_index == mVideoStreamId ) { -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0) +#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 ) #else if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 ) @@ -224,7 +224,7 @@ int FfmpegCamera::OpenFfmpeg() { mIsOpening = true; // Open the input, not necessarily a file -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) Debug ( 1, "Calling av_open_input_file" ); if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 ) #else @@ -275,7 +275,7 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Opened input" ); // Locate stream info from avformat_open_input -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0) Debug ( 1, "Calling av_find_stream_info" ); if ( av_find_stream_info( mFormatContext ) < 0 ) #else @@ -283,14 +283,14 @@ int FfmpegCamera::OpenFfmpeg() { if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 ) #endif Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) ); - + Debug ( 1, "Got stream info" ); // Find first video stream present mVideoStreamId = -1; for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) @@ -314,7 +314,7 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Found decoder" ); // Open the codec -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) Debug ( 1, "Calling avcodec_open" ); if ( avcodec_open( mCodecContext, mCodec ) < 0 ) #else @@ -326,11 +326,19 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Opened codec" ); // Allocate space for the native video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mRawFrame = av_frame_alloc(); +#else mRawFrame = avcodec_alloc_frame(); +#endif // Allocate space for the converted video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mFrame = av_frame_alloc(); +#else mFrame = avcodec_alloc_frame(); - +#endif + if(mRawFrame == NULL || mFrame == NULL) Fatal( "Unable to allocate frame for %s", mPath.c_str() ); @@ -399,7 +407,7 @@ int FfmpegCamera::CloseFfmpeg(){ } if ( mFormatContext ) { -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) av_close_input_file( mFormatContext ); #else avformat_close_input( &mFormatContext ); diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 6740647bb..e2efa3dfb 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -434,7 +434,7 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel, Panic("Unexpected colours: %d",colours); } if( capture ) { -#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0) +#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) if(!sws_isSupportedInput(capturePixFormat)) { Error("swscale does not support the used capture format: %c%c%c%c",(capturePixFormat)&0xff,((capturePixFormat>>8)&0xff),((capturePixFormat>>16)&0xff),((capturePixFormat>>24)&0xff)); conversion_type = 2; /* Try ZM format conversions */ @@ -622,7 +622,11 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel, #if HAVE_LIBSWSCALE /* Initialize swscale stuff */ if(capture && conversion_type == 1) { +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + tmpPicture = av_frame_alloc(); +#else tmpPicture = avcodec_alloc_frame(); +#endif if ( !tmpPicture ) Fatal( "Could not allocate temporary picture" ); @@ -852,7 +856,11 @@ void LocalCamera::Initialise() Fatal( "Can't map video buffer %d (%d bytes) to memory: %s(%d)", i, vid_buf.length, strerror(errno), errno ); #if HAVE_LIBSWSCALE +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + capturePictures[i] = av_frame_alloc(); +#else capturePictures[i] = avcodec_alloc_frame(); +#endif if ( !capturePictures[i] ) Fatal( "Could not allocate picture" ); avpicture_fill( (AVPicture *)capturePictures[i], (uint8_t*)v4l2_data.buffers[i].start, capturePixFormat, v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height ); @@ -1006,7 +1014,11 @@ void LocalCamera::Initialise() v4l1_data.buffers[i].height = height; v4l1_data.buffers[i].format = palette; +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + capturePictures[i] = av_frame_alloc(); +#else capturePictures[i] = avcodec_alloc_frame(); +#endif if ( !capturePictures[i] ) Fatal( "Could not allocate picture" ); avpicture_fill( (AVPicture *)capturePictures[i], (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], capturePixFormat, width, height ); diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index 90092d96c..647ebeb7f 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -48,7 +48,7 @@ void VideoStream::Initialise( ) av_log_set_level( AV_LOG_QUIET ); av_register_all( ); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 13, 0) +#if LIBAVFORMAT_VERSION_CHECK(53, 13, 0, 19, 0) avformat_network_init(); #endif initialised = true; @@ -58,7 +58,7 @@ void VideoStream::SetupFormat( ) { /* allocate the output media context */ ofc = NULL; -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 5, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) avformat_alloc_output_context2( &ofc, NULL, format, filename ); #else AVFormatContext *s= avformat_alloc_context(); @@ -69,7 +69,7 @@ void VideoStream::SetupFormat( ) AVOutputFormat *oformat; if (format) { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 45, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) oformat = av_guess_format(format, NULL, NULL); #else oformat = guess_format(format, NULL, NULL); @@ -78,7 +78,7 @@ void VideoStream::SetupFormat( ) Fatal( "Requested output format '%s' is not a suitable output format", format ); } } else { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 45, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) oformat = av_guess_format(NULL, filename, NULL); #else oformat = guess_format(NULL, filename, NULL); @@ -95,7 +95,7 @@ void VideoStream::SetupFormat( ) { Fatal( "Could not allocate private data for output format." ); } -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 92, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0) if (s->oformat->priv_class) { *(const AVClass**)s->priv_data = s->oformat->priv_class; av_opt_set_defaults(s->priv_data); @@ -186,7 +186,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei } else { -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) ); #else Debug( 1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id ); @@ -202,20 +202,20 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei codec = avcodec_find_encoder( codec_id ); if ( !codec ) { -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) ); #else Fatal( "Could not find encoder for '%d'", codec_id ); #endif } -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) Debug( 1, "Found encoder for '%s'", avcodec_get_name( codec_id ) ); #else Debug( 1, "Found encoder for '%d'", codec_id ); #endif -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 10, 0) +#if LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0) ost = avformat_new_stream( ofc, codec ); #else ost = av_new_stream( ofc, 0 ); @@ -311,7 +311,7 @@ void VideoStream::OpenStream( ) AVCodecContext *c = ost->codec; /* open the codec */ -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) if ( (avRet = avcodec_open( c, codec )) < 0 ) #else if ( (avRet = avcodec_open2( c, codec, 0 )) < 0 ) @@ -323,7 +323,11 @@ void VideoStream::OpenStream( ) Debug( 1, "Opened codec" ); /* allocate the encoded raw picture */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + opicture = av_frame_alloc( ); +#else opicture = avcodec_alloc_frame( ); +#endif if ( !opicture ) { Panic( "Could not allocate opicture" ); @@ -344,7 +348,11 @@ void VideoStream::OpenStream( ) tmp_opicture = NULL; if ( c->pix_fmt != pf ) { +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + tmp_opicture = av_frame_alloc( ); +#else tmp_opicture = avcodec_alloc_frame( ); +#endif if ( !tmp_opicture ) { Panic( "Could not allocate tmp_opicture" ); @@ -364,9 +372,9 @@ void VideoStream::OpenStream( ) if ( !(of->flags & AVFMT_NOFILE) ) { int ret; -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 14, 0) +#if LIBAVFORMAT_VERSION_CHECK(53, 15, 0, 21, 0) ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL ); -#elif LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 102, 0) +#elif LIBAVFORMAT_VERSION_CHECK(52, 102, 0, 102, 0) ret = avio_open( &ofc->pb, filename, AVIO_FLAG_WRITE ); #else ret = url_fopen( &ofc->pb, filename, AVIO_FLAG_WRITE ); @@ -395,19 +403,19 @@ void VideoStream::OpenStream( ) Fatal("Unable to malloc memory for outbuf"); } } - -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 100, 1) + +#if LIBAVFORMAT_VERSION_CHECK(52, 101, 0, 101, 0) av_dump_format(ofc, 0, filename, 1); #else dump_format(ofc, 0, filename, 1); #endif - -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) + +#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) int ret = av_write_header( ofc ); #else int ret = avformat_write_header( ofc, NULL ); #endif - + if ( ret < 0 ) { Fatal( "?_write_header failed with error %d \"%s\"", ret, av_err2str( ret ) ); @@ -525,7 +533,7 @@ VideoStream::~VideoStream( ) if ( !(of->flags & AVFMT_NOFILE) ) { /* close the output file */ -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if LIBAVFORMAT_VERSION_CHECK(52, 105, 0, 105, 0) avio_close( ofc->pb ); #else url_fclose( ofc->pb ); @@ -625,7 +633,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, int got_packet = 0; if ( of->flags & AVFMT_RAWPICTURE ) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 2, 1) +#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) pkt->flags |= AV_PKT_FLAG_KEY; #else pkt->flags |= PKT_FLAG_KEY; @@ -640,7 +648,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, opicture_ptr->pts = c->frame_number; opicture_ptr->quality = c->global_quality; -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(54, 0, 0) +#if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100) int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet ); if ( ret != 0 ) { @@ -656,7 +664,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, { if ( c->coded_frame->key_frame ) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) pkt->flags |= AV_PKT_FLAG_KEY; #else pkt->flags |= PKT_FLAG_KEY; diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 910b2ac42..9f7b39227 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -162,7 +162,7 @@ int RemoteCameraRtsp::PrimeCapture() mVideoStreamId = -1; for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) @@ -183,7 +183,7 @@ int RemoteCameraRtsp::PrimeCapture() Panic( "Unable to locate codec %d decoder", mCodecContext->codec_id ); // Open codec -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) if ( avcodec_open( mCodecContext, mCodec ) < 0 ) #else if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 ) @@ -191,11 +191,19 @@ int RemoteCameraRtsp::PrimeCapture() Panic( "Can't open codec" ); // Allocate space for the native video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mRawFrame = av_frame_alloc(); +#else mRawFrame = avcodec_alloc_frame(); +#endif // Allocate space for the converted video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mFrame = av_frame_alloc(); +#else mFrame = avcodec_alloc_frame(); - +#endif + if(mRawFrame == NULL || mFrame == NULL) Fatal( "Unable to allocate frame(s)"); @@ -292,7 +300,7 @@ int RemoteCameraRtsp::Capture( Image &image ) { packet.data = buffer.head(); packet.size = buffer.size(); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0) +#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); #else int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index f36814945..02fdc4e22 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -211,7 +211,7 @@ RtspThread::~RtspThread() { if ( mFormatContext ) { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 96, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 96, 0, 96, 0) avformat_free_context( mFormatContext ); #else av_free_format_context( mFormatContext ); @@ -437,7 +437,7 @@ int RtspThread::run() for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) { SessionDescriptor::MediaDescriptor *mediaDesc = mSessDesc->getStream( i ); -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index 361b58850..dbc63a82f 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -23,7 +23,7 @@ #include "zm_sdp.h" -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) SessionDescriptor::StaticPayloadDesc SessionDescriptor::smStaticPayloads[] = { { 0, "PCMU", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_MULAW, 8000, 1 }, { 3, "GSM", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, @@ -372,7 +372,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const for ( unsigned int i = 0; i < mMediaList.size(); i++ ) { const MediaDescriptor *mediaDesc = mMediaList[i]; -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 8, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0) AVStream *stream = av_new_stream( formatContext, i ); #else AVStream *stream = avformat_new_stream( formatContext, NULL ); @@ -380,7 +380,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const #endif Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mediaDesc->getType() == "video" ) stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; else if ( mediaDesc->getType() == "audio" ) @@ -396,6 +396,9 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const stream->codec->codec_type = CODEC_TYPE_DATA; #endif +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + std::string codec_name; +#endif if ( mediaDesc->getPayloadType() < PAYLOAD_TYPE_DYNAMIC ) { // Look in static table @@ -404,7 +407,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if ( smStaticPayloads[i].payloadType == mediaDesc->getPayloadType() ) { Debug( 1, "Got static payload type %d, %s", smStaticPayloads[i].payloadType, smStaticPayloads[i].payloadName ); +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + codec_name = std::string( smStaticPayloads[i].payloadName ); +#else strncpy( stream->codec->codec_name, smStaticPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; +#endif stream->codec->codec_type = smStaticPayloads[i].codecType; stream->codec->codec_id = smStaticPayloads[i].codecId; stream->codec->sample_rate = smStaticPayloads[i].clockRate; @@ -420,7 +427,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) { Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName ); +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + codec_name = std::string( smStaticPayloads[i].payloadName ); +#else strncpy( stream->codec->codec_name, smDynamicPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; +#endif stream->codec->codec_type = smDynamicPayloads[i].codecType; stream->codec->codec_id = smDynamicPayloads[i].codecId; stream->codec->sample_rate = mediaDesc->getClock(); @@ -428,7 +439,12 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const } } } + +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + if ( codec_name.empty() ) +#else if ( !stream->codec->codec_name[0] ) +#endif { Warning( "Can't find payload details for %s payload type %d, name %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); //return( 0 ); diff --git a/src/zm_sdp.h b/src/zm_sdp.h index fb56a2886..21eb227c1 100644 --- a/src/zm_sdp.h +++ b/src/zm_sdp.h @@ -40,7 +40,7 @@ protected: { int payloadType; const char payloadName[6]; -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) AVMediaType codecType; #else enum CodecType codecType; @@ -53,7 +53,7 @@ protected: struct DynamicPayloadDesc { const char payloadName[32]; -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) AVMediaType codecType; #else enum CodecType codecType; From f6d69e02b52bac071ac24efae0a9427217487294 Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Fri, 29 May 2015 17:45:35 +0200 Subject: [PATCH 150/154] Mention original source for check functions --- src/zm_ffmpeg.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 54a323cb6..8d50f0e17 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -34,6 +34,7 @@ extern "C" { #include /* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg + * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) * a is the major version * b and c the minor and micro versions of libav * d and e the minor and micro versions of FFmpeg */ @@ -57,7 +58,9 @@ extern "C" { #if HAVE_LIBAVCODEC_AVCODEC_H #include -/* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg +/* + * LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg + * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) * a is the major version * b and c the minor and micro versions of libav * d and e the minor and micro versions of FFmpeg */ @@ -82,6 +85,7 @@ extern "C" { #include /* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg + * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) * a is the major version * b and c the minor and micro versions of libav * d and e the minor and micro versions of FFmpeg */ From 818a5256e46645087061ad7205b7889252fd8513 Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Fri, 29 May 2015 19:23:00 +0200 Subject: [PATCH 151/154] Readd checking of micro version in zm_mpeg.cpp to fix compilation issue --- src/zm_ffmpeg.h | 2 +- src/zm_mpeg.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 8d50f0e17..714665cf8 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -178,7 +178,7 @@ protected: }; #endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL -#if LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) +#if !LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) #define AV_CODEC_ID_NONE CODEC_ID_NONE #define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW #define AV_CODEC_ID_PCM_ALAW CODEC_ID_PCM_ALAW diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index 647ebeb7f..eaf0952af 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -43,10 +43,10 @@ VideoStream::MimeData VideoStream::mime_data[] = { void VideoStream::Initialise( ) { if ( logDebugging() ) - av_log_set_level( AV_LOG_DEBUG ); + av_log_set_level( AV_LOG_DEBUG ); else - av_log_set_level( AV_LOG_QUIET ); - + av_log_set_level( AV_LOG_QUIET ); + av_register_all( ); #if LIBAVFORMAT_VERSION_CHECK(53, 13, 0, 19, 0) avformat_network_init(); @@ -58,15 +58,15 @@ void VideoStream::SetupFormat( ) { /* allocate the output media context */ ofc = NULL; -#if LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) +#if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) avformat_alloc_output_context2( &ofc, NULL, format, filename ); #else AVFormatContext *s= avformat_alloc_context(); - if(!s) + if(!s) { Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) ); } - + AVOutputFormat *oformat; if (format) { #if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) @@ -186,7 +186,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei } else { -#if LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) +#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) ); #else Debug( 1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id ); @@ -202,14 +202,14 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei codec = avcodec_find_encoder( codec_id ); if ( !codec ) { -#if LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) +#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) ); #else Fatal( "Could not find encoder for '%d'", codec_id ); #endif } -#if LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) +#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Debug( 1, "Found encoder for '%s'", avcodec_get_name( codec_id ) ); #else Debug( 1, "Found encoder for '%d'", codec_id ); From 7811354d92631217ea97b6f639eb357df532e640 Mon Sep 17 00:00:00 2001 From: Emmanuel Papin Date: Fri, 29 May 2015 23:22:20 +0200 Subject: [PATCH 152/154] Move iostream inclusion in zm.h and declare explicitely the namespace for cout --- src/zm.h | 2 ++ src/zm_image_analyser.h | 1 - src/zma.cpp | 2 +- src/zmc.cpp | 2 +- src/zmf.cpp | 2 +- src/zmstreamer.cpp | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zm.h b/src/zm.h index be2882f8d..a60ab655d 100644 --- a/src/zm.h +++ b/src/zm.h @@ -33,6 +33,8 @@ #include +#include + extern const char* self; #endif // ZM_H diff --git a/src/zm_image_analyser.h b/src/zm_image_analyser.h index d1d0c1da0..74cc7a73a 100644 --- a/src/zm_image_analyser.h +++ b/src/zm_image_analyser.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "zm.h" diff --git a/src/zma.cpp b/src/zma.cpp index cb6ddb4e8..e45327cc1 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -70,7 +70,7 @@ int main( int argc, char *argv[] ) Usage(); break; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); diff --git a/src/zmc.cpp b/src/zmc.cpp index e97f0054f..5be5ed8af 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -115,7 +115,7 @@ int main( int argc, char *argv[] ) Usage(); break; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); diff --git a/src/zmf.cpp b/src/zmf.cpp index d97a9e5d5..94bd0bdb5 100644 --- a/src/zmf.cpp +++ b/src/zmf.cpp @@ -138,7 +138,7 @@ int main( int argc, char *argv[] ) Usage(); break; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); diff --git a/src/zmstreamer.cpp b/src/zmstreamer.cpp index 5c11cfbea..7385accca 100644 --- a/src/zmstreamer.cpp +++ b/src/zmstreamer.cpp @@ -102,7 +102,7 @@ int main(int argc, char** argv) { printf("-v : This installed version of ZoneMinder\n"); return EXIT_SUCCESS; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); } } From f99c5f36278d2b98bddd42959f1f0663accea2ff Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Jun 2015 12:09:38 -0400 Subject: [PATCH 153/154] use correct tag for the frame popup so that it gets the correct popup window size --- web/skins/classic/views/frames.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index 148457e49..5883286ca 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -61,7 +61,7 @@ if ( count($frames) ) $class = strtolower($frame['Type']); ?>
    - + From c8e41319e66b29f7f9f33b662b7e378767d53a96 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Jun 2015 12:22:12 -0400 Subject: [PATCH 154/154] fix state popup dimensions --- web/skins/classic/js/flat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/js/flat.js b/web/skins/classic/js/flat.js index f6ddf214d..4e43ce170 100644 --- a/web/skins/classic/js/flat.js +++ b/web/skins/classic/js/flat.js @@ -58,7 +58,7 @@ var popupSizes = { 'options': { 'width': 1000, 'height': 660 }, 'preset': { 'width': 300, 'height': 120 }, 'settings': { 'width': 220, 'height': 225 }, - 'state': { 'width': 370, 'height': 134 }, + 'state': { 'width': 400, 'height': 170 }, 'stats': { 'width': 840, 'height': 200 }, 'timeline': { 'width': 760, 'height': 540 }, 'user': { 'width': 360, 'height': 420 },
     /  / 
    '.$SLANG['Fn'.$monitor['Function']].( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?>'.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?> '.$monitor['Device'].' ('.$monitor['Channel'].')', canEdit( 'Monitors' ) ) ?>