My Calendar - Version 1.8.9

Version Description

  • Fixed bug with database upgrade in multi-user additional calendars
  • Fixed bug where calendar picked up current month labeling using current day of the month
  • Added French translation
Download this release

Release Info

Developer joedolson
Plugin Icon 128x128 My Calendar
Version 1.8.9
Comparing to
See all releases

Code changes from version 1.7.8 to 1.8.9

Files changed (72) hide show
  1. button/generator.css +37 -0
  2. button/generator.php +105 -0
  3. button/mcb.js +125 -0
  4. button/tinymce3/calendarButton.gif +0 -0
  5. button/tinymce3/editor_plugin.js +61 -0
  6. button/tinymce3/langs/en.js +4 -0
  7. button/tinymce3/langs/es.js +4 -0
  8. button/tinymce3/langs/fr.js +4 -0
  9. button/tinymce3/langs/ru.js +4 -0
  10. button/tinymce3/mcb.png +0 -0
  11. date-utilities.php +24 -11
  12. images/icon.png +0 -0
  13. js/calendrical.css +91 -0
  14. js/jquery.calendrical.js +504 -0
  15. js/ui.datepicker.css +0 -212
  16. js/ui.datepicker.js +0 -1718
  17. my-calendar-cs_CZ.mo → lang/my-calendar-cs_CZ.mo +0 -0
  18. my-calendar-cs_CZ.po → lang/my-calendar-cs_CZ.po +0 -0
  19. my-calendar-da_DK.mo → lang/my-calendar-da_DK.mo +0 -0
  20. my-calendar-da_DK.po → lang/my-calendar-da_DK.po +0 -0
  21. lang/my-calendar-de_DE.mo +0 -0
  22. lang/my-calendar-de_DE.po +2258 -0
  23. my-calendar-es_ES.mo → lang/my-calendar-es_ES.mo +0 -0
  24. my-calendar-es_ES.po → lang/my-calendar-es_ES.po +0 -0
  25. my-calendar-fi.mo → lang/my-calendar-fi.mo +0 -0
  26. my-calendar-fi.po → lang/my-calendar-fi.po +0 -0
  27. lang/my-calendar-fr_FR.mo +0 -0
  28. lang/my-calendar-fr_FR.po +2071 -0
  29. my-calendar-it_IT.mo → lang/my-calendar-it_IT.mo +0 -0
  30. my-calendar-it_IT.po → lang/my-calendar-it_IT.po +0 -0
  31. lang/my-calendar-ja.mo +0 -0
  32. my-calendar-ja.po → lang/my-calendar-ja.po +1415 -1258
  33. my-calendar-nl.mo → lang/my-calendar-nl.mo +0 -0
  34. my-calendar-nl.po → lang/my-calendar-nl.po +0 -0
  35. my-calendar-nl_NL.mo → lang/my-calendar-nl_NL.mo +0 -0
  36. my-calendar-nl_NL.po → lang/my-calendar-nl_NL.po +0 -0
  37. my-calendar-pt_BR.mo → lang/my-calendar-pt_BR.mo +0 -0
  38. my-calendar-pt_BR.po → lang/my-calendar-pt_BR.po +0 -0
  39. lang/my-calendar-ru_RU.mo +0 -0
  40. lang/my-calendar-ru_RU.po +2052 -0
  41. lang/my-calendar-sv_SE.mo +0 -0
  42. lang/my-calendar-sv_SE.po +1974 -0
  43. lang/my-calendar-tr_TR.mo +0 -0
  44. lang/my-calendar-tr_TR.po +1974 -0
  45. my-calendar.pot → lang/my-calendar.pot +1159 -917
  46. mc-styles.css +45 -0
  47. my-calendar-behaviors.php +4 -4
  48. my-calendar-categories.php +96 -62
  49. my-calendar-core.php +871 -0
  50. my-calendar-de_DE.mo +0 -0
  51. my-calendar-de_DE.po +0 -1372
  52. my-calendar-detect-mobile.php +918 -0
  53. my-calendar-event-manager.php +143 -149
  54. my-calendar-events.php +733 -0
  55. my-calendar-help.php +43 -14
  56. my-calendar-ical.php +3 -2
  57. my-calendar-install.php +39 -38
  58. my-calendar-ja.mo +0 -0
  59. my-calendar-limits.php +106 -0
  60. my-calendar-locations.php +92 -50
  61. my-calendar-output.php +313 -175
  62. my-calendar-rss.php +10 -7
  63. my-calendar-settings.php +305 -309
  64. my-calendar-shortcodes.php +59 -0
  65. my-calendar-styles.php +4 -5
  66. my-calendar-templates.php +37 -91
  67. my-calendar-upgrade-db.php +9 -19
  68. my-calendar-user.php +2 -2
  69. my-calendar-widgets.php +143 -33
  70. my-calendar.php +63 -1502
  71. readme.txt +106 -7
  72. uninstall.php +4 -2
