src.dualinventive.com/mtinfo/dist/webroot/rc-4.05/html/javascript/calender.js

2615 lines
138 KiB
JavaScript

/* *****************************************************************************
JavaScript Advanced Calendar Script (JACS) - Cross-Browser pop-up calendar.
Copyright (C) 2007-2008 Anthony Garrett
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, it is available at
the GNU web site (http://www.gnu.org/) or by writing to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301 USA
*///*****************************************************************************
/*
Contact: Sorry, I can't offer support for this but if you find a problem
(or just want to tell me how useful you find it), please send
me an email at jacsFeedback@tarrget.info (Note the two Rs in
tarrget). I will try to fix problems quickly but this is a
spare time thing for me.
Credits: I wrote this based on my Simple Calendar Widget script which
I wrote from scratch myself but I couldn't have done either
without the superb "JavaScript The Definitive Guide" by David
Flanagan (Pub. O'Reilly ISBN 0-596-00048-0) and Peter-Paul Koch's
(PPK) brilliant Quirksmode site.
Link back: Please give me credit and link back to my page if you can. To
ensure that search engines give my page a higher ranking you can
add the following HTML to any indexed page on your web site:
<A HREF="http://www.tarrget.info/calendar/jacs.htm">
JavaScript Advanced Calendar Script (JACS) by Anthony Garrett
</A>
Your root directory of the web site should also contain an empty
file called "jacsblank.html". For a full explanation see
http://www.tarrget.info/calendar/IEnightmare.html.
Features: Easily customised (output date format, colours, language,
year range and week start day)
Accepts a date as input (see comments below for formats).
Allows multiple calendars on a page and static calendar displays.
Cross-browser code tested against;
Internet Explorer 6.0.28+ Mozilla 1.7.1
Opera 7.52+ Firefox 0.9.1+
Konqueror 4.0.1 Safari 3 (Beta for Windows)
How to add the Calendar to your page:
This script needs to be defined for your page so add the following
line;
<script type='text/JavaScript' src='jacs.js'></script>
How to use the Calendar once it is defined for your page:
Dynamic calendar:
Simply choose an event to trigger the calendar (like an onclick or an onmouseover)
and an element to work on (for the calendar to take its initial date from and write
its output date to) then write it like this;
onclick="JACS.show(document.getElementById('myElement'),event);"
or
onfocus="JACS.show(this,event);"
NOTE: If you wish to use the calendar with an Anchor tag, do not use the
href="javascript:JACS.show(...)" syntax.
Instead you should use the following;
<a href="#" onclick="JACS.show(<<element>>,event);return false;">
<<your text>>
</a>
If you are using a text node then specify the text's parent node in the
function call. The date should be the only text under that node;
<p onclick="JACS.show(this,event);"><<date>></p>
Static calendar:
JACS.show(<<element>><<,optional calendar ID>><<,optional disabled days>>);
A static calendar appears on screen when the page loads, cannot be dragged and
remains on screen after it has been used to select a date. It returns the date
into the value of a defined element (e.g. an INPUT element) but, of course,
that can be hidden.
Calendar with selected days:
You can select days of the week by adding arguments to the
call to JACS.show. These selected days can be the only ones
enabled or the only ones disabled depending on the setting of
the attribute valuesEnabled (see below). The values should be
Sunday = 0 through to Saturday = 6. The parameters can be a
series of single values or an array holding those values. A call
to JACS.show with Friday and Monday selected could look something
like this;
JACS.show(<<element>>,event,5,1);
or this;
var myArray = [5,1];
JACS.show(<<element>>,event,myArray);
Named calendar:
JACS.show(<<element>>,event<<,calendar ID>>);
'jacs' is the default ID of the calendar but you can assign any ID
you want. You can call one name as many times as you like,
but as it is one object, it can only appear on screen in one location
at a time. If you want more than that then you must give different IDs.
[Note: in the above paragraph I use "name" and "id" interchangeably, not
in the sense of HTML tag attributes "name" and "id". ]
No event? No problem!
Normally the calendar will be triggered by an event but if you wish to
control it in code and the event is not available to you, simply pass
an element as the second parameter;
E.G. JACS.show(<<target element>>,<<source element>>);
as in: JACS.show(this,this);
Calendar with post-processing:
The following technique runs a function each time a dynamic calendar
closes or a date is selected from a static calendar:
JACS.show(<<Dynamic or Static calendar argument list>>);
JACS.next(<<optional calendar ID,>><<function>><<,arguments>>);
Where <<function>> is a function defined on the calling page
and <<arguments>> is the list of arguments being passed to that
function.
The calendar ID defaults to 'jacs', if you are using a different
calendar object (See calendar naming above), you must give its
ID as the first argument.
NOTES: These two calls are expected in this order (i.e. show before
next) because JACS.next expects the calendar object to exist.
If JACS.make has not been called for the object and JACS.show
is called after JACS.next then the calendar object may not
exist (if the object has not been created earlier in the
users path through the page) so a JavaScript error would
be generated.
Every function that is triggered using JACS.next() acquires an
attribute JACSid. This attribute holds the value of the
calendar ID that JACS.next() has been called for. So, your
function has access to all of the calendar instance's attributes.
These include;
dateReturned Boolean TRUE if the calendar has been closed by
selection of a date, otherwise FALSE), and
outputDate The user-selected date in JavaScript date format.
E.G. document.getElementById(<<function>>.JACSid).dateReturned
Disabling or enabling dates or date ranges;
Setting enabled or disabled date ranges for a calendar object is
achieved by setting the dates array attribute of the calendar object
(see more information below).
By default the calendar object is only created when it is first
needed for display so you should make sure that it is explicitly
created using;
JACS.make(<<calendar id>><<,dynamic (boolean, default TRUE)>>);
Combining the techniques:
A fully defined call to JACS.show, including all optional parameters
should send parameters in the following order;
I/O Trigger Calendar Selected
Element Event ID days
Dynamic 0 1 2 2/3
Static 0 1 1/2
Type Object Object String Number(s)
Required Yes Yes No No
Default None None 'jacs' None
NOTE: The Trigger Event is ONLY relevant for dynamic calendars
and must be omitted for static calendars.
Dynamic e.g. JACS.show(document.getElementById('myElement1'),
event,'jacs',0,1,2,3,4,5,6);
Static e.g. JACS.show(document.getElementById('myElement2'),
'myCal',0,6);
A single calendar instance must not be called with both Dynamic
and Static parameters (It is only one structure within the page
so it cannot remain visible in one location while it is displayed
in another).
----------------------------------------------------------------------------------
See http://www.tarrget.info/calendar/scw.htm for a full version history
up to version 3.60 and
http://www.tarrget.info/calendar/jacs.htm for versions to date.
Version Date By Description
======= ==== =============== ===========
1.30 2008-05-05 Anthony Garrett Added optional auto-positioning of the
calendar when its normal position would
go off the visible area.
Thanks to Chandramouli Iyer for this
suggestion.
Added an optional "Clear" button for
use when handling a read-only text
input element. Thanks to Sanjay Gangwal
for his suggestion.
1.21 2008-04-11 Anthony Garrett Corrected the input month name parsing
so that it set the calendar to the
right month when long month names used.
Thanks to Ben Diamand for this bug report.
1.20 2008-04-10 Anthony Garrett Added attribute to allow calendar to
appear in "display" mode only (i.e.
dates not selectable.
Added the option to highlight specified
dates and date ranges.
Thanks to Ben Diamand for both
suggestions.
1.11 2008-02-24 Anthony Garrett Trapped calls to script with only a
NAME attribute is set for the target
element when the script really requires
an ID attribute. This is the most
frequent mistake reported to me.
1.10 2008-01-14 Anthony Garrett Restored the ability to use an element
as the second parameter when opening a
dynamic calendar while retaining the
option of passing an event. Thanks to
Thierry Blind and Sergey Snovsky for
the feedback.
Added a calendar attribute that holds the
returned date. This simplifies use of
the calendar within JavaScript. Thanks
to Juha Valvanne for the query that
led to this enhancement.
Fixed bug in the handling of focus events
that caused calendar to fail to appear.
Thanks to Steve Davis for reporting the
problem.
1.00 2007-09-21 Anthony Garrett Fixed JACS.next parameters - thanks to
Rogier Lankhorst for the feedback, also
refined JACS.next processing.
Updated the event trapping to make it
less intrusive on the page body. NOTE:
This requires that a dynamic calendar's
second parameter should be the calling
event (not the calling object as in
previous versions). Thanks to Steve
Davis for the bug report that led to
this change.
Replaced the date input sequence user
configuration setting with parsing the
sequence from the full format. New users
are often confused by the sequence and
in practice (to allow the calendar's date
output to be used for input) the sequence
must always match the full format element
order.
Fixed a bug that caused undelimited
dates to be handled incorrectly. They
are now parsed against the full date
output format then checked for validity.
Thanks to Dan Wood for raising this bug.
Fixed Standards-based (non IE)
calendar dragging which wasn't releasing
the calendar onmouseup.
Fixed problem where selected weekdays
carried over from one call to another
on the same calendar object.
Corrected the Month and Year select box
displays in Opera. They were not changing
when the month was shifted using the
calendar's left and right arrows.
Extended IFRAME backing to all calendar objects
in order to improve calendar display over
some embedded applets and objects. Thanks to
Stanko Kupcevic for his feedback on this.
NOTE: It is not possible to protect any
JavaScript object displayed over an
embedded DYNAMIC (and, therefore refreshed)
object because browsers usually do not
directly control the screen handling within
the object. The best advice therefore remains
to design pages in such a way that the calendar
does not overlap embedded objects.
Added curly braces and semi-colons
for best practice and for robustness
when code is compacted/obfuscated.
0.90 2007-04-04 Anthony Garrett Major re-write of the script to allow
multiple calendar objects visible on
on the page, and to allow static
calendars. Dropped the legacy
"showCal" entry-point function.
Added ability to select calendar
position relative to return value
element. Thanks to Justin Lawrence
for that request.
*///*****************************************************************************
// ********************************************************
// Start of Javascript Advanced Calendar Script (JACS) Code
// ********************************************************
/* *****************************************************************************
EXPOSED CALENDAR OBJECTS (FUNCTIONS):
JACS.make Creates calendar objects;
is called as part of JACS.show (if needed) but can also
be called to create a calendar instance at any time.
JACS.show Entry point for display of a calendar: Called in main page.
JACS.next Sets up a function that runs when a date is selected on a
static calendar or a dynamic calendar moves or closes.
JACS.cals returns an array of all the calendar IDs that have been
used on the page.
NOTES: 1 "used" here means: Invoked with JACS.make or JACS.show.
Calls without a defined calendar ID invoke the default
ID, 'jacs'.
2 Each calendar structure is added to the page when it
is first used. So this array may not hold all dynamic
calendar IDs that are defined on the page. If you
want to be sure that the array does show all of them,
explicitly invoke JACs.make(<<ID>>); for each ID on
page load.
*///*****************************************************************************
// Namespace JACS
// --------------
// This namespace encapsulates all the calendar script code eliminating
// naming conflicts between the JavaScript in this script and your calling
// page(s) [as long as you don't use JACS as a variable of course]. It is
// still possible for CSS inheritance to cause problems but that is unavoidable.
var JACS = new function()
{// This date is used throughout to determine today's date.
var dateNow = new Date(Date.parse(new Date().toDateString()));
// This array keeps track of the defined calendars for the page.
var cals = new Array();
// This function shortens the code replacing
// document.getElementById('myID') with getEl('myId')
// everywhere in the script. It also tries to handle a common
// error when calling the script: when the developer has only
// set a NAME attribute value, so no ID attribute is set.
function getEl(id)
{if (document.getElementById(id) || (!document.getElementById(id) && document.getElementsByName(id).length==0))
// IF An ID attribute is assigned
// OR No ID attribute is assigned but using IE and Opera
// (which will find the NAME attribute value using getElementById)
// OR No element has this ID or NAME attribute value
// (used internally by the script)
// THEN Return the required element.
{return document.getElementById(id);}
else {if (document.getElementsByName(id).length==1)
// IF No ID attribute is assigned
// AND Using a standards-based browser
// AND Only one element has the NAME attribute set to the value
// THEN Return the required element (using the NAME attribute value).
{return document.getElementsByName(id)[0];}
else {if (document.getElementsByName(id).length>1)
{ // IF No ID attribute is assigned
// AND using a standards-based browser
// AND more than one element has the NAME attribute set to the value
// THEN alert developer to fix the fault.
alert( 'JACS' +
' \nCannot uniquely identify element named: ' + id +
'.\nMore than one identical NAME attribute defined' +
'.\nSolution: Assign the required element a unique ID attribute value.');
}
}
}
};
// This DIV inside an IE-only conditional comments is a
// reliable way of setting up object testing for IE.
document.writeln("<!--[if IE]><div id='jacsIE'></div><![endif]-->");
document.writeln("<!--[if lt IE 7]><div id='jacsIElt7'></div><![endif]-->");
//******************************************************************************
//------------------------------------------------------------------------------
// Customisation section
//------------------------------------------------------------------------------
//******************************************************************************
// I have made every effort to isolate the pop-up script from any
// CSS defined on the main page but if you have anything set that
// affects the pop-up (or you may want to change the way it looks)
// then you can address it in the following style sheets.
document.writeln(
'<style type="text/css">' +
'.jacs, .jacsStatic {padding:1px;vertical-align:middle;margin:0px;}' +
'iframe.jacs {position:absolute;visibility:hidden;' +
'top:0px;left:0px;width:1px;height:1px;}' +
'table.jacs, ' +
'table.jacsStatic {padding:0px;visibility:hidden;width:10px;' +
'cursor:default;text-align:center;}' +
'table.jacs {top:0px;left:0px;position:absolute}' +
'</style>' );
// This style sheet can be extracted from the script and edited into regular
// CSS (by removing all occurrences of + and '). That can be used as the
// basis for themes. Classes are described in comments within the style
// sheet.
document.writeln(
'<style type="text/css">' +
'/* IMPORTANT: The JACS calendar script requires all ' +
' the classes defined here. */' +
'table.jacs,' +
'table.jacsStatic {padding: 1px;' +
'vertical-align:middle;' +
'border: ridge 2px;' +
'font-size: 10pt;' +
'font-family: Verdana, Verdana, Geneva, sans-serif;' +
'font-weight: bold;}' +
'td.jacsDrag,' +
'td.jacsHead {padding: 0px 0px;' +
'text-align: center;}' +
'td.jacsDrag {font-size: 8pt;}' +
'select.jacsHead {margin: 1px 1px;' +
'width: 115px;}' +
'input.jacsHead {height: 19px;' +
'width: 19px;' +
'vertical-align:middle;' +
'text-align: center;' +
'margin: 0px 0px 0px 0px;' +
'font-weight: bold;' +
'font-size: 10pt;' +
'font-family: fixedSys;}' +
'td.jacsWeekNumberHead,' +
'td.jacsWeek {padding: 0px;' +
'text-align: center;' +
'font-weight: bold;}' +
'td.jacsNow,' +
'td.jacsNowHover,' +
'td.jacsNow:hover,' +
'td.jacsNowDisabled {padding: 0px;' +
'text-align: center;' +
'vertical-align:middle;' +
'font-size: 8pt;' +
'font-weight: normal;}' +
'table.jacsCells {text-align: center;' +
'font-size: 8pt;' +
'margin: 0px;' +
'width: 96%;}' +
'td.jacsCells,' +
'td.jacsCellsHover,' +
'td.jacsCells:hover,' +
'td.jacsCellsDisabled,' +
'td.jacsCellsExMonth,' +
'td.jacsCellsExMonthHover,' +
'td.jacsCellsExMonth:hover,' +
'td.jacsCellsExMonthDisabled,' +
'td.jacsCellsWeekend,' +
'td.jacsCellsWeekendHover,' +
'td.jacsCellsWeekend:hover,' +
'td.jacsCellsWeekendDisabled,' +
'td.jacsCellsHighlighted,' +
'td.jacsCellsHighlightedHover,' +
'td.jacsCellsHighlighted:hover,' +
'td.jacsCellsHighlightedWeekend,' +
'td.jacsCellsHighlightedWeekendHover,' +
'td.jacsCellsHighlightedWeekend:hover,' +
'td.jacsInputDate,' +
'td.jacsInputDateHover,' +
'td.jacsInputDate:hover,' +
'td.jacsInputDateDisabled,' +
'td.jacsWeekNo,' +
'td.jacsWeeks {padding: 0px;' +
'width: 14%;' +
'height: 8px;' +
'border-width: 1px;' +
'border-style: solid;' +
'font-weight: bold;' +
'vertical-align: middle;}' +
'/* Blend the colours into your page here... */' +
'/* Calendar background */' +
'table.jacs,' +
'table.jacsStatic {background-color: #002F4C;}' +
'/* Drag Handle */' +
'td.jacsDrag {background-color: #9999CC;' +
'color: #CCCCFF;}' +
'/* Week number heading */' +
'td.jacsWeekNumberHead {color: #002F4C;}' +
'/* Week day headings */' +
'td.jacsWeek {color: #CCCCCC;}' +
'/* Week numbers */' +
'td.jacsWeekNo {background-color: #776677;' +
'color: #CCCCCC;}' +
'/* Enabled Days */' +
'/* Week Day */' +
'td.jacsCells {background-color: #FFFFFF;' +
'color: #000000;}' +
'/* Day matching the input date */' +
'td.jacsInputDate {background-color: #F28424;' +
'color: #000000;}' +
'/* Weekend Day */' +
'td.jacsCellsWeekend {background-color: #FFFFFF;' +
'color: #000000;}' +
'/* Day outside the current month */' +
'td.jacsCellsExMonth {background-color: #FFFFFF;' +
'color: #666666;}' +
'/* Today selector */' +
'td.jacsNow {background-color: #002F4C;' +
'color: #FFFFFF;}' +
'/* MouseOver/Hover formatting ' +
' If you want to "turn off" any of the formatting ' +
' then just set to the same as the standard format' +
' above. ' +
' ' +
' Note: The reason that the following are' +
' implemented using both a class and a :hover' +
' pseudoclass is because Opera handles the rendering' +
' involved in the class-swap very poorly and IE6 ' +
' (and below) only implements pseudoclasses on the' +
' anchor tag.' +
'*/' +
'/* Highlighted Days */' +
'/* Week Day */' +
'td.jacsCellsHighlighted {background-color: #E0E0E0;' +
'color: #FF0000;}' +
'/* Weekend Day */' +
'td.jacsCellsHighlightedWeekend {background-color: #E0E0E0;' +
'color: #CC6666;}' +
'/* Active cells */' +
'td.jacsCells:hover,' +
'td.jacsCellsHover,' +
'td.jacsCellsHighlighted:hover,' +
'td.jacsCellsHighlightedHover,' +
'td.jacsCellsHighlightedWeekend:hover,' +
'td.jacsCellsHighlightedWeekendHover ' +
'{background-color: #F28424;' +
'cursor: pointer;' +
'color: #000000;}' +
'/* Day matching the input date */' +
'td.jacsInputDate:hover,' +
'td.jacsInputDateHover {background-color: #F28424;' +
'cursor: pointer;' +
'color: #000000;}' +
'/* Weekend cells */' +
'td.jacsCellsWeekend:hover,' +
'td.jacsCellsWeekendHover {background-color: #F28424;' +
'cursor: pointer;' +
'color: #000000;}' +
'/* Day outside the current month */' +
'td.jacsCellsExMonth:hover,' +
'td.jacsCellsExMonthHover {background-color: #F28424;' +
'cursor: pointer;' +
'color: #000000;}' +
'/* Clear Button */' +
'td.Clear {padding: 0px;}' +
'input.Clear {padding: 0px;' +
'margin-top: 5px;' +
'text-align: center;' +
'font-size: 8pt;}' +
'/* Today selector */' +
'td.jacsNow:hover,' +
'td.jacsNowHover {color: #F28424;' +
'cursor: pointer;' +
'font-weight: bold;}' +
'/* Disabled cells */' +
'/* Week Day */' +
'/* Day matching the input date */' +
'td.jacsInputDateDisabled {background-color: #999999;' +
'color: #000000;}' +
'td.jacsCellsDisabled {background-color: #999999;' +
'color: #000000;}' +
'/* Weekend Day */' +
'td.jacsCellsWeekendDisabled {background-color: #999999;' +
'color: #CC6666;}' +
'/* Day outside the current month */' +
'td.jacsCellsExMonthDisabled {background-color: #999999;' +
'color: #666666;}' +
'td.jacsNowDisabled {background-color: #002F4C;' +
'color: #FFFFFF;}' +
'</style>');
function calAttributes(cal)
{switch (cal.id)
{case 'EnterYourIDHere':
// If you want to vary the attributes for a specific instance
// of the calendar, replace 'EnterYourIDHere' (above) with the
// ID that you have defined for that calendar then amend and
// uncomment the block-commented section below (which is just
// a copy of the default section below with all the
// documentation comments removed).
/*
cal.zIndex = 1;
cal.baseYear = dateNow.getFullYear()-10;
cal.dropDownYears = 20;
cal.weekStart = 1;
cal.weekNumberBaseDay = 4;
cal.weekNumberDisplay = false;
try {jacsSetLanguage(cal);}
catch (exception)
{cal.today = 'Today:';
cal.clear = 'Clear';
cal.drag = 'click here to drag';
cal.monthNames = ['Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec'];
cal.weekInits = ['S','M','T','W','T','F','S'];
cal.invalidDateMsg = 'The entered date is invalid.\n';
cal.outOfRangeMsg = 'The entered date is out of range.';
cal.doesNotExistMsg = 'The entered date does not exist.';
cal.invalidAlert = ['Invalid date (',') ignored.'];
cal.dateSettingError = ['Error ',' is not a Date object.'];
cal.rangeSettingError = ['Error ',' should consist of two elements.'];
}
cal.showInvalidDateMsg = true;
cal.showOutOfRangeMsg = true;
cal.showDoesNotExistMsg = true;
cal.showInvalidAlert = true;
cal.showDateSettingError = true;
cal.showRangeSettingError = true;
cal.delimiters = ['/','-','.',':',',',' '];
cal.dateDisplayFormat = 'dd-mm-yy';
cal.dateFormat = 'DD MMM, YYYY';
cal.strict = false;
cal.dates = new Array();
cal.higlightDates = new Array();
cal.dayCells = [true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true];
cal.outOfRangeDisable = true;
cal.outOfMonthDisable = false;
cal.outOfMonthHide = false;
cal.formatTodayCell = true;
cal.todayCellBorderColour = 'red';
cal.allowDrag = false;
cal.onBlurMoveNext = false;
cal.clickToHide = false;
cal.xBase = 'L'; // L Left, M Middle, R Right or integer pixel offset from left
cal.yBase = 'B'; // T Top, M Middle, B Bottom or integer pixel offset from top
cal.xPosition = 'L'; // L Left, M Middle, R Right or integer pixel offset from left
cal.yPosition = 'T'; // T Top, M Middle, B Bottom or integer pixel offset from top
cal.autoPosition = true;
*/
break;
default:
// cal.zIndex controls how the pop-up calendar interacts with
// the rest of the page. It is usually adequate to leave it
// as 1 (One) but I have made it available here to help anyone
// who needs to alter the level in order to ensure that the
// calendar displays correctly in relation to all other elements
// on the page.
cal.zIndex = 1;
// Set the bounds for the calendar here...
// If you want the year to roll forward you can use something
// like this...
// var baseYear = dateNow.getFullYear()-5;
// alternatively, hard code a date like this...
// var baseYear = 1990;
cal.baseYear = dateNow.getFullYear()-10;
// How many years do want to be valid and to show in the
// drop-down list?
cal.dropDownYears = 20;
// weekStart determines the start of the week in the display
// Set it to: 0 (Zero) for Sunday, 1 (One) for Monday etc..
// Note: Always start the weekInits array with your
// string for Sunday whatever weekStart (below)
// is set to.
cal.weekStart = 1;
// Week numbering rules are generally based on a day in the week
// that determines the first week of the year. ISO 8601 uses
// Thursday (day four when Sunday is day zero). You can alter
// the base day here.
// See http://www.cl.cam.ac.uk/~mgk25/iso-time.html
// for more information
cal.weekNumberBaseDay = 4;
// The week start day for the display is taken as the week start
// for week numbering. This ensures that only one week number
// applies to one line of the calendar table.
// [ISO 8601 begins the week with Day 1 = Monday.]
// If you want to see week numbering on the calendar, set
// this to true. If not, false.
cal.weekNumberDisplay = false;
// If the calendar is given a date that it can't parse a month
// from, it will use a default month. If the following attribute
// is FALSE then the default month is month 6 (June), if set to
// TRUE then the default will be the current month.
cal.defaultToCurrentMonth = false;
// Using multiple languages:
// language var has been set in core.php
cal.language = language;
switch (cal.language)
{
case 'en':
// English
cal.language = 'en';
cal.today = 'Today:';
cal.clear = 'Clear';
cal.drag = 'click here to drag';
cal.monthNames = ['Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec'];
cal.weekInits = ['S','M','T','W','T','F','S'];
cal.invalidDateMsg = 'The entered date is invalid.\n';
cal.outOfRangeMsg = 'The entered date is out of range.';
cal.doesNotExistMsg = 'The entered date does not exist.';
cal.invalidAlert = ['Invalid date (',') ignored.'];
cal.dateSettingError = ['Error ',' is not a Date object.'];
cal.rangeSettingError = ['Error ',' should consist of two elements.'];
break;
default:
// Dutch
cal.language = 'nl';
cal.today = 'Vandaag:';
cal.clear = 'Wissen';
cal.drag = 'Klik hier om te verschuiven';
cal.monthNames = ['Jan','Feb','Mar','Apr','Mei','Jun',
'Jul','Aug','Sep','Okt','Nov','Dec'];
cal.weekInits = ['Z','M','D','W','D','V','Z'];
cal.invalidDateMsg = 'De ingevulde datum is ongeldig.\n';
cal.outOfRangeMsg = 'De ingevulde datum is niet binnen de grenzen.';
cal.doesNotExistMsg = 'De ingevulde datum bestaat niet.';
cal.invalidAlert = ['Ongeldige datum (',') genegeerd.'];
cal.dateSettingError = ['Fout ',' is geen datum object.'];
cal.rangeSettingError = ['Fout ',' moet uit twee elementen bestaan.'];
}
// Each of the calendar's alert message types can be disabled
// independently here.
cal.showInvalidDateMsg = true;
cal.showOutOfRangeMsg = true;
cal.showDoesNotExistMsg = true;
cal.showInvalidAlert = true;
cal.showDateSettingError = true;
cal.showRangeSettingError = true;
// Set the whole calendar as active (dates selectable)
// or inactive (display only)
cal.active = true;
// Set the allowed input date delimiters here...
// E.g. To set the rising slash, hyphen, full-stop (aka stop or
// point), colon, comma and space as delimiters use
// var cal.delimiters = ['/','-','.',':',',',' '];
cal.delimiters = ['/','-','.',':',',',' '];
// Set the format for the displayed 'Today' date and for the
// output date here.
//
// The format is described using delimiters of your choice (as
// set in cal.delimiters above) and case insensitive letters
// D, M and Y.
//
// NOTE: If no delimiters are input then the date output format is used
// to parse the value. This allows less flexiblility in the input
// value than using delimiters but an accurately entered date
// remains parsable.
// Displayed "Today" date format
cal.dateDisplayFormat = 'YYYY-MM-DD';
// Output date format
cal.dateFormat = 'YYYY-MM-DD';
// Note: The delimiters used should be in cal.delimiters.
// Personally I like the fact that entering 31-Sep-2005 (a date
// that doesn't exist) displays 1-Oct-2005, however you may want
// that to be an error. If so, set cal.strict = true. That
// will cause an error message to display and the selected month
// is displayed without a selected day. Thanks to Brad Allan for
// his feedback prompting this feature.
cal.strict = false;
// If you are using ReadOnly or diaabled fields to return the date
// value into, it can be useful to show a button on the calendar
// that allows the value to be cleared. If you want to do that,
// set cal.clearButton = true;
cal.clearButton = true;
// Choose whether the dates and days you specify in cal.dates
// and as parameters to the JACS.show call are enabled (with all
// other dates disabled) or disabled (with all other dates enabled).
cal.valuesEnabled = false;
// If you wish to set any displayed day, e.g. Every Monday,
// you can do it using the following array. The array elements
// match the displayed cells.
//
// With the valuesEnabled attribute FALSE you could put something
// like the following in your calling page to disable all weekend
// days;
//
// for (var i=0;i<<<calendar object>>.dayCells.length;i++)
// {if (i%7%6==0) <<calendar object>>.dayCells[i] = false;}
//
// The above approach will allow you to select days of the week
// for the whole of your page easily. If you need to set different
// selected days for a number of date input fields on your page
// there is an easier way: You can pass optional arguments to
// JACS.show. The syntax is described at the top of this script in
// the section:
// "How to use the Calendar once it is defined for your page:"
//
// It is possible to use these two approaches in combination.
cal.dayCells = [true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true, true];
// You can specify any date (e.g. 24-Jan-2006 or Today) by creating
// an element of the array cal.dates as a date object with the
// value you want to handle. Date ranges can be handled by placing
// an array of two values (Start and End) into an element of this array.
//
// Use cal.valuesEnabled to determine whether any specified dates
// are treated as the only enabled ones or the only disabled ones.
cal.dates = new Array();
// e.g. To specify 10-Dec-2005:
// cal.dates[0] = new Date(2005,11,10);
//
// Or a range from 2004-Dec-25 to 2005-Jan-01:
//
// cal.dates[1] =
// [new Date(2004,11,25),new Date(2005,0,1)];
//
// The following will specify all calendar dates up to
// yesterday:
//
// cal.dates[2] =
// [new Date(cal.baseYear,0,1),
// new Date(dateNow.getFullYear(),
// dateNow.getMonth(),
// dateNow.getDate()-1)];
//
// Remember that Javascript months are zero-based.
// Allow specified dates to be highlighted when they are enabled.
// You can set individual dates or date ranges in the same way as
// above.
cal.highlightDates = new Array();
// Dates that are out of the specified range can be displayed at
// the start of the very first month and end of the very last.
// Set outOfRangeDisable = true to disable these dates
// (or false to allow their selection).
cal.outOfRangeDisable = true;
// Dates that are out of the displayed month are shown at the start
// (unless the month starts on the first day of the week) and end of
// each month. Set outOfMonthDisable = true to disable these dates
// (or false to allow their selection). Set outOfMonthHide = true
// to hide these dates (or false to make them visible).
cal.outOfMonthDisable = false;
cal.outOfMonthHide = false;
// If you want a special format for the cell that contains the current day
// set this to true. This sets a thin border around the cell in the colour
// set by cal.todayCellBorderColour.
cal.formatTodayCell = true;
cal.todayCellBorderColour = '#f00'; // red
// You can allow the calendar to be dragged around the screen by
// using the setting allowDrag = true.
// I can't say I recommend it because of the danger of the user
// forgetting which date field the calendar will update when
// there are multiple date fields on a page.
cal.allowDrag = false;
// It is not easy to code HTML events to make the focus move
// automatically on to the next element in the tab order so
// here is a parameter you can set that will tell the script
// to do it for you. NOTE: The script may have to build a list
// of all the page's elements in tabIndex order to achieve this
// so there can be an overhead to using this feature.
cal.onBlurMoveNext = false;
// You can allow a click on the calendar to close dynamic
// calendars by setting clickToHide = true. If set to false
// the script will hide a dynamic calendar when a date is
// selected or the main page is clicked.
cal.clickToHide = false;
// Dynamic calendar positioning is relative to the return value
// element. The script is supplied with the parameters below
// setting the calendar's top left corner to appear at the
// return element's bottom left corner.
cal.xBase = 'L';
cal.yBase = 'B';
cal.xPosition = 'L';
cal.yPosition = 'T';
// For the horizontal (X) parameters, xBase and xPosition,
// the accepted values are; L - Left
// M - Middle
// R - Right
// or nn - integer pixel offset from left +/-
//
// For the vertical (Y) parameters, yBase and yPosition,
// the accepted values are; T - Top
// M - Middle
// B - Bottom
// or nn - integer pixel offset from top +/-
// The calendar will position itself aligned according to the
// choices above. If automatic positioning is turned
// on with cal.autoPosition = true then if the chosen position
// would cause the calendar to display off the visible screen,
// it is shifted to a position that is visible.
cal.autoPosition = true;
}
// Do not set the value of this calendar attribute. It is used
// to tell you whether a date has been selected or not when
// using the JACS.next feature to trigger a function after the
// calendar is used.
// dateReturned is False unless the user has clicked on an
// active date cell or the value for "Today", in which case
// it is True.
cal.dateReturned = false;
// The most recent date output to the target element is stored
// as an attribute of the calendar. Initialised to Midnight
// on 1st January 1970 (UTC), a selected date can never
// equal this because returned dates are always 12 Midday.
cal.outputDate = new Date(0);
// Finally: The following attributes are used in calendar
// functions. You need do nothing with them here.
cal.seedDate = new Date();
cal.fullInputDate = false;
cal.activeToday = true;
cal.monthSum = 0;
cal.days = new Array();
cal.arrOnNext = new Array();
cal.triggerEle;
cal.targetEle;
};
//******************************************************************************
//------------------------------------------------------------------------------
// End of customisation section
//------------------------------------------------------------------------------
//******************************************************************************
// *******************************************************
// Custom methods for Date, String and Function prototypes
// *******************************************************
// Format a date into the required pattern
Date.prototype.jacsFormat =
function(format,monthNames)
{var charCount = 0,
codeChar = '',
result = '';
for (var i=0;i<=format.length;i++)
{if (i<format.length && format.charAt(i)==codeChar)
{// If we haven't hit the end of the string and
// the format string character is the same as
// the previous one, just clock up one to the
// length of the current element definition
charCount++;
}
else {switch (codeChar)
{case 'y': case 'Y':
result += (this.getFullYear()%Math.pow(10,charCount)).toString().jacsPadLeft(charCount);
break;
case 'm': case 'M':
// If we find an M, check the number of them to
// determine whether to get the month number or
// the month name.
result += (charCount<3)
?(this.getMonth()+1).toString().jacsPadLeft(charCount)
:monthNames[this.getMonth()];
break;
case 'd': case 'D':
// If we find a D, get the date and format it
result += this.getDate().toString().jacsPadLeft(charCount);
break;
default:
// Copy any unrecognised characters across
while (charCount-->0) {result += codeChar;}
}
if (i<format.length)
{// Store the character we have just worked on
codeChar = format.charAt(i);
charCount = 1;
}
}
}
return result;
};
// Left pad zeroes
String.prototype.jacsPadLeft =
function(padToLength)
{var result = '';
for (var i=0;i<(padToLength-this.length);i++) {result += '0'};
return (result+this);
};
// Set up a closure so that any next function can be triggered after the calendar
// has been closed AND that function can take arguments.
Function.prototype.jacsRunNext =
function() {var func = this, args = arguments[0];
func.JACSid = arguments[1];
return function() {return func.apply(this, args);};
};
// **************************************
// Set up calendar events on calling page
// **************************************
if (document.addEventListener)
{window.addEventListener( 'load',jacsLoader,true);}
else {window.attachEvent ('onload',jacsLoader);}
function jacsLoader()
{// Define document level event to hide the calendar on click.
if (document.addEventListener)
{document.addEventListener('click',hide, false);}
else {document.attachEvent('onclick',hide);}
// Create an onBeforeUnload event to handle IE memory leaks.
if (getEl('jacsIElt7')) {window.attachEvent('onbeforeunload',defeatLeaks);}
function defeatLeaks()
{for (var i=0;i<cals.length;i++)
{// Display the week number column (header and row numbers).
getEl(cals[i]+'Week_').style.display='';
for (var j=0;j<6;j++) {getEl(cals[i]+'Week_'+j).style.display='';}
// Set events to null.
getEl(cals[i]+'Now').onclick = null;
getEl(cals[i]+'Now').onmouseover = null;
getEl(cals[i]+'Now').onmouseout = null;
getEl(cals[i]+'ClearButton').onclick = null;
var cal = getEl(cals[i]),
cells = getEl(cals[i]+'Cells').childNodes;
for (var j=0;j<cells.length;j++)
{var rows = cells[j].childNodes;
for (var k=1;k<rows.length;k++)
{rows[k].onclick = null;
rows[k].onmouseover = null;
rows[k].onmouseout = null;
}
}
// Set calendar's leaky custom attributes to null.
cal.arrOnNext = null;
cal.targetEle = null;
}
};
};
// ****************************************************************************
// Start of Main Private Function Library
// ****************************************************************************
function showMonth(bias,calId)
{// Set the selectable Month and Year
// May be called: from the left and right arrows
// (shift month -1 and +1 respectively)
// from the month selection list
// from the year selection list
// from the showCal routine
// (which initiates the display).
var cal = getEl(calId),
showDate = new Date(Date.parse(new Date().toDateString())),
startDate = new Date();
// Set the time to the middle of the day so that the handful of
// regions that have daylight saving shifts that change the day
// of the month (i.e. turn the clock back at midnight or forward
// at 23:00) do not mess up the date display in the calendar.
showDate.setHours(12);
selYears = getEl(calId+'Years');
selMonths = getEl(calId+'Months');
if ( selYears.options.selectedIndex>-1) {cal.monthSum =12*(selYears.options.selectedIndex)+bias;}
if (selMonths.options.selectedIndex>-1) {cal.monthSum+=selMonths.options.selectedIndex;}
showDate.setFullYear(cal.baseYear+Math.floor(cal.monthSum/12),(cal.monthSum%12),1);
// If the Week numbers are displayed, shift the week day names to the right.
getEl(calId+'Week_').style.display = (cal.weekNumberDisplay)?'':'none';
// Opera has a bug with setting the selected index.
// It requires the following work-around to force SELECTs to display correctly.
if (window.opera)
{selMonths.style.display = 'inherit';
selYears.style.display = 'inherit';
}
tmp = (12*parseInt((showDate.getFullYear()-cal.baseYear),10)) + parseInt(showDate.getMonth(),10);
if (tmp > -1 && tmp < (12*cal.dropDownYears))
{selYears.options.selectedIndex = Math.floor(cal.monthSum/12);
selMonths.options.selectedIndex = (cal.monthSum%12);
curMonth = showDate.getMonth();
showDate.setDate((((showDate.getDay()-cal.weekStart)<0)?-6:1)+cal.weekStart-showDate.getDay());
var compareDateValue = new Date(showDate.getFullYear(),showDate.getMonth(),showDate.getDate()).valueOf();
startDate = new Date(showDate);
var now = getEl(calId+'Now');
function nowOutput() {setOutput(dateNow,calId);};
if (cal.dates.length==0)
{if (cal.active && cal.activeToday)
{now.onclick = nowOutput;
now.className = 'jacsNow';
if (getEl('jacsIE'))
{now.onmouseover = changeClass;
now.onmouseout = changeClass;
}
if (document.removeEventListener)
{now.removeEventListener('click',stopPropagation,false);}
else {now.detachEvent( 'onclick',stopPropagation);}
}
else
{now.onclick = null;
now.className = 'jacsNowDisabled';
if (getEl('jacsIE'))
{now.onmouseover = null;
now.onmouseout = null;
}
if (document.addEventListener)
{now.addEventListener('click',stopPropagation,false);}
else {now.attachEvent( 'onclick',stopPropagation);}
}
}
else
{for (var k=0;k<cal.dates.length;k++)
{if (!cal.activeToday ||
(typeof cal.dates[k]=='object' &&
((cal.dates[k].constructor==Date && dateNow.valueOf() == cal.dates[k].valueOf()) ||
(cal.dates[k].constructor==Array && dateNow.valueOf() >= cal.dates[k][0].valueOf() &&
dateNow.valueOf() <= cal.dates[k][1].valueOf()
)
)
)
)
{now.onclick = (cal.active && cal.valuesEnabled)?nowOutput:null;
now.className = (cal.active && cal.valuesEnabled)?'jacsNow':'jacsNowDisabled';
if (getEl('jacsIE'))
{now.onmouseover = (cal.active && cal.valuesEnabled)?changeClass:null;
now.onmouseout = (cal.active && cal.valuesEnabled)?changeClass:null;
}
if (cal.active && cal.valuesEnabled)
{if (document.removeEventListener) {now.removeEventListener('click',stopPropagation,false);}
else {now.detachEvent( 'onclick',stopPropagation);}
}
else
{if (document.addEventListener) {now.addEventListener('click',stopPropagation,false);}
else {now.attachEvent( 'onclick',stopPropagation);}
}
break;
}
else
{now.onclick = (cal.active && cal.valuesEnabled)?null:nowOutput;
now.className = (cal.active && cal.valuesEnabled)?'jacsNowDisabled':'jacsNow';
if (getEl('jacsIE'))
{now.onmouseover = (cal.active && cal.valuesEnabled)?null:changeClass;
now.onmouseout = (cal.active && cal.valuesEnabled)?null:changeClass;
}
if (cal.active && cal.valuesEnabled)
{if (document.addEventListener) {now.addEventListener('click',stopPropagation,false);}
else {now.attachEvent( 'onclick',stopPropagation);}
}
else
{if (document.removeEventListener) {now.removeEventListener('click',stopPropagation,false);}
else {now.detachEvent( 'onclick',stopPropagation);}
}
}
}
}
function setOutput(outputDate,calId)
{var cal = getEl(calId);
if (typeof cal.targetEle.value == 'undefined')
{cal.triggerEle.textNode.replaceData(0,cal.triggerEle.len,outputDate.jacsFormat(cal.dateFormat,cal.monthNames));}
else {cal.ele.value = outputDate.jacsFormat(cal.dateFormat,cal.monthNames);}
cal.dateReturned = true;
cal.outputDate = outputDate;
if (cal.dynamic) {hide(calId);}
else {if (typeof cal.onNext!='undefined' && cal.onNext!=null) {cal.onNext();}
JACS.show(cal.ele,cal.id,cal.days);
}
if (cal.onBlurMoveNext)
{// if the target element has a tabIndex look for tabIndex+1
// if that exists then set the focus to it
var tagsToFind = 'INPUT;A;SELECT;TEXTAREA;BUTTON;AREA;OBJECT',
found = false;
if (cal.ele.tabIndex>0)
{var tags = tagsToFind.split(';');
tagsOuterLoop:
for (var i=0;tags.length;i++)
{elementsByTag = document.getElementsByTagName(tags[i]);
for (var j=0;j<elementsByTag.length;j++)
{if (elementsByTag[j].tabIndex==(cal.ele.tabIndex+1) && !elementsByTag[j].disabled &&
elementsByTag[j].type!='hidden' && elementsByTag[j].style.display!='none' &&
elementsByTag[j].style.visibility!='hidden')
{elementsByTag[j].focus();
found = true;
break tagsOuterLoop;
}
}
}
}
// else do the full search to find the next element
if (!found)
{// find element tabIndices
function orderElements()
{var tabOrder = new Array,
unordered = new Array;
function elementArrays(ele)
{for (var i=0;i<ele.childNodes.length;i++)
{var tempEle = ele.childNodes[i];
if (tempEle.nodeType==1 && tempEle.style.display!='none' &&
!tempEle.disabled && tempEle.type!='hidden' &&
tempEle.style.visibility!='hidden')
{if (tagsToFind.indexOf(tempEle.tagName)>-1)
{if (tempEle.tabIndex>0) {tabOrder[tempEle.tabIndex] = tempEle}
else {unordered[unordered.length] = tempEle}
}
elementArrays(tempEle);
}
}
};
elementArrays(document.body);
while (tabOrder.length>0 && tabOrder[0]==null) {tabOrder.shift();}
return tabOrder.concat(unordered);
};
var tabSequenced = orderElements();
// find the current element in tabIndex ordered array
// and set focus to the next element (or the first if
// the current is the last)
for (var i=0;i<tabSequenced.length;i++)
{if (tabSequenced[i]==cal.targetEle)
{if (i<(tabSequenced.length-1)) {tabSequenced[i+1].focus()}
else {tabSequenced[0].focus()}
break;
}
}
}
}
else
{if (!cal.targetEle.disabled && cal.targetEle.style.display!='none' &&
cal.targetEle.type!='hidden' && cal.targetEle.style.visibility!='hidden')
{cal.targetEle.focus();}
}
};
function changeClass(evt)
{var ele = eventTrigger(evt);
if (ele.nodeType==3) {ele=ele.parentNode;}
if (((evt)?evt.type:event.type)=='mouseover')
{switch (ele.className)
{case 'jacsCells':
ele.className = 'jacsCellsHover'; break;
case 'jacsCellsHighlighted':
ele.className = 'jacsCellsHighlightedHover'; break;
case 'jacsCellsExMonth':
ele.className = 'jacsCellsExMonthHover'; break;
case 'jacsCellsWeekend':
ele.className = 'jacsCellsWeekendHover'; break;
case 'jacsCellsHighlightedWeekend':
ele.className = 'jacsCellsHighlightedWeekendHover'; break;
case 'jacsNow':
ele.className = 'jacsNowHover'; break;
case 'jacsInputDate':
ele.className = 'jacsInputDateHover';
}
}
else
{switch (ele.className)
{case 'jacsCellsHover':
ele.className = 'jacsCells'; break;
case 'jacsCellsHighlightedHover':
ele.className = 'jacsCellsHighlighted'; break;
case 'jacsCellsExMonthHover':
ele.className = 'jacsCellsExMonth'; break;
case 'jacsCellsWeekendHover':
ele.className = 'jacsCellsWeekend'; break;
case 'jacsCellsHighlightedWeekendHover':
ele.className = 'jacsCellsHighlightedWeekend'; break;
case 'jacsNowHover':
ele.className = 'jacsNow'; break;
case 'jacsInputDateHover':
ele.className = 'jacsInputDate';
}
}
return true;
};
function eventTrigger(evt)
{if (!evt) {evt = event;}
return evt.target||evt.srcElement;
};
function weekNumber(inDate)
{// The base day in the week of the input date
var inDateWeekBase = new Date(inDate);
inDateWeekBase.setDate(inDateWeekBase.getDate() - inDateWeekBase.getDay() + cal.weekNumberBaseDay +
((inDate.getDay() > cal.weekNumberBaseDay)?7:0));
// The first Base Day in the year
var firstBaseDay = new Date(inDateWeekBase.getFullYear(),0,1);
firstBaseDay.setDate(firstBaseDay.getDate() - firstBaseDay.getDay() + cal.weekNumberBaseDay);
if (firstBaseDay<new Date(inDateWeekBase.getFullYear(),0,1))
{firstBaseDay.setDate(firstBaseDay.getDate()+7);}
// Start of Week 01
var startWeekOne = new Date(firstBaseDay - cal.weekNumberBaseDay + inDate.getDay());
if (startWeekOne>firstBaseDay) {startWeekOne.setDate(startWeekOne.getDate()-7);}
// Subtract the date of the current week from the date of the first week of the year to
// get the number of weeks in milliseconds. Divide by the number of milliseconds in a
// week then round to no decimals in order to remove the effect of daylight saving. Add
// one to make the first week, week 1. Place a string zero on the front so that week
// numbers are zero filled.
var weekNo = '0'+(Math.round((inDateWeekBase - firstBaseDay)/604800000,0)+1);
// Return the last two characters in the week number string
return weekNo.substring(weekNo.length-2,weekNo.length);
};
// walk the DOM to display the dates.
var cells = getEl(calId+'Cells').childNodes;
for (var i=0;i<cells.length;i++)
{var rows = cells[i];
if (rows.nodeType==1 && rows.tagName=='TR')
{tmpEl = rows.childNodes[0];
if (cal.weekNumberDisplay)
{//Calculate the week number using showDate
tmpEl.innerHTML = weekNumber(showDate);
tmpEl.style.borderColor =
(tmpEl.currentStyle)
?tmpEl.currentStyle['backgroundColor']
:(document.defaultView.getComputedStyle)
?document.defaultView.getComputedStyle(tmpEl,null).backgroundColor
:'';
tmpEl.style.display = '';
}
else {tmpEl.style.display='none';}
for (var j=1;j<rows.childNodes.length;j++)
{var cols = rows.childNodes[j];
if (cols.nodeType==1 && cols.tagName=='TD')
{rows.childNodes[j].innerHTML = showDate.getDate();
var cell = rows.childNodes[j];
cell.style.visibility = (cal.outOfMonthHide &&
(showDate < (new Date(showDate.getFullYear(),curMonth,1,showDate.getHours())) ||
showDate > (new Date(showDate.getFullYear(),curMonth+1,0,showDate.getHours()))
)
)?'hidden':'inherit';
// Disable if the outOfRangeDisable option has been set and the current date
// is out of range or the cal.valuesEnabled option is true.
var disabled = cal.valuesEnabled;
if ((cal.outOfRangeDisable && (showDate < (new Date(cal.baseYear,0,1,12)) ||
showDate > (new Date(cal.baseYear+cal.dropDownYears,0,0,12))
)
) ||
(cal.outOfMonthDisable && (showDate < (new Date(showDate.getFullYear(),curMonth,1,showDate.getHours())) ||
showDate > (new Date(showDate.getFullYear(),curMonth+1,0,showDate.getHours()))
)
)
) {disabled = true;}
else
{if ((cal.days.join().search(((j-1+(7*(i*cells.length/6))+cal.weekStart)%7))>-1) ||
!cal.dayCells[j-1+(7*((i*cells.length)/6))]
) {disabled = !cal.valuesEnabled;} // Set (Disable or Enable) if the day is passed as a parameter of JACS.show
else {for (var k=0;k<cal.dates.length;k++)
{if (typeof cal.dates[k]=='object' &&
((cal.dates[k].constructor==Date && compareDateValue == cal.dates[k].valueOf()) ||
(cal.dates[k].constructor==Array && compareDateValue >= cal.dates[k][0].valueOf() &&
compareDateValue <= cal.dates[k][1].valueOf()
)
)
)
{disabled = !cal.valuesEnabled;
break;
}
}
}
}
if (disabled)
{rows.childNodes[j].onclick = null;
if (getEl('jacsIE'))
{rows.childNodes[j].onmouseover = null;
rows.childNodes[j].onmouseout = null;
}
cell.className=
(showDate.getMonth()!=curMonth)
?'jacsCellsExMonthDisabled'
:(cal.fullInputDate &&
compareDateValue==
cal.seedDate.valueOf())
?'jacsInputDateDisabled'
:(showDate.getDay()%6==0)
?'jacsCellsWeekendDisabled'
:'jacsCellsDisabled';
cell.style.borderColor =
(cal.formatTodayCell && showDate.toDateString()==dateNow.toDateString())
?cal.todayCellBorderColour
:(cell.currentStyle)
?cell.currentStyle['backgroundColor']
:(document.defaultView.getComputedStyle)
?document.defaultView.getComputedStyle(cell,null).backgroundColor
:'';
}
else
{function cellOutput(evt)
{var ele = eventTrigger(evt),
outputDate = new Date(startDate);
if (ele.nodeType==3) ele=ele.parentNode;
outputDate.setDate(startDate.getDate() +
parseInt(ele.id.substr(calId.length+5),10));
setOutput(outputDate,calId);
};
if (cal.active)
{rows.childNodes[j].onclick=cellOutput;}
if (getEl('jacsIE'))
{rows.childNodes[j].onmouseover = changeClass;
rows.childNodes[j].onmouseout = changeClass;
}
var highlighted = false;
for (var k=0;k<cal.highlightDates.length;k++)
{if (typeof cal.highlightDates[k]=='object' &&
((cal.highlightDates[k].constructor==Date &&
compareDateValue == cal.highlightDates[k].valueOf()) ||
(cal.highlightDates[k].constructor==Array &&
compareDateValue >= cal.highlightDates[k][0].valueOf() &&
compareDateValue <= cal.highlightDates[k][1].valueOf()
)
)
)
{highlighted = true;
break;
}
}
cell.className=
(showDate.getMonth()!=curMonth)
?'jacsCellsExMonth'
:(cal.fullInputDate &&
compareDateValue==
cal.seedDate.valueOf())
?'jacsInputDate'
:(showDate.getDay()%6==0)
?(highlighted)?'jacsCellsHighlightedWeekend':'jacsCellsWeekend'
:(highlighted)?'jacsCellsHighlighted':'jacsCells';
cell.style.borderColor =
(cal.formatTodayCell && showDate.toDateString()==dateNow.toDateString())
?cal.todayCellBorderColour
:(cell.currentStyle)
?cell.currentStyle['backgroundColor']
:(document.defaultView.getComputedStyle)
?document.defaultView.getComputedStyle(cell,null).backgroundColor
:'';
}
showDate.setDate(showDate.getDate()+1);
compareDateValue = new Date(showDate.getFullYear(),
showDate.getMonth(),
showDate.getDate()).valueOf();
}
}
}
}
}
// Opera has a bug with setting the selected index.
// It requires the following work-around to force SELECTs to display correctly.
// Also Opera's poor dynamic rendering prior to 9.5 requires
// the visibility to be reset to prevent garbage in the calendar
// when the displayed month is changed.
if (window.opera)
{selMonths.style.display = 'inline';
selYears.style.display = 'inline';
cal.style.visibility = 'hidden';
cal.style.visibility = 'inherit';
}
};
function hide(instanceID)
{if (typeof instanceID=='object')
{for (var i=0;i<cals.length;i++) {hideOne(cals[i]);}}
else {hideOne(instanceID);}
function hideOne(id)
{cal = getEl(id);
if (cal.dynamic)
{cal.style.visibility = 'hidden';
getEl(id+'Iframe').style.visibility='hidden';
doNext(cal);
}
};
};
function doNext(cal)
{if (cal.arrOnNext)
{if (cal.arrOnNext.length > 0)
{cal.onNext = cal.arrOnNext.shift();
cal.onNext();
// Explicit null set to prevent closure causing memory leak
cal.onNext = null;
}
}
};
function stopPropagation(evt)
{if (evt.stopPropagation)
{if (evt.target!=evt.currentTarget) {evt.stopPropagation(); evt.preventDefault();}}
else {evt.cancelBubble = true;}
};
// *********************************
// End of Private Function Library
// *********************************
// Start of Public Function Library
// *********************************
return {show: function(ele)
{// Check the type of any additional parameters.
// The optional string parameter is a calendar ID,
// Take any remaining parameters as day numbers to be handled
// (enabled/disabled) according to the setting of the
// calendar's valuesEnabled attribute.
// 0 = Sunday through to 6 = Saturday.
if (typeof arguments[1]=='object')
{var dynamic = true;
if (typeof arguments[2]=='string')
{var calId = arguments[2], min = 3;}
else {var calId = 'jacs', min = 2;}
// Stop the click event that opens the calendar
// from bubbling up to the document-level event
// handler that hides it!
var source = arguments[1];
if (!source) {source = window.event;}
if (source.tagName) // Second parameter isn't an event it's an element
{var sourceEle = source;
if (getEl('jacsIE')) {window.event.cancelBubble = true;}
else {sourceEle.parentNode.addEventListener('click',stopPropagation,false);}
}
else // Second parameter is an event
{var event = source;
// Stop the click event that opens the calendar from bubbling up to
// the document-level event handler that hides it!
var sourceEle = (event.target)?event.target:event.srcElement;
if (event.stopPropagation) {event.stopPropagation();}
else {event.cancelBubble = true;}
}
}
else
{var sourceEle = ele, dynamic = false;
if (typeof arguments[1]=='string')
{var calId = arguments[1], min = 2;}
else {var calId = 'jacs', min = 1;}
}
// Add event handlers to the return element and its parent.
// This helps the script to support tab sequences and focus events.
if (document.addEventListener)
{ele.addEventListener('keydown',hideOnTab,false);
ele.parentNode.addEventListener('click',stopPropagation,false);}
else {ele.attachEvent('onkeydown',hideOnTab);
if (ele.parentNode!=document.body)
{ele.parentNode.attachEvent('onclick',stopPropagation);}
}
function hideOnTab(evt)
{if (!evt) {var evt = window.event;}
if ((evt.keyCode||evt.which)==9) {hide(calId);}
};
// Create the calendar structure. One is enough unless you want more
// than one calendar visible on the page at one time. If you DO need
// more, you can create as many as you like but each must have a unique
// ID.
// The first parameter of JACS.make is the ID of the calendar. The
// second is a boolean that determines whether the calendar is to be
// static on the page (assigned to a single input field and always
// visible) or dynamic (shown and hidden on events and can be assigned
// to any number of input fields).
if (!getEl(calId)) {JACS.make(calId,dynamic);}
cal = getEl(calId);
// If the calendar has been triggered using an onfocus event,
// and the script actively returns the focus to the target
// element (i.e. when cal.onBlurMoveNext = false). We need
// to kill the event.
if (event)
{if (event.type == 'focus' && cal.dateReturned && !cal.onBlurMoveNext && cal.prevEventType == 'focus')
{stopPropagation(event); cal.prevEventType = ''; cal.dateReturned = false; return false;}
cal.prevEventType = event.type;
}
if (cal.style.visibility != 'hidden' &&
cal.style.visibility != 'inherit' &&
typeof doNext == 'function') {doNext(cal);}
cal.triggerEle = sourceEle;
cal.dateReturned = false;
cal.activeToday = true;
// Set enabled/disabled days
if (arguments.length==min) {cal.days.length=0;}
else {selectedDays = (typeof arguments[min]=='object')?arguments[min]:arguments;
for (var i=(min|0);i<selectedDays.length;i++)
{if (cal.days.join().indexOf(selectedDays[i])==-1) {cal.days.push(selectedDays[i]);}}
}
for (var i=0;i<cal.days.length;i++)
{if (dateNow.getDay()==cal.days[i]%7) {cal.activeToday = false; break;}}
// If no value is preset then the seed date is
// Today (when today is in range) OR
// The middle of the date range.
cal.seedDate = dateNow;
// Find the date and Strip space characters from start and
// end of date input.
var dateValue = '';
if (ele.value) {dateValue = ele.value.replace(/^\s+/,'').replace(/\s+$/,'');}
else {if (typeof ele.value == 'undefined')
{var childNodes = ele.childNodes;
for (var i=0;i<childNodes.length;i++)
{if (childNodes[i].nodeType == 3)
{dateValue = childNodes[i].nodeValue.replace(/^\s+/,'').replace(/\s+$/,'');
if (dateValue.length > 0)
{cal.triggerEle.textNode = childNodes[i];
cal.triggerEle.len = childNodes[i].nodeValue.length;
break;
}
}
}
}
}
// Set the year range
var yearOptions = getEl(calId+'Years').options;
if (yearOptions.length==0 || yearOptions[0].value!=cal.baseYear)
{yearOptions.length = 0;
for (var i=0;i<cal.dropDownYears;i++) {yearOptions[i] = new Option((cal.baseYear+i),(cal.baseYear+i));}
}
if (dateValue.length==0)
{// If no value is entered and today is within the range,
// use today's date, otherwise use the middle of the valid range.
cal.fullInputDate=false;
if ((new Date(cal.baseYear+cal.dropDownYears,0,0))<cal.seedDate ||
(new Date(cal.baseYear,0,1)) >cal.seedDate
)
{cal.seedDate = new Date(cal.baseYear+Math.floor(cal.dropDownYears / 2), 5, 1);}
}
else
{function inputFormat()
{var seed = new Array(),
input = dateValue.split(new RegExp('[\\'+cal.delimiters.join('\\')+']+','g'));
// "Escape" all the user defined date delimiters above -
// several delimiters will need it and it does no harm for
// the others.
// Strip any empty array elements (caused by delimiters)
// from the beginning or end of the array. They will
// still appear in the output string if in the output
// format.
if (input[0]!=null)
{if (input[0].length==0) {input.splice(0,1);}
if (input[input.length-1].length==0) {input.splice(input.length-1,1);}
}
cal.fullInputDate = false;
cal.dateFormat = cal.dateFormat.toUpperCase();
// List all the allowed letters in the date format
var template = ['D','M','Y'];
// Prepare the sequence of date input elements
var result = new Array();
for (var i=0;i<template.length;i++)
{if (cal.dateFormat.search(template[i])>-1)
{result[cal.dateFormat.search(template[i])] = template[i];}
}
cal.dateSequence = result.join('');
// Separate the elements of the date input
switch (input.length)
{case 1:
{// Year only entry or undelimited date format
if (cal.dateFormat.indexOf('Y')>-1 &&
input[0].length>cal.dateFormat.lastIndexOf('Y'))
{seed[0] = parseInt(input[0].substring(cal.dateFormat.indexOf('Y'),
cal.dateFormat.lastIndexOf('Y')+1),10);
}
else {seed[0] = parseInt(input[0],10);}
if (cal.dateFormat.indexOf('M')>-1 &&
input[0].length>cal.dateFormat.lastIndexOf('M'))
{seed[1] = input[0].substring(cal.dateFormat.indexOf('M'),
cal.dateFormat.lastIndexOf('M')+1);
}
else {seed[1] = cal.defaultToCurrentMonth?(dateNow.getMonth()+1).toString():'6';}
if (cal.dateFormat.indexOf('D')>-1 &&
input[0].length>cal.dateFormat.lastIndexOf('D'))
{seed[2] = parseInt(input[0].substring(cal.dateFormat.indexOf('D'),
cal.dateFormat.lastIndexOf('D')+1),10);
}
else {seed[2] = 1;}
if (input[0].length==cal.dateFormat.length) {cal.fullInputDate = true;}
break;
}
case 2:
{// Year and Month entry
seed[0] = parseInt(input[cal.dateSequence.replace(/D/i,'').search(/Y/i)],10); // Year
seed[1] = input[cal.dateSequence.replace(/D/i,'').search(/M/i)]; // Month
seed[2] = 1; // Day
break;
}
case 3:
{// Day Month and Year entry
seed[0] = parseInt(input[cal.dateSequence.search(/Y/i)],10); // Year
seed[1] = input[cal.dateSequence.search(/M/i)]; // Month
seed[2] = parseInt(input[cal.dateSequence.search(/D/i)],10); // Day
cal.fullInputDate = true;
break;
}
default:
{// A stuff-up has led to more than three elements in the date.
seed[0] = 0; // Year
seed[1] = 0; // Month
seed[2] = 0; // Day
}
}
// These regular expressions validate the input date format
// to the following rules;
// Day 1-31 (optional zero on single digits)
// Month 1-12 (optional zero on single digits)
// or case insensitive name
// Year One, Two or four digits
// Months names are as set in the language-dependent
// definitions and delimiters are set just below there
var expValDay = new RegExp('^(0?[1-9]|[1-2][0-9]|3[0-1])$'),
expValMonth = new RegExp('^(0?[1-9]|1[0-2]|'+cal.monthNames.join('|')+')$','i'),
expValYear = new RegExp('^([0-9]{1,2}|[0-9]{4})$');
// Apply validation and report failures
if (expValYear.exec(seed[0]) ==null ||
expValMonth.exec(seed[1])==null ||
expValDay.exec(seed[2]) ==null
)
{if (cal.showInvalidDateMsg)
{alert(cal.invalidDateMsg + cal.invalidAlert[0] + dateValue + cal.invalidAlert[1]);}
seed[0] = cal.baseYear + Math.floor(cal.dropDownYears/2); // Year
seed[1] = cal.defaultToCurrentMonth?(dateNow.getMonth()+1).toString():'6'; // Month
seed[2] = 1; // Day
cal.fullInputDate = false;
}
// Return the Year in seed[0]
// Month in seed[1]
// Day in seed[2]
return seed;
};
// Parse the string into an array using the allowed delimiters
seedDate = inputFormat();
// So now we have the Year, Month and Day in an array.
// If the year is one or two digits then the routine assumes a
// year belongs in the 21st Century unless it is less than 50
// in which case it assumes the 20th Century is intended.
if (seedDate[0]<100) {seedDate[0] += (seedDate[0]>50)?1900:2000;}
// Check whether the month is in digits or an abbreviation
if (seedDate[1].search(/\d+/)<0)
{for (i=0;i<cal.monthNames.length;i++)
{if (seedDate[1].toUpperCase()==cal.monthNames[i].toUpperCase())
{seedDate[1]=i+1;
break;
}
}
}
cal.seedDate = new Date(seedDate[0],seedDate[1]-1,seedDate[2]);
}
// Test that we have arrived at a valid date
if (isNaN(cal.seedDate))
{if (cal.showInvalidDateMsg)
{alert(cal.invalidDateMsg + cal.invalidAlert[0] + dateValue + cal.invalidAlert[1]);}
cal.seedDate = new Date(cal.baseYear + Math.floor(cal.dropDownYears/2),5,1);
cal.fullInputDate = false;
}
else
{// Test that the date is within range,
// if not then set date to a sensible date in range.
if ((new Date(cal.baseYear,0,1))>cal.seedDate)
{if (cal.strict && cal.showOutOfRangeMsg) {alert(cal.outOfRangeMsg);}
cal.seedDate = new Date(cal.baseYear,0,1);
cal.fullInputDate=false;
}
else
{if ((new Date(cal.baseYear+cal.dropDownYears,0,0))<cal.seedDate)
{if (cal.strict && cal.showOutOfRangeMsg) {alert(cal.outOfRangeMsg);}
cal.seedDate = new Date(cal.baseYear + Math.floor(cal.dropDownYears),-1,1);
cal.fullInputDate=false;
}
else
{if (cal.strict && cal.fullInputDate &&
(cal.seedDate.getDate() !=seedDate[2] ||
(cal.seedDate.getMonth()+1)!=seedDate[1] ||
cal.seedDate.getFullYear() !=seedDate[0]
)
)
{if (cal.showDoesNotExistMsg) {alert(cal.doesNotExistMsg);}
cal.seedDate = new Date(cal.seedDate.getFullYear(),cal.seedDate.getMonth()-1,1);
cal.fullInputDate=false;
}
}
}
}
// Test the chosen dates for validity
// Give error message if not valid
for (var i=0;i<cal.dates.length;i++)
{if (!((typeof cal.dates[i]=='object') && (cal.dates[i].constructor==Date)))
{if ((typeof cal.dates[i]=='object') && (cal.dates[i].constructor==Array))
{var pass = true;
if (cal.dates[i].length!=2)
{if (cal.showRangeSettingError)
{alert(cal.rangeSettingError[0] + cal.dates[i] + cal.rangeSettingError[1]);}
pass = false;
}
else
{for (var j=0;j<cal.dates[i].length;j++)
if (!((typeof cal.dates[i][j]=='object') && (cal.dates[i][j].constructor==Date)))
{if (cal.showRangeSettingError)
{alert(cal.dateSettingError[0] + cal.dates[i][j] + cal.dateSettingError[1]);}
pass = false;
}
}
if (pass && (cal.dates[i][0]>cal.dates[i][1])) {cal.dates[i].reverse();}
}
else
{if (cal.showRangeSettingError)
{alert(cal.dateSettingError[0] + cal.dates[i] + cal.dateSettingError[1]);}
}
}
}
// Set language-dependent values
getEl(calId+'DragText').innerHTML = cal.drag;
var monthOptions = getEl(calId+'Months').options, months = '';
if (monthOptions.length>0) {for (var i=0;i<monthOptions.length;i++) {months += monthOptions[i].value+',';}}
if (monthOptions.length==0 || (cal.monthNames.join()+',')!=months)
{monthOptions.length = 0;
if (cal.monthNames.length<monthOptions.length) {monthOptions.length = cal.monthNames.length;}
for (var i=0;i<cal.monthNames.length;i++)
{if (i>monthOptions.length-1)
{monthOptions[i] = new Option(cal.monthNames[i],cal.monthNames[i]);}
else {monthOptions[i].innerHTML = cal.monthNames[i];}
}
}
for (var i=0;i<cal.weekInits.length;i++)
{getEl(calId+'WeekInit'+i).innerHTML = cal.weekInits[(i+cal.weekStart)%cal.weekInits.length];}
if (((new Date(cal.baseYear + cal.dropDownYears, 0, 0)) > dateNow &&
(new Date(cal.baseYear, 0, 0)) < dateNow) ||
(cal.clearButton && (ele.readOnly || ele.disabled))
) {getEl(calId+'Now').innerHTML = cal.today+' '+dateNow.jacsFormat(cal.dateDisplayFormat,cal.monthNames);
getEl(calId+'ClearButton').value = cal.clear;
getEl(calId+'Foot').style.display = '';
if ((new Date(cal.baseYear + cal.dropDownYears, 0, 0)) > dateNow &&
(new Date(cal.baseYear, 0, 0)) < dateNow)
{getEl(calId+'Now').style.display = '';
if (cal.clearButton && (ele.readOnly || ele.disabled))
{getEl(calId+'Clear').style.display = '';
getEl(calId+'Clear').style.textAlign = 'left';
getEl(calId+'Now' ).style.textAlign = 'right';
}
else {getEl(calId+'Clear').style.display = 'none';
getEl(calId+'Now' ).style.textAlign = 'center';
}
}
else {getEl(calId+'Clear').style.textAlign = 'center';
getEl(calId+'Clear').style.display = '';
getEl(calId+'Now' ).style.display = 'none';
}
}
else {getEl(calId+'Foot').style.display = 'none';}
// Calculate the number of months that the entered (or
// defaulted) month is after the start of the allowed
// date range.
cal.monthSum = 12*(cal.seedDate.getFullYear() - cal.baseYear) + cal.seedDate.getMonth();
// Set the drop down boxes.
getEl(calId+'Years').options.selectedIndex = Math.floor(cal.monthSum/12);
getEl(calId+'Months').options.selectedIndex = (cal.monthSum%12);
getEl(calId).ele = ele;
// Display the month
showMonth(0,calId);
// Remember the Element
cal.targetEle = ele;
// Position the calendar box.
if (dynamic)
{// Check whether or not dragging is allowed and display drag handle if necessary
getEl(calId+'Drag').style.display = (cal.allowDrag)?'':'none';
var offsetTop = parseInt(ele.offsetTop ,10),
offsetLeft = parseInt(ele.offsetLeft,10);
// The object sniffing for Opera allows for the fact that Opera
// is the only major browser that correctly reports the position
// of an element in a scrollable DIV. This is because IE and
// Firefox omit the DIV from the offsetParent tree.
if (!window.opera)
{while (ele.tagName!='BODY' && ele.tagName!='HTML')
{offsetTop -= parseInt(ele.scrollTop, 10);
offsetLeft -= parseInt(ele.scrollLeft,10);
ele = ele.parentNode;
}
ele = cal.targetEle;
}
while (ele.tagName!='BODY' && ele.tagName!='HTML')
{ele = ele.offsetParent;
offsetTop += parseInt(ele.offsetTop, 10);
offsetLeft += parseInt(ele.offsetLeft,10);
}
ele = cal.targetEle;
var eleOffsetTop = offsetTop,
eleOffsetLeft = offsetLeft;
if (cal.xBase.length>0)
{if (isNaN(cal.xBase))
{cal.xBase = cal.xBase.toUpperCase();
offsetLeft += (cal.xBase=='R')
?parseInt(ele.offsetWidth,10)
:(cal.xBase=='M')?Math.round(parseInt(ele.offsetWidth,10)/2):0;
}
else {offsetLeft += parseInt(cal.xBase,10);}
}
if (cal.yBase.length>0)
{if (isNaN(cal.yBase))
{cal.yBase = cal.yBase.toUpperCase();
offsetTop += (cal.yBase=='B')
?parseInt(ele.offsetHeight,10)
:(cal.yBase=='M')?Math.round(parseInt(ele.offsetHeight,10)/2):0;
}
else {offsetTop += parseInt(cal.yBase,10);}
}
else {offsetTop += parseInt(ele.offsetHeight,10);}
if (cal.xPosition.length>0)
{if (isNaN(cal.xPosition))
{cal.xPosition = cal.xPosition.toUpperCase();
offsetLeft -= (cal.xPosition=='R')
?parseInt(cal.offsetWidth,10)
:(cal.xPosition=='M')?Math.round(parseInt(cal.offsetWidth,10)/2):0;
}
else {offsetLeft += parseInt(cal.xPosition,10);}
}
if (cal.yPosition.length>0)
{if (isNaN(cal.yPosition))
{cal.yPosition = cal.yPosition.toUpperCase();
offsetTop -= (cal.yPosition=='B')
?parseInt(cal.offsetHeight,10)
:(cal.yPosition=='M')?Math.round((parseInt(cal.offsetHeight,10))/2):0;
}
else {offsetTop += parseInt(cal.yPosition,10);}
}
if (cal.autoPosition)
{var width = parseInt(cal.offsetWidth, 10),
height = parseInt(cal.offsetHeight,10),
windowLeft =
(document.body && document.body.scrollLeft)
?document.body.scrollLeft //DOM compliant
:(document.documentElement && document.documentElement.scrollLeft)
?document.documentElement.scrollLeft //IE6+ standards compliant
:0, //Failed
windowWidth =
(typeof(innerWidth) == 'number')
?innerWidth //DOM compliant
:(document.documentElement && document.documentElement.clientWidth)
?document.documentElement.clientWidth //IE6+ standards compliant
:(document.body && document.body.clientWidth)
?document.body.clientWidth //IE non-compliant
:0, //Failed
windowTop =
(document.body && document.body.scrollTop)
?document.body.scrollTop //DOM compliant
:(document.documentElement && document.documentElement.scrollTop)
?document.documentElement.scrollTop //IE6+ standards compliant
:0, //Failed
windowHeight =
(typeof(innerHeight) == 'number')
?innerHeight //DOM compliant
:(document.documentElement && document.documentElement.clientHeight)
?document.documentElement.clientHeight //IE6+ standards compliant
:(document.body && document.body.clientHeight)
?document.body.clientHeight //IE non-compliant
:0; //Failed
if (eleOffsetLeft + parseInt(ele.offsetWidth,10) - width >= windowLeft &&
offsetLeft + width > windowLeft + windowWidth
) {offsetLeft = eleOffsetLeft + parseInt(ele.offsetWidth,10) - width;}
else if (eleOffsetLeft >= windowLeft && offsetLeft < windowLeft
) {offsetLeft = eleOffsetLeft;}
if (eleOffsetTop - height >= windowTop &&
offsetTop + height > windowTop + windowHeight
) {offsetTop = eleOffsetTop - height;}
else if (offsetTop + height <= windowTop + windowHeight && offsetTop < windowTop)
{offsetTop = eleOffsetTop + parseInt(ele.offsetHeight,10);}
}
cal.style.top = offsetTop+'px';
cal.style.left = offsetLeft+'px';
getEl(calId+'Iframe').style.top = offsetTop + 'px';
getEl(calId+'Iframe').style.left = offsetLeft+ 'px';
getEl(calId+'Iframe').style.width = (cal.offsetWidth -(getEl('jacsIE')?2:4))+'px';
getEl(calId+'Iframe').style.height = (cal.offsetHeight-(getEl('jacsIE')?2:4))+'px';
getEl(calId+'Iframe').style.visibility = 'inherit';
}
// Show it on the page
cal.style.visibility = 'inherit';
},
make: function (calId)
{cals.push(calId);
var dynamic = (typeof arguments[1]=='boolean')?arguments[1]:true;
TABLEjacs = document.createElement('table');
TABLEjacs.id = calId;
TABLEjacs.dynamic = dynamic;
TABLEjacs.className = (dynamic)?'jacs':'jacsStatic';
calAttributes(TABLEjacs);
if (dynamic) {TABLEjacs.style.zIndex = TABLEjacs.zIndex+1;}
function cancel(evt)
{if (TABLEjacs.clickToHide) {hide(calId);}
stopPropagation(evt);
};
TBODYjacs = document.createElement('tbody');
TRjacs1 = document.createElement('tr');
TRjacs1.className = 'jacs';
TDjacs1 = document.createElement('td');
TDjacs1.className = 'jacs';
TABLEjacsHead = document.createElement('table');
TABLEjacsHead.id = calId+'Head';
TABLEjacsHead.cellSpacing = '0';
TABLEjacsHead.cellPadding = '0';
TABLEjacsHead.className = 'jacsHead';
TABLEjacsHead.width = '100%';
TBODYjacsHead = document.createElement('tbody');
TRjacsDrag = document.createElement('tr');
TRjacsDrag.id = calId+'Drag';
TRjacsDrag.style.display = 'none';
TDjacsDrag = document.createElement('td');
TDjacsDrag.className = 'jacsDrag';
TDjacsDrag.colSpan = '4';
function beginDrag(evt)
{var elToDrag = getEl(calId);
var deltaX = evt.clientX,
deltaY = evt.clientY,
offsetEle = elToDrag;
while (offsetEle.tagName!='BODY' && offsetEle.tagName!='HTML')
{deltaX -= parseInt(offsetEle.offsetLeft,10);
deltaY -= parseInt(offsetEle.offsetTop ,10);
offsetEle = offsetEle.offsetParent;
}
if (document.addEventListener)
{elToDrag.addEventListener('mousemove',moveHandler,true);
elToDrag.addEventListener('mouseup', upHandler,true);
}
else {elToDrag.attachEvent('onmousemove', moveHandler);
elToDrag.attachEvent('onmouseup', upHandler);
elToDrag.setCapture();
}
stopPropagation(evt);
function moveHandler(evt)
{if (!evt) {evt = window.event;}
elToDrag.style.left = (evt.clientX-deltaX)+'px';
elToDrag.style.top = (evt.clientY-deltaY)+'px';
getEl(calId+'Iframe').style.left = (evt.clientX-deltaX)+'px';
getEl(calId+'Iframe').style.top = (evt.clientY-deltaY)+'px';
stopPropagation(evt);
};
function upHandler(evt)
{if (!evt) {evt = window.event;}
if (document.removeEventListener)
{elToDrag.removeEventListener('mousemove',moveHandler,true);
elToDrag.removeEventListener( 'mouseup', upHandler,true);
}
else {elToDrag.detachEvent('onmouseup', upHandler);
elToDrag.detachEvent('onmousemove',moveHandler);
elToDrag.releaseCapture();
}
stopPropagation(evt);
};
};
DIVjacsDragText = document.createElement('span');
DIVjacsDragText.id = calId+'DragText';
TRjacsHead = document.createElement('tr');
TRjacsHead.className = 'jacsHead';
TDjacsHead1 = document.createElement('td');
TDjacsHead1.className = 'jacsHead';
INPUTjacsHead1 = document.createElement('input');
INPUTjacsHead1.className = 'jacsHead';
INPUTjacsHead1.id = calId+'HeadLeft';
INPUTjacsHead1.type = 'button';
INPUTjacsHead1.tabIndex = '-1';
INPUTjacsHead1.value = '<';
INPUTjacsHead1.onclick = function() {showMonth(-1,calId);}
TDjacsHead2 = document.createElement('td');
TDjacsHead2.className = 'jacsHead';
SELECTjacsHead2 = document.createElement('select');
SELECTjacsHead2.className = 'jacsHead';
SELECTjacsHead2.id = calId+'Months';
SELECTjacsHead2.tabIndex = '-1';
SELECTjacsHead2.onchange = function() {showMonth(0,calId);}
TDjacsHead3 = document.createElement('td');
TDjacsHead3.className = 'jacsHead';
SELECTjacsHead3 = document.createElement('select');
SELECTjacsHead3.className = 'jacsHead';
SELECTjacsHead3.id = calId+'Years';
SELECTjacsHead3.tabIndex = '-1';
SELECTjacsHead3.onchange = function() {showMonth(0,calId);}
TDjacsHead4 = document.createElement('td');
TDjacsHead4.className = 'jacsHead';
INPUTjacsHead4 = document.createElement('input');
INPUTjacsHead4.className = 'jacsHead';
INPUTjacsHead4.id = calId+'HeadRight';
INPUTjacsHead4.type = 'button';
INPUTjacsHead4.tabIndex = '-1';
INPUTjacsHead4.value = '>';
INPUTjacsHead4.onclick = function() {showMonth(1,calId);}
TRjacs2 = document.createElement('tr');
TRjacs2.className = 'jacs';
TDjacs2 = document.createElement('td');
TDjacs2.className = 'jacs';
TABLEjacsCells = document.createElement('table');
TABLEjacsCells.className = 'jacsCells';
TABLEjacsCells.align = 'center';
TABLEjacsCells.width = '100%';
THEADjacsCells = document.createElement('thead');
TRjacsCells = document.createElement('tr');
TDjacsCells = document.createElement('td');
TDjacsCells.className = 'jacsWeekNumberHead';
TDjacsCells.id = calId+'Week_';
TABLEjacs.appendChild(TBODYjacs);
TBODYjacs.appendChild(TRjacs1);
TRjacs1.appendChild(TDjacs1);
TDjacs1.appendChild(TABLEjacsHead);
TABLEjacsHead.appendChild(TBODYjacsHead);
TBODYjacsHead.appendChild(TRjacsDrag);
TRjacsDrag.appendChild(TDjacsDrag);
TDjacsDrag.appendChild(DIVjacsDragText);
TBODYjacsHead.appendChild(TRjacsHead);
TRjacsHead.appendChild(TDjacsHead1);
TDjacsHead1.appendChild(INPUTjacsHead1);
TRjacsHead.appendChild(TDjacsHead2);
TDjacsHead2.appendChild(SELECTjacsHead2);
TRjacsHead.appendChild(TDjacsHead3);
TDjacsHead3.appendChild(SELECTjacsHead3);
TRjacsHead.appendChild(TDjacsHead4);
TDjacsHead4.appendChild(INPUTjacsHead4);
TBODYjacs.appendChild(TRjacs2);
TRjacs2.appendChild(TDjacs2);
TDjacs2.appendChild(TABLEjacsCells);
TABLEjacsCells.appendChild(THEADjacsCells);
THEADjacsCells.appendChild(TRjacsCells);
TRjacsCells.appendChild(TDjacsCells);
for (var i=0;i<7;i++)
{TDjacsCells = document.createElement('td');
TDjacsCells.className = 'jacsWeek';
TDjacsCells.id = calId+'WeekInit'+i;
TRjacsCells.appendChild(TDjacsCells);
}
TBODYjacsCells = document.createElement('tbody');
TBODYjacsCells.id = calId+'Cells';
TABLEjacsCells.appendChild(TBODYjacsCells);
for (var i=0;i<6;i++)
{TRjacsCells = document.createElement('tr');
TBODYjacsCells.appendChild(TRjacsCells);
TDjacsCells = document.createElement('td');
TDjacsCells.className = 'jacsWeekNo';
TDjacsCells.id = calId+'Week_'+i;
TRjacsCells.appendChild(TDjacsCells);
for (var j=0;j<7;j++)
{TDjacsCells = document.createElement('td');
TDjacsCells.className = 'jacsCells';
TDjacsCells.id = calId+'Cell_'+(j+(i*7));
TRjacsCells.appendChild(TDjacsCells);
}
}
TFOOTjacsFoot = document.createElement('tfoot');
TABLEjacsCells.appendChild(TFOOTjacsFoot);
TRjacsFoot = document.createElement('tr');
TRjacsFoot.id = calId+'Foot';
TFOOTjacsFoot.appendChild(TRjacsFoot);
TDjacsFoot = document.createElement('td');
TDjacsFoot.colSpan = '8';
TDjacsFoot.style.padding = '0px';
TRjacsFoot.appendChild(TDjacsFoot);
TABLEjacsFootDetail = document.createElement('table');
TABLEjacsFootDetail.style.width = '100%';
TABLEjacsFootDetail.cellSpacing = '0';
TABLEjacsFootDetail.cellPadding = '0';
TDjacsFoot.appendChild(TABLEjacsFootDetail);
TBODYjacsFootDetail = document.createElement('tbody');
TABLEjacsFootDetail.appendChild(TBODYjacsFootDetail);
TRjacsFootDetail = document.createElement('tr');
TBODYjacsFootDetail.appendChild(TRjacsFootDetail);
TDjacsFootDetail = document.createElement('td');
TDjacsFootDetail.className = 'jacsClear';
TDjacsFootDetail.id = calId+'Clear';
TDjacsFootDetail.style.padding = '0px';
TRjacsFootDetail.appendChild(TDjacsFootDetail);
INPUTjacsClearButton = document.createElement('input');
INPUTjacsClearButton.type = 'button';
INPUTjacsClearButton.id = calId+'ClearButton';
INPUTjacsClearButton.className = 'Clear';
INPUTjacsClearButton.style.textAlign = 'center';
INPUTjacsClearButton.onclick = function() {cal.targetEle.value='';hide(calId);};
TDjacsFootDetail.appendChild(INPUTjacsClearButton);
TDjacsNow = document.createElement('td');
TDjacsNow.className = 'jacsNow';
TDjacsNow.id = calId+'Now';
TDjacsNow.style.padding = '0px';
TRjacsFootDetail.appendChild(TDjacsNow);
if (TABLEjacs.clickToHide)
{if (document.addEventListener)
{ TABLEjacs.addEventListener('click', cancel, false);
TABLEjacs.addEventListener('change', cancel, false);
TDjacsDrag.addEventListener('mousedown',beginDrag, false);
INPUTjacsHead1.addEventListener('click', stopPropagation,false);
SELECTjacsHead2.addEventListener('click', stopPropagation,false);
SELECTjacsHead2.addEventListener('change', stopPropagation,false);
SELECTjacsHead3.addEventListener('click', stopPropagation,false);
SELECTjacsHead3.addEventListener('change', stopPropagation,false);
INPUTjacsHead4.addEventListener('click', stopPropagation,false);
TBODYjacsCells.addEventListener('click', stopPropagation,false);
}
else { TABLEjacs.attachEvent('onclick', cancel);
TABLEjacs.attachEvent('onchange', cancel);
TDjacsDrag.attachEvent('onmousedown',beginDrag);
INPUTjacsHead1.attachEvent('onclick', stopPropagation);
SELECTjacsHead2.attachEvent('onclick', stopPropagation);
SELECTjacsHead2.attachEvent('onchange', stopPropagation);
SELECTjacsHead3.attachEvent('onclick', stopPropagation);
SELECTjacsHead3.attachEvent('onchange', stopPropagation);
INPUTjacsHead4.attachEvent('onclick', stopPropagation);
TBODYjacsCells.attachEvent('onclick', stopPropagation);
}
}
else
{if (document.addEventListener)
{ TABLEjacs.addEventListener('click', stopPropagation,false);
TABLEjacs.addEventListener('change', stopPropagation,false);
TDjacsDrag.addEventListener('mousedown',beginDrag, false);
}
else
{ TABLEjacs.attachEvent('onclick', stopPropagation);
TABLEjacs.attachEvent('onchange', stopPropagation);
TDjacsDrag.attachEvent('onmousedown',beginDrag);
}
}
if (dynamic)
{iFrame = document.createElement('iframe');
iFrame.className = 'jacs';
iFrame.id = calId+'Iframe';
if (getEl('jacsIElt7')) {iFrame.src = '/jacsblank.html';}
iFrame.name = 'jacsIframe';
iFrame.frameborder = '0';
iFrame.style.zIndex = TABLEjacs.zIndex;
document.body.insertBefore(iFrame, document.body.firstChild);
document.body.insertBefore(TABLEjacs, iFrame);
}
else {if (!getEl('jacsSpan'+calId)) {document.writeln("<span id='jacsSpan"+calId+"'></span>");}
getEl('jacsSpan'+calId).appendChild(TABLEjacs);
}
},
cals: function () {return cals;},
next: function ()
{if (typeof arguments[0]=='string')
{calID = arguments[0];
inFunc = arguments[1];
argPosition = 2;
}
else {calID = 'jacs';
inFunc = arguments[0];
argPosition = 1;
}
if (getEl(calID))
{// Take the arguments to be passed through to the defined function.
var args = new Array();
for (var i=argPosition;i<arguments.length;i++) {args.push(arguments[i]);}
// Pass them through to jacsRunNext
newFunc = inFunc.jacsRunNext(args,calID);
// If the function has already been set, clear the old
// function and set the new one (mostly relevant for dynamic
// calendars but refreshing the function for static calendars
// caters for dynamic parameters).
var cal = getEl(calID);
if (cal.dynamic) {cal.arrOnNext.push(newFunc);}
else {cal.onNext = newFunc;}
}
else
{alert('ERROR: Calendar object <<' + calID + '>> does not exist.\n' +
'Please check that the calendar object id is correct\n' +
'and that JACS.show is called before JACS.next.');
}
}
};
};
// ******************************
// End of Public Function Library
// ******************************************************
// End of Javascript Advanced Calendar Script (JACS) Code
// ******************************************************