merb-admin 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +58 -0
  3. data/Rakefile +64 -0
  4. data/app/controllers/application.rb +6 -0
  5. data/app/controllers/main.rb +145 -0
  6. data/app/helpers/application_helper.rb +64 -0
  7. data/app/helpers/main_helper.rb +122 -0
  8. data/app/views/layout/_message.html.erb +10 -0
  9. data/app/views/layout/dashboard.html.erb +34 -0
  10. data/app/views/layout/form.html.erb +48 -0
  11. data/app/views/layout/list.html.erb +42 -0
  12. data/app/views/main/_belongs_to.html.erb +29 -0
  13. data/app/views/main/_big_decimal.html.erb +12 -0
  14. data/app/views/main/_boolean.html.erb +7 -0
  15. data/app/views/main/_date.html.erb +12 -0
  16. data/app/views/main/_datetime.html.erb +12 -0
  17. data/app/views/main/_float.html.erb +12 -0
  18. data/app/views/main/_has_many.html.erb +16 -0
  19. data/app/views/main/_has_one.html.erb +30 -0
  20. data/app/views/main/_integer.html.erb +18 -0
  21. data/app/views/main/_properties.html.erb +18 -0
  22. data/app/views/main/_string.html.erb +12 -0
  23. data/app/views/main/_text.html.erb +11 -0
  24. data/app/views/main/_time.html.erb +12 -0
  25. data/app/views/main/_timestamp.html.erb +12 -0
  26. data/app/views/main/delete.html.erb +12 -0
  27. data/app/views/main/edit.html.erb +25 -0
  28. data/app/views/main/index.html.erb +22 -0
  29. data/app/views/main/list.html.erb +72 -0
  30. data/app/views/main/new.html.erb +22 -0
  31. data/lib/abstract_model.rb +67 -0
  32. data/lib/activerecord_support.rb +169 -0
  33. data/lib/datamapper_support.rb +157 -0
  34. data/lib/generic_support.rb +17 -0
  35. data/lib/merb-admin/merbtasks.rb +103 -0
  36. data/lib/merb-admin/slicetasks.rb +20 -0
  37. data/lib/merb-admin/spectasks.rb +53 -0
  38. data/lib/merb-admin.rb +99 -0
  39. data/public/images/arrow-down.gif +0 -0
  40. data/public/images/arrow-up.gif +0 -0
  41. data/public/images/changelist-bg.gif +0 -0
  42. data/public/images/changelist-bg_rtl.gif +0 -0
  43. data/public/images/chooser-bg.gif +0 -0
  44. data/public/images/chooser_stacked-bg.gif +0 -0
  45. data/public/images/default-bg-reverse.gif +0 -0
  46. data/public/images/default-bg.gif +0 -0
  47. data/public/images/deleted-overlay.gif +0 -0
  48. data/public/images/icon-no.gif +0 -0
  49. data/public/images/icon-unknown.gif +0 -0
  50. data/public/images/icon-yes.gif +0 -0
  51. data/public/images/icon_addlink.gif +0 -0
  52. data/public/images/icon_alert.gif +0 -0
  53. data/public/images/icon_calendar.gif +0 -0
  54. data/public/images/icon_changelink.gif +0 -0
  55. data/public/images/icon_clock.gif +0 -0
  56. data/public/images/icon_deletelink.gif +0 -0
  57. data/public/images/icon_error.gif +0 -0
  58. data/public/images/icon_searchbox.png +0 -0
  59. data/public/images/icon_success.gif +0 -0
  60. data/public/images/inline-delete-8bit.png +0 -0
  61. data/public/images/inline-delete.png +0 -0
  62. data/public/images/inline-restore-8bit.png +0 -0
  63. data/public/images/inline-restore.png +0 -0
  64. data/public/images/inline-splitter-bg.gif +0 -0
  65. data/public/images/nav-bg-grabber.gif +0 -0
  66. data/public/images/nav-bg-reverse.gif +0 -0
  67. data/public/images/nav-bg.gif +0 -0
  68. data/public/images/selector-add.gif +0 -0
  69. data/public/images/selector-addall.gif +0 -0
  70. data/public/images/selector-remove.gif +0 -0
  71. data/public/images/selector-removeall.gif +0 -0
  72. data/public/images/selector-search.gif +0 -0
  73. data/public/images/selector_stacked-add.gif +0 -0
  74. data/public/images/selector_stacked-remove.gif +0 -0
  75. data/public/images/tool-left.gif +0 -0
  76. data/public/images/tool-left_over.gif +0 -0
  77. data/public/images/tool-right.gif +0 -0
  78. data/public/images/tool-right_over.gif +0 -0
  79. data/public/images/tooltag-add.gif +0 -0
  80. data/public/images/tooltag-add_over.gif +0 -0
  81. data/public/images/tooltag-arrowright.gif +0 -0
  82. data/public/images/tooltag-arrowright_over.gif +0 -0
  83. data/public/javascripts/CollapsedFieldsets.js +85 -0
  84. data/public/javascripts/DateTimeShortcuts.js +255 -0
  85. data/public/javascripts/RelatedObjectLookups.js +96 -0
  86. data/public/javascripts/SelectBox.js +111 -0
  87. data/public/javascripts/SelectFilter2.js +113 -0
  88. data/public/javascripts/actions.js +39 -0
  89. data/public/javascripts/calendar.js +143 -0
  90. data/public/javascripts/core.js +176 -0
  91. data/public/javascripts/dateparse.js +233 -0
  92. data/public/javascripts/getElementsBySelector.js +167 -0
  93. data/public/javascripts/i18n.js +33 -0
  94. data/public/javascripts/master.js +0 -0
  95. data/public/javascripts/ordering.js +137 -0
  96. data/public/javascripts/timeparse.js +94 -0
  97. data/public/javascripts/urlify.js +140 -0
  98. data/public/stylesheets/base.css +746 -0
  99. data/public/stylesheets/changelists.css +269 -0
  100. data/public/stylesheets/dashboard.css +24 -0
  101. data/public/stylesheets/forms.css +327 -0
  102. data/public/stylesheets/global.css +142 -0
  103. data/public/stylesheets/ie.css +51 -0
  104. data/public/stylesheets/layout.css +29 -0
  105. data/public/stylesheets/login.css +54 -0
  106. data/public/stylesheets/master.css +2 -0
  107. data/public/stylesheets/null.css +1 -0
  108. data/public/stylesheets/patch-iewin.css +8 -0
  109. data/public/stylesheets/rtl.css +206 -0
  110. data/public/stylesheets/widgets.css +506 -0
  111. data/schema/migrations/001_create_divisions_migration.rb +15 -0
  112. data/schema/migrations/002_create_drafts_migration.rb +21 -0
  113. data/schema/migrations/003_create_leagues_migration.rb +13 -0
  114. data/schema/migrations/004_create_players_migration.rb +23 -0
  115. data/schema/migrations/005_create_teams_migration.rb +18 -0
  116. data/spec/controllers/main_spec.rb +25 -0
  117. data/spec/models/activerecord/division.rb +8 -0
  118. data/spec/models/activerecord/draft.rb +16 -0
  119. data/spec/models/activerecord/league.rb +6 -0
  120. data/spec/models/activerecord/player.rb +10 -0
  121. data/spec/models/activerecord/team.rb +11 -0
  122. data/spec/models/datamapper/division.rb +12 -0
  123. data/spec/models/datamapper/draft.rb +18 -0
  124. data/spec/models/datamapper/league.rb +11 -0
  125. data/spec/models/datamapper/player.rb +21 -0
  126. data/spec/models/datamapper/team.rb +15 -0
  127. data/spec/requests/main_spec.rb +475 -0
  128. data/spec/spec_helper.rb +112 -0
  129. metadata +209 -0
