Initial commit based on Aviary core
5
.gitignore
vendored
Executable file
@ -0,0 +1,5 @@
|
||||
*~
|
||||
autodocs/
|
||||
config/*.cfg
|
||||
.emacs.desktop
|
||||
.emacs.desktop.lock
|
47
.htaccess
Executable file
@ -0,0 +1,47 @@
|
||||
# Example .htaccess for apache webservers.
|
||||
|
||||
# Uncomment the following three lines if you want your webapp to force HTTPS
|
||||
# RewriteEngine On
|
||||
# RewriteCond %{HTTPS} off
|
||||
# RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
||||
|
||||
# Pass pathinfo and query string to the index script
|
||||
AcceptPathInfo on
|
||||
RewriteEngine On
|
||||
|
||||
# If the installation is in a subdirectory, add a rewritebase rule for the subdir
|
||||
# RewriteBase /subdir/
|
||||
RewriteBase /orb/
|
||||
|
||||
RewriteCond %{REQUEST_URI} !^/orb/(templates|media|docs|ckeditor|images|index.cgi)
|
||||
RewriteRule (.*) index.cgi/$1 [PT,L]
|
||||
|
||||
# Compress text, html, javascript, css, xml:
|
||||
AddOutputFilterByType DEFLATE text/plain
|
||||
AddOutputFilterByType DEFLATE text/html
|
||||
AddOutputFilterByType DEFLATE text/xml
|
||||
AddOutputFilterByType DEFLATE text/css
|
||||
AddOutputFilterByType DEFLATE application/xml
|
||||
AddOutputFilterByType DEFLATE application/xhtml+xml
|
||||
AddOutputFilterByType DEFLATE application/rss+xml
|
||||
AddOutputFilterByType DEFLATE application/javascript
|
||||
AddOutputFilterByType DEFLATE application/x-javascript
|
||||
|
||||
# For extra efficiency, make sure cache expiration times are set for content.
|
||||
# For example, add the following to the webapp's <VirtualHost>:
|
||||
#
|
||||
# ExpiresActive On
|
||||
# ExpiresDefault "access plus 300 seconds"
|
||||
#
|
||||
# And the followin on its <Directory>:
|
||||
#
|
||||
# ExpiresByType text/html "access plus 30 minutes"
|
||||
# ExpiresByType text/css "access plus 1 day"
|
||||
# ExpiresByType text/javascript "access plus 1 day"
|
||||
# ExpiresByType image/gif "access plus 1 month"
|
||||
# ExpiresByType image/jpeg "access plus 1 month"
|
||||
# ExpiresByType image/jpg "access plus 1 month"
|
||||
# ExpiresByType image/png "access plus 1 month"
|
||||
# ExpiresByType application/x-shockwave-flash "access plus 1 day"
|
||||
# ExpiresByType application/x-javascript "access plus 1 day"
|
||||
# ExpiresByType application/x-icon "access plus 1 day"
|
1
blocks/.htaccess
Executable file
@ -0,0 +1 @@
|
||||
Deny from all
|
1289
blocks/ORB/Login.pm
Executable file
122
blocks/ORB/Userbar.pm
Normal file
@ -0,0 +1,122 @@
|
||||
## @file
|
||||
# This file contains the implementation of the ORB user toolbar.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class ORB::Userbar
|
||||
# The Userbar class encapsulates the code required to generate and
|
||||
# manage the user toolbar.
|
||||
package ORB::Userbar;
|
||||
|
||||
use strict;
|
||||
use parent qw(ORB);
|
||||
use v5.12;
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Bar generation
|
||||
|
||||
## @method $ block_display($title, $current, $doclink)
|
||||
# Generate a user toolbar, populating it as needed to reflect the user's options
|
||||
# at the current time.
|
||||
#
|
||||
# @param title A string to show as the page title.
|
||||
# @param current The current page name.
|
||||
# @param doclink The name of a document link to include in the userbar. If not
|
||||
# supplied, no link is shown.
|
||||
# @return A string containing the user toolbar html on success, undef on error.
|
||||
sub block_display {
|
||||
my $self = shift;
|
||||
my $title = shift;
|
||||
my $current = shift;
|
||||
my $doclink = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $loginurl = $self -> build_url(block => "login",
|
||||
fullurl => 1,
|
||||
pathinfo => [],
|
||||
params => {},
|
||||
forcessl => 1);
|
||||
|
||||
my $fronturl = $self -> build_url(block => $self -> {"settings"} -> {"config"} -> {"default_block"},
|
||||
fullurl => 1,
|
||||
pathinfo => [],
|
||||
params => {});
|
||||
|
||||
# Initialise fragments to sane "logged out" defaults.
|
||||
my ($import, $userprofile, $docs) =
|
||||
($self -> {"template"} -> load_template("userbar/import_disabled.tem"),
|
||||
$self -> {"template"} -> load_template("userbar/profile_loggedout_http".($ENV{"HTTPS"} eq "on" ? "s" : "").".tem", {"***url-login***" => $loginurl}),
|
||||
$self -> {"template"} -> load_template("userbar/doclink_disabled.tem"),
|
||||
);
|
||||
|
||||
# Is documentation available?
|
||||
my $url = $self -> get_documentation_url($doclink);
|
||||
$docs = $self -> {"template"} -> load_template("userbar/doclink_enabled.tem", {"***url-doclink***" => $url})
|
||||
if($url);
|
||||
|
||||
# Is the user logged in?
|
||||
if(!$self -> {"session"} -> anonymous_session()) {
|
||||
my $user = $self -> {"session"} -> get_user_byid()
|
||||
or return $self -> self_error("Unable to obtain user data for logged in user. This should not happen!");
|
||||
|
||||
$import = $self -> {"template"} -> load_template("userbar/import_enabled.tem" , {"***url-import***" => $self -> build_url(block => "import", pathinfo => [])})
|
||||
if($self -> check_permission("import") && $current ne "import");
|
||||
|
||||
# User is logged in, so actually reflect their current options and state
|
||||
$userprofile = $self -> {"template"} -> load_template("userbar/profile_loggedin.tem", {"***realname***" => $user -> {"fullname"},
|
||||
"***username***" => $user -> {"username"},
|
||||
"***gravhash***" => $user -> {"gravatar_hash"},
|
||||
"***url-logout***" => $self -> build_url(block => "login" , pathinfo => ["logout"])});
|
||||
} # if(!$self -> {"session"} -> anonymous_session())
|
||||
|
||||
return $self -> {"template"} -> load_template("userbar/userbar.tem", {"***pagename***" => $title,
|
||||
"***front_url***" => $fronturl,
|
||||
"***import***" => $import,
|
||||
"***doclink***" => $docs,
|
||||
"***profile***" => $userprofile});
|
||||
}
|
||||
|
||||
|
||||
## @method $ page_display()
|
||||
# Produce the string containing this block's full page content. This is primarily provided for
|
||||
# API operations that allow the user to change their profile and settings.
|
||||
#
|
||||
# @return The string containing this block's page content.
|
||||
sub page_display {
|
||||
my $self = shift;
|
||||
my ($content, $extrahead, $title);
|
||||
|
||||
if(!$self -> {"session"} -> anonymous_session()) {
|
||||
my $user = $self -> {"session"} -> get_user_byid()
|
||||
or return '';
|
||||
|
||||
my $apiop = $self -> is_api_operation();
|
||||
if(defined($apiop)) {
|
||||
given($apiop) {
|
||||
default {
|
||||
return $self -> api_html_response($self -> api_errorhash('bad_op',
|
||||
$self -> {"template"} -> replace_langvar("API_BAD_OP")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "<p class=\"error\">".$self -> {"template"} -> replace_langvar("BLOCK_PAGE_DISPLAY")."</p>";
|
||||
}
|
||||
|
||||
1;
|
52
index.cgi
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/perl -w
|
||||
# Note: above -w flag should be removed in production, as it will cause warnings in
|
||||
# 3rd party modules to appear in the server error log
|
||||
|
||||
use utf8;
|
||||
use v5.12;
|
||||
use lib qw(/var/www/webperl);
|
||||
use FindBin;
|
||||
|
||||
# Work out where the script is, so module and config loading can work.
|
||||
my $scriptpath;
|
||||
BEGIN {
|
||||
if($FindBin::Bin =~ /(.*)/) {
|
||||
$scriptpath = $1;
|
||||
}
|
||||
}
|
||||
|
||||
use CGI::Carp qw(fatalsToBrowser set_message); # Catch as many fatals as possible and send them to the user as well as stderr
|
||||
|
||||
use lib "$scriptpath/modules";
|
||||
|
||||
my $contact = 'contact@email.address'; # global contact address, for error messages
|
||||
|
||||
# System modules
|
||||
use CGI::Carp qw(fatalsToBrowser set_message); # Catch as many fatals as possible and send them to the user as well as stderr
|
||||
|
||||
# Webperl modules
|
||||
use Webperl::Application;
|
||||
|
||||
# Webapp modules
|
||||
use ORB::AppUser;
|
||||
use ORB::BlockSelector;
|
||||
use ORB::System;
|
||||
|
||||
delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)}; # Clean up ENV
|
||||
|
||||
# install more useful error handling
|
||||
sub handle_errors {
|
||||
my $msg = shift;
|
||||
print "<h1>Software error</h1>\n";
|
||||
print '<p>Server time: ',scalar(localtime()),'<br/>Error was:</p><pre>',$msg,'</pre>';
|
||||
print '<p>Please report this error to ',$contact,' giving the text of this error and the time and date at which it occured</p>';
|
||||
}
|
||||
set_message(\&handle_errors);
|
||||
|
||||
do {
|
||||
my $app = Webperl::Application -> new(appuser => ORB::AppUser -> new(),
|
||||
system => ORB::System -> new(),
|
||||
block_selector => ORB::BlockSelector -> new())
|
||||
or die "Unable to create application";
|
||||
$app -> run();
|
||||
}
|
1
lang/en/aviary.lang
Executable file
@ -0,0 +1 @@
|
||||
AVIARY_TITLE = Aviary
|
10
lang/en/calendar.lang
Normal file
@ -0,0 +1,10 @@
|
||||
CALENDAR_TITLE = Tweet Schedule
|
||||
CALENDAR_ADDTWEET = + Add tweet
|
||||
|
||||
CALENDAR_DAY1 = Monday
|
||||
CALENDAR_DAY2 = Tuesday
|
||||
CALENDAR_DAY3 = Wednesday
|
||||
CALENDAR_DAY4 = Thursday
|
||||
CALENDAR_DAY5 = Friday
|
||||
CALENDAR_DAY6 = Saturday
|
||||
CALENDAR_DAY7 = Sunday
|
5
lang/en/debug.lang
Executable file
@ -0,0 +1,5 @@
|
||||
DEBUG_TIMEUSED = Execution time
|
||||
DEBUG_SECONDS = seconds
|
||||
DEBUG_USER = User time
|
||||
DEBUG_SYSTEM = System time
|
||||
DEBUG_MEMORY = Memory used
|
55
lang/en/global.lang
Executable file
@ -0,0 +1,55 @@
|
||||
EMAIL_SIG = The {V_[sitename]} Team
|
||||
|
||||
SITE_CONTINUE = Continue
|
||||
|
||||
API_BAD_OP = Unknown API operation requested.
|
||||
API_BAD_CALL = Incorrect invocation of an API-only module.
|
||||
API_ERROR = An API error has occurred: ***error***
|
||||
|
||||
API_SESSION_GONE = Your session appears to have timed out.<br /><br /><a href="***login_url***">Click here to log in again</a>
|
||||
|
||||
# Times for Template::fancy_time
|
||||
TIMES_JUSTNOW = just now
|
||||
TIMES_SECONDS = %t seconds ago
|
||||
TIMES_MINUTE = a minute ago
|
||||
TIMES_MINUTES = %t minutes ago
|
||||
TIMES_HOUR = an hour ago
|
||||
TIMES_HOURS = %t hours ago
|
||||
TIMES_DAY = a day ago
|
||||
TIMES_DAYS = %t days ago
|
||||
TIMES_WEEK = a week ago
|
||||
TIMES_WEEKS = %t weeks ago
|
||||
TIMES_MONTH = a month ago
|
||||
TIMES_MONTHS = %t months ago
|
||||
TIMES_YEAR = a year ago
|
||||
TIMES_YEARS = %t years ago
|
||||
|
||||
FUTURE_JUSTNOW = shortly
|
||||
FUTURE_SECONDS = in %t seconds
|
||||
FUTURE_MINUTE = in a minute
|
||||
FUTURE_MINUTES = in %t minutes
|
||||
FUTURE_HOUR = in an hour
|
||||
FUTURE_HOURS = in %t hours
|
||||
FUTURE_DAY = in a day
|
||||
FUTURE_DAYS = in %t days
|
||||
FUTURE_WEEK = in a week
|
||||
FUTURE_WEEKS = in %t weeks
|
||||
FUTURE_MONTH = in a month
|
||||
FUTURE_MONTHS = in %t months
|
||||
FUTURE_YEAR = in a year
|
||||
FUTURE_YEARS = in %t years
|
||||
|
||||
BLOCK_BLOCK_DISPLAY = Direct call to unimplemented block_display()
|
||||
BLOCK_SECTION_DISPLAY = Direct call to unimplemented section_display()
|
||||
|
||||
PAGE_ERROR = Error
|
||||
PAGE_ERROROK = Okay
|
||||
|
||||
FATAL_ERROR = Fatal Error
|
||||
FATAL_ERROR_SUMMARY = The system has encountered a fatal error and can not continue. The error is shown below.
|
||||
|
||||
CANCEL_OPTION = Cancel
|
||||
CLOSE_OPTION = Close
|
||||
|
||||
PAGE_POPUP = Error
|
||||
PAGE_FOOTER =
|
13
lang/en/import.lang
Normal file
@ -0,0 +1,13 @@
|
||||
IMPORT_TITLE = Import Schedule
|
||||
|
||||
IMPORT_INTRO = Use this form to import an Excel workbook (.xls format only, <em>not</em> .xlsx) into your schedule. Any previously imported scheduled messages that have not yet been posted will be removed as part of the import process.
|
||||
IMPORT_EXCELFILE = Excel workbook file
|
||||
IMPORT_SUBMIT = Import
|
||||
|
||||
IMPORT_SUCCESS = Import completed successfully
|
||||
IMPORT_SUMMARY = Import completed successfully
|
||||
IMPORT_LONGDESC = <p>The schedule in the uploaded spreadsheet has been imported successfully. ***removed*** unposted scheduled messages were removed, and ***added*** messages were added.<p>
|
||||
|
||||
IMPORT_ERR_NOFILESET = No excel file selected, unable to import anything.
|
||||
IMPORT_ERR_BADHANDLE = An internal file handle problem was encoutered. Please try again.
|
||||
IMPORT_ERR_BADPARSER = Unable to create a spreadsheet parser object.
|
175
lang/en/login.lang
Executable file
@ -0,0 +1,175 @@
|
||||
LOGIN_TITLE = Log in
|
||||
LOGIN_LOGINFORM = Log in
|
||||
LOGIN_INTRO = Enter your username and password to log in.
|
||||
LOGIN_USERNAME = Username
|
||||
LOGIN_PASSWORD = Password
|
||||
LOGIN_EMAIL = Email address
|
||||
LOGIN_PERSIST = Remember me
|
||||
LOGIN_LOGIN = Log in
|
||||
LOGIN_FAILED = Login failed
|
||||
LOGIN_RECOVER = Forgotten your username or password?
|
||||
LOGIN_SENDACT = Click to resend your activation code
|
||||
|
||||
PERSIST_WARNING = <strong>WARNING</strong>: do not enable the "Remember me" option on shared, cluster, or public computers. This option should only be enabled on machines you have exclusive access to.
|
||||
|
||||
LOGIN_DONETITLE = Logged in
|
||||
LOGIN_SUMMARY = You have successfully logged into the system.
|
||||
LOGIN_LONGDESC = You have successfully logged in, and you will be redirected shortly. If you do not want to wait, click continue. Alternatively, <a href="{V_[scriptpath]}">Click here</a> to return to the front page.
|
||||
LOGIN_NOREDIRECT = You have successfully logged in, but warnings were encountered during login. Please check the warning messages, and <a href="mailto:***supportaddr***">contact support</a> if a serious problem has been encountered, otherwise, click continue. Alternatively, <a href="{V_[scriptpath]}">Click here</a> to return to the front page.
|
||||
|
||||
LOGOUT_TITLE = Logged out
|
||||
LOGOUT_SUMMARY = You have successfully logged out.
|
||||
LOGOUT_LONGDESC = You have successfully logged out, and you will be redirected shortly. If you do not want to wait, click continue. Alternatively, <a href="{V_[scriptpath]}">Click here</a> to return to the front page.
|
||||
|
||||
LOGIN_ERR_BADUSERCHAR = Illegal character in username. Usernames may only contain alphanumeric characters, underscores, or hyphens.
|
||||
LOGIN_ERR_INVALID = Login failed: unknown username or password provided.
|
||||
|
||||
# Registration-related stuff
|
||||
LOGIN_REGISTER = Sign up
|
||||
LOGIN_REG_INTRO = Create an account by choosing a username and giving a valid email address. A password will be emailed to you.
|
||||
LOGIN_SECURITY = Security question
|
||||
LOGIN_SEC_INTRO = In order to prevent abuse by automated spamming systems, please answer the following question to prove that you are a human.<br/>Note: the answer is not case sensitive.
|
||||
LOGIN_SEC_SUBMIT = Sign up
|
||||
|
||||
LOGIN_ERR_NOSELFREG = Self-registration is not currently permitted.
|
||||
LOGIN_ERR_REGFAILED = Registration failed
|
||||
LOGIN_ERR_BADSECURE = You did not answer the security question correctly, please check your answer and try again.
|
||||
LOGIN_ERR_BADEMAIL = The specified email address does not appear to be valid.
|
||||
LOGIN_ERR_USERINUSE = The specified username is already in use. If you can't remember your password, <strong>please use the <a href="***url-recover***">account recovery</a> facility</strong> rather than attempt to make a new account.
|
||||
LOGIN_ERR_EMAILINUSE = The specified email address is already in use. If you can't remember your username or password, <strong>please use the <a href="***url-recover***">account recovery</a> facility</strong> rather than attempt to make a new account.
|
||||
LOGIN_ERR_INACTIVE = Your account is currently inactive. Please check your email for an 'Activation Required' email and follow the link it contains to activate your account. If you have not received an actication email, or need a new one, <a href="***url-resend***">request a new activation email</a>.
|
||||
|
||||
# Registration done
|
||||
LOGIN_REG_DONETITLE = Registration successful
|
||||
LOGIN_REG_SUMMARY = Activation required!
|
||||
LOGIN_REG_LONGDESC = A new user account has been created for you, and an email has been sent to you with your new account password and an activation link.<br /><br />Please check your email for a message with the subject '{V_[sitename]} account created - Activation required!' and follow the instructions it contains to activate your account.
|
||||
|
||||
# Registration email
|
||||
LOGIN_REG_SUBJECT = {V_[sitename]} account created - Activation required!
|
||||
LOGIN_REG_GREETING = Hi ***username***
|
||||
LOGIN_REG_CREATED = A new account in the {V_[sitename]} system has just been created for you. Your username and password for the system are given below.
|
||||
LOGIN_REG_ACTNEEDED = Before you can log in, you must activate your account. To activate your account, please click on the following link, or copy and paste it into your web browser:
|
||||
LOGIN_REG_ALTACT = Alternatively, enter the following code in the account activation form:
|
||||
LOGIN_REG_ENJOY = Thank you for registering!
|
||||
|
||||
# Activation related
|
||||
LOGIN_ACTCODE = Activation code
|
||||
LOGIN_ACTFAILED = User account activation failed
|
||||
LOGIN_ACTFORM = Activate account
|
||||
LOGIN_ACTINTRO = Please enter your 64 character activation code here.
|
||||
LOGIN_ACTIVATE = Activate account
|
||||
LOGIN_ERR_BADACTCHAR = Activation codes may only contain alphanumeric characters.
|
||||
LOGIN_ERR_BADCODE = The provided activation code is invalid: either your account is already active, or you entered the code incorrectly. Note that the code is case sensitive - upper and lower case characters are treated differently. Please check you entered the code correctly.
|
||||
|
||||
# Activation done
|
||||
LOGIN_ACT_DONETITLE = Account activated
|
||||
LOGIN_ACT_SUMMARY = Activation successful!
|
||||
LOGIN_ACT_LONGDESC = Your new account has been acivated, and you can now <a href="***url-login***">log in</a> using your username and the password emailed to you.
|
||||
|
||||
# Recovery related
|
||||
LOGIN_RECFORM = Recover account details
|
||||
LOGIN_RECINTRO = If you have forgotten your username or password, enter the email address associated with your account in the field below. An email will be sent to you containing your username, and a link to click on to reset your password. If you do not have access to the email address associated with your account, please contact the site owner.
|
||||
LOGIN_RECEMAIL = Email address
|
||||
LOGIN_DORECOVER = Recover account
|
||||
LOGIN_RECOVER_SUBJECT = Your {V_[sitename]} account
|
||||
LOGIN_RECOVER_GREET = Hi ***username***
|
||||
LOGIN_RECOVER_INTRO = You, or someone pretending to be you, has requested that your password be reset. In order to reset your account, please click on the following link, or copy and paste it into your web browser.
|
||||
LOGIN_RECOVER_IGNORE = If you did not request this reset, please either ignore this email or report it to the {V_[sitename]} administrator.
|
||||
LOGIN_RECOVER_FAILED = Account recovery failed
|
||||
LOGIN_RECOVER_DONETITLE = Account recovery code sent
|
||||
LOGIN_RECOVER_SUMMARY = Recovery code sent!
|
||||
LOGIN_RECOVER_LONGDESC = An account recovery code has been send to your email address.<br /><br />Please check your email for a message with the subject 'Your {V_[sitename]} account' and follow the instructions it contains.
|
||||
LOGIN_ERR_NOUID = No user id specified.
|
||||
LOGIN_ERR_BADUID = The specfied user id is not valid.
|
||||
LOGIN_ERR_BADRECCHAR = Account reset codes may only contain alphanumeric characters.
|
||||
LOGIN_ERR_BADRECCODE = The provided account reset code is invalid. Note that the code is case sensitive - upper and lower case characters are treated differently. Please check you entered the code correctly.
|
||||
LOGIN_ERR_NORECINACT = Your account is inactive, and therefore can not be recovered. In order to access your account, please request a new activation code and password.
|
||||
|
||||
LOGIN_RESET_SUBJECT = Your {V_[sitename]} account
|
||||
LOGIN_RESET_GREET = Hi ***username***
|
||||
LOGIN_RESET_INTRO = Your password has been reset, and your username and new password are given below:
|
||||
LOGIN_RESET_LOGIN = To log into the {V_[sitename]}, please go to the following form and enter the username and password above. Once you have logged in, please change your password.
|
||||
|
||||
LOGIN_RESET_DONETITLE = Account reset complete
|
||||
LOGIN_RESET_SUMMARY = Password reset successfully
|
||||
LOGIN_RESET_LONGDESC = Your username and a new password have been sent to your email address. Please look for an email with the subject 'Your {V_[sitename]} account', you can use the account information it contains to log into the system by clicking the 'Log in' button below.
|
||||
LOGIN_RESET_ERRTITLE = Account reset failed
|
||||
LOGIN_RESET_ERRSUMMARY = Password reset failed
|
||||
LOGIN_RESET_ERRDESC = The system has been unable to reset your account. The error encountered was:<br /><br/>***reason***
|
||||
|
||||
# Activation resend
|
||||
LOGIN_RESENDFORM = Resend activation code
|
||||
LOGIN_RESENDINTRO = If you have accidentally deleted your activation email, or you have not received an an activation email more than 30 minutes after creating an account, enter your account email address below to be sent your activation code again.<br /><br/><strong>IMPORTANT</strong>: requesting a new copy of your activation code will also reset your password. If you later receive the original registration email, the code and password it contains will not work and should be ignored.
|
||||
LOGIN_RESENDEMAIL = Email address
|
||||
LOGIN_DORESEND = Resend code
|
||||
LOGIN_ERR_BADUSER = The email address provided does not appear to belong to any account in the system.
|
||||
LOGIN_ERR_BADAUTH = The user account with the provided email address does not have a valid authentication method associated with it. This should not happen!
|
||||
LOGIN_ERR_ALREADYACT = The user account with the provided email address is already active, and does not need a code to be activated.
|
||||
LOGIN_RESEND_SUBJECT = Your {V_[sitename]} activation code
|
||||
LOGIN_RESEND_GREET = Hi ***username***
|
||||
LOGIN_RESEND_INTRO = You, or someone pretending to be you, has requested that another copy of your activation code be sent to your email address.
|
||||
LOGIN_RESEND_ALTACT = Alternatively, enter the following code in the account activation form:
|
||||
LOGIN_RESEND_ENJOY = Thank you for registering!
|
||||
LOGIN_RESEND_FAILED = Activation code resend failed
|
||||
|
||||
LOGIN_RESEND_DONETITLE = Activation code resent
|
||||
LOGIN_RESEND_SUMMARY = Resend successful!
|
||||
LOGIN_RESEND_LONGDESC = A new password and an activation link have been send to your email address.<br /><br />Please check your email for a message with the subject 'Your {V_[sitename]} activation code' and follow the instructions it contains to activate your account.
|
||||
# Force password change
|
||||
LOGIN_PASSCHANGE = Change password
|
||||
LOGIN_FORCECHANGE_INTRO = Before you continue, please choose a new password to set for your account.
|
||||
LOGIN_FORCECHANGE_TEMP = Your account is currently set up with a temporary password.
|
||||
LOGIN_FORCECHANGE_OLD = The password on your account has expired as a result of age limits enforced by the site's password policy.
|
||||
LOGIN_NEWPASSWORD = New password
|
||||
LOGIN_CONFPASS = Confirm password
|
||||
LOGIN_OLDPASS = Your current password
|
||||
LOGIN_SETPASS = Change password
|
||||
LOGIN_PASSCHANGE_FAILED = Password change failed
|
||||
|
||||
LOGIN_PASSCHANGE_ERRNOUSER = No logged in user detected, password change unsupported.
|
||||
LOGIN_PASSCHANGE_ERRMATCH = The new password specified does not match the confirm password.
|
||||
LOGIN_PASSCHANGE_ERRSAME = The new password can not be the same as the old password.
|
||||
LOGIN_PASSCHANGE_ERRVALID = The specified old password is not correct. You must enter the password you used to log in.
|
||||
|
||||
|
||||
LOGIN_POLICY = Password policy
|
||||
LOGIN_POLICY_INTRO = When choosing a new password, keep in mind that:
|
||||
LOGIN_POLICY_NONE = No password policy is currently in place, you may use any password you want.
|
||||
LOGIN_POLICY_MIN_LENGTH = Minimum length is ***value*** characters.
|
||||
LOGIN_POLICY_MIN_LOWERCASE = At least ***value*** lowercase letters are needed.
|
||||
LOGIN_POLICY_MIN_UPPERCASE = At least ***value*** uppercase letters are needed.
|
||||
LOGIN_POLICY_MIN_DIGITS = At least ***value*** numbers must be included.
|
||||
LOGIN_POLICY_MIN_OTHER = ***value*** non-alphanumeric chars are needed.
|
||||
LOGIN_POLICY_MIN_ENTROPY = Passwords must pass a strength check.
|
||||
LOGIN_POLICY_USE_CRACKLIB = Cracklib is used to test passwords.
|
||||
|
||||
LOGIN_POLICY_MIN_LENGTHERR = Password is only ***set*** characters, minimum is ***require***.
|
||||
LOGIN_POLICY_MIN_LOWERCASEERR = Only ***set*** of ***require*** lowercase letters provided.
|
||||
LOGIN_POLICY_MIN_UPPERCASEERR = Only ***set*** of ***require*** uppercase letters provided.
|
||||
LOGIN_POLICY_MIN_DIGITSERRR = Only ***set*** of ***require*** digits included.
|
||||
LOGIN_POLICY_MIN_OTHERERR = Only ***set*** of ***require*** non-alphanumeric chars included.
|
||||
LOGIN_POLICY_MIN_ENTROPYERR = The supplied password is not strong enough.
|
||||
LOGIN_POLICY_USE_CRACKLIBERR = ***set***
|
||||
|
||||
LOGIN_POLICY_MAX_PASSWORDAGE = Passwords must be changed after ***value*** days.
|
||||
LOGIN_POLICY_MAX_LOGINFAIL = You can log in incorrectly ***value*** times before your account needs reactivation.
|
||||
|
||||
LOGIN_CRACKLIB_WAYSHORT = The password is far too short.
|
||||
LOGIN_CRACKLIB_TOOSHORT = The password is too short.
|
||||
LOGIN_CRACKLIB_MORECHARS = A greater range of characters are needed in the password.
|
||||
LOGIN_CRACKLIB_WHITESPACE = Passwords can not be entirely whitespace!
|
||||
LOGIN_CRACKLIB_SIMPLISTIC = The password is too simplistic or systematic.
|
||||
LOGIN_CRACKLIB_NINUMBER = You can not use a NI number as a password.
|
||||
LOGIN_CRACKLIB_DICTWORD = The password is based on a dictionary word.
|
||||
LOGIN_CRACKLIB_DICTBACK = The password is based on a reversed dictionary word.
|
||||
|
||||
# Login limiting
|
||||
LOGIN_FAILLIMIT = You have used ***failcount*** of ***faillimit*** login attempts. If you exceed the limit, your account will be deactivated. If you can not remember your account details, please use the <a href="***url-recover***">account recovery form</a>
|
||||
LOGIN_LOCKEDOUT = You have exceeded the number of login failures permitted by the system, and your account has been deactivated. An email has been sent to the address associated with your account explaining how to reactivate your account.
|
||||
LOGIN_LOCKOUT_SUBJECT = {V_[sitename]} account locked
|
||||
LOGIN_LOCKOUT_GREETING = Hi
|
||||
LOGIN_LOCKOUT_MESSAGE = Your '{V_[sitename]}' account has deactivated and your password has been changed because more than ***faillimit*** login failures have been recorded for your account. This may be the result of attempted unauthorised access to your account - if you are not responsible for these login attempts you should probably contact the site administator to report that your account may be under attack. Your username and new password for the site are:
|
||||
LOGIN_LOCKOUT_ACTNEEDED = As your account has been deactivated, before you can successfully log in you will need to reactivate your account. To do this, please click on the following link, or copy and paste it into your web browser:
|
||||
LOGIN_LOCKOUT_ALTACT = Alternatively, enter the following code in the account activation form:
|
||||
|
||||
#
|
6
lang/en/navigation.lang
Executable file
@ -0,0 +1,6 @@
|
||||
NAVBOX_PAGEOF = Page ***pagenum*** of ***maxpage***
|
||||
NAVBOX_FIRST = First
|
||||
NAVBOX_PREV = Newer
|
||||
NAVBOX_NEXT = Older
|
||||
NAVBOX_LAST = Last
|
||||
NAVBOX_SPACER =
|
4
lang/en/permission.lang
Executable file
@ -0,0 +1,4 @@
|
||||
PERMISSION_FAILED_TITLE = Access denied
|
||||
PERMISSION_FAILED_SUMMARY = You do not have permission to perform this operation.
|
||||
|
||||
PERMISSION_VIEW_DESC = You do not have permission to view the requested resource. If you think this is incorrect, please contact <a href="mailto:{V_[admin_email]}">{V_[admin_email]}</a> for assistance.
|
14
lang/en/userbar.lang
Normal file
@ -0,0 +1,14 @@
|
||||
USERBAR_PROFILE_EDIT = Edit Profile
|
||||
USERBAR_PROFILE_PREFS = Change Settings
|
||||
USERBAR_PROFILE_LOGOUT = Log out
|
||||
USERBAR_PROFILE_LOGIN = Log in
|
||||
|
||||
USERBAR_LOGIN_USER = Username
|
||||
USERBAR_LOGIN_PASS = Password
|
||||
USERBAR_LOGIN = Log in
|
||||
|
||||
USERBAR_DOCLINK = Documentation (opens in new window)
|
||||
|
||||
USERBAR_FRONT = Aviary front page
|
||||
|
||||
USERBAR_IMPORT = Import schedule
|
18
lang/en/validate.lang
Executable file
@ -0,0 +1,18 @@
|
||||
BLOCK_VALIDATE_NOTSET = No value provided for '***field***', this field is required.
|
||||
BLOCK_VALIDATE_TOOSHORT = The value provided for '***field***' is too short. ***minlen*** or more characters must be provided for this field.
|
||||
BLOCK_VALIDATE_TOOLONG = The value provided for '***field***' is too long. No more than ***maxlen*** characters can be provided for this field.
|
||||
BLOCK_VALIDATE_BADCHARS = The value provided for '***field***' contains illegal characters. ***desc***
|
||||
BLOCK_VALIDATE_BADFORMAT = The value provided for '***field***' is not valid. ***desc***
|
||||
BLOCK_VALIDATE_DBERR = Unable to look up the value for '***field***' in the database. Error was: ***dberr***.
|
||||
BLOCK_VALIDATE_BADOPT = The value selected for '***field***' is not a valid option.
|
||||
BLOCK_VALIDATE_SCRUBFAIL = No content was left after cleaning the contents of html field '***field***'.
|
||||
BLOCK_VALIDATE_TIDYFAIL = htmltidy failed for field '***field***'.
|
||||
BLOCK_VALIDATE_CHKERRS = ***error*** html errors where encountered while validating '***field***'. Clean up the html and try again.
|
||||
BLOCK_VALIDATE_CHKFAIL = Validation of '***field***' failed. Error from the W3C validator was: ***error***.
|
||||
BLOCK_VALIDATE_NOTNUMBER = The value provided for '***field***' is not a valid number.
|
||||
BLOCK_VALIDATE_RANGEMIN = The value provided for '***field***' is out of range (minimum is ***min***)
|
||||
BLOCK_VALIDATE_RANGEMAX = The value provided for '***field***' is out of range (maximum is ***max***)
|
||||
|
||||
BLOCK_ERROR_TITLE = Fatal System Error
|
||||
BLOCK_ERROR_SUMMARY = The system has encountered an unrecoverable error.
|
||||
BLOCK_ERROR_TEXT = A serious error has been encountered while processing your request. The following information was generated by the system, please contact moodlesupport@cs.man.ac.uk about this, including this error and a description of what you were doing when it happened!<br /><br /><span class="error">***error***</span>
|
7
makedocs.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get the latest tag annotation out of git.
|
||||
VERS=`git tag -n1 | sort -V | tail -n1 | perl -e '$tag = <STDIN>; $tag =~ s/^.*?\s\s+(.*)$/$1/; print $tag;'`
|
||||
|
||||
# Generate the documentation with the project number updated with the tag.
|
||||
(cat supportfiles/Doxyfile; echo "PROJECT_NUMBER = \"$VERS\"") | doxygen -
|
1
modules/.htaccess
Executable file
@ -0,0 +1 @@
|
||||
Deny from all
|
773
modules/ORB.pm
Executable file
@ -0,0 +1,773 @@
|
||||
## @file
|
||||
# This file contains the implementation of the ORB block base class.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
#
|
||||
package ORB;
|
||||
|
||||
use strict;
|
||||
use experimental qw(smartmatch);
|
||||
use v5.14;
|
||||
|
||||
use parent qw(Webperl::Block); # Features are just a specific form of Block
|
||||
use CGI::Util qw(escape);
|
||||
use HTML::Entities;
|
||||
use Webperl::Utils qw(join_complex path_join);
|
||||
use XML::Simple;
|
||||
use DateTime;
|
||||
use JSON;
|
||||
|
||||
# Hack the DateTime object to include the TO_JSON function needed to support
|
||||
# JSON output of datetime objects. Outputs as ISO8601
|
||||
sub DateTime::TO_JSON {
|
||||
my $dt = shift;
|
||||
|
||||
return $dt -> format_cldr('yyyy-MM-ddTHH:mm:ssZZZZZ');
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Constructor
|
||||
|
||||
## @cmethod $ new(%args)
|
||||
# Overloaded constructor for ORB block modules. This will ensure that a valid
|
||||
# item id has been stored in the block object data.
|
||||
#
|
||||
# @param args A hash of values to initialise the object with. See the Block docs
|
||||
# for more information.
|
||||
# @return A reference to a new ORB object on success, undef on error.
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = $class -> SUPER::new(entitymap => { '–' => '-',
|
||||
'—' => '-',
|
||||
'’' => "'",
|
||||
'‘' => "'",
|
||||
'“' => '"',
|
||||
'”' => '"',
|
||||
'…' => '...',
|
||||
'>' => '>',
|
||||
'<' => '<',
|
||||
'&' => '&',
|
||||
' ' => ' ',
|
||||
},
|
||||
api_auth_header => 'Private-Token',
|
||||
api_auth_keylen => 24,
|
||||
@_)
|
||||
or return undef;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# HTML generation support
|
||||
|
||||
## @method $ generate_cadence_page($title, $content, $extrahead, $doclink)
|
||||
# A convenience function to wrap page content in the standard page template. This
|
||||
# function allows blocks to embed their content in a page without having to build
|
||||
# the whole page including "common" items themselves. It should be called to wrap
|
||||
# the content when the block's page_display is returning.
|
||||
#
|
||||
# @param title The page title.
|
||||
# @param content The content to show in the page.
|
||||
# @param extrahead Any extra directives to place in the header.
|
||||
# @param doclink The name of a document link to include in the userbar. If not
|
||||
# supplied, no link is shown.
|
||||
# @return A string containing the page.
|
||||
sub generate_cadence_page {
|
||||
my $self = shift;
|
||||
my $title = shift;
|
||||
my $content = shift;
|
||||
my $extrahead = shift;
|
||||
my $doclink = shift;
|
||||
|
||||
my $userbar = $self -> {"module"} -> load_module("ORB::Userbar");
|
||||
|
||||
return $self -> {"template"} -> load_template("page.tem", {"%(extrahead)s" => $extrahead || "",
|
||||
"%(title)s" => $title || "",
|
||||
"%(userbar)s" => ($userbar ? $userbar -> block_display($title, $self -> {"block"}, $doclink) : "<!-- Userbar load failed: ".$self -> {"module"} -> errstr()." -->"),
|
||||
"%(content)s" => $content});
|
||||
}
|
||||
|
||||
|
||||
## @method $ generate_errorbox($message, $title)
|
||||
# Generate the HTML to show in the page when a fatal error has been encountered.
|
||||
#
|
||||
# @param message The message to show in the page.
|
||||
# @param title The title to use for the error. If not set "{L_FATAL_ERROR}" is used.
|
||||
# @return A string containing the page
|
||||
sub generate_errorbox {
|
||||
my $self = shift;
|
||||
my $message = shift;
|
||||
my $title = shift || "{L_FATAL_ERROR}";
|
||||
|
||||
$self -> log("error:fatal", $message);
|
||||
|
||||
$message = $self -> {"template"} -> message_box($title,
|
||||
"error",
|
||||
"{L_FATAL_ERROR_SUMMARY}",
|
||||
$message,
|
||||
undef,
|
||||
"errorcore",
|
||||
[ {"message" => $self -> {"template"} -> replace_langvar("SITE_CONTINUE"),
|
||||
"colour" => "blue",
|
||||
"action" => "location.href='{V_[scriptpath]}'"} ]);
|
||||
my $userbar = $self -> {"module"} -> load_module("ORB::Userbar");
|
||||
|
||||
# Build the error page...
|
||||
return $self -> {"template"} -> load_template("error/general.tem",
|
||||
{"%(title)s" => $title,
|
||||
"%(message)s" => $message,
|
||||
"%(extrahead)s" => "",
|
||||
"%(userbar)s" => ($userbar ? $userbar -> block_display($title) : "<!-- Userbar load failed: ".$self -> {"module"} -> errstr()." -->"),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
## @method $ generate_multiselect($name, $class, $idbase, $options, $selected)
|
||||
# Generate a MultiSelect dropdown list (essentially a list of checkboxes that gets
|
||||
# converted to a dropdown using the MultiSelect javascript module).
|
||||
#
|
||||
# @param name The name of the multiselect option list.
|
||||
# @param class A class to add to the class attribute for the checkboxes in the list.
|
||||
# @param idbase A unique base name for the ID of checkboxes in the list.
|
||||
# @param options A reference to an array of option hashes. Each hash should contain
|
||||
# `name` a short name used in the class, `id` a numeric ID used in the
|
||||
# id and value attributes, and `desc` used in the label.
|
||||
# @param selected A reference to a list of selected option IDs.
|
||||
# @return A string containing the multiselect list checkboxes.
|
||||
sub generate_multiselect {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $class = shift;
|
||||
my $idbase = shift;
|
||||
my $options = shift;
|
||||
my $selected = shift;
|
||||
|
||||
# Convert the selected list to a hash for faster lookup
|
||||
my %active = map { $_ => 1} @{$selected};
|
||||
|
||||
my $result = "";
|
||||
foreach my $option (@{$options}) {
|
||||
$result .= $self -> {"template"} -> load_template("multisel-item.tem", {"%(class)s" => $class,
|
||||
"%(idbase)s" => $idbase,
|
||||
"%(selname)s" => $name,
|
||||
"%(name)s" => $option -> {"name"},
|
||||
"%(id)s" => $option -> {"id"},
|
||||
"%(desc)s" => $option -> {"desc"},
|
||||
"%(checked)s" => $active{$option -> {"id"}} ? 'checked="checked"' : ''});
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Permissions/Roles related.
|
||||
|
||||
## @method $ check_permission($action, $contextid, $userid)
|
||||
# Determine whether the user has permission to peform the requested action. This
|
||||
# should be overridden in subclasses to provide actual checks.
|
||||
#
|
||||
# @param action The action the user is attempting to perform.
|
||||
# @param contextid The ID of the metadata context the user is trying to perform
|
||||
# an action in. If this is not given, the root context is used.
|
||||
# @param userid The ID of the user to check the permissions for. If not
|
||||
# specified, the current session user is used.
|
||||
# @return true if the user has permission, false if they do not, undef on error.
|
||||
sub check_permission {
|
||||
my $self = shift;
|
||||
my $action = shift;
|
||||
my $contextid = shift || $self -> {"system"} -> {"roles"} -> {"root_context"};
|
||||
my $userid = shift || $self -> {"session"} -> get_session_userid();
|
||||
|
||||
return $self -> {"system"} -> {"roles"} -> user_has_capability($contextid, $userid, $action);
|
||||
}
|
||||
|
||||
|
||||
## @method $ check_login()
|
||||
# Determine whether the current user is logged in, and if not force them to
|
||||
# the login form.
|
||||
#
|
||||
# @return undef if the user is logged in and has access, otherwise a page to
|
||||
# send back with a permission error. If the user is not logged in, this
|
||||
# will 'silently' redirect the user to the login form.
|
||||
sub check_login {
|
||||
my $self = shift;
|
||||
|
||||
# Anonymous users need to get punted over to the login form
|
||||
if($self -> {"session"} -> anonymous_session()) {
|
||||
$self -> log("error:anonymous", "Redirecting anonymous user to login form");
|
||||
|
||||
print $self -> {"cgi"} -> redirect($self -> build_login_url());
|
||||
exit;
|
||||
|
||||
# Otherwise, permissions need to be checked
|
||||
} elsif(!$self -> check_permission("view")) {
|
||||
$self -> log("error:permission", "User does not have perission 'view'");
|
||||
|
||||
# Logged in, but permission failed
|
||||
my $message = $self -> {"template"} -> message_box("{L_PERMISSION_FAILED_TITLE}",
|
||||
"error",
|
||||
"{L_PERMISSION_FAILED_SUMMARY}",
|
||||
"{L_PERMISSION_VIEW_DESC}",
|
||||
undef,
|
||||
"errorcore",
|
||||
[ {"message" => $self -> {"template"} -> replace_langvar("SITE_CONTINUE"),
|
||||
"colour" => "blue",
|
||||
"action" => "location.href='{V_[scriptpath]}'"} ]);
|
||||
my $userbar = $self -> {"module"} -> load_module("ORB::Userbar");
|
||||
|
||||
# Build the error page...
|
||||
return $self -> {"template"} -> load_template("error/general.tem",
|
||||
{"%(title)s" => "{L_PERMISSION_FAILED_TITLE}",
|
||||
"%(message)s" => $message,
|
||||
"%(extrahead)s" => "",
|
||||
"%(userbar)s" => ($userbar ? $userbar -> block_display("{L_PERMISSION_FAILED_TITLE}") : "<!-- Userbar load failed: ".$self -> {"module"} -> errstr()." -->"),
|
||||
});
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# API support
|
||||
|
||||
## @method $ is_api_operation()
|
||||
# Determine whether the feature is being called in API mode, and if so what operation
|
||||
# is being requested.
|
||||
#
|
||||
# @return A string containing the API operation name if the script is being invoked
|
||||
# in API mode, undef otherwise. Note that, if the script is invoked in API mode,
|
||||
# but no operation has been specified, this returns an empty string.
|
||||
sub is_api_operation {
|
||||
my $self = shift;
|
||||
|
||||
my @api = $self -> {"cgi"} -> multi_param('api');
|
||||
|
||||
# No api means no API mode.
|
||||
return undef unless(scalar(@api));
|
||||
|
||||
# API mode is set by placing 'api' in the first api entry. The second api
|
||||
# entry is the operation.
|
||||
return $api[1] || "" if($api[0] eq 'api');
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
## @method $ api_param($param, $hasval, $params)
|
||||
# Determine whether an API parameter has been set, and optionally return
|
||||
# its value. This checks through the list of API parameters specified and,
|
||||
# if the named parameter is present, this will either return the value
|
||||
# that follows it in the parameter list if $hasval is true, or it will
|
||||
# simply return true to indicate the parameter is present.
|
||||
#
|
||||
# @param param The name of the API parameter to search for.
|
||||
# @param hasval If true, expect the value following the parameter in the
|
||||
# list of parameters to be the value thereof, and return it.
|
||||
# If false, this will return true if the parameter is present.
|
||||
# @param params An optional reference to a list of parameters. If making
|
||||
# multiple calls to api_param, grabbing the api parameter
|
||||
# list beforehand and passing a reference to that into each
|
||||
# api_param call will help speed the process up a bit.
|
||||
# @return The value for the parameter if it is set and hasval is true,
|
||||
# otherwise true if the paramter is present. If the parameter is
|
||||
# not present, this will return undef.
|
||||
sub api_param {
|
||||
my $self = shift;
|
||||
my $param = shift;
|
||||
my $hasval = shift;
|
||||
my $params = shift;
|
||||
|
||||
if(!$params) {
|
||||
my @api = $self -> {"cgi"} -> multi_param('api');
|
||||
return undef unless(scalar(@api));
|
||||
|
||||
$params = \@api;
|
||||
}
|
||||
|
||||
for(my $pos = 2; $pos < scalar(@{$params}); ++$pos) {
|
||||
if($params -> [$pos] eq $param) {
|
||||
return $hasval ? $params -> [$pos + 1] : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
## @method $ api_errorhash($code, $message)
|
||||
# Generate a hash that can be passed to api_response() to indicate that an error was encountered.
|
||||
#
|
||||
# @param code A 'code' to identify the error. Does not need to be numeric, but it
|
||||
# should be short, and as unique as possible to the error.
|
||||
# @param message The human-readable error message.
|
||||
# @return A reference to a hash to pass to api_response()
|
||||
sub api_errorhash {
|
||||
my $self = shift;
|
||||
my $code = shift;
|
||||
my $message = shift;
|
||||
|
||||
return { 'error' => {
|
||||
'info' => $message,
|
||||
'code' => $code
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
## @method $ api_html_response($data)
|
||||
# Generate a HTML response containing the specified data.
|
||||
#
|
||||
# @param data The data to send back to the client. If this is a hash, it is
|
||||
# assumed to be the result of a call to api_errorhash() and it is
|
||||
# converted to an appropriate error box. Otherwise, the data is
|
||||
# wrapped in a minimal html wrapper for return to the client.
|
||||
# @return The html response to send back to the client.
|
||||
sub api_html_response {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
# Fix up error hash returns
|
||||
$data = $self -> {"template"} -> load_template("api/html_error.tem", {"%(code)s" => $data -> {"error"} -> {"code"},
|
||||
"%(info)s" => $data -> {"error"} -> {"info"}})
|
||||
if(ref($data) eq "HASH" && $data -> {"error"});
|
||||
|
||||
return $self -> {"template"} -> load_template("api/html_wrapper.tem", {"%(data)s" => $data});
|
||||
}
|
||||
|
||||
|
||||
## @method private void _xml_api_response($data, %xmlopts)
|
||||
# Print out the specified data as a XML response.
|
||||
#
|
||||
# @param data The data to send back to the client as XML.
|
||||
# @param xmlopts Additional options passed to XML::Simple::XMLout. See the
|
||||
# documentation for api_response() regarding this argument.
|
||||
sub _xml_api_response {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
my %xmlopts = shift;
|
||||
my $xmldata;
|
||||
|
||||
$xmlopts{"XMLDecl"} = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'
|
||||
unless(defined($xmlopts{"XMLDecl"}));
|
||||
|
||||
$xmlopts{"KeepRoot"} = 0
|
||||
unless(defined($xmlopts{"KeepRoot"}));
|
||||
|
||||
$xmlopts{"RootName"} = 'api'
|
||||
unless(defined($xmlopts{"RootName"}));
|
||||
|
||||
eval { $xmldata = XMLout($data, %xmlopts); };
|
||||
$xmldata = $self -> {"template"} -> load_template("xml/error_response.tem", { "%(code)s" => "encoding_failed",
|
||||
"%(error)s" => "Error encoding XML response: $@"})
|
||||
if($@);
|
||||
|
||||
print $self -> {"cgi"} -> header(-type => 'application/xml',
|
||||
-charset => 'utf-8');
|
||||
print Encode::encode_utf8($xmldata);
|
||||
}
|
||||
|
||||
|
||||
## @method private void _json_api_response($data)
|
||||
# Print out the specified data as a JSON response.
|
||||
#
|
||||
# @param data The data to send back to the client as JSON.
|
||||
sub _json_api_response {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
my $json = JSON -> new();
|
||||
print $self -> {"cgi"} -> header(-type => 'application/json',
|
||||
-charset => 'utf-8');
|
||||
print Encode::encode_utf8($json -> pretty -> convert_blessed(1) -> encode($data));
|
||||
}
|
||||
|
||||
|
||||
## @method $ api_response($data, %xmlopts)
|
||||
# Generate an API response containing the specified data. This function will not return
|
||||
# if it is successful - it will return an response and exit. The content generated by
|
||||
# this function will be either JSON or XML depending on whether the user has specified
|
||||
# an appropriate 'format=' argument, whether a system default default is set, falling back
|
||||
# on JSON otherwise.
|
||||
#
|
||||
# @param data A reference to a hash containing the data to send back to the client as an
|
||||
# API response.
|
||||
# @param xmlopts Options passed to XML::Simple::XMLout if the respons is in XML. Note that
|
||||
# the following defaults are set for you:
|
||||
# - XMLDecl is set to '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'
|
||||
# - KeepRoot is set to 0
|
||||
# - RootName is set to 'api'
|
||||
# @return Does not return if successful, otherwise returns undef.
|
||||
sub api_response {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
my @xmlopts = @_;
|
||||
|
||||
# What manner of result should be resulting?
|
||||
my $format = $self -> {"settings"} -> {"API:format"} || "json";
|
||||
$format = "json" if($self -> {"cgi"} -> param("format") && $self -> {"cgi"} -> param("format") =~ /^json$/i);
|
||||
$format = "xml" if($self -> {"cgi"} -> param("format") && $self -> {"cgi"} -> param("format") =~ /^xml$/i);
|
||||
|
||||
given($format) {
|
||||
when("xml") { $self -> _xml_api_response($data, @xmlopts); }
|
||||
default { $self -> _json_api_response($data); }
|
||||
}
|
||||
|
||||
$self -> {"template"} -> set_module_obj(undef);
|
||||
$self -> {"messages"} -> set_module_obj(undef);
|
||||
$self -> {"system"} -> clear() if($self -> {"system"});
|
||||
$self -> {"session"} -> {"auth"} -> {"app"} -> set_system(undef) if($self -> {"session"} -> {"auth"} -> {"app"});
|
||||
|
||||
$self -> {"dbh"} -> disconnect();
|
||||
$self -> {"logger"} -> end_log();
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
## @method $ api_token_login()
|
||||
# Determine whether the client has sent an API token as part of the http request, and
|
||||
# if so establish whether the key is valid and corresponds to a user in the system.
|
||||
# This will set up the global session object to be 'logged in' as the key owner,
|
||||
# if they key is valid. Note that methods that rely on or generate session cookies
|
||||
# are not going to operate correctly when this is used: use only for API code!
|
||||
#
|
||||
# @note If using token auth, https *must* be used, or you may as well remove the
|
||||
# auth code entirely.
|
||||
#
|
||||
# @return The ID of the user the token corresponds to on success, undef if the user
|
||||
# has not provided a token header, or the token is not valid.
|
||||
sub api_token_login {
|
||||
my $self = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $key = $self -> {"cgi"} -> http($self -> {"api_auth_header"});
|
||||
return undef unless($key);
|
||||
|
||||
my ($checkkey) = $key =~ /^(\w+)$/;
|
||||
return undef unless($checkkey && length($checkkey) == $self -> {"api_auth_keylen"});
|
||||
|
||||
my $keyrec = $self -> {"dbh"} -> prepare("SELECT `user_id`
|
||||
FROM `".$self -> {"settings"} -> {"database"} -> {"apikeys"}."`
|
||||
WHERE `token` = ?
|
||||
AND `active` = 1
|
||||
ORDER BY `created` DESC
|
||||
LIMIT 1");
|
||||
$keyrec -> execute($checkkey)
|
||||
or return $self -> self_error("Unable to look up api key: ".$self -> {"dbh"} -> errstr());
|
||||
|
||||
my $keydata = $keyrec -> fetchrow_hashref()
|
||||
or return $self -> self_error("No matching api key record when looking for key '$checkkey'");
|
||||
|
||||
# This is a bit of a hack, but as long as it is called before any other session
|
||||
# code in the API module, it'll fake a logged-in session.
|
||||
$self -> {"session"} -> {"sessuser"} = $keydata -> {"user_id"};
|
||||
|
||||
return $keydata -> {"user_id"};
|
||||
}
|
||||
|
||||
|
||||
## @method $ api_token_generate($userid)
|
||||
# Generate a guaranteed-unique API token/key for the specified user. This will record the
|
||||
# new token in the database for later use, deactivating any previously-issued tokens for
|
||||
# the user, and return a copy of the new token.
|
||||
#
|
||||
# @param userid The ID of the user to generate a token for
|
||||
# @return The new token string on success, undef on error.
|
||||
sub api_token_generate {
|
||||
my $self = shift;
|
||||
my $userid = shift;
|
||||
my $token = '';
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $checkh = $self -> {"dbh"} -> prepare("SELECT `user_id`
|
||||
FROM `".$self -> {"settings"} -> {"database"} -> {"apikeys"}."`
|
||||
WHERE `token` = ?");
|
||||
|
||||
# Generate tokens until we hit one that isn't already defined.
|
||||
do {
|
||||
$token = join("", map { ("a".."z", "A".."Z", 0..9)[rand 62] } 1..$self -> {"api_auth_keylen"});
|
||||
|
||||
$checkh -> execute($token)
|
||||
or return $self -> self_error("Unable to look up api token: ".$self -> {"dbh"} -> errstr());
|
||||
|
||||
} while($checkh -> fetchrow_hashref());
|
||||
|
||||
# Deactivate the user's old tokens
|
||||
my $blockh = $self -> {"dbh"} -> prepare("UPDATE `".$self -> {"settings"} -> {"database"} -> {"apikeys"}."`
|
||||
SET `active` = 0
|
||||
WHERE `active` = 1 AND `user_id` = ?");
|
||||
$blockh -> execute($userid)
|
||||
or return $self -> self_error("Unable to deactivate old api tokens: ".$self -> {"dbh"} -> errstr());
|
||||
|
||||
# And add the new token
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO `".$self -> {"settings"} -> {"database"} -> {"apikeys"}."`
|
||||
(`user_id`, `token`, `created`)
|
||||
VALUES(?, ?, UNIX_TIMESTAMP())");
|
||||
|
||||
my $row = $newh -> execute($userid, $token);
|
||||
return $self -> self_error("Unable to store token '$token' for user '$userid': ".$self -> {"dbh"} -> errstr) if(!$row);
|
||||
return $self -> self_error("Insert failed for token '$token' for user '$userid': no rows inserted") if($row eq "0E0");
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# General utility
|
||||
|
||||
## @method void log($type, $message)
|
||||
# Log the current user's actions in the system. This is a convenience wrapper around the
|
||||
# Logger::log function.
|
||||
#
|
||||
# @param type The type of log entry to make, may be up to 64 characters long.
|
||||
# @param message The message to attach to the log entry, avoid messages over 128 characters.
|
||||
sub log {
|
||||
my $self = shift;
|
||||
my $type = shift;
|
||||
my $message = shift;
|
||||
|
||||
$message = "[Item:".($self -> {"itemid"} ? $self -> {"itemid"} : "none")."] $message";
|
||||
$self -> {"logger"} -> log($type, $self -> {"session"} -> get_session_userid(), $self -> {"cgi"} -> remote_host(), $message);
|
||||
}
|
||||
|
||||
|
||||
## @method $ set_saved_state()
|
||||
# Store the current status of the script, including block, api, pathinfo, and querystring
|
||||
# to session variables for later restoration.
|
||||
#
|
||||
# @return true on success, undef on error.
|
||||
sub set_saved_state {
|
||||
my $self = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $res = $self -> {"session"} -> set_variable("saved_block", $self -> {"cgi"} -> param("block"));
|
||||
return undef unless(defined($res));
|
||||
|
||||
my @pathinfo = $self -> {"cgi"} -> param("pathinfo");
|
||||
$res = $self -> {"session"} -> set_variable("saved_pathinfo", join("/", @pathinfo));
|
||||
return undef unless(defined($res));
|
||||
|
||||
my @api = $self -> {"cgi"} -> param("api");
|
||||
$res = $self -> {"session"} -> set_variable("saved_api", join("/", @api));
|
||||
return undef unless(defined($res));
|
||||
|
||||
# Convert the query parameters to a string, skipping the block, pathinfo, and api
|
||||
my @names = $self -> {"cgi"} -> param;
|
||||
my @qstring = ();
|
||||
foreach my $name (@names) {
|
||||
next if($name eq "block" || $name eq "pathinfo" || $name eq "api");
|
||||
|
||||
my @vals = $self -> {"cgi"} -> param($name);
|
||||
foreach my $val (@vals) {
|
||||
push(@qstring, escape($name)."=".escape($val));
|
||||
}
|
||||
}
|
||||
$res = $self -> {"session"} -> set_variable("saved_qstring", join("&", @qstring));
|
||||
return undef unless(defined($res));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
## @method @ get_saved_state()
|
||||
# A convenience wrapper around Session::get_variable() for fetching the state saved in
|
||||
# build_login_url().
|
||||
#
|
||||
# @return An array of strings, containing the block, pathinfo, api, and query string.
|
||||
sub get_saved_state {
|
||||
my $self = shift;
|
||||
|
||||
# Yes, these use set_variable. set_variable will return the value in the
|
||||
# variable, like get_variable, except that this will also delete the variable
|
||||
return ($self -> {"session"} -> set_variable("saved_block"),
|
||||
$self -> {"session"} -> set_variable("saved_pathinfo"),
|
||||
$self -> {"session"} -> set_variable("saved_api"),
|
||||
$self -> {"session"} -> set_variable("saved_qstring"));
|
||||
}
|
||||
|
||||
|
||||
## @method $ cleanup_entities($html)
|
||||
# Wrangle the specified HTML into something that won't produce an unholy mess when
|
||||
# passed to something that doesn't handle UTF-8 properly.
|
||||
#
|
||||
# @param html The HTML to process
|
||||
# @return A somewhat cleaned-up string of HTML
|
||||
sub cleanup_entities {
|
||||
my $self = shift;
|
||||
my $html = shift;
|
||||
|
||||
$html =~ s/\r//g;
|
||||
return encode_entities($html, '^\n\x20-\x7e');
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# URL building
|
||||
|
||||
## @method $ build_login_url()
|
||||
# Attempt to generate a URL that can be used to redirect the user to a login form.
|
||||
# The user's current query state (course, block, etc) is stored in a session variable
|
||||
# that can later be used to bring them back to the location this was called from.
|
||||
#
|
||||
# @return A relative login form redirection URL.
|
||||
sub build_login_url {
|
||||
my $self = shift;
|
||||
|
||||
# Store as much state as possible to restore after login (does not store POST
|
||||
# data!)
|
||||
$self -> set_saved_state();
|
||||
|
||||
return $self -> build_url(block => "login",
|
||||
fullurl => 1,
|
||||
pathinfo => [],
|
||||
params => {},
|
||||
forcessl => 1);
|
||||
}
|
||||
|
||||
|
||||
## @method $ build_return_url($fullurl)
|
||||
# Pulls the data out of the session saved state, checks it for safety,
|
||||
# and returns the URL the user should be redirected/linked to to return to the
|
||||
# location they were attempting to access before login.
|
||||
#
|
||||
# @param fullurl If set to true, the generated url will contain the protocol and
|
||||
# host. Otherwise the URL will be absolute from the server root.
|
||||
# @return A relative return URL.
|
||||
sub build_return_url {
|
||||
my $self = shift;
|
||||
my $fullurl = shift;
|
||||
my ($block, $pathinfo, $api, $qstring) = $self -> get_saved_state();
|
||||
|
||||
# Return url block should never be "login"
|
||||
$block = $self -> {"settings"} -> {"config"} -> {"default_block"} if($block eq "login" || !$block);
|
||||
|
||||
# Build the URL from them
|
||||
return $self -> build_url("block" => $block,
|
||||
"pathinfo" => $pathinfo,
|
||||
"api" => $api,
|
||||
"params" => $qstring,
|
||||
"fullurl" => $fullurl);
|
||||
}
|
||||
|
||||
|
||||
## @method $ build_url(%args)
|
||||
# Build a url suitable for use at any point in the system. This takes the args
|
||||
# and attempts to build a url from them. Supported arguments are:
|
||||
#
|
||||
# * fullurl - if set, the resulting URL will include the protocol and host. Defaults to
|
||||
# false (URL is absolute from the host root).
|
||||
# * block - the name of the block to include in the url. If not set, the current block
|
||||
# is used if possible, otherwise the system-wide default block is used.
|
||||
# * pathinfo - Either a string containing the pathinfo, or a reference to an array
|
||||
# containing pathinfo fragments. If not set, the current pathinfo is used.
|
||||
# * api - api fragments. If the first element is not "api", it is added.
|
||||
# * params - Either a string containing additional query string parameters to add to
|
||||
# the URL, or a reference to a hash of additional query string arguments.
|
||||
# Values in the hash may be references to arrays, in which case multiple
|
||||
# copies of the parameter are added to the query string, one for each
|
||||
# value in the array.
|
||||
# * forcessl - If true, the URL is forced to https: rather than http:
|
||||
#
|
||||
# @param args A hash of arguments to use when building the URL.
|
||||
# @return A string containing the URL.
|
||||
sub build_url {
|
||||
my $self = shift;
|
||||
my %args = @_;
|
||||
my $base = "";
|
||||
|
||||
# Default the block, item, and API fragments if needed and possible
|
||||
$args{"block"} = ($self -> {"cgi"} -> param("block") || $self -> {"settings"} -> {"config"} -> {"default_block"})
|
||||
if(!defined($args{"block"}));
|
||||
|
||||
if(!defined($args{"pathinfo"})) {
|
||||
my @cgipath = $self -> {"cgi"} -> multi_param("pathinfo");
|
||||
$args{"pathinfo"} = \@cgipath if(scalar(@cgipath));
|
||||
}
|
||||
|
||||
if(!defined($args{"api"})) {
|
||||
my @cgiapi = $self -> {"cgi"} -> multi_param("api");
|
||||
$args{"api"} = \@cgiapi if(scalar(@cgiapi));
|
||||
}
|
||||
|
||||
# Convert the pathinfo and api to slash-delimited strings
|
||||
my $pathinfo = join_complex($args{"pathinfo"}, joinstr => "/");
|
||||
my $api = join_complex($args{"api"}, joinstr => "/");
|
||||
|
||||
# Force the API call to start 'api' if it doesn't
|
||||
$api = "api/$api" if($api && $api !~ m|^/?api|);
|
||||
|
||||
# build the query string parameters.
|
||||
my $querystring = join_complex($args{"params"}, joinstr => ($args{"joinstr"} || "&"), pairstr => "=", escape => 1);
|
||||
|
||||
# building the URL involves shoving the bits together. path_join is intelligent enough to ignore
|
||||
# anything that is undef or "" here, so explicit checks beforehand should not be needed.
|
||||
my $url = path_join($self -> {"settings"} -> {"config"} -> {"scriptpath"}, $args{"block"}, $pathinfo, $api);
|
||||
$url = path_join($self -> {"cgi"} -> url(-base => 1), $url)
|
||||
if($args{"fullurl"});
|
||||
|
||||
# Strip block, pathinfo, and api from the query string if they've somehow made it in there.
|
||||
# Note this can't simply be made 'eg' as the progressive match can leave a trailing &
|
||||
if($querystring) {
|
||||
while($querystring =~ s{((?:&(?:amp;))?)(?:api|block|pathinfo)=[^&]+(&?)}{$1 && $2 ? "&" : ""}e) {}
|
||||
$url .= "?$querystring";
|
||||
}
|
||||
|
||||
$url =~ s/^http:/https:/
|
||||
if($args{"forcessl"} && $url =~ /^http:/);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Documentation support
|
||||
|
||||
## @method $ get_documentation_url($doclink)
|
||||
# Given a documentation link name, obtain the URL associated with that name.
|
||||
#
|
||||
# @param doclink The name of the documentation link to fetch.
|
||||
# @return The documentation URL if the doclink is valid, undef otherwise.
|
||||
sub get_documentation_url {
|
||||
my $self = shift;
|
||||
my $doclink = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# No point trying anything if there is no link name set.
|
||||
return undef if(!$doclink);
|
||||
|
||||
my $urlh = $self -> {"dbh"} -> prepare("SELECT `url`
|
||||
FROM `".$self -> {"settings"} -> {"database"} -> {"docs"}."`
|
||||
WHERE `name` LIKE ?");
|
||||
$urlh -> execute($doclink)
|
||||
or return $self -> self_error("Unable to look up documentation link: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# Fetch the url row, and if one has been found return it.
|
||||
my $url = $urlh -> fetchrow_arrayref();
|
||||
return $url ? $url -> [0] : undef;
|
||||
}
|
||||
|
||||
|
||||
1;
|
197
modules/ORB/AppUser.pm
Executable file
@ -0,0 +1,197 @@
|
||||
## @file
|
||||
# This file contains the ORB-specific user handling.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
package ORB::AppUser;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::AppUser);
|
||||
use Digest::MD5 qw(md5_hex);
|
||||
use Webperl::Utils qw(trimspace);
|
||||
|
||||
|
||||
## @method $ get_user($username, $onlyreal)
|
||||
# Obtain the user record for the specified user, if they exist. This returns a
|
||||
# reference to a hash of user data corresponding to the specified userid,
|
||||
# or undef if the userid does not correspond to a valid user. If the onlyreal
|
||||
# argument is set, the userid must correspond to 'real' user - bots or inactive
|
||||
# users are not be returned.
|
||||
#
|
||||
# @param username The username of the user to obtain the data for.
|
||||
# @param onlyreal If true, only users of type 0 or 3 are returned.
|
||||
# @return A reference to a hash containing the user's data, or undef if the user
|
||||
# can not be located (or is not real)
|
||||
sub get_user {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
my $onlyreal = shift;
|
||||
|
||||
my $user = $self -> _get_user("username", $username, $onlyreal, 1)
|
||||
or return undef;
|
||||
|
||||
return $self -> _make_user_extradata($user);
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_user_byid($userid, $onlyreal)
|
||||
# Obtain the user record for the specified user, if they exist. This returns a
|
||||
# reference to a hash of user data corresponding to the specified userid,
|
||||
# or undef if the userid does not correspond to a valid user. If the onlyreal
|
||||
# argument is set, the userid must correspond to 'real' user - bots or inactive
|
||||
# users are not be returned.
|
||||
#
|
||||
# @param userid The id of the user to obtain the data for.
|
||||
# @param onlyreal If true, only users of type 0 or 3 are returned.
|
||||
# @return A reference to a hash containing the user's data, or undef if the user
|
||||
# can not be located (or is not real)
|
||||
sub get_user_byid {
|
||||
my $self = shift;
|
||||
my $userid = shift;
|
||||
my $onlyreal = shift;
|
||||
|
||||
# obtain the user record
|
||||
my $user = $self -> _get_user("user_id", $userid, $onlyreal)
|
||||
or return undef;
|
||||
|
||||
return $self -> _make_user_extradata($user);
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_user_byemail($email, $onlyreal)
|
||||
# Obtain the user record for the user with the specified email, if available.
|
||||
# This returns a reference to a hash containing the user data corresponding
|
||||
# to the user with the specified email, or undef if no users have the email
|
||||
# specified. If the onlyreal argument is set, the userid must correspond to
|
||||
# 'real' user - bots or inactive users should not be returned.
|
||||
#
|
||||
# @param email The email address to find an owner for.
|
||||
# @param onlyreal If true, only users of type 0 or 3 are returned.
|
||||
# @return A reference to a hash containing the user's data, or undef if the email
|
||||
# address can not be located (or is not real)
|
||||
sub get_user_byemail {
|
||||
my $self = shift;
|
||||
my $email = shift;
|
||||
my $onlyreal = shift;
|
||||
|
||||
my $user = $self -> _get_user("email", $email, $onlyreal, 1)
|
||||
or return undef;
|
||||
|
||||
return $self -> _make_user_extradata($user);
|
||||
}
|
||||
|
||||
|
||||
## @method $ post_authenticate($username, $password, $auth, $extradata)
|
||||
# After the user has logged in, ensure that they have an in-system record.
|
||||
# This is essentially a wrapper around the standard AppUser::post_authenticate()
|
||||
# that handles things like user account activation checks.
|
||||
#
|
||||
# @param username The username of the user to perform post-auth tasks on.
|
||||
# @param password The password the user authenticated with.
|
||||
# @param auth A reference to the auth object calling this.
|
||||
# @param authmethod The id of the authmethod to set for the user.
|
||||
# @param extradata A reference to a hash of extra data fields for the user.
|
||||
# @return A reference to a hash containing the user's data on success,
|
||||
# undef otherwise. If this returns undef, an error message will be
|
||||
# set in to the specified auth's errstr field.
|
||||
sub post_authenticate {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
my $password = shift;
|
||||
my $auth = shift;
|
||||
my $authmethod = shift;
|
||||
my $extradata = shift;
|
||||
|
||||
# Let the superclass handle user creation
|
||||
my $user = $self -> SUPER::post_authenticate($username, $password, $auth, $authmethod, $extradata);
|
||||
return undef unless($user);
|
||||
|
||||
# User now exists, determine whether the user is active
|
||||
return $self -> post_login_checks($user, $auth)
|
||||
if($user -> {"activated"});
|
||||
|
||||
# User is inactive, does the account need activating?
|
||||
if(!$user -> {"act_code"}) {
|
||||
# No code provided, so just activate the account
|
||||
if($self -> activate_user_byid($user -> {"user_id"})) {
|
||||
return $user; #$self -> post_login_checks($user, $auth)
|
||||
} else {
|
||||
return $auth -> self_error($self -> {"errstr"});
|
||||
}
|
||||
} else {
|
||||
return $auth -> self_error("User account is not active.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## @method $ post_login_checks($user, $auth)
|
||||
# Perform checks on the specified user after they have logged in (post_authenticate is
|
||||
# going to return the user record). This ensures that the user has the appropriate
|
||||
# roles and settings.
|
||||
#
|
||||
# @param user A reference to a hash containing the user's data.
|
||||
# @param auth A reference to the auth object calling this.
|
||||
# @return A reference to a hash containing the user's data on success,
|
||||
# undef otherwise. If this returns undef, an error message will be
|
||||
# set in to the specified auth's errstr field.
|
||||
sub post_login_checks {
|
||||
my $self = shift;
|
||||
my $user = shift;
|
||||
my $auth = shift;
|
||||
|
||||
# All users must have the user role in the metadata root
|
||||
my $roleid = $self -> {"system"} -> {"roles"} -> role_get_roleid("user");
|
||||
my $root = $self -> {"system"} -> {"roles"} -> {"root_context"};
|
||||
my $hasrole = $self -> {"system"} -> {"roles"} -> user_has_role($root, $user -> {"user_id"}, $roleid);
|
||||
|
||||
# Give up if the role check failed.
|
||||
return $auth -> self_error($self -> {"system"} -> {"roles"} -> {"errstr"})
|
||||
if(!defined($hasrole));
|
||||
|
||||
# Try to assign the role if the user does not have it.
|
||||
$self -> {"system"} -> {"roles"} -> user_assign_role($root, $user -> {"user_id"}, $roleid)
|
||||
or return $auth -> self_error($self -> {"system"} -> {"roles"} -> {"errstr"})
|
||||
if(!$hasrole);
|
||||
|
||||
# TODO: Assign other roles as needed.
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Internal functions
|
||||
|
||||
## @method private $ _make_user_extradata($user)
|
||||
# Generate the 'calculated' user fields - full name, gravatar hash, etc.
|
||||
#
|
||||
# @param user A reference to the user hash to work on.
|
||||
# @return The user hash reference.
|
||||
sub _make_user_extradata {
|
||||
my $self = shift;
|
||||
my $user = shift;
|
||||
|
||||
# Generate the user's full name
|
||||
$user -> {"fullname"} = $user -> {"realname"} || $user -> {"username"};
|
||||
|
||||
# Make the user gravatar hash
|
||||
$user -> {"gravatar_hash"} = md5_hex(lc(trimspace($user -> {"email"} || "")));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
1;
|
115
modules/ORB/BlockSelector.pm
Executable file
@ -0,0 +1,115 @@
|
||||
## @file
|
||||
# This file contains the ORB-specific implementation of the runtime
|
||||
# block selection class.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
# Select the appropriate block to render a page based on an ORB URL.
|
||||
# This allows a url of the form /block/item/path/?args to be parsed into
|
||||
# something the ORB classes can use to render pages properly, and
|
||||
# select the appropriate block for the current request.
|
||||
package ORB::BlockSelector;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::BlockSelector);
|
||||
|
||||
# ============================================================================
|
||||
# Block Selection
|
||||
|
||||
## @method $ get_block($dbh, $cgi, $settings, $logger, $session)
|
||||
# Determine which block to use to generate the requested page. This performs
|
||||
# the same task as BlockSelector::get_block(), except that it will also parse
|
||||
# the contents of the PATH_INFO environment variable into the query string
|
||||
# data, allowing ORB paths to be passed to the rest of the code without
|
||||
# the need to check both the query string and PATH_INFO.
|
||||
#
|
||||
# After this has been called, the following variables may be set in the cgi
|
||||
# object:
|
||||
#
|
||||
# - `block` contains the currently selected block name, or the gallery block name
|
||||
# if one has not been specified.
|
||||
# - `pathinfo` contains the path to the currently selected item, as an array
|
||||
# of path segments. If not set, no item has been selected. Note that
|
||||
# this is simply a split version of any path info between the block and any
|
||||
# api specification, so it may be used by blocks to mean something other than
|
||||
# the item selected if needed.
|
||||
# - `pathinfo` contains any API call data, if any, as an array of path items.
|
||||
# If this is set, the first item will be the literal `api`, while the remaining
|
||||
# items will be the API operation and arguments.
|
||||
#
|
||||
# @param dbh A reference to the database handle to issue queries through.
|
||||
# @param cgi A reference to the system CGI object.
|
||||
# @param settings A reference to the global settings object.
|
||||
# @param logger A reference to the system logger object.
|
||||
# @param session A reference to the session object.
|
||||
# @return The id or name of the block to use to render the page, or undef if
|
||||
# an error occurred while selecting the block.
|
||||
sub get_block {
|
||||
my $self = shift;
|
||||
my $dbh = shift;
|
||||
my $cgi = shift;
|
||||
my $settings = shift;
|
||||
my $logger = shift;
|
||||
my $session = shift;
|
||||
|
||||
$self -> self_error("");
|
||||
|
||||
my $pathinfo = $ENV{'PATH_INFO'};
|
||||
|
||||
# If path info is present, it needs to be shoved into the cgi object
|
||||
if($pathinfo) {
|
||||
# strip off the script if it is present
|
||||
$pathinfo =~ s|^(/media)?/index.cgi||;
|
||||
|
||||
# pull out the api if specified
|
||||
my ($apicall) = $pathinfo =~ m|/(api.*)$|;
|
||||
$pathinfo =~ s|/api.*|| if($apicall);
|
||||
|
||||
# No need for leading /, it'll just confuse the split
|
||||
$pathinfo =~ s|^/||;
|
||||
|
||||
# Split along slashes
|
||||
my @args = split(/\//, $pathinfo);
|
||||
|
||||
# Defaults the block to the gallery, and clear the pathinfo and pathinfo for safety
|
||||
my $block = $settings -> {"config"} -> {"gallery_block"};
|
||||
$cgi -> delete('pathinfo', 'api');
|
||||
|
||||
# If a single item remains in the argument, it is a block name
|
||||
if(scalar(@args) == 1) {
|
||||
$block = shift @args;
|
||||
|
||||
# Two or more items in the argument are a block and item path
|
||||
} elsif(scalar(@args) >= 2) {
|
||||
$block = shift @args;
|
||||
$cgi -> param(-name => 'pathinfo', -values => \@args);
|
||||
}
|
||||
|
||||
$cgi -> param(-name => 'block', -value => $block);
|
||||
|
||||
# Now sort out the API
|
||||
if($apicall) {
|
||||
my @api = split(/\//, $apicall);
|
||||
$cgi -> param(-name => 'api', -values => \@api);
|
||||
}
|
||||
}
|
||||
|
||||
# The behaviour of BlockSelector::get_block() is fine, so let it work out the block
|
||||
return $self -> SUPER::get_block($dbh, $cgi, $settings, $logger);
|
||||
}
|
||||
|
||||
1;
|
70
modules/ORB/System.pm
Executable file
@ -0,0 +1,70 @@
|
||||
## @file
|
||||
# This file contains the ORB-specific implementation of the runtime
|
||||
# application-specific module loader class.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
# Loads any system-wide application specific modules needed by the
|
||||
# ORB application.
|
||||
package ORB::System;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::System);
|
||||
|
||||
use ORB::System::Metadata;
|
||||
use ORB::System::Roles;
|
||||
|
||||
|
||||
## @method $ init(%args)
|
||||
# Initialise the ORB System's references to other system objects. This
|
||||
# sets up the ORB-specific modules, placing references to them into the
|
||||
# object's hash. The argument hash provided must minimally contain the
|
||||
# following references:
|
||||
#
|
||||
# * cgi, a reference to a CGI object.
|
||||
# * dbh, a reference to the DBI object to issue database queries through.
|
||||
# * settings, a reference to the global settings object.
|
||||
# * logger, a reference to a Logger object.
|
||||
# * template, a reference to the system template engine.
|
||||
# * session, a reference to the system session handler.
|
||||
# * modules, a reference to the module loader.
|
||||
#
|
||||
# @param args A hash of arguments to initialise the System object with.
|
||||
# @return true on success, false if something failed. If this returns false,
|
||||
# the reason is in $self -> {"errstr"}.
|
||||
sub init {
|
||||
my $self = shift;
|
||||
|
||||
# Let the superclass copy the references over
|
||||
$self -> SUPER::init(@_)
|
||||
or return undef;
|
||||
|
||||
$self -> {"metadata"} = ORB::System::Metadata -> new(dbh => $self -> {"dbh"},
|
||||
settings => $self -> {"settings"},
|
||||
logger => $self -> {"logger"})
|
||||
or return $self -> self_error("Metadata system init failed: ".$Webperl::SystemModule::errstr);
|
||||
|
||||
$self -> {"roles"} = ORB::System::Roles -> new(dbh => $self -> {"dbh"},
|
||||
settings => $self -> {"settings"},
|
||||
logger => $self -> {"logger"},
|
||||
metadata => $self -> {"metadata"})
|
||||
or return $self -> self_error("Roles system init failed: ".$Webperl::SystemModule::errstr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
376
modules/ORB/System/Entity.pm
Normal file
@ -0,0 +1,376 @@
|
||||
## @file
|
||||
# This file contains the implementation of the Entity base class.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class Entity
|
||||
# This is a base class for entities in the system, providing common
|
||||
# features for all of the entities. Entities are any simple named
|
||||
# object in the system, typically things like ingredients, prep
|
||||
# memthods, recipe types and states.
|
||||
#
|
||||
# Tables for entities must have a minimum of the following fields:
|
||||
#
|
||||
# - `id`: unsigned int or larger, auto incremement
|
||||
# - `name`: varchar ot text, utf8_unicode_ci charset recommended
|
||||
# - `refcount`: unsigned int recommended
|
||||
#
|
||||
package ORB::System::Entity;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::SystemModule);
|
||||
use v5.14;
|
||||
|
||||
use Webperl::Utils qw(hash_or_hashref);
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Constructor
|
||||
|
||||
## @cmethod $ new(%args)
|
||||
# Create a new Entity object to manage entity creation and management.
|
||||
# The minimum values you need to provide are:
|
||||
#
|
||||
# - `dbh` - The database handle to use for queries.
|
||||
# - `settings` - The system settings object
|
||||
# - `logger` - The system logger object.
|
||||
# - `entity_table` - The name of the table the entities are stored in.
|
||||
#
|
||||
# @param args A hash of key value pairs to initialise the object with.
|
||||
# @return A new Entity object, or undef if a problem occured.
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = $class -> SUPER::new(@_);
|
||||
|
||||
return SystemModule::set_error("No entity table specified when attempting to create object")
|
||||
if(!$self -> {"entity_table"});
|
||||
|
||||
return $self
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Entity creation and deletion
|
||||
|
||||
## @method $ create($name)
|
||||
# Attempt to create a new named entity in the entoty table. Generally you
|
||||
# should not call this directly, as it will create a new entity in the table
|
||||
# even if an entity already exists with the same name: you will generally
|
||||
# want to call get_id() instead, as that will determine whether that the
|
||||
# entity already exists before calling this if it does not.
|
||||
#
|
||||
# @param name The name of the entity to add.
|
||||
# @return The new entity ID on success, undef on error.
|
||||
sub create {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO `".$self -> {"settings"} -> {"database"} -> {$self -> {"entity_table"}}."`
|
||||
(`name`)
|
||||
VALUES(?)");
|
||||
my $rows = $newh -> execute($name);
|
||||
return $self -> self_error("Unable to perform ".$self -> {"entity_table"}." insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error($self -> {"entity_table"}." insert failed, no rows inserted") if($rows eq "0E0");
|
||||
|
||||
# FIXME: This ties to MySQL, but is more reliable that last_insert_id in general.
|
||||
# Try to find a decent solution for this mess...
|
||||
# NOTE: the DBD::mysql documentation doesn't actually provide any useful information
|
||||
# about what this will contain if the insert fails. In fact, DBD::mysql calls
|
||||
# libmysql's mysql_insert_id(), which returns 0 on error (last insert failed).
|
||||
# There, why couldn't they bloody /say/ that?!
|
||||
my $id = $self -> {"dbh"} -> {"mysql_insertid"};
|
||||
return $self -> self_error("Unable to obtain id for entity '$name'") if(!$id);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
|
||||
## @method $ destroy(%args)
|
||||
# Attempt to remove the specified entity, and any assignments of it, from the system.
|
||||
# Supported arguments are:
|
||||
#
|
||||
# - `id`: The ID of the entity to remove. If not specified, a name must be given.
|
||||
# - `name`: The name of the entity to remove. If ID is specified, this is ignored.
|
||||
# - `relations`: A hash containing `name` and `field` fields specifying the table
|
||||
# to remove any relations from. This may be specified as a
|
||||
# reference to an array of hashes.
|
||||
#
|
||||
# @param args A hash, or reference to a hash, or argument.
|
||||
# @return true on success, undef on error
|
||||
sub destroy {
|
||||
my $self = shift;
|
||||
my $args = hash_or_hashref(@_);
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
return $self -> self_error("No id or name specified in call to destroy")
|
||||
unless($args -> {"id"} || $args -> {"name"});
|
||||
|
||||
# Convert name to ID if needed
|
||||
$args -> {"id"} = $self -> _fetch_id($args -> {"name"})
|
||||
unless($args -> {"id"});
|
||||
|
||||
# fall over if the relations argument is specified, but it's not a hash or arrayref
|
||||
return $self -> self_error("destroy invoked with invalid relations data")
|
||||
if($args -> {"relations"} &&
|
||||
ref($args -> {"relations"} ne "HASH" && ref($args -> {"relations"}) ne "ARRAY"));
|
||||
|
||||
# Force arrayref of hashes for simplicity
|
||||
$args -> {"relations"} = [ $args -> {"relations"} ]
|
||||
if($args -> {"relations"} && ref($args -> {"relations"} eq "HASH"));
|
||||
|
||||
# Process and remove each relation... or possibly none if there are none.
|
||||
foreach my $relation (@{$args -> {"relations"}}) {
|
||||
return $self -> self_error("Relation hash data invalid")
|
||||
unless($relation -> {"table"} && $relation -> {"field"});
|
||||
|
||||
$self -> remove_relation($args -> {"id"}, $relation -> {"table"}, $relation -> {"field"})
|
||||
or return undef;
|
||||
}
|
||||
|
||||
# Check that the entity is safe to delete...
|
||||
my $refcount = $self -> _fetch_refcount($id);
|
||||
|
||||
return $self -> self_error("Attempt to delete non-existent entity $id from ".$self -> {"entity_table"})
|
||||
unless(defined($refcount));
|
||||
|
||||
return $self -> self_error("Attempt to delete entity $id in ".$self -> {"entity_table"}." while still in use ($refcount references)")
|
||||
if($refcount);
|
||||
|
||||
# And now delete the entity itself
|
||||
my $nukeh = $self -> {"dbh"} -> prepare("DELETE FROM `".$self -> {"settings"} -> {"database"} -> {$self -> {"entity_table"}}."`
|
||||
WHERE `id` = ?");
|
||||
$nukeh -> execute($args -> {"id"})
|
||||
or return $self -> self_error("Unable to perform entity $id removal from ".$self -> {"entity_table"}.": ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Lookup
|
||||
|
||||
## @method $ get_id($name)
|
||||
# Obtain the ID associated with the specified entity. If the entity
|
||||
# does not yet exist in the entity's table, this will create it and
|
||||
# return the id the new entity was allocated.
|
||||
#
|
||||
# @param name The name of the entity to obtain the ID for
|
||||
# @return The ID of the entity on success, undef on error.
|
||||
sub get_id {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
|
||||
my $id = $self -> _fetch_id($name);
|
||||
return $id if(!defined($id) || $id); # return undefs, or non-zero ids.
|
||||
|
||||
# Get here, and $id is zero - no entity exists with the specified name, so
|
||||
# a new entity is needed.
|
||||
return $self -> create($name);
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Relation handling
|
||||
|
||||
## @method $ remove_relation($id, $table, $field, $retain_unused)
|
||||
# Remove any relations to the specified entity from the table provided.
|
||||
# This will decrease the refcount for the entity.
|
||||
#
|
||||
# @param id The Id of the entity to remove the relation for.
|
||||
# @param table The name of the table containing the relation to remove.
|
||||
# @param field The field containing the entity ID in the relation table.
|
||||
# @param retain_unused If true, do not delete the entity even if its refcount will
|
||||
# be zero after calling this. Defaults to true.
|
||||
# @return true on success, false on error.
|
||||
sub remove_relation {
|
||||
my $self = shift;
|
||||
my $id = shift;
|
||||
my $table = shift;
|
||||
my $field = shift;
|
||||
my $retain_unused = shift // 1;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $removeh = $self -> {"dbh"} -> prepare("DELETE FROM `$table`
|
||||
WHERE `$field` = ?");
|
||||
my $rows = $removeh -> execute($id);
|
||||
return $self -> self_error("Unable to remove entity relations to $id from $table") if(!$rows);
|
||||
return 1 if($rows eq "0E0"); # Zero row removal is possible and not an error
|
||||
|
||||
my $result = $self -> _update_refcount($id, subtract => $rows);
|
||||
return undef if(!defined($result));
|
||||
|
||||
# Nuke the entity if there's no reason to keep it around.
|
||||
return $self -> destroy($id)
|
||||
unless($retain_unused || $result);
|
||||
|
||||
return defined($result);
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Reference counting
|
||||
|
||||
## @method $ increase_refcount($id)
|
||||
# Increase the refcount for the entity with the specified id.
|
||||
#
|
||||
# @param id The ID of the entity to increase the refcount for.
|
||||
# @return true on success (actually, the reference count), false on error.
|
||||
sub increase_refcount {
|
||||
my $self = shift;
|
||||
my $id = shift;
|
||||
|
||||
return $self -> _update_refcount($id, add => 1);
|
||||
}
|
||||
|
||||
|
||||
## @method $ decrease_refcount($id, $retain_unused)
|
||||
# Reduce the refcount for the entity with the specified id. If the refcount
|
||||
# becomes zero, and $retain_unused is not true, the entity is removed from
|
||||
# the system.
|
||||
#
|
||||
# @param id The ID of the entity to decrease the refcount for.
|
||||
# @param retain_unused If true, do not delete the entity even if its refcount will
|
||||
# be zero after calling this. Defaults to true.
|
||||
# @return true on success, false on error.
|
||||
sub decrease_refcount {
|
||||
my $self = shift;
|
||||
my $id = shift;
|
||||
my $retain_unused = shift // 1;
|
||||
|
||||
# Change the refcount, bomb if the change failed.
|
||||
my $result = $self -> _update_refcount($id, subtract => 1);
|
||||
return undef if(!defined($result));
|
||||
|
||||
# Nuke the entity if there's no reason to keep it around.
|
||||
return $self -> destroy($id)
|
||||
unless($retain_unused || $result);
|
||||
|
||||
return defined($result);
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# ID lookup
|
||||
|
||||
## @method protected $ _fetch_id($name)
|
||||
# Given an entity name, attempt to find a record for that name. This will locate the
|
||||
# first defined entity whose name matches the provided name. Note that if there are
|
||||
# duplicate entities in the system, this will never find duplicates - it is guaranteed to
|
||||
# find the entity with the lowest ID whose name matches the provided value, or nothing.
|
||||
#
|
||||
# @param name The name of the entity to find.
|
||||
# @return The ID of the entity with the specified name on success, 0 if it does not exist,
|
||||
# undef on error occurred.
|
||||
sub _fetch_id {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Simple lookup. If the name field is set up as a _ci field, this will be case insensitive
|
||||
my $entityh = $self -> {"dbh"} -> prepare("SELECT `id`
|
||||
FROM `".$self -> {"settings"} -> {"database"} -> {$self -> {"entity_table"}}."`
|
||||
WHERE `name` LIKE ?
|
||||
ORDER BY `id`
|
||||
LIMIT 1"); # Limit to avoid pulling multiple rows if there are duplicates.
|
||||
$entityh -> execute($name)
|
||||
or return $self -> self_error("Unable to perform entity lookup: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# Return the ID if we have located it
|
||||
my $entityrow = $entityh-> fetchrow_arrayref();
|
||||
return $entityrow ? $entityrow -> [0] : 0;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Reference handling - generally intended only for subclasses to use
|
||||
|
||||
## @method protected $ _fetch_refcount($id)
|
||||
# Obtain the reference count for the specified entity. This will attempt to
|
||||
# fetch the reference count for the entity, if it fails - because the entity
|
||||
# does not exist, or the database has shat itself - it will return undef.
|
||||
#
|
||||
# @param id The entity to fetch the reference count for.
|
||||
# @return The number of references to the entity (which may be zero), or undef
|
||||
# on error.
|
||||
sub _fetch_refcount {
|
||||
my $self = shift;
|
||||
my $id = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Simple lookup, nothing spectacular to see here...
|
||||
my $refh = $self -> {"dbh"} -> prepare("SELECT `refcount`
|
||||
FROM `".$self -> {"settings"} -> {"database"} -> {$self -> {"entity_table"}}."`
|
||||
WHERE `id` = ?");
|
||||
$refh -> execute($id)
|
||||
or return $self -> self_error("Unable to perform entity refcount lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
my $refcount = $refh -> fetchrow_arrayref();
|
||||
return $refcount ? $refcount -> [0] : $self -> self_error("Unable to locate entity ".$self -> {"entity_table"}."[$id]: does not exist");
|
||||
}
|
||||
|
||||
|
||||
## @method protected $ _update_refcount($id, %operation)
|
||||
# Update the refcount for the specified entity. This will increment, decrement,
|
||||
# or set the value stored in the specified entity's reference counter. This is the
|
||||
# actual implementation underlying increase_refcount() and decrease_refcount().
|
||||
#
|
||||
# @param id The ID of the entity to update the refcount for.
|
||||
# @param operation A hash containing one of 'add', 'subtract', or 'set' with
|
||||
# values that indicate how much to change the refcount by.
|
||||
# @return The new value of the reference count on success (which may be zero), undef on error.
|
||||
sub _update_refcount {
|
||||
my $self = shift;
|
||||
my $id = shift;
|
||||
my %operation = @_;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $refcount = $self -> _fetch_refcount($id);
|
||||
return undef if(!defined($refcount));
|
||||
|
||||
# Calculate the new refcount
|
||||
if(defined($operation{"add"})) {
|
||||
$refcount += $operation{"add"};
|
||||
} elsif(defined($operation{"subtract"})) {
|
||||
$refcount -= $operation{"subtract"};
|
||||
} elsif(defined($operation{"set"})) {
|
||||
$refcount = $operation{"set"};
|
||||
} else {
|
||||
return $self -> self_error("No valid operation specified in call to _update_refcount() for ".$self -> {"entity_table"}."[$id]");
|
||||
}
|
||||
|
||||
# Is the new refcount sane?
|
||||
return $self -> self_error("New refount of $refcount for entity ".$self -> {"entity_table"}."[$id]: is invalid")
|
||||
if($refcount < 0 || ($self -> {"max_refcount"} && $refcount > $self -> {"max_refcount"}));
|
||||
|
||||
# Update is safe, do the operation.
|
||||
my $atth = $self -> {"dbh"} -> prepare("UPDATE `".$self -> {"settings"} -> {"database"} -> {$self -> {"entity_table"}}."`
|
||||
SET `refcount` = ?
|
||||
WHERE `id` = ?");
|
||||
my $result = $atth -> execute($refcount, $id);
|
||||
return $self -> self_error("Unable to update entity refcount: ".$self -> {"dbh"} -> errstr) if(!$result);
|
||||
return $self -> self_error("Entity refcount update failed: no rows updated. This should not happen!") if($result eq "0E0");
|
||||
|
||||
return $refcount;
|
||||
}
|
||||
|
||||
1;
|
369
modules/ORB/System/Metadata.pm
Executable file
@ -0,0 +1,369 @@
|
||||
## @file
|
||||
# This file contains the implementation of the metadata handling engine.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
# A class to encapsulate metadata context handling. This class provides the
|
||||
# methods required to manage metadata contexts in the system, including
|
||||
# creating and removing them, and modifying the reference count in the context
|
||||
# when roles, tags, courses, resources and so on are added to, or removed from,
|
||||
# the context.
|
||||
#
|
||||
# Metadata contexts are generic containers to which other pieces of data may
|
||||
# be attached. Usually each context has a parent, and if the parent is undef
|
||||
# the context is considered to be a root context. Generally there will only be
|
||||
# a single root in the system - the one corresponding to the front page of the
|
||||
# site. Contexts also have a reference count, which keeps track of how many
|
||||
# things have attached themselves to the context - a metadata context can not
|
||||
# be deleted unless its reference count is zero.
|
||||
#
|
||||
# Individual things - roles, tags, etc - need to keep track of which metadata
|
||||
# context they are attached to, by storing a metadata ID with their data. The
|
||||
# metadata context itself does not retain a list of attached 'things'.
|
||||
package ORB::System::Metadata;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::SystemModule);
|
||||
|
||||
# ============================================================================
|
||||
# Clean shutdown support
|
||||
|
||||
## @method void clear()
|
||||
# A function callable by System to ensure that the 'ondestroy' array does not
|
||||
# prevent object destruction.
|
||||
sub clear {
|
||||
my $self = shift;
|
||||
|
||||
# Nuke any ondelete entries
|
||||
$self -> {"ondestroy"} = [];
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Public interface
|
||||
|
||||
## @method void register_ondestroy($obj)
|
||||
# Register a class as needing to have its on_metadata_destroy() function called
|
||||
# when destroy() removes a metadata context.
|
||||
#
|
||||
# @param obj A reference to an object that needs to do cleanup when a context is destroyed.
|
||||
sub register_ondestroy {
|
||||
my $self = shift;
|
||||
my $obj = shift;
|
||||
|
||||
push(@{$self -> {"ondestroy"}}, $obj);
|
||||
}
|
||||
|
||||
|
||||
## @method $ create($parentid)
|
||||
# Create a new metadata context with the specified parent ID, and return the ID
|
||||
# of the newly created context.
|
||||
#
|
||||
# @param parentid The ID of this context's parent, or undef to create a root. Note
|
||||
# that root contexts should only be created with the utmost caution,
|
||||
# as they terminate role inheritance hierarchies.
|
||||
# @return The new metadata context id, or undef on error.
|
||||
sub create {
|
||||
my $self = shift;
|
||||
my $parentid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"metadata"}."
|
||||
(parent_id)
|
||||
VALUES(?)");
|
||||
my $rows = $newh -> execute($parentid);
|
||||
return $self -> self_error("Unable to perform metadata insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Metadata insert failed, no rows inserted") if($rows eq "0E0");
|
||||
|
||||
# FIXME: This ties to MySQL, but is more reliable that last_insert_id in general.
|
||||
# Try to find a decent solution for this mess...
|
||||
# NOTE: the DBD::mysql documentation doesn't actually provide any useful information
|
||||
# about what this will contain if the insert fails. In fact, DBD::mysql calls
|
||||
# libmysql's mysql_insert_id(), which returns 0 on error (last insert failed).
|
||||
# There, why couldn't they bloody /say/ that?!
|
||||
my $metadataid = $self -> {"dbh"} -> {"mysql_insertid"};
|
||||
|
||||
# Increment the parent's refcount if addition worked
|
||||
$self -> attach($parentid) or return undef
|
||||
if($parentid && $metadataid);
|
||||
|
||||
# Return undef if metadataid is undef or zero
|
||||
return $metadataid ? $metadataid : undef;
|
||||
}
|
||||
|
||||
|
||||
## @method $ destroy($metadataid)
|
||||
# Attempt to delete the specified metadata context from the system. If the refcount for
|
||||
# the context is non-zero, this will fail with an error. Note that this will not attempt
|
||||
# to delete any child contexts - they must have been deleted, and detached, before calling
|
||||
# this function.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to delete.
|
||||
# @return true on success, undef on error.
|
||||
sub destroy {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Can't do anything without knowing the reference count value
|
||||
my $refcount = $self -> _fetch_metadata_refcount($metadataid);
|
||||
return undef if(!defined($refcount));
|
||||
|
||||
return $self -> self_error("Attempt to delete metadata context $metadataid with non-zero ($refcount) reference count.")
|
||||
if($refcount);
|
||||
|
||||
# Reference count is zero, so nuke the context
|
||||
my $nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"metadata"}."
|
||||
WHERE id = ?");
|
||||
$nukeh -> execute($metadataid)
|
||||
or return $self -> self_error("Metadata context delete failed: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# Call any objects that need to do cleanup
|
||||
foreach my $obj (@{$self -> {"ondestroy"}}) {
|
||||
$obj -> on_metadata_destroy($metadataid) if($obj -> can("on_metadata_destroy"));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
## @method $ attach($metadataid)
|
||||
# Attach to the specified metadata context. This increments the specified metadata
|
||||
# context's reference counter, ensuring that it can not be destroyed until everything
|
||||
# that references it has detached.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to attach to.
|
||||
# @return The number of references on success, undef on error.
|
||||
sub attach {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
|
||||
return $self -> _update_metadata_refcount($metadataid, 1);
|
||||
}
|
||||
|
||||
|
||||
## @method $ detach($metadataid, $retain_unused)
|
||||
# Detach from the specified metadata context. This decrements the specified metadata
|
||||
# context's reference counter, potentially zeroing it - if this happens, and
|
||||
# retain_unused has not been set, the metadata context will be deleted.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to attach to.
|
||||
# @param retain_unused If true, do not delete the context even if its refcount will
|
||||
# be zero after calling this.
|
||||
# @return The reference count (which may be zero) on success, false on error.
|
||||
sub detach {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $retain_unused = shift;
|
||||
|
||||
# Change the refcount, bomb if the change failed.
|
||||
my $result = $self -> _update_metadata_refcount($metadataid, 0);
|
||||
return undef if(!defined($result));
|
||||
|
||||
# Nuke the context if there's no reason to keep it around.
|
||||
return $self -> destroy($metadataid)
|
||||
unless($retain_unused || $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
## @method $ parentid($metadataid)
|
||||
# Obtain the ID of the specified metadata context's parent. This will look up the
|
||||
# ID of the parent of the specified metadata context, and return it, potentially
|
||||
# returning undef if the parent id is NULL - the specified metadata id corresponds
|
||||
# to the root context. This method will attempt to use the role cache before going
|
||||
# to the database for the id.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to obtain the parent ID for.
|
||||
# @return The ID of the metadata context's parent (which may be ""). If an error
|
||||
# occurred, this will return undef and the error message will be stored
|
||||
# in $self -> {"errstr"}
|
||||
sub parentid {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
|
||||
# Check the cache for the metadata entry, return the parent if it's there...
|
||||
return $self -> {"cache"} -> {"metadata"} -> {$metadataid} -> {"parent_id"}
|
||||
if(defined($self -> {"cache"} -> {"metadata"} -> {$metadataid} -> {"parent_id"}));
|
||||
|
||||
# Otherwise, fetch the parent
|
||||
my $parentid = $self -> _fetch_metadata_parentid($metadataid);
|
||||
return undef if(!defined($parentid));
|
||||
|
||||
# Cache the parent
|
||||
$self -> {"cache"} -> {"metadata"} -> {$metadataid} -> {"parent_id"} = $parentid;
|
||||
|
||||
return $parentid;
|
||||
}
|
||||
|
||||
|
||||
## @method $ reparent($metadataid, $newparentid)
|
||||
# Detatch the specified metadata context from its current parent (if possible) and
|
||||
# reattach it to a different parent. This will handle ensuring that reference
|
||||
# counters are changed appropriately, and links are maintained.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to reparent.
|
||||
# @param newparentid The ID of the metadata context to set as the new parent.
|
||||
# @return true on success, undef on error.
|
||||
sub reparent {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $newparentid = shift;
|
||||
|
||||
my $parentid = $self -> parentid($metadataid);
|
||||
return undef if(!defined($parentid));
|
||||
|
||||
my $refcount = $self -> detach($parentid);
|
||||
return undef if(!defined($refcount));
|
||||
|
||||
$self -> _set_metadata_parentid($metadataid, $newparentid)
|
||||
or return undef;
|
||||
|
||||
$self -> attach($newparentid)
|
||||
or return undef;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Private methods
|
||||
|
||||
|
||||
## @method private $ _fetch_metadata_parentid($metadataid)
|
||||
# Obtain the metadata ID of the parent of the specified metadata context. If the
|
||||
# metadataid specified corresponds to a root node (one with no parent), this will
|
||||
# return an empty string.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to find the parent ID for.
|
||||
# @return The metadata context's parent ID, the empty string if the context has no
|
||||
# parent, or undef on error.
|
||||
sub _fetch_metadata_parentid {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $parenth = $self -> {"dbh"} -> prepare("SELECT parent_id FROM ".$self -> {"settings"} -> {"database"} -> {"metadata"}."
|
||||
WHERE id = ?");
|
||||
$parenth -> execute($metadataid)
|
||||
or return $self -> self_error("Unable to perform metadata parent lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# This should return something, or the metadataid is invalid
|
||||
my $parent = $parenth -> fetchrow_arrayref();
|
||||
return $self -> self_error("Unable to find metadata parent: invalid metadataid specified") if(!$parent);
|
||||
|
||||
# Parent is either defined, or undef. If it's undef, return "" instead.
|
||||
return $parent -> [0] || "";
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _fetch_metadata_refcount($metadataid)
|
||||
# Obtain the reference count for the specified metadata context.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to fetch the refcount for.
|
||||
# @return The reference count, which may be zero, or undef on error.
|
||||
sub _fetch_metadata_refcount {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Check that the refcount exists, and under/overflow is not going to happen
|
||||
my $checkh = $self -> {"dbh"} -> prepare("SELECT refcount FROM ".$self -> {"settings"} -> {"database"} -> {"metadata"}."
|
||||
WHERE id = ?");
|
||||
$checkh -> execute($metadataid)
|
||||
or return $self -> self_error("Metadata lookup failed: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
my $metadata = $checkh -> fetchrow_arrayref();
|
||||
return $self -> self_error("Metadata refcount update failed: unable to locate context $metadataid")
|
||||
if(!$metadata);
|
||||
|
||||
return $metadata -> [0];
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _update_metadata_refcount($metadataid, $increment)
|
||||
# Increment or decrement the value stored in the specified metadata context's reference
|
||||
# counter. This is the actual implementation underlying attach() and detach().
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to update the refcount for.
|
||||
# @param increment If true, the refcount is incremented, otherwise it is decremented.
|
||||
# @return The new value of the reference count on success (which may be zero), undef on error.
|
||||
sub _update_metadata_refcount {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $increment = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $refcount = $self -> _fetch_metadata_refcount($metadataid);
|
||||
return undef if(!defined($refcount));
|
||||
|
||||
return $self -> self_error("Metadata refcount update failed: attempt to set refcount for $metadataid out of range (old: $refcount, mode is ".($increment ? "inc)" : "dec)"))
|
||||
if((!$increment && $refcount == 0) || ($increment && $refcount == $self -> {"max_refcount"}));
|
||||
|
||||
# Update is safe, do the operation.
|
||||
my $atth = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"metadata"}."
|
||||
SET refcount = refcount ".($increment ? "+" : "-")." 1
|
||||
WHERE id = ?");
|
||||
my $result = $atth -> execute($metadataid);
|
||||
|
||||
# Detect and handle errors
|
||||
return $self -> self_error("Unable to update metadata refcount: ".$self -> {"dbh"} -> errstr)
|
||||
if(!$result);
|
||||
|
||||
# Detect row change failure, assume bad id
|
||||
return $self -> self_error("Metadata refcount update failed: no rows updated. This should not happen!")
|
||||
if($result eq "0E0");
|
||||
|
||||
# Work out what the new refcount is and return it
|
||||
$refcount = ($increment ? $refcount + 1 : $refcount - 1);
|
||||
return $refcount;
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _set_metadata_parentid($metadataid, $parentid)
|
||||
# Set the parent ID of the specified metadata context.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to set the parent for.
|
||||
# @param parentid The ID of the metadata context's new parent.
|
||||
# @return true on success, undef on error.
|
||||
sub _set_metadata_parentid {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $parentid = shift;
|
||||
|
||||
my $seth = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"metadata"}."
|
||||
SET parent_id = ?
|
||||
WHERE id = ?");
|
||||
my $result = $seth -> execute($parentid, $metadataid);
|
||||
|
||||
# Detect and handle errors
|
||||
return $self -> self_error("Unable to update metadata parent: ".$self -> {"dbh"} -> errstr) if(!$result);
|
||||
return $self -> self_error("Metadata parent update failed: no rows updated. This should not happen!") if($result eq "0E0");
|
||||
|
||||
# Cache the parent
|
||||
$self -> {"cache"} -> {"metadata"} -> {$metadataid} -> {"parent_id"} = $parentid;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
883
modules/ORB/System/Roles.pm
Executable file
@ -0,0 +1,883 @@
|
||||
## @file
|
||||
# This file contains the implementation of the Role handling engine.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
# This class encapsulates operations involving roles in the system. The methods
|
||||
# in this class provide the rest of the system with the ability to query user's
|
||||
# roles and capabilities, as well as assign roles to users, remove those assignments,
|
||||
# and define the capabilities of roles.
|
||||
#
|
||||
package ORB::System::Roles;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::SystemModule);
|
||||
|
||||
# ==============================================================================
|
||||
# Creation
|
||||
|
||||
## @cmethod $ new(%args)
|
||||
# Create a new Roles object to manage user role allocation and lookup.
|
||||
# The minimum values you need to provide are:
|
||||
#
|
||||
# * dbh - The database handle to use for queries.
|
||||
# * settings - The system settings object
|
||||
# * metadata - The system Metadata object.
|
||||
# * logger - The system logger object.
|
||||
#
|
||||
# @param args A hash of key value pairs to initialise the object with.
|
||||
# @return A new Roles object, or undef if a problem occured.
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = $class -> SUPER::new(root_context => 1,
|
||||
@_)
|
||||
or return undef;
|
||||
|
||||
# Check that the required objects are present
|
||||
return Webperl::SystemModule::set_error("No metadata object available.") if(!$self -> {"metadata"});
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Public interface - user-centric role functions.
|
||||
|
||||
## @method $ user_capabilities($metadataid, $userid, $rolelimit)
|
||||
# Obtain a hash of user capabilities for the specified metadata context. This will
|
||||
# check the specified metadata context and all its parents to create a full
|
||||
# set of capabilities the user has in the context.Normal role combination rules apply
|
||||
# (higher priority roles will take precedent over lower priority roles), except
|
||||
# that all metadata levels from the specified level to the root are considered.
|
||||
# If `rolelimit` is specified, only roleids present in the hash will be included
|
||||
# when determining whether the user has the requested capability.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to start searching from. This
|
||||
# will generally be the context associated with the resource
|
||||
# checking the user's capabilities.
|
||||
# @param userid The ID of the user to establish the capabilities of.
|
||||
# @param rolelimit An optional hash containing role ids as keys, and true or
|
||||
# false as values. If a role id's value is true, the role
|
||||
# will be allowed through to capability testing, otherwise
|
||||
# the role is excluded from capability testing. IMPORTANT:
|
||||
# specifying this hash *does not* grant the user any roles they
|
||||
# do not already have - this is used to conditionally exclude
|
||||
# roles the user *does* have from capability testing, not grant
|
||||
# roles!
|
||||
# @return A reference to a capability hash on success, undef on error.
|
||||
sub user_capabilities {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $userid = shift;
|
||||
my $rolelimit = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# User roles will accumulate in here...
|
||||
my $user_roles = {};
|
||||
|
||||
# Now get all the roles the user has from this metadata context to the root
|
||||
while($metadataid) {
|
||||
# Fetch the roles for the user set at this metadata level, give up if there was
|
||||
# an error doing it.
|
||||
my $roles = $self -> metadata_assigned_roles($metadataid, $userid);
|
||||
return undef if(!defined($roles));
|
||||
|
||||
# copy over any roles set...
|
||||
foreach my $role (keys(%{$roles})) {
|
||||
# skip any roles not present in $rolelimit, if needed
|
||||
next if($rolelimit && !$rolelimit -> {$role});
|
||||
|
||||
$user_roles -> {$role} = $roles -> {$role};
|
||||
}
|
||||
|
||||
# go up a level if possible
|
||||
$metadataid = $self -> {"metadata"} -> parentid($metadataid);
|
||||
}
|
||||
|
||||
# $user_roles now contains an unsorted hash of roleids and priorities,
|
||||
# we need a sorted list of roleids, highest priority last so that higher
|
||||
# priorities overwrite lower
|
||||
my @roleids = sort { $user_roles -> {$a} <=> $user_roles -> {$b} } keys(%{$user_roles});
|
||||
|
||||
my $capabilities = {};
|
||||
# Now fo through each role, merging the role capabilities into the
|
||||
# capabilities hash
|
||||
foreach my $roleid (@roleids) {
|
||||
my $rolecaps = $self -> role_get_capabilities($roleid);
|
||||
|
||||
# Merge the new capabilities into the ones collected so far, this will
|
||||
# overwrite any capabilities already defined - hence the need to sort above!
|
||||
@{$capabilities}{keys %{$rolecaps}} = values %{$rolecaps};
|
||||
}
|
||||
|
||||
return $capabilities;
|
||||
}
|
||||
|
||||
|
||||
## @method $ user_has_capability($metadataid, $userid, $capability, $rolelimit)
|
||||
# Determine whether the user has the specified capability within the metadata
|
||||
# context. This will search the current metadata context, and its parents, to
|
||||
# determine whether the user has the capability requested, and if so whether
|
||||
# that capability is enabled or disabled. Normal role combination rules apply
|
||||
# (higher priority roles will take precedent over lower priority roles), except
|
||||
# that all metadata levels from the specified level to the root are considered.
|
||||
# If `rolelimit` is specified, only roleids present in the hash will be included
|
||||
# when determining whether the user has the requested capability.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to start searching from. This
|
||||
# will generally be the context associated with the resource
|
||||
# checking the user's capabilities.
|
||||
# @param userid The ID of the user to establish the capabilities of.
|
||||
# @param capability The name of the capability the user needs.
|
||||
# @param rolelimit An optional hash containing role ids as keys, and true or
|
||||
# false as values. If a role id's value is true, the role
|
||||
# will be allowed through to capability testing, otherwise
|
||||
# the role is excluded from capability testing. IMPORTANT:
|
||||
# specifying this hash *does not* grant the user any roles they
|
||||
# do not already have - this is used to conditionally exclude
|
||||
# roles the user *does* have from capability testing, not grant
|
||||
# roles!
|
||||
# @return true if the user has the requested capability, false if they do not, undef
|
||||
# if an error was encountered.
|
||||
sub user_has_capability {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $userid = shift;
|
||||
my $capability = shift;
|
||||
my $rolelimit = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Has the user's capability at this metadata level been queried before? If so, use the cached value.
|
||||
# In most cases this will probably miss, but it's not like it is a big overhead.
|
||||
return $self -> {"cache"} -> {"user"} -> {$userid} -> {"capabilities"} -> {$metadataid} -> {$capability}
|
||||
if(defined($self -> {"cache"} -> {"user"} -> {$userid} -> {"capabilities"} -> {$metadataid} -> {$capability}));
|
||||
|
||||
# User roles will accumulate in here...
|
||||
my $user_roles = {};
|
||||
|
||||
# Need to preserve the original ID for caching, so copy it...
|
||||
my $currentmdid = $metadataid;
|
||||
|
||||
# Now get all the roles the user has from this metadata context to the root
|
||||
while($currentmdid) {
|
||||
# Fetch the roles for the user set at this metadata level, give up if there was
|
||||
# an error doing it.
|
||||
my $roles = $self -> metadata_assigned_roles($currentmdid, $userid);
|
||||
return undef if(!defined($roles));
|
||||
|
||||
# copy over any roles set...
|
||||
foreach my $role (keys(%{$roles})) {
|
||||
# skip any roles not present in $rolelimit, if needed
|
||||
next if($rolelimit && !$rolelimit -> {$role});
|
||||
|
||||
$user_roles -> {$role} = $roles -> {$role};
|
||||
}
|
||||
|
||||
# FUTURE: At this point, discontinuities could be introduced into the role
|
||||
# inheritance hierarchy by halting tree climbing if the metadata indicates
|
||||
# inheritance should break here. However, doing so would probably need special
|
||||
# edge-cases for admin users.
|
||||
|
||||
# go up a level if possible
|
||||
$currentmdid = $self -> {"metadata"} -> parentid($currentmdid);
|
||||
}
|
||||
|
||||
# $user_roles now contains an unsorted hash of roleids and priorities,
|
||||
# we need a sorted list of roleids, highest priority first, to check for
|
||||
# the capability.
|
||||
my @roleids = sort { $user_roles -> {$b} <=> $user_roles -> {$a} } keys(%{$user_roles});
|
||||
|
||||
# Go through the list of roles, determining whether the role sets the
|
||||
# capability in some fasion
|
||||
my $set_capability;
|
||||
foreach my $role (@roleids) {
|
||||
$set_capability = $self -> role_has_capability($role, $capability);
|
||||
return undef if(defined($set_capability) && $set_capability eq "error");
|
||||
|
||||
# stop if a setting for the capability has been located
|
||||
last if($set_capability);
|
||||
}
|
||||
|
||||
# If set_capability is still undefined, none of the roles defined the capability,
|
||||
# so set it to the default 'deny'
|
||||
$set_capability = "deny" unless(defined($set_capability));
|
||||
|
||||
# store the result in the cache
|
||||
$self -> {"cache"} -> {"user"} -> {$userid} -> {"capabilities"} -> {$metadataid} -> {$capability} = ($set_capability eq "allow");
|
||||
|
||||
# And done
|
||||
return $self -> {"cache"} -> {"user"} -> {$userid} -> {"capabilities"} -> {$metadataid} -> {$capability};
|
||||
}
|
||||
|
||||
|
||||
## @method $ user_has_role($metadataid, $userid, $roleid, $sourceid, $check_tree)
|
||||
# Determine whether the user has the specified role in the current metadata context.
|
||||
# If sourceid is specified, only roles granted by the corresponding enrolment source
|
||||
# will be considered when checking for the role. If $check_tree is set, this will
|
||||
# not only check the specified metadata context for the role, but any parent context,
|
||||
# until either the role is found or the search fails at the root. Byt default, only
|
||||
# the specified metadata context is checked.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to check.
|
||||
# @param userid The ID of the user to check the role for.
|
||||
# @param roleid The ID of the role to look for.
|
||||
# @param sourceid If specified, only roles granted by this enrolment source are considered.
|
||||
# @param check_tree If true, this function will walk back up the tree trying to locate
|
||||
# any assignment of the role. Otherwise, only the specified context is
|
||||
# checked.
|
||||
# @return true if the user has the role, false if the user does not, and undef on error.
|
||||
sub user_has_role {
|
||||
my $self = shift;
|
||||
my ($metadataid, $userid, $roleid, $sourceid, $check_tree) = @_;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Note lack of caching - while it would be possible to cache the result of this, doing
|
||||
# so is likely to introduce subtle bugs. Caching can be added in future if needed.
|
||||
my $has_role;
|
||||
do {
|
||||
$has_role = $self -> _fetch_user_role($metadataid, $userid, $roleid, $sourceid);
|
||||
# _fetch_user_role returns undef when the role hasn't been granted, or error. Check errors...
|
||||
return undef if($self -> {"errstr"});
|
||||
|
||||
# Otherwise, try going up to the parent
|
||||
$metadataid = $self -> {"metadata"} -> parentid($metadataid);
|
||||
} while(!$has_role && $check_tree && $metadataid);
|
||||
|
||||
return defined($has_role);
|
||||
}
|
||||
|
||||
|
||||
## @method $ user_assign_role($metadataid, $userid, $roleid, $sourceid, $groupid)
|
||||
# Assign the user a role in the specified metadata context. This will give the user
|
||||
# the role, if the user does not already have it. If the user has the role, this
|
||||
# will update the persist flag if it differs.
|
||||
#
|
||||
# @note Users may be given the same role by different enrolment sources, and the
|
||||
# persist flag may be different for each source. This means that the user
|
||||
# may have Role A set by Source A, and Role A set by Source B. In practice
|
||||
# this feature is unlikely to be needed or used, but is provided Just In Case.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to grant the role in.
|
||||
# @param userid The ID of the user to grant the role to.
|
||||
# @param roleid The ID of the role to grant.
|
||||
# @param sourceid The ID of the enrolment source granting the role.
|
||||
# @param groupid The ID of the group this is an assignment for. If this is an
|
||||
# individual assignment rather than a group assignment, set this
|
||||
# to undef.
|
||||
# @return true on success, false if an error occurred.
|
||||
sub user_assign_role {
|
||||
my $self = shift;
|
||||
my ($metadataid, $userid, $roleid, $sourceid, $groupid) = @_;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Try to get the role, bomb if an error occurred
|
||||
my $role = $self -> _fetch_user_role($metadataid, $userid, $roleid, $sourceid, $groupid);
|
||||
return undef if(!$role && $self -> {"errstr"});
|
||||
|
||||
my $rows;
|
||||
# no role found? Try to assign it.
|
||||
if(!$role) {
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}."
|
||||
(metadata_id, role_id, user_id, source_id, group_id, attached, touched)
|
||||
VALUES(?, ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())");
|
||||
$rows = $newh -> execute($metadataid, $roleid, $userid, $sourceid, $groupid);
|
||||
return $self -> self_error("Unable to perform metadata role insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
|
||||
# If a row has been added, increment the metadata's refcount
|
||||
$rows = $self -> {"metadata"} -> attach($metadataid)
|
||||
if($rows ne "0E0");
|
||||
|
||||
# A role has been located in this context that matches the user and source,
|
||||
# update its touched timestamp
|
||||
} else {
|
||||
my $oldh = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}."
|
||||
SET touched = UNIX_TIMESTAMP(),
|
||||
WHERE id = ?");
|
||||
$rows = $oldh -> execute($role -> {"id"});
|
||||
return $self -> self_error("Unable to perform metadata role update: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
}
|
||||
|
||||
# Check that a row has been modified before finishing.
|
||||
return $self -> self_error("Role assignment failed: no rows modified") if($rows eq "0E0");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
## @method $ user_remove_role($metadataid, $userid, $roleid, $sourceid, $groupid)
|
||||
# Remove a role from a user in the specified metadata context. If the user does
|
||||
# not have the role in the context, this does nothing, and this function *will not*
|
||||
# traverse the tree looking for any assignment of the role to the user: it will
|
||||
# inspect the specified metadata context only. If sourceid is not specified, the
|
||||
# role is guaranteed to be entirely removed from the user in the context if it was
|
||||
# set there. If sourceid is provided, only the role allocation previously made by
|
||||
# the specified source will be removed, and any other copies of the role allocation
|
||||
# made by other sources will remain in effect.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to remove the role in.
|
||||
# @param userid The ID of the user to remove the role from.
|
||||
# @param roleid The ID of the role to remove.
|
||||
# @param sourceid The ID of the enrolment source removing the role, or undef if
|
||||
# copies of the role applied by all sources should be removed.
|
||||
# @param groupid The ID of the group this is a removal for.
|
||||
# @return true on success, false if an error occurred.
|
||||
sub user_remove_role {
|
||||
my $self = shift;
|
||||
my ($metadataid, $userid, $roleid, $sourceid, $groupid) = @_;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my @args = ($metadataid, $roleid, $userid, $groupid);
|
||||
my $query = "DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}."
|
||||
WHERE metadata_id = ?
|
||||
AND role_id = ?
|
||||
AND user_id = ?
|
||||
AND group_id = ?";
|
||||
|
||||
if($sourceid) {
|
||||
$query .= " AND source_id = ?";
|
||||
push(@args, $sourceid);
|
||||
}
|
||||
|
||||
my $nukeh = $self -> {"dbh"} -> prepare($query);
|
||||
my $rows = $nukeh -> execute(@args);
|
||||
|
||||
return $self -> self_error("Unable to perform metadata role delete: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Metadata context delete failed: no rows removed") if($rows eq "0E0");
|
||||
|
||||
# Removal worked, so decrement the refcount
|
||||
my $refcount = $self -> {"metadata"} -> detach($metadataid);
|
||||
return defined($refcount);
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_role_users($metadataid, $roleid, $fields, $orderby, $sourceid)
|
||||
# Obtain a list of users who have the specified role at this metadata level. If
|
||||
# the sourceid is specified, only roles allocated by the specified source are
|
||||
# considered when constructing the list.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to list users from.
|
||||
# @param roleid The ID of the role that has been assigned to users.
|
||||
# @param fields A reference to an array containing the user table fields to include
|
||||
# in the returned data. If this is undef, all fields are collected.
|
||||
# If the selected fields do not start with "u." it will be prepended
|
||||
# for you.
|
||||
# @param orderby Optional contents of the 'ORDER BY' clause of the query. The user table
|
||||
# is aliased as 'u', so you can do things like "u.username ASC". Set
|
||||
# to undef if you don't care about sorting.
|
||||
# @param sourceid The ID of the enrolment source that allocated the role, or
|
||||
# undef if any source is acceptable
|
||||
# @return A reference to an array of hashrefs, each hashref contains the data
|
||||
# for a user with the specified role.
|
||||
sub get_role_users {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $roleid = shift;
|
||||
my $fields = shift || [];
|
||||
my $orderby = shift;
|
||||
my $sourceid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $selectedfields = "";
|
||||
foreach my $field (@{$fields}) {
|
||||
$selectedfields .= ", " if($selectedfields);
|
||||
|
||||
# Make sure the field is coming out of the user table
|
||||
$field = "u.$field" unless($field =~ /^u\./);
|
||||
|
||||
$selectedfields .= $field;
|
||||
}
|
||||
# Fall back on fetching everything if there's no field selection.
|
||||
$selectedfields = "u.*" if(!$selectedfields);
|
||||
|
||||
# Simple query is pretty simple...
|
||||
my $userh = $self -> {"dbh"} -> prepare("SELECT $selectedfields
|
||||
FROM ".$self -> {"settings"} -> {"database"} -> {"users"}." AS u,
|
||||
".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}." AS r
|
||||
WHERE r.role_id = ?
|
||||
AND u.user_id = r.user_id"
|
||||
.($sourceid ? " AND source_id = ?" : "")
|
||||
.($orderby ? " ORDER BY $orderby" : ""));
|
||||
if($sourceid) {
|
||||
$userh -> execute($roleid, $sourceid)
|
||||
or return $self -> self_error("Unable to fetch role users: ". $self -> {"dbh"} -> errstr);
|
||||
} else {
|
||||
$userh -> execute($roleid)
|
||||
or return $self -> self_error("Unable to fetch role users: ". $self -> {"dbh"} -> errstr);
|
||||
}
|
||||
|
||||
# Fetch all the results as an array of hashrefs
|
||||
return $userh -> fetchall_arrayref({});
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Public interface - role-centric role functions.
|
||||
|
||||
## @method $ create($name, $priority, $capabilities)
|
||||
# Create a new role, initialising it with the specified priority and capabilities.
|
||||
#
|
||||
# @param name The name of the role. If a role already exists with this name,
|
||||
# the function will abort.
|
||||
# @param priority The role priority, in the range 0 (lowest) to 255 (highest).
|
||||
# @param capabilities A reference to a hash containing the capabilities to set for
|
||||
# the role. Keys should be capability names, and the values should
|
||||
# be true for 'allow' and false for 'deny'. Set this to undef to
|
||||
# skip capability settings.
|
||||
# @return The new role ID on success, undef on error.
|
||||
sub create {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $priority = shift;
|
||||
my $capabilities = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"roles"}."
|
||||
(name, priority)
|
||||
VALUES(?, ?)");
|
||||
my $rows = $newh -> execute($name, $priority);
|
||||
return $self -> self_error("Unable to perform role insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Role insert failed, no rows inserted") if($rows eq "0E0");
|
||||
|
||||
# FIXME: This ties to MySQL, but is more reliable that last_insert_id in general.
|
||||
# Try to find a decent solution for this mess...
|
||||
# NOTE: the DBD::mysql documentation doesn't actually provide any useful information
|
||||
# about what this will contain if the insert fails. In fact, DBD::mysql calls
|
||||
# libmysql's mysql_insert_id(), which returns 0 on error (last insert failed).
|
||||
# There, why couldn't they bloody /say/ that?!
|
||||
my $roleid = $self -> {"dbh"} -> {"mysql_insertid"};
|
||||
return $self -> self_error("Unable to obtain roleid for role '$name'") if(!$roleid);
|
||||
|
||||
# Skip capability setting if there are no capabilities to set.
|
||||
return $roleid if(!$capabilities);
|
||||
|
||||
# Set up the capabilities
|
||||
return $self -> role_set_capabilities($roleid, $capabilities) ? $roleid : undef;
|
||||
}
|
||||
|
||||
|
||||
## @method $ destroy($roleid)
|
||||
# Attempt to remove the specified role, and any capabilities associated with it, from
|
||||
# the system.
|
||||
#
|
||||
# @warning This will remove the role, the capabilities set for the role, and any
|
||||
# role assignments. It will work even if there are users currently allocated
|
||||
# this role. Use with extreme caution!
|
||||
#
|
||||
# @param roleid The ID of the role to remove from the system
|
||||
# @return true on success, undef on error
|
||||
sub destroy {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Delete any role assignments first. This is utterly indiscriminate, if this breaks
|
||||
# something important, don't say I didn't warn you.
|
||||
my $nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}."
|
||||
WHERE role_id = ?");
|
||||
$nukeh -> execute($roleid)
|
||||
or return $self -> self_error("Unable to perform role allocation removal: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# Now delete the capabilities
|
||||
$nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"role_capabilities"}."
|
||||
WHERE role_id = ?");
|
||||
$nukeh -> execute($roleid)
|
||||
or return $self -> self_error("Unable to perform role capability removal: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# And now the role itself
|
||||
$nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"roles"}."
|
||||
WHERE id = ?");
|
||||
$nukeh -> execute($roleid)
|
||||
or return $self -> self_error("Unable to perform role removal: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# Trash the cache, too, just in case
|
||||
$self -> {"cache"} = {};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
## @method $ set_priority($roleid, $priority)
|
||||
# Update the priority for the specified role.
|
||||
#
|
||||
# @param roleid The role to update the priority for.
|
||||
# @param priority The new priority for the role.
|
||||
# @return true on success, undef on error.
|
||||
sub set_priority {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
my $priority = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $seth = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"roles"}."
|
||||
SET priority = ?
|
||||
WHERE id = ?");
|
||||
my $rows = $seth -> execute($priority, $roleid);
|
||||
return $self -> self_error("Unable to perform role priority update: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Role priority update failed: no rows updated (possibly bad role id $roleid)") if($rows eq "0E0");
|
||||
|
||||
# This could invalidate the cache, so clear it
|
||||
$self -> {"cache"} = {};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_priority($roleid)
|
||||
# Obtain the priority of the specified role.
|
||||
#
|
||||
# @param roleid The role to obtain the priority for.
|
||||
# @return The priority of the role on success (note this may be zero!), undef on error.
|
||||
sub get_priority {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $geth = $self -> {"dbh"} -> prepare("SELECT priority FROM ".$self -> {"settings"} -> {"database"} -> {"roles"}."
|
||||
WHERE id = ?");
|
||||
$geth -> execute($roleid)
|
||||
or return $self -> self_error("Unable to perform role priority lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
my $role = $geth -> fetchrow_arrayref();
|
||||
|
||||
return $role ? $role -> [0] : $self -> self_error("Role priority lookup failed: bad role id $roleid");
|
||||
}
|
||||
|
||||
|
||||
## @method $ role_get_roleid($name)
|
||||
# Given a role name, obtain the id of the role.
|
||||
#
|
||||
# @param name The name of the role to look up.
|
||||
# @return The id of the role, or undef if the role name is not valid or an error
|
||||
# occurred.
|
||||
sub role_get_roleid {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $roleh = $self -> {"dbh"} -> prepare("SELECT id FROM ".$self -> {"settings"} -> {"database"} -> {"roles"}."
|
||||
WHERE role_name LIKE ?");
|
||||
$roleh -> execute($name)
|
||||
or return $self -> self_error("Unable to perform role lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# Return the role id if it is found, otherwise undef.
|
||||
my $role = $roleh -> fetchrow_arrayref();
|
||||
return $role ? $role -> [0] : undef;
|
||||
}
|
||||
|
||||
|
||||
## @method $ role_has_capability($roleid, $capability)
|
||||
# Determine whether the specified role defines the requested capability. This will
|
||||
# check whether the capability is defined for the role, and if it is return the
|
||||
# value that is set for its mode. If the capability is not set for the role,
|
||||
# this returns undef.
|
||||
#
|
||||
# @param roleid The ID of the role to check.
|
||||
# @param capability The name of the capability to look for in the role.
|
||||
# @return 'allow' or 'deny' if the role sets the capability, undef otherwise.
|
||||
# This will return 'error' if an error was encountered.
|
||||
sub role_has_capability {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
my $capability = shift;
|
||||
|
||||
# Is the value cached?
|
||||
if($self -> {"cache"} -> {"role"} -> {$roleid} -> {$capability}) {
|
||||
# If the cache indicates the value is undefined for this role, return undef, otherwise return
|
||||
# the cached value.
|
||||
return undef if($self -> {"cache"} -> {"role"} -> {$roleid} -> {$capability} eq "undef");
|
||||
return $self -> {"cache"} -> {"role"} -> {$roleid} -> {$capability};
|
||||
}
|
||||
|
||||
# Ask the database for the capability definition, if provided
|
||||
my $set_capability = $self -> _fetch_role_capability($roleid, $capability);
|
||||
return "error" if(defined($set_capability) && $set_capability eq "error");
|
||||
|
||||
# Cache the result
|
||||
$self -> {"cache"} -> {"role"} -> {$roleid} -> {$capability} = defined($set_capability) ? $set_capability : "undef";
|
||||
|
||||
return $set_capability;
|
||||
}
|
||||
|
||||
|
||||
## @method $ role_get_capabilities($roleid)
|
||||
# Obtain a hash containing the capabilities defined for the specified role. This
|
||||
# will pull the role capability settings out of the database and return a hash
|
||||
# containing the capability names as keys and their mode as the value. The value
|
||||
# is true if the mode is 'allow', and false if it is 'deny'.
|
||||
#
|
||||
# @param roleid The ID of the role to obtain capability data for.
|
||||
# @return A reference to a hash containing role capabilities on success, undef
|
||||
# on error.
|
||||
sub role_get_capabilities {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# There's no need to order the results of this, as it's going into a hash anyway
|
||||
my $caph = $self -> {"dbh"} -> prepare("SELECT capability, mode
|
||||
FROM ".$self -> {"settings"} -> {"database"} -> {"role_capabilities"}."
|
||||
WHERE role_id = ?");
|
||||
$caph -> execute($roleid)
|
||||
or return $self -> self_error("Unable to fetch role capability list: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# Bung the results in a hash. Would be nice to use fetchall here, but for the mode translate
|
||||
my $caphash = {};
|
||||
while(my $capability = $caph -> fetchrow_hashref()) {
|
||||
$caphash -> {$capability -> {"capability"}} = ($capability -> {"mode"} eq "allow");
|
||||
}
|
||||
|
||||
return $caphash;
|
||||
}
|
||||
|
||||
|
||||
## @method $ role_set_capabilities($roleid, $capabilities)
|
||||
# Update the capabilities for the specified role. This takes a hash of capabilities,
|
||||
# capability names as keys and mode as value (true is 'allow', false is 'deny') and
|
||||
# sets the capabilities for the role to the settings in the hash. Note that any
|
||||
# capabilities not in the hash, but previously assigned to the role *will be removed*.
|
||||
#
|
||||
# @param roleid The ID of the role to update.
|
||||
# @param capabilities A reference to a hash containing the capabilities to set for
|
||||
# the role. Keys should be capability names, and the values should
|
||||
# be true for 'allow' and false for 'deny'.
|
||||
# @return true on success, undef on error. Note that if an error occurs, it is possible
|
||||
# that the capability list may no longer reflect the old list, or the full
|
||||
# list specified in the capabilities hash.
|
||||
sub role_set_capabilities {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
my $capabilities = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Nuke any existing capabilities for this role
|
||||
my $nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"role_capabilities"}."
|
||||
WHERE role_id = ?");
|
||||
$nukeh -> execute($roleid)
|
||||
or return $self -> self_error("Unable to delete capabilities for role $roleid: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# Now insert new capabilities
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"role_capabilities"}."
|
||||
(role_id, capability, mode)
|
||||
VALUES(?, ?, ?)");
|
||||
foreach my $capability (keys(%{$capabilities})) {
|
||||
my $inserted = $newh -> execute($roleid, $capability, $capabilities -> {$capability} ? "allow" : "deny");
|
||||
|
||||
return $self -> self_error("Unable to give capability $capability to role $roleid: ".$self -> {"dbh"} -> errstr)
|
||||
if(!$inserted);
|
||||
|
||||
return $self -> self_error("Unable to give capability $capability to role $roleid: row insertion failed")
|
||||
if($inserted eq "0E0");
|
||||
}
|
||||
|
||||
# Reset the cache, to prevent stale values causing problems
|
||||
$self -> {"cache"} = {};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Public-ish, mostly internal metadata bridge
|
||||
|
||||
## @method $ metadata_assigned_roles($metadataid, $userid)
|
||||
# Obtain a hash of roles defined for the user in the specified metadata context. This
|
||||
# returns only the roles defined *in the specified metadata*, it does not include any
|
||||
# roles defined in any parents. If no roles are defined at this level, an empty hash
|
||||
# is returned, otherwise the returned hash contains the roleids as keys and their
|
||||
# priorities as values.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to fetch user roles for.
|
||||
# @param userid The ID of the user to fetch roles for.
|
||||
# @return A hash containing the roles set at this level, role ids as keys and
|
||||
# role priorities as values. If any errors are encountered, this returns
|
||||
# undef and the error message is stored in $self -> {"errstr"}
|
||||
sub metadata_assigned_roles {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $userid = shift;
|
||||
|
||||
# Are the user's roles at this level cached?
|
||||
return $self -> {"cache"} -> {"user"} -> {$userid} -> {"roles"} -> {$metadataid}
|
||||
if(defined($self -> {"cache"} -> {"user"} -> {$userid} -> {"roles"} -> {$metadataid}));
|
||||
|
||||
# Not cached, try to fetch them
|
||||
my $roles = $self -> _fetch_metadata_roles($metadataid, $userid);
|
||||
return undef if(!defined($roles));
|
||||
|
||||
$self -> {"cache"} -> {"user"} -> {$userid} -> {$metadataid} -> {"roles"} = $roles;
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Private methods
|
||||
|
||||
## @method private $ _fetch_metadata_roles($metadataid, $userid)
|
||||
# Fetch the roles set for the user at the specified metadata level. If there
|
||||
# are no roles for the user attached to the specified metadata id, this returns
|
||||
# an empty roles hash, otherwise it will return a hash containing the ids of
|
||||
# any roles set and their priorities.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to fetch user roles for.
|
||||
# @param userid The ID of the user to fetch roles for.
|
||||
# @return A hash containing the roles set at this level, role ids as keys and
|
||||
# role priorities as values. If any errors are encountered, this returns
|
||||
# undef and the error message is stored in $self -> {"errstr"}
|
||||
sub _fetch_metadata_roles {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $userid = shift;
|
||||
my $set_roles = {};
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Pull the list of roles, highest priority first
|
||||
my $roleh = $self -> {"dbh"} -> prepare("SELECT r.id, r.priority
|
||||
FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}." AS m,
|
||||
".$self -> {"settings"} -> {"database"} -> {"roles"}." AS r
|
||||
WHERE r.id = m.role_id
|
||||
AND m.metadata_id = ?
|
||||
AND m.user_id = ?
|
||||
ORDER BY r.priority DESC");
|
||||
$roleh -> execute($metadataid, $userid)
|
||||
or return $self -> self_error("Unable to perform metadata role lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# Store roles set at this level, and their priorities
|
||||
while(my $role = $roleh -> fetchrow_hashref()) {
|
||||
$set_roles -> {$role -> {"id"}} = $role -> {"priority"};
|
||||
}
|
||||
|
||||
# If the user has no roles in this context, and default roles have been enabled,
|
||||
# determine whether the context has a default role set.
|
||||
$set_roles = $self -> _fetch_metadata_default_role($metadataid)
|
||||
if(!scalar($set_roles) && $self -> {"settings"} -> {"database"} -> {"metadata_default_roles"});
|
||||
|
||||
return $set_roles;
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _fetch_metadata_default_role($metadataid)
|
||||
# Obtain the default role set for the specified metadata context, and its priority, if
|
||||
# the metadata context has a default role set.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to obtain the default role for.
|
||||
# @return A reference to a hash containing the default role id and priority on
|
||||
# success, an empty hashref if no default is defined, and undef on error.
|
||||
sub _fetch_metadata_default_role {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
|
||||
my $defh = $self -> {"dbh"} -> prepare("SELECT d.role_id,d.priority AS override,r.priority
|
||||
FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_default_roles"}." AS d,
|
||||
".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}." AS r
|
||||
WHERE d.metadata_id = ?
|
||||
AND r.id = d.role_id");
|
||||
$defh -> execute($metadataid)
|
||||
or return $self -> self_error("Unable to perform metadata default role lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# If a default has been specified, return a hashref with it set, otherwise just return an empty hashref.
|
||||
my $def = $defh -> fetchrow_hashref();
|
||||
return $def ? {$def -> {"role_id"} => ($def -> {"override"} || $def -> {"priority"})} : {};
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _fetch_role_capability($roleid, $capability)
|
||||
# Look up whether the specified role defines the requested capability, and if
|
||||
# it does, return the mode defined for it.
|
||||
#
|
||||
# @param roleid The ID of the role to check.
|
||||
# @param capability The name of the capability to look for in the role.
|
||||
# @return 'allow' or 'deny' if the role sets the capability, undef otherwise.
|
||||
# This will return 'error' if an error was encountered.
|
||||
sub _fetch_role_capability {
|
||||
my $self = shift;
|
||||
my $roleid = shift;
|
||||
my $capability = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $roleh = $self -> {"dbh"} -> prepare("SELECT mode FROM ".$self -> {"settings"} -> {"database"} -> {"role_capabilities"}."
|
||||
WHERE role_id = ?
|
||||
AND capability LIKE ?");
|
||||
$roleh -> execute($roleid, $capability)
|
||||
or return ($self -> self_error("Unable to perform role capability lookup: ". $self -> {"dbh"} -> errstr) || "error");
|
||||
|
||||
# Fetch the role's definition of the capability, and it if has one return it.
|
||||
my $role = $roleh -> fetchrow_arrayref();
|
||||
return $role ? $role -> [0] : undef;
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _fetch_user_role($metadataid, $userid, $roleid, $sourceid, $groupid)
|
||||
# Obtain the metadata role record for the user and role. If sourceid is specified,
|
||||
# this will only return a metadata role record if it was granted by the source. If
|
||||
# a group id is specified, this will only return a record if it was added as part of
|
||||
# that group.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to look at for the role assignment.
|
||||
# @param userid The ID of the user whose role allocation should be checked.
|
||||
# @param roleid The ID of the role to look for.
|
||||
# @param sourceid Optional ID of the enrolment source that granted the role.
|
||||
# @param groupid Optional ID of a group the role assignment was made as part of.
|
||||
# @return A reference to a hash containing the metadata role allocation, or undef
|
||||
# if no matching allocation was found, or an error occurred.
|
||||
sub _fetch_user_role {
|
||||
my $self = shift;
|
||||
my ($metadataid, $userid, $roleid, $sourceid, $groupid) = @_;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $query = "SELECT *
|
||||
FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_roles"}."
|
||||
WHERE metadata_id = ?
|
||||
AND user_id = ?
|
||||
AND role_id = ?";
|
||||
my @args = ($metadataid, $userid, $roleid);
|
||||
|
||||
if($sourceid) {
|
||||
$query .= " AND source_id = ?";
|
||||
push(@args, $sourceid);
|
||||
}
|
||||
|
||||
if($groupid) {
|
||||
$query .= " AND group_id = ?";
|
||||
push(@args, $groupid);
|
||||
}
|
||||
|
||||
my $roleh = $self -> {"dbh"} -> prepare($query);
|
||||
$roleh -> execute(@args)
|
||||
or return $self -> self_error("Unable to perform metadata role lookup: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
return $roleh -> fetchrow_hashref();
|
||||
}
|
||||
|
||||
1;
|
512
modules/ORB/System/Tags.pm
Executable file
@ -0,0 +1,512 @@
|
||||
## @file
|
||||
# This file contains the implementation of the tag handling engine.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
# This class encapsulates operations involving tags in the system.
|
||||
package ORB::System::Tags;
|
||||
|
||||
use strict;
|
||||
use parent qw(Webperl::SystemModule);
|
||||
|
||||
# ==============================================================================
|
||||
# Creation
|
||||
|
||||
## @cmethod $ new(%args)
|
||||
# Create a new Tags object to manage tag allocation and lookup.
|
||||
# The minimum values you need to provide are:
|
||||
#
|
||||
# * dbh - The database handle to use for queries.
|
||||
# * settings - The system settings object
|
||||
# * metadata - The system Metadata object.
|
||||
# * logger - The system logger object.
|
||||
#
|
||||
# @param args A hash of key value pairs to initialise the object with.
|
||||
# @return A new Tags object, or undef if a problem occured.
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = $class -> SUPER::new(@_)
|
||||
or return undef;
|
||||
|
||||
# Check that the required objects are present
|
||||
return Webperl::SystemModule::set_error("No metadata object available.") if(!$self -> {"metadata"});
|
||||
|
||||
# Register with the metadata destroy handler
|
||||
$self -> {"metadata"} -> register_ondestroy($self);
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Public interface - tag creation, deletion, etc
|
||||
|
||||
## @method $ create($name, $userid)
|
||||
# Create a new tag with the specified name. This will create a new tag, setting
|
||||
# its name and creator to the values specified. Note that this will not check
|
||||
# whether a tag with the same name already exists
|
||||
#
|
||||
# @param name The name of the tag to add.
|
||||
# @param userid The ID of the user creating the tag.
|
||||
# @return The new tag ID on success, undef on error.
|
||||
sub create {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $userid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"tags"}."
|
||||
(name, creator_id, created)
|
||||
VALUES(?, ?, UNIX_TIMESTAMP())");
|
||||
my $rows = $newh -> execute($name, $userid);
|
||||
return $self -> self_error("Unable to perform tag insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Tag insert failed, no rows inserted") if($rows eq "0E0");
|
||||
|
||||
# FIXME: This ties to MySQL, but is more reliable that last_insert_id in general.
|
||||
# Try to find a decent solution for this mess...
|
||||
# NOTE: the DBD::mysql documentation doesn't actually provide any useful information
|
||||
# about what this will contain if the insert fails. In fact, DBD::mysql calls
|
||||
# libmysql's mysql_insert_id(), which returns 0 on error (last insert failed).
|
||||
# There, why couldn't they bloody /say/ that?!
|
||||
my $tagid = $self -> {"dbh"} -> {"mysql_insertid"};
|
||||
return $self -> self_error("Unable to obtain id for tag '$name'") if(!$tagid);
|
||||
|
||||
return $tagid;
|
||||
}
|
||||
|
||||
|
||||
## @method $ destroy($tagid)
|
||||
# Attempt to remove the specified tag, and any assignments of it, from the system.
|
||||
#
|
||||
# @warning This will remove the tag, any tag assignments, and any active flags for the
|
||||
# tag. It will work even if there are resources currently tagged with this tag.
|
||||
# Use with extreme caution!
|
||||
#
|
||||
# @param tagid The ID of the tag to remove from the system
|
||||
# @return true on success, undef on error
|
||||
sub destroy {
|
||||
my $self = shift;
|
||||
my $tagid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Delete any tag assignments first. This is utterly indiscriminate, if this breaks
|
||||
# something important, don't say I didn't warn you.
|
||||
my $nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}."
|
||||
WHERE tag_id = ?");
|
||||
$nukeh -> execute($tagid)
|
||||
or return $self -> self_error("Unable to perform tag allocation removal: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# Delete any activations of this tag
|
||||
$nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"active_tags"}."
|
||||
WHERE tag_id = ?");
|
||||
$nukeh -> execute($tagid)
|
||||
or return $self -> self_error("Unable to perform active tag removal: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
# And now delete the tag itself
|
||||
$nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"tags"}."
|
||||
WHERE id = ?");
|
||||
$nukeh -> execute($tagid)
|
||||
or return $self -> self_error("Unable to perform tag removal: ". $self -> {"dbh"} -> errstr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_tagid($name, $userid)
|
||||
# Obtain the ID associated with the specified tag. If the tag does not yet exist
|
||||
# in the tags table, this will create it and return the ID the new row was
|
||||
# allocated.
|
||||
#
|
||||
# @param name The name of the tag to obtain the ID for
|
||||
# @param userid The ID of the user requesting the tag, in case it must be created.
|
||||
# @return The ID of the tag on success, undef on error.
|
||||
sub get_tagid {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
my $userid = shift;
|
||||
|
||||
# Search for a tag with the specified name, give up if an error occurred
|
||||
my $tagid = $self -> _fetch_tagid($name);
|
||||
return $tagid if($tagid || $self -> {"errstr"});
|
||||
|
||||
# Get here and the tag doesn't exist, create it
|
||||
return $self -> create($name, $userid);
|
||||
}
|
||||
|
||||
|
||||
## @method $ attach($metadataid, $tagid, $userid, $persist, $rating)
|
||||
# Attach a tag to a metadata context. This will attempt to apply the specified tag
|
||||
# to the metadata context, recording the user that requested the attachment.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to attach the tag to.
|
||||
# @param tagid The ID of the tag to attach.
|
||||
# @param userid The ID of the user responsible for attaching the tag.
|
||||
# @param rating Optional initial rating to give the tag. If not specified, this
|
||||
# will default to "default_rating" in the configuration.
|
||||
# @return true on success, undef on error.
|
||||
sub attach {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $userid = shift;
|
||||
my $rating = shift || $self -> {"settings"} -> {"config"} -> {"default_rating"} || 0;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# determine whether the tag is already set on this metadata context
|
||||
my $tag = $self -> _attached($metadataid, $tagid);
|
||||
return undef if(!defined($tag));
|
||||
|
||||
# Tag is already set, return true, but log it as it shouldn't really happen
|
||||
if($tag) {
|
||||
$self -> {"logger"} -> log("warning", $userid, undef, "Attempt to re-set tag $tagid on metadata $metadataid by $userid.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Tag is not set, so add it
|
||||
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}."
|
||||
(metadata_id, tag_id, attached_by, attached_date, rating)
|
||||
VALUES(?, ?, ?, UNIX_TIMESTAMP(), ?)");
|
||||
my $rows = $newh -> execute($metadataid, $tagid, $userid, $rating);
|
||||
return $self -> self_error("Unable to perform metadata tag insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Metadata tag insert failed: no rows modified") if($rows eq "0E0");
|
||||
|
||||
# Tag has been set, what is the ID of the newly added metadata tag relation?
|
||||
my $relation = $self -> {"dbh"} -> {"mysql_insertid"};
|
||||
return $self -> self_error("Unable to obtain id for metadata tag relation '$tagid' on '$metadataid'") if(!$relation);
|
||||
|
||||
# Attach to the metadata context
|
||||
my $attached = $self -> {"metadata"} -> attach($metadataid);
|
||||
return undef if(!$attached); # this should always be 1 or greater if the attach worked.
|
||||
|
||||
# And log the tagging operation in the history
|
||||
return $self -> _log_action($metadataid, $tagid, "added", $userid, $rating);
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_attached_tags($metadataid, $alphasort)
|
||||
# Generate a list of tags attached to the specified metadata context. This will create
|
||||
# a list containing reference to tag data hashes, and return a reference to it. If there
|
||||
# are no tags attached to the context, this returns a reference to an empty list.
|
||||
#
|
||||
# @note This will not fetch tags attached to parent contexts: only tags attached to the
|
||||
# current context are returned. If your code needs to inherit from the parent, you
|
||||
# will need to call this on the parent context and merge the arrays yourself.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to fetch the tags for.
|
||||
# @param alphasort If true, sort the list alphanumerically. If this is false, the list
|
||||
# is sorted by rating (highest first), and then alphanumerically.
|
||||
# @return A reference to an array of tag data hashes (which may be empty) on success,
|
||||
# undef if an error occurred.
|
||||
sub get_attached_tags {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $alphasort = shift;
|
||||
|
||||
# Tag lookup query, pretty simple...
|
||||
my $tagh = $self -> {"dbh"} -> prepare("SELECT m.*,t.name,t.creator_id,t.created
|
||||
FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}." AS m,
|
||||
".$self -> {"settings"} -> {"database"} -> {"tags"}." AS t
|
||||
WHERE t.id = m.tag_id
|
||||
AND m.metadata_id = ?
|
||||
ORDER BY ".($alphasort ? "t.name ASC, m.rating DESC" : "m.rating DESC, t.name ASC"));
|
||||
$tagh -> execute($metadataid)
|
||||
or $self -> self_error("Unable to perform tag lookup query: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# Get the results as a reference to an array of hash refs.
|
||||
return $tagh -> fetchall_arrayref({});
|
||||
}
|
||||
|
||||
|
||||
## @method $ detach($metadataid, $tagid, $userid)
|
||||
# Remove the tag from the specified metadata context. This will do nothing if the tag is
|
||||
# not attached to the context, returning true if the tag is not set on the context (but
|
||||
# potentially logging the attempt as a warning). No permission checks are (or can be) done
|
||||
# by this method: the caller is required to ensure that the user performing the tag
|
||||
# removal has permission to do so.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to remove the tag from.
|
||||
# @param tagid The ID of the tag to remove.
|
||||
# @param userid The ID of the user doing the removal.
|
||||
# @return true on success (tag is no longer attached, or never was), under on error.
|
||||
sub detach {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $userid = shift;
|
||||
|
||||
my $tagdata = $self -> _fetch_attached_tag($metadataid, $tagid);
|
||||
return undef if($self -> {"errstr"}); # Was an error encountered in the fetch?
|
||||
|
||||
# No need to do anything if the tag is not attached, but log it as an error anyway
|
||||
if(!$tagdata) {
|
||||
$self -> {"logger"} -> log("warning", $userid, undef, "Attempt to remove unattached tag $tagid from metadata $metadataid by $userid.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Tag is set, so remove it
|
||||
my $nukeh = $self -> {"dbh"} -> prepare("DELETE FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}."
|
||||
WHERE metadata_id = ?
|
||||
AND tag_id = ?");
|
||||
my $rows = $nukeh -> execute($metadataid, $tagid);
|
||||
return $self -> self_error("Unable to perform metadata tag removal: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Metadata tag removal failed: no rows modified") if($rows eq "0E0");
|
||||
|
||||
# Tag is gone, log the removal
|
||||
$self -> _log_action($metadataid, $tagid, "delete", $userid, $tagdata -> {"rating"});
|
||||
|
||||
# Detach from the context
|
||||
return defined($self -> {"metadata"} -> detach($metadataid));
|
||||
}
|
||||
|
||||
|
||||
## @method $ rate_up($metadataid, $tagid, $userid)
|
||||
# Rate up the specified tag in the metadata context, marking the provided user as the
|
||||
# person doing the rating. Note that this will not do any permission checking - the
|
||||
# caller must have established that the user has permission to update the rating.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context containing the tag to rate.
|
||||
# @param tagid The ID of the tag to change the rating of.
|
||||
# @param userid The ID of the user performing the rating change.
|
||||
# @return true on success, undef on error.
|
||||
sub rate_up {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $userid = shift;
|
||||
|
||||
return $self -> _update_rating($metadataid, $tagid, $userid, 1);
|
||||
}
|
||||
|
||||
|
||||
## @method $ rate_down($metadataid, $tagid, $userid)
|
||||
# Rate down the specified tag in the metadata context, marking the provided user as the
|
||||
# person doing the rating. Note that this will not do any permission checking - the
|
||||
# caller must have established that the user has permission to update the rating.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context containing the tag to rate.
|
||||
# @param tagid The ID of the tag to change the rating of.
|
||||
# @param userid The ID of the user performing the rating change.
|
||||
# @return true on success, undef on error.
|
||||
sub rate_down {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $userid = shift;
|
||||
|
||||
return $self -> _update_rating($metadataid, $tagid, $userid, 0);
|
||||
}
|
||||
|
||||
|
||||
## @method $ user_has_rated($metadataid, $tagid, $userid)
|
||||
# Determine whether the user has rated the specified tag in the metadata context. Note that
|
||||
# this counts adding a tag as rating it - ie: users who added a tag automatically rate it as
|
||||
# the default rating. This will only check as far back as the addition of a tag, if a tag has
|
||||
# been added to a context, rated by a user, and then deleted and re-added, the user is not
|
||||
# counted as having rated it (that is, this only checks the latest attachement of a tag).
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to check for tag ratings.
|
||||
# @param tagid The ID of the tag to look for ratings of.
|
||||
# @param userid The ID of the user to look for when checking ratings.
|
||||
# @return true if the user has rated the tag, false otherwise, and undef on error.
|
||||
sub user_has_rated {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $userid = shift;
|
||||
|
||||
# Fetch the history of the tag, sorted in descending chronological order
|
||||
# (ie: latest change first) filtered on the user's id or addition events.
|
||||
# This will mean that the first row fetched is either a rating change by
|
||||
# the user, or an addition event (possibly also by the user), so only one
|
||||
# row is needed to determine whether the user has rated the tag.
|
||||
my $histh = $self -> {"dbh"} -> prepare("SELECT user_id FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_tags_log"}."
|
||||
WHERE metadata_id = ?
|
||||
AND tag_id = ?
|
||||
AND (user_id = ? OR event = 'added')
|
||||
ORDER BY event_time DESC
|
||||
LIMIT 1");
|
||||
$histh -> execute($metadataid, $tagid, $userid)
|
||||
or return $self -> self_error("Unable to perform rating check query: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# If there's no row here, something has gone Badly Wrong (probably the tag isn't attached)
|
||||
my $histrow = $histh -> fetchrow_arrayref();
|
||||
return $self -> self_error("Unexpected empty result from rating check query: no history for $tagid in $metadataid?")
|
||||
if(!$histrow);
|
||||
|
||||
# If the user_id in the fetched row matches $userid, the user has rated the
|
||||
# tag implicitly (by adding it) or explicitly (by up/down rating it)
|
||||
return $histrow -> [0] == $userid;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Private functions
|
||||
|
||||
## @method private $ _attached($metadataid, $tagid)
|
||||
# Determine whether the specified tag is set in the metadata context. This will check
|
||||
# whether the tag has been attached to the specified context, and return true if it is.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to check for the tag.
|
||||
# @param tagid The ID of the tag to look for.
|
||||
# @return true if the tag is attached to the context, false if it is not, and undef on error.
|
||||
sub _attached {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $tagh = $self -> {"dbh"} -> prepare("SELECT id FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}."
|
||||
WHERE metadata_id = ?
|
||||
AND tag_id = ?");
|
||||
$tagh -> execute($metadataid, $tagid)
|
||||
or return $self -> self_error("Unable to execute metadata tag lookup: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
my $tag = $tagh -> fetchrow_arrayref();
|
||||
return defined($tag);
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _fetch_attached_tag($metadataid, $tagid)
|
||||
# Obtain the attachment data for the specified tag on a metadata context. This attempts to
|
||||
# fetch the data associated with an attached tag - who attached it, when, what its current
|
||||
# rating is - and returns a reference to a hash containing that data.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context to check for the tag.
|
||||
# @param tagid The ID of the tag to look for.
|
||||
# @return A reference to a hash containing the attached tag's data, or undef if the tag is
|
||||
# not attached, or on error.
|
||||
sub _fetch_attached_tag {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $tagh = $self -> {"dbh"} -> prepare("SELECT * FROM ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}."
|
||||
WHERE metadata_id = ?
|
||||
AND tag_id = ?");
|
||||
$tagh -> execute($metadataid, $tagid)
|
||||
or return $self -> self_error("Unable to execute metadata tag lookup: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
return $tagh -> fetchrow_hashref();
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _fetch_tagid($name)
|
||||
# Given a tag name, attempt to find a tag record for that name. This will locate the
|
||||
# first defined tag whose name matches the provided name. Note that if there are
|
||||
# duplicate tags in the system, this will never find duplicates - it is guaranteed to
|
||||
# find the tag with the lowest ID whose name matches the provided value, or nothing.
|
||||
#
|
||||
# @param name The name of the tag to find.
|
||||
# @return The ID of the tag with the specified name on success, undef if the tag
|
||||
# does not exist or an error occurred.
|
||||
sub _fetch_tagid {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Does the tag already exist
|
||||
my $tagid = $self -> {"dbh"} -> prepare("SELECT id FROM ".$self -> {"settings"} -> {"database"} -> {"tags"}."
|
||||
WHERE name LIKE ?");
|
||||
$tagid -> execute($name)
|
||||
or return $self -> self_error("Unable to perform tag lookup: ".$self -> {"dbh"} -> errstr);
|
||||
my $tagrow = $tagid -> fetchrow_arrayref();
|
||||
|
||||
# Return the ID if found, undef otherwise
|
||||
return $tagrow ? $tagrow -> [0] : undef;;
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _update_rating($metadataid, $tagid, $userid, $increment)
|
||||
# Update the rating for the tag in the specified metadata context. This increments or
|
||||
# decrements the rating for the tag, marking the specified user as the user doing the
|
||||
# rating change. Note that this does not (and can not) perform any permission checking:
|
||||
# the caller must ensure that the user has permission to rate the tag.
|
||||
#
|
||||
# @param metadataid The ID of the metadata context containing the tag to rate.
|
||||
# @param tagid The ID of the tag to change the rating of.
|
||||
# @param userid The ID of the user performing the rating change.
|
||||
# @param increment If true, the rating is incremented, otherwise it is decremented.
|
||||
# @return true on success, undef otherwise.
|
||||
sub _update_rating {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $userid = shift;
|
||||
my $increment = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
# Get the tag, which will include the current rating and confirm the tag is attached...
|
||||
my $tag = $self -> _fetch_attached_tag($metadataid, $tagid);
|
||||
return undef if($self -> {"errstr"}); # Was an error encountered in the fetch?
|
||||
return $self -> self_error("Unable to update rating for $tagid in $metadataid: tag is not attached|") if(!$tag);
|
||||
|
||||
# Got a tag, update the rating
|
||||
$tag -> {"rating"} += ($increment ? 1 : -1);
|
||||
|
||||
my $rateh = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"metadata_tags"}."
|
||||
SET rating = ?
|
||||
WHERE id = ?");
|
||||
my $rows = $rateh -> execute($tag -> {"rating"}, $tag -> {"id"});
|
||||
return $self -> self_error("Unable to perform rating update: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Rating update failed: no rows modified") if($rows eq "0E0");
|
||||
|
||||
# Rating has been updated, log the update
|
||||
return $self -> _log_action($metadataid, $tagid, "rate ".($increment ? "up" : "down"), $userid, $tag -> {"rating"});
|
||||
}
|
||||
|
||||
|
||||
## @method private $ _log_action($metadataid, $tagid, $event, $userid, $rating)
|
||||
# Log an action on an attached (or newly detached) tag. This allows the history of a tag
|
||||
# to be tracked over its lifetime of attachment to a resource.
|
||||
#
|
||||
# @param metadataid The ID of the metadata the event happened in.
|
||||
# @param tagid The ID of the tag involved in the event.
|
||||
# @param event The event to be logged, must be 'added', 'deleted', 'rate up',
|
||||
# 'rate down', 'activate', or 'deactivate'.
|
||||
# @param userid The ID of the user who caused the event.
|
||||
# @param rating The rating set on the tag after the operation.
|
||||
# @return true on success, undef on error.
|
||||
sub _log_action {
|
||||
my $self = shift;
|
||||
my $metadataid = shift;
|
||||
my $tagid = shift;
|
||||
my $event = shift;
|
||||
my $userid = shift;
|
||||
my $rating = shift;
|
||||
|
||||
$self -> clear_error();
|
||||
|
||||
my $acth = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"metadata_tags_log"}."
|
||||
(metadata_id, tag_id, event, event_user, event_time, rating)
|
||||
VALUES(?, ?, ?, ?, UNIX_TIMESTAMP(), ?)");
|
||||
my $rows = $acth -> execute($metadataid, $tagid, $event, $userid, $rating);
|
||||
return $self -> self_error("Unable to perform metadata tag log insert: ". $self -> {"dbh"} -> errstr) if(!$rows);
|
||||
return $self -> self_error("Metadata tag log insert failed: no rows modified") if($rows eq "0E0");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
1
supportfiles/.htaccess
Executable file
@ -0,0 +1 @@
|
||||
Deny from all
|
2282
supportfiles/Doxyfile
Normal file
194
supportfiles/DoxygenLayout.xml
Normal file
@ -0,0 +1,194 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.8.5 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="" intro=""/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="yes" title="">
|
||||
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||
<tab type="globals" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="no"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title="Class Description"/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
51
supportfiles/SendMessages.pl
Executable file
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/perl -wT
|
||||
|
||||
use strict;
|
||||
use lib qw(/var/www/webperl);
|
||||
use lib qw(../modules);
|
||||
use utf8;
|
||||
|
||||
# System modules
|
||||
use DBI;
|
||||
use Modules;
|
||||
use ConfigMicro;
|
||||
use Logger;
|
||||
use Message::Queue;
|
||||
|
||||
my $logger = Logger -> new()
|
||||
or die "FATAL: Unable to create logger object";
|
||||
|
||||
# Load the system config
|
||||
my $settings = ConfigMicro -> new("../config/site.cfg")
|
||||
or $logger -> die_log("Not avilable", "SendMessages.pl: Unable to obtain configuration file: ".$ConfigMicro::errstr);
|
||||
|
||||
# Database initialisation. Errors in this will kill program.
|
||||
my $dbh = DBI->connect($settings -> {"database"} -> {"database"},
|
||||
$settings -> {"database"} -> {"username"},
|
||||
$settings -> {"database"} -> {"password"},
|
||||
{ RaiseError => 0, AutoCommit => 1, mysql_enable_utf8 => 1 })
|
||||
or $logger -> die_log("None", "SendMessages.pl: Unable to connect to database: ".$DBI::errstr);
|
||||
|
||||
# Pull configuration data out of the database into the settings hash
|
||||
$settings -> load_db_config($dbh, $settings -> {"database"} -> {"settings"});
|
||||
|
||||
# Start database logging if available
|
||||
$logger -> init_database_log($dbh, $settings -> {"database"} -> {"logging"})
|
||||
if($settings -> {"database"} -> {"logging"});
|
||||
|
||||
# Start doing logging if needed
|
||||
$logger -> start_log($settings -> {"config"} -> {"logfile"}) if($settings -> {"config"} -> {"logfile"});
|
||||
|
||||
my $messages = Message::Queue -> new(logger => $logger,
|
||||
dbh => $dbh,
|
||||
settings => $settings)
|
||||
or $logger -> die_log("none", "SendMessages.pl: Unable to create message handler: ".$SystemModule::errstr);
|
||||
|
||||
my $module = Modules -> new(logger => $logger,
|
||||
dbh => $dbh,
|
||||
settings => $settings)
|
||||
or $logger -> die_log("none", "SendMessages.pl: Unable to create module loader: ".$SystemModule::errstr);
|
||||
|
||||
$messages -> set_module_obj($module);
|
||||
|
||||
$messages -> deliver_queue($ARGV[0]);
|
1029
supportfiles/customdoxygen.css
Normal file
157
supportfiles/lang_to_db.pl
Executable file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use lib "/var/www/webperl";
|
||||
|
||||
use DBI;
|
||||
use Webperl::ConfigMicro;
|
||||
use Webperl::Utils qw(path_join superchomp);
|
||||
|
||||
## @fn $ clear_language_table($dbh, $tablename)
|
||||
# Clear the contents of the specified language table. This truncates the table,
|
||||
# erasing all its contents, and resetting the autoincrement for the ID.
|
||||
#
|
||||
# @param dbh The database handle to issue queries through.
|
||||
# @param tablename The name of the database table containing the language variables.
|
||||
# @return undef on success, otherwise an error message.
|
||||
sub clear_language_table {
|
||||
my $dbh = shift;
|
||||
my $tablename = shift;
|
||||
|
||||
my $nukeh = $dbh -> prepare("TRUNCATE `$tablename`");
|
||||
$nukeh -> execute()
|
||||
or return "Unable to clear language table: ".$dbh -> errstr;
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
## @fn $ set_language_variable($dbh, $tablename, $name, $lang, $message)
|
||||
# Set the langauge variable with the specified name and lang to contain
|
||||
# the specified message. This will determine whether the name has already
|
||||
# been set in the specified language, and if so the message will not be
|
||||
# updated, and an error will be returned.
|
||||
#
|
||||
# @param dbh The database handle to issue queries through.
|
||||
# @param tablename The name of the database table containing the language variables.
|
||||
# @param name The name of the language variable.
|
||||
# @param lang The language the variable is being defined in.
|
||||
# @param message The message to set for the language variable.
|
||||
# @return undef on success, otherwise an error message.
|
||||
sub set_language_variable {
|
||||
my ($dbh, $tablename, $name, $lang, $message) = @_;
|
||||
|
||||
# First check that the variable hasn't already been defined
|
||||
my $checkh = $dbh -> prepare("SELECT message FROM `$tablename` WHERE `name` LIKE ? AND `lang` LIKE ?");
|
||||
$checkh -> execute($name, $lang)
|
||||
or return "Unable to perform language variable check: ".$dbh -> errstr;
|
||||
|
||||
my $row = $checkh -> fetchrow_arrayref();
|
||||
return "Redefinition of language variable $name in language $lang (old: '".$row -> [0]."', new: '$message')"
|
||||
if($row);
|
||||
|
||||
# Doesn't exist, make it...
|
||||
my $newh = $dbh -> prepare("INSERT INTO `$tablename` (`name`, `lang`, `message`)
|
||||
VALUES(?, ?, ?)");
|
||||
my $rows = $newh -> execute($name, $lang, $message);
|
||||
return "Unable to perform language variable insert: ". $dbh -> errstr if(!$rows);
|
||||
return "User insert failed, no rows added." if($rows eq "0E0");
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
## @fn $ load_language($dbh, $tablename, $langdir)
|
||||
# Load all of the language files in the appropriate language directory into the
|
||||
# database. This will attempt to load all .lang files inside the langdir/lang/
|
||||
# directory, and store the language variables defined therein in the database.
|
||||
# The database language table is cleared before adding new entries.
|
||||
#
|
||||
# @return true if the language files loaded correctly, undef otherwise.
|
||||
sub load_language {
|
||||
my $dbh = shift;
|
||||
my $tablename = shift;
|
||||
my $langdir = shift;
|
||||
|
||||
my $res = clear_language_table($dbh, $tablename);
|
||||
return $res if($res);
|
||||
|
||||
print "Processing language directories in '$langdir'...\n";
|
||||
|
||||
opendir(LANGDIR, $langdir)
|
||||
or return "Unable to open languages directory '$langdir' for reading: $!";
|
||||
|
||||
my @langs = readdir(LANGDIR);
|
||||
closedir(LANGDIR);
|
||||
|
||||
foreach my $lang (@langs) {
|
||||
next if($lang =~ /^\.+$/);
|
||||
|
||||
my $langsubdir = path_join($langdir, $lang);
|
||||
next unless(-d $langsubdir);
|
||||
|
||||
print "Checking for lang files in '$lang'...\n";
|
||||
|
||||
# open it, so we can process files therein
|
||||
opendir(LANG, $langsubdir)
|
||||
or return "Unable to open language directory '$langsubdir' for reading: $!";
|
||||
|
||||
my @files = readdir(LANG);
|
||||
closedir(LANG);
|
||||
|
||||
foreach my $name (@files) {
|
||||
# Skip anything that doesn't identify itself as a .lang file
|
||||
next unless($name =~ /\.lang$/);
|
||||
|
||||
print "Processing language file '$name'...\n";
|
||||
|
||||
my $filename = path_join($langsubdir, $name);
|
||||
|
||||
# Attempt to open and parse the lang file
|
||||
if(open(WORDFILE, "<:utf8", $filename)) {
|
||||
my @lines = <WORDFILE>;
|
||||
close(WORDFILE);
|
||||
|
||||
foreach my $line (@lines) {
|
||||
superchomp($line);
|
||||
|
||||
# skip comments
|
||||
next if($line =~ /^\s*#/);
|
||||
|
||||
# Pull out the key and value, and
|
||||
my ($key, $value) = $line =~ /^\s*(\w+)\s*=\s*(.*)$/;
|
||||
next unless(defined($key) && defined($value));
|
||||
|
||||
# Unslash any \"s
|
||||
$value =~ s/\\\"/\"/go;
|
||||
|
||||
print "Storing language variable '$key'\n";
|
||||
$res = set_language_variable($dbh, $tablename, $key, $lang, $value);
|
||||
return $res if($res);
|
||||
}
|
||||
} else {
|
||||
return "Unable to open language file $filename: $!";
|
||||
}
|
||||
} # foreach $name (@files) {
|
||||
} # foreach my $lang (@langs) {
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
my $settings = Webperl::ConfigMicro -> new("../config/site.cfg")
|
||||
or die "Unable to open configuration file: ".$Webperl::SystemModule::errstr."\n";
|
||||
|
||||
die "No 'language' table defined in configuration, unable to proceed.\n"
|
||||
unless($settings -> {"database"} -> {"language"});
|
||||
|
||||
my $dbh = DBI->connect($settings -> {"database"} -> {"database"},
|
||||
$settings -> {"database"} -> {"username"},
|
||||
$settings -> {"database"} -> {"password"},
|
||||
{ RaiseError => 0, AutoCommit => 1, mysql_enable_utf8 => 1 })
|
||||
or die "Unable to connect to database: ".$DBI::errstr."\n";
|
||||
|
||||
my $error = load_language($dbh, $settings -> {"database"} -> {"language"}, "../lang")
|
||||
or print "Finished successfully.\n";
|
||||
|
||||
print "Failed: $error\n" if($error);
|
35
supportfiles/perlmod.deps
Executable file
@ -0,0 +1,35 @@
|
||||
Required modules, usually provided within distro repositories:
|
||||
|
||||
Class::Accessor
|
||||
Class::Mix
|
||||
Compress::Bzip2
|
||||
Date-Calc
|
||||
DBI
|
||||
Email::MIME
|
||||
Email::Sender::Simple (in Email-Sender)
|
||||
Email::Sender::Transport::SMTP (in Email-Sender)
|
||||
Email::Sender::Transport::SMTP::Persistent (in Email-Sender)
|
||||
Email::Valid
|
||||
Expect
|
||||
File::Type
|
||||
HTML::Entities (in HTML::Parser)
|
||||
HTML::Scrubber
|
||||
HTML::TokeParser::Simple
|
||||
JSON
|
||||
Net::LDAPS (perl-ldap)
|
||||
Params::Classify
|
||||
Try::Tiny (installed with Email-Sender)
|
||||
WWW::Mechanize
|
||||
XML::Simple
|
||||
|
||||
|
||||
Required modules, usuallny not in repost, install from CPAN:
|
||||
|
||||
MediaWiki::API
|
||||
HTML::FormatText
|
||||
HTML::Tidy (Requires tidyp from http://tidyp.com/ )
|
||||
HTML::WikiConverter::Markdown
|
||||
WebService::Validator::HTML::W3C
|
||||
Crypt::Eksblowfish::Bcrypt
|
||||
Net::SSH::Expect
|
||||
CGI::Compress::Gzip
|
1
templates/default/api/html_error.tem
Executable file
@ -0,0 +1 @@
|
||||
<div id="apierror" class="error ***code***">***info***</div>
|
7
templates/default/api/html_wrapper.tem
Executable file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head profile="http://www.w3.org/2005/10/profile">
|
||||
<title>API Response</title>
|
||||
</head>
|
||||
<body>***data***</body>
|
||||
</html>
|
43
templates/default/css/body.css
Executable file
@ -0,0 +1,43 @@
|
||||
body {
|
||||
font: 100% Verdana, Arial, Helvetica, sans-serif;
|
||||
color: #000;
|
||||
font-size: 13px;
|
||||
min-width: 900px;
|
||||
background-color: #eee;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body, h1, h2, h3, h4, h5 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #0645ad;
|
||||
background: none;
|
||||
}
|
||||
a:visited {
|
||||
color: #0b0080;
|
||||
}
|
||||
a:active {
|
||||
color: #faa700;
|
||||
}
|
||||
a:hover, a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.alignleft {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.alignright {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
167
templates/default/css/button.css
Executable file
@ -0,0 +1,167 @@
|
||||
/* based on http://webdesignerwall.com/tutorials/css3-gradient-buttons */
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */
|
||||
*display: inline;
|
||||
vertical-align: baseline;
|
||||
margin: 0 2px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font: 14px/100% Arial, Helvetica, sans-serif;
|
||||
font-weight: bold;
|
||||
padding: .5em 2em .55em;
|
||||
text-shadow: 0 1px 1px rgba(0,0,0,.3);
|
||||
-webkit-border-radius: .5em;
|
||||
-moz-border-radius: .5em;
|
||||
border-radius: .5em;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
}
|
||||
.button a {
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font: 14px/100% Arial, Helvetica, sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
.button a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.button a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.button:active {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
/* blue */
|
||||
.button.blue {
|
||||
color: #d9eef7;
|
||||
border: solid 1px #0076a3;
|
||||
|
||||
background-color: #0095cd; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #00adee, #0078a5); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #00adee, #0078a5); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #00adee, #0078a5); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #00adee, #0078a5); /* new Webkit */
|
||||
background-image: linear-gradient(top, #00adee, #0078a5); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5');
|
||||
}
|
||||
.button.blue:hover {
|
||||
background-color: #007ead; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #0095cc, #00678e); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #0095cc, #00678e); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #0095cc, #00678e); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#0095cc), to(#00678e)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #0095cc, #00678e); /* new Webkit */
|
||||
background-image: linear-gradient(top, #0095cc, #00678e); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0095cc', endColorstr='#00678e');
|
||||
}
|
||||
.button.blue:active {
|
||||
background-color: #80bed6; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #0078a5, #00adee); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #0078a5, #00adee); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #0078a5, #00adee); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#0078a5), to(#00adee)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #0078a5, #00adee); /* new Webkit */
|
||||
background-image: linear-gradient(top, #0078a5, #00adee); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0078a5', endColorstr='#00adee');
|
||||
}
|
||||
.button.blue a {
|
||||
color: #d9eef7;
|
||||
}
|
||||
|
||||
/* red */
|
||||
.button.red {
|
||||
color: #d9eef7;
|
||||
border: solid 1px #a30000;
|
||||
|
||||
background-color: #cc0015; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #ed0034, #A60000); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #ed0034, #A60000); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #ed0034, #A60000); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ed0034), to(#A60000)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #ed0034, #A60000); /* new Webkit */
|
||||
background-image: linear-gradient(top, #ed0034, #A60000); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ed0034', endColorstr='#A60000');
|
||||
}
|
||||
.button.red:hover {
|
||||
background-color: #ad0000; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #cc0000, #8f0000); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #cc0000, #8f0000); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #cc0000, #8f0000); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#cc0000), to(#8f0000)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #cc0000, #8f0000); /* new Webkit */
|
||||
background-image: linear-gradient(top, #cc0000, #8f0000); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cc0000', endColorstr='#8f0000');
|
||||
}
|
||||
.button.red:active {
|
||||
background-color: #80bed6; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #A60000, #ed0034); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #A60000, #ed0034); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #A60000, #ed0034); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#A60000), to(#ed0034)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #A60000, #ed0034); /* new Webkit */
|
||||
background-image: linear-gradient(top, #A60000, #ed0034); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#A60000', endColorstr='#ed0034');
|
||||
}
|
||||
.button.red a {
|
||||
color: #d9eef7;
|
||||
}
|
||||
|
||||
|
||||
/* disabled */
|
||||
.button.disabled {
|
||||
color: #555;
|
||||
border: solid 1px #a3a3a3;
|
||||
|
||||
background-color: #cdcdcd; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #eeeeee, #a5a5a5); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #eeeeee, #a5a5a5); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #eeeeee, #a5a5a5); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#a5a5a5)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee, #a5a5a5); /* new Webkit */
|
||||
background-image: linear-gradient(top, #eeeeee, #a5a5a5); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#a5a5a5');
|
||||
}
|
||||
|
||||
.button.disabled:hover {
|
||||
color: #555;
|
||||
border: solid 1px #a3a3a3;
|
||||
|
||||
background-color: #cdcdcd; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #eeeeee, #a5a5a5); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #eeeeee, #a5a5a5); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #eeeeee, #a5a5a5); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#a5a5a5)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee, #a5a5a5); /* new Webkit */
|
||||
background-image: linear-gradient(top, #eeeeee, #a5a5a5); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#a5a5a5');
|
||||
}
|
||||
|
||||
.button.disabled:active {
|
||||
color: #555;
|
||||
border: solid 1px #a3a3a3;
|
||||
|
||||
background-color: #cdcdcd; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #eeeeee, #a5a5a5); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #eeeeee, #a5a5a5); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #eeeeee, #a5a5a5); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#a5a5a5)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee, #a5a5a5); /* new Webkit */
|
||||
background-image: linear-gradient(top, #eeeeee, #a5a5a5); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#a5a5a5');
|
||||
}
|
||||
|
||||
.button.disabled a {
|
||||
color: #555;
|
||||
}
|
31
templates/default/css/controls.css
Executable file
@ -0,0 +1,31 @@
|
||||
div.controls {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
ul.controls {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
ul.controls > li {
|
||||
list-style-type: none;
|
||||
padding-left: 5px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.control {
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url('../images/control_sprites.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0px 0px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.control > img {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
border: none;
|
||||
opacity: 0;
|
||||
}
|
333
templates/default/css/core.css
Executable file
@ -0,0 +1,333 @@
|
||||
@charset "utf-8";
|
||||
@import url('body.css'); /* global body styling */
|
||||
@import url('notebox.css'); /* pull in warning/important box styles */
|
||||
@import url('shadowbox.css'); /* and support for shadowed divs */
|
||||
@import url('messagebox.css'); /* support for message boxes */
|
||||
@import url('button.css'); /* button rules (okay?) */
|
||||
@import url('inputglow.css'); /* make input boxes glow when active */
|
||||
@import url('controls.css'); /* sprite-based control buttons */
|
||||
|
||||
.aviary #topbar {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
background-image: url(../images/topbar_bg.png);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.aviary #titleblock {
|
||||
line-height: 36px;
|
||||
float: left;
|
||||
margin-left: 15px;
|
||||
font-weight: bold;
|
||||
padding-right: 10px;
|
||||
background-image: url(../images/topbar_div.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.aviary #topbar ul {
|
||||
float: right;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.aviary #topbar ul li {
|
||||
line-height: 36px;
|
||||
float: left;
|
||||
list-style: none;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
background-image: url(../images/topbar_div.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.aviary .footer {
|
||||
text-align: center;
|
||||
width: 50%;
|
||||
margin: 0px auto;
|
||||
font-size: 11px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.aviary #botbar {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
background-image: url(../images/botbar_bg.png);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.aviary #botbar ul {
|
||||
float: right;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.aviary #botbar ul li {
|
||||
line-height: 46px;
|
||||
float: left;
|
||||
list-style: none;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #leftbar {
|
||||
float: left;
|
||||
width: 5px;
|
||||
height: 46px;
|
||||
background-image: url(../images/botbar_div.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #rightbar {
|
||||
float: right;
|
||||
width: 5px;
|
||||
height: 46px;
|
||||
background-image: url(../images/botbar_div.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #navfloat {
|
||||
float: left;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #navfloat #navbox {
|
||||
margin: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #navfloat #navbox td {
|
||||
padding: 3px 3px;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #navfloat #navbox td.navleft {
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.aviary #botbar #navblock #navinner #navfloat #navbox td.navright {
|
||||
vertical-align: middle;
|
||||
text-align: right;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.aviary #displaycore {
|
||||
padding-top: 36px;
|
||||
padding-bottom: 46px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.aviary #displaycore div.imageframe {
|
||||
position: absolute;
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.aviary #content {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.navpoint {
|
||||
border: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.navend {
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
label.check {
|
||||
font-weight: normal;
|
||||
font-size: 13px;
|
||||
padding-left: 0.75em;
|
||||
}
|
||||
|
||||
.overTxtLabel {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
clear: both;
|
||||
height: 0px;
|
||||
margin: 15px 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
input.fillwide, select.fillwide, textarea.fillwide {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fillwide.lockwide {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
input[type=text].datepick {
|
||||
padding: 4px 4px 4px 23px;
|
||||
background: url(../images/datepicker.png) no-repeat 2px center;
|
||||
}
|
||||
|
||||
input:disabled.datepick {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.submitbox {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
ul.tabs {
|
||||
border-bottom: 1px solid #aaa;
|
||||
margin-bottom: 0px;
|
||||
padding: 0px 0px 2px;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
li.tab {
|
||||
cursor: pointer;
|
||||
display: inline;
|
||||
padding: 4px .4em 2px .4em;
|
||||
list-style: none;
|
||||
border: 1px #ddd solid;
|
||||
border-bottom: 1px #aaa solid;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
li.tab.active {
|
||||
background-color: #fff;
|
||||
border: 1px #aaa solid;
|
||||
}
|
||||
|
||||
div.paginate {
|
||||
text-align: right;
|
||||
margin: 4px auto;
|
||||
}
|
||||
|
||||
div.paginate div.location {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.paginate {
|
||||
display: inline-block;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
ul.paginate li {
|
||||
display: inline;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.paginate li.pagebox {
|
||||
color: #d9eef7;
|
||||
border: solid 1px #0076a3;
|
||||
margin: 0 0;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font: 14px/100% Arial, Helvetica, sans-serif;
|
||||
font-weight: bold;
|
||||
padding: .3em 1em .3em;
|
||||
text-shadow: 0 1px 1px rgba(0,0,0,.3);
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
|
||||
background-color: #0095cd; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #00adee, #0078a5); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #00adee, #0078a5); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #00adee, #0078a5); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #00adee, #0078a5); /* new Webkit */
|
||||
background-image: linear-gradient(top, #00adee, #0078a5); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5');
|
||||
}
|
||||
|
||||
ul.paginate li.pagebox:hover {
|
||||
background-color: #007ead; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #0095cc, #00678e); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #0095cc, #00678e); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #0095cc, #00678e); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#0095cc), to(#00678e)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #0095cc, #00678e); /* new Webkit */
|
||||
background-image: linear-gradient(top, #0095cc, #00678e); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0095cc', endColorstr='#00678e');
|
||||
}
|
||||
|
||||
ul.paginate li.pagebox.disabled, ul.paginate li.pagebox.disabled:hover {
|
||||
color: #888;
|
||||
border: solid 1px #a3a3a3;
|
||||
cursor: auto;
|
||||
|
||||
background-color: #cdcdcd; /* Fallback */
|
||||
background-image: -ms-linear-gradient(top, #eeeeee, #a5a5a5); /* IE10 */
|
||||
background-image: -moz-linear-gradient(top, #eeeeee, #a5a5a5); /* Firefox */
|
||||
background-image: -o-linear-gradient(top, #eeeeee, #a5a5a5); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#a5a5a5)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee, #a5a5a5); /* new Webkit */
|
||||
background-image: linear-gradient(top, #eeeeee, #a5a5a5); /* proposed W3C Markup */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#a5a5a5');
|
||||
}
|
||||
|
||||
ul.paginate li.pagebox a {
|
||||
color: #d9eef7;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
ul.paginate li.pagebox:first-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
ul.paginate li.pagebox:last-child {
|
||||
border-bottom-right-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
li.pagebox.active {
|
||||
}
|
||||
|
||||
code, tt {
|
||||
font-face: fixed;
|
||||
color: #a96300;
|
||||
background: inherit !important;
|
||||
}
|
29
templates/default/css/error.css
Executable file
@ -0,0 +1,29 @@
|
||||
@charset "utf-8";
|
||||
@import url('body.css'); /* global body styling */
|
||||
@import url('notebox.css'); /* pull in warning/important box styles */
|
||||
@import url('shadowbox.css'); /* and support for shadowed divs */
|
||||
@import url('messagebox.css'); /* support for message boxes */
|
||||
@import url('button.css'); /* button rules (okay?) */
|
||||
@import url('userbar.css'); /* Userbar styling. */
|
||||
@import url('inputglow.css'); /* make input boxes glow when active */
|
||||
|
||||
#errorcore {
|
||||
margin: 0px auto;
|
||||
padding: 100px 0px 0px;
|
||||
width: 440px;
|
||||
}
|
||||
|
||||
#errorcore h1#logo a {
|
||||
display: block;
|
||||
width: 141px;
|
||||
height: 78px;
|
||||
background: url('../images/page_layout/logo.png') 50% top no-repeat;
|
||||
padding-bottom: 10px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password] {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 2px;
|
||||
}
|
6
templates/default/css/hotimage.css
Executable file
@ -0,0 +1,6 @@
|
||||
|
||||
img.hotimage {
|
||||
cursor: pointer;
|
||||
border: 0px;
|
||||
margin: 0px 0px;
|
||||
}
|
6
templates/default/css/inputglow.css
Executable file
@ -0,0 +1,6 @@
|
||||
|
||||
input[type=text]:focus, input[type=password]:focus, input[type=checkbox]:focus, textarea:focus {
|
||||
box-shadow: 0 0 5px rgba(0, 0, 255, 1);
|
||||
-webkit-box-shadow: 0 0 5px rgba(0, 0, 255, 1);
|
||||
-moz-box-shadow: 0 0 5px rgba(0, 0, 255, 1);
|
||||
}
|
91
templates/default/css/login.css
Executable file
@ -0,0 +1,91 @@
|
||||
@charset "utf-8";
|
||||
@import url('body.css'); /* global base body styles */
|
||||
@import url('notebox.css'); /* pull in warning/important box styles */
|
||||
@import url('shadowbox.css'); /* and support for shadowed divs */
|
||||
@import url('messagebox.css'); /* support for message boxes */
|
||||
@import url('button.css'); /* button rules (okay?) */
|
||||
@import url('inputglow.css'); /* make input boxes glow when active */
|
||||
|
||||
#logincore {
|
||||
margin: 0px auto;
|
||||
padding: 100px 0px 0px;
|
||||
}
|
||||
|
||||
#logincore h1#logo a {
|
||||
display: block;
|
||||
width: 150px;
|
||||
height: 124px;
|
||||
background: url('../images/logo.png') 50% top no-repeat;
|
||||
padding-bottom: 10px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
div.logincore {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 10px;
|
||||
width: 440px;
|
||||
}
|
||||
|
||||
div.persist {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.loginform {
|
||||
width: 400px;
|
||||
padding: 0px 20px;
|
||||
}
|
||||
.regform {
|
||||
width: 400px;
|
||||
padding: 0px 20px;
|
||||
border-left: 1px solid #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.sbcontent { clear: both; }
|
||||
|
||||
div.entry {
|
||||
text-align: left;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
div.entry label {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
div.entry label input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.submit {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.submit .contextlink {
|
||||
float: left;
|
||||
text-align: left;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
div.persist .contextlink {
|
||||
text-align: left;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
div.loginform {
|
||||
display: inline-block;
|
||||
/*float: left;*/
|
||||
}
|
||||
div.regform {
|
||||
display: inline-block;
|
||||
/*float: left;*/
|
||||
}
|
||||
div.regform.policy {
|
||||
float: right;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password] {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 2px;
|
||||
}
|
46
templates/default/css/messagebox.css
Executable file
@ -0,0 +1,46 @@
|
||||
.messagebox .mcore {
|
||||
width: 100%;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.messagebox > img {
|
||||
padding: 0px;
|
||||
border: none;
|
||||
float: right;
|
||||
margin-top: -2px; /* adjust up slightly to v-centre */
|
||||
}
|
||||
|
||||
.messagebox .mcore .msummary {
|
||||
padding: 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.messagebox .mcore .mtext {
|
||||
padding: 0;
|
||||
margin-top: 0.5em;
|
||||
border: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.messagebox .buttonbox {
|
||||
padding-top: 3px;
|
||||
margin-top: 2px;
|
||||
border-top: 1px solid #ddd;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.messagecore {
|
||||
margin: 100px auto !important;
|
||||
width: 440px;
|
||||
}
|
||||
|
||||
.messagecore h1#logo a {
|
||||
display: block;
|
||||
width: 141px;
|
||||
height: 78px;
|
||||
background: url('../images/page_layout/logo.png') 50% top no-repeat;
|
||||
padding-bottom: 10px;
|
||||
margin: 0px auto;
|
||||
}
|
43
templates/default/css/notebox.css
Executable file
@ -0,0 +1,43 @@
|
||||
table.notebox {
|
||||
margin: 0px 10%; /* 10% = Will not overlap with other elements */
|
||||
border: 1px solid #aaa;
|
||||
border-left: 10px solid #1e90ff; /* Default "notice" blue */
|
||||
background: #fbfbfb;
|
||||
display: block;
|
||||
text-align: left;
|
||||
border-radius: 1px;
|
||||
-moz-box-shadow: 3px 3px 4px rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 3px 3px 4px rgba(0,0,0,0.1);
|
||||
box-shadow: 3px 3px 4px rgba(0,0,0,0.1);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
table.ienotebox {
|
||||
margin: 0px 10%; /* 10% = Will not overlap with other elements */
|
||||
border: 1px solid #aaa;
|
||||
border-left: 10px solid #1e90ff; /* Default "notice" blue */
|
||||
background: #fbfbfb;
|
||||
}
|
||||
|
||||
table.notebox + table.notebox { /* Single border between stacked boxes. */
|
||||
margin-top: -5px;
|
||||
}
|
||||
th.nbox-text,
|
||||
td.nbox-text { /* The message body cell(s) */
|
||||
padding: 0.25em 0.5em; /* 0.5em left/right */
|
||||
}
|
||||
td.nbox-image { /* The left image cell */
|
||||
padding: 2px 0 2px 0.5em; /* 0.5em left, 0px right */
|
||||
}
|
||||
td.nbox-imageright { /* The right image cell */
|
||||
padding: 2px 0.5em 2px 0; /* 0px left, 0.5em right */
|
||||
}
|
||||
|
||||
table.notebox-notice {
|
||||
border-left: 10px solid #1e90ff; /* Blue */
|
||||
}
|
||||
table.notebox-warning {
|
||||
border-left: 10px solid #e1b416; /* Orange */
|
||||
}
|
||||
table.notebox-error {
|
||||
border-left: 10px solid #b22222; /* Red */
|
||||
}
|
47
templates/default/css/orb.css
Executable file
@ -0,0 +1,47 @@
|
||||
#aviary-core {
|
||||
padding-top: 40px;
|
||||
margin: 0px auto;
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
#aviary-core > ul {
|
||||
float: left;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#aviary-core > ul > li {
|
||||
list-style-type: none;
|
||||
margin: 0px 0px 10px 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
dl.input {
|
||||
margin: 5px 0px 0px 0px;
|
||||
}
|
||||
|
||||
dl.input > dt {
|
||||
margin: 0px 0px 6px;
|
||||
}
|
||||
|
||||
dl.input > dd {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
dl.input > dd > select {
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
dl.input > dd > input[type="radio"] {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.submitbox {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
img.workspin {
|
||||
opacity: 0;
|
||||
}
|
40
templates/default/css/shadowbox.css
Executable file
@ -0,0 +1,40 @@
|
||||
.shadowbox {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
-moz-box-shadow: 3px 3px 4px rgba(0,0,0,0.6);
|
||||
-webkit-box-shadow: 3px 3px 4px rgba(0,0,0,0.6);
|
||||
box-shadow: 3px 3px 4px rgba(0,0,0,0.6);
|
||||
margin: 0px 0px 10px;
|
||||
overflow: hidden;
|
||||
padding: 8px 10px 0px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.shadowbox.core {
|
||||
margin: 0px auto;
|
||||
margin-top: 40px;
|
||||
width: 1130px;
|
||||
}
|
||||
|
||||
.shadowbox > h2 {
|
||||
font-size: 14px;
|
||||
margin: 0px;
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.shadowbox div.sbcontent {
|
||||
border-top: 1px solid #eee;
|
||||
color: #000;
|
||||
background: #f4f4f4;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
margin-left: -10px;
|
||||
margin-top: 8px;
|
||||
padding: 5px 10px;
|
||||
width: 100%;
|
||||
clear: both;
|
||||
}
|
249
templates/default/css/userbar.css
Executable file
@ -0,0 +1,249 @@
|
||||
/* CSS rules for the site-wide user bar that appears at the top
|
||||
* of the page. This have been kept separate from site.css and
|
||||
* other stylesheets to reduce madness therein.
|
||||
*
|
||||
* Bits of this are based on, or blatantly lifted from, the WordPress
|
||||
* admin-bar.css under the terms of the GNU GPL v2.
|
||||
*/
|
||||
#userbar {
|
||||
color: #ccc;
|
||||
font: normal 13px/28px Arial,Verdana,sans-serif;
|
||||
height: 28px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
min-width: 900px; /* must match min-width in site.css */
|
||||
z-index: 2317; /* /o\ */
|
||||
|
||||
background-color: #464646; /* Fallback */
|
||||
background-image: -ms-linear-gradient(bottom, #373737, #464646 5px); /* IE10 */
|
||||
background-image: -moz-linear-gradient(bottom, #373737, #464646 5px); /* Firefox */
|
||||
background-image: -o-linear-gradient(bottom, #373737, #464646 5px); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, from(#373737), to(#464646)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(bottom, #373737, #464646 5px); /* new Webkit */
|
||||
background-image: linear-gradient(bottom, #373737, #464646 5px); /* proposed W3C Markup */
|
||||
}
|
||||
|
||||
#userbar * {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: static;
|
||||
line-height: 1;
|
||||
font: normal 13px/28px sans-serif;
|
||||
color: #ccc;
|
||||
text-shadow: #444 0px -1px 0px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* overall container for the bar, has site-options on the left and user-options on the right */
|
||||
#userbar .bar-container {
|
||||
padding-left: 1px;
|
||||
}
|
||||
|
||||
/* float the user-options menus to the right side */
|
||||
#userbar .user-options {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#userbar a, #userbar a:hover, #userbar a img, #userbar a img:hover {
|
||||
outline: none;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#userbar .menu-wrapper, #userbar ul, #userbar ul li {
|
||||
background: none;
|
||||
clear: none;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
#userbar .bar-container ul {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#userbar li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#userbar .bar-container > ul > li {
|
||||
border-right: 1px solid #555;
|
||||
}
|
||||
|
||||
#userbar .bar-container > ul > li > a, #userbar .bar-container > ul > li > .empty-item {
|
||||
border-right: 1px solid #333;
|
||||
}
|
||||
|
||||
#userbar .bar-container .user-options > li {
|
||||
border-left: 1px solid #333;
|
||||
border-right: 0;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#userbar .bar-container .user-options > li > a, #userbar .bar-container .user-options > li > .empty-item {
|
||||
border-left: 1px solid #555;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
#userbar .bar-container a, #userbar .bar-container .empty-item {
|
||||
height: 28px;
|
||||
display: block;
|
||||
padding: 0 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#userbar .menu .menu-wrapper {
|
||||
margin: 0 0 0 -1px;
|
||||
padding: 0;
|
||||
-moz-box-shadow: 3px 3px 4px rgba(0,0,0,0.2);
|
||||
-webkit-box-shadow: 3px 3px 4px rgba(0,0,0,0.2);
|
||||
box-shadow: 3px 3px 4px rgba(0,0,0,0.2);
|
||||
background: #fff;
|
||||
display: none;
|
||||
position: absolute;
|
||||
float: none;
|
||||
border-width: 0 1px 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: #dfdfdf;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#userbar .user-options .menu .menu-wrapper {
|
||||
right: 0;
|
||||
left: auto;
|
||||
margin: 0 -1px 0 0;
|
||||
}
|
||||
|
||||
#userbar .menu-wrapper > .menu-submenu:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#userbar .menu-submenu {
|
||||
padding: 6px 0;
|
||||
border-top: 1px solid #dfdfdf;
|
||||
}
|
||||
|
||||
#userbar .bar-container .menu ul li {
|
||||
float: none;
|
||||
}
|
||||
|
||||
#userbar .top-menu > li.menu:hover > .item, #userbar .top-menu > li.menu.hover > .item {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#userbar .top-menu > li:hover > .item, #userbar .top-menu > li.hover > .item, #userbar .top-menu > li > .item:focus {
|
||||
color: #fafafa;
|
||||
background-color: #3a3a3a; /* Fallback */
|
||||
background-image: -ms-linear-gradient(bottom, #3a3a3a, #222); /* IE10 */
|
||||
background-image: -moz-linear-gradient(bottom, #3a3a3a, #222); /* Firefox */
|
||||
background-image: -o-linear-gradient(bottom, #3a3a3a, #222); /* Opera */
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, from(#3a3a3a), to(#222)); /* old Webkit */
|
||||
background-image: -webkit-linear-gradient(bottom, #3a3a3a, #222); /* new Webkit */
|
||||
background-image: linear-gradient(bottom, #3a3a3a, #222); /* proposed W3C Markup */
|
||||
}
|
||||
|
||||
#userbar .top-menu > li.menu:hover > .item, #userbar .top-menu > li.menu.hover > .item {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#userbar .menu li:hover,
|
||||
#userbar .menu li.hover,
|
||||
#userbar .bar-container .menu .item:focus,
|
||||
#userbar .bar-container .top-menu .menu .item:focus {
|
||||
background-color: #eaf2fa;
|
||||
}
|
||||
|
||||
#userbar .menu-submenu .item {
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#userbar li:hover > .menu-wrapper,
|
||||
#userbar li.hover > .menu-wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#userbar .bar-container .menu ul li .item,
|
||||
#userbar .bar-container .menu ul li a strong,
|
||||
#userbar .bar-container .menu.hover ul li .item,
|
||||
#userbar .bar-container .menu:hover ul li .item {
|
||||
line-height: 26px;
|
||||
height: 26px;
|
||||
text-shadow: none;
|
||||
white-space: nowrap;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
#userbar .bar-container ul li a img.controlicon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* User profile */
|
||||
#userbar #user-profile > a img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #999;
|
||||
padding: 0;
|
||||
background: #eee;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
float: none;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#userbar #profile-actions li {
|
||||
margin-left: 88px;
|
||||
}
|
||||
|
||||
#userbar #user-profile .menu-wrapper .menu-submenu .avatar {
|
||||
position: absolute;
|
||||
left: -72px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
#userbar #profile-display {
|
||||
margin-top: 6px;
|
||||
margin-bottom: 15px;
|
||||
height: auto;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#userbar #profile-display a {
|
||||
background: none;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#userbar #profile-display span {
|
||||
background: none;
|
||||
padding: 0;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#userbar #profile-display .display-name, #userbar #profile-display .username {
|
||||
text-shadow: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#userbar #profile-display .display-name {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#userbar #profile-display .username {
|
||||
color: #999;
|
||||
font-size: 11px;
|
||||
padding-left: 1.5em;
|
||||
}
|
6
templates/default/error/error_box.tem
Executable file
@ -0,0 +1,6 @@
|
||||
<table class="notebox notebox-error">
|
||||
<tr>
|
||||
<td class="nbox-image"><img src="{V_[scriptpath]}templates/default/images/error.png" width="48" height="48" alt="error" /></td>
|
||||
<td class="nbox-text">***message***</td>
|
||||
</tr>
|
||||
</table>
|
1
templates/default/error/error_item.tem
Executable file
@ -0,0 +1 @@
|
||||
<li>***error***</li>
|
2
templates/default/error/error_list.tem
Executable file
@ -0,0 +1,2 @@
|
||||
<div>***message***</div>
|
||||
<ul>***errors***</ul>
|
33
templates/default/error/general.tem
Executable file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>***title***</title>
|
||||
|
||||
<link href="{V_[templatepath]}css/error.css" rel="stylesheet" type="text/css" />
|
||||
|
||||
<!-- mootools for effects and javascript sanity -->
|
||||
<script type='text/javascript' src="{V_[templatepath]}js/mootools-core.js"></script>
|
||||
<script type='text/javascript' src="{V_[templatepath]}js/mootools-more.js"></script>
|
||||
|
||||
<!-- lightface for popup window -->
|
||||
<script type='text/javascript' src="{V_[templatepath]}lightface/LightFaceMod.js"></script>
|
||||
<link href="{V_[templatepath]}lightface/LightFace.css" rel="stylesheet" type="text/css" />
|
||||
|
||||
<!-- userbar support -->
|
||||
<script type='text/javascript' src="{V_[templatepath]}js/userbar.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{V_[templatepath]}css/userbar.css" />
|
||||
|
||||
<!-- favicon -->
|
||||
<link rel="icon" type="image/png" href="{V_[templatepath]}images/favicon.png" />
|
||||
|
||||
***extrahead***
|
||||
</head>
|
||||
<body class="error">
|
||||
<div id="errorcore">
|
||||
<h1 id="logo"><a href="{V_[scriptpath]}" title="{V_[sitename]}"></a></h1>
|
||||
***message***
|
||||
</div>
|
||||
***userbar***
|
||||
</body>
|
||||
</html>
|
BIN
templates/default/images/calendar/addtweet.png
Executable file
After Width: | Height: | Size: 125 B |
BIN
templates/default/images/calendar/next.png
Executable file
After Width: | Height: | Size: 174 B |
BIN
templates/default/images/calendar/previous.png
Executable file
After Width: | Height: | Size: 182 B |
BIN
templates/default/images/control_sprites.png
Executable file
After Width: | Height: | Size: 5.9 KiB |
BIN
templates/default/images/datepicker.png
Executable file
After Width: | Height: | Size: 3.2 KiB |
BIN
templates/default/images/error.png
Executable file
After Width: | Height: | Size: 3.2 KiB |
0
templates/default/images/favicon.png
Executable file
BIN
templates/default/images/feed-icon-14.png
Executable file
After Width: | Height: | Size: 689 B |
BIN
templates/default/images/important.png
Executable file
After Width: | Height: | Size: 3.0 KiB |
BIN
templates/default/images/info.png
Executable file
After Width: | Height: | Size: 3.7 KiB |
BIN
templates/default/images/logo.png
Executable file
After Width: | Height: | Size: 18 KiB |
BIN
templates/default/images/messages/articleok22.png
Executable file
After Width: | Height: | Size: 4.0 KiB |
BIN
templates/default/images/messages/error22.png
Executable file
After Width: | Height: | Size: 995 B |
BIN
templates/default/images/messages/imported22.png
Executable file
After Width: | Height: | Size: 1.1 KiB |
BIN
templates/default/images/messages/permission_error22.png
Executable file
After Width: | Height: | Size: 4.0 KiB |
BIN
templates/default/images/messages/security22.png
Executable file
After Width: | Height: | Size: 3.9 KiB |
BIN
templates/default/images/mode_sprites.png
Executable file
After Width: | Height: | Size: 4.0 KiB |
BIN
templates/default/images/slideknob.png
Executable file
After Width: | Height: | Size: 584 B |
BIN
templates/default/images/spinner.gif
Executable file
After Width: | Height: | Size: 1.8 KiB |
BIN
templates/default/images/tree_closed-hover.png
Executable file
After Width: | Height: | Size: 418 B |
BIN
templates/default/images/tree_closed.png
Executable file
After Width: | Height: | Size: 434 B |
BIN
templates/default/images/tree_open-hover.png
Executable file
After Width: | Height: | Size: 425 B |
BIN
templates/default/images/tree_open.png
Executable file
After Width: | Height: | Size: 427 B |
BIN
templates/default/images/tree_sprites.png
Executable file
After Width: | Height: | Size: 651 B |
19
templates/default/js/Locale.en-GB.DatePicker.js
Executable file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
---
|
||||
name: Locale.en-GB.DatePicker
|
||||
description: British Language File for DatePicker
|
||||
authors: Chris Page
|
||||
requires: [More/Locale]
|
||||
provides: Locale.en-GB.DatePicker
|
||||
...
|
||||
*/
|
||||
|
||||
|
||||
Locale.define('en-GB', 'DatePicker', {
|
||||
select_a_time: 'Select a time',
|
||||
use_mouse_wheel: 'Use the mouse wheel to quickly change value',
|
||||
time_confirm_button: 'OK',
|
||||
apply_range: 'Apply',
|
||||
cancel: 'Cancel',
|
||||
week: 'Wk'
|
||||
});
|
108
templates/default/js/TabPane.js
Executable file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
---
|
||||
description: TabPane Class
|
||||
|
||||
license: MIT-style
|
||||
|
||||
authors: akaIDIOT
|
||||
|
||||
version: 0.5.1
|
||||
|
||||
requires:
|
||||
core/1.4:
|
||||
- Class
|
||||
- Class.Extras
|
||||
- Event
|
||||
- Element
|
||||
- Element.Event
|
||||
- Element.Delegation
|
||||
|
||||
provides: TabPane
|
||||
...
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
// make typeOf usable for MooTools 1.2 through 1.4
|
||||
var typeOf = this.typeOf || this.$type;
|
||||
|
||||
var TabPane = this.TabPane = new Class({
|
||||
|
||||
Implements: [Events, Options],
|
||||
|
||||
options: {
|
||||
tabSelector: '.tab',
|
||||
contentSelector: '.content',
|
||||
activeClass: 'active'
|
||||
},
|
||||
|
||||
container: null,
|
||||
|
||||
initialize: function(container, options, showNow) {
|
||||
this.setOptions(options);
|
||||
|
||||
this.container = document.id(container);
|
||||
// hide all the content parts by default
|
||||
this.container.getElements(this.options.contentSelector).setStyle('display', 'none');
|
||||
|
||||
// add a relayed click event to handle switching tabs
|
||||
this.container.addEvent('click:relay(' + this.options.tabSelector + ')', function(event, tab) {
|
||||
this.show(tab);
|
||||
}.bind(this));
|
||||
|
||||
// determine what tab to show right now (default to the 'leftmost' one)
|
||||
if (typeOf(showNow) == 'function') {
|
||||
showNow = showNow();
|
||||
} else {
|
||||
showNow = showNow || 0;
|
||||
}
|
||||
|
||||
this.show(showNow);
|
||||
},
|
||||
|
||||
get: function(index) {
|
||||
if (typeOf(index) == 'element') {
|
||||
// call get with the index of the supplied element (NB: will break if indexOf returns -1)
|
||||
return this.get(this.indexOf(index));
|
||||
} else {
|
||||
var tab = this.container.getElements(this.options.tabSelector)[index];
|
||||
var content = this.container.getElements(this.options.contentSelector)[index];
|
||||
return [tab, content];
|
||||
}
|
||||
},
|
||||
|
||||
indexOf: function(element) {
|
||||
if (element.match(this.options.tabSelector)) {
|
||||
return this.container.getElements(this.options.tabSelector).indexOf(element);
|
||||
} else if (element.match(this.options.contentSelector)) {
|
||||
return this.container.getElements(this.options.contentSelector).indexOf(element);
|
||||
} else {
|
||||
// element is neither tab nor content, return -1 per convention
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
|
||||
show: function(what) {
|
||||
if (typeOf(what) != 'number') {
|
||||
// turn the argument into its usable form: a number
|
||||
what = this.indexOf(what);
|
||||
}
|
||||
|
||||
// if only JavaScript had tuple unpacking...
|
||||
var items = this.get(what);
|
||||
var tab = items[0];
|
||||
var content = items[1];
|
||||
|
||||
if (tab) {
|
||||
this.container.getElements(this.options.tabSelector).removeClass(this.options.activeClass);
|
||||
this.container.getElements(this.options.contentSelector).setStyle('display', 'none');
|
||||
tab.addClass(this.options.activeClass);
|
||||
content.setStyle('display', 'block');
|
||||
this.fireEvent('change', what);
|
||||
}
|
||||
// no else, not clear what to do
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})();
|
66
templates/default/js/api.js
Executable file
@ -0,0 +1,66 @@
|
||||
/** Generate a request path to send AJAX requests to. This will
|
||||
* automatically compensate for missing url fragments if needed.
|
||||
*
|
||||
* @param block The system block the API is provided by.
|
||||
* @param operation The API operation to perform.
|
||||
* @return A string containing the request path to use.
|
||||
*/
|
||||
function api_request_path(block, operation)
|
||||
{
|
||||
var reqpath = window.location.pathname;
|
||||
|
||||
// First, determine whether the path already contains the block, if so back up to it
|
||||
var blockpos = reqpath.indexOf(block);
|
||||
if(blockpos != -1) {
|
||||
reqpath = reqpath.substring(0, blockpos + block.length);
|
||||
}
|
||||
|
||||
// Ensure the request path has a trailing slash
|
||||
if(reqpath.charAt(reqpath.length - 1) != '/') reqpath += '/';
|
||||
|
||||
// Does the current page end in news/? If not, add it
|
||||
if(!reqpath.test(block+'\/$')) reqpath += (block + "/");
|
||||
|
||||
// Add the api call
|
||||
reqpath += "api/" + operation + "/";
|
||||
|
||||
return reqpath;
|
||||
}
|
||||
|
||||
|
||||
/** Attach a spinner to the specified container, and fade it in.
|
||||
* Once the spinner is no longer needed, you must call hide_spinner()
|
||||
* to remove the spinner (or destroy the container), or horrible things
|
||||
* will happen.
|
||||
*
|
||||
* @param container The container to add the spinner to.
|
||||
* @param position The position to add the spinner in (see Element.inject)
|
||||
*/
|
||||
function show_spinner(container, position)
|
||||
{
|
||||
if(!position) position = 'bottom';
|
||||
|
||||
if(!container.spinimg) {
|
||||
container.spinimg = new Element('img', {src: spinner_url,
|
||||
width: '16',
|
||||
height: '16',
|
||||
'class': 'spinner'});
|
||||
container.spinimg.inject(container, position);
|
||||
container.spinimg.fade('in');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Remove a previously-added spinner from a container. This will
|
||||
* fade out and then destroy a spinner added to the container with
|
||||
* show_spinner().
|
||||
*
|
||||
* @param container The container to remove the spinner from.
|
||||
*/
|
||||
function hide_spinner(container)
|
||||
{
|
||||
if(container.spinimg) {
|
||||
container.spinimg.fade('out').get('tween').chain(function() { container.spinimg.destroy();
|
||||
container.spinimg = null; });
|
||||
}
|
||||
}
|
527
templates/default/js/mootools-core.js
Executable file
@ -0,0 +1,527 @@
|
||||
/*
|
||||
---
|
||||
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
|
||||
|
||||
copyrights:
|
||||
- [MooTools](http://mootools.net)
|
||||
|
||||
licenses:
|
||||
- [MIT License](http://mootools.net/license.txt)
|
||||
...
|
||||
*/
|
||||
|
||||
(function(){this.MooTools={version:"1.4.5",build:"ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0"};var e=this.typeOf=function(i){if(i==null){return"null";}if(i.$family!=null){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 u=this.instanceOf=function(w,i){if(w==null){return false;}var v=w.$constructor||w.constructor;
|
||||
while(v){if(v===i){return true;}v=v.parent;}if(!w.hasOwnProperty){return false;}return w instanceof i;};var f=this.Function;var r=true;for(var q in {toString:1}){r=null;
|
||||
}if(r){r=["hasOwnProperty","valueOf","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","constructor"];}f.prototype.overloadSetter=function(v){var i=this;
|
||||
return function(x,w){if(x==null){return this;}if(v||typeof x!="string"){for(var y in x){i.call(this,y,x[y]);}if(r){for(var z=r.length;z--;){y=r[z];if(x.hasOwnProperty(y)){i.call(this,y,x[y]);
|
||||
}}}}else{i.call(this,x,w);}return this;};};f.prototype.overloadGetter=function(v){var i=this;return function(x){var y,w;if(typeof x!="string"){y=x;}else{if(arguments.length>1){y=arguments;
|
||||
}else{if(v){y=[x];}}}if(y){w={};for(var z=0;z<y.length;z++){w[y[z]]=i.call(this,y[z]);}}else{w=i.call(this,x);}return w;};};f.prototype.extend=function(i,v){this[i]=v;
|
||||
}.overloadSetter();f.prototype.implement=function(i,v){this.prototype[i]=v;}.overloadSetter();var o=Array.prototype.slice;f.from=function(i){return(e(i)=="function")?i:function(){return i;
|
||||
};};Array.from=function(i){if(i==null){return[];}return(k.isEnumerable(i)&&typeof i!="string")?(e(i)=="array")?i:o.call(i):[i];};Number.from=function(v){var i=parseFloat(v);
|
||||
return isFinite(i)?i:null;};String.from=function(i){return i+"";};f.implement({hide:function(){this.$hidden=true;return this;},protect:function(){this.$protected=true;
|
||||
return this;}});var k=this.Type=function(x,w){if(x){var v=x.toLowerCase();var i=function(y){return(e(y)==v);};k["is"+x]=i;if(w!=null){w.prototype.$family=(function(){return v;
|
||||
}).hide();w.type=i;}}if(w==null){return null;}w.extend(this);w.$constructor=k;w.prototype.$constructor=w;return w;};var p=Object.prototype.toString;k.isEnumerable=function(i){return(i!=null&&typeof i.length=="number"&&p.call(i)!="[object Function]");
|
||||
};var b={};var d=function(i){var v=e(i.prototype);return b[v]||(b[v]=[]);};var h=function(w,A){if(A&&A.$hidden){return;}var v=d(this);for(var x=0;x<v.length;
|
||||
x++){var z=v[x];if(e(z)=="type"){h.call(z,w,A);}else{z.call(this,w,A);}}var y=this.prototype[w];if(y==null||!y.$protected){this.prototype[w]=A;}if(this[w]==null&&e(A)=="function"){t.call(this,w,function(i){return A.apply(i,o.call(arguments,1));
|
||||
});}};var t=function(i,w){if(w&&w.$hidden){return;}var v=this[i];if(v==null||!v.$protected){this[i]=w;}};k.implement({implement:h.overloadSetter(),extend:t.overloadSetter(),alias:function(i,v){h.call(this,i,this.prototype[v]);
|
||||
}.overloadSetter(),mirror:function(i){d(this).push(i);return this;}});new k("Type",k);var c=function(v,A,y){var x=(A!=Object),E=A.prototype;if(x){A=new k(v,A);
|
||||
}for(var B=0,z=y.length;B<z;B++){var F=y[B],D=A[F],C=E[F];if(D){D.protect();}if(x&&C){A.implement(F,C.protect());}}if(x){var w=E.propertyIsEnumerable(y[0]);
|
||||
A.forEachMethod=function(J){if(!w){for(var I=0,G=y.length;I<G;I++){J.call(E,E[y[I]],y[I]);}}for(var H in E){J.call(E,E[H],H);}};}return c;};c("String",String,["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","indexOf","lastIndexOf","filter","forEach","every","map","some","reduce","reduceRight"])("Number",Number,["toExponential","toFixed","toLocaleString","toPrecision"])("Function",f,["apply","call","bind"])("RegExp",RegExp,["exec","test"])("Object",Object,["create","defineProperty","defineProperties","keys","getPrototypeOf","getOwnPropertyDescriptor","getOwnPropertyNames","preventExtensions","isExtensible","seal","isSealed","freeze","isFrozen"])("Date",Date,["now"]);
|
||||
Object.extend=t.overloadSetter();Date.extend("now",function(){return +(new Date);});new k("Boolean",Boolean);Number.prototype.$family=function(){return isFinite(this)?"number":"null";
|
||||
}.hide();Number.extend("random",function(v,i){return Math.floor(Math.random()*(i-v+1)+v);});var l=Object.prototype.hasOwnProperty;Object.extend("forEach",function(i,w,x){for(var v in i){if(l.call(i,v)){w.call(x,i[v],v,i);
|
||||
}}});Object.each=Object.forEach;Array.implement({forEach:function(x,y){for(var w=0,v=this.length;w<v;w++){if(w in this){x.call(y,this[w],w,this);}}},each:function(i,v){Array.forEach(this,i,v);
|
||||
return this;}});var s=function(i){switch(e(i)){case"array":return i.clone();case"object":return Object.clone(i);default:return i;}};Array.implement("clone",function(){var v=this.length,w=new Array(v);
|
||||
while(v--){w[v]=s(this[v]);}return w;});var a=function(v,i,w){switch(e(w)){case"object":if(e(v[i])=="object"){Object.merge(v[i],w);}else{v[i]=Object.clone(w);
|
||||
}break;case"array":v[i]=w.clone();break;default:v[i]=w;}return v;};Object.extend({merge:function(C,y,x){if(e(y)=="string"){return a(C,y,x);}for(var B=1,w=arguments.length;
|
||||
B<w;B++){var z=arguments[B];for(var A in z){a(C,A,z[A]);}}return C;},clone:function(i){var w={};for(var v in i){w[v]=s(i[v]);}return w;},append:function(z){for(var y=1,w=arguments.length;
|
||||
y<w;y++){var v=arguments[y]||{};for(var x in v){z[x]=v[x];}}return z;}});["Object","WhiteSpace","TextNode","Collection","Arguments"].each(function(i){new k(i);
|
||||
});var j=Date.now();String.extend("uniqueID",function(){return(j++).toString(36);});var g=this.Hash=new k("Hash",function(i){if(e(i)=="hash"){i=Object.clone(i.getClean());
|
||||
}for(var v in i){this[v]=i[v];}return this;});g.implement({forEach:function(i,v){Object.forEach(this,i,v);},getClean:function(){var v={};for(var i in this){if(this.hasOwnProperty(i)){v[i]=this[i];
|
||||
}}return v;},getLength:function(){var v=0;for(var i in this){if(this.hasOwnProperty(i)){v++;}}return v;}});g.alias("each","forEach");Object.type=k.isObject;
|
||||
var n=this.Native=function(i){return new k(i.name,i.initialize);};n.type=k.type;n.implement=function(x,v){for(var w=0;w<x.length;w++){x[w].implement(v);
|
||||
}return n;};var m=Array.type;Array.type=function(i){return u(i,Array)||m(i);};this.$A=function(i){return Array.from(i).slice();};this.$arguments=function(v){return function(){return arguments[v];
|
||||
};};this.$chk=function(i){return !!(i||i===0);};this.$clear=function(i){clearTimeout(i);clearInterval(i);return null;};this.$defined=function(i){return(i!=null);
|
||||
};this.$each=function(w,v,x){var i=e(w);((i=="arguments"||i=="collection"||i=="array"||i=="elements")?Array:Object).each(w,v,x);};this.$empty=function(){};
|
||||
this.$extend=function(v,i){return Object.append(v,i);};this.$H=function(i){return new g(i);};this.$merge=function(){var i=Array.slice(arguments);i.unshift({});
|
||||
return Object.merge.apply(null,i);};this.$lambda=f.from;this.$mixin=Object.merge;this.$random=Number.random;this.$splat=Array.from;this.$time=Date.now;
|
||||
this.$type=function(i){var v=e(i);if(v=="elements"){return"array";}return(v=="null")?false:v;};this.$unlink=function(i){switch(e(i)){case"object":return Object.clone(i);
|
||||
case"array":return Array.clone(i);case"hash":return new g(i);default:return i;}};})();Array.implement({every:function(c,d){for(var b=0,a=this.length>>>0;
|
||||
b<a;b++){if((b in this)&&!c.call(d,this[b],b,this)){return false;}}return true;},filter:function(d,f){var c=[];for(var e,b=0,a=this.length>>>0;b<a;b++){if(b in this){e=this[b];
|
||||
if(d.call(f,e,b,this)){c.push(e);}}}return c;},indexOf:function(c,d){var b=this.length>>>0;for(var a=(d<0)?Math.max(0,b+d):d||0;a<b;a++){if(this[a]===c){return a;
|
||||
}}return -1;},map:function(c,e){var d=this.length>>>0,b=Array(d);for(var a=0;a<d;a++){if(a in this){b[a]=c.call(e,this[a],a,this);}}return b;},some:function(c,d){for(var b=0,a=this.length>>>0;
|
||||
b<a;b++){if((b in this)&&c.call(d,this[b],b,this)){return true;}}return false;},clean:function(){return this.filter(function(a){return a!=null;});},invoke:function(a){var b=Array.slice(arguments,1);
|
||||
return this.map(function(c){return c[a].apply(c,b);});},associate:function(c){var d={},b=Math.min(this.length,c.length);for(var a=0;a<b;a++){d[c[a]]=this[a];
|
||||
}return d;},link:function(c){var a={};for(var e=0,b=this.length;e<b;e++){for(var d in c){if(c[d](this[e])){a[d]=this[e];delete c[d];break;}}}return a;},contains:function(a,b){return this.indexOf(a,b)!=-1;
|
||||
},append:function(a){this.push.apply(this,a);return this;},getLast:function(){return(this.length)?this[this.length-1]:null;},getRandom:function(){return(this.length)?this[Number.random(0,this.length-1)]:null;
|
||||
},include:function(a){if(!this.contains(a)){this.push(a);}return this;},combine:function(c){for(var b=0,a=c.length;b<a;b++){this.include(c[b]);}return this;
|
||||
},erase:function(b){for(var a=this.length;a--;){if(this[a]===b){this.splice(a,1);}}return this;},empty:function(){this.length=0;return this;},flatten:function(){var d=[];
|
||||
for(var b=0,a=this.length;b<a;b++){var c=typeOf(this[b]);if(c=="null"){continue;}d=d.concat((c=="array"||c=="collection"||c=="arguments"||instanceOf(this[b],Array))?Array.flatten(this[b]):this[b]);
|
||||
}return d;},pick:function(){for(var b=0,a=this.length;b<a;b++){if(this[b]!=null){return this[b];}}return null;},hexToRgb:function(b){if(this.length!=3){return null;
|
||||
}var a=this.map(function(c){if(c.length==1){c+=c;}return c.toInt(16);});return(b)?a:"rgb("+a+")";},rgbToHex:function(d){if(this.length<3){return null;}if(this.length==4&&this[3]==0&&!d){return"transparent";
|
||||
}var b=[];for(var a=0;a<3;a++){var c=(this[a]-0).toString(16);b.push((c.length==1)?"0"+c:c);}return(d)?b:"#"+b.join("");}});Array.alias("extend","append");
|
||||
var $pick=function(){return Array.from(arguments).pick();};String.implement({test:function(a,b){return((typeOf(a)=="regexp")?a:new RegExp(""+a,b)).test(this);
|
||||
},contains:function(a,b){return(b)?(b+this+b).indexOf(b+a+b)>-1:String(this).indexOf(a)>-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(a){return a.charAt(1).toUpperCase();
|
||||
});},hyphenate:function(){return String(this).replace(/[A-Z]/g,function(a){return("-"+a.charAt(0).toLowerCase());});},capitalize:function(){return String(this).replace(/\b[a-z]/g,function(a){return a.toUpperCase();
|
||||
});},escapeRegExp:function(){return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1");},toInt:function(a){return parseInt(this,a||10);},toFloat:function(){return parseFloat(this);
|
||||
},hexToRgb:function(b){var a=String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);return(a)?a.slice(1).hexToRgb(b):null;},rgbToHex:function(b){var a=String(this).match(/\d{1,3}/g);
|
||||
return(a)?a.rgbToHex(b):null;},substitute:function(a,b){return String(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;a<this;a++){b.call(c,a,this);}},toFloat:function(){return parseFloat(this);},toInt:function(a){return parseInt(this,a||10);
|
||||
}});Number.alias("each","times");(function(b){var a={};b.each(function(c){if(!Number[c]){a[c]=function(){return Math[c].apply(null,[this].concat(Array.from(arguments)));
|
||||
};}});Number.implement(a);})(["abs","acos","asin","atan","atan2","ceil","cos","exp","floor","log","max","min","pow","sin","sqrt","tan"]);Function.extend({attempt:function(){for(var b=0,a=arguments.length;
|
||||
b<a;b++){try{return arguments[b]();}catch(c){}}return null;}});Function.implement({attempt:function(a,c){try{return this.apply(c,Array.from(a));}catch(b){}return null;
|
||||
},bind:function(e){var a=this,b=arguments.length>1?Array.slice(arguments,1):null,d=function(){};var c=function(){var g=e,h=arguments.length;if(this instanceof c){d.prototype=a.prototype;
|
||||
g=new d;}var f=(!b&&!h)?a.call(g):a.apply(g,b&&h?b.concat(Array.slice(arguments)):b||arguments);return g==e?f:g;};return c;},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);}});delete Function.prototype.bind;Function.implement({create:function(b){var a=this;
|
||||
b=b||{};return function(d){var c=b.arguments;c=(c!=null)?Array.from(c):Array.slice(arguments,(b.event)?1:0);if(b.event){c=[d||window.event].extend(c);}var e=function(){return a.apply(b.bind||null,c);
|
||||
};if(b.delay){return setTimeout(e,b.delay);}if(b.periodical){return setInterval(e,b.periodical);}if(b.attempt){return Function.attempt(e);}return e();};
|
||||
},bind:function(c,b){var a=this;if(b!=null){b=Array.from(b);}return function(){return a.apply(c,b||arguments);};},bindWithEvent:function(c,b){var a=this;
|
||||
if(b!=null){b=Array.from(b);}return function(d){return a.apply(c,(b==null)?arguments:[d].concat(b));};},run:function(a,b){return this.apply(b,Array.from(a));
|
||||
}});if(Object.create==Function.prototype.create){Object.create=null;}var $try=Function.attempt;(function(){var a=Object.prototype.hasOwnProperty;Object.extend({subset:function(d,g){var f={};
|
||||
for(var e=0,b=g.length;e<b;e++){var c=g[e];if(c in d){f[c]=d[c];}}return f;},map:function(b,e,f){var d={};for(var c in b){if(a.call(b,c)){d[c]=e.call(f,b[c],c,b);
|
||||
}}return d;},filter:function(b,e,g){var d={};for(var c in b){var f=b[c];if(a.call(b,c)&&e.call(g,f,c,b)){d[c]=f;}}return d;},every:function(b,d,e){for(var c in b){if(a.call(b,c)&&!d.call(e,b[c],c)){return false;
|
||||
}}return true;},some:function(b,d,e){for(var c in b){if(a.call(b,c)&&d.call(e,b[c],c)){return true;}}return false;},keys:function(b){var d=[];for(var c in b){if(a.call(b,c)){d.push(c);
|
||||
}}return d;},values:function(c){var b=[];for(var d in c){if(a.call(c,d)){b.push(c[d]);}}return b;},getLength:function(b){return Object.keys(b).length;},keyOf:function(b,d){for(var c in b){if(a.call(b,c)&&b[c]===d){return c;
|
||||
}}return null;},contains:function(b,c){return Object.keyOf(b,c)!=null;},toQueryString:function(b,c){var d=[];Object.each(b,function(h,g){if(c){g=c+"["+g+"]";
|
||||
}var f;switch(typeOf(h)){case"object":f=Object.toQueryString(h,g);break;case"array":var e={};h.each(function(k,j){e[j]=k;});f=Object.toQueryString(e,g);
|
||||
break;default:f=g+"="+encodeURIComponent(h);}if(h!=null){d.push(f);}});return d.join("&");}});})();Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(a){return Object.keyOf(this,a);
|
||||
},hasValue:function(a){return Object.contains(this,a);},extend:function(a){Hash.each(a||{},function(c,b){Hash.set(this,b,c);},this);return this;},combine:function(a){Hash.each(a||{},function(c,b){Hash.include(this,b,c);
|
||||
},this);return this;},erase:function(a){if(this.hasOwnProperty(a)){delete this[a];}return this;},get:function(a){return(this.hasOwnProperty(a))?this[a]:null;
|
||||
},set:function(a,b){if(!this[a]||this.hasOwnProperty(a)){this[a]=b;}return this;},empty:function(){Hash.each(this,function(b,a){delete this[a];},this);
|
||||
return this;},include:function(a,b){if(this[a]==null){this[a]=b;}return this;},map:function(a,b){return new Hash(Object.map(this,a,b));},filter:function(a,b){return new Hash(Object.filter(this,a,b));
|
||||
},every:function(a,b){return Object.every(this,a,b);},some:function(a,b){return Object.some(this,a,b);},getKeys:function(){return Object.keys(this);},getValues:function(){return Object.values(this);
|
||||
},toQueryString:function(a){return Object.toQueryString(this,a);}});Hash.extend=Object.append;Hash.alias({indexOf:"keyOf",contains:"hasValue"});(function(){var k=this.document;
|
||||
var h=k.window=this;var a=navigator.userAgent.toLowerCase(),b=navigator.platform.toLowerCase(),i=a.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0],f=i[1]=="ie"&&k.documentMode;
|
||||
var o=this.Browser={extend:Function.prototype.extend,name:(i[1]=="version")?i[3]:i[1],version:f||parseFloat((i[1]=="opera"&&i[4])?i[4]:i[2]),Platform:{name:a.match(/ip(?:ad|od|hone)/)?"ios":(a.match(/(?:webos|android)/)||b.match(/mac|win|linux/)||["other"])[0]},Features:{xpath:!!(k.evaluate),air:!!(h.runtime),query:!!(k.querySelector),json:!!(h.JSON)},Plugins:{}};
|
||||
o[o.name]=true;o[o.name+parseInt(o.version,10)]=true;o.Platform[o.Platform.name]=true;o.Request=(function(){var q=function(){return new XMLHttpRequest();
|
||||
};var p=function(){return new ActiveXObject("MSXML2.XMLHTTP");};var e=function(){return new ActiveXObject("Microsoft.XMLHTTP");};return Function.attempt(function(){q();
|
||||
return q;},function(){p();return p;},function(){e();return e;});})();o.Features.xhr=!!(o.Request);var j=(Function.attempt(function(){return navigator.plugins["Shockwave Flash"].description;
|
||||
},function(){return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version");})||"0 r0").match(/\d+/g);o.Plugins.Flash={version:Number(j[0]||"0."+j[1])||0,build:Number(j[2])||0};
|
||||
o.exec=function(p){if(!p){return p;}if(h.execScript){h.execScript(p);}else{var e=k.createElement("script");e.setAttribute("type","text/javascript");e.text=p;
|
||||
k.head.appendChild(e);k.head.removeChild(e);}return p;};String.implement("stripScripts",function(p){var e="";var q=this.replace(/<script[^>]*>([\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){h[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 c=function(){this.detachEvent("onunload",c);
|
||||
k.head=k.html=k.window=null;};this.attachEvent("onunload",c);}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));};});}if(o.Platform.ios){o.Platform.ipod=true;}o.Engine={};var d=function(p,e){o.Engine.name=p;
|
||||
o.Engine[p+e]=true;o.Engine.version=e;};if(o.ie){o.Engine.trident=true;switch(o.version){case 6:d("trident",4);break;case 7:d("trident",5);break;case 8:d("trident",6);
|
||||
}}if(o.firefox){o.Engine.gecko=true;if(o.version>=3){d("gecko",19);}else{d("gecko",18);}}if(o.safari||o.chrome){o.Engine.webkit=true;switch(o.version){case 2:d("webkit",419);
|
||||
break;case 3:d("webkit",420);break;case 4:d("webkit",525);}}if(o.opera){o.Engine.presto=true;if(o.version>=9.6){d("presto",960);}else{if(o.version>=9.5){d("presto",950);
|
||||
}else{d("presto",925);}}}if(o.name=="unknown"){switch((a.match(/(?:webkit|khtml|gecko)/)||[])[0]){case"webkit":case"khtml":o.Engine.webkit=true;break;case"gecko":o.Engine.gecko=true;
|
||||
}}this.$exec=o.exec;})();(function(){var b={};var a=this.DOMEvent=new Type("DOMEvent",function(c,g){if(!g){g=window;}c=c||g.event;if(c.$extended){return c;
|
||||
}this.event=c;this.$extended=true;this.shift=c.shiftKey;this.control=c.ctrlKey;this.alt=c.altKey;this.meta=c.metaKey;var i=this.type=c.type;var h=c.target||c.srcElement;
|
||||
while(h&&h.nodeType==3){h=h.parentNode;}this.target=document.id(h);if(i.indexOf("key")==0){var d=this.code=(c.which||c.keyCode);this.key=b[d]||Object.keyOf(Event.Keys,d);
|
||||
if(i=="keydown"){if(d>111&&d<124){this.key="f"+(d-111);}else{if(d>95&&d<106){this.key=d-96;}}}if(this.key==null){this.key=String.fromCharCode(d).toLowerCase();
|
||||
}}else{if(i=="click"||i=="dblclick"||i=="contextmenu"||i=="DOMMouseScroll"||i.indexOf("mouse")==0){var j=g.document;j=(!j.compatMode||j.compatMode=="CSS1Compat")?j.html:j.body;
|
||||
this.page={x:(c.pageX!=null)?c.pageX:c.clientX+j.scrollLeft,y:(c.pageY!=null)?c.pageY:c.clientY+j.scrollTop};this.client={x:(c.pageX!=null)?c.pageX-g.pageXOffset:c.clientX,y:(c.pageY!=null)?c.pageY-g.pageYOffset:c.clientY};
|
||||
if(i=="DOMMouseScroll"||i=="mousewheel"){this.wheel=(c.wheelDelta)?c.wheelDelta/120:-(c.detail||0)/3;}this.rightClick=(c.which==3||c.button==2);if(i=="mouseover"||i=="mouseout"){var k=c.relatedTarget||c[(i=="mouseover"?"from":"to")+"Element"];
|
||||
while(k&&k.nodeType==3){k=k.parentNode;}this.relatedTarget=document.id(k);}}else{if(i.indexOf("touch")==0||i.indexOf("gesture")==0){this.rotation=c.rotation;
|
||||
this.scale=c.scale;this.targetTouches=c.targetTouches;this.changedTouches=c.changedTouches;var f=this.touches=c.touches;if(f&&f[0]){var e=f[0];this.page={x:e.pageX,y:e.pageY};
|
||||
this.client={x:e.clientX,y:e.clientY};}}}}if(!this.client){this.client={};}if(!this.page){this.page={};}});a.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;}});a.defineKey=function(d,c){b[d]=c;return this;};a.defineKeys=a.defineKey.overloadSetter(true);a.defineKeys({"38":"up","40":"down","37":"left","39":"right","27":"esc","32":"space","8":"backspace","9":"tab","46":"delete","13":"enter"});
|
||||
})();var Event=DOMEvent;Event.Keys={};Event.Keys=new Hash(Event.Keys);(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);
|
||||
if(c==$empty){return this;}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<r.length;p++){var t=r[p];var q={parts:[],tag:"*",combinator:i(t[0].combinator)};for(var o=0;o<t.length;
|
||||
o++){var s=t[o];if(!s.reverseCombinator){s.reverseCombinator=" ";}s.combinator=s.reverseCombinator;delete s.reverseCombinator;}t.reverse().push(q);}return u;
|
||||
};var f=function(o){return o.replace(/[-[\]{}()*+?.\\^$|,#\s]/g,function(p){return"\\"+p;});};var j=new RegExp("^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)".replace(/<combinator>/,"["+f(">+~`!@$%^&={}\\;</")+"]").replace(/<unicode>/g,"(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])").replace(/<unicode1>/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 k={},m={},d=Object.prototype.toString;
|
||||
k.isNativeCode=function(c){return(/\{\s*\[native code\]\s*\}/).test(""+c);};k.isXML=function(c){return(!!c.xmlVersion)||(!!c.xml)||(d.call(c)=="[object XMLDocument]")||(c.nodeType==9&&c.documentElement.nodeName!="HTML");
|
||||
};k.setDocument=function(w){var p=w.nodeType;if(p==9){}else{if(p){w=w.ownerDocument;}else{if(w.navigator){w=w.document;}else{return;}}}if(this.document===w){return;
|
||||
}this.document=w;var A=w.documentElement,o=this.getUIDXML(A),s=m[o],r;if(s){for(r in s){this[r]=s[r];}return;}s=m[o]={};s.root=A;s.isXMLDocument=this.isXML(w);
|
||||
s.brokenStarGEBTN=s.starSelectsClosedQSA=s.idGetsName=s.brokenMixedCaseQSA=s.brokenGEBCN=s.brokenCheckedQSA=s.brokenEmptyAttributeQSA=s.isHTMLDocument=s.nativeMatchesSelector=false;
|
||||
var q,u,y,z,t;var x,v="slick_uniqueid";var c=w.createElement("div");var n=w.body||w.getElementsByTagName("body")[0]||A;n.appendChild(c);try{c.innerHTML='<a id="'+v+'"></a>';
|
||||
s.isHTMLDocument=!!w.getElementById(v);}catch(C){}if(s.isHTMLDocument){c.style.display="none";c.appendChild(w.createComment(""));u=(c.getElementsByTagName("*").length>1);
|
||||
try{c.innerHTML="foo</foo>";x=c.getElementsByTagName("*");q=(x&&!!x.length&&x[0].nodeName.charAt(0)=="/");}catch(C){}s.brokenStarGEBTN=u||q;try{c.innerHTML='<a name="'+v+'"></a><b id="'+v+'"></b>';
|
||||
s.idGetsName=w.getElementById(v)===c.firstChild;}catch(C){}if(c.getElementsByClassName){try{c.innerHTML='<a class="f"></a><a class="b"></a>';c.getElementsByClassName("b").length;
|
||||
c.firstChild.className="b";z=(c.getElementsByClassName("b").length!=2);}catch(C){}try{c.innerHTML='<a class="a"></a><a class="f b a"></a>';y=(c.getElementsByClassName("a").length!=2);
|
||||
}catch(C){}s.brokenGEBCN=z||y;}if(c.querySelectorAll){try{c.innerHTML="foo</foo>";x=c.querySelectorAll("*");s.starSelectsClosedQSA=(x&&!!x.length&&x[0].nodeName.charAt(0)=="/");
|
||||
}catch(C){}try{c.innerHTML='<a class="MiX"></a>';s.brokenMixedCaseQSA=!c.querySelectorAll(".MiX").length;}catch(C){}try{c.innerHTML='<select><option selected="selected">a</option></select>';
|
||||
s.brokenCheckedQSA=(c.querySelectorAll(":checked").length==0);}catch(C){}try{c.innerHTML='<a class=""></a>';s.brokenEmptyAttributeQSA=(c.querySelectorAll('[class*=""]').length!=0);
|
||||
}catch(C){}}try{c.innerHTML='<form action="s"><input id="action"/></form>';t=(c.firstChild.getAttribute("action")!="s");}catch(C){}s.nativeMatchesSelector=A.matchesSelector||A.mozMatchesSelector||A.webkitMatchesSelector;
|
||||
if(s.nativeMatchesSelector){try{s.nativeMatchesSelector.call(A,":slick");s.nativeMatchesSelector=null;}catch(C){}}}try{A.slick_expando=1;delete A.slick_expando;
|
||||
s.getUID=this.getUIDHTML;}catch(C){s.getUID=this.getUIDXML;}n.removeChild(c);c=x=n=null;s.getAttribute=(s.isHTMLDocument&&t)?function(G,E){var H=this.attributeGetters[E];
|
||||
if(H){return H.call(G);}var F=G.getAttributeNode(E);return(F)?F.nodeValue:null;}:function(F,E){var G=this.attributeGetters[E];return(G)?G.call(F):F.getAttribute(E);
|
||||
};s.hasAttribute=(A&&this.isNativeCode(A.hasAttribute))?function(F,E){return F.hasAttribute(E);}:function(F,E){F=F.getAttributeNode(E);return !!(F&&(F.specified||F.nodeValue));
|
||||
};var D=A&&this.isNativeCode(A.contains),B=w&&this.isNativeCode(w.contains);s.contains=(D&&B)?function(E,F){return E.contains(F);}:(D&&!B)?function(E,F){return E===F||((E===w)?w.documentElement:E).contains(F);
|
||||
}:(A&&A.compareDocumentPosition)?function(E,F){return E===F||!!(E.compareDocumentPosition(F)&16);}:function(E,F){if(F){do{if(F===E){return true;}}while((F=F.parentNode));
|
||||
}return false;};s.documentSorter=(A.compareDocumentPosition)?function(F,E){if(!F.compareDocumentPosition||!E.compareDocumentPosition){return 0;}return F.compareDocumentPosition(E)&4?-1:F===E?0:1;
|
||||
}:("sourceIndex" in A)?function(F,E){if(!F.sourceIndex||!E.sourceIndex){return 0;}return F.sourceIndex-E.sourceIndex;}:(w.createRange)?function(H,F){if(!H.ownerDocument||!F.ownerDocument){return 0;
|
||||
}var G=H.ownerDocument.createRange(),E=F.ownerDocument.createRange();G.setStart(H,0);G.setEnd(H,0);E.setStart(F,0);E.setEnd(F,0);return G.compareBoundaryPoints(Range.START_TO_END,E);
|
||||
}:null;A=null;for(r in s){this[r]=s[r];}};var f=/^([#.]?)((?:[\w-]+|\*))$/,h=/\[.+[*$^]=(?:""|'')?\]/,g={};k.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(f);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)"+e.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||g[z]||this.brokenMixedCaseQSA||(this.brokenCheckedQSA&&z.indexOf(":checked")>-1)||(this.brokenEmptyAttributeQSA&&h.test(z))||(!y&&z.indexOf(",")>-1)||e.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){g[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;L<K;L++){this[B](N[L],J,D,q,G,W,c);if(p.length){break search;}}}else{for(L=0,K=N.length;L<K;L++){this[B](N[L],J,D,q,G,W,c);
|
||||
}}}N=this.found;}}if(I||(F.expressions.length>1)){this.sort(p);}return(s)?(p[0]||null):p;};k.uidx=1;k.uidk="slick-uniqueid";k.getUIDXML=function(n){var c=n.getAttribute(this.uidk);
|
||||
if(!c){c=this.uidx++;n.setAttribute(this.uidk,c);}return c;};k.getUIDHTML=function(c){return c.uniqueNumber||(c.uniqueNumber=this.uidx++);};k.sort=function(c){if(!this.documentSorter){return c;
|
||||
}c.sort(this.documentSorter);return c;};k.cacheNTH={};k.matchNTH=/^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;k.parseNTHArgument=function(q){var o=q.match(this.matchNTH);
|
||||
if(!o){return false;}var p=o[2]||false;var n=o[1]||1;if(n=="-"){n=-1;}var c=+o[3]||0;o=(p=="n")?{a:n,b:c}:(p=="odd")?{a:2,b:1}:(p=="even")?{a:2,b:0}:{a:0,b:n};
|
||||
return(this.cacheNTH[q]=o);};k.createNTHPseudo=function(p,n,c,o){return function(s,q){var u=this.getUID(s);if(!this[c][u]){var A=s.parentNode;if(!A){return false;
|
||||
}var r=A[p],t=1;if(o){var z=s.nodeName;do{if(r.nodeName!=z){continue;}this[c][this.getUID(r)]=t++;}while((r=r[n]));}else{do{if(r.nodeType!=1){continue;
|
||||
}this[c][this.getUID(r)]=t++;}while((r=r[n]));}}q=q||"n";var v=this.cacheNTH[q]||this.parseNTHArgument(q);if(!v){return false;}var y=v.a,x=v.b,w=this[c][u];
|
||||
if(y==0){return x==w;}if(y>0){if(w<x){return false;}}else{if(x<w){return false;}}return((w-x)%y)==0;};};k.pushArray=function(p,c,r,o,n,q){if(this.matchSelector(p,c,r,o,n,q)){this.found.push(p);
|
||||
}};k.pushUID=function(q,c,s,p,n,r){var o=this.getUID(q);if(!this.uniques[o]&&this.matchSelector(q,c,s,p,n,r)){this.uniques[o]=true;this.found.push(q);}};
|
||||
k.matchNode=function(n,o){if(this.isHTMLDocument&&this.nativeMatchesSelector){try{return this.nativeMatchesSelector.call(n,o.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g,'[$1="$2"]'));
|
||||
}catch(u){}}var t=this.Slick.parse(o);if(!t){return true;}var r=t.expressions,s=0,q;for(q=0;(currentExpression=r[q]);q++){if(currentExpression.length==1){var p=currentExpression[0];
|
||||
if(this.matchSelector(n,(this.isXMLDocument)?p.tag:p.tag.toUpperCase(),p.id,p.classes,p.attributes,p.pseudos)){return true;}s++;}}if(s==t.length){return false;
|
||||
}var c=this.search(this.document,t),v;for(q=0;v=c[q++];){if(v===n){return true;}}return false;};k.matchPseudo=function(q,c,p){var n="pseudo:"+c;if(this[n]){return this[n](q,p);
|
||||
}var o=this.getAttribute(q,c);return(p)?p==o:!!o;};k.matchSelector=function(o,v,c,p,q,s){if(v){var t=(this.isXMLDocument)?o.nodeName:o.nodeName.toUpperCase();
|
||||
if(v=="*"){if(t<"@"){return false;}}else{if(t!=v){return false;}}}if(c&&o.getAttribute("id")!=c){return false;}var r,n,u;if(p){for(r=p.length;r--;){u=this.getAttribute(o,"class");
|
||||
if(!(u&&p[r].regexp.test(u))){return false;}}}if(q){for(r=q.length;r--;){n=q[r];if(n.operator?!n.test(this.getAttribute(o,n.key)):!this.hasAttribute(o,n.key)){return false;
|
||||
}}}if(s){for(r=s.length;r--;){n=s[r];if(!this.matchPseudo(o,n.key,n.value)){return false;}}}return true;};var j={" ":function(q,w,n,r,s,u,p){var t,v,o;
|
||||
if(this.isHTMLDocument){getById:if(n){v=this.document.getElementById(n);if((!v&&q.all)||(this.idGetsName&&v&&v.getAttributeNode("id").nodeValue!=n)){o=q.all[n];
|
||||
if(!o){return;}if(!o[0]){o=[o];}for(t=0;v=o[t++];){var c=v.getAttributeNode("id");if(c&&c.nodeValue==n){this.push(v,w,null,r,s,u);break;}}return;}if(!v){if(this.contains(this.root,q)){return;
|
||||
}else{break getById;}}else{if(this.document!==q&&!this.contains(q,v)){return;}}this.push(v,w,null,r,s,u);return;}getByClass:if(r&&q.getElementsByClassName&&!this.brokenGEBCN){o=q.getElementsByClassName(p.join(" "));
|
||||
if(!(o&&o.length)){break getByClass;}for(t=0;v=o[t++];){this.push(v,w,n,null,s,u);}return;}}getByTag:{o=q.getElementsByTagName(w);if(!(o&&o.length)){break getByTag;
|
||||
}if(!this.brokenStarGEBTN){w=null;}for(t=0;v=o[t++];){this.push(v,w,n,r,s,u);}}},">":function(p,c,r,o,n,q){if((p=p.firstChild)){do{if(p.nodeType==1){this.push(p,c,r,o,n,q);
|
||||
}}while((p=p.nextSibling));}},"+":function(p,c,r,o,n,q){while((p=p.nextSibling)){if(p.nodeType==1){this.push(p,c,r,o,n,q);break;}}},"^":function(p,c,r,o,n,q){p=p.firstChild;
|
||||
if(p){if(p.nodeType==1){this.push(p,c,r,o,n,q);}else{this["combinator:+"](p,c,r,o,n,q);}}},"~":function(q,c,s,p,n,r){while((q=q.nextSibling)){if(q.nodeType!=1){continue;
|
||||
}var o=this.getUID(q);if(this.bitUniques[o]){break;}this.bitUniques[o]=true;this.push(q,c,s,p,n,r);}},"++":function(p,c,r,o,n,q){this["combinator:+"](p,c,r,o,n,q);
|
||||
this["combinator:!+"](p,c,r,o,n,q);},"~~":function(p,c,r,o,n,q){this["combinator:~"](p,c,r,o,n,q);this["combinator:!~"](p,c,r,o,n,q);},"!":function(p,c,r,o,n,q){while((p=p.parentNode)){if(p!==this.document){this.push(p,c,r,o,n,q);
|
||||
}}},"!>":function(p,c,r,o,n,q){p=p.parentNode;if(p!==this.document){this.push(p,c,r,o,n,q);}},"!+":function(p,c,r,o,n,q){while((p=p.previousSibling)){if(p.nodeType==1){this.push(p,c,r,o,n,q);
|
||||
break;}}},"!^":function(p,c,r,o,n,q){p=p.lastChild;if(p){if(p.nodeType==1){this.push(p,c,r,o,n,q);}else{this["combinator:!+"](p,c,r,o,n,q);}}},"!~":function(q,c,s,p,n,r){while((q=q.previousSibling)){if(q.nodeType!=1){continue;
|
||||
}var o=this.getUID(q);if(this.bitUniques[o]){break;}this.bitUniques[o]=true;this.push(q,c,s,p,n,r);}}};for(var i in j){k["combinator:"+i]=j[i];}var l={empty:function(c){var n=c.firstChild;
|
||||
return !(n&&n.nodeType==1)&&!(c.innerText||c.textContent||"").length;},not:function(c,n){return !this.matchNode(c,n);},contains:function(c,n){return(c.innerText||c.textContent||"").indexOf(n)>-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(o){var n=o;while((n=n.previousSibling)){if(n.nodeType==1){return false;}}var c=o;while((c=c.nextSibling)){if(c.nodeType==1){return false;
|
||||
}}return true;},"nth-child":k.createNTHPseudo("firstChild","nextSibling","posNTH"),"nth-last-child":k.createNTHPseudo("lastChild","previousSibling","posNTHLast"),"nth-of-type":k.createNTHPseudo("firstChild","nextSibling","posNTHType",true),"nth-last-of-type":k.createNTHPseudo("lastChild","previousSibling","posNTHTypeLast",true),index:function(n,c){return this["pseudo:nth-child"](n,""+(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 n=c.nodeName;
|
||||
while((c=c.previousSibling)){if(c.nodeName==n){return false;}}return true;},"last-of-type":function(c){var n=c.nodeName;while((c=c.nextSibling)){if(c.nodeName==n){return false;
|
||||
}}return true;},"only-of-type":function(o){var n=o,p=o.nodeName;while((n=n.previousSibling)){if(n.nodeName==p){return false;}}var c=o;while((c=c.nextSibling)){if(c.nodeName==p){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 b in l){k["pseudo:"+b]=l[b];}var a=k.attributeGetters={"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");
|
||||
},maxlength:function(){var c=this.getAttributeNode("maxLength");return(c&&c.specified)?c.nodeValue:null;}};a.MAXLENGTH=a.maxLength=a.maxlength;var e=k.Slick=(this.Slick||{});
|
||||
e.version="1.1.7";e.search=function(n,o,c){return k.search(n,o,c);};e.find=function(c,n){return k.search(c,n,null,true);};e.contains=function(c,n){k.setDocument(c);
|
||||
return k.contains(c,n);};e.getAttribute=function(n,c){k.setDocument(n);return k.getAttribute(n,c);};e.hasAttribute=function(n,c){k.setDocument(n);return k.hasAttribute(n,c);
|
||||
};e.match=function(n,c){if(!(n&&c)){return false;}if(!c||c===n){return true;}k.setDocument(n);return k.matchNode(n,c);};e.defineAttributeGetter=function(c,n){k.attributeGetters[c]=n;
|
||||
return this;};e.lookupAttributeGetter=function(c){return k.attributeGetters[c];};e.definePseudo=function(c,n){k["pseudo:"+c]=function(p,o){return n.call(p,o);
|
||||
};return this;};e.lookupPseudo=function(c){var n=k["pseudo:"+c];if(n){return function(o){return n.call(this,o);};}return null;};e.override=function(n,c){k.override(n,c);
|
||||
return this;};e.isXML=k.isXML;e.uidOf=function(c){return k.getUIDHTML(c);};if(!this.Slick){this.Slick=e;}}).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 a,f=0,c=d.length;f<c;f++){a=d[f];if(g[a.key]!=null){continue;
|
||||
}if(a.value!=null&&a.operator=="="){g[a.key]=a.value;}else{if(!a.value&&!a.operator){g[a.key]=true;}}}}if(e.classList&&g["class"]==null){g["class"]=e.classList.join(" ");
|
||||
}}return document.newElement(b,g);};if(Browser.Element){Element.prototype=Browser.Element.prototype;Element.prototype._fireEvent=(function(a){return function(b,c){return a.call(this,b,c);
|
||||
};})(Element.prototype.fireEvent);}new Type("Element",Element).mirror(function(a){if(Array.prototype[a]){return;}var b={};b[a]=function(){var h=[],e=arguments,j=true;
|
||||
for(var g=0,d=this.length;g<d;g++){var f=this[g],c=h[g]=f[a].apply(f,e);j=(j&&typeOf(c)=="element");}return(j)?new Elements(h):h;};Elements.implement(b);
|
||||
});if(!Browser.Element){Element.parent=Object;Element.Prototype={"$constructor":Element,"$family":Function.from("element").hide()};Element.mirror(function(a,b){Element.Prototype[a]=b;
|
||||
});}Element.Constructors={};Element.Constructors=new Hash;var IFrame=new Type("IFrame",function(){var e=Array.link(arguments,{properties:Type.isObject,iframe:function(f){return(f!=null);
|
||||
}});var c=e.properties||{},b;if(e.iframe){b=document.id(e.iframe);}var d=c.onload||function(){};delete c.onload;c.id=c.name=[c.id,c.name,b?(b.id||b.name):"IFrame_"+String.uniqueID()].pick();
|
||||
b=new Element(b||"iframe",c);var a=function(){d.call(b.contentWindow);};if(window.frames[c.id]){a();}else{b.addListener("load",a);}return b;});var Elements=this.Elements=function(a){if(a&&a.length){var e={},d;
|
||||
for(var c=0;d=a[c++];){var b=Slick.uidOf(d);if(!e[b]){e[b]=true;this.push(d);}}}};Elements.prototype={length:0};Elements.parent=Array;new Type("Elements",Elements).implement({filter:function(a,b){if(!a){return this;
|
||||
}return new Elements(Array.filter(this,(typeOf(a)=="string")?function(c){return c.match(a);}:a,b));}.protect(),push:function(){var d=this.length;for(var b=0,a=arguments.length;
|
||||
b<a;b++){var c=document.id(arguments[b]);if(c){this[d++]=c;}}return(this.length=d);}.protect(),unshift:function(){var b=[];for(var c=0,a=arguments.length;
|
||||
c<a;c++){var d=document.id(arguments[c]);if(d){b.push(d);}}return Array.prototype.unshift.apply(this,b);}.protect(),concat:function(){var b=new Elements(this);
|
||||
for(var c=0,a=arguments.length;c<a;c++){var d=arguments[c];if(Type.isEnumerable(d)){b.append(d);}else{b.push(d);}}return b;}.protect(),append:function(c){for(var b=0,a=c.length;
|
||||
b<a;b++){this.push(c[b]);}return this;}.protect(),empty:function(){while(this.length){delete this[--this.length];}return this;}.protect()});Elements.alias("extend","append");
|
||||
(function(){var f=Array.prototype.splice,a={"0":0,"1":1,length:2};f.call(a,1,1);if(a[1]==1){Elements.implement("splice",function(){var g=this.length;var e=f.apply(this,arguments);
|
||||
while(g>=this.length){delete this[g--];}return e;}.protect());}Array.forEachMethod(function(g,e){Elements.implement(e,g);});Array.mirror(Elements);var d;
|
||||
try{d=(document.createElement("<input name=x>").name=="x");}catch(b){}var c=function(e){return(""+e).replace(/&/g,"&").replace(/"/g,""");};Document.implement({newElement:function(e,g){if(g&&g.checked!=null){g.defaultChecked=g.checked;
|
||||
}if(d&&g){e="<"+e;if(g.name){e+=' name="'+c(g.name)+'"';}if(g.type){e+=' type="'+c(g.type)+'"';}e+=">";delete g.name;delete g.type;}return this.id(this.createElement(e)).set(g);
|
||||
}});})();(function(){Slick.uidOf(window);Slick.uidOf(document);Document.implement({newTextNode:function(e){return this.createTextNode(e);},getDocument:function(){return this;
|
||||
},getWindow:function(){return this.window;},id:(function(){var e={string:function(E,D,l){E=Slick.find(l,"#"+E.replace(/(\W)/g,"\\$1"));return(E)?e.element(E,D):null;
|
||||
},element:function(D,E){Slick.uidOf(D);if(!E&&!D.$family&&!(/^(?:object|embed)$/i).test(D.tagName)){var l=D.fireEvent;D._fireEvent=function(F,G){return l(F,G);
|
||||
};Object.append(D,Element.Prototype);}return D;},object:function(D,E,l){if(D.toElement){return e.element(D.toElement(l),E);}return null;}};e.textnode=e.whitespace=e.window=e.document=function(l){return l;
|
||||
};return function(D,F,E){if(D&&D.$family&&D.uniqueNumber){return D;}var l=typeOf(D);return(e[l])?e[l](D,F,E||document):null;};})()});if(window.$==null){Window.implement("$",function(e,l){return document.id(e,l,this.document);
|
||||
});}Window.implement({getDocument:function(){return this.document;},getWindow:function(){return this;}});[Document,Element].invoke("implement",{getElements:function(e){return Slick.search(this,e,new Elements);
|
||||
},getElement:function(e){return document.id(Slick.find(this,e));}});var m={contains:function(e){return Slick.contains(this,e);}};if(!document.contains){Document.implement(m);
|
||||
}if(!document.createElement("div").contains){Element.implement(m);}Element.implement("hasChild",function(e){return this!==e&&this.contains(e);});(function(l,E,e){this.Selectors={};
|
||||
var F=this.Selectors.Pseudo=new Hash();var D=function(){for(var G in F){if(F.hasOwnProperty(G)){Slick.definePseudo(G,F[G]);delete F[G];}}};Slick.search=function(H,I,G){D();
|
||||
return l.call(this,H,I,G);};Slick.find=function(G,H){D();return E.call(this,G,H);};Slick.match=function(H,G){D();return e.call(this,H,G);};})(Slick.search,Slick.find,Slick.match);
|
||||
var r=function(E,D){if(!E){return D;}E=Object.clone(Slick.parse(E));var l=E.expressions;for(var e=l.length;e--;){l[e][0].combinator=D;}return E;};Object.forEach({getNext:"~",getPrevious:"!~",getParent:"!"},function(e,l){Element.implement(l,function(D){return this.getElement(r(D,e));
|
||||
});});Object.forEach({getAllNext:"~",getAllPrevious:"!~",getSiblings:"~~",getChildren:">",getParents:"!"},function(e,l){Element.implement(l,function(D){return this.getElements(r(D,e));
|
||||
});});Element.implement({getFirst:function(e){return document.id(Slick.search(this,r(e,">"))[0]);},getLast:function(e){return document.id(Slick.search(this,r(e,">")).getLast());
|
||||
},getWindow:function(){return this.ownerDocument.window;},getDocument:function(){return this.ownerDocument;},getElementById:function(e){return document.id(Slick.find(this,"#"+(""+e).replace(/(\W)/g,"\\$1")));
|
||||
},match:function(e){return !e||Slick.match(this,e);}});if(window.$$==null){Window.implement("$$",function(e){var H=new Elements;if(arguments.length==1&&typeof e=="string"){return Slick.search(this.document,e,H);
|
||||
}var E=Array.flatten(arguments);for(var F=0,D=E.length;F<D;F++){var G=E[F];switch(typeOf(G)){case"element":H.push(G);break;case"string":Slick.search(this.document,G,H);
|
||||
}}return H;});}if(window.$$==null){Window.implement("$$",function(e){if(arguments.length==1){if(typeof e=="string"){return Slick.search(this.document,e,new Elements);
|
||||
}else{if(Type.isEnumerable(e)){return new Elements(e);}}}return new Elements(arguments);});}var w={before:function(l,e){var D=e.parentNode;if(D){D.insertBefore(l,e);
|
||||
}},after:function(l,e){var D=e.parentNode;if(D){D.insertBefore(l,e.nextSibling);}},bottom:function(l,e){e.appendChild(l);},top:function(l,e){e.insertBefore(l,e.firstChild);
|
||||
}};w.inside=w.bottom;Object.each(w,function(l,D){D=D.capitalize();var e={};e["inject"+D]=function(E){l(this,document.id(E,true));return this;};e["grab"+D]=function(E){l(document.id(E,true),this);
|
||||
return this;};Element.implement(e);});var j={},d={};var k={};Array.forEach(["type","value","defaultValue","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","rowSpan","tabIndex","useMap"],function(e){k[e.toLowerCase()]=e;
|
||||
});k.html="innerHTML";k.text=(document.createElement("div").textContent==null)?"innerText":"textContent";Object.forEach(k,function(l,e){d[e]=function(D,E){D[l]=E;
|
||||
};j[e]=function(D){return D[l];};});var x=["compact","nowrap","ismap","declare","noshade","checked","disabled","readOnly","multiple","selected","noresize","defer","defaultChecked","autofocus","controls","autoplay","loop"];
|
||||
var h={};Array.forEach(x,function(e){var l=e.toLowerCase();h[l]=e;d[l]=function(D,E){D[e]=!!E;};j[l]=function(D){return !!D[e];};});Object.append(d,{"class":function(e,l){("className" in e)?e.className=(l||""):e.setAttribute("class",l);
|
||||
},"for":function(e,l){("htmlFor" in e)?e.htmlFor=l:e.setAttribute("for",l);},style:function(e,l){(e.style)?e.style.cssText=l:e.setAttribute("style",l);
|
||||
},value:function(e,l){e.value=(l!=null)?l:"";}});j["class"]=function(e){return("className" in e)?e.className||null:e.getAttribute("class");};var f=document.createElement("button");
|
||||
try{f.type="button";}catch(z){}if(f.type!="button"){d.type=function(e,l){e.setAttribute("type",l);};}f=null;var p=document.createElement("input");p.value="t";
|
||||
p.type="submit";if(p.value!="t"){d.type=function(l,e){var D=l.value;l.type=e;l.value=D;};}p=null;var q=(function(e){e.random="attribute";return(e.getAttribute("random")=="attribute");
|
||||
})(document.createElement("div"));Element.implement({setProperty:function(l,D){var E=d[l.toLowerCase()];if(E){E(this,D);}else{if(q){var e=this.retrieve("$attributeWhiteList",{});
|
||||
}if(D==null){this.removeAttribute(l);if(q){delete e[l];}}else{this.setAttribute(l,""+D);if(q){e[l]=true;}}}return this;},setProperties:function(e){for(var l in e){this.setProperty(l,e[l]);
|
||||
}return this;},getProperty:function(F){var D=j[F.toLowerCase()];if(D){return D(this);}if(q){var l=this.getAttributeNode(F),E=this.retrieve("$attributeWhiteList",{});
|
||||
if(!l){return null;}if(l.expando&&!E[F]){var G=this.outerHTML;if(G.substr(0,G.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(F)<0){return null;}E[F]=true;}}var e=Slick.getAttribute(this,F);
|
||||
return(!e&&!Slick.hasAttribute(this,F))?null:e;},getProperties:function(){var e=Array.from(arguments);return e.map(this.getProperty,this).associate(e);
|
||||
},removeProperty:function(e){return this.setProperty(e,null);},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this;},set:function(D,l){var e=Element.Properties[D];
|
||||
(e&&e.set)?e.set.call(this,l):this.setProperty(D,l);}.overloadSetter(),get:function(l){var e=Element.Properties[l];return(e&&e.get)?e.get.apply(this):this.getProperty(l);
|
||||
}.overloadGetter(),erase:function(l){var e=Element.Properties[l];(e&&e.erase)?e.erase.apply(this):this.removeProperty(l);return this;},hasClass:function(e){return this.className.clean().contains(e," ");
|
||||
},addClass:function(e){if(!this.hasClass(e)){this.className=(this.className+" "+e).clean();}return this;},removeClass:function(e){this.className=this.className.replace(new RegExp("(^|\\s)"+e+"(?:\\s|$)"),"$1");
|
||||
return this;},toggleClass:function(e,l){if(l==null){l=!this.hasClass(e);}return(l)?this.addClass(e):this.removeClass(e);},adopt:function(){var E=this,e,G=Array.flatten(arguments),F=G.length;
|
||||
if(F>1){E=e=document.createDocumentFragment();}for(var D=0;D<F;D++){var l=document.id(G[D],true);if(l){E.appendChild(l);}}if(e){this.appendChild(e);}return this;
|
||||
},appendText:function(l,e){return this.grab(this.getDocument().newTextNode(l),e);},grab:function(l,e){w[e||"bottom"](document.id(l,true),this);return this;
|
||||
},inject:function(l,e){w[e||"bottom"](this,document.id(l,true));return this;},replaces:function(e){e=document.id(e,true);e.parentNode.replaceChild(this,e);
|
||||
return this;},wraps:function(l,e){l=document.id(l,true);return this.replaces(l).grab(l,e);},getSelected:function(){this.selectedIndex;return new Elements(Array.from(this.options).filter(function(e){return e.selected;
|
||||
}));},toQueryString:function(){var e=[];this.getElements("input, select, textarea").each(function(D){var l=D.type;if(!D.name||D.disabled||l=="submit"||l=="reset"||l=="file"||l=="image"){return;
|
||||
}var E=(D.get("tag")=="select")?D.getSelected().map(function(F){return document.id(F).get("value");}):((l=="radio"||l=="checkbox")&&!D.checked)?null:D.get("value");
|
||||
Array.from(E).each(function(F){if(typeof F!="undefined"){e.push(encodeURIComponent(D.name)+"="+encodeURIComponent(F));}});});return e.join("&");}});var i={},A={};
|
||||
var B=function(e){return(A[e]||(A[e]={}));};var v=function(l){var e=l.uniqueNumber;if(l.removeEvents){l.removeEvents();}if(l.clearAttributes){l.clearAttributes();
|
||||
}if(e!=null){delete i[e];delete A[e];}return l;};var C={input:"checked",option:"selected",textarea:"value"};Element.implement({destroy:function(){var e=v(this).getElementsByTagName("*");
|
||||
Array.each(e,v);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;
|
||||
},clone:function(G,E){G=G!==false;var L=this.cloneNode(G),D=[L],F=[this],J;if(G){D.append(Array.from(L.getElementsByTagName("*")));F.append(Array.from(this.getElementsByTagName("*")));
|
||||
}for(J=D.length;J--;){var H=D[J],K=F[J];if(!E){H.removeAttribute("id");}if(H.clearAttributes){H.clearAttributes();H.mergeAttributes(K);H.removeAttribute("uniqueNumber");
|
||||
if(H.options){var O=H.options,e=K.options;for(var I=O.length;I--;){O[I].selected=e[I].selected;}}}var l=C[K.tagName.toLowerCase()];if(l&&K[l]){H[l]=K[l];
|
||||
}}if(Browser.ie){var M=L.getElementsByTagName("object"),N=this.getElementsByTagName("object");for(J=M.length;J--;){M[J].outerHTML=N[J].outerHTML;}}return document.id(L);
|
||||
}});[Element,Window,Document].invoke("implement",{addListener:function(E,D){if(E=="unload"){var e=D,l=this;D=function(){l.removeListener("unload",D);e();
|
||||
};}else{i[Slick.uidOf(this)]=this;}if(this.addEventListener){this.addEventListener(E,D,!!arguments[2]);}else{this.attachEvent("on"+E,D);}return this;},removeListener:function(l,e){if(this.removeEventListener){this.removeEventListener(l,e,!!arguments[2]);
|
||||
}else{this.detachEvent("on"+l,e);}return this;},retrieve:function(l,e){var E=B(Slick.uidOf(this)),D=E[l];if(e!=null&&D==null){D=E[l]=e;}return D!=null?D:null;
|
||||
},store:function(l,e){var D=B(Slick.uidOf(this));D[l]=e;return this;},eliminate:function(e){var l=B(Slick.uidOf(this));delete l[e];return this;}});if(window.attachEvent&&!window.addEventListener){window.addListener("unload",function(){Object.each(i,v);
|
||||
if(window.CollectGarbage){CollectGarbage();}});}Element.Properties={};Element.Properties=new Hash;Element.Properties.style={set:function(e){this.style.cssText=e;
|
||||
},get:function(){return this.style.cssText;},erase:function(){this.style.cssText="";}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase();
|
||||
}};Element.Properties.html={set:function(e){if(e==null){e="";}else{if(typeOf(e)=="array"){e=e.join("");}}this.innerHTML=e;},erase:function(){this.innerHTML="";
|
||||
}};var t=document.createElement("div");t.innerHTML="<nav></nav>";var a=(t.childNodes.length==1);if(!a){var s="abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "),b=document.createDocumentFragment(),u=s.length;
|
||||
while(u--){b.createElement(s[u]);}}t=null;var g=Function.attempt(function(){var e=document.createElement("table");e.innerHTML="<tr><td></td></tr>";return true;
|
||||
});var c=document.createElement("tr"),o="<td></td>";c.innerHTML=o;var y=(c.innerHTML==o);c=null;if(!g||!y||!a){Element.Properties.html.set=(function(l){var e={table:[1,"<table>","</table>"],select:[1,"<select>","</select>"],tbody:[2,"<table><tbody>","</tbody></table>"],tr:[3,"<table><tbody><tr>","</tr></tbody></table>"]};
|
||||
e.thead=e.tfoot=e.tbody;return function(D){var E=e[this.get("tag")];if(!E&&!a){E=[0,"",""];}if(!E){return l.call(this,D);}var H=E[0],G=document.createElement("div"),F=G;
|
||||
if(!a){b.appendChild(G);}G.innerHTML=[E[1],D,E[2]].flatten().join("");while(H--){F=F.firstChild;}this.empty().adopt(F.childNodes);if(!a){b.removeChild(G);
|
||||
}G=null;};})(Element.Properties.html.set);}var n=document.createElement("form");n.innerHTML="<select><option>s</option></select>";if(n.firstChild.value!="s"){Element.Properties.value={set:function(G){var l=this.get("tag");
|
||||
if(l!="select"){return this.setProperty("value",G);}var D=this.getElements("option");for(var E=0;E<D.length;E++){var F=D[E],e=F.getAttributeNode("value"),H=(e&&e.specified)?F.value:F.get("text");
|
||||
if(H==G){return F.selected=true;}}},get:function(){var D=this,l=D.get("tag");if(l!="select"&&l!="option"){return this.getProperty("value");}if(l=="select"&&!(D=D.getSelected()[0])){return"";
|
||||
}var e=D.getAttributeNode("value");return(e&&e.specified)?D.value:D.get("text");}};}n=null;if(document.createElement("div").getAttributeNode("id")){Element.Properties.id={set:function(e){this.id=this.getAttributeNode("id").value=e;
|
||||
},get:function(){return this.id||null;},erase:function(){this.id=this.getAttributeNode("id").value="";}};}})();(function(){var i=document.html;var d=document.createElement("div");
|
||||
d.style.color="red";d.style.color=null;var c=d.style.color=="red";d=null;Element.Properties.styles={set:function(k){this.setStyles(k);}};var h=(i.style.opacity!=null),e=(i.style.filter!=null),j=/alpha\(opacity=([\d.]+)\)/i;
|
||||
var a=function(l,k){l.store("$opacity",k);l.style.visibility=k>0||k==null?"visible":"hidden";};var f=(h?function(l,k){l.style.opacity=k;}:(e?function(l,k){var n=l.style;
|
||||
if(!l.currentStyle||!l.currentStyle.hasLayout){n.zoom=1;}if(k==null||k==1){k="";}else{k="alpha(opacity="+(k*100).limit(0,100).round()+")";}var m=n.filter||l.getComputedStyle("filter")||"";
|
||||
n.filter=j.test(m)?m.replace(j,k):m+k;if(!n.filter){n.removeAttribute("filter");}}:a));var g=(h?function(l){var k=l.style.opacity||l.getComputedStyle("opacity");
|
||||
return(k=="")?1:k.toFloat();}:(e?function(l){var m=(l.style.filter||l.getComputedStyle("filter")),k;if(m){k=m.match(j);}return(k==null||m==null)?1:(k[1]/100);
|
||||
}:function(l){var k=l.retrieve("$opacity");if(k==null){k=(l.style.visibility=="hidden"?0:1);}return k;}));var b=(i.style.cssFloat==null)?"styleFloat":"cssFloat";
|
||||
Element.implement({getComputedStyle:function(m){if(this.currentStyle){return this.currentStyle[m.camelCase()];}var l=Element.getDocument(this).defaultView,k=l?l.getComputedStyle(this,null):null;
|
||||
return(k)?k.getPropertyValue((m==b)?"float":m.hyphenate()):null;},setStyle:function(l,k){if(l=="opacity"){if(k!=null){k=parseFloat(k);}f(this,k);return this;
|
||||
}l=(l=="float"?b:l).camelCase();if(typeOf(k)!="string"){var m=(Element.Styles[l]||"@").split(" ");k=Array.from(k).map(function(o,n){if(!m[n]){return"";
|
||||
}return(typeOf(o)=="number")?m[n].replace("@",Math.round(o)):o;}).join(" ");}else{if(k==String(Number(k))){k=Math.round(k);}}this.style[l]=k;if((k==""||k==null)&&c&&this.style.removeAttribute){this.style.removeAttribute(l);
|
||||
}return this;},getStyle:function(q){if(q=="opacity"){return g(this);}q=(q=="float"?b:q).camelCase();var k=this.style[q];if(!k||q=="zIndex"){k=[];for(var p in Element.ShortStyles){if(q!=p){continue;
|
||||
}for(var o in Element.ShortStyles[p]){k.push(this.getStyle(o));}return k.join(" ");}k=this.getComputedStyle(q);}if(k){k=String(k);var m=k.match(/rgba?\([\d\s,]+\)/);
|
||||
if(m){k=k.replace(m[0],m[0].rgbToHex());}}if(Browser.opera||Browser.ie){if((/^(height|width)$/).test(q)&&!(/px$/.test(k))){var l=(q=="width")?["left","right"]:["top","bottom"],n=0;
|
||||
l.each(function(r){n+=this.getStyle("border-"+r+"-width").toInt()+this.getStyle("padding-"+r).toInt();},this);return this["offset"+q.capitalize()]-n+"px";
|
||||
}if(Browser.ie&&(/^border(.+)Width|margin|padding/).test(q)&&isNaN(parseFloat(k))){return"0px";}}return k;},setStyles:function(l){for(var k in l){this.setStyle(k,l[k]);
|
||||
}return this;},getStyles:function(){var k={};Array.flatten(arguments).each(function(l){k[l]=this.getStyle(l);},this);return k;}});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.implement({setOpacity:function(k){f(this,k);return this;},getOpacity:function(){return g(this);}});Element.Properties.opacity={set:function(k){f(this,k);
|
||||
a(this,k);},get:function(){return g(this);}};Element.Styles=new Hash(Element.Styles);Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};
|
||||
["Top","Right","Bottom","Left"].each(function(q){var p=Element.ShortStyles;var l=Element.Styles;["margin","padding"].each(function(r){var s=r+q;p[r][s]=l[s]="@px";
|
||||
});var o="border"+q;p.border[o]=l[o]="@px @ rgb(@, @, @)";var n=o+"Width",k=o+"Style",m=o+"Color";p[o]={};p.borderWidth[n]=p[o][n]=l[n]="@px";p.borderStyle[k]=p[o][k]=l[k]="@";
|
||||
p.borderColor[m]=p[o][m]=l[m]="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,f);
|
||||
}if(b.condition){d=function(k){if(b.condition.call(this,k,f)){return h.call(this,k);}return true;};}if(b.base){g=Function.from(b.base).call(this,f);}}var e=function(){return h.call(j);
|
||||
};var c=Element.NativeEvents[g];if(c){if(c==2){e=function(k){k=new DOMEvent(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);}if(f.base){e=Function.from(f.base).call(this,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,paste:2,input:2,load:2,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1};
|
||||
Element.Events={mousewheel:{base:(Browser.firefox)?"DOMMouseScroll":"mousewheel"}};if("onmouseenter" in document.documentElement){Element.NativeEvents.mouseenter=Element.NativeEvents.mouseleave=2;
|
||||
}else{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};Element.Events.mouseleave={base:"mouseout",condition:a};}if(!window.addEventListener){Element.NativeEvents.propertychange=2;
|
||||
Element.Events.change={base:function(){var b=this.type;return(this.get("tag")=="input"&&(b=="radio"||b=="checkbox"))?"propertychange":"change";},condition:function(b){return this.type!="radio"||(b.event.propertyName=="checked"&&this.checked);
|
||||
}};}Element.Events=new Hash(Element.Events);})();(function(){var c=!!window.addEventListener;Element.NativeEvents.focusin=Element.NativeEvents.focusout=2;
|
||||
var k=function(l,m,n,o,p){while(p&&p!=l){if(m(p,o)){return n.call(p,o,p);}p=document.id(p.parentNode);}};var a={mouseenter:{base:"mouseover"},mouseleave:{base:"mouseout"},focus:{base:"focus"+(c?"":"in"),capture:true},blur:{base:c?"blur":"focusout",capture:true}};
|
||||
var b="$delegation:";var i=function(l){return{base:"focusin",remove:function(m,o){var p=m.retrieve(b+l+"listeners",{})[o];if(p&&p.forms){for(var n=p.forms.length;
|
||||
n--;){p.forms[n].removeEvent(l,p.fns[n]);}}},listen:function(x,r,v,n,t,s){var o=(t.get("tag")=="form")?t:n.target.getParent("form");if(!o){return;}var u=x.retrieve(b+l+"listeners",{}),p=u[s]||{forms:[],fns:[]},m=p.forms,w=p.fns;
|
||||
if(m.indexOf(o)!=-1){return;}m.push(o);var q=function(y){k(x,r,v,y,t);};o.addEvent(l,q);w.push(q);u[s]=p;x.store(b+l+"listeners",u);}};};var d=function(l){return{base:"focusin",listen:function(m,n,p,q,r){var o={blur:function(){this.removeEvents(o);
|
||||
}};o[l]=function(s){k(m,n,p,s,r);};q.target.addEvents(o);}};};if(!c){Object.append(a,{submit:i("submit"),reset:i("reset"),change:d("change"),select:d("select")});
|
||||
}var h=Element.prototype,f=h.addEvent,j=h.removeEvent;var e=function(l,m){return function(r,q,n){if(r.indexOf(":relay")==-1){return l.call(this,r,q,n);
|
||||
}var o=Slick.parse(r).expressions[0][0];if(o.pseudos[0].key!="relay"){return l.call(this,r,q,n);}var p=o.tag;o.pseudos.slice(1).each(function(s){p+=":"+s.key+(s.value?"("+s.value+")":"");
|
||||
});l.call(this,r,q);return m.call(this,p,o.pseudos[0].value,q);};};var g={addEvent:function(v,q,x){var t=this.retrieve("$delegates",{}),r=t[v];if(r){for(var y in r){if(r[y].fn==x&&r[y].match==q){return this;
|
||||
}}}var p=v,u=q,o=x,n=a[v]||{};v=n.base||p;q=function(B){return Slick.match(B,u);};var w=Element.Events[p];if(w&&w.condition){var l=q,m=w.condition;q=function(C,B){return l(C,B)&&m.call(C,B,v);
|
||||
};}var z=this,s=String.uniqueID();var A=n.listen?function(B,C){if(!C&&B&&B.target){C=B.target;}if(C){n.listen(z,q,x,B,C,s);}}:function(B,C){if(!C&&B&&B.target){C=B.target;
|
||||
}if(C){k(z,q,x,B,C);}};if(!r){r={};}r[s]={match:u,fn:o,delegator:A};t[p]=r;return f.call(this,v,A,n.capture);},removeEvent:function(r,n,t,u){var q=this.retrieve("$delegates",{}),p=q[r];
|
||||
if(!p){return this;}if(u){var m=r,w=p[u].delegator,l=a[r]||{};r=l.base||m;if(l.remove){l.remove(this,u);}delete p[u];q[m]=p;return j.call(this,r,w);}var o,v;
|
||||
if(t){for(o in p){v=p[o];if(v.match==n&&v.fn==t){return g.removeEvent.call(this,r,n,t,o);}}}else{for(o in p){v=p[o];if(v.match==n){g.removeEvent.call(this,r,n,v.fn,o);
|
||||
}}}return this;}};[Element,Window,Document].invoke("implement",{addEvent:e(f,g.addEvent),removeEvent:e(j,g.removeEvent)});})();(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){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<this.frames){var j=this.transition(this.frame/this.frames);this.set(this.compute(this.from,this.to,j));
|
||||
}else{this.frame=this.frames;this.set(this.compute(this.from,this.to,1));this.stop();}},set:function(g){return g;},compute:function(i,h,g){return f.compute(i,h,g);
|
||||
},check:function(){if(!this.isRunning()){return true;}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(this.caller.pass(arguments,this));
|
||||
return false;}return false;},start:function(k,j){if(!this.check(k,j)){return this;}this.from=k;this.to=j;this.frame=(this.options.frameSkip)?0:-1;this.time=null;
|
||||
this.transition=this.getTransition();var i=this.options.frames,h=this.options.fps,g=this.options.duration;this.duration=f.Durations[g]||g.toInt();this.frameInterval=1000/h;
|
||||
this.frames=i||Math.round(this.duration/this.frameInterval);this.fireEvent("start",this.subject);b.call(this,h);return this;},stop:function(){if(this.isRunning()){this.time=null;
|
||||
d.call(this,this.options.fps);if(this.frames==this.frame){this.fireEvent("complete",this.subject);if(!this.callChain()){this.fireEvent("chainComplete",this.subject);
|
||||
}}else{this.fireEvent("stop",this.subject);}}return this;},cancel:function(){if(this.isRunning()){this.time=null;d.call(this,this.options.fps);this.frame=this.frames;
|
||||
this.fireEvent("cancel",this.subject).clearChain();}return this;},pause:function(){if(this.isRunning()){this.time=null;d.call(this,this.options.fps);}return this;
|
||||
},resume:function(){if((this.frame<this.frames)&&!this.isRunning()){b.call(this,this.options.fps);}return this;},isRunning:function(){var g=e[this.options.fps];
|
||||
return g&&g.contains(this);}});f.compute=function(i,h,g){return(h-i)*g+i;};f.Durations={"short":250,normal:500,"long":1000};var e={},c={};var a=function(){var h=Date.now();
|
||||
for(var j=this.length;j--;){var g=this[j];if(g){g.step(h);}}};var b=function(h){var g=e[h]||(e[h]=[]);g.push(this);if(!c[h]){c[h]=a.periodical(Math.round(1000/h),g);
|
||||
}};var d=function(h){var g=e[h];if(g){g.erase(this);if(!g.length&&c[h]){delete e[h];c[h]=clearInterval(c[h]);}}};})();Fx.CSS=new Class({Extends:Fx,prepare:function(b,e,a){a=Array.from(a);
|
||||
var h=a[0],g=a[1];if(g==null){g=h;h=b.getStyle(e);var c=this.options.unit;if(c&&h.slice(-c.length)!=c&&parseFloat(h)!=0){b.setStyle(e,g+c);var d=b.getComputedStyle(e);
|
||||
if(!(/px$/.test(d))){d=b.style[("pixel-"+e).camelCase()];if(d==null){var f=b.style.left;b.style.left=g+c;d=b.style.pixelLeft;b.style.left=f;}}h=(g||1)/(parseFloat(d)||1)*(parseFloat(h)||0);
|
||||
b.setStyle(e,h+c);}}return{from:this.parse(h),to:this.parse(g)};},parse:function(a){a=Function.from(a)();a=(typeof a=="string")?a.split(" "):Array.from(a);
|
||||
return a.map(function(c){c=String(c);var b=false;Object.each(Fx.CSS.Parsers,function(f,e){if(b){return;}var d=f.parse(c);if(d||d===0){b={value:d,parser:f};
|
||||
}});b=b||{value:c,parser:Fx.CSS.Parsers.String};return b;});},compute:function(d,c,b){var a=[];(Math.min(d.length,c.length)).times(function(e){a.push({value:d[e].parser.compute(d[e].value,c[e].value,b),parser:d[e].parser});
|
||||
});a.$family=Function.from("fx:css:value");return a;},serve:function(c,b){if(typeOf(c)!="fx:css:value"){c=this.parse(c);}var a=[];c.each(function(d){a=a.concat(d.parser.serve(d.value,b));
|
||||
});return a;},render:function(a,d,c,b){a.setStyle(d,this.serve(c,b));},search:function(a){if(Fx.CSS.Cache[a]){return Fx.CSS.Cache[a];}var c={},b=new RegExp("^"+a.escapeRegExp()+"$");
|
||||
Array.each(document.styleSheets,function(f,e){var d=f.href;if(d&&d.contains("://")&&!d.contains(document.domain)){return;}var g=f.rules||f.cssRules;Array.each(g,function(k,h){if(!k.style){return;
|
||||
}var j=(k.selectorText)?k.selectorText.replace(/^\w+/,function(i){return i.toLowerCase();}):null;if(!j||!b.test(j)){return;}Object.each(Element.Styles,function(l,i){if(!k.style[i]||Element.ShortStyles[i]){return;
|
||||
}l=String(k.style[i]);c[i]=((/^rgb/).test(l))?l.rgbToHex():l;});});});return Fx.CSS.Cache[a]=c;}});Fx.CSS.Cache={};Fx.CSS.Parsers={Color:{parse:function(a){if(a.match(/^#[0-9a-f]{3,6}$/i)){return a.hexToRgb(true);
|
||||
}return((a=a.match(/(\d+),\s*(\d+),\s*(\d+)/)))?[a[1],a[2],a[3]]:false;},compute:function(c,b,a){return c.map(function(e,d){return Math.round(Fx.compute(c[d],b[d],a));
|
||||
});},serve:function(a){return a.map(Number);}},Number:{parse:parseFloat,compute:Fx.compute,serve:function(b,a){return(a)?b+a:b;}},String:{parse:Function.from(false),compute:function(b,a){return a;
|
||||
},serve:function(a){return a;}}};Fx.CSS.Parsers=new Hash(Fx.CSS.Parsers);Fx.Tween=new Class({Extends:Fx.CSS,initialize:function(b,a){this.element=this.subject=document.id(b);
|
||||
this.parent(a);},set:function(b,a){if(arguments.length==1){a=b;b=this.property||this.options.property;}this.render(this.element,b,a,this.options.unit);
|
||||
return this;},start:function(c,e,d){if(!this.check(c,e,d)){return this;}var b=Array.flatten(arguments);this.property=this.options.property||b.shift();var a=this.prepare(this.element,this.property,b);
|
||||
return this.parent(a.from,a.to);}});Element.Properties.tween={set:function(a){this.get("tween").cancel().setOptions(a);return this;},get:function(){var a=this.retrieve("tween");
|
||||
if(!a){a=new Fx.Tween(this,{link:"cancel"});this.store("tween",a);}return a;}};Element.implement({tween:function(a,c,b){this.get("tween").start(a,c,b);
|
||||
return this;},fade:function(d){var e=this.get("tween"),g,c=["opacity"].append(arguments),a;if(c[1]==null){c[1]="toggle";}switch(c[1]){case"in":g="start";
|
||||
c[1]=1;break;case"out":g="start";c[1]=0;break;case"show":g="set";c[1]=1;break;case"hide":g="set";c[1]=0;break;case"toggle":var b=this.retrieve("fade:flag",this.getStyle("opacity")==1);
|
||||
g="start";c[1]=b?0:1;this.store("fade:flag",!b);a=true;break;default:g="start";}if(!a){this.eliminate("fade:flag");}e[g].apply(e,c);var f=c[c.length-1];
|
||||
if(g=="set"||f!=0){this.setStyle("visibility",f==0?"hidden":"visible");}else{e.chain(function(){this.element.setStyle("visibility","hidden");this.callChain();
|
||||
});}return this;},highlight:function(c,a){if(!a){a=this.retrieve("highlight:original",this.getStyle("background-color"));a=(a=="transparent")?"#fff":a;
|
||||
}var b=this.get("tween");b.start("background-color",c||"#ffff88",a).chain(function(){this.setStyle("background-color",this.retrieve("highlight:original"));
|
||||
b.callChain();}.bind(this));return this;}});Fx.Morph=new Class({Extends:Fx.CSS,initialize:function(b,a){this.element=this.subject=document.id(b);this.parent(a);
|
||||
},set:function(a){if(typeof a=="string"){a=this.search(a);}for(var b in a){this.render(this.element,b,a[b],this.options.unit);}return this;},compute:function(e,d,c){var a={};
|
||||
for(var b in e){a[b]=this.parent(e[b],d[b],c);}return a;},start:function(b){if(!this.check(b)){return this;}if(typeof b=="string"){b=this.search(b);}var e={},d={};
|
||||
for(var c in b){var a=this.prepare(this.element,c,b[c]);e[c]=a.from;d[c]=a.to;}return this.parent(e,d);}});Element.Properties.morph={set:function(a){this.get("morph").cancel().setOptions(a);
|
||||
return this;},get:function(){var a=this.retrieve("morph");if(!a){a=new Fx.Morph(this,{link:"cancel"});this.store("morph",a);}return a;}};Element.implement({morph:function(a){this.get("morph").start(a);
|
||||
return this;}});Fx.implement({getTransition:function(){var a=this.options.transition||Fx.Transitions.Sine.easeInOut;if(typeof a=="string"){var b=a.split(":");
|
||||
a=Fx.Transitions;a=a[b[0]]||a[b[0].capitalize()];if(b[1]){a=a["ease"+b[1].capitalize()+(b[2]?b[2].capitalize():"")];}}return a;}});Fx.Transition=function(c,b){b=Array.from(b);
|
||||
var a=function(d){return c(d,b);};return Object.append(a,{easeIn:a,easeOut:function(d){return 1-c(1-d,b);},easeInOut:function(d){return(d<=0.5?c(2*d,b):(2-c(2*(1-d),b)))/2;
|
||||
}});};Fx.Transitions={linear:function(a){return a;}};Fx.Transitions=new Hash(Fx.Transitions);Fx.Transitions.extend=function(a){for(var b in a){Fx.Transitions[b]=new Fx.Transition(a[b]);
|
||||
}};Fx.Transitions.extend({Pow:function(b,a){return Math.pow(b,a&&a[0]||6);},Expo:function(a){return Math.pow(2,8*(a-1));},Circ:function(a){return 1-Math.sin(Math.acos(a));
|
||||
},Sine:function(a){return 1-Math.cos(a*Math.PI/2);},Back:function(b,a){a=a&&a[0]||1.618;return Math.pow(b,2)*((a+1)*b-a);},Bounce:function(f){var e;for(var d=0,c=1;
|
||||
1;d+=c,c/=2){if(f>=(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();}else{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(f){var e=this.options,c=this.response;
|
||||
c.html=f.stripScripts(function(h){c.javascript=h;});var d=c.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);if(d){c.html=d[1];}var b=new Element("div").set("html",c.html);
|
||||
c.tree=b.childNodes;c.elements=b.getElements(e.filter||"*");if(e.filter){c.tree=c.elements;}if(e.update){var g=document.id(e.update).empty();if(e.filter){g.adopt(c.elements);
|
||||
}else{g.set("html",c.html);}}else{if(e.append){var a=document.id(e.append);if(e.filter){c.elements.reverse().inject(a);}else{a.adopt(b.getChildren());}}}if(e.evalScripts){Browser.exec(c.javascript);
|
||||
}this.onSuccess(c.tree,c.elements,c.html,c.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={};
|
||||
}JSON=new Hash({stringify:JSON.stringify,parse:JSON.parse});(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='<object id="'+id+'"';for(var property in properties){build+=" "+property+'="'+properties[property]+'"';
|
||||
}build+=">";for(var param in params){if(params[param]){build+='<param name="'+param+'" value="'+params[param]+'" />';}}build+="</object>";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('<invoke name="'+fn+'" returntype="javascript">'+__flash__argumentsToXML(arguments,2)+"</invoke>");
|
||||
return eval(rs);};})();
|
472
templates/default/js/mootools-more.js
Executable file
@ -0,0 +1,472 @@
|
||||
// MooTools: the javascript framework.
|
||||
// Load this file's selection again by visiting: http://mootools.net/more/f137303781e12a3fb874125002b23b78
|
||||
// Or build this file again with packager using: packager build More/More More/Class.Refactor More/Chain.Wait More/Array.Extras More/Date More/Date.Extras More/Number.Format More/Object.Extras More/String.Extras More/String.QueryString More/URI More/Hash More/Hash.Extras More/Element.Forms More/Element.Measure More/Element.Pin More/Element.Position More/Element.Shortcuts More/Form.Request More/OverText More/Fx.Elements More/Fx.Accordion More/Fx.Move More/Fx.Reveal More/Fx.Scroll More/Fx.Slide More/Fx.SmoothScroll More/Fx.Sort More/Drag More/Drag.Move More/Slider More/Sortables More/Assets More/Color More/Group More/Mask More/Spinner More/Locale More/Locale.en-US.Date More/Locale.en-US.Number More/Locale.en-GB.Date
|
||||
/*
|
||||
---
|
||||
copyrights:
|
||||
- [MooTools](http://mootools.net)
|
||||
|
||||
licenses:
|
||||
- [MIT License](http://mootools.net/license.txt)
|
||||
...
|
||||
*/
|
||||
MooTools.More={version:"1.4.0.1",build:"a4244edf2aa97ac8a196fc96082dd35af1abab87"};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;};(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;c<b;c++){if(c in this){e=e===a?this[c]:d.call(null,e,this[c],c,this);
|
||||
}}return e;},reduceRight:function(c,d){var b=this.length;while(b--){if(b in this){d=d===a?this[b]:c.call(null,d,this[b],b,this);}}return d;}});})();(function(){var b=function(c){return c!=null;
|
||||
};var a=Object.prototype.hasOwnProperty;Object.extend({getFromPath:function(e,f){if(typeof f=="string"){f=f.split(".");}for(var d=0,c=f.length;d<c;d++){if(a.call(e,f[d])){e=e[f[d]];
|
||||
}else{return null;}}return e;},cleanValues:function(c,e){e=e||b;for(var d in c){if(!e(c[d])){delete c[d];}}return c;},erase:function(c,d){if(a.call(c,d)){delete c[d];
|
||||
}return c;},run:function(d){var c=Array.slice(arguments,1);for(var e in d){if(d[e].apply){d[e].apply(d,c);}}return d;}});})();(function(){var b=null,a={},e={};
|
||||
var d=function(g){if(instanceOf(g,f.Set)){return g;}else{return a[g];}};var f=this.Locale={define:function(g,k,i,j){var h;if(instanceOf(g,f.Set)){h=g.name;
|
||||
if(h){a[h]=g;}}else{h=g;if(!a[h]){a[h]=new f.Set(h);}g=a[h];}if(k){g.define(k,i,j);}if(k=="cascade"){return f.inherit(h,i);}if(!b){b=g;}return g;},use:function(g){g=d(g);
|
||||
if(g){b=g;this.fireEvent("change",g);this.fireEvent("langChange",g.name);}return this;},getCurrent:function(){return b;},get:function(h,g){return(b)?b.get(h,g):"";
|
||||
},inherit:function(g,h,i){g=d(g);if(g){g.inherit(h,i);}return this;},list:function(){return Object.keys(a);}};Object.append(f,new Events);f.Set=new Class({sets:{},inherits:{locales:[],sets:{}},initialize:function(g){this.name=g||"";
|
||||
},define:function(j,h,i){var g=this.sets[j];if(!g){g={};}if(h){if(typeOf(h)=="object"){g=Object.merge(g,h);}else{g[h]=i;}}this.sets[j]=g;return this;},get:function(s,k,r){var q=Object.getFromPath(this.sets,s);
|
||||
if(q!=null){var n=typeOf(q);if(n=="function"){q=q.apply(null,Array.from(k));}else{if(n=="object"){q=Object.clone(q);}}return q;}var j=s.indexOf("."),p=j<0?s:s.substr(0,j),m=(this.inherits.sets[p]||[]).combine(this.inherits.locales).include("en-US");
|
||||
if(!r){r=[];}for(var h=0,g=m.length;h<g;h++){if(r.contains(m[h])){continue;}r.include(m[h]);var o=a[m[h]];if(!o){continue;}q=o.get(s,k,r);if(q!=null){return q;
|
||||
}}return"";},inherit:function(h,i){h=Array.from(h);if(i&&!this.inherits.sets[i]){this.inherits.sets[i]=[];}var g=h.length;while(g--){(i?this.inherits.sets[i]:this.inherits.locales).unshift(h[g]);
|
||||
}return this;}});var c=MooTools.lang={};Object.append(c,f,{setLanguage:f.use,getCurrentLanguage:function(){var g=f.getCurrent();return(g)?g.name:null;},set:function(){f.define.apply(this,arguments);
|
||||
return this;},get:function(i,h,g){if(h){i+="."+h;}return f.get(i,g);}});})();Locale.define("en-US","Date",{months:["January","February","March","April","May","June","July","August","September","October","November","December"],months_abbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],days_abbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dateOrder:["month","date","year"],shortDate:"%m/%d/%Y",shortTime:"%I:%M%p",AM:"AM",PM:"PM",firstDayOfWeek:0,ordinal:function(a){return(a>3&&a<21)?"th":["th","st","nd","rd","th"][Math.min(a%10,4)];
|
||||
},lessThanMinuteAgo:"less than a minute ago",minuteAgo:"about a minute ago",minutesAgo:"{delta} minutes ago",hourAgo:"about an hour ago",hoursAgo:"about {delta} hours ago",dayAgo:"1 day ago",daysAgo:"{delta} days ago",weekAgo:"1 week ago",weeksAgo:"{delta} weeks ago",monthAgo:"1 month ago",monthsAgo:"{delta} months ago",yearAgo:"1 year ago",yearsAgo:"{delta} years ago",lessThanMinuteUntil:"less than a minute from now",minuteUntil:"about a minute from now",minutesUntil:"{delta} minutes from now",hourUntil:"about an hour from now",hoursUntil:"about {delta} hours from now",dayUntil:"1 day from now",daysUntil:"{delta} days from now",weekUntil:"1 week from now",weeksUntil:"{delta} weeks from now",monthUntil:"1 month from now",monthsUntil:"{delta} months from now",yearUntil:"1 year from now",yearsUntil:"{delta} years from now"});
|
||||
(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(s){a.Methods[s.toLowerCase()]=s;
|
||||
});var p=function(u,t,s){if(t==1){return u;}return u<Math.pow(10,t-1)?(s||"0")+p(u,t-1,s):u;};a.implement({set:function(u,s){u=u.toLowerCase();var t=f[u]&&"set"+f[u];
|
||||
if(t&&this[t]){this[t](s);}return this;}.overloadSetter(),get:function(t){t=t.toLowerCase();var s=f[t]&&"get"+f[t];if(s&&this[s]){return this[s]();}return null;
|
||||
}.overloadGetter(),clone:function(){return new a(this.get("time"));},increment:function(s,u){s=s||"day";u=u!=null?u:1;switch(s){case"year":return this.increment("month",u*12);
|
||||
case"month":var t=this.get("date");this.set("date",1).set("mo",this.get("mo")+u);return this.set("date",t.min(this.get("lastdayofmonth")));case"week":return this.increment("day",u*7);
|
||||
case"day":return this.set("date",this.get("date")+u);}if(!a.units[s]){throw new Error(s+" is not a supported interval");}return this.set("time",this.get("time")+u*a.units[s]());
|
||||
},decrement:function(s,t){return this.increment(s,-1*(t!=null?t:1));},isLeapYear:function(){return a.isLeapYear(this.get("year"));},clearTime:function(){return this.set({hr:0,min:0,sec:0,ms:0});
|
||||
},diff:function(t,s){if(typeOf(t)=="string"){t=a.parse(t);}return((t-this)/a.units[s||"day"](3,3)).round();},getLastDayOfMonth:function(){return a.daysInMonth(this.get("mo"),this.get("year"));
|
||||
},getDayOfYear:function(){return(a.UTC(this.get("year"),this.get("mo"),this.get("date")+1)-a.UTC(this.get("year"),0,1))/a.units.day();},setDay:function(t,s){if(s==null){s=a.getMsg("firstDayOfWeek");
|
||||
if(s===""){s=1;}}t=(7+a.parseDay(t,true)-s)%7;var u=(7+this.get("day")-s)%7;return this.increment("day",t-u);},getWeek:function(v){if(v==null){v=a.getMsg("firstDayOfWeek");
|
||||
if(v===""){v=1;}}var x=this,u=(7+x.get("day")-v)%7,t=0,w;if(v==1){var y=x.get("month"),s=x.get("date")-u;if(y==11&&s>28){return 1;}if(y==0&&s<-2){x=new a(x).decrement("day",u);
|
||||
u=0;}w=new a(x.get("year"),0,1).get("day")||7;if(w>4){t=-7;}}else{w=new a(x.get("year"),0,1).get("day");}t+=x.get("dayofyear");t+=6-u;t+=(7+w-v)%7;return(t/7);
|
||||
},getOrdinal:function(s){return a.getMsg("ordinal",s||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 s=this.get("timezoneOffset");return((s>0)?"-":"+")+p((s.abs()/60).floor(),2)+p(s%60,2);},setAMPM:function(s){s=s.toUpperCase();
|
||||
var t=this.get("hr");if(t>11&&s=="AM"){return this.decrement("hour",12);}else{if(t<12&&s=="PM"){return this.increment("hour",12);}}return this;},getAMPM:function(){return(this.get("hr")<12)?"AM":"PM";
|
||||
},parse:function(s){this.set("time",a.parse(s));return this;},isValid:function(s){if(!s){s=this;}return typeOf(s)=="date"&&!isNaN(s.valueOf());},format:function(s){if(!this.isValid()){return"invalid date";
|
||||
}if(!s){s="%x %X";}if(typeof s=="string"){s=g[s.toLowerCase()]||s;}if(typeof s=="function"){return s(this);}var t=this;return s.replace(/%([a-z%])/gi,function(v,u){switch(u){case"a":return a.getMsg("days_abbr")[t.get("day")];
|
||||
case"A":return a.getMsg("days")[t.get("day")];case"b":return a.getMsg("months_abbr")[t.get("month")];case"B":return a.getMsg("months")[t.get("month")];
|
||||
case"c":return t.format("%a %b %d %H:%M:%S %Y");case"d":return p(t.get("date"),2);case"e":return p(t.get("date"),2," ");case"H":return p(t.get("hr"),2);
|
||||
case"I":return p((t.get("hr")%12)||12,2);case"j":return p(t.get("dayofyear"),3);case"k":return p(t.get("hr"),2," ");case"l":return p((t.get("hr")%12)||12,2," ");
|
||||
case"L":return p(t.get("ms"),3);case"m":return p((t.get("mo")+1),2);case"M":return p(t.get("min"),2);case"o":return t.get("ordinal");case"p":return a.getMsg(t.get("ampm"));
|
||||
case"s":return Math.round(t/1000);case"S":return p(t.get("seconds"),2);case"T":return t.format("%H:%M:%S");case"U":return p(t.get("week"),2);case"w":return t.get("day");
|
||||
case"x":return t.format(a.getMsg("shortDate"));case"X":return t.format(a.getMsg("shortTime"));case"y":return t.get("year").toString().substr(2);case"Y":return t.get("year");
|
||||
case"z":return t.get("GMTOffset");case"Z":return t.get("Timezone");}return u;});},toISOString:function(){return this.format("iso8601");}}).alias({toJSON:"toISOString",compare:"diff",strftime:"format"});
|
||||
var k=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];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",rfc822:function(s){return k[s.get("day")]+s.format(", %d ")+h[s.get("month")]+s.format(" %Y %H:%M:%S %Z");
|
||||
},rfc2822:function(s){return k[s.get("day")]+s.format(", %d ")+h[s.get("month")]+s.format(" %Y %H:%M:%S %z");},iso8601:function(s){return(s.getUTCFullYear()+"-"+p(s.getUTCMonth()+1,2)+"-"+p(s.getUTCDate(),2)+"T"+p(s.getUTCHours(),2)+":"+p(s.getUTCMinutes(),2)+":"+p(s.getUTCSeconds(),2)+"."+p(s.getUTCMilliseconds(),3)+"Z");
|
||||
}};var c=[],n=a.parse;var r=function(v,x,u){var t=-1,w=a.getMsg(v+"s");switch(typeOf(x)){case"object":t=w[x.get(v)];break;case"number":t=w[x];if(!t){throw new Error("Invalid "+v+" index: "+x);
|
||||
}break;case"string":var s=w.filter(function(y){return this.test(y);},new RegExp("^"+x,"i"));if(!s.length){throw new Error("Invalid "+v+" string");}if(s.length>1){throw new Error("Ambiguous "+v);
|
||||
}t=s[0];}return(u)?w.indexOf(t):t;};var i=1900,o=70;a.extend({getMsg:function(t,s){return Locale.get("Date."+t,s);},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(t,s){var u=new a;
|
||||
return a.daysInMonth(t!=null?t:u.get("mo"),s!=null?s:u.get("year"))*86400000;},year:function(s){s=s||new a().get("year");return a.isLeapYear(s)?31622400000:31536000000;
|
||||
}},daysInMonth:function(t,s){return[31,a.isLeapYear(s)?29:28,31,30,31,30,31,31,30,31,30,31][t];},isLeapYear:function(s){return((s%4===0)&&(s%100!==0))||(s%400===0);
|
||||
},parse:function(v){var u=typeOf(v);if(u=="number"){return new a(v);}if(u!="string"){return v;}v=v.clean();if(!v.length){return null;}var s;c.some(function(w){var t=w.re.exec(v);
|
||||
return(t)?(s=w.handler(t)):false;});if(!(s&&s.isValid())){s=new a(n(v));if(!(s&&s.isValid())){s=new a(v.toInt());}}return s;},parseDay:function(s,t){return r("day",s,t);
|
||||
},parseMonth:function(t,s){return r("month",t,s);},parseUTC:function(t){var s=new a(t);var u=a.UTC(s.get("year"),s.get("mo"),s.get("date"),s.get("hr"),s.get("min"),s.get("sec"),s.get("ms"));
|
||||
return new a(u);},orderIndex:function(s){return a.getMsg("dateOrder").indexOf(s)+1;},defineFormat:function(s,t){g[s]=t;return this;},parsePatterns:c,defineParser:function(s){c.push((s.re&&s.handler)?s:l(s));
|
||||
return this;},defineParsers:function(){Array.flatten(arguments).each(a.defineParser);return this;},define2DigitYearStart:function(s){o=s%100;i=s-o;return this;
|
||||
}}).extend({defineFormats:a.defineFormat.overloadSetter()});var d=function(s){return new RegExp("(?:"+a.getMsg(s).map(function(t){return t.substr(0,3);
|
||||
}).join("|")+")[a-z]*");};var m=function(s){switch(s){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(s){e=s;j.a=j.A=d("days");j.b=j.B=d("months");c.each(function(u,t){if(u.format){c[t]=l(u.format);}});};var l=function(u){if(!e){return{format:u};
|
||||
}var s=[];var t=(u.source||u).replace(/%([a-z])/gi,function(w,v){return m(v)||w;}).replace(/\((?!\?)/g,"(?:").replace(/ (?!\?|\*)/g,",? ").replace(/%([a-z%])/gi,function(w,v){var x=j[v];
|
||||
if(!x){return v;}s.push(v);return"("+x.source+")";}).replace(/\[a-z\]/gi,"[a-z\\u00c0-\\uffff;&]");return{format:u,re:new RegExp("^"+t+"$","i"),handler:function(y){y=y.slice(1).associate(s);
|
||||
var v=new a().clearTime(),x=y.y||y.Y;if(x!=null){q.call(v,"y",x);}if("d" in y){q.call(v,"d",1);}if("m" in y||y.b||y.B){q.call(v,"m",1);}for(var w in y){q.call(v,w,y[w]);
|
||||
}return v;}};};var q=function(s,t){if(!t){return this;}switch(s){case"a":case"A":return this.set("day",a.parseDay(t,true));case"b":case"B":return this.set("mo",a.parseMonth(t,true));
|
||||
case"d":return this.set("date",t);case"H":case"I":return this.set("hr",t);case"m":return this.set("mo",t-1);case"M":return this.set("min",t);case"p":return this.set("ampm",t.replace(/\./g,""));
|
||||
case"S":return this.set("sec",t);case"s":return this.set("ms",("0."+t)*1000);case"w":return this.set("day",t);case"Y":return this.set("year",t);case"y":t=+t;
|
||||
if(t<100){t+=i+(t<o?100:0);}return this.set("year",t);case"z":if(t=="Z"){t="+00";}var u=t.match(/([+-])(\d{2}):?(\d{2})?/);u=(u[1]+"1")*(u[2]*60+(+u[3]||0))+this.getTimezoneOffset();
|
||||
return this.set("time",this-u*60000);}return this;};a.defineParsers("%Y([-./]%m([-./]%d((T| )%X)?)?)?","%Y%m%d(T%H(%M%S?)?)?","%x( %X)?","%d%o( %b( %Y)?)?( %X)?","%b( %d%o)?( %Y)?( %X)?","%Y %b( %d%o( %X)?)?","%o %b %d %X %z %Y","%T","%H:%M( ?%p)?");
|
||||
Locale.addEvent("change",function(s){if(Locale.get("Date")){b(s);}}).fireEvent("change",Locale.getCurrent());})();Date.implement({timeDiffInWords:function(a){return Date.distanceOfTimeInWords(this,a||new Date);
|
||||
},timeDiff:function(f,c){if(f==null){f=new Date;}var h=((f-this)/1000).floor().abs();var e=[],a=[60,60,24,365,0],d=["s","m","h","d","y"],g,b;for(var i=0;
|
||||
i<a.length;i++){if(i&&!h){break;}g=h;if((b=a[i])){g=(h%b);h=(h/b).floor();}e.unshift(g+(d[i]||""));}return e.join(c||":");}}).extend({distanceOfTimeInWords:function(b,a){return Date.getTimePhrase(((a-b)/1000).toInt());
|
||||
},getTimePhrase:function(f){var d=(f<0)?"Until":"Ago";if(f<0){f*=-1;}var b={minute:60,hour:60,day:24,week:7,month:52/12,year:12,eon:Infinity};var e="lessThanMinute";
|
||||
for(var c in b){var a=b[c];if(f<1.5*a){if(f>0.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(b){var a=Locale.get("Number.currency")||{};
|
||||
if(a.scientific==null){a.scientific=false;}a.decimals=b!=null?b:(a.decimals==null?2:a.decimals);return this.format(a);},formatPercentage:function(b){var a=Locale.get("Number.percentage")||{};
|
||||
if(a.suffix==null){a.suffix="%";}a.decimals=b!=null?b:(a.decimals==null?2:a.decimals);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]*?)</"+e+"(?!\\w)>":"</?"+e+"([^>]+)?>",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(j<f.length-1){h=h[k]=l||{};}else{if(typeOf(l)=="array"){l.push(g);}else{h[k]=l!=null?[l,g]:g;
|
||||
}}});});return b;},cleanQueryString:function(a){return this.split("&").filter(function(e){var b=e.indexOf("="),c=b<0?"":e.substr(0,b),d=e.substr(b+1);return a?a.call(null,c,d):(d||d===0);
|
||||
}).join("&");}});(function(){var b=function(){return this.get("value");};var a=this.URI=new Class({Implements:Options,options:{},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(d,c){this.setOptions(c);
|
||||
var e=this.options.base||a.base;if(!d){d=e;}if(d&&d.parsed){this.parsed=Object.clone(d.parsed);}else{this.set("value",d.href||d.toString(),e?new a(e):false);
|
||||
}},parse:function(e,d){var c=e.match(this.regex);if(!c){return false;}c.shift();return this.merge(c.associate(this.parts),d);},merge:function(d,c){if((!d||!d.scheme)&&(!c||!c.scheme)){return false;
|
||||
}if(c){this.parts.every(function(e){if(d[e]){return false;}d[e]=c[e]||"";return true;});}d.port=d.port||this.schemes[d.scheme.toLowerCase()];d.directory=d.directory?this.parseDirectory(d.directory,c?c.directory:""):"/";
|
||||
return d;},parseDirectory:function(d,e){d=(d.substr(0,1)=="/"?"":(e||"/"))+d;if(!d.test(a.regs.directoryDot)){return d;}var c=[];d.replace(a.regs.endSlash,"").split("/").each(function(f){if(f==".."&&c.length>0){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);
|
||||
}});})();(function(){if(this.Hash){return;}var a=this.Hash=new Type("Hash",function(b){if(typeOf(b)=="hash"){b=Object.clone(b.getClean());}for(var c in b){this[c]=b[c];
|
||||
}return this;});this.$H=function(b){return new a(b);};a.implement({forEach:function(b,c){Object.forEach(this,b,c);},getClean:function(){var c={};for(var b in this){if(this.hasOwnProperty(b)){c[b]=this[b];
|
||||
}}return c;},getLength:function(){var c=0;for(var b in this){if(this.hasOwnProperty(b)){c++;}}return c;}});a.alias("each","forEach");a.implement({has:Object.prototype.hasOwnProperty,keyOf:function(b){return Object.keyOf(this,b);
|
||||
},hasValue:function(b){return Object.contains(this,b);},extend:function(b){a.each(b||{},function(d,c){a.set(this,c,d);},this);return this;},combine:function(b){a.each(b||{},function(d,c){a.include(this,c,d);
|
||||
},this);return this;},erase:function(b){if(this.hasOwnProperty(b)){delete this[b];}return this;},get:function(b){return(this.hasOwnProperty(b))?this[b]:null;
|
||||
},set:function(b,c){if(!this[b]||this.hasOwnProperty(b)){this[b]=c;}return this;},empty:function(){a.each(this,function(c,b){delete this[b];},this);return this;
|
||||
},include:function(b,c){if(this[b]==undefined){this[b]=c;}return this;},map:function(b,c){return new a(Object.map(this,b,c));},filter:function(b,c){return new a(Object.filter(this,b,c));
|
||||
},every:function(b,c){return Object.every(this,b,c);},some:function(b,c){return Object.some(this,b,c);},getKeys:function(){return Object.keys(this);},getValues:function(){return Object.values(this);
|
||||
},toQueryString:function(b){return Object.toQueryString(this,b);}});a.alias({indexOf:"keyOf",contains:"hasValue"});})();Hash.implement({getFromPath:function(a){return Object.getFromPath(this,a);
|
||||
},cleanValues:function(a){return new Hash(Object.cleanValues(this,a));},run:function(){Object.run(arguments);}});Element.implement({tidy:function(){this.set("value",this.get("value").tidy());
|
||||
},getTextInRange:function(b,a){return this.get("value").substring(b,a);},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 e={start:0,end:0};var a=this.getDocument().selection.createRange();if(!a||a.parentElement()!=this){return e;}var c=a.duplicate();if(this.type=="text"){e.start=0-c.moveStart("character",-100000);
|
||||
e.end=e.start+a.text.length;}else{var b=this.get("value");var d=b.length;c.moveToElementText(this);c.setEndPoint("StartToEnd",a);if(c.text.length){d-=b.match(/[\n\r]*$/)[0].length;
|
||||
}e.end=d-c.text.length;c.setEndPoint("StartToStart",a);e.start=d-c.text.length;}return e;},getSelectionStart:function(){return this.getSelectedRange().start;
|
||||
},getSelectionEnd:function(){return this.getSelectedRange().end;},setCaretPosition:function(a){if(a=="end"){a=this.get("value").length;}this.selectRange(a,a);
|
||||
return this;},getCaretPosition:function(){return this.getSelectedRange().start;},selectRange:function(e,a){if(this.setSelectionRange){this.focus();this.setSelectionRange(e,a);
|
||||
}else{var c=this.get("value");var d=c.substr(e,a-e).replace(/\r/g,"").length;e=c.substr(0,e).replace(/\r/g,"").length;var b=this.createTextRange();b.collapse(true);
|
||||
b.moveEnd("character",e+d);b.moveStart("character",e);b.select();}return this;},insertAtCursor:function(b,a){var d=this.getSelectedRange();var c=this.get("value");
|
||||
this.set("value",c.substring(0,d.start)+b+c.substring(d.end,c.length));if(a!==false){this.selectRange(d.start,d.start+b.length);}else{this.setCaretPosition(d.start+b.length);
|
||||
}return this;},insertAroundCursor:function(b,a){b=Object.append({before:"",defaultMiddle:"",after:""},b);var c=this.getSelectedText()||b.defaultMiddle;
|
||||
var g=this.getSelectedRange();var f=this.get("value");if(g.start==g.end){this.set("value",f.substring(0,g.start)+b.before+c+b.after+f.substring(g.end,f.length));
|
||||
this.selectRange(g.start+b.before.length,g.end+b.before.length+c.length);}else{var d=f.substring(g.start,g.end);this.set("value",f.substring(0,g.start)+b.before+d+b.after+f.substring(g.end,f.length));
|
||||
var e=g.start+b.before.length;if(a!==false){this.selectRange(e,e+d.length);}else{this.setCaretPosition(e+f.length);}}return this;}});(function(){var b=function(e,d){var f=[];
|
||||
Object.each(d,function(g){Object.each(g,function(h){e.each(function(i){f.push(i+"-"+h+(i=="border"?"-width":""));});});});return f;};var c=function(f,e){var d=0;
|
||||
Object.each(e,function(h,g){if(g.test(f)){d=d+h.toInt();}});return d;};var a=function(d){return !!(!d||d.offsetHeight||d.offsetWidth);};Element.implement({measure:function(h){if(a(this)){return h.call(this);
|
||||
}var g=this.getParent(),e=[];while(!a(g)&&g!=document.body){e.push(g.expose());g=g.getParent();}var f=this.expose(),d=h.call(this);f();e.each(function(i){i();
|
||||
});return d;},expose:function(){if(this.getStyle("display")!="none"){return function(){};}var d=this.style.cssText;this.setStyles({display:"block",position:"absolute",visibility:"hidden"});
|
||||
return function(){this.style.cssText=d;}.bind(this);},getDimensions:function(d){d=Object.merge({computeSize:false},d);var i={x:0,y:0};var h=function(j,e){return(e.computeSize)?j.getComputedSize(e):j.getSize();
|
||||
};var f=this.getParent("body");if(f&&this.getStyle("display")=="none"){i=this.measure(function(){return h(this,d);});}else{if(f){try{i=h(this,d);}catch(g){}}}return Object.append(i,(i.x||i.x===0)?{width:i.x,height:i.y}:{x:i.width,y:i.height});
|
||||
},getComputedSize:function(d){if(d&&d.plains){d.planes=d.plains;}d=Object.merge({styles:["padding","border"],planes:{height:["top","bottom"],width:["left","right"]},mode:"both"},d);
|
||||
var g={},e={width:0,height:0},f;if(d.mode=="vertical"){delete e.width;delete d.planes.width;}else{if(d.mode=="horizontal"){delete e.height;delete d.planes.height;
|
||||
}}b(d.styles,d.planes).each(function(h){g[h]=this.getStyle(h).toInt();},this);Object.each(d.planes,function(i,h){var k=h.capitalize(),j=this.getStyle(h);
|
||||
if(j=="auto"&&!f){f=this.getDimensions();}j=g[h]=(j=="auto")?f[h]:j.toInt();e["total"+k]=j;i.each(function(m){var l=c(m,g);e["computed"+m.capitalize()]=l;
|
||||
e["total"+k]+=l;});},this);return Object.append(e,g);}});})();(function(){var a=false,b=false;var c=function(){var d=new Element("div").setStyles({position:"fixed",top:0,right:0}).inject(document.body);
|
||||
a=(d.offsetTop===0);d.dispose();b=true;};Element.implement({pin:function(h,f){if(!b){c();}if(this.getStyle("display")=="none"){return this;}var j,k=window.getScroll(),l,e;
|
||||
if(h!==false){j=this.getPosition(a?document.body:this.getOffsetParent());if(!this.retrieve("pin:_pinned")){var g={top:j.y-k.y,left:j.x-k.x};if(a&&!f){this.setStyle("position","fixed").setStyles(g);
|
||||
}else{l=this.getOffsetParent();var i=this.getPosition(l),m=this.getStyles("left","top");if(l&&m.left=="auto"||m.top=="auto"){this.setPosition(i);}if(this.getStyle("position")=="static"){this.setStyle("position","absolute");
|
||||
}i={x:m.left.toInt()-k.x,y:m.top.toInt()-k.y};e=function(){if(!this.retrieve("pin:_pinned")){return;}var n=window.getScroll();this.setStyles({left:i.x+n.x,top:i.y+n.y});
|
||||
}.bind(this);this.store("pin:_scrollFixer",e);window.addEvent("scroll",e);}this.store("pin:_pinned",true);}}else{if(!this.retrieve("pin:_pinned")){return this;
|
||||
}l=this.getParent();var d=(l.getComputedStyle("position")!="static"?l:l.getOffsetParent());j=this.getPosition(d);this.store("pin:_pinned",false);e=this.retrieve("pin:_scrollFixer");
|
||||
if(!e){this.setStyles({position:"absolute",top:j.y+k.y,left:j.x+k.x});}else{this.store("pin:_scrollFixer",null);window.removeEvent("scroll",e);}this.removeClass("isPinned");
|
||||
}return this;},unpin:function(){return this.pin(false);},togglePin:function(){return this.pin(!this.retrieve("pin:_pinned"));}});Element.alias("togglepin","togglePin");
|
||||
})();(function(b){var a=Element.Position={options:{relativeTo:document.body,position:{x:"center",y:"center"},offset:{x:0,y:0}},getOptions:function(d,c){c=Object.merge({},a.options,c);
|
||||
a.setPositionOption(c);a.setEdgeOption(c);a.setOffsetOption(d,c);a.setDimensionsOption(d,c);return c;},setPositionOption:function(c){c.position=a.getCoordinateFromValue(c.position);
|
||||
},setEdgeOption:function(d){var c=a.getCoordinateFromValue(d.edge);d.edge=c?c:(d.position.x=="center"&&d.position.y=="center")?{x:"center",y:"center"}:{x:"left",y:"top"};
|
||||
},setOffsetOption:function(f,d){var c={x:0,y:0},g=f.measure(function(){return document.id(this.getOffsetParent());}),e=g.getScroll();if(!g||g==f.getDocument().body){return;
|
||||
}c=g.measure(function(){var i=this.getPosition();if(this.getStyle("position")=="fixed"){var h=window.getScroll();i.x+=h.x;i.y+=h.y;}return i;});d.offset={parentPositioned:g!=document.id(d.relativeTo),x:d.offset.x-c.x+e.x,y:d.offset.y-c.y+e.y};
|
||||
},setDimensionsOption:function(d,c){c.dimensions=d.getDimensions({computeSize:true,styles:["padding","border","margin"]});},getPosition:function(e,d){var c={};
|
||||
d=a.getOptions(e,d);var f=document.id(d.relativeTo)||document.body;a.setPositionCoordinates(d,c,f);if(d.edge){a.toEdge(c,d);}var g=d.offset;c.left=((c.x>=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)){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<c.y){d.totalHeight=c.y;}if(d.totalWidth<c.x){d.totalWidth=c.x;}}this.element.setStyles({width:Array.pick([a,d.totalWidth,d.x]),height:Array.pick([e,d.totalHeight,d.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(b){var a=this.retrieve("mask");if(a){a.destroy();}return this.eliminate("mask").store("mask:options",b);
|
||||
},get:function(){var a=this.retrieve("mask");if(!a){a=new Mask(this,this.retrieve("mask:options"));this.store("mask",a);}return a;}};Element.implement({mask:function(a){if(a){this.set("mask",a);
|
||||
}this.get("mask").show();return this;},unmask:function(){this.get("mask").hide();return this;}});var Spinner=new Class({Extends:Mask,Implements:Chain,options:{"class":"spinner",containerPosition:{},content:{"class":"spinner-content"},messageContainer:{"class":"spinner-msg"},img:{"class":"spinner-img"},fxOptions:{link:"chain"}},initialize:function(c,a){this.target=document.id(c)||document.id(document.body);
|
||||
this.target.store("spinner",this);this.setOptions(a);this.render();this.inject();var b=function(){this.active=false;}.bind(this);this.addEvents({hide:b,show:b});
|
||||
},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(a){if(this.active){return this.chain(this.show.bind(this));}if(!this.hidden){this.callChain.delay(20,this);
|
||||
return this;}this.active=true;return this.parent(a);},showMask:function(a){var b=function(){this.content.position(Object.merge({relativeTo:this.element},this.options.containerPosition));
|
||||
}.bind(this);if(a){this.parent();b();}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);
|
||||
b();this.hidden=false;this.fireEvent("show");this.callChain();}},hide:function(a){if(this.active){return this.chain(this.hide.bind(this));}if(this.hidden){this.callChain.delay(20,this);
|
||||
return this;}this.active=true;return this.parent(a);},hideMask:function(a){if(a){return this.parent();}this.element.tween("opacity",0).get("tween").chain(function(){this.element.setStyle("display","none");
|
||||
this.hidden=true;this.fireEvent("hide");this.callChain();}.bind(this));},destroy:function(){this.content.destroy();this.parent();this.target.eliminate("spinner");
|
||||
}});Request=Class.refactor(Request,{options:{useSpinner:false,spinnerOptions:{},spinnerTarget:false},initialize:function(a){this._send=this.send;this.send=function(b){var c=this.getSpinner();
|
||||
if(c){c.chain(this._send.pass(b,this)).show();}else{this._send(b);}return this;};this.previous(a);},getSpinner:function(){if(!this.spinner){var b=document.id(this.options.spinnerTarget)||document.id(this.options.update);
|
||||
if(this.options.useSpinner&&b){b.set("spinner",this.options.spinnerOptions);var a=this.spinner=b.get("spinner");["complete","exception","cancel"].each(function(c){this.addEvent(c,a.hide.bind(a));
|
||||
},this);}}return this.spinner;}});Element.Properties.spinner={set:function(a){var b=this.retrieve("spinner");if(b){b.destroy();}return this.eliminate("spinner").store("spinner:options",a);
|
||||
},get:function(){var a=this.retrieve("spinner");if(!a){a=new Spinner(this,this.retrieve("spinner:options"));this.store("spinner",a);}return a;}};Element.implement({spin:function(a){if(a){this.set("spinner",a);
|
||||
}this.get("spinner").show();return this;},unspin:function(){this.get("spinner").hide();return this;}});(function(){Events.Pseudos=function(h,e,f){var d="_monitorEvents:";
|
||||
var c=function(i){return{store:i.store?function(j,k){i.store(d+j,k);}:function(j,k){(i._monitorEvents||(i._monitorEvents={}))[j]=k;},retrieve:i.retrieve?function(j,k){return i.retrieve(d+j,k);
|
||||
}:function(j,k){if(!i._monitorEvents){return k;}return i._monitorEvents[j]||k;}};};var g=function(k){if(k.indexOf(":")==-1||!h){return null;}var j=Slick.parse(k).expressions[0][0],p=j.pseudos,i=p.length,o=[];
|
||||
while(i--){var n=p[i].key,m=h[n];if(m!=null){o.push({event:j.tag,value:p[i].value,pseudo:n,original:k,listener:m});}}return o.length?o:null;};return{addEvent:function(m,p,j){var n=g(m);
|
||||
if(!n){return e.call(this,m,p,j);}var k=c(this),r=k.retrieve(m,[]),i=n[0].event,l=Array.slice(arguments,2),o=p,q=this;n.each(function(s){var t=s.listener,u=o;
|
||||
if(t==false){i+=":"+s.pseudo+"("+s.value+")";}else{o=function(){t.call(q,s,u,arguments,o);};}});r.include({type:i,event:p,monitor:o});k.store(m,r);if(m!=i){e.apply(this,[m,p].concat(l));
|
||||
}return e.apply(this,[i,o].concat(l));},removeEvent:function(m,l){var k=g(m);if(!k){return f.call(this,m,l);}var n=c(this),j=n.retrieve(m);if(!j){return this;
|
||||
}var i=Array.slice(arguments,2);f.apply(this,[m,l].concat(i));j.each(function(o,p){if(!l||o.event==l){f.apply(this,[o.type,o.monitor].concat(i));}delete j[p];
|
||||
},this);n.store(m,j);return this;}};};var b={once:function(e,f,d,c){f.apply(this,d);this.removeEvent(e.event,c).removeEvent(e.original,f);},throttle:function(d,e,c){if(!e._throttled){e.apply(this,c);
|
||||
e._throttled=setTimeout(function(){e._throttled=false;},d.value||250);}},pause:function(d,e,c){clearTimeout(e._pause);e._pause=e.delay(d.value||250,this,c);
|
||||
}};Events.definePseudo=function(c,d){b[c]=d;return this;};Events.lookupPseudo=function(c){return b[c];};var a=Events.prototype;Events.implement(Events.Pseudos(b,a.addEvent,a.removeEvent));
|
||||
["Request","Fx"].each(function(c){if(this[c]){this[c].implement(Events.prototype);}});})();(function(){var d={relay:false},c=["once","throttle","pause"],b=c.length;
|
||||
while(b--){d[c[b]]=Events.lookupPseudo(c[b]);}DOMEvent.definePseudo=function(e,f){d[e]=f;return this;};var a=Element.prototype;[Element,Window,Document].invoke("implement",Events.Pseudos(d,a.addEvent,a.removeEvent));
|
||||
})();if(!window.Form){window.Form={};}(function(){Form.Request=new Class({Binds:["onSubmit","onFormValidate"],Implements:[Options,Events,Class.Occlude],options:{requestOptions:{evalScripts:true,useSpinner:true,emulation:false,link:"ignore"},sendButtonClicked:true,extraData:{},resetForm:true},property:"form.request",initialize:function(b,c,a){this.element=document.id(b);
|
||||
if(this.occlude()){return this.occluded;}this.setOptions(a).setTarget(c).attach();},setTarget:function(a){this.target=document.id(a);if(!this.request){this.makeRequest();
|
||||
}else{this.request.setOptions({update:this.target});}return this;},toElement:function(){return this.element;},makeRequest:function(){var a=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(c,e,d,b){["complete","success"].each(function(f){a.fireEvent(f,[a.target,c,e,d,b]);
|
||||
});},failure:function(){a.fireEvent("complete",arguments).fireEvent("failure",arguments);},exception:function(){a.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(a){var c=(a!=false)?"addEvent":"removeEvent";this.element[c]("click:relay(button, input[type=submit])",this.saveClickedButton.bind(this));
|
||||
var b=this.element.retrieve("validator");if(b){b[c]("onFormValidate",this.onFormValidate);}else{this.element[c]("submit",this.onSubmit);}return this;},detach:function(){return this.attach(false);
|
||||
},enable:function(){return this.attach();},disable:function(){return this.detach();},onFormValidate:function(c,b,a){if(!a){return;}var d=this.element.retrieve("validator");
|
||||
if(c||(d&&!d.options.stopOnFailure)){a.stop();this.send();}},onSubmit:function(a){var b=this.element.retrieve("validator");if(b){this.element.removeEvent("submit",this.onSubmit);
|
||||
b.addEvent("onFormValidate",this.onFormValidate);this.element.validate();return;}if(a){a.stop();}this.send();},saveClickedButton:function(b,c){var a=c.get("name");
|
||||
if(!a||!this.options.sendButtonClicked){return;}this.options.extraData[a]=c.get("value")||true;this.clickedCleaner=function(){delete this.options.extraData[a];
|
||||
this.clickedCleaner=function(){};}.bind(this);},clickedCleaner:function(){},send:function(){var b=this.element.toQueryString().trim(),a=Object.toQueryString(this.options.extraData);
|
||||
if(b){b+="&"+a;}else{b=a;}this.fireEvent("send",[this.element,b.parseQueryString()]);this.request.send({data:b,url:this.options.requestOptions.url||this.element.get("action")});
|
||||
this.clickedCleaner();return this;}});Element.implement("formUpdate",function(c,b){var a=this.retrieve("form.request");if(!a){a=new Form.Request(this,c,b);
|
||||
}else{if(c){a.setTarget(c);}if(b){a.setOptions(b).makeRequest();}}a.send();return this;});})();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.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<a;c++){this.addSection(e[c],this.elements[c]);}this.elements.each(function(j,h){if(b.show===h){this.fireEvent("active",[e[h],j]);
|
||||
}else{for(var k in d){j.setStyle(k,0);}}},this);if(b.display||b.display===0||b.initialDisplayFx===false){this.display(b.display,b.initialDisplayFx);}if(b.fixedHeight!==false){b.resetHeight=false;
|
||||
}this.addEvent("complete",this.internalChain.callChain.bind(this.internalChain));},addSection:function(g,d){g=document.id(g);d=document.id(d);this.togglers.include(g);
|
||||
this.elements.include(d);var f=this.togglers,c=this.options,h=f.contains(g),a=f.indexOf(g),b=this.display.pass(a,this);g.store("accordion:display",b).addEvent(c.trigger,b);
|
||||
if(c.height){d.setStyles({"padding-top":0,"border-top":"none","padding-bottom":0,"border-bottom":"none"});}if(c.width){d.setStyles({"padding-left":0,"border-left":"none","padding-right":0,"border-right":"none"});
|
||||
}d.fullOpacity=1;if(c.fixedWidth){d.fullWidth=c.fixedWidth;}if(c.fixedHeight){d.fullHeight=c.fixedHeight;}d.setStyle("overflow","hidden");if(!h){for(var e in this.effects){d.setStyle(e,0);
|
||||
}}return this;},removeSection:function(f,b){var e=this.togglers,a=e.indexOf(f),c=this.elements[a];var d=function(){e.erase(f);this.elements.erase(c);this.detach(f);
|
||||
}.bind(this);if(this.now==a||b!=null){this.display(b!=null?b:(a-1>=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();}});var Accordion=new Class({Extends:Fx.Accordion,initialize:function(){this.parent.apply(this,arguments);
|
||||
var a=Array.link(arguments,{container:Type.isElement});this.container=a.container;},addSection:function(c,b,e){c=document.id(c);b=document.id(b);var d=this.togglers.contains(c);
|
||||
var a=this.togglers.length;if(a&&(!d||e)){e=e!=null?e:a-1;c.inject(this.togglers[e],"before");b.inject(c,"after");}else{if(this.container&&!d){c.inject(this.container);
|
||||
b.inject(this.container);}}return this.parent.apply(this,arguments);}});Fx.Move=new Class({Extends:Fx.Morph,options:{relativeTo:document.body,position:"center",edge:false,offset:{x:0,y:0}},start:function(a){var b=this.element,c=b.getStyles("top","left");
|
||||
if(c.top=="auto"||c.left=="auto"){b.setPosition(b.getPosition(b.getOffsetParent()));}return this.parent(b.position(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;}});(function(){var a=function(d){var b=d.options.hideInputs;
|
||||
if(window.OverText){var c=[null];OverText.each(function(e){c.include("."+e.options.labelClass);});if(c){b+=c.join(", ");}}return(b)?d.element.getElements(b):null;
|
||||
};Fx.Reveal=new Class({Extends:Fx.Morph,options:{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 d=this.element.getComputedSize({styles:this.options.styles,mode:this.options.mode});
|
||||
if(this.options.transitionOpacity){d.opacity=this.options.opacity;}var c={};Object.each(d,function(f,e){c[e]=[f,0];});this.element.setStyles({display:Function.from(this.options.display).call(this),overflow:"hidden"});
|
||||
var b=a(this);if(b){b.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(b){b.setStyle("visibility","visible");}}this.fireEvent("hide",this.element);this.callChain();}.bind(this));this.start(c);
|
||||
}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 d;this.element.measure(function(){d=this.element.getComputedSize({styles:this.options.styles,mode:this.options.mode});
|
||||
}.bind(this));if(this.options.heightOverride!=null){d.height=this.options.heightOverride.toInt();}if(this.options.widthOverride!=null){d.width=this.options.widthOverride.toInt();
|
||||
}if(this.options.transitionOpacity){this.element.setStyle("opacity",0);d.opacity=this.options.opacity;}var c={height:0,display:Function.from(this.options.display).call(this)};
|
||||
Object.each(d,function(f,e){c[e]=0;});c.overflow="hidden";this.element.setStyles(c);var b=a(this);if(b){b.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(b){b.setStyle("visibility","visible");
|
||||
}this.callChain();this.fireEvent("show",this.element);}.bind(this));this.start(d);}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(b){this.get("reveal").cancel().setOptions(b);
|
||||
return this;},get:function(){var b=this.retrieve("reveal");if(!b){b=new Fx.Reveal(this);this.store("reveal",b);}return b;}};Element.Properties.dissolve=Element.Properties.reveal;
|
||||
Element.implement({reveal:function(b){this.get("reveal").setOptions(b).reveal();return this;},dissolve:function(b){this.get("reveal").setOptions(b).dissolve();
|
||||
return this;},nix:function(b){var c=Array.link(arguments,{destroy:Type.isBoolean,options:Type.isObject});this.get("reveal").setOptions(b).dissolve().chain(function(){this[c.destroy?"destroy":"dispose"]();
|
||||
}.bind(this));return this;},wink:function(){var c=Array.link(arguments,{duration:Type.isNumber,options:Type.isObject});var b=this.get("reveal").setOptions(c.options);
|
||||
b.reveal().chain(function(){(function(){b.dissolve();}).delay(c.duration||2000);});}});})();(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]<h[k]){i[k]=f[k];}}if(i[k]==null){i[k]=h[k];}if(e&&e[k]){i[k]=i[k]+e[k];
|
||||
}},this);if(i.x!=h.x||i.y!=h.y){this.start(i.x,i.y);}return this;},toElementCenter:function(e,f,h){f=f?Array.from(f):["x","y"];e=document.id(e);var i={},c=e.getPosition(this.element),d=e.getSize(),b=this.element.getScroll(),g=this.element.getSize();
|
||||
["x","y"].each(function(j){if(f.contains(j)){i[j]=c[j]-(g[j]-d[j])/2;}if(i[j]==null){i[j]=b[j];}if(h&&h[j]){i[j]=i[j]+h[j];}},this);if(i.x!=b.x||i.y!=b.y){this.start(i.x,i.y);
|
||||
}return this;}});Fx.Scroll.implement({scrollToCenter:function(){return this.toElementCenter.apply(this,arguments);},scrollIntoView:function(){return this.toElementEdge.apply(this,arguments);
|
||||
}});function a(b){return(/^(?:body|html)$/i).test(b.tagName);}})();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;}});var SmoothScroll=Fx.SmoothScroll=new Class({Extends:Fx.Scroll,options:{axes:["x","y"]},initialize:function(c,d){d=d||document;
|
||||
this.doc=d.getDocument();this.parent(this.doc,c);var e=d.getWindow(),a=e.location.href.match(/^[^#]*/)[0]+"#",b=$$(this.options.links||this.doc.links);
|
||||
b.each(function(g){if(g.href.indexOf(a)!=0){return;}var f=g.href.substr(a.length);if(f){this.useLink(g,f);}},this);this.addEvent("complete",function(){e.location.hash=this.anchor;
|
||||
this.element.scrollTo(this.to[0],this.to[1]);},true);},useLink:function(b,a){b.addEvent("click",function(d){var c=document.id(a)||this.doc.getElement("a[name="+a+"]");
|
||||
if(!c){return;}d.preventDefault();this.toElement(c,this.options.axes).chain(function(){this.fireEvent("scrolledTo",[b,c]);}.bind(this));this.anchor=a;}.bind(this));
|
||||
return this;}});Fx.Sort=new Class({Extends:Fx.Elements,options:{mode:"vertical"},initialize:function(b,a){this.parent(b,a);this.elements.each(function(c){if(c.getStyle("position")=="static"){c.setStyle("position","relative");
|
||||
}});this.setDefaultOrder();},setDefaultOrder:function(){this.currentOrder=this.elements.map(function(b,a){return a;});},sort:function(){if(!this.check(arguments)){return this;
|
||||
}var e=Array.flatten(arguments);var i=0,a=0,c={},h={},d=this.options.mode=="vertical";var f=this.elements.map(function(m,k){var l=m.getComputedSize({styles:["border","padding","margin"]});
|
||||
var n;if(d){n={top:i,margin:l["margin-top"],height:l.totalHeight};i+=n.height-l["margin-top"];}else{n={left:a,margin:l["margin-left"],width:l.totalWidth};
|
||||
a+=n.width;}var j=d?"top":"left";h[k]={};var o=m.getStyle(j).toInt();h[k][j]=o||0;return n;},this);this.set(h);e=e.map(function(j){return j.toInt();});
|
||||
if(e.length!=this.elements.length){this.currentOrder.each(function(j){if(!e.contains(j)){e.push(j);}});if(e.length>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]<this.limit[c][0])){this.value.now[c]=this.limit[c][0];
|
||||
}}}if(a.grid[c]){this.value.now[c]-=((this.value.now[c]-(this.limit[c][0]||0))%a.grid[c]);}if(a.style){this.element.setStyle(a.modifiers[c],this.value.now[c]+a.unit);
|
||||
}else{this.element[a.modifiers[c]]=this.value.now[c];}}this.fireEvent("drag",[this.element,b]);},cancel:function(a){this.document.removeEvents({mousemove:this.bound.check,mouseup:this.bound.cancel});
|
||||
if(a){this.document.removeEvent(this.selection,this.bound.eventStop);this.fireEvent("cancel",this.element);}},stop:function(b){var a={mousemove:this.bound.drag,mouseup:this.bound.stop};
|
||||
a[this.selection]=this.bound.eventStop;this.document.removeEvents(a);if(b){this.fireEvent("complete",[this.element,b]);}}});Element.implement({makeResizable:function(a){var b=new Drag(this,Object.merge({modifiers:{x:"width",y:"height"}},a));
|
||||
this.store("resizer",b);return b.addEvent("drag",function(){this.fireEvent("resize",b);}.bind(this));}});Drag.Move=new Class({Extends:Drag,options:{droppables:[],container:false,precalculate:false,includeMargins:true,checkDroppables:true},initialize:function(b,a){this.parent(b,a);
|
||||
b=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 c=b.getOffsetParent(),d=b.getStyles("left","top");if(c&&(d.left=="auto"||d.top=="auto")){b.setPosition(b.getPosition(c));
|
||||
}}if(b.getStyle("position")=="static"){b.setStyle("position","absolute");}}this.addEvent("start",this.checkDroppables,true);this.overed=null;},start:function(a){if(this.container){this.options.limit=this.calculateLimit();
|
||||
}if(this.options.precalculate){this.positions=this.droppables.map(function(b){return b.getCoordinates();});}this.parent(a);},calculateLimit:function(){var j=this.element,e=this.container,d=document.id(j.getOffsetParent())||document.body,h=e.getCoordinates(d),c={},b={},k={},g={},m={};
|
||||
["top","right","bottom","left"].each(function(q){c[q]=j.getStyle("margin-"+q).toInt();b[q]=j.getStyle("border-"+q).toInt();k[q]=e.getStyle("margin-"+q).toInt();
|
||||
g[q]=e.getStyle("border-"+q).toInt();m[q]=d.getStyle("padding-"+q).toInt();},this);var f=j.offsetWidth+c.left+c.right,p=j.offsetHeight+c.top+c.bottom,i=0,l=0,o=h.right-g.right-f,a=h.bottom-g.bottom-p;
|
||||
if(this.options.includeMargins){i+=c.left;l+=c.top;}else{o+=c.right;a+=c.bottom;}if(j.getStyle("position")=="relative"){var n=j.getCoordinates(d);n.left-=j.getStyle("left").toInt();
|
||||
n.top-=j.getStyle("top").toInt();i-=n.left;l-=n.top;if(e.getStyle("position")!="relative"){i+=g.left;l+=g.top;}o+=c.left-n.left;a+=c.top-n.top;if(e!=d){i+=k.left+m.left;
|
||||
l+=((Browser.ie6||Browser.ie7)?0:k.top)+m.top;}}else{i-=c.left;l-=c.top;if(e!=d){i+=h.left+g.left;l+=h.top+g.top;}}return{x:[i,o],y:[l,a]};},getDroppableCoordinates:function(c){var b=c.getCoordinates();
|
||||
if(c.getStyle("position")=="fixed"){var a=window.getScroll();b.left+=a.x;b.right+=a.x;b.top+=a.y;b.bottom+=a.y;}return b;},checkDroppables:function(){var a=this.droppables.filter(function(d,c){d=this.positions?this.positions[c]:this.getDroppableCoordinates(d);
|
||||
var b=this.mouse.now;return(b.x>d.left&&b.x<d.right&&b.y<d.bottom&&b.y>d.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)^(a<this.min))){a=this.min;
|
||||
}if(!((this.range>0)^(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:{},snap:4,constrain:false,preventDefault:false},initialize:function(a,b){this.setOptions(b);
|
||||
this.elements=[];this.lists=[];this.idle=true;this.addLists($$(document.id(a)||a));if(!this.options.clone){this.options.revert=false;}if(this.options.revert){this.effect=new Fx.Morph(null,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","textarea"].contains(b.target.get("tag"))){return;}this.idle=false;this.element=a;
|
||||
this.opacity=a.getStyle("opacity");this.list=a.getParent();this.clone=this.getClone(b,a);this.drag=new Drag.Move(this.clone,Object.merge({preventDefault:this.options.preventDefault,snap:this.options.snap,container:this.options.constrain&&this.element.getParent(),droppables:this.getDroppables()},this.options.dragOptions)).addEvents({onSnap:function(){b.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(b);
|
||||
},end:function(){this.drag.detach();this.element.setStyle("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&&a<this.lists.length?b[a]:b;}});var Asset={javascript:function(d,b){if(!b){b={};}var a=new Element("script",{src:d,type:"text/javascript"}),e=b.document||document,c=b.onload||b.onLoad;
|
||||
delete b.onload;delete b.onLoad;delete b.document;if(c){if(typeof a.onreadystatechange!="undefined"){a.addEvent("readystatechange",function(){if(["loaded","complete"].contains(this.readyState)){c.call(this);
|
||||
}});}else{a.addEvent("load",c);}}return a.set(b).inject(e.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);
|
||||
},addEvent:function(e,d){var g=this.instances,a=g.length,f=a,c=new Array(a),b=this;g.each(function(h,j){h.addEvent(e,function(){if(!c[j]){f--;}c[j]=arguments;
|
||||
if(!f){d.call(b,g,h,c);f=a;c=new Array(a);}});});}});})();Locale.define("en-GB","Date",{dateOrder:["date","month","year"],shortDate:"%d/%m/%Y",shortTime:"%H:%M"}).inherit("en-US","Date");
|
1
templates/default/js/userbar.js
Executable file
@ -0,0 +1 @@
|
||||
/* Nothing yet */
|
59
templates/default/lightface/LightFace.Request.js
Executable file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
---
|
||||
description: LightFace.Request
|
||||
|
||||
authors:
|
||||
- David Walsh (http://davidwalsh.name)
|
||||
|
||||
license:
|
||||
- MIT-style license
|
||||
|
||||
requires:
|
||||
core/1.2.1: "*"
|
||||
|
||||
provides:
|
||||
- LightFace.Request
|
||||
...
|
||||
*/
|
||||
LightFace.Request = new Class({
|
||||
Extends: LightFace,
|
||||
options: {
|
||||
url: "",
|
||||
request: {
|
||||
url: false
|
||||
}
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.parent(options);
|
||||
if(this.options.url) this.load();
|
||||
},
|
||||
load: function(url, title) {
|
||||
var props = (Object.append || $extend)({
|
||||
onRequest: function() {
|
||||
this.fade();
|
||||
this.fireEvent("request");
|
||||
}.bind(this),
|
||||
onSuccess: function(response) {
|
||||
this.messageBox.set("html", response);
|
||||
this.fireEvent("success");
|
||||
}.bind(this),
|
||||
onFailure: function() {
|
||||
this.messageBox.set("html", this.options.errorMessage);
|
||||
this.fireEvent("failure");
|
||||
}.bind(this),
|
||||
onComplete: function() {
|
||||
this._resize();
|
||||
this._ie6Size();
|
||||
this.messageBox.setStyle("opacity", 1);
|
||||
this.unfade();
|
||||
this.fireEvent("complete");
|
||||
}.bind(this)
|
||||
},this.options.request);
|
||||
|
||||
if(title && this.title) this.title.set("html", title);
|
||||
if(!props.url) props.url = url || this.options.url;
|
||||
|
||||
new Request(props).send();
|
||||
return this;
|
||||
}
|
||||
});
|
90
templates/default/lightface/LightFace.css
Executable file
@ -0,0 +1,90 @@
|
||||
|
||||
.lightfaceContent {
|
||||
top: -9000px;
|
||||
left: -9000px;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
-moz-box-shadow: 3px 3px 4px rgba(0,0,0,0.6);
|
||||
-webkit-box-shadow: 3px 3px 4px rgba(0,0,0,0.6);
|
||||
box-shadow: 3px 3px 4px rgba(0,0,0,0.6);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.lightfaceContent .lightfaceTitle {
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
font-weight: bold;
|
||||
margin: -1px;
|
||||
margin-bottom: 0;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.lightfaceContent .lightfaceDraggable {
|
||||
cursor:move;
|
||||
}
|
||||
|
||||
.lightfaceContent .lightfaceMessage {
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.lightfaceContent .lightfaceMessage h3,
|
||||
.lightfaceContent .lightfaceMessage h4,
|
||||
.lightfaceContent .lightfaceMessage h5,
|
||||
.lightfaceContent .lightfaceMessage h6 {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.lightfaceContent .lightfaceFooter {
|
||||
padding: 6px 10px;
|
||||
text-align: right;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
.hiddenButton {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.lightfaceOverlay {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
/*
|
||||
background-image: url(images/fbloader.gif);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #fff;
|
||||
*/
|
||||
background: #444;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.lightfaceMessageBox {
|
||||
overflow: auto;
|
||||
padding: 5px 10px;
|
||||
min-height: 20px;
|
||||
position:relative;
|
||||
border-top: 1px solid #eee;
|
||||
color: #000;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
.lightFaceMessageBoxImage {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
background:url(images/fbloader.gif) center center no-repeat #fff;
|
||||
}
|
||||
|
||||
.lightFaceMessageBoxImage img {
|
||||
display: block;
|
||||
}
|
339
templates/default/lightface/LightFace.js
Executable file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
---
|
||||
description: LightFace
|
||||
|
||||
license: MIT-style
|
||||
|
||||
authors:
|
||||
- David Walsh (http://davidwalsh.name)
|
||||
|
||||
requires:
|
||||
- core/1.2.1: "*"
|
||||
|
||||
provides: [LightFace]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var LightFace = new Class({
|
||||
|
||||
Implements: [Options,Events],
|
||||
|
||||
options: {
|
||||
width: "auto",
|
||||
height: "auto",
|
||||
draggable: false,
|
||||
title: "",
|
||||
buttons: [],
|
||||
fadeDelay: 400,
|
||||
fadeDuration: 400,
|
||||
keys: {
|
||||
esc: function() { this.close(); }
|
||||
},
|
||||
content: "<p>Message not specified.</p>",
|
||||
zIndex: 9001,
|
||||
pad: 100,
|
||||
overlayAll: false,
|
||||
constrain: false,
|
||||
resetOnScroll: true,
|
||||
baseClass: "lightface",
|
||||
errorMessage: "<p>The requested file could not be found.</p>"/*,
|
||||
onOpen: $empty,
|
||||
onClose: $empty,
|
||||
onFade: $empty,
|
||||
onUnfade: $empty,
|
||||
onComplete: $empty,
|
||||
onRequest: $empty,
|
||||
onSuccess: $empty,
|
||||
onFailure: $empty
|
||||
*/
|
||||
},
|
||||
|
||||
|
||||
initialize: function(options) {
|
||||
this.setOptions(options);
|
||||
this.state = false;
|
||||
this.buttons = {};
|
||||
this.resizeOnOpen = true;
|
||||
this.ie6 = typeof document.body.style.maxHeight == "undefined";
|
||||
this.draw();
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
|
||||
//create main box
|
||||
this.box = new Element("table",{
|
||||
"class": this.options.baseClass,
|
||||
styles: {
|
||||
"z-index": this.options.zIndex,
|
||||
opacity: 0
|
||||
},
|
||||
tween: {
|
||||
duration: this.options.fadeDuration,
|
||||
onComplete: function() {
|
||||
if(this.box.getStyle("opacity") == 0) {
|
||||
this.box.setStyles({ top: -9000, left: -9000 });
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
}).inject(document.body,"bottom");
|
||||
|
||||
//draw rows and cells; use native JS to avoid IE7 and I6 offsetWidth and offsetHeight issues
|
||||
var verts = ["top","center","bottom"], hors = ["Left","Center","Right"], len = verts.length;
|
||||
for(var x = 0; x < len; x++) {
|
||||
var row = this.box.insertRow(x);
|
||||
for(var y = 0; y < len; y++) {
|
||||
var cssClass = verts[x] + hors[y], cell = row.insertCell(y);
|
||||
cell.className = cssClass;
|
||||
if (cssClass == "centerCenter") {
|
||||
this.contentBox = new Element("div",{
|
||||
"class": "lightfaceContent",
|
||||
styles: {
|
||||
width: this.options.width
|
||||
}
|
||||
});
|
||||
cell.appendChild(this.contentBox);
|
||||
}
|
||||
else {
|
||||
document.id(cell).setStyle("opacity", 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//draw title
|
||||
|
||||
this.title = new Element("h2",{
|
||||
"class": "lightfaceTitle",
|
||||
html: this.options.title
|
||||
}).inject(this.contentBox);
|
||||
|
||||
if(this.options.draggable && window["Drag"] != null) {
|
||||
this.draggable = true;
|
||||
new Drag(this.box, { handle: this.title });
|
||||
this.title.addClass("lightfaceDraggable");
|
||||
}
|
||||
|
||||
//draw message box
|
||||
this.messageBox = new Element("div", {
|
||||
"class": "lightfaceMessageBox",
|
||||
html: this.options.content || "",
|
||||
styles: {
|
||||
height: this.options.height
|
||||
}
|
||||
}).inject(this.contentBox);
|
||||
|
||||
//button container
|
||||
this.footer = new Element("div", {
|
||||
"class": "lightfaceFooter",
|
||||
styles: {
|
||||
display: "none"
|
||||
}
|
||||
}).inject(this.contentBox);
|
||||
|
||||
//draw overlay
|
||||
this.overlay = new Element("div", {
|
||||
html: " ",
|
||||
styles: {
|
||||
opacity: 0,
|
||||
visibility: "hidden",
|
||||
"z-index": this.options.zIndex - 1, // force the overlay under the box
|
||||
},
|
||||
"class": "lightfaceOverlay",
|
||||
tween: {
|
||||
duration: this.options.fadeDuration,
|
||||
onComplete: function() {
|
||||
if(this.overlay.getStyle("opacity") == 0) {
|
||||
// Rehide the overlay when it is transparent
|
||||
this.overlay.setStyle('visibility', 'hidden');
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
}).inject(document.body, 'bottom');
|
||||
if(!this.options.overlayAll) {
|
||||
this.overlay.setStyle("top", (this.title ? this.title.getSize().y - 1: 0));
|
||||
}
|
||||
|
||||
//create initial buttons
|
||||
this.buttons = [];
|
||||
if(this.options.buttons.length) {
|
||||
this.options.buttons.each(function(button) {
|
||||
this.addButton(button.title, button.event, button.color);
|
||||
},this);
|
||||
}
|
||||
|
||||
//focus node
|
||||
this.focusNode = this.box;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// Manage buttons
|
||||
addButton: function(title,clickEvent,color) {
|
||||
this.footer.setStyle("display", "block");
|
||||
var focusClass = "lightfacefocus" + color;
|
||||
this.buttons[title] = (new Element("input", {
|
||||
"class": color ? "button "+color : "button",
|
||||
type: "button",
|
||||
value: title,
|
||||
events: {
|
||||
click: (clickEvent || this.close).bind(this)
|
||||
}
|
||||
}).inject(this.footer));
|
||||
return this;
|
||||
},
|
||||
showButton: function(title) {
|
||||
if(this.buttons[title]) this.buttons[title].removeClass("hiddenButton");
|
||||
return this.buttons[title];
|
||||
},
|
||||
hideButton: function(title) {
|
||||
if(this.buttons[title]) this.buttons[title].addClass("hiddenButton");
|
||||
return this.buttons[title];
|
||||
},
|
||||
|
||||
// Open and close box
|
||||
close: function(fast) {
|
||||
if(this.isOpen) {
|
||||
this.box[fast ? "setStyles" : "tween"]("opacity", 0);
|
||||
this.overlay[fast ? "setStyles" : "tween"]("opacity", 0);
|
||||
this.fireEvent("close");
|
||||
this._detachEvents();
|
||||
this.isOpen = false;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
open: function(fast) {
|
||||
if(!this.isOpen) {
|
||||
this.overlay[fast ? "setStyles" : "tween"]("opacity", 0.4);
|
||||
this.overlay.setStyle("visibility", 'visible');
|
||||
this.box[fast ? "setStyles" : "tween"]("opacity", 1);
|
||||
if(this.resizeOnOpen) this._resize();
|
||||
this.fireEvent("open");
|
||||
this._attachEvents();
|
||||
(function() {
|
||||
this._setFocus();
|
||||
}).bind(this).delay(this.options.fadeDuration + 10);
|
||||
this.isOpen = true;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_setFocus: function() {
|
||||
this.focusNode.setAttribute("tabIndex", 0);
|
||||
this.focusNode.focus();
|
||||
},
|
||||
|
||||
// Show and hide overlay
|
||||
fade: function(fade, delay) {
|
||||
this._ie6Size();
|
||||
(function() {
|
||||
this.overlay.setStyle("opacity", fade || 1);
|
||||
}.bind(this)).delay(delay || 0);
|
||||
this.fireEvent("fade");
|
||||
return this;
|
||||
},
|
||||
unfade: function(delay) {
|
||||
(function() {
|
||||
this.overlay.fade(0);
|
||||
}.bind(this)).delay(delay || this.options.fadeDelay);
|
||||
this.fireEvent("unfade");
|
||||
return this;
|
||||
},
|
||||
_ie6Size: function() {
|
||||
if(this.ie6) {
|
||||
var size = this.contentBox.getSize();
|
||||
var titleHeight = (this.options.overlayAll || !this.title) ? 0 : this.title.getSize().y;
|
||||
this.overlay.setStyles({
|
||||
height: size.y - titleHeight,
|
||||
width: size.x
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Loads content
|
||||
load: function(content, title) {
|
||||
if(content) this.messageBox.set("html", content);
|
||||
title = title || this.options.title;
|
||||
if(title) this.title.set("html", title).setStyle("display", "block");
|
||||
else this.title.setStyle("display", "none");
|
||||
this.fireEvent("complete");
|
||||
return this;
|
||||
},
|
||||
|
||||
// Attaches events when opened
|
||||
_attachEvents: function() {
|
||||
this.keyEvent = function(e){
|
||||
if(this.options.keys[e.key]) this.options.keys[e.key].call(this);
|
||||
}.bind(this);
|
||||
this.focusNode.addEvent("keyup", this.keyEvent);
|
||||
|
||||
this.resizeEvent = this.options.constrain ? function(e) {
|
||||
this._resize();
|
||||
}.bind(this) : function() {
|
||||
this._position();
|
||||
}.bind(this);
|
||||
window.addEvent("resize", this.resizeEvent);
|
||||
|
||||
if(this.options.resetOnScroll) {
|
||||
this.scrollEvent = function() {
|
||||
this._position();
|
||||
}.bind(this);
|
||||
window.addEvent("scroll", this.scrollEvent);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// Detaches events upon close
|
||||
_detachEvents: function() {
|
||||
this.focusNode.removeEvent("keyup", this.keyEvent);
|
||||
window.removeEvent("resize", this.resizeEvent);
|
||||
if(this.scrollEvent) window.removeEvent("scroll", this.scrollEvent);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Repositions the box
|
||||
_position: function() {
|
||||
var windowSize = window.getSize(),
|
||||
scrollSize = window.getScroll(),
|
||||
boxSize = this.box.getSize();
|
||||
this.box.setStyles({
|
||||
left: scrollSize.x + ((windowSize.x - boxSize.x) / 2),
|
||||
top: scrollSize.y + ((windowSize.y - boxSize.y) / 2)
|
||||
});
|
||||
this._ie6Size();
|
||||
return this;
|
||||
},
|
||||
|
||||
// Resizes the box, then positions it
|
||||
_resize: function() {
|
||||
var height = this.options.height;
|
||||
if(height == "auto") {
|
||||
//get the height of the content box
|
||||
var max = window.getSize().y - this.options.pad;
|
||||
if(this.contentBox.getSize().y > max) height = max;
|
||||
}
|
||||
this.messageBox.setStyle("height", height);
|
||||
this._position();
|
||||
},
|
||||
|
||||
// Expose message box
|
||||
toElement: function () {
|
||||
return this.messageBox;
|
||||
},
|
||||
|
||||
// Expose entire modal box
|
||||
getBox: function() {
|
||||
return this.box;
|
||||
},
|
||||
|
||||
// Cleanup
|
||||
destroy: function() {
|
||||
this._detachEvents();
|
||||
this.buttons.each(function(button) {
|
||||
button.removeEvents("click");
|
||||
});
|
||||
this.box.dispose();
|
||||
delete this.box;
|
||||
}
|
||||
});
|
332
templates/default/lightface/LightFaceMod.js
Executable file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
---
|
||||
description: LightFace
|
||||
|
||||
license: MIT-style
|
||||
|
||||
authors:
|
||||
- David Walsh (http://davidwalsh.name)
|
||||
- Chris Page (http://starforge.co.uk/)
|
||||
|
||||
requires:
|
||||
- core/1.2.1: "*"
|
||||
|
||||
provides: [LightFace]
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
var LightFace = new Class({
|
||||
|
||||
Implements: [Options,Events],
|
||||
|
||||
options: {
|
||||
width: "auto",
|
||||
height: "auto",
|
||||
draggable: false,
|
||||
title: "",
|
||||
buttons: [],
|
||||
fadeDelay: 400,
|
||||
fadeDuration: 400,
|
||||
keys: {
|
||||
esc: function() { this.close(); }
|
||||
},
|
||||
content: "<p>Message not specified.</p>",
|
||||
zIndex: 9001,
|
||||
pad: 100,
|
||||
overlayAll: false,
|
||||
constrain: false,
|
||||
resetOnScroll: true,
|
||||
baseClass: "lightface",
|
||||
errorMessage: "<p>The requested file could not be found.</p>"/*,
|
||||
onOpen: $empty,
|
||||
onClose: $empty,
|
||||
onFade: $empty,
|
||||
onUnfade: $empty,
|
||||
onComplete: $empty,
|
||||
onRequest: $empty,
|
||||
onSuccess: $empty,
|
||||
onFailure: $empty
|
||||
*/
|
||||
},
|
||||
|
||||
|
||||
initialize: function(options) {
|
||||
this.setOptions(options);
|
||||
this.state = false;
|
||||
this.buttons = {};
|
||||
this.resizeOnOpen = true;
|
||||
this.ie6 = typeof document.body.style.maxHeight == "undefined";
|
||||
this.draw();
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
|
||||
//create main box
|
||||
this.contentBox = this.box = new Element("div",
|
||||
{
|
||||
"class": "lightfaceContent",
|
||||
styles: {
|
||||
"z-index": this.options.zIndex,
|
||||
width: this.options.width
|
||||
},
|
||||
tween: {
|
||||
duration: this.options.fadeDuration,
|
||||
onComplete: function() {
|
||||
if(this.box.getStyle("opacity") < 0.2) {
|
||||
this.box.setStyles({ top: -9000, left: -9000 });
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
}).inject(document.body, "bottom");
|
||||
|
||||
//draw title
|
||||
this.title = new Element("h2",{
|
||||
"class": "lightfaceTitle",
|
||||
html: this.options.title
|
||||
}).inject(this.contentBox);
|
||||
|
||||
if(this.options.draggable && window["Drag"] != null) {
|
||||
this.draggable = true;
|
||||
new Drag(this.box, { handle: this.title });
|
||||
this.title.addClass("lightfaceDraggable");
|
||||
}
|
||||
|
||||
//draw message box
|
||||
this.messageBox = new Element("div", {
|
||||
"class": "lightfaceMessageBox",
|
||||
html: this.options.content || "",
|
||||
styles: {
|
||||
height: this.options.height
|
||||
}
|
||||
}).inject(this.contentBox);
|
||||
|
||||
//button container
|
||||
this.footer = new Element("div", {
|
||||
"class": "lightfaceFooter",
|
||||
styles: {
|
||||
display: "none"
|
||||
}
|
||||
}).inject(this.contentBox);
|
||||
|
||||
//draw overlay
|
||||
this.overlay = new Element("div", {
|
||||
html: " ",
|
||||
styles: {
|
||||
opacity: 0,
|
||||
visibility: "hidden",
|
||||
"z-index": this.options.zIndex - 1, // force the overlay under the box
|
||||
},
|
||||
"class": "lightfaceOverlay",
|
||||
tween: {
|
||||
duration: this.options.fadeDuration,
|
||||
onComplete: function() {
|
||||
if(this.overlay.getStyle("opacity") == 0) {
|
||||
// Rehide the overlay when it is transparent
|
||||
this.overlay.setStyle('visibility', 'hidden');
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
}).inject(document.body, 'bottom');
|
||||
if(!this.options.overlayAll) {
|
||||
this.overlay.setStyle("top", (this.title ? this.title.getSize().y - 1: 0));
|
||||
}
|
||||
|
||||
//create initial buttons
|
||||
this.buttons = [];
|
||||
if(this.options.buttons.length) {
|
||||
this.options.buttons.each(function(button) {
|
||||
this.addButton(button.title, button.event, button.color);
|
||||
},this);
|
||||
}
|
||||
|
||||
//focus node
|
||||
this.focusNode = this.box;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// Manage buttons
|
||||
addButton: function(title,clickEvent,color) {
|
||||
this.footer.setStyle("display", "block");
|
||||
var focusClass = "lightfacefocus" + color;
|
||||
this.buttons.push(new Element("input", {
|
||||
"class": color ? "button "+color : "button",
|
||||
type: "button",
|
||||
value: title,
|
||||
events: {
|
||||
click: (clickEvent || this.close).bind(this)
|
||||
}
|
||||
}).inject(this.footer));
|
||||
return this;
|
||||
},
|
||||
|
||||
// Remove any existing buttons from the bar
|
||||
clearButtons: function() {
|
||||
this.buttons.each(function(element) {
|
||||
element.removeEvents('click');
|
||||
element.destroy();
|
||||
});
|
||||
this.buttons.empty();
|
||||
this.footer.setStyle("display", "none");
|
||||
},
|
||||
// Set the buttons for the window to the specified ones (is effectively a
|
||||
// clear if newbuttons is null or an empty object)
|
||||
setButtons: function(newbuttons) {
|
||||
this.clearButtons();
|
||||
|
||||
if(newbuttons && newbuttons.length) {
|
||||
newbuttons.each(function(button) {
|
||||
this.addButton(button.title, button.event, button.color);
|
||||
},this);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Open and close box
|
||||
close: function(fast) {
|
||||
if(this.isOpen) {
|
||||
this.box[fast ? "setStyles" : "tween"]("opacity", 0);
|
||||
this.overlay[fast ? "setStyles" : "tween"]("opacity", 0);
|
||||
this.fireEvent("close");
|
||||
this._detachEvents();
|
||||
this.isOpen = false;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
open: function(fast) {
|
||||
if(!this.isOpen) {
|
||||
this.overlay[fast ? "setStyles" : "tween"]("opacity", 0.4);
|
||||
this.overlay.setStyle("visibility", 'visible');
|
||||
this.box[fast ? "setStyles" : "tween"]("opacity", 1);
|
||||
if(this.resizeOnOpen) this._resize();
|
||||
this.fireEvent("open");
|
||||
this._attachEvents();
|
||||
(function() {
|
||||
this._setFocus();
|
||||
}).bind(this).delay(this.options.fadeDuration + 10);
|
||||
this.isOpen = true;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_setFocus: function() {
|
||||
this.focusNode.setAttribute("tabIndex", 0);
|
||||
this.focusNode.focus();
|
||||
},
|
||||
|
||||
// Show and hide overlay
|
||||
fade: function(fade, delay) {
|
||||
this._ie6Size();
|
||||
(function() {
|
||||
this.overlay.setStyle("opacity", fade || 1);
|
||||
}.bind(this)).delay(delay || 0);
|
||||
this.fireEvent("fade");
|
||||
return this;
|
||||
},
|
||||
unfade: function(delay) {
|
||||
(function() {
|
||||
this.overlay.fade(0);
|
||||
}.bind(this)).delay(delay || this.options.fadeDelay);
|
||||
this.fireEvent("unfade");
|
||||
return this;
|
||||
},
|
||||
_ie6Size: function() {
|
||||
if(this.ie6) {
|
||||
var size = this.contentBox.getSize();
|
||||
var titleHeight = (this.options.overlayAll || !this.title) ? 0 : this.title.getSize().y;
|
||||
this.overlay.setStyles({
|
||||
height: size.y - titleHeight,
|
||||
width: size.x
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Loads content
|
||||
load: function(content, title) {
|
||||
if(content) this.messageBox.set("html", content);
|
||||
title = title || this.options.title;
|
||||
if(title) this.title.set("html", title).setStyle("display", "block");
|
||||
else this.title.setStyle("display", "none");
|
||||
this.fireEvent("complete");
|
||||
return this;
|
||||
},
|
||||
|
||||
// Attaches events when opened
|
||||
_attachEvents: function() {
|
||||
this.keyEvent = function(e){
|
||||
if(this.options.keys[e.key]) this.options.keys[e.key].call(this);
|
||||
}.bind(this);
|
||||
this.focusNode.addEvent("keyup", this.keyEvent);
|
||||
|
||||
this.resizeEvent = this.options.constrain ? function(e) {
|
||||
this._resize();
|
||||
}.bind(this) : function() {
|
||||
this._position();
|
||||
}.bind(this);
|
||||
window.addEvent("resize", this.resizeEvent);
|
||||
|
||||
if(this.options.resetOnScroll) {
|
||||
this.scrollEvent = function() {
|
||||
this._position();
|
||||
}.bind(this);
|
||||
window.addEvent("scroll", this.scrollEvent);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// Detaches events upon close
|
||||
_detachEvents: function() {
|
||||
this.focusNode.removeEvent("keyup", this.keyEvent);
|
||||
window.removeEvent("resize", this.resizeEvent);
|
||||
if(this.scrollEvent) window.removeEvent("scroll", this.scrollEvent);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Repositions the box
|
||||
_position: function() {
|
||||
var windowSize = window.getSize(),
|
||||
scrollSize = window.getScroll(),
|
||||
boxSize = this.box.getSize();
|
||||
this.box.setStyles({
|
||||
left: scrollSize.x + ((windowSize.x - boxSize.x) / 2),
|
||||
top: scrollSize.y + ((windowSize.y - boxSize.y) / 2)
|
||||
});
|
||||
this._ie6Size();
|
||||
return this;
|
||||
},
|
||||
|
||||
// Resizes the box, then positions it
|
||||
_resize: function() {
|
||||
var height = this.options.height;
|
||||
if(height == "auto") {
|
||||
//get the height of the content box
|
||||
var max = window.getSize().y - this.options.pad;
|
||||
if(this.contentBox.getSize().y > max) height = max;
|
||||
}
|
||||
this.messageBox.setStyle("height", height);
|
||||
this._position();
|
||||
},
|
||||
|
||||
// Expose message box
|
||||
toElement: function () {
|
||||
return this.messageBox;
|
||||
},
|
||||
|
||||
// Expose entire modal box
|
||||
getBox: function() {
|
||||
return this.box;
|
||||
},
|
||||
|
||||
// Cleanup
|
||||
destroy: function() {
|
||||
this._detachEvents();
|
||||
this.buttons.each(function(button) {
|
||||
button.removeEvents("click");
|
||||
});
|
||||
this.box.dispose();
|
||||
delete this.box;
|
||||
}
|
||||
});
|
BIN
templates/default/lightface/images/b.png
Executable file
After Width: | Height: | Size: 84 B |
BIN
templates/default/lightface/images/bl.png
Executable file
After Width: | Height: | Size: 124 B |
BIN
templates/default/lightface/images/br.png
Executable file
After Width: | Height: | Size: 124 B |
BIN
templates/default/lightface/images/button.png
Executable file
After Width: | Height: | Size: 841 B |
BIN
templates/default/lightface/images/spinner.gif
Executable file
After Width: | Height: | Size: 2.5 KiB |
BIN
templates/default/lightface/images/tl.png
Executable file
After Width: | Height: | Size: 132 B |
BIN
templates/default/lightface/images/tr.png
Executable file
After Width: | Height: | Size: 125 B |
141
templates/default/lightface/version
Executable file
@ -0,0 +1,141 @@
|
||||
Pulled 6 June 2012, modified to overlay whole page:
|
||||
|
||||
diff -Naur orig/LightFace.css mod/LightFace.css
|
||||
--- orig/LightFace.css 2012-06-06 12:08:46.000000000 +0100
|
||||
+++ mod/LightFace.css 2012-06-06 12:08:28.000000000 +0100
|
||||
@@ -20,7 +20,7 @@
|
||||
.lightface .centerLeft, .lightface .centerRight {
|
||||
width: 10px;
|
||||
height: auto;
|
||||
- background-image: url(b.png);
|
||||
+ background-image: url(images/b.png);
|
||||
background-repeat: repeat-y;
|
||||
}
|
||||
|
||||
@@ -31,29 +31,29 @@
|
||||
}
|
||||
|
||||
.lightface .topLeft {
|
||||
- background-image: url(tl.png);
|
||||
+ background-image: url(images/tl.png);
|
||||
background-position: top left;
|
||||
}
|
||||
|
||||
.lightface .topRight {
|
||||
- background-image: url(tr.png);
|
||||
+ background-image: url(images/tr.png);
|
||||
background-position: top right;
|
||||
}
|
||||
|
||||
.lightface .bottomLeft {
|
||||
- background-image: url(bl.png);
|
||||
+ background-image: url(images/bl.png);
|
||||
background-position: bottom left;
|
||||
}
|
||||
|
||||
.lightface .bottomRight {
|
||||
- background-image: url(br.png);
|
||||
+ background-image: url(images/br.png);
|
||||
background-position: bottom right;
|
||||
}
|
||||
|
||||
.lightface .topCenter, .lightface .bottomCenter {
|
||||
width: auto;
|
||||
height: 10px;
|
||||
- background-image: url(b.png);
|
||||
+ background-image: url(images/b.png);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
.lightface .lightfaceFooter label {
|
||||
font-size: 13px;
|
||||
border-style: solid;
|
||||
- background-image:url(button.png);
|
||||
+ background-image:url(images/button.png);
|
||||
cursor:pointer;
|
||||
font-weight:bold;
|
||||
padding:2px 6px 2px 6px;
|
||||
@@ -196,22 +196,23 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
-.lightface .lightfaceOverlay {
|
||||
- position: absolute;
|
||||
+.lightfaceOverlay {
|
||||
+ position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
/*
|
||||
- background-image: url(fbloader.gif);
|
||||
+ background-image: url(images/fbloader.gif);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #fff;
|
||||
*/
|
||||
- background:url(fbloader.gif) center center no-repeat #fff;
|
||||
+ background: #444;
|
||||
+ opacity: 0.5;
|
||||
}
|
||||
|
||||
-.lightface .lightfaceMessageBox {
|
||||
+.lightface .lightfaceMessageBox {
|
||||
overflow: auto;
|
||||
padding: 10px 10px;
|
||||
min-height: 20px;
|
||||
@@ -221,7 +222,7 @@
|
||||
.lightface .lightFaceMessageBoxImage {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
- background:url(fbloader.gif) center center no-repeat #fff;
|
||||
+ background:url(images/fbloader.gif) center center no-repeat #fff;
|
||||
}
|
||||
|
||||
.lightface .lightFaceMessageBoxImage img {
|
||||
diff -Naur orig/LightFace.js mod/LightFace.js
|
||||
--- orig/LightFace.js 2012-06-06 12:07:58.000000000 +0100
|
||||
+++ mod/LightFace.js 2012-06-06 12:49:18.000000000 +0100
|
||||
@@ -135,17 +135,20 @@
|
||||
html: " ",
|
||||
styles: {
|
||||
opacity: 0,
|
||||
- visibility: "hidden"
|
||||
+ visibility: "hidden",
|
||||
+ "z-index": this.options.zIndex - 1, // force the overlay under the box
|
||||
},
|
||||
"class": "lightfaceOverlay",
|
||||
tween: {
|
||||
- link: "chain",
|
||||
duration: this.options.fadeDuration,
|
||||
onComplete: function() {
|
||||
- if(this.overlay.getStyle("opacity") == 0) this.box.focus();
|
||||
+ if(this.overlay.getStyle("opacity") == 0) {
|
||||
+ // Rehide the overlay when it is transparent
|
||||
+ this.overlay.setStyle('visibility', 'hidden');
|
||||
+ }
|
||||
}.bind(this)
|
||||
}
|
||||
- }).inject(this.contentBox);
|
||||
+ }).inject(document.body, 'bottom');
|
||||
if(!this.options.overlayAll) {
|
||||
this.overlay.setStyle("top", (this.title ? this.title.getSize().y - 1: 0));
|
||||
}
|
||||
@@ -206,6 +209,7 @@
|
||||
close: function(fast) {
|
||||
if(this.isOpen) {
|
||||
this.box[fast ? "setStyles" : "tween"]("opacity", 0);
|
||||
+ this.overlay[fast ? "setStyles" : "tween"]("opacity", 0);
|
||||
this.fireEvent("close");
|
||||
this._detachEvents();
|
||||
this.isOpen = false;
|
||||
@@ -215,6 +219,8 @@
|
||||
|
||||
open: function(fast) {
|
||||
if(!this.isOpen) {
|
||||
+ this.overlay[fast ? "setStyles" : "tween"]("opacity", 0.4);
|
||||
+ this.overlay.setStyle("visibility", 'visible');
|
||||
this.box[fast ? "setStyles" : "tween"]("opacity", 1);
|
||||
if(this.resizeOnOpen) this._resize();
|
||||
this.fireEvent("open");
|
2
templates/default/login/act_error.tem
Executable file
@ -0,0 +1,2 @@
|
||||
{L_LOGIN_ACTFAILED}:<br/>
|
||||
<code>***reason***</code>
|
19
templates/default/login/act_form.tem
Executable file
@ -0,0 +1,19 @@
|
||||
***error***
|
||||
<div class="shadowbox logincore">
|
||||
<h2>{L_LOGIN_ACTFORM}</h2>
|
||||
<div class="sbcontent">
|
||||
<div class="loginform">
|
||||
<p>{L_LOGIN_ACTINTRO}</p>
|
||||
<form id="loginform" method="post" action="***target***">
|
||||
<div class="entry">
|
||||
<label for="actcode">{L_LOGIN_ACTCODE}:<br />
|
||||
<input type="text" id="actcode" name="actcode" class="highlight" size="24" maxlength="64" /></label>
|
||||
</div>
|
||||
<div class="submit">
|
||||
<div class="contextlink">(<a href="***url-resend***">{L_LOGIN_SENDACT}</a>)</div>
|
||||
<input type="submit" class="button blue" id="doactivate" name="doactivate" value="{L_LOGIN_ACTIVATE}" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
19
templates/default/login/email_actcode.tem
Executable file
@ -0,0 +1,19 @@
|
||||
{L_LOGIN_RESEND_GREET},
|
||||
|
||||
{L_LOGIN_RESEND_INTRO}
|
||||
|
||||
{L_LOGIN_USERNAME}: ***username***
|
||||
{L_LOGIN_PASSWORD}: ***password***
|
||||
|
||||
{L_LOGIN_REG_ACTNEEDED}
|
||||
|
||||
***act_url***
|
||||
|
||||
{L_LOGIN_REG_ALTACT}
|
||||
|
||||
***act_form***
|
||||
***act_code***
|
||||
|
||||
{L_LOGIN_RESEND_ENJOY}
|
||||
--
|
||||
{L_EMAIL_SIG}
|
18
templates/default/login/email_lockout.tem
Executable file
@ -0,0 +1,18 @@
|
||||
{L_LOGIN_LOCKOUT_GREETING} ***username***,
|
||||
|
||||
{L_LOGIN_LOCKOUT_MESSAGE}
|
||||
|
||||
{L_LOGIN_USERNAME}: ***username***
|
||||
{L_LOGIN_PASSWORD}: ***password***
|
||||
|
||||
{L_LOGIN_LOCKOUT_ACTNEEDED}
|
||||
|
||||
***act_url***
|
||||
|
||||
{L_LOGIN_LOCKOUT_ALTACT}
|
||||
|
||||
***act_form***
|
||||
***act_code***
|
||||
|
||||
--
|
||||
{L_EMAIL_SIG}
|
9
templates/default/login/email_recover.tem
Executable file
@ -0,0 +1,9 @@
|
||||
{L_LOGIN_RECOVER_GREET},
|
||||
|
||||
{L_LOGIN_RECOVER_INTRO}
|
||||
|
||||
***reset_url***
|
||||
|
||||
{L_LOGIN_RECOVER_IGNORE}
|
||||
--
|
||||
{L_EMAIL_SIG}
|
19
templates/default/login/email_registered.tem
Executable file
@ -0,0 +1,19 @@
|
||||
{L_LOGIN_REG_GREETING},
|
||||
|
||||
{L_LOGIN_REG_CREATED}
|
||||
|
||||
{L_LOGIN_USERNAME}: ***username***
|
||||
{L_LOGIN_PASSWORD}: ***password***
|
||||
|
||||
{L_LOGIN_REG_ACTNEEDED}
|
||||
|
||||
***act_url***
|
||||
|
||||
{L_LOGIN_REG_ALTACT}
|
||||
|
||||
***act_form***
|
||||
***act_code***
|
||||
|
||||
{L_LOGIN_REG_ENJOY}
|
||||
--
|
||||
{L_EMAIL_SIG}
|