button/generator.css ADDED
@@ -0,0 +1,37 @@
1
+ .wrap {
2
+ margin: 0 5px;
3
+ }
4
+ fieldset {
5
+ border: 1px solid #ccc;
6
+ margin: 10px 0;
7
+ padding: 10px;
8
+ }
9
+ label {
10
+ display: block;
11
+ float: left;
12
+ width: 30%;
13
+ margin-right: 10px;
14
+ }
15
+ .help, .clear {
16
+ clear: left;
17
+ }
18
+ fieldset {
19
+ margin: 6px 0;
20
+ }
21
+ input {
22
+ line-height: normal;
23
+ }
24
+
25
+ input[type=text],
26
+ select {
27
+ width: 60%;
28
+ }
29
+ .req {
30
+ color: red;
31
+ }
32
+ .resources {
33
+ margin: 5px;
34
+ padding: 10px;
35
+ background: #fff;
36
+ border: 1px solid #ccc;
37
+ }
button/generator.php ADDED
@@ -0,0 +1,105 @@
1
+ <?php
2
+ // Load WordPress core files
3
+ $iswin = preg_match('/:\\\/', dirname(__file__));
4
+ $slash = ($iswin) ? "\\" : "/";
5
+ $wp_path = preg_split('/(?=((\\\|\/)wp-content)).*/', dirname(__file__));
6
+ $wp_path = (isset($wp_path[0]) && $wp_path[0] != "") ? $wp_path[0] : $_SERVER["DOCUMENT_ROOT"];
7
+ require_once($wp_path . $slash . 'wp-load.php');
8
+ require_once($wp_path . $slash . 'wp-admin' . $slash . 'admin.php');
9
+
10
+ // check for rights
11
+ if ( !is_user_logged_in() || !current_user_can('edit_posts') )
12
+ wp_die(__( "You don't have access to this function.", 'my-calendar' ));
13
+ ?>
14
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
15
+ <html xmlns="http://www.w3.org/1999/xhtml" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
16
+ <head>
17
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
18
+ <title><?php bloginfo('name') ?> &rsaquo; <?php _e("My Calendar Shortcode Generator",'my-calendar'); ?> &#8212; WordPress</title>
19
+ <?php
20
+ // WordPress styles
21
+ wp_admin_css( 'css/global' );
22
+ wp_admin_css();
23
+ wp_admin_css( 'css/colors' );
24
+ wp_admin_css( 'css/ie' );
25
+ $hook_suffix = '';
26
+ if ( isset($page_hook) )
27
+ $hook_suffix = "$page_hook";
28
+ else if ( isset($plugin_page) )
29
+ $hook_suffix = "$plugin_page";
30
+ else if ( isset($pagenow) )
31
+ $hook_suffix = "$pagenow";
32
+ do_action("admin_print_styles-$hook_suffix");
33
+ do_action('admin_print_styles');
34
+ do_action("admin_print_scripts-$hook_suffix");
35
+ do_action('admin_print_scripts');
36
+ do_action("admin_head-$hook_suffix");
37
+ do_action('admin_head');
38
+ ?>
39
+ <link rel="stylesheet" href="<?php echo plugins_url('/my-calendar/button/generator.css'); ?>?ver=<?php echo mc_tiny_mce_version(); ?>" type="text/css" media="screen" charset="utf-8" />
40
+ <script src="<?php echo plugins_url('/my-calendar/button/mcb.js'); ?>" type="text/javascript" charset="utf-8"></script>
41
+ </head>
42
+ <body class="<?php echo apply_filters( 'admin_body_class', '' ); ?>">
43
+ <div class="wrap">
44
+ <h2><?php _e("My Calendar Shortcode Generator",'my-calendar'); ?></h2>
45
+ <form action="#" mode="POST">
46
+ <fieldset>
47
+ <legend><?php _e('Shortcode Atributes', 'my-calendar'); ?></legend>
48
+ <p>
49
+ <?php my_calendar_categories_list('select','admin'); ?>
50
+ </p>
51
+ <p>
52
+ <label for="format"><?php _e('Format', 'my-calendar'); ?></label>
53
+ <select name="format" id="format">
54
+ <option value="calendar" selected="selected">Grid</option>
55
+ <option value="list">List</option>
56
+ </select>
57
+ </p>
58
+ <p>
59
+ <label for="showkey"><?php _e('Show Category Key', 'my-calendar'); ?></label>
60
+ <select name="showkey" id="showkey">
61
+ <option value="yes">Yes</option>
62
+ <option value="no" selected="selected">No</option>
63
+ </select>
64
+ </p>
65
+ <p>
66
+ <label for="shownav"><?php _e('Show Previous/Next Links', 'my-calendar'); ?></label>
67
+ <select name="shownav" id="shownav">
68
+ <option value="yes">Yes</option>
69
+ <option value="no" selected="selected">No</option>
70
+ </select>
71
+ </p>
72
+ <p>
73
+ <label for="toggle"><?php _e('Show Format Toggle', 'my-calendar'); ?></label>
74
+ <select name="toggle" id="toggle">
75
+ <option value="yes">Yes</option>
76
+ <option value="no" selected="selected">No</option>
77
+ </select>
78
+ </p>
79
+ <p>
80
+ <label for="time"><?php _e('Time Segment', 'my-calendar'); ?></label>
81
+ <select name="time" id="time">
82
+ <option value="month" selected="selected">Month</option>
83
+ <option value="week">Week</option>
84
+ </select>
85
+ </p>
86
+ </fieldset>
87
+ <p>
88
+ <input type="button" class="button" id="mycalendar" name="generate" value="<?php _e('Generate Shortcode', 'my-calendar'); ?>" />
89
+ </p>
90
+ </form>
91
+ </div>
92
+ <?php jd_show_support_box(); ?>
93
+ <script type="text/javascript" charset="utf-8">
94
+ // <![CDATA[
95
+ jQuery(document).ready(function(){
96
+ try {
97
+ myCalQT.Tag.Generator.initialize();
98
+ } catch (e) {
99
+ throw "<?php _e("My Calendar: this generator isn't going to put the shortcode in your page. Sorry!", 'my-calendar'); ?>";
100
+ }
101
+ });
102
+ // ]]>
103
+ </script>
104
+ </body>
105
+ </html>
button/mcb.js ADDED
@@ -0,0 +1,125 @@
1
+ // pass the window to the object
2
+ var myCalQT = window.myCalQT || {};
3
+ // set the function
4
+ (myCalQT.Tag = function() {
5
+ return {
6
+ // set the function
7
+ embed : function() {
8
+ // check if the URL is a string and if the function tb_show works, if not, return
9
+ if (typeof this.configUrl !== 'string' || typeof tb_show !== 'function') {
10
+ return;
11
+ }
12
+ // pepare the url
13
+ var url = this.configUrl + ((this.configUrl.match(/\?/)) ? "&" : "?") + "TB_iframe=true";
14
+ // call lightbox to show the embed
15
+ tb_show('My Calendar Shortcode Generator', url , false);
16
+ }
17
+ };
18
+ }());
19
+ /* Generator specific script */
20
+ (myCalQT.Tag.Generator = function(){
21
+ // tags to find
22
+ var tags = 'category,format,showkey,shownav,toggle,time'.split(',');
23
+ // to validate and generate the tag
24
+ var vt = function(id){
25
+ var form = jQuery('#'+id).val();
26
+ if(form==''){
27
+ return '';
28
+ }else{
29
+ return ' '+id+'="'+form+'"';
30
+ }
31
+ };
32
+ // to build tag
33
+ var buildTag = function() {
34
+ var r = '[my_calendar';
35
+ for (i=0;i<tags.length;i++){
36
+ r += vt(tags[i]);
37
+ }
38
+ return r + ']';
39
+ };
40
+
41
+ // get the selected text in the box
42
+ var getSel = function(){
43
+ var win = window.parent || window;
44
+ var ret = '';
45
+ if ( typeof win.tinyMCE !== 'undefined' && ( win.ed = win.tinyMCE.activeEditor ) && !win.ed.isHidden() ) {
46
+ win.ed.focus();
47
+ if (win.tinymce.isIE){
48
+ win.ed.selection.moveToBookmark(win.tinymce.EditorManager.activeEditor.windowManager.bookmark);
49
+ }
50
+ ret = win.tinymce.EditorManager.activeEditor.selection.getContent({format : 'text'});
51
+ } else {
52
+ var myField = win.edCanvas;
53
+ // IE
54
+ if (document.selection) {
55
+ myField.focus();
56
+ ret = (win.document.all) ? win.document.selection.createRange().text : win.document.getSelection();
57
+ }
58
+ // Mozilla, Netscape
59
+ else if (myField.selectionStart || myField.selectionStart == '0') {
60
+ ret = myField.value.substring(myField.selectionStart, myField.selectionEnd);
61
+ }
62
+ }
63
+ return (ret=='')?false:ret;
64
+ };
65
+
66
+ // Tag parser
67
+ var parseTagEdit = function(){
68
+ // get selection
69
+ var selec = getSel();
70
+ if(selec != false){
71
+ // trim
72
+ selec = selec.replace(/^\s+|\s+#x2F;g,'');
73
+ // look for the endpoint
74
+ var endp = selec.lastIndexOf(']');
75
+ // if no endpoint is found
76
+ if(endp == -1){
77
+ return;
78
+ }
79
+ // look for the starting point
80
+ if(selec.substring(0,13) != '[my_calendar '){
81
+ return;
82
+ }
83
+ // only params
84
+ selec = selec.substring(13, endp);
85
+ // remove more than two white spaces
86
+ selec = selec.replace(/\s+/g, ' ')
87
+ // get params separated by space
88
+ var params = selec.split(' ');
89
+ // modify values
90
+ for (i=0;i<params.length;i++){
91
+ var parval = params[i].split('=');
92
+ jQuery('#'+parval[0]).val(parval[1]);
93
+ }
94
+ }
95
+ };
96
+ // to insert tag
97
+ var insertTag = function() {
98
+ var tag = buildTag() || "";
99
+ var win = window.parent || window;
100
+
101
+ if ( typeof win.tinyMCE !== 'undefined' && ( win.ed = win.tinyMCE.activeEditor ) && !win.ed.isHidden() ) {
102
+ win.ed.focus();
103
+ if (win.tinymce.isIE){
104
+ win.ed.selection.moveToBookmark(win.tinymce.EditorManager.activeEditor.windowManager.bookmark);
105
+ }
106
+ win.ed.execCommand('mceInsertContent', false, tag);
107
+ } else {
108
+ win.edInsertContent(win.edCanvas, tag);
109
+ }
110
+ // Close Lightbox
111
+ win.tb_remove();
112
+ };
113
+ return {
114
+ initialize : function() {
115
+ if (typeof jQuery === 'undefined') {
116
+ return;
117
+ }
118
+ jQuery("#mycalendar").click(function(e) {
119
+ e.preventDefault();
120
+ insertTag();
121
+ });
122
+ parseTagEdit();
123
+ }
124
+ };
125
+ }());
button/tinymce3/calendarButton.gif ADDED
Binary file
button/tinymce3/editor_plugin.js ADDED
@@ -0,0 +1,61 @@
1
+ (function() {
2
+ // Load plugin specific language pack
3
+ tinymce.PluginManager.requireLangPack('mcqt');
4
+ tinymce.create('tinymce.plugins.myCalendar', {
5
+ /**
6
+ * Initializes the plugin, this will be executed after the plugin has been created.
7
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
8
+ * of the editor instance to intercept that event.
9
+ *
10
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
11
+ * @param {string} url Absolute URL to where the plugin is located.
12
+ */
13
+ init : function(ed, url) {
14
+
15
+ if (typeof myCalQT === 'undefined' ||
16
+ typeof myCalQT.Tag === 'undefined' ||
17
+ typeof myCalQT.Tag.embed !== 'function'
18
+ ) {
19
+ return;
20
+ }
21
+ ed.addCommand('createMCTag', function() {
22
+ myCalQT.Tag.embed.apply(myCalQT.Tag);
23
+ });
24
+ ed.addButton('myCalendar', {
25
+ title : 'mcqt.description',
26
+ image : url + '/mcb.png',
27
+ cmd : 'createMCTag'
28
+ });
29
+ },
30
+ /**
31
+ * Creates control instances based in the incomming name. This method is normally not
32
+ * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
33
+ * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
34
+ * method can be used to create those.
35
+ *
36
+ * @param {String} n Name of the control to create.
37
+ * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
38
+ * @return {tinymce.ui.Control} New control instance or null if no control was created.
39
+ */
40
+ createControl : function(n, cm) {
41
+ return null;
42
+ },
43
+ /**
44
+ * Returns information about the plugin as a name/value array.
45
+ * The current keys are longname, author, authorurl, infourl and version.
46
+ *
47
+ * @return {Object} Name/value array containing information about the plugin.
48
+ */
49
+ getInfo : function() {
50
+ return {
51
+ longname : 'My Calendar TinyMCE Plugin',
52
+ author : 'Joseph C Dolson',
53
+ authorurl : 'http://www.joedolson.com',
54
+ infourl : 'http://http://www.joedolson.com/articles/my-calendar/',
55
+ version : "1.7.9"
56
+ };
57
+ }
58
+ });
59
+ // Register plugin
60
+ tinymce.PluginManager.add('mcqt', tinymce.plugins.myCalendar);
61
+ })();
button/tinymce3/langs/en.js ADDED
@@ -0,0 +1,4 @@
1
+ // English lang variables
2
+ tinyMCE.addI18n("en.mcqt", {
3
+ description : "Insert My Calendar"
4
+ });
button/tinymce3/langs/es.js ADDED
@@ -0,0 +1,4 @@
1
+ // Spanish lang variables
2
+ tinyMCE.addI18n("es.mcqt", {
3
+ description : "Insertar etiqueta My Calendar"
4
+ });
button/tinymce3/langs/fr.js ADDED
@@ -0,0 +1,4 @@
1
+ // Spanish lang variables
2
+ tinyMCE.addI18n("es.mcqt", {
3
+ description : "Insertar etiqueta My Calendar"
4
+ });
button/tinymce3/langs/ru.js ADDED
@@ -0,0 +1,4 @@
1
+ // Russian lang variables
2
+ tinyMCE.addI18n("ru.mcqt", {
3
+ description : "вставка тегов My Calendar"
4
+ });
button/tinymce3/mcb.png ADDED
Binary file
date-utilities.php CHANGED
@@ -14,6 +14,16 @@ function my_calendar_date_comp($early,$late) {
14
return false;
15
}
16
}
17
18
function my_calendar_date_equal($early,$late) {
19
$firstdate = strtotime($early);
@@ -120,17 +130,20 @@ function week_of_month($date_of_event) {
120
* @param string $start_of_week The start day of the week you want returned
121
* @return integer The unix timestamp of the date is returned
122
*/
123
- function get_week_date( $week, $year, $start_of_week=0 ) {
124
- // Get the target week of the year with reference to the starting day of
125
- // the year
126
- $target_week = strtotime("$week week", strtotime("1 January $year"));
127
- $date_info = getdate($target_week);
128
- $day_of_week = $date_info['wday'];
129
- // normal start day of the week is Monday
130
- $adjusted_date = $day_of_week - $start_of_week;
131
- // Get the timestamp of that day
132
- $first_day = strtotime("-$adjusted_date day",$target_week);
133
- return $first_day;
134
}
135
136
function add_days_to_date( $givendate,$day=0 ) {
14
return false;
15
}
16
}
17
+ // where the above returns true if the date is before or equal, this one only returns if before
18
+ function my_calendar_date_xcomp($early,$late) {
19
+ $firstdate = strtotime($early);
20
+ $lastdate = strtotime($late);
21
+ if ($firstdate < $lastdate) {
22
+ return true;
23
+ } else {
24
+ return false;
25
+ }
26
+ }
27
28
function my_calendar_date_equal($early,$late) {
29
$firstdate = strtotime($early);
130
* @param string $start_of_week The start day of the week you want returned
131
* @return integer The unix timestamp of the date is returned
132
*/
133
+ function get_week_date( $week, $year ) {
134
+ // Get the target week of the year with reference to the starting day of
135
+ // the year
136
+ $start_of_week = (get_option('start_of_week')==1||get_option('start_of_week')==0)?get_option('start_of_week'):0;
137
+ $week_adjustment = ($start_of_week == 0)?0:1;
138
+
139
+ $target_week = strtotime("$week week", strtotime("1 January $year"));
140
+ $date_info = getdate($target_week);
141
+ $day_of_week = $date_info['wday'];
142
+ // normal start day of the week is Monday
143
+ $adjusted_date = $day_of_week - $start_of_week;
144
+ // Get the timestamp of that day
145
+ $first_day = strtotime("-$adjusted_date day",$target_week);
146
+ return $first_day;
147
}
148
149
function add_days_to_date( $givendate,$day=0 ) {
images/icon.png ADDED
Binary file
js/calendrical.css ADDED
@@ -0,0 +1,91 @@
1
+ #event_begin, #event_time, #event_end, #event_endtime {
2
+ position: relative;
3
+ }
4
+ .calendricalDatePopup {
5
+ background: white;
6
+ border: solid 1px #999999;
7
+ padding: 2px;
8
+ text-align: center;
9
+ width: 160px;
10
+ z-index: 5;
11
+ }
12
+ .calendricalDatePopup table {
13
+ border-collapse: collapse;
14
+ width: 160px;
15
+ }
16
+ .calendricalDatePopup table .monthCell {
17
+ padding: 2px 0;
18
+ }
19
+ .calendricalDatePopup table .monthCell a {
20
+ display: block;
21
+ float: left;
22
+ line-height: 20px;
23
+ }
24
+ .calendricalDatePopup table .monthCell .prevMonth, .calendricalDatePopup table .monthCell .nextMoth {
25
+ width: 24px;
26
+ }
27
+ .calendricalDatePopup table .monthCell .monthName {
28
+ width: 110px;
29
+ }
30
+ .calendricalDatePopup table a {
31
+ text-decoration: none;
32
+ }
33
+ .calendricalDatePopup table td {
34
+ text-align: center;
35
+ font-size: 12px;
36
+ padding: 0;
37
+ }
38
+ .calendricalDatePopup table td a {
39
+ display: block;
40
+ color: black;
41
+ padding: 2px 3px;
42
+ }
43
+ .calendricalDatePopup table td a:hover {
44
+ background: #ccccff;
45
+ border: none;
46
+ padding: 2px 3px;
47
+ }
48
+ .calendricalDatePopup table td.today a {
49
+ background: #eeeebb;
50
+ }
51
+ .calendricalDatePopup table td.selected a {
52
+ background: #ccccff;
53
+ }
54
+ .calendricalDatePopup table td.today_selected a {
55
+ background: #eeeebb;
56
+ border: solid 1px #dddd66;
57
+ padding: 1px 2px;
58
+ }
59
+ .calendricalDatePopup table td.nonMonth a {
60
+ color: #999999;
61
+ }
62
+
63
+ .calendricalTimePopup {
64
+ background: white;
65
+ border: solid 1px #999999;
66
+ width: 110px;
67
+ height: 130px;
68
+ overflow: auto;
69
+ z-index: 5;
70
+ }
71
+ .calendricalTimePopup ul {
72
+ margin: 0;
73
+ padding: 0;
74
+ }
75
+ .calendricalTimePopup ul li {
76
+ list-style: none;
77
+ margin: 0;
78
+ }
79
+ .calendricalTimePopup ul li a, .calendricalTimePopup ul li a:visited {
80
+ text-indent: 10px;
81
+ padding: 4px;
82
+ display: block;
83
+ color: black;
84
+ text-decoration: none;
85
+ }
86
+ .calendricalTimePopup ul li a:hover, .calendricalTimePopup ul li.selected a {
87
+ background: #ccccff;
88
+ }
89
+ .calendricalEndTimePopup {
90
+ width: 160px;
91
+ }
js/jquery.calendrical.js ADDED
@@ -0,0 +1,504 @@
1
+ (function($) {
2
+ var monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
3
+ 'July', 'August', 'September', 'October', 'November', 'December'];
4
+
5
+ function getToday()
6
+ {
7
+ var date = new Date();
8
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
9
+ }
10
+
11
+ function areDatesEqual(date1, date2)
12
+ {
13
+ return String(date1) == String(date2);
14
+ }
15
+
16
+ function daysInMonth(year, month)
17
+ {
18
+ if (year instanceof Date) return daysInMonth(year.getFullYear(), year.getMonth());
19
+ if (month == 1) {
20
+ var leapYear = (year % 4 == 0) &&
21
+ (!(year % 100 == 0) || (year % 400 == 0));
22
+ return leapYear ? 29 : 28;
23
+ } else if (month == 3 || month == 5 || month == 8 || month == 10) {
24
+ return 30;
25
+ } else {
26
+ return 31;
27
+ }
28
+ }
29
+
30
+ function dayAfter(date)
31
+ {
32
+ var year = date.getFullYear();
33
+ var month = date.getMonth();
34
+ var day = date.getDate();
35
+ var lastDay = daysInMonth(date);
36
+ return (day == lastDay) ?
37
+ ((month == 11) ?
38
+ new Date(year + 1, 0, 1) :
39
+ new Date(year, month + 1, 1)
40
+ ) :
41
+ new Date(year, month, day + 1);
42
+ }
43
+
44
+ function dayBefore(date)
45
+ {
46
+ var year = date.getFullYear();
47
+ var month = date.getMonth();
48
+ var day = date.getDate();
49
+ return (day == 1) ?
50
+ ((month == 0) ?
51
+ new Date(year - 1, 11, daysInMonth(year - 1, 11)) :
52
+ new Date(year, month - 1, daysInMonth(year, month - 1))
53
+ ) :
54
+ new Date(year, month, day - 1);
55
+ }
56
+
57
+ function monthAfter(year, month)
58
+ {
59
+ return (month == 11) ?
60
+ new Date(year + 1, 0, 1) :
61
+ new Date(year, month + 1, 1);
62
+ }
63
+
64
+ function formatDate(date)
65
+ {
66
+ var d = date.getDate();
67
+ var m = date.getMonth() + 1;
68
+ var dlen = d.toString();
69
+ var mlen = m.toString();
70
+ var day = ( dlen.length == 2 ) ? d : '0' + d;
71
+ var month = ( mlen.length == 2 ) ? ( m ) : '0' + m;
72
+ return (date.getFullYear() + '-' + month + '-' + day );
73
+ }
74
+
75
+ function parseDate(date)
76
+ {
77
+ a = date.split(/[\.\-\/]/);
78
+ var year = a.shift();
79
+ var month = a.shift()-1;
80
+ var day = a.shift();
81
+ return new Date( year, month, day );
82
+ }
83
+
84
+ function formatTime(hour, minute)
85
+ {
86
+ var printHour = hour % 12;
87
+ if (printHour == 0) printHour = 12;
88
+ var printMinute = minute;
89
+ if (minute < 10) printMinute = '0' + minute;
90
+ var half = (hour < 12) ? 'am' : 'pm';
91
+
92
+ return printHour + ':' + printMinute + half;
93
+ }
94
+
95
+ function parseTime(text)
96
+ {
97
+ var match = match = /(\d+)\s*[:\-\.,]\s*(\d+)\s*(am|pm)?/i.exec(text);
98
+ if (match && match.length >= 3) {
99
+ var hour = Number(match[1]);
100
+ var minute = Number(match[2])
101
+ if (hour == 12 && match[3]) hour -= 12;
102
+ if (match[3] && match[3].toLowerCase() == 'pm') hour += 12;
103
+ return {
104
+ hour: hour,
105
+ minute: minute
106
+ };
107
+ } else {
108
+ return null;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Generates calendar header, with month name, << and >> controls, and
114
+ * initials for days of the week.
115
+ */
116
+ function renderCalendarHeader(element, year, month, options)
117
+ {
118
+ //Prepare thead element
119
+ var thead = $('<thead />');
120
+ var titleRow = $('<tr />').appendTo(thead);
121
+
122
+ //Generate << (back a month) link
123
+ $('<th />').addClass('monthCell').append(
124
+ $('<a href="javascript:;">&laquo;</a>')
125
+ .addClass('prevMonth')
126
+ .mousedown(function(e) {
127
+ renderCalendarPage(element,
128
+ month == 0 ? (year - 1) : year,
129
+ month == 0 ? 11 : (month - 1), options
130
+ );
131
+ e.preventDefault();
132
+ })
133
+ ).appendTo(titleRow);
134
+
135
+ //Generate month title
136
+ $('<th />').addClass('monthCell').attr('colSpan', 5).append(
137
+ $('<a href="javascript:;">' + monthNames[month] + ' ' +
138
+ year + '</a>').addClass('monthName')
139
+ ).appendTo(titleRow);
140
+
141
+ //Generate >> (forward a month) link
142
+ $('<th />').addClass('monthCell').append(
143
+ $('<a href="javascript:;">&raquo;</a>')
144
+ .addClass('nextMonth')
145
+ .mousedown(function() {
146
+ renderCalendarPage(element,
147
+ month == 11 ? (year + 1) : year,
148
+ month == 11 ? 0 : (month + 1), options
149
+ );
150
+ })
151
+ ).appendTo(titleRow);
152
+
153
+ //Generate weekday initials row
154
+ var dayNames = $('<tr />').appendTo(thead);
155
+ $.each(String('SMTWTFS').split(''), function(k, v) {
156
+ $('<td />').addClass('dayName').append(v).appendTo(dayNames);
157
+ });
158
+
159
+ return thead;
160
+ }
161
+
162
+ function renderCalendarPage(element, year, month, options)
163
+ {
164
+ options = options || {};
165
+
166
+ var today = getToday();
167
+
168
+ var date = new Date(year, month, 1);
169
+
170
+ //Wind end date forward to saturday week after month
171
+ var endDate = monthAfter(year, month);
172
+ var ff = 6 - endDate.getDay();
173
+ if (ff < 6) ff += 7;
174
+ for (var i = 0; i < ff; i++) endDate = dayAfter(endDate);
175
+
176
+ var table = $('<table />');
177
+ renderCalendarHeader(element, year, month, options).appendTo(table);
178
+
179
+ var tbody = $('<tbody />').appendTo(table);
180
+ var row = $('<tr />');
181
+
182
+ //Rewind date to monday week before month
183
+ var rewind = date.getDay() + 7;
184
+ for (var i = 0; i < rewind; i++) date = dayBefore(date);
185
+
186
+ while (date <= endDate) {
187
+ var td = $('<td />')
188
+ .addClass('day')
189
+ .append(
190
+ $('<a href="javascript:;">' +
191
+ date.getDate() + '</a>'
192
+ ).click((function() {
193
+ var thisDate = date;
194
+
195
+ return function() {
196
+ if (options && options.selectDate) {
197
+ options.selectDate(thisDate);
198
+ }
199
+ }
200
+ }()))
201
+ )
202
+ .appendTo(row);
203
+
204
+ var isToday = areDatesEqual(date, today);
205
+ var isSelected = options.selected &&
206
+ areDatesEqual(options.selected, date);
207
+
208
+ if (isToday) td.addClass('today');
209
+ if (isSelected) td.addClass('selected');
210
+ if (isToday && isSelected) td.addClass('today_selected');
211
+ if (date.getMonth() != month) td.addClass('nonMonth');
212
+
213
+ dow = date.getDay();
214
+ if (dow == 6) {
215
+ tbody.append(row);
216
+ row = $('<tr />');
217
+ }
218
+ date = dayAfter(date);
219
+ }
220
+ if (row.children().length) {
221
+ tbody.append(row);
222
+ } else {
223
+ row.remove();
224
+ }
225
+
226
+ element.empty().append(table);
227
+ }
228
+
229
+ function roundNumber( num, dec ) {
230
+ var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
231
+ return result;
232
+ }
233
+
234
+ function renderTimeSelect(element, options)
235
+ {
236
+ var selection = options.selection && parseTime(options.selection);
237
+ if (selection) {
238
+ selection.minute = Math.floor(selection.minute / 15.0) * 15;
239
+ }
240
+ var startTime = options.startTime &&
241
+ (options.startTime.hour * 60 + options.startTime.minute);
242
+
243
+ var scrollTo; //Element to scroll the dropdown box to when shown
244
+ var ul = $('<ul />');
245
+ var first = $('<li />').append(
246
+ $('<a href="javascript:;">No time/All day</a>')
247
+ .click(function() {
248
+ if (options && options.selectTime) {
249
+ options.selectTime('');
250
+ }
251
+ }).mousemove(function() {
252
+ $('li.selected', ul).removeClass('selected');
253
+ })
254
+ ).appendTo(ul);
255
+ for (var hour = 0; hour < 24; hour++) {
256
+ for (var minute = 0; minute < 60; minute += 15) {
257
+ //if (startTime && startTime > (hour * 60 + minute)) continue;
258
+
259
+ (function() {
260
+ var timeText = formatTime(hour, minute);
261
+ var fullText = timeText;
262
+ if (startTime != null) {
263
+ var duration = roundNumber( ( (hour * 60 + minute) - startTime ), 2 );
264
+ if (duration < 60 && duration >= 0) {
265
+ fullText += ' (' + duration + ' mins)';
266
+ } else if (duration == 60) {
267
+ fullText += ' (1 hr)';
268
+ } else {
269
+ var long_duration = roundNumber( ( duration / 60.0 ), 2 );
270
+ fullText += ' (' + long_duration + ' hrs)';
271
+ }
272
+ }
273
+ var li = $('<li />').append(
274
+ $('<a href="javascript:;">' + fullText + '</a>')
275
+ .click(function() {
276
+ if (options && options.selectTime) {
277
+ options.selectTime(timeText);
278
+ }
279
+ }).mousemove(function() {
280
+ $('li.selected', ul).removeClass('selected');
281
+ })
282
+ ).appendTo(ul);
283
+
284
+ //Set to scroll to the default hour, unless already set
285
+ if (!scrollTo && hour == options.defaultHour) {
286
+ scrollTo = li;
287
+ }
288
+
289
+ if (selection &&
290
+ selection.hour == hour &&
291
+ selection.minute == minute)
292
+ {
293
+ //Highlight selected item
294
+ li.addClass('selected');
295
+ //Set to scroll to the selected hour
296
+ //
297
+ //This is set even if scrollTo is already set, since scrolling to selected hour is more important than
298
+ //scrolling to default hour
299
+ scrollTo = li;
300
+ }
301
+ })();
302
+ }
303
+ }
304
+ var last = $('<li />').append(
305
+ $('<a href="javascript:;">12:00am</a>')
306
+ .click(function() {
307
+ if (options && options.selectTime) {
308
+ options.selectTime('12:00am');
309
+ }
310
+ }).mousemove(function() {
311
+ $('li.selected', ul).removeClass('selected');
312
+ })
313
+ ).appendTo(ul);
314
+ if (scrollTo) {
315
+ //Set timeout of zero so code runs immediately after any calling
316
+ //functions are finished (this is needed, since box hasn't been
317
+ //added to the DOM yet)
318
+ setTimeout(function() {
319
+ //Scroll the dropdown box so that scrollTo item is in the middle
320
+ element[0].scrollTop =
321
+ scrollTo[0].offsetTop - scrollTo.height() * 2;
322
+ }, 0);
323
+ }
324
+ element.empty().append(ul);
325
+ }
326
+
327
+ $.fn.calendricalDate = function( options )
328
+ {
329
+ options = options || {};
330
+ options.padding = options.padding || 4;
331
+
332
+ return this.each(function() {
333
+ var element = $(this);
334
+ var div;
335
+ var within = false;
336
+
337
+ element.bind('focus click', function() {
338
+ if (div) return;
339
+ var offset = element.position();
340
+ var padding = element.css('padding-left');
341
+ div = $('<div />')
342
+ .addClass('calendricalDatePopup')
343
+ .mouseenter(function() { within = true; })
344
+ .mouseleave(function() { within = false; })
345
+ .mousedown(function(e) {
346
+ e.preventDefault();
347
+ })
348
+ .css({
349
+ position: 'absolute',
350
+ left: offset.left,
351
+ top: offset.top + element.height
352
+ });
353
+ element.after(div);
354
+
355
+ var selected = parseDate(element.val());
356
+ if (!selected.getFullYear()) selected = getToday();
357
+
358
+ renderCalendarPage(
359
+ div,
360
+ selected.getFullYear(),
361
+ selected.getMonth(), {
362
+ selected: selected,
363
+ selectDate: function(date) {
364
+ within = false;
365
+ element.val(formatDate(date));
366
+ div.remove();
367
+ div = null;
368
+ if (options.endDate) {
369
+ var endDate = parseDate(
370
+ options.endDate.val()
371
+ );
372
+ if (endDate >= selected) {
373
+ options.endDate.val(formatDate(
374
+ new Date(
375
+ date.getTime() +
376
+ endDate.getTime() -
377
+ selected.getTime()
378
+ )
379
+ ));
380
+ }
381
+ }
382
+ }
383
+ }
384
+ );
385
+ }).blur(function() {
386
+ if (within){
387
+ if (div) element.focus();
388
+ return;
389
+ }
390
+ if (!div) return;
391
+ div.remove();
392
+ div = null;
393
+ });
394
+ });
395
+ };
396
+
397
+ $.fn.calendricalDateRange = function(options)
398
+ {
399
+ if (this.length >= 2) {
400
+ $(this[0]).calendricalDate($.extend({
401
+ endDate: $(this[1])
402
+ }, options));
403
+ $(this[1]).calendricalDate(options);
404
+ }
405
+ return this;
406
+ };
407
+
408
+ $.fn.calendricalTime = function(options)
409
+ {
410
+ options = options || {};
411
+ options.padding = options.padding || 4;
412
+
413
+ return this.each(function() {
414
+ var element = $(this);
415
+ var div;
416
+ var within = false;
417
+
418
+ element.bind('focus click', function() {
419
+ if (div) return;
420
+
421
+ var useStartTime = options.startTime;
422
+ if (useStartTime) {
423
+ if (options.startDate && options.endDate &&
424
+ !areDatesEqual(parseDate(options.startDate.val()),
425
+ parseDate(options.endDate.val())))
426
+ useStartTime = true;
427
+ }
428
+
429
+ var offset = element.position();
430
+ div = $('<div />')
431
+ .addClass('calendricalTimePopup')
432
+ .mouseenter(function() { within = true; })
433
+ .mouseleave(function() { within = false; })
434
+ .mousedown(function(e) {
435
+ e.preventDefault();
436
+ })
437
+ .css({
438
+ position: 'absolute',
439
+ left: offset.left,
440
+ top: offset.top + element.height
441
+ });
442
+ if (useStartTime) {
443
+ div.addClass('calendricalEndTimePopup');
444
+ }
445
+
446
+ element.after(div);
447
+
448
+ var opts = {
449
+ selection: element.val(),
450
+ selectTime: function(time) {
451
+ within = false;
452
+ element.val(time);
453
+ div.remove();
454
+ div = null;
455
+ },
456
+ defaultHour: (options.defaultHour != null) ?
457
+ options.defaultHour : 8
458
+ };
459
+
460
+ if (useStartTime) {
461
+ opts.startTime = parseTime(options.startTime.val());
462
+ }
463
+
464
+ renderTimeSelect(div, opts);
465
+ }).blur(function() {
466
+ if (within){
467
+ if (div) element.focus();
468
+ return;
469
+ }
470
+ if (!div) return;
471
+ div.remove();
472
+ div = null;
473
+ });
474
+ });
475
+ },
476
+
477
+ $.fn.calendricalTimeRange = function(options)
478
+ {
479
+ if (this.length >= 2) {
480
+ $(this[0]).calendricalTime(options);
481
+ $(this[1]).calendricalTime($.extend({
482
+ startTime: $(this[0])
483
+ }, options));
484
+ }
485
+ return this;
486
+ };
487
+
488
+ $.fn.calendricalDateTimeRange = function(options)
489
+ {
490
+ if (this.length >= 4) {
491
+ $(this[0]).calendricalDate($.extend({
492
+ endDate: $(this[2])
493
+ }, options));
494
+ $(this[1]).calendricalTime(options);
495
+ $(this[2]).calendricalDate(options);
496
+ $(this[3]).calendricalTime($.extend({
497
+ startTime: $(this[1]),
498
+ startDate: $(this[0]),
499
+ endDate: $(this[2])
500
+ }, options));
501
+ }
502
+ return this;
503
+ };
504
+ })( jQuery );
js/ui.datepicker.css DELETED
@@ -1,212 +0,0 @@
1
- /* Main Style Sheet for jQuery UI date picker */
2
- #ui-datepicker-div, .ui-datepicker-inline {
3
- font-size: 13px;
4
- padding: 0;
5
- margin: 0;
6
- background: #ddd;
7
- width: 185px;
8
- }
9
- #ui-datepicker-div {
10
- display: none;
11
- border: 1px solid #3185bb;
12
- z-index: 9999;
13
- /*must have*/
14
- }
15
- .ui-datepicker-inline {
16
- float: left;
17
- display: block;
18
- border: 0;
19
- }
20
- .ui-datepicker-rtl {
21
- direction: rtl;
22
- }
23
- .ui-datepicker-dialog {
24
- padding: 5px !important;
25
- border: 4px ridge #ccc!important;
26
- }
27
- button.ui-datepicker-trigger {
28
- width: 25px;
29
- }
30
- img.ui-datepicker-trigger {
31
- margin: 2px;
32
- vertical-align: middle;
33
- }
34
- .ui-datepicker-prompt {
35
- float: left;
36
- padding: 2px;
37
- background: #ddd;
38
- color: #000;
39
- }
40
- * html .ui-datepicker-prompt {
41
- width: 185px;
42
- }
43
- .ui-datepicker-control, .ui-datepicker-links, .ui-datepicker-header, .ui-datepicker {
44
- clear: both;
45
- float: left;
46
- width: 100%;
47
- color: #fff;
48
- }
49
- .ui-datepicker-control {
50
- background: #21759b;
51
- padding: 2px 0px;
52
- }
53
- .ui-datepicker-links {
54
- background: #222;
55
- padding: 2px 0px;
56
- }
57
- .ui-datepicker-control, .ui-datepicker-links {
58
- font-weight: bold;
59
- font-size: 80%;
60
- }
61
- .ui-datepicker-links label {
62
- /* disabled links */
63
- padding: 2px 5px;
64
- color: #888;
65
- }
66
- .ui-datepicker-clear, .ui-datepicker-prev {
67
- float: left;
68
- width: 34%;
69
- }
70
- .ui-datepicker-rtl .ui-datepicker-clear, .ui-datepicker-rtl .ui-datepicker-prev {
71
- float: right;
72
- text-align: right;
73
- }
74
- .ui-datepicker-current {
75
- float: left;
76
- width: 30%;
77
- text-align: center;
78
- }
79
- .ui-datepicker-close, .ui-datepicker-next {
80
- float: right;
81
- width: 34%;
82
- text-align: right;
83
- }
84
- .ui-datepicker-rtl .ui-datepicker-close, .ui-datepicker-rtl .ui-datepicker-next {
85
- float: left;
86
- text-align: left;
87
- }
88
- .ui-datepicker-header {
89
- padding: 1px 0 3px;
90
- background: #333;
91
- text-align: center;
92
- font-weight: bold;
93
- height: 1.3em;
94
- }
95
- .ui-datepicker-header select {
96
- background: #333;
97
- color: #fff;
98
- border: 0px;
99
- font-weight: bold;
100
- }
101
- .ui-datepicker {
102
- background: #ccc;
103
- text-align: center;
104
- font-size: 100%;
105
- }
106
- .ui-datepicker a {
107
- display: block;
108
- width: 100%;
109
- }
110
- .ui-datepicker-title-row {
111
- background: #666;
112
- }
113
- .ui-datepicker-days-row {
114
- background: #e6e6e6;
115
- color: #666;
116
- }
117
- .ui-datepicker-week-col {
118
- background: #666;
119
- color: #fff;
120
- }
121
- .ui-datepicker-days-cell {
122
- color: #000;
123
- border: 1px solid #ddd;
124
- }
125
- .ui-datepicker-days-cell a {
126
- display: block;
127
- }
128
- .ui-datepicker-week-end-cell {
129
- background: #e6e6e6;
130
- }
131
- .ui-datepicker-title-row .ui-datepicker-week-end-cell {
132
- background: #666;
133
- }
134
- .ui-datepicker-days-cell-over {
135
- background: #fff;
136
- border: 1px solid #01355b;
137
- }
138
- .ui-datepicker-unselectable {
139
- color: #888;
140
- }
141
- .ui-datepicker-today {
142
- background: #fcc !important;
143
- }
144
- .ui-datepicker-current-day {
145
- background: #ccc !important;
146
- }
147
- .ui-datepicker-status {
148
- background: #ddd;
149
- width: 100%;
150
- font-size: 80%;
151
- text-align: center;
152
- }
153
- /* ________ Datepicker Links _______** Reset link properties and then override them with !important */
154
- #ui-datepicker-div a, .ui-datepicker-inline a {
155
- cursor: pointer;
156
- margin: 0;
157
- padding: 0;
158
- background: none;
159
- color: #000;
160
- }
161
- .ui-datepicker-inline .ui-datepicker-links a {
162
- padding: 0 5px !important;
163
- }
164
- .ui-datepicker-control a, .ui-datepicker-links a {
165
- padding: 2px 5px !important;
166
- color: #eee !important;
167
- }
168
- .ui-datepicker-title-row a {
169
- color: #eee !important;
170
- }
171
- .ui-datepicker-control a:hover {
172
- background: #fdd !important;
173
- color: #333 !important;
174
- }
175
- .ui-datepicker-links a:hover, .ui-datepicker-title-row a:hover {
176
- background: #ddd !important;
177
- color: #333 !important;
178
- }
179
- /* ___________ MULTIPLE MONTHS _________*/
180
- .ui-datepicker-multi .ui-datepicker {
181
- border: 1px solid #777;
182
- }
183
- .ui-datepicker-one-month {
184
- float: left;
185
- width: 185px;
186
- }
187
- .ui-datepicker-new-row {
188
- clear: left;
189
- }
190
- /* ___________ IE6 IFRAME FIX ________ */
191
- .ui-datepicker-cover {
192
- display: none;
193
- /*sorry for IE5*/
194
- display
195
- /**/
196
- : block;
197
- /*sorry for IE5*/
198
- position: absolute;
199
- /*must have*/
200
- z-index: -1;
201
- /*must have*/
202
- filter: mask();
203
- /*must have*/
204
- top: -4px;
205
- /*must have*/
206
- left: -4px;
207
- /*must have*/
208
- width: 200px;
209
- /*must have*/
210
- height: 200px;
211
- /*must have*/
212
- }
js/ui.datepicker.js DELETED
@@ -1,1718 +0,0 @@
1
- /*
2
- * jQuery UI Datepicker @VERSION
3
- *
4
- * Copyright (c) 2006, 2007, 2008 Marc Grabanski
5
- * Dual licensed under the MIT (MIT-LICENSE.txt)
6
- * and GPL (GPL-LICENSE.txt) licenses.
7
- *
8
- * http://docs.jquery.com/UI/Datepicker
9
- *
10
- * Depends:
11
- * ui.core.js
12
- *
13
- * Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au).
14
- */
15
-
16
- (function($) { // hide the namespace
17
-
18
- var PROP_NAME = 'datepicker';
19
-
20
- /* Date picker manager.
21
- Use the singleton instance of this class, $.datepicker, to interact with the date picker.
22
- Settings for (groups of) date pickers are maintained in an instance object,
23
- allowing multiple different settings on the same page. */
24
-
25
- function Datepicker() {
26
- this.debug = false; // Change this to true to start debugging
27
- this._curInst = null; // The current instance in use
28
- this._disabledInputs = []; // List of date picker inputs that have been disabled
29
- this._datepickerShowing = false; // True if the popup picker is showing , false if not
30
- this._inDialog = false; // True if showing within a "dialog", false if not
31
- this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
32
- this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
33
- this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
34
- this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
35
- this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
36
- this._promptClass = 'ui-datepicker-prompt'; // The name of the dialog prompt marker class
37
- this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
38
- this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
39
- this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
40
- this.regional = []; // Available regional settings, indexed by language code
41
- this.regional[''] = { // Default regional settings
42
- clearText: 'Clear', // Display text for clear link
43
- clearStatus: 'Erase the current date', // Status text for clear link
44
- closeText: 'Close', // Display text for close link
45
- closeStatus: 'Close without change', // Status text for close link
46
- prevText: '&#x3c;Prev', // Display text for previous month link
47
- prevStatus: 'Show the previous month', // Status text for previous month link
48
- prevBigText: '&#x3c;&#x3c;', // Display text for previous year link
49
- prevBigStatus: 'Show the previous year', // Status text for previous year link
50
- nextText: 'Next&#x3e;', // Display text for next month link
51
- nextStatus: 'Show the next month', // Status text for next month link
52
- nextBigText: '&#x3e;&#x3e;', // Display text for next year link
53
- nextBigStatus: 'Show the next year', // Status text for next year link
54
- currentText: 'Today', // Display text for current month link
55
- currentStatus: 'Show the current month', // Status text for current month link
56
- monthNames: ['January','February','March','April','May','June',
57
- 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
58
- monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
59
- monthStatus: 'Show a different month', // Status text for selecting a month
60
- yearStatus: 'Show a different year', // Status text for selecting a year
61
- weekHeader: 'Wk', // Header for the week of the year column
62
- weekStatus: 'Week of the year', // Status text for the week of the year column
63
- dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
64
- dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
65
- dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
66
- dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
67
- dateStatus: 'Select DD, M d', // Status text for the date selection
68
- dateFormat: 'mm/dd/yy', // See format options on parseDate
69
- firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
70
- initStatus: 'Select a date', // Initial Status text on opening
71
- isRTL: false // True if right-to-left language, false if left-to-right
72
- };
73
- this._defaults = { // Global defaults for all the date picker instances
74
- showOn: 'focus', // 'focus' for popup on focus,
75
- // 'button' for trigger button, or 'both' for either
76
- showAnim: 'show', // Name of jQuery animation for popup
77
- showOptions: {}, // Options for enhanced animations
78
- defaultDate: null, // Used when field is blank: actual date,
79
- // +/-number for offset from today, null for today
80
- appendText: '', // Display text following the input box, e.g. showing the format
81
- buttonText: '...', // Text for trigger button
82
- buttonImage: '', // URL for trigger button image
83
- buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
84
- closeAtTop: true, // True to have the clear/close at the top,
85
- // false to have them at the bottom
86
- mandatory: false, // True to hide the Clear link, false to include it
87
- hideIfNoPrevNext: false, // True to hide next/previous month links
88
- // if not applicable, false to just disable them
89
- navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
90
- showBigPrevNext: false, // True to show big prev/next links
91
- gotoCurrent: false, // True if today link goes back to current selection instead
92
- changeMonth: true, // True if month can be selected directly, false if only prev/next
93
- changeYear: true, // True if year can be selected directly, false if only prev/next
94
- showMonthAfterYear: false, // True if the year select precedes month, false for month then year
95
- yearRange: '-10:+10', // Range of years to display in drop-down,
96
- // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
97
- changeFirstDay: true, // True to click on day name to change, false to remain as set
98
- highlightWeek: false, // True to highlight the selected week
99
- showOtherMonths: false, // True to show dates in other months, false to leave blank
100
- showWeeks: false, // True to show week of the year, false to omit
101
- calculateWeek: this.iso8601Week, // How to calculate the week of the year,
102
- // takes a Date and returns the number of the week for it
103
- shortYearCutoff: '+10', // Short year values < this are in the current century,
104
- // > this are in the previous century,
105
- // string value starting with '+' for current year + value
106
- showStatus: false, // True to show status bar at bottom, false to not show it
107
- statusForDate: this.dateStatus, // Function to provide status text for a date -
108
- // takes date and instance as parameters, returns display text
109
- minDate: null, // The earliest selectable date, or null for no limit
110
- maxDate: null, // The latest selectable date, or null for no limit
111
- duration: 'normal', // Duration of display/closure
112
- beforeShowDay: null, // Function that takes a date and returns an array with
113
- // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
114
- // [2] = cell title (optional), e.g. $.datepicker.noWeekends
115
- beforeShow: null, // Function that takes an input field and
116
- // returns a set of custom settings for the date picker
117
- onSelect: null, // Define a callback function when a date is selected
118
- onChangeMonthYear: null, // Define a callback function when the month or year is changed
119
- onClose: null, // Define a callback function when the datepicker is closed
120
- numberOfMonths: 1, // Number of months to show at a time
121
- showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
122
- stepMonths: 1, // Number of months to step back/forward
123
- stepBigMonths: 12, // Number of months to step back/forward for the big links
124
- rangeSelect: false, // Allows for selecting a date range on one date picker
125
- rangeSeparator: ' - ', // Text between two dates in a range
126
- altField: '', // Selector for an alternate field to store selected dates into
127
- altFormat: '', // The date format to use for the alternate field
128
- constrainInput: true // The input is constrained by the current date format
129
- };
130
- $.extend(this._defaults, this.regional['']);
131
- this.dpDiv = $('<div id="' + this._mainDivId + '" style="display: none;"></div>');
132
- }
133
-
134
- $.extend(Datepicker.prototype, {
135
- /* Class name added to elements to indicate already configured with a date picker. */
136
- markerClassName: 'hasDatepicker',
137
-
138
- /* Debug logging (if enabled). */
139
- log: function () {
140
- if (this.debug)
141
- console.log.apply('', arguments);
142
- },
143
-
144
- /* Override the default settings for all instances of the date picker.
145
- @param settings object - the new settings to use as defaults (anonymous object)
146
- @return the manager object */
147
- setDefaults: function(settings) {
148
- extendRemove(this._defaults, settings || {});
149
- return this;
150
- },
151
-
152
- /* Attach the date picker to a jQuery selection.
153
- @param target element - the target input field or division or span
154
- @param settings object - the new settings to use for this date picker instance (anonymous) */
155
- _attachDatepicker: function(target, settings) {
156
- // check for settings on the control itself - in namespace 'date:'
157
- var inlineSettings = null;
158
- for (attrName in this._defaults) {
159
- var attrValue = target.getAttribute('date:' + attrName);
160
- if (attrValue) {
161
- inlineSettings = inlineSettings || {};
162
- try {
163
- inlineSettings[attrName] = eval(attrValue);
164
- } catch (err) {
165
- inlineSettings[attrName] = attrValue;
166
- }
167
- }
168
- }
169
- var nodeName = target.nodeName.toLowerCase();
170
- var inline = (nodeName == 'div' || nodeName == 'span');
171
- if (!target.id)
172
- target.id = 'dp' + (++this.uuid);
173
- var inst = this._newInst($(target), inline);
174
- inst.settings = $.extend({}, settings || {}, inlineSettings || {});
175
- if (nodeName == 'input') {
176
- this._connectDatepicker(target, inst);
177
- } else if (inline) {
178
- this._inlineDatepicker(target, inst);
179
- }
180
- },
181
-
182
- /* Create a new instance object. */
183
- _newInst: function(target, inline) {
184
- var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars
185
- return {id: id, input: target, // associated target
186
- selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
187
- drawMonth: 0, drawYear: 0, // month being drawn
188
- inline: inline, // is datepicker inline or not
189
- dpDiv: (!inline ? this.dpDiv : // presentation div
190
- $('<div class="' + this._inlineClass + '"></div>'))};
191
- },
192
-
193
- /* Attach the date picker to an input field. */
194
- _connectDatepicker: function(target, inst) {
195
- var input = $(target);
196
- if (input.hasClass(this.markerClassName))
197
- return;
198
- var appendText = this._get(inst, 'appendText');
199
- var isRTL = this._get(inst, 'isRTL');
200
- if (appendText)
201
- input[isRTL ? 'before' : 'after']('<span class="' + this._appendClass + '">' + appendText + '</span>');
202
- var showOn = this._get(inst, 'showOn');
203
- if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
204
- input.focus(this._showDatepicker);
205
- if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
206
- var buttonText = this._get(inst, 'buttonText');
207
- var buttonImage = this._get(inst, 'buttonImage');
208
- var trigger = $(this._get(inst, 'buttonImageOnly') ?
209
- $('<img/>').addClass(this._triggerClass).
210
- attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
211
- $('<button type="button"></button>').addClass(this._triggerClass).
212
- html(buttonImage == '' ? buttonText : $('<img/>').attr(
213
- { src:buttonImage, alt:buttonText, title:buttonText })));
214
- input[isRTL ? 'before' : 'after'](trigger);
215
- trigger.click(function() {
216
- if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target)
217
- $.datepicker._hideDatepicker();
218
- else
219
- $.datepicker._showDatepicker(target);
220
- return false;
221
- });
222
- }
223
- input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
224
- bind("setData.datepicker", function(event, key, value) {
225
- inst.settings[key] = value;
226
- }).bind("getData.datepicker", function(event, key) {
227
- return this._get(inst, key);
228
- });
229
- $.data(target, PROP_NAME, inst);
230
- },
231
-
232
- /* Attach an inline date picker to a div. */
233
- _inlineDatepicker: function(target, inst) {
234
- var divSpan = $(target);
235
- if (divSpan.hasClass(this.markerClassName))
236
- return;
237
- divSpan.addClass(this.markerClassName).append(inst.dpDiv).
238
- bind("setData.datepicker", function(event, key, value){
239
- inst.settings[key] = value;
240
- }).bind("getData.datepicker", function(event, key){
241
- return this._get(inst, key);
242
- });
243
- $.data(target, PROP_NAME, inst);
244
- this._setDate(inst, this._getDefaultDate(inst));
245
- this._updateDatepicker(inst);
246
- },
247
-
248
- /* Tidy up after displaying the date picker. */
249
- _inlineShow: function(inst) {
250
- var numMonths = this._getNumberOfMonths(inst); // fix width for dynamic number of date pickers
251
- inst.dpDiv.width(numMonths[1] * $('.ui-datepicker', inst.dpDiv[0]).width());
252
- },
253
-
254
- /* Pop-up the date picker in a "dialog" box.
255
- @param input element - ignored
256
- @param dateText string - the initial date to display (in the current format)
257
- @param onSelect function - the function(dateText) to call when a date is selected
258
- @param settings object - update the dialog date picker instance's settings (anonymous object)
259
- @param pos int[2] - coordinates for the dialog's position within the screen or
260
- event - with x/y coordinates or
261
- leave empty for default (screen centre)
262
- @return the manager object */
263
- _dialogDatepicker: function(input, dateText, onSelect, settings, pos) {
264
- var inst = this._dialogInst; // internal instance
265
- if (!inst) {
266
- var id = 'dp' + (++this.uuid);
267
- this._dialogInput = $('<input type="text" id="' + id +
268
- '" size="1" style="position: absolute; top: -100px;"/>');
269
- this._dialogInput.keydown(this._doKeyDown);
270
- $('body').append(this._dialogInput);
271
- inst = this._dialogInst = this._newInst(this._dialogInput, false);
272
- inst.settings = {};
273
- $.data(this._dialogInput[0], PROP_NAME, inst);
274
- }
275
- extendRemove(inst.settings, settings || {});
276
- this._dialogInput.val(dateText);
277
-
278
- this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
279
- if (!this._pos) {
280
- var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
281
- var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
282
- var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
283
- var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
284
- this._pos = // should use actual width/height below
285
- [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
286
- }
287
-
288
- // move input on screen for focus, but hidden behind dialog
289
- this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
290
- inst.settings.onSelect = onSelect;
291
- this._inDialog = true;
292
- this.dpDiv.addClass(this._dialogClass);
293
- this._showDatepicker(this._dialogInput[0]);
294
- if ($.blockUI)
295
- $.blockUI(this.dpDiv);
296
- $.data(this._dialogInput[0], PROP_NAME, inst);
297
- return this;
298
- },
299
-
300
- /* Detach a datepicker from its control.
301
- @param target element - the target input field or division or span */
302
- _destroyDatepicker: function(target) {
303
- var $target = $(target);
304
- if (!$target.hasClass(this.markerClassName)) {
305
- return;
306
- }
307
- var nodeName = target.nodeName.toLowerCase();
308
- $.removeData(target, PROP_NAME);
309
- if (nodeName == 'input') {
310
- $target.siblings('.' + this._appendClass).remove().end().
311
- siblings('.' + this._triggerClass).remove().end().
312
- removeClass(this.markerClassName).
313
- unbind('focus', this._showDatepicker).
314
- unbind('keydown', this._doKeyDown).
315
- unbind('keypress', this._doKeyPress);
316
- } else if (nodeName == 'div' || nodeName == 'span')
317
- $target.removeClass(this.markerClassName).empty();
318
- },
319
-
320
- /* Enable the date picker to a jQuery selection.
321
- @param target element - the target input field or division or span */
322
- _enableDatepicker: function(target) {
323
- var $target = $(target);
324
- if (!$target.hasClass(this.markerClassName)) {
325
- return;
326
- }
327
- var nodeName = target.nodeName.toLowerCase();
328
- if (nodeName == 'input') {
329
- target.disabled = false;
330
- $target.siblings('button.' + this._triggerClass).
331
- each(function() { this.disabled = false; }).end().
332
- siblings('img.' + this._triggerClass).
333
- css({opacity: '1.0', cursor: ''});
334
- }
335
- else if (nodeName == 'div' || nodeName == 'span') {
336
- $target.children('.' + this._disableClass).remove();
337
- }
338
- this._disabledInputs = $.map(this._disabledInputs,
339
- function(value) { return (value == target ? null : value); }); // delete entry
340
- },
341
-
342
- /* Disable the date picker to a jQuery selection.
343
- @param target element - the target input field or division or span */
344
- _disableDatepicker: function(target) {
345
- var $target = $(target);
346
- if (!$target.hasClass(this.markerClassName)) {
347
- return;
348
- }
349
- var nodeName = target.nodeName.toLowerCase();
350
- if (nodeName == 'input') {
351
- target.disabled = true;
352
- $target.siblings('button.' + this._triggerClass).
353
- each(function() { this.disabled = true; }).end().
354
- siblings('img.' + this._triggerClass).
355
- css({opacity: '0.5', cursor: 'default'});
356
- }
357
- else if (nodeName == 'div' || nodeName == 'span') {
358
- var inline = $target.children('.' + this._inlineClass);
359
- var offset = inline.offset();
360
- var relOffset = {left: 0, top: 0};
361
- inline.parents().each(function() {
362
- if ($(this).css('position') == 'relative') {
363
- relOffset = $(this).offset();
364
- return false;
365
- }
366
- });
367
- $target.prepend('<div class="' + this._disableClass + '" style="' +
368
- ($.browser.msie ? 'background-color: transparent; ' : '') +
369
- 'width: ' + inline.width() + 'px; height: ' + inline.height() +
370
- 'px; left: ' + (offset.left - relOffset.left) +
371
- 'px; top: ' + (offset.top - relOffset.top) + 'px;"></div>');
372
- }
373
- this._disabledInputs = $.map(this._disabledInputs,
374
- function(value) { return (value == target ? null : value); }); // delete entry
375
- this._disabledInputs[this._disabledInputs.length] = target;
376
- },
377
-
378
- /* Is the first field in a jQuery collection disabled as a datepicker?
379
- @param target element - the target input field or division or span
380
- @return boolean - true if disabled, false if enabled */
381
- _isDisabledDatepicker: function(target) {
382
- if (!target)
383
- return false;
384
- for (var i = 0; i < this._disabledInputs.length; i++) {
385
- if (this._disabledInputs[i] == target)
386
- return true;
387
- }
388
- return false;
389
- },
390
-
391
- /* Retrieve the instance data for the target control.
392
- @param target element - the target input field or division or span
393
- @return object - the associated instance data
394
- @throws error if a jQuery problem getting data */
395
- _getInst: function(target) {
396
- try {
397
- return $.data(target, PROP_NAME);
398
- }
399
- catch (err) {
400
- throw 'Missing instance data for this datepicker';
401
- }
402
- },
403
-
404
- /* Update the settings for a date picker attached to an input field or division.
405
- @param target element - the target input field or division or span
406
- @param name object - the new settings to update or
407
- string - the name of the setting to change or
408
- @param value any - the new value for the setting (omit if above is an object) */
409
- _optionDatepicker: function(target, name, value) {
410
- var settings = name || {};
411
- if (typeof name == 'string') {
412
- settings = {};
413
- settings[name] = value;
414
- }
415
- var inst = this._getInst(target);
416
- if (inst) {
417
- if (this._curInst == inst) {
418
- this._hideDatepicker(null);
419
- }
420
- extendRemove(inst.settings, settings);
421
- var date = new Date();
422
- extendRemove(inst, {rangeStart: null, // start of range
423
- endDay: null, endMonth: null, endYear: null, // end of range
424
- selectedDay: date.getDate(), selectedMonth: date.getMonth(),
425
- selectedYear: date.getFullYear(), // starting point
426
- currentDay: date.getDate(), currentMonth: date.getMonth(),
427
- currentYear: date.getFullYear(), // current selection
428
- drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn
429
- this._updateDatepicker(inst);
430
- }
431
- },
432
-
433
- // change method deprecated
434
- _changeDatepicker: this._optionDatepicker,
435
-
436
- /* Redraw the date picker attached to an input field or division.
437
- @param target element - the target input field or division or span */
438
- _refreshDatepicker: function(target) {
439
- var inst = this._getInst(target);
440
- if (inst) {
441
- this._updateDatepicker(inst);
442
- }
443
- },
444
-
445
- /* Set the dates for a jQuery selection.
446
- @param target element - the target input field or division or span
447
- @param date Date - the new date
448
- @param endDate Date - the new end date for a range (optional) */
449
- _setDateDatepicker: function(target, date, endDate) {
450
- var inst = this._getInst(target);
451
- if (inst) {
452
- this._setDate(inst, date, endDate);
453
- this._updateDatepicker(inst);
454
- this._updateAlternate(inst);
455
- }
456
- },
457
-
458
- /* Get the date(s) for the first entry in a jQuery selection.
459
- @param target element - the target input field or division or span
460
- @return Date - the current date or
461
- Date[2] - the current dates for a range */
462
- _getDateDatepicker: function(target) {
463
- var inst = this._getInst(target);
464
- if (inst && !inst.inline)
465
- this._setDateFromField(inst);
466
- return (inst ? this._getDate(inst) : null);
467
- },
468
-
469
- /* Handle keystrokes. */
470
- _doKeyDown: function(e) {
471
- var inst = $.datepicker._getInst(e.target);
472
- var handled = true;
473
- if ($.datepicker._datepickerShowing)
474
- switch (e.keyCode) {
475
- case 9: $.datepicker._hideDatepicker(null, '');
476
- break; // hide on tab out
477
- case 13: if ($('td.ui-datepicker-days-cell-over', inst.dpDiv)[0])
478
- $.datepicker._selectDay(e.target, inst.selectedMonth, inst.selectedYear,
479
- $('td.ui-datepicker-days-cell-over', inst.dpDiv)[0]);
480
- return false; // don't submit the form
481
- break; // select the value on enter
482
- case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
483
- break; // hide on escape
484
- case 33: $.datepicker._adjustDate(e.target, (e.ctrlKey ?
485
- -$.datepicker._get(inst, 'stepBigMonths') :
486
- -$.datepicker._get(inst, 'stepMonths')), 'M');
487
- break; // previous month/year on page up/+ ctrl
488
- case 34: $.datepicker._adjustDate(e.target, (e.ctrlKey ?
489
- +$.datepicker._get(inst, 'stepBigMonths') :
490
- +$.datepicker._get(inst, 'stepMonths')), 'M');
491
- break; // next month/year on page down/+ ctrl
492
- case 35: if (e.ctrlKey || e.metaKey) $.datepicker._clearDate(e.target);
493
- handled = e.ctrlKey;
494
- break; // clear on ctrl or command +end
495
- case 36: if (e.ctrlKey || e.metaKey) $.datepicker._gotoToday(e.target);
496
- handled = e.ctrlKey;
497
- break; // current on ctrl or command +home
498
- case 37: if (e.ctrlKey || e.metaKey) $.datepicker._adjustDate(e.target, -1, 'D');
499
- handled = e.ctrlKey;
500
- // -1 day on ctrl or command +left
501
- if (e.originalEvent.altKey) $.datepicker._adjustDate(e.target, (e.ctrlKey ?
502
- -$.datepicker._get(inst, 'stepBigMonths') :
503
- -$.datepicker._get(inst, 'stepMonths')), 'M');
504
- // next month/year on alt +left on Mac
505
- break;
506
- case 38: if (e.ctrlKey || e.metaKey) $.datepicker._adjustDate(e.target, -7, 'D');
507
- handled = e.ctrlKey;
508
- break; // -1 week on ctrl or command +up
509
- case 39: if (e.ctrlKey || e.metaKey) $.datepicker._adjustDate(e.target, +1, 'D');
510
- handled = e.ctrlKey;
511
- // +1 day on ctrl or command +right
512
- if (e.originalEvent.altKey) $.datepicker._adjustDate(e.target, (e.ctrlKey ?
513
- +$.datepicker._get(inst, 'stepBigMonths') :
514
- +$.datepicker._get(inst, 'stepMonths')), 'M');
515
- // next month/year on alt +right
516
- break;
517
- case 40: if (e.ctrlKey || e.metaKey) $.datepicker._adjustDate(e.target, +7, 'D');
518
- handled = e.ctrlKey;
519
- break; // +1 week on ctrl or command +down
520
- default: handled = false;
521
- }
522
- else if (e.keyCode == 36 && e.ctrlKey) // display the date picker on ctrl+home
523
- $.datepicker._showDatepicker(this);
524
- else
525
- handled = false;
526
- if (handled) {
527
- e.preventDefault();
528
- e.stopPropagation();
529
- }
530
- },
531
-
532
- /* Filter entered characters - based on date format. */
533
- _doKeyPress: function(e) {
534
- var inst = $.datepicker._getInst(e.target);
535
- if ($.datepicker._get(inst, 'constrainInput')) {
536
- var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
537
- var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
538
- return e.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
539
- }
540
- },
541
-
542
- /* Pop-up the date picker for a given input field.
543
- @param input element - the input field attached to the date picker or
544
- event - if triggered by focus */
545
- _showDatepicker: function(input) {
546
- input = input.target || input;
547
- if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
548
- input = $('input', input.parentNode)[0];
549
- if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
550
- return;
551
- var inst = $.datepicker._getInst(input);
552
- var beforeShow = $.datepicker._get(inst, 'beforeShow');
553
- extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
554
- $.datepicker._hideDatepicker(null, '');
555
- $.datepicker._lastInput = input;
556
- $.datepicker._setDateFromField(inst);
557
- if ($.datepicker._inDialog) // hide cursor
558
- input.value = '';
559
- if (!$.datepicker._pos) { // position below input
560
- $.datepicker._pos = $.datepicker._findPos(input);
561
- $.datepicker._pos[1] += input.offsetHeight; // add the height
562
- }
563
- var isFixed = false;
564
- $(input).parents().each(function() {
565
- isFixed |= $(this).css('position') == 'fixed';
566
- return !isFixed;
567
- });
568
- if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
569
- $.datepicker._pos[0] -= document.documentElement.scrollLeft;
570
- $.datepicker._pos[1] -= document.documentElement.scrollTop;
571
- }
572
- var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
573
- $.datepicker._pos = null;
574
- inst.rangeStart = null;
575
- // determine sizing offscreen
576
- inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
577
- $.datepicker._updateDatepicker(inst);
578
- // fix width for dynamic number of date pickers
579
- inst.dpDiv.width($.datepicker._getNumberOfMonths(inst)[1] *
580
- $('.ui-datepicker', inst.dpDiv[0])[0].offsetWidth);
581
- // and adjust position before showing
582
- offset = $.datepicker._checkOffset(inst, offset, isFixed);
583
- inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
584
- 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
585
- left: offset.left + 'px', top: offset.top + 'px'});
586
- if (!inst.inline) {
587
- var showAnim = $.datepicker._get(inst, 'showAnim') || 'show';
588
- var duration = $.datepicker._get(inst, 'duration');
589
- var postProcess = function() {
590
- $.datepicker._datepickerShowing = true;
591
- if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems
592
- $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
593
- height: inst.dpDiv.height() + 4});
594
- };
595
- if ($.effects && $.effects[showAnim])
596
- inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
597
- else
598
- inst.dpDiv[showAnim](duration, postProcess);
599
- if (duration == '')
600
- postProcess();
601
- if (inst.input[0].type != 'hidden')
602
- inst.input[0].focus();
603
- $.datepicker._curInst = inst;
604
- }
605
- },
606
-
607
- /* Generate the date picker content. */
608
- _updateDatepicker: function(inst) {
609
- var dims = {width: inst.dpDiv.width() + 4,
610
- height: inst.dpDiv.height() + 4};
611
- inst.dpDiv.empty().append(this._generateHTML(inst)).
612
- find('iframe.ui-datepicker-cover').
613
- css({width: dims.width, height: dims.height});
614
- var numMonths = this._getNumberOfMonths(inst);
615
- inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
616
- 'Class']('ui-datepicker-multi');
617
- inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
618
- 'Class']('ui-datepicker-rtl');
619
- if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst)
620
- $(inst.input[0]).focus();
621
- },
622
-
623
- /* Check positioning to remain on screen. */
624
- _checkOffset: function(inst, offset, isFixed) {
625
- var pos = inst.input ? this._findPos(inst.input[0]) : null;
626
- var browserWidth = window.innerWidth || (document.documentElement ?
627
- document.documentElement.clientWidth : document.body.clientWidth);
628
- var browserHeight = window.innerHeight || (document.documentElement ?
629
- document.documentElement.clientHeight : document.body.clientHeight);
630
- var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
631
- var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
632
- // reposition date picker horizontally if outside the browser window
633
- if (this._get(inst, 'isRTL') || (offset.left + inst.dpDiv.width() - scrollX) > browserWidth)
634
- offset.left = Math.max((isFixed ? 0 : scrollX),
635
- pos[0] + (inst.input ? inst.input.width() : 0) - (isFixed ? scrollX : 0) - inst.dpDiv.width() -
636
- (isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0));
637
- else
638
- offset.left -= (isFixed ? scrollX : 0);
639
- // reposition date picker vertically if outside the browser window
640
- if ((offset.top + inst.dpDiv.height() - scrollY) > browserHeight)
641
- offset.top = Math.max((isFixed ? 0 : scrollY),
642
- pos[1] - (isFixed ? scrollY : 0) - (this._inDialog ? 0 : inst.dpDiv.height()) -
643
- (isFixed && $.browser.opera ? document.documentElement.scrollTop : 0));
644
- else
645
- offset.top -= (isFixed ? scrollY : 0);
646
- return offset;
647
- },
648
-
649
- /* Find an object's position on the screen. */
650
- _findPos: function(obj) {
651
- while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
652
- obj = obj.nextSibling;
653
- }
654
- var position = $(obj).offset();
655
- return [position.left, position.top];
656
- },
657
-
658
- /* Hide the date picker from view.
659
- @param input element - the input field attached to the date picker
660
- @param duration string - the duration over which to close the date picker */
661
- _hideDatepicker: function(input, duration) {
662
- var inst = this._curInst;
663
- if (!inst || (input && inst != $.data(input, PROP_NAME)))
664
- return;
665
- var rangeSelect = this._get(inst, 'rangeSelect');
666
- if (rangeSelect && inst.stayOpen)
667
- this._selectDate('#' + inst.id, this._formatDate(inst,
668
- inst.currentDay, inst.currentMonth, inst.currentYear));
669
- inst.stayOpen = false;
670
- if (this._datepickerShowing) {
671
- duration = (duration != null ? duration : this._get(inst, 'duration'));
672
- var showAnim = this._get(inst, 'showAnim');
673
- var postProcess = function() {
674
- $.datepicker._tidyDialog(inst);
675
- };
676
- if (duration != '' && $.effects && $.effects[showAnim])
677
- inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
678
- duration, postProcess);
679
- else
680
- inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
681
- (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
682
- if (duration == '')
683
- this._tidyDialog(inst);
684
- var onClose = this._get(inst, 'onClose');
685
- if (onClose)
686
- onClose.apply((inst.input ? inst.input[0] : null),
687
- [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback
688
- this._datepickerShowing = false;
689
- this._lastInput = null;
690
- inst.settings.prompt = null;
691
- if (this._inDialog) {
692
- this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
693
- if ($.blockUI) {
694
- $.unblockUI();
695
- $('body').append(this.dpDiv);
696
- }
697
- }
698
- this._inDialog = false;
699
- }
700
- this._curInst = null;
701
- },
702
-
703
- /* Tidy up after a dialog display. */
704
- _tidyDialog: function(inst) {
705
- inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker');
706
- $('.' + this._promptClass, inst.dpDiv).remove();
707
- },
708
-
709
- /* Close date picker if clicked elsewhere. */
710
- _checkExternalClick: function(event) {
711
- if (!$.datepicker._curInst)
712
- return;
713
- var $target = $(event.target);
714
- if (($target.parents('#' + $.datepicker._mainDivId).length == 0) &&
715
- !$target.hasClass($.datepicker.markerClassName) &&
716
- !$target.hasClass($.datepicker._triggerClass) &&
717
- $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
718
- $.datepicker._hideDatepicker(null, '');
719
- },
720
-
721
- /* Adjust one of the date sub-fields. */
722
- _adjustDate: function(id, offset, period) {
723
- var target = $(id);
724
- var inst = this._getInst(target[0]);
725
- this._adjustInstDate(inst, offset, period);
726
- this._updateDatepicker(inst);
727
- },
728
-
729
- /* Action for current link. */
730
- _gotoToday: function(id) {
731
- var target = $(id);
732
- var inst = this._getInst(target[0]);
733
- if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
734
- inst.selectedDay = inst.currentDay;
735
- inst.drawMonth = inst.selectedMonth = inst.currentMonth;
736
- inst.drawYear = inst.selectedYear = inst.currentYear;
737
- }
738
- else {
739
- var date = new Date();
740
- inst.selectedDay = date.getDate();
741
- inst.drawMonth = inst.selectedMonth = date.getMonth();
742
- inst.drawYear = inst.selectedYear = date.getFullYear();
743
- }
744
- this._notifyChange(inst);
745
- this._adjustDate(target);
746
- },
747
-
748
- /* Action for selecting a new month/year. */
749
- _selectMonthYear: function(id, select, period) {
750
- var target = $(id);
751
- var inst = this._getInst(target[0]);
752
- inst._selectingMonthYear = false;
753
- inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
754
- inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
755
- parseInt(select.options[select.selectedIndex].value,10);
756
- this._notifyChange(inst);
757
- this._adjustDate(target);
758
- },
759
-
760
- /* Restore input focus after not changing month/year. */
761
- _clickMonthYear: function(id) {
762
- var target = $(id);
763
- var inst = this._getInst(target[0]);
764
- if (inst.input && inst._selectingMonthYear && !$.browser.msie)
765
- inst.input[0].focus();
766
- inst._selectingMonthYear = !inst._selectingMonthYear;
767
- },
768
-
769
- /* Action for changing the first week day. */
770
- _changeFirstDay: function(id, day) {
771
- var target = $(id);
772
- var inst = this._getInst(target[0]);
773
- inst.settings.firstDay = day;
774
- this._updateDatepicker(inst);
775
- },
776
-
777
- /* Action for selecting a day. */
778
- _selectDay: function(id, month, year, td) {
779
- if ($(td).hasClass(this._unselectableClass))
780
- return;
781
- var target = $(id);
782
- var inst = this._getInst(target[0]);
783
- var rangeSelect = this._get(inst, 'rangeSelect');
784
- if (rangeSelect) {
785
- inst.stayOpen = !inst.stayOpen;
786
- if (inst.stayOpen) {
787
- $('.ui-datepicker td', inst.dpDiv).removeClass(this._currentClass);
788
- $(td).addClass(this._currentClass);
789
- }
790
- }
791
- inst.selectedDay = inst.currentDay = $('a', td).html();
792
- inst.selectedMonth = inst.currentMonth = month;
793
- inst.selectedYear = inst.currentYear = year;
794
- if (inst.stayOpen) {
795
- inst.endDay = inst.endMonth = inst.endYear = null;
796
- }
797
- else if (rangeSelect) {
798
- inst.endDay = inst.currentDay;
799
- inst.endMonth = inst.currentMonth;
800
- inst.endYear = inst.currentYear;
801
- }
802
- this._selectDate(id, this._formatDate(inst,
803
- inst.currentDay, inst.currentMonth, inst.currentYear));
804
- if (inst.stayOpen) {
805
- inst.rangeStart = new Date(inst.currentYear, inst.currentMonth, inst.currentDay);
806
- this._updateDatepicker(inst);
807
- }
808
- else if (rangeSelect) {
809
- inst.selectedDay = inst.currentDay = inst.rangeStart.getDate();
810
- inst.selectedMonth = inst.currentMonth = inst.rangeStart.getMonth();
811
- inst.selectedYear = inst.currentYear = inst.rangeStart.getFullYear();
812
- inst.rangeStart = null;
813
- if (inst.inline)
814
- this._updateDatepicker(inst);
815
- }
816
- },
817
-
818
- /* Erase the input field and hide the date picker. */
819
- _clearDate: function(id) {
820
- var target = $(id);
821
- var inst = this._getInst(target[0]);
822
- if (this._get(inst, 'mandatory'))
823
- return;
824
- inst.stayOpen = false;
825
- inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
826
- this._selectDate(target, '');
827
- },
828
-
829
- /* Update the input field with the selected date. */
830
- _selectDate: function(id, dateStr) {
831
- var target = $(id);
832
- var inst = this._getInst(target[0]);
833
- dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
834
- if (this._get(inst, 'rangeSelect') && dateStr)
835
- dateStr = (inst.rangeStart ? this._formatDate(inst, inst.rangeStart) :
836
- dateStr) + this._get(inst, 'rangeSeparator') + dateStr;
837
- if (inst.input)
838
- inst.input.val(dateStr);
839
- this._updateAlternate(inst);
840
- var onSelect = this._get(inst, 'onSelect');
841
- if (onSelect)
842
- onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
843
- else if (inst.input)
844
- inst.input.trigger('change'); // fire the change event
845
- if (inst.inline)
846
- this._updateDatepicker(inst);
847
- else if (!inst.stayOpen) {
848
- this._hideDatepicker(null, this._get(inst, 'duration'));
849
- this._lastInput = inst.input[0];
850
- if (typeof(inst.input[0]) != 'object')
851
- inst.input[0].focus(); // restore focus
852
- this._lastInput = null;
853
- }
854
- },
855
-
856
- /* Update any alternate field to synchronise with the main field. */
857
- _updateAlternate: function(inst) {
858
- var altField = this._get(inst, 'altField');
859
- if (altField) { // update alternate field too
860
- var altFormat = this._get(inst, 'altFormat');
861
- var date = this._getDate(inst);
862
- dateStr = (isArray(date) ? (!date[0] && !date[1] ? '' :
863
- this.formatDate(altFormat, date[0], this._getFormatConfig(inst)) +
864
- this._get(inst, 'rangeSeparator') + this.formatDate(
865
- altFormat, date[1] || date[0], this._getFormatConfig(inst))) :
866
- this.formatDate(altFormat, date, this._getFormatConfig(inst)));
867
- $(altField).each(function() { $(this).val(dateStr); });
868
- }
869
- },
870
-
871
- /* Set as beforeShowDay function to prevent selection of weekends.
872
- @param date Date - the date to customise
873
- @return [boolean, string] - is this date selectable?, what is its CSS class? */
874
- noWeekends: function(date) {
875
- var day = date.getDay();
876
- return [(day > 0 && day < 6), ''];
877
- },
878
-
879
- /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
880
- @param date Date - the date to get the week for
881
- @return number - the number of the week within the year that contains this date */
882
- iso8601Week: function(date) {
883
- var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
884
- (date.getTimezoneOffset() / -60));
885
- var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
886
- var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
887
- firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
888
- if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
889
- checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
890
- return $.datepicker.iso8601Week(checkDate);
891
- } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
892
- firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
893
- if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
894
- return 1;
895
- }
896
- }
897
- return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
898
- },
899
-
900
- /* Provide status text for a particular date.
901
- @param date the date to get the status for
902
- @param inst the current datepicker instance
903
- @return the status display text for this date */
904
- dateStatus: function(date, inst) {
905
- return $.datepicker.formatDate($.datepicker._get(inst, 'dateStatus'),
906
- date, $.datepicker._getFormatConfig(inst));
907
- },
908
-
909
- /* Parse a string value into a date object.
910
- See formatDate below for the possible formats.
911
-
912
- @param format string - the expected format of the date
913
- @param value string - the date in the above format
914
- @param settings Object - attributes include:
915
- shortYearCutoff number - the cutoff year for determining the century (optional)
916
- dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
917
- dayNames string[7] - names of the days from Sunday (optional)
918
- monthNamesShort string[12] - abbreviated names of the months (optional)
919
- monthNames string[12] - names of the months (optional)
920
- @return Date - the extracted date value or null if value is blank */
921
- parseDate: function (format, value, settings) {
922
- if (format == null || value == null)
923
- throw 'Invalid arguments';
924
- value = (typeof value == 'object' ? value.toString() : value + '');
925
- if (value == '')
926
- return null;
927
- var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
928
- var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
929
- var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
930
- var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
931
- var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
932
- var year = -1;
933
- var month = -1;
934
- var day = -1;
935
- var doy = -1;
936
- var literal = false;
937
- // Check whether a format character is doubled
938
- var lookAhead = function(match) {
939
- var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
940
- if (matches)
941
- iFormat++;
942
- return matches;
943
- };
944
- // Extract a number from the string value
945
- var getNumber = function(match) {
946
- lookAhead(match);
947
- var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2)));
948
- var size = origSize;
949
- var num = 0;
950
- while (size > 0 && iValue < value.length &&
951
- value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
952
- num = num * 10 + parseInt(value.charAt(iValue++),10);
953
- size--;
954
- }
955
- if (size == origSize)
956
- throw 'Missing number at position ' + iValue;
957
- return num;
958
- };
959
- // Extract a name from the string value and convert to an index
960
- var getName = function(match, shortNames, longNames) {
961
- var names = (lookAhead(match) ? longNames : shortNames);
962
- var size = 0;
963
- for (var j = 0; j < names.length; j++)
964
- size = Math.max(size, names[j].length);
965
- var name = '';
966
- var iInit = iValue;
967
- while (size > 0 && iValue < value.length) {
968
- name += value.charAt(iValue++);
969
- for (var i = 0; i < names.length; i++)
970
- if (name == names[i])
971
- return i + 1;
972
- size--;
973
- }
974
- throw 'Unknown name at position ' + iInit;
975
- };
976
- // Confirm that a literal character matches the string value
977
- var checkLiteral = function() {
978
- if (value.charAt(iValue) != format.charAt(iFormat))
979
- throw 'Unexpected literal at position ' + iValue;
980
- iValue++;
981
- };
982
- var iValue = 0;
983
- for (var iFormat = 0; iFormat < format.length; iFormat++) {
984
- if (literal)
985
- if (format.charAt(iFormat) == "'" && !lookAhead("'"))
986
- literal = false;
987
- else
988
- checkLiteral();
989
- else
990
- switch (format.charAt(iFormat)) {
991
- case 'd':
992
- day = getNumber('d');
993
- break;
994
- case 'D':
995
- getName('D', dayNamesShort, dayNames);
996
- break;
997
- case 'o':
998
- doy = getNumber('o');
999
-