@@ -0,0 +1,143 @@
1
+ /*
2
+ calendar.js - Calendar functions by Adrian Holovaty
3
+ */
4
+
5
+ function removeChildren(a) { // "a" is reference to an object
6
+ while (a.hasChildNodes()) a.removeChild(a.lastChild);
7
+ }
8
+
9
+ // quickElement(tagType, parentReference, textInChildNode, [, attribute, attributeValue ...]);
10
+ function quickElement() {
11
+ var obj = document.createElement(arguments[0]);
12
+ if (arguments[2] != '' && arguments[2] != null) {
13
+ var textNode = document.createTextNode(arguments[2]);
14
+ obj.appendChild(textNode);
15
+ }
16
+ var len = arguments.length;
17
+ for (var i = 3; i < len; i += 2) {
18
+ obj.setAttribute(arguments[i], arguments[i+1]);
19
+ }
20
+ arguments[1].appendChild(obj);
21
+ return obj;
22
+ }
23
+
24
+ // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions
25
+ var CalendarNamespace = {
26
+ monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
27
+ daysOfWeek: gettext('S M T W T F S').split(' '),
28
+ isLeapYear: function(year) {
29
+ return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
30
+ },
31
+ getDaysInMonth: function(month,year) {
32
+ var days;
33
+ if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) {
34
+ days = 31;
35
+ }
36
+ else if (month==4 || month==6 || month==9 || month==11) {
37
+ days = 30;
38
+ }
39
+ else if (month==2 && CalendarNamespace.isLeapYear(year)) {
40
+ days = 29;
41
+ }
42
+ else {
43
+ days = 28;
44
+ }
45
+ return days;
46
+ },
47
+ draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999
48
+ month = parseInt(month);
49
+ year = parseInt(year);
50
+ var calDiv = document.getElementById(div_id);
51
+ removeChildren(calDiv);
52
+ var calTable = document.createElement('table');
53
+ quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month-1] + ' ' + year);
54
+ var tableBody = quickElement('tbody', calTable);
55
+
56
+ // Draw days-of-week header
57
+ var tableRow = quickElement('tr', tableBody);
58
+ for (var i = 0; i < 7; i++) {
59
+ quickElement('th', tableRow, CalendarNamespace.daysOfWeek[i]);
60
+ }
61
+
62
+ var startingPos = new Date(year, month-1, 1).getDay();
63
+ var days = CalendarNamespace.getDaysInMonth(month, year);
64
+
65
+ // Draw blanks before first of month
66
+ tableRow = quickElement('tr', tableBody);
67
+ for (var i = 0; i < startingPos; i++) {
68
+ var _cell = quickElement('td', tableRow, ' ');
69
+ _cell.style.backgroundColor = '#f3f3f3';
70
+ }
71
+
72
+ // Draw days of month
73
+ var currentDay = 1;
74
+ for (var i = startingPos; currentDay <= days; i++) {
75
+ if (i%7 == 0 && currentDay != 1) {
76
+ tableRow = quickElement('tr', tableBody);
77
+ }
78
+ var cell = quickElement('td', tableRow, '');
79
+ quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));');
80
+ currentDay++;
81
+ }
82
+
83
+ // Draw blanks after end of month (optional, but makes for valid code)
84
+ while (tableRow.childNodes.length < 7) {
85
+ var _cell = quickElement('td', tableRow, ' ');
86
+ _cell.style.backgroundColor = '#f3f3f3';
87
+ }
88
+
89
+ calDiv.appendChild(calTable);
90
+ }
91
+ }
92
+
93
+ // Calendar -- A calendar instance
94
+ function Calendar(div_id, callback) {
95
+ // div_id (string) is the ID of the element in which the calendar will
96
+ // be displayed
97
+ // callback (string) is the name of a JavaScript function that will be
98
+ // called with the parameters (year, month, day) when a day in the
99
+ // calendar is clicked
100
+ this.div_id = div_id;
101
+ this.callback = callback;
102
+ this.today = new Date();
103
+ this.currentMonth = this.today.getMonth() + 1;
104
+ this.currentYear = this.today.getFullYear();
105
+ }
106
+ Calendar.prototype = {
107
+ drawCurrent: function() {
108
+ CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback);
109
+ },
110
+ drawDate: function(month, year) {
111
+ this.currentMonth = month;
112
+ this.currentYear = year;
113
+ this.drawCurrent();
114
+ },
115
+ drawPreviousMonth: function() {
116
+ if (this.currentMonth == 1) {
117
+ this.currentMonth = 12;
118
+ this.currentYear--;
119
+ }
120
+ else {
121
+ this.currentMonth--;
122
+ }
123
+ this.drawCurrent();
124
+ },
125
+ drawNextMonth: function() {
126
+ if (this.currentMonth == 12) {
127
+ this.currentMonth = 1;
128
+ this.currentYear++;
129
+ }
130
+ else {
131
+ this.currentMonth++;
132
+ }
133
+ this.drawCurrent();
134
+ },
135
+ drawPreviousYear: function() {
136
+ this.currentYear--;
137
+ this.drawCurrent();
138
+ },
139
+ drawNextYear: function() {
140
+ this.currentYear++;
141
+ this.drawCurrent();
142
+ }
143
+ }
@@ -0,0 +1,176 @@
1
+ // Core javascript helper functions
2
+
3
+ // basic browser identification & version
4
+ var isOpera = (navigator.userAgent.indexOf("Opera")>=0) && parseFloat(navigator.appVersion);
5
+ var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]);
6
+
7
+ // Cross-browser event handlers.
8
+ function addEvent(obj, evType, fn) {
9
+ if (obj.addEventListener) {
10
+ obj.addEventListener(evType, fn, false);
11
+ return true;
12
+ } else if (obj.attachEvent) {
13
+ var r = obj.attachEvent("on" + evType, fn);
14
+ return r;
15
+ } else {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ function removeEvent(obj, evType, fn) {
21
+ if (obj.removeEventListener) {
22
+ obj.removeEventListener(evType, fn, false);
23
+ return true;
24
+ } else if (obj.detachEvent) {
25
+ obj.detachEvent("on" + evType, fn);
26
+ return true;
27
+ } else {
28
+ return false;
29
+ }
30
+ }
31
+
32
+ // quickElement(tagType, parentReference, textInChildNode, [, attribute, attributeValue ...]);
33
+ function quickElement() {
34
+ var obj = document.createElement(arguments[0]);
35
+ if (arguments[2] != '' && arguments[2] != null) {
36
+ var textNode = document.createTextNode(arguments[2]);
37
+ obj.appendChild(textNode);
38
+ }
39
+ var len = arguments.length;
40
+ for (var i = 3; i < len; i += 2) {
41
+ obj.setAttribute(arguments[i], arguments[i+1]);
42
+ }
43
+ arguments[1].appendChild(obj);
44
+ return obj;
45
+ }
46
+
47
+ // ----------------------------------------------------------------------------
48
+ // Cross-browser xmlhttp object
49
+ // from http://jibbering.com/2002/4/httprequest.html
50
+ // ----------------------------------------------------------------------------
51
+ var xmlhttp;
52
+ /*@cc_on @*/
53
+ /*@if (@_jscript_version >= 5)
54
+ try {
55
+ xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
56
+ } catch (e) {
57
+ try {
58
+ xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
59
+ } catch (E) {
60
+ xmlhttp = false;
61
+ }
62
+ }
63
+ @else
64
+ xmlhttp = false;
65
+ @end @*/
66
+ if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
67
+ xmlhttp = new XMLHttpRequest();
68
+ }
69
+
70
+ // ----------------------------------------------------------------------------
71
+ // Find-position functions by PPK
72
+ // See http://www.quirksmode.org/js/findpos.html
73
+ // ----------------------------------------------------------------------------
74
+ function findPosX(obj) {
75
+ var curleft = 0;
76
+ if (obj.offsetParent) {
77
+ while (obj.offsetParent) {
78
+ curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft);
79
+ obj = obj.offsetParent;
80
+ }
81
+ // IE offsetParent does not include the top-level
82
+ if (isIE && obj.parentElement){
83
+ curleft += obj.offsetLeft - obj.scrollLeft;
84
+ }
85
+ } else if (obj.x) {
86
+ curleft += obj.x;
87
+ }
88
+ return curleft;
89
+ }
90
+
91
+ function findPosY(obj) {
92
+ var curtop = 0;
93
+ if (obj.offsetParent) {
94
+ while (obj.offsetParent) {
95
+ curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop);
96
+ obj = obj.offsetParent;
97
+ }
98
+ // IE offsetParent does not include the top-level
99
+ if (isIE && obj.parentElement){
100
+ curtop += obj.offsetTop - obj.scrollTop;
101
+ }
102
+ } else if (obj.y) {
103
+ curtop += obj.y;
104
+ }
105
+ return curtop;
106
+ }
107
+
108
+ //-----------------------------------------------------------------------------
109
+ // Date object extensions
110
+ // ----------------------------------------------------------------------------
111
+ Date.prototype.getCorrectYear = function() {
112
+ // Date.getYear() is unreliable --
113
+ // see http://www.quirksmode.org/js/introdate.html#year
114
+ var y = this.getYear() % 100;
115
+ return (y < 38) ? y + 2000 : y + 1900;
116
+ }
117
+
118
+ Date.prototype.getTwoDigitMonth = function() {
119
+ return (this.getMonth() < 9) ? '0' + (this.getMonth()+1) : (this.getMonth()+1);
120
+ }
121
+
122
+ Date.prototype.getTwoDigitDate = function() {
123
+ return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
124
+ }
125
+
126
+ Date.prototype.getTwoDigitHour = function() {
127
+ return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
128
+ }
129
+
130
+ Date.prototype.getTwoDigitMinute = function() {
131
+ return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
132
+ }
133
+
134
+ Date.prototype.getTwoDigitSecond = function() {
135
+ return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
136
+ }
137
+
138
+ Date.prototype.getISODate = function() {
139
+ return this.getCorrectYear() + '-' + this.getTwoDigitMonth() + '-' + this.getTwoDigitDate();
140
+ }
141
+
142
+ Date.prototype.getHourMinute = function() {
143
+ return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute();
144
+ }
145
+
146
+ Date.prototype.getHourMinuteSecond = function() {
147
+ return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();
148
+ }
149
+
150
+ // ----------------------------------------------------------------------------
151
+ // String object extensions
152
+ // ----------------------------------------------------------------------------
153
+ String.prototype.pad_left = function(pad_length, pad_string) {
154
+ var new_string = this;
155
+ for (var i = 0; new_string.length < pad_length; i++) {
156
+ new_string = pad_string + new_string;
157
+ }
158
+ return new_string;
159
+ }
160
+
161
+ // ----------------------------------------------------------------------------
162
+ // Get the computed style for and element
163
+ // ----------------------------------------------------------------------------
164
+ function getStyle(oElm, strCssRule){
165
+ var strValue = "";
166
+ if(document.defaultView && document.defaultView.getComputedStyle){
167
+ strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
168
+ }
169
+ else if(oElm.currentStyle){
170
+ strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
171
+ return p1.toUpperCase();
172
+ });
173
+ strValue = oElm.currentStyle[strCssRule];
174
+ }
175
+ return strValue;
176
+ }
@@ -0,0 +1,233 @@
1
+ /* 'Magic' date parsing, by Simon Willison (6th October 2003)
2
+ http://simon.incutio.com/archive/2003/10/06/betterDateInput
3
+ Adapted for 6newslawrence.com, 28th January 2004
4
+ */
5
+
6
+ /* Finds the index of the first occurence of item in the array, or -1 if not found */
7
+ if (typeof Array.prototype.indexOf == 'undefined') {
8
+ Array.prototype.indexOf = function(item) {
9
+ var len = this.length;
10
+ for (var i = 0; i < len; i++) {
11
+ if (this[i] == item) {
12
+ return i;
13
+ }
14
+ }
15
+ return -1;
16
+ };
17
+ }
18
+ /* Returns an array of items judged 'true' by the passed in test function */
19
+ if (typeof Array.prototype.filter == 'undefined') {
20
+ Array.prototype.filter = function(test) {
21
+ var matches = [];
22
+ var len = this.length;
23
+ for (var i = 0; i < len; i++) {
24
+ if (test(this[i])) {
25
+ matches[matches.length] = this[i];
26
+ }
27
+ }
28
+ return matches;
29
+ };
30
+ }
31
+
32
+ var monthNames = gettext("January February March April May June July August September October November December").split(" ");
33
+ var weekdayNames = gettext("Sunday Monday Tuesday Wednesday Thursday Friday Saturday").split(" ");
34
+
35
+ /* Takes a string, returns the index of the month matching that string, throws
36
+ an error if 0 or more than 1 matches
37
+ */
38
+ function parseMonth(month) {
39
+ var matches = monthNames.filter(function(item) {
40
+ return new RegExp("^" + month, "i").test(item);
41
+ });
42
+ if (matches.length == 0) {
43
+ throw new Error("Invalid month string");
44
+ }
45
+ if (matches.length > 1) {
46
+ throw new Error("Ambiguous month");
47
+ }
48
+ return monthNames.indexOf(matches[0]);
49
+ }
50
+ /* Same as parseMonth but for days of the week */
51
+ function parseWeekday(weekday) {
52
+ var matches = weekdayNames.filter(function(item) {
53
+ return new RegExp("^" + weekday, "i").test(item);
54
+ });
55
+ if (matches.length == 0) {
56
+ throw new Error("Invalid day string");
57
+ }
58
+ if (matches.length > 1) {
59
+ throw new Error("Ambiguous weekday");
60
+ }
61
+ return weekdayNames.indexOf(matches[0]);
62
+ }
63
+
64
+ /* Array of objects, each has 're', a regular expression and 'handler', a
65
+ function for creating a date from something that matches the regular
66
+ expression. Handlers may throw errors if string is unparseable.
67
+ */
68
+ var dateParsePatterns = [
69
+ // Today
70
+ { re: /^tod/i,
71
+ handler: function() {
72
+ return new Date();
73
+ }
74
+ },
75
+ // Tomorrow
76
+ { re: /^tom/i,
77
+ handler: function() {
78
+ var d = new Date();
79
+ d.setDate(d.getDate() + 1);
80
+ return d;
81
+ }
82
+ },
83
+ // Yesterday
84
+ { re: /^yes/i,
85
+ handler: function() {
86
+ var d = new Date();
87
+ d.setDate(d.getDate() - 1);
88
+ return d;
89
+ }
90
+ },
91
+ // 4th
92
+ { re: /^(\d{1,2})(st|nd|rd|th)?$/i,
93
+ handler: function(bits) {
94
+ var d = new Date();
95
+ d.setDate(parseInt(bits[1], 10));
96
+ return d;
97
+ }
98
+ },
99
+ // 4th Jan
100
+ { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+)$/i,
101
+ handler: function(bits) {
102
+ var d = new Date();
103
+ d.setDate(parseInt(bits[1], 10));
104
+ d.setMonth(parseMonth(bits[2]));
105
+ return d;
106
+ }
107
+ },
108
+ // 4th Jan 2003
109
+ { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+),? (\d{4})$/i,
110
+ handler: function(bits) {
111
+ var d = new Date();
112
+ d.setDate(parseInt(bits[1], 10));
113
+ d.setMonth(parseMonth(bits[2]));
114
+ d.setYear(bits[3]);
115
+ return d;
116
+ }
117
+ },
118
+ // Jan 4th
119
+ { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i,
120
+ handler: function(bits) {
121
+ var d = new Date();
122
+ d.setDate(parseInt(bits[2], 10));
123
+ d.setMonth(parseMonth(bits[1]));
124
+ return d;
125
+ }
126
+ },
127
+ // Jan 4th 2003
128
+ { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i,
129
+ handler: function(bits) {
130
+ var d = new Date();
131
+ d.setDate(parseInt(bits[2], 10));
132
+ d.setMonth(parseMonth(bits[1]));
133
+ d.setYear(bits[3]);
134
+ return d;
135
+ }
136
+ },
137
+ // next Tuesday - this is suspect due to weird meaning of "next"
138
+ { re: /^next (\w+)$/i,
139
+ handler: function(bits) {
140
+ var d = new Date();
141
+ var day = d.getDay();
142
+ var newDay = parseWeekday(bits[1]);
143
+ var addDays = newDay - day;
144
+ if (newDay <= day) {
145
+ addDays += 7;
146
+ }
147
+ d.setDate(d.getDate() + addDays);
148
+ return d;
149
+ }
150
+ },
151
+ // last Tuesday
152
+ { re: /^last (\w+)$/i,
153
+ handler: function(bits) {
154
+ throw new Error("Not yet implemented");
155
+ }
156
+ },
157
+ // mm/dd/yyyy (American style)
158
+ { re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/,
159
+ handler: function(bits) {
160
+ var d = new Date();
161
+ d.setYear(bits[3]);
162
+ d.setDate(parseInt(bits[2], 10));
163
+ d.setMonth(parseInt(bits[1], 10) - 1); // Because months indexed from 0
164
+ return d;
165
+ }
166
+ },
167
+ // yyyy-mm-dd (ISO style)
168
+ { re: /(\d{4})-(\d{1,2})-(\d{1,2})/,
169
+ handler: function(bits) {
170
+ var d = new Date();
171
+ d.setYear(parseInt(bits[1]));
172
+ d.setMonth(parseInt(bits[2], 10) - 1);
173
+ d.setDate(parseInt(bits[3], 10));
174
+ return d;
175
+ }
176
+ },
177
+ ];
178
+
179
+ function parseDateString(s) {
180
+ for (var i = 0; i < dateParsePatterns.length; i++) {
181
+ var re = dateParsePatterns[i].re;
182
+ var handler = dateParsePatterns[i].handler;
183
+ var bits = re.exec(s);
184
+ if (bits) {
185
+ return handler(bits);
186
+ }
187
+ }
188
+ throw new Error("Invalid date string");
189
+ }
190
+
191
+ function fmt00(x) {
192
+ // fmt00: Tags leading zero onto numbers 0 - 9.
193
+ // Particularly useful for displaying results from Date methods.
194
+ //
195
+ if (Math.abs(parseInt(x)) < 10){
196
+ x = "0"+ Math.abs(x);
197
+ }
198
+ return x;
199
+ }
200
+
201
+ function parseDateStringISO(s) {
202
+ try {
203
+ var d = parseDateString(s);
204
+ return d.getFullYear() + '-' + (fmt00(d.getMonth() + 1)) + '-' + fmt00(d.getDate())
205
+ }
206
+ catch (e) { return s; }
207
+ }
208
+ function magicDate(input) {
209
+ var messagespan = input.id + 'Msg';
210
+ try {
211
+ var d = parseDateString(input.value);
212
+ input.value = d.getFullYear() + '-' + (fmt00(d.getMonth() + 1)) + '-' +
213
+ fmt00(d.getDate());
214
+ input.className = '';
215
+ // Human readable date
216
+ if (document.getElementById(messagespan)) {
217
+ document.getElementById(messagespan).firstChild.nodeValue = d.toDateString();
218
+ document.getElementById(messagespan).className = 'normal';
219
+ }
220
+ }
221
+ catch (e) {
222
+ input.className = 'error';
223
+ var message = e.message;
224
+ // Fix for IE6 bug
225
+ if (message.indexOf('is null or not an object') > -1) {
226
+ message = 'Invalid date string';
227
+ }
228
+ if (document.getElementById(messagespan)) {
229
+ document.getElementById(messagespan).firstChild.nodeValue = message;
230
+ document.getElementById(messagespan).className = 'error';
231
+ }
232
+ }
233
+ }