liquid_feedback_frontend

view static/gregor.js/gregor.js @ 54:2cb85f9210b8

Changed version string to beta16
author jbe
date Thu Apr 15 21:26:21 2010 +0200 (2010-04-15)
parents 77d58efe99fd
children 77260f05fd4b
line source
1 //
2 // Copyright (c) 2009 Public Software Group e. V., Berlin
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
24 //
25 // All date calculations are based on the gregorian calender, also for
26 // dates before 1582 (before the gegorian calendar was introduced).
27 // The supported range is from January 1st 0001 up to December 31st 9999.
28 //
29 // gregor_daycount({year: <year>, month: <month>, day: <day>}) returns
30 // the number of days between the given date and January 1st 0001 (greg.).
31 //
32 // gregor_completeDate({year: <year>, month: <month>, day: <day>}) returns
33 // a structure (an object) with the following properties:
34 // - daycount (days since January 1st 0001, see gregor_daycount)
35 // - year (with century)
36 // - month (from 1 to 12)
37 // - day (from 1 to 28, 29, 30 or 31)
38 // - iso_string (string with format YYYY-MM-DD)
39 // - us_weekday (from 0 for Sunday to 6 for Monday)
40 // - iso_weekday (from 0 for Monday to 6 for Sunday)
41 // - iso_weekyear (Year containing greater part of week st. w. Monday)
42 // - iso_week (from 1 to 52 or 53)
43 // - us_week (from 1 to 53 or 54)
44 //
45 // The structure (the object) passed as parameter to gregor_daycount or
46 // gregor_completeDate may describe a date in the following ways:
47 // - daycount
48 // - year, month, day
49 // - year, us_week, us_weekday
50 // - year, iso_week, iso_weekday
51 // - iso_weekyear, iso_week, iso_weekday
52 //
53 // gregor_sheet({...}) returns a calendar sheet as DOM object. The
54 // structure (the object) passed to the function as an argument is altered
55 // by the function and used to store state variables. Initially it can
56 // contain the following fields:
57 // - year (year to show, defaults to todays year)
58 // - month (month to show, defaults to todays month)
59 // - today (structure describing a day, e.g. year, month, day)
60 // - selected (structure describing a day, e.g. year, month, day)
61 // - navigation ("enabled", "disabled", "hidden", default "enabled")
62 // - week_mode ("iso" or "us", defaults to "iso")
63 // - week_numbers ("left", "right" or null, defaults to null)
64 // - month_names (e.g. ["January", "Feburary", ...])
65 // - weekday_names (e.g. ["Mon", "Tue", ...] or ["Sun", "Mon", ...])
66 // - day_callback (function to render a cell)
67 // - select_callback (function to be called, when a date was selected)
68 // - element (for internal use only)
69 // If "today" is undefined, it is automatically intitialized with the
70 // current clients date. If "selected" is undefined or null, no date is
71 // be initially selected. It is mandatory to provide month_names and
72 // weekday_names.
73 //
74 // gregor_addGui({...}) alters a referenced input field in a way that
75 // focussing on it causes a calendar being shown at its right side, where a
76 // date can be selected. The structure (the object) passed to this function
77 // is only evaluated once, and never modified. All options except "element"
78 // of the gregor_sheet({...}) function may be used as options to
79 // gregor_addGui({...}) as well. In addition an "element_id" must be
80 // provided as argument, containing the id of a text input field. The
81 // behaviour caused by the options "selected" and "select_callback" are
82 // slightly different: If "selected" === undefined, then the current value
83 // of the text field referenced by "element_id" will be parsed and used as
84 // date selection. If "selected" === null, then no date will be initially
85 // selected, and the text field will be cleared. The "select_callback"
86 // function is always called once with the pre-selected date (or with null,
87 // if no date is initially selected). Whenever the selected date is changed
88 // or unselected later, the callback function is called again with the new
89 // date (or with null, in case of deselection).
90 //
91 // EXAMPLE:
92 //
93 // <input type="text" id="test_field" name="test_field" value=""/>
94 // <script type="text/javascript">
95 // gregor_addGui({
96 // element_id: 'test_field',
97 // month_names: [
98 // "January", "February", "March", "April", "May", "June",
99 // "July", "August", "September", "October", "November", "December"
100 // ],
101 // weekday_names: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
102 // week_numbers: "left"
103 // });
104 // </script>
105 //
110 // Internal constants and helper functions for date calculation
113 gregor_c1 = 365; // days of a non-leap year
114 gregor_c4 = 4 * gregor_c1 + 1; // days of a full 4 year cycle
115 gregor_c100 = 25 * gregor_c4 - 1; // days of a full 100 year cycle
116 gregor_c400 = 4 * gregor_c100 + 1; // days of a full 400 year cycle
118 gregor_normalMonthOffsets = [
119 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
120 ];
122 function gregor_getMonthOffset(year, month) {
123 if (
124 (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) &&
125 month > 2
126 ) return gregor_normalMonthOffsets[month-1] + 1;
127 else return gregor_normalMonthOffsets[month-1];
128 }
130 function gregor_formatInteger(int, digits) {
131 var result = int.toFixed();
132 if (digits != null) {
133 while (result.length < digits) result = "0" + result;
134 }
135 return result;
136 }
140 // Calculate days since January 1st 0001 (Gegorian) for a given date
143 function gregor_daycount(obj) {
144 if (
145 obj.daycount >= 0 && obj.daycount <= 3652058 && obj.daycount % 1 == 0
146 ) {
147 return obj.daycount;
148 } else if (
149 obj.year >= 1 && obj.year <= 9999 && obj.year % 1 == 0 &&
150 obj.month >= 1 && obj.month <= 12 && obj.month % 1 == 0 &&
151 obj.day >= 0 && obj.day <= 31 && obj.day % 1 == 0
152 ) {
153 var n400 = Math.floor((obj.year-1) / 400);
154 var r400 = (obj.year-1) % 400;
155 var n100 = Math.floor(r400 / 100);
156 var r100 = r400 % 100;
157 var n4 = Math.floor(r100 / 4);
158 var n1 = r100 % 4;
159 return (
160 gregor_c400 * n400 +
161 gregor_c100 * n100 +
162 gregor_c4 * n4 +
163 gregor_c1 * n1 +
164 gregor_getMonthOffset(obj.year, obj.month) + (obj.day - 1)
165 );
166 } else if (
167 (
168 (
169 obj.year >= 1 && obj.year <= 9999 &&
170 obj.year % 1 == 0 && obj.iso_weekyear == null
171 ) || (
172 obj.iso_weekyear >= 1 && obj.iso_weekyear <= 9999 &&
173 obj.iso_weekyear % 1 == 0 && obj.year == null
174 )
175 ) &&
176 obj.iso_week >= 0 && obj.iso_week <= 53 && obj.iso_week % 1 == 0 &&
177 obj.iso_weekday >= 0 && obj.iso_weekday <= 6 &&
178 obj.iso_weekday % 1 == 0
179 ) {
180 var jan4th = gregor_daycount({
181 year: (obj.year != null) ? obj.year : obj.iso_weekyear,
182 month: 1,
183 day: 4
184 });
185 var monday0 = jan4th - (jan4th % 7) - 7; // monday of week 0
186 return monday0 + 7 * obj.iso_week + obj.iso_weekday;
187 } else if (
188 obj.year >= 1 && obj.year <= 9999 && obj.year % 1 == 0 &&
189 obj.us_week >= 0 && obj.us_week <= 54 && obj.us_week % 1 == 0 &&
190 obj.us_weekday >= 0 && obj.us_weekday <= 6 && obj.us_weekday % 1 == 0
191 ) {
192 var jan1st = gregor_daycount({
193 year: obj.year,
194 month: 1,
195 day: 1
196 });
197 var sunday0 = jan1st - ((jan1st+1) % 7) - 7; // sunday of week 0
198 return sunday0 + 7 * obj.us_week + obj.us_weekday;
199 }
200 }
204 // Calculate all calendar related numbers for a given date
207 function gregor_completeDate(obj) {
208 if (
209 obj.daycount >= 0 && obj.daycount <= 3652058 && obj.daycount % 1 == 0
210 ) {
211 var daycount = obj.daycount;
212 var n400 = Math.floor(daycount / gregor_c400);
213 var r400 = daycount % gregor_c400;
214 var n100 = Math.floor(r400 / gregor_c100);
215 var r100 = r400 % gregor_c100;
216 if (n100 == 4) { n100 = 3; r100 = gregor_c100; }
217 var n4 = Math.floor(r100 / gregor_c4);
218 var r4 = r100 % gregor_c4;
219 var n1 = Math.floor(r4 / gregor_c1);
220 var r1 = r4 % gregor_c1;
221 if (n1 == 4) { n1 = 3; r1 = gregor_c1; }
222 var year = 1 + 400 * n400 + 100 * n100 + 4 * n4 + n1;
223 var month = 1 + Math.floor(r1 / 31);
224 var monthOffset = gregor_getMonthOffset(year, month);
225 if (month < 12) {
226 var nextMonthOffset = gregor_getMonthOffset(year, month + 1);
227 if (r1 >= nextMonthOffset) {
228 month++;
229 monthOffset = nextMonthOffset;
230 }
231 }
232 var day = 1 + r1 - monthOffset;
233 var iso_string = ("" +
234 gregor_formatInteger(year, 4) + "-" +
235 gregor_formatInteger(month, 2) + "-" +
236 gregor_formatInteger(day, 2)
237 );
238 var us_weekday = (daycount+1) % 7;
239 var iso_weekday = daycount % 7;
240 var iso_weekyear = year;
241 if (
242 month == 1 && (
243 (day == 3 && iso_weekday == 6) ||
244 (day == 2 && iso_weekday >= 5) ||
245 (day == 1 && iso_weekday >= 4)
246 )
247 ) iso_weekyear--;
248 else if (
249 month == 12 && (
250 (day == 29 && iso_weekday == 0) ||
251 (day == 30 && iso_weekday <= 1) ||
252 (day == 31 && iso_weekday <= 2)
253 )
254 ) iso_weekyear++;
255 var jan4th = gregor_daycount({year: iso_weekyear, month: 1, day: 4});
256 var monday0 = jan4th - (jan4th % 7) - 7; // monday of week 0
257 var iso_week = Math.floor((daycount - monday0) / 7);
258 var jan1st = gregor_daycount({year: year, month: 1, day: 1});
259 var sunday0 = jan1st - ((jan1st+1) % 7) - 7; // sunday of week 0
260 var us_week = Math.floor((daycount - sunday0) / 7);
261 return {
262 daycount: daycount,
263 year: year,
264 month: month,
265 day: day,
266 iso_string: iso_string,
267 us_weekday: (daycount+1) % 7, // 0 = Sunday
268 iso_weekday: daycount % 7, // 0 = Monday
269 iso_weekyear: iso_weekyear,
270 iso_week: iso_week,
271 us_week: us_week
272 };
273 } else if (obj.daycount == null) {
274 var daycount = gregor_daycount(obj);
275 if (daycount != null) {
276 return gregor_completeDate({daycount: gregor_daycount(obj)});
277 }
278 }
279 }
283 // Test gregor_daycount and gregor_completeDate for consistency
284 // (Debugging only)
287 function gregor_test() {
288 for (i=650000; i<900000; i++) {
289 var obj = gregor_completeDate({daycount: i});
290 var j;
291 j = gregor_daycount({
292 year: obj.year,
293 month: obj.month,
294 day: obj.day
295 });
296 if (i != j) { alert("ERROR"); return; }
297 j = gregor_daycount({
298 iso_weekyear: obj.iso_weekyear,
299 iso_week: obj.iso_week,
300 iso_weekday: obj.iso_weekday
301 });
302 if (i != j) { alert("ERROR"); return; }
303 j = gregor_daycount({
304 year: obj.year,
305 iso_week:
306 (obj.iso_weekyear == obj.year + 1) ? 53 :
307 (obj.iso_weekyear == obj.year - 1) ? 0 :
308 obj.iso_week,
309 iso_weekday: obj.iso_weekday
310 });
311 if (i != j) { alert("ERROR"); return; }
312 j = gregor_daycount({
313 year: obj.year,
314 us_week: obj.us_week,
315 us_weekday: obj.us_weekday
316 });
317 if (i != j) { alert("ERROR"); return; }
318 }
319 alert("SUCCESS");
320 }
324 // Graphical calendar
327 gregor_iso_weekday_css = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
329 function gregor_sheet(args) {
331 // setting args.today and args.selected
332 if (args.today === undefined) {
333 var js_date = new Date();
334 args.today = gregor_completeDate({
335 year: js_date.getFullYear(),
336 month: js_date.getMonth() + 1,
337 day: js_date.getDate()
338 });
339 } else if (args.today != null) {
340 args.today = gregor_completeDate(args.today);
341 }
342 if (args.selected == "today") {
343 args.selected = args.today;
344 } else if (args.selected != null) {
345 args.selected = gregor_completeDate(args.selected);
346 }
348 // setting args.year and args.month
349 if (args.year == null) {
350 if (args.selected != null) args.year = args.selected.year;
351 else args.year = args.today.year;
352 }
353 if (args.month == null) {
354 if (args.selected != null) args.month = args.selected.month;
355 else args.month = args.today.month;
356 }
358 // setting first_day
359 var first_day = gregor_completeDate({
360 year: args.year,
361 month: args.month,
362 day: 1
363 });
364 if (first_day == null) return;
366 // checking args.navigation, args.week_mode and args.week_numbers
367 if (args.navigation == null) args.navigation = "enabled";
368 else if (
369 args.navigation != "enabled" &&
370 args.navigation != "disabled" &&
371 args.navigation != "hidden"
372 ) return;
373 if (args.week_mode == null) args.week_mode = "iso";
374 else if (args.week_mode != "iso" && args.week_mode != "us") return;
375 if (
376 args.week_numbers != null &&
377 args.week_numbers != "left" &&
378 args.week_numbers != "right"
379 ) return;
381 // checking args.month.names and args.weekday_names
382 if (args.month_names.length != 12) return;
383 if (args.weekday_names.length != 7) return;
385 // calculating number of days in month
386 var count;
387 if (args.year < 9999 || args.month < 12) {
388 count = gregor_daycount({
389 year: (args.month == 12) ? (args.year + 1) : args.year,
390 month: (args.month == 12) ? 1 : (args.month + 1),
391 day: 1
392 }) - first_day.daycount;
393 } else {
394 // workaround for year 9999
395 count = 31;
396 }
398 // locale variables for UI construction
399 var table, row, cell, element;
401 // take table element from args.element,
402 // if neccessary create and store it
403 if (args.element == null) {
404 table = document.createElement("table");
405 args.element = table;
406 } else {
407 table = args.element;
408 while (table.firstChild) table.removeChild(table.firstChild);
409 }
411 // set CSS class of table according to args.week_numbers
412 if (args.week_numbers == "left") {
413 table.className = "gregor_sheet gregor_weeks_left";
414 } else if (args.week_numbers == "right") {
415 table.className = "gregor_sheet gregor_weeks_right";
416 } else {
417 table.className = "gregor_sheet gregor_weeks_none";
418 }
420 // begin of table head
421 var thead = document.createElement("thead");
423 // navigation
424 if (args.navigation != "hidden") {
426 // UI head row containing the year
427 row = document.createElement("tr");
428 row.className = "gregor_year_row";
429 cell = document.createElement("th");
430 cell.className = "gregor_year";
431 cell.colSpan = args.week_numbers ? 8 : 7;
432 if (args.navigation == "enabled") {
433 element = document.createElement("a");
434 element.className = "gregor_turn gregor_turn_left";
435 element.style.cssFloat = "left";
436 element.style.styleFloat = "left";
437 element.href = "#";
438 element.onclick = function() {
439 if (args.year > 1) args.year--;
440 gregor_sheet(args);
441 return false;
442 }
443 element.ondblclick = element.onclick;
444 element.appendChild(document.createTextNode("<<"));
445 cell.appendChild(element);
446 element = document.createElement("a");
447 element.className = "gregor_turn gregor_turn_right";
448 element.style.cssFloat = "right";
449 element.style.styleFloat = "right";
450 element.href = "#";
451 element.onclick = function() {
452 if (args.year < 9999) args.year++;
453 gregor_sheet(args);
454 return false;
455 }
456 element.ondblclick = element.onclick;
457 element.appendChild(document.createTextNode(">>"));
458 cell.appendChild(element);
459 }
460 cell.appendChild(document.createTextNode(first_day.year));
461 row.appendChild(cell);
462 thead.appendChild(row);
464 // UI head row containing the month
465 row = document.createElement("tr");
466 row.className = "gregor_month_row";
467 cell = document.createElement("th");
468 cell.className = "gregor_month";
469 cell.colSpan = args.week_numbers ? 8 : 7;
470 if (args.navigation == "enabled") {
471 element = document.createElement("a");
472 element.className = "gregor_turn gregor_turn_left";
473 element.style.cssFloat = "left";
474 element.style.styleFloat = "left";
475 element.href = "#";
476 element.onclick = function() {
477 if (args.year > 1 || args.month > 1) {
478 args.month--;
479 if (args.month < 1) {
480 args.month = 12;
481 args.year--;
482 }
483 }
484 gregor_sheet(args);
485 return false;
486 }
487 element.ondblclick = element.onclick;
488 element.appendChild(document.createTextNode("<<"));
489 cell.appendChild(element);
490 element = document.createElement("a");
491 element.className = "gregor_turn gregor_turn_right";
492 element.style.cssFloat = "right";
493 element.style.styleFloat = "right";
494 element.href = "#";
495 element.onclick = function() {
496 if (args.year < 9999 || args.month < 12) {
497 args.month++;
498 if (args.month > 12) {
499 args.month = 1;
500 args.year++;
501 }
502 }
503 gregor_sheet(args);
504 return false;
505 }
506 element.ondblclick = element.onclick;
507 element.appendChild(document.createTextNode(">>"));
508 cell.appendChild(element);
509 }
510 cell.appendChild(document.createTextNode(
511 args.month_names[first_day.month-1]
512 ));
513 row.appendChild(cell);
514 thead.appendChild(row);
516 // end of navigation
517 }
519 // UI weekday row
520 row = document.createElement("tr");
521 row.className = "gregor_weekday_row";
522 if (args.week_numbers == "left") {
523 cell = document.createElement("th");
524 cell.className = "gregor_corner";
525 row.appendChild(cell);
526 }
527 for (var i=0; i<7; i++) {
528 cell = document.createElement("th");
529 cell.className = (
530 "gregor_weekday gregor_" +
531 gregor_iso_weekday_css[(args.week_mode == "us") ? ((i+6)%7) : i]
532 );
533 cell.appendChild(document.createTextNode(args.weekday_names[i]));
534 row.appendChild(cell);
535 }
536 if (args.week_numbers == "right") {
537 cell = document.createElement("th");
538 cell.className = "gregor_corner";
539 row.appendChild(cell);
540 }
541 thead.appendChild(row);
543 // end of table head and begin of table body
544 table.appendChild(thead);
545 var tbody = document.createElement("tbody");
547 // definition of insert_week function
548 var week = (
549 (args.week_mode == "us") ? first_day.us_week : first_day.iso_week
550 );
551 insert_week = function() {
552 cell = document.createElement("th");
553 cell.className = "gregor_week";
554 cell.appendChild(document.createTextNode(
555 (week < 10) ? ("0" + week) : week)
556 );
557 week++;
558 if (
559 args.week_mode == "iso" && (
560 (
561 args.month == 1 && week > 52
562 ) || (
563 args.month == 12 && week == 53 && (
564 first_day.iso_weekday == 0 ||
565 first_day.iso_weekday == 5 ||
566 first_day.iso_weekday == 6
567 )
568 )
569 )
570 ) week = 1;
571 row.appendChild(cell);
572 }
574 // output data fields
575 row = document.createElement("tr");
576 if (args.week_numbers == "left") insert_week();
577 var filler_count = (
578 (args.week_mode == "us") ? first_day.us_weekday : first_day.iso_weekday
579 );
580 for (var i=0; i<filler_count; i++) {
581 cell = document.createElement("td");
582 cell.className = "gregor_empty";
583 row.appendChild(cell);
584 }
585 for (var i=0; i<count; i++) {
586 var date = gregor_completeDate({daycount: first_day.daycount + i});
587 if (row == null) {
588 row = document.createElement("tr");
589 if (args.week_numbers == "left") insert_week();
590 }
591 cell = document.createElement("td");
592 var cssClass = (
593 "gregor_day gregor_" + gregor_iso_weekday_css[date.iso_weekday]
594 );
595 if (args.today != null && date.daycount == args.today.daycount) {
596 cssClass += " gregor_today";
597 }
598 if (args.selected != null && date.daycount == args.selected.daycount) {
599 cssClass += " gregor_selected";
600 }
601 cell.className = cssClass;
602 if (args.day_callback) {
603 args.day_callback(cell, date);
604 } else {
605 element = document.createElement("a");
606 element.href = "#";
607 var generate_onclick = function(date) {
608 return function() {
609 args.selected = date;
610 gregor_sheet(args);
611 if (args.select_callback != null) {
612 args.select_callback(date);
613 }
614 return false;
615 }
616 }
617 element.onclick = generate_onclick(date);
618 element.ondblclick = element.onclick;
619 element.appendChild(document.createTextNode(first_day.day + i));
620 cell.appendChild(element);
621 }
622 row.appendChild(cell);
623 if (row.childNodes.length == ((args.week_numbers == "left") ? 8 : 7)) {
624 if (args.week_numbers == "right") insert_week();
625 tbody.appendChild(row);
626 row = null;
627 }
628 }
629 if (row != null) {
630 while (row.childNodes.length < ((args.week_numbers == "left") ? 8 : 7)) {
631 cell = document.createElement("td");
632 cell.className = "gregor_empty";
633 row.appendChild(cell);
634 }
635 if (args.week_numbers == "right") insert_week();
636 tbody.appendChild(row);
637 }
639 // end of table body
640 table.appendChild(tbody);
642 // return table
643 return table;
644 }
648 // Rich form field support
651 function gregor_getAbsoluteLeft(elem) {
652 var result = 0;
653 while (elem && elem.style.position != "static") {
654 result += elem.offsetLeft;
655 elem = elem.offsetParent;
656 }
657 return result;
658 }
660 function gregor_getAbsoluteTop(elem) {
661 var result = 0;
662 while (elem && elem.style.position != "static") {
663 result += elem.offsetTop;
664 elem = elem.offsetParent;
665 }
666 return result;
667 }
669 function gregor_formatDate(format, date) {
670 if (date == null) return "";
671 var result = format;
672 result = result.replace(/Y+/, function(s) {
673 if (s.length == 2) return gregor_formatInteger(date.year % 100, 2);
674 else return gregor_formatInteger(date.year, s.length);
675 });
676 result = result.replace(/M+/, function(s) {
677 return gregor_formatInteger(date.month, s.length);
678 });
679 result = result.replace(/D+/, function(s) {
680 return gregor_formatInteger(date.day, s.length);
681 });
682 return result;
683 }
685 function gregor_map2digitYear(y2, maxYear) {
686 var guess = Math.floor(maxYear / 100) * 100 + y2;
687 if (guess <= maxYear) return guess;
688 else return guess - 100;
689 }
691 function gregor_parseDate(format, string, terminated, maxYear) {
692 var numericParts, formatParts;
693 numericParts = string.match(/^\s*([0-9]{4})-([0-9]{2})-([0-9]{2})\s*$/);
694 if (numericParts != null) {
695 return gregor_completeDate({
696 year: numericParts[1],
697 month: numericParts[2],
698 day: numericParts[3]
699 });
700 }
701 numericParts = string.match(/[0-9]+/g);
702 if (numericParts == null) return null;
703 formatParts = format.match(/[YMD]+/g);
704 if (numericParts.length != formatParts.length) return null;
705 if (
706 !terminated && (
707 numericParts[numericParts.length-1].length <
708 formatParts[formatParts.length-1].length
709 )
710 ) return null;
711 var year, month, day;
712 for (var i=0; i<numericParts.length; i++) {
713 var numericPart = numericParts[i];
714 var formatPart = formatParts[i];
715 if (formatPart.match(/^Y+$/)) {
716 if (numericPart.length == 2 && maxYear != null) {
717 year = gregor_map2digitYear(parseInt(numericPart, 10), maxYear);
718 } else if (numericPart.length > 2) {
719 year = parseInt(numericPart, 10);
720 }
721 } else if (formatPart.match(/^M+$/)) {
722 month = parseInt(numericPart, 10);
723 } else if (formatPart.match(/^D+$/)) {
724 day = parseInt(numericPart, 10);
725 } else {
726 //alert("Not implemented.");
727 return null;
728 }
729 }
730 return gregor_completeDate({year: year, month: month, day: day});
731 }
733 function gregor_addGui(args) {
735 // copy argument structure
736 var state = {};
737 for (key in args) state[key] = args[key];
739 // unset state.element, which should never be set anyway
740 state.element = null;
742 // save original values of "year" and "month" options
743 var original_year = state.year;
744 var original_month = state.month;
746 // get text field element
747 var element = document.getElementById(state.element_id);
748 state.element_id = null;
750 // setup state.today, state.selected and state.format options
751 if (state.today === undefined) {
752 var js_date = new Date();
753 state.today = gregor_completeDate({
754 year: js_date.getFullYear(),
755 month: js_date.getMonth() + 1,
756 day: js_date.getDate()
757 });
758 } else if (state.today != null) {
759 state.today = gregor_completeDate(args.today);
760 }
761 if (state.selected == "today") {
762 state.selected = state.today;
763 } else if (args.selected != null) {
764 state.selected = gregor_completeDate(state.selected);
765 }
766 if (state.format == null) state.format = "YYYY-MM-DD";
768 // using state.future to calculate maxYear (for 2 digit year conversions)
769 var maxYear = (state.today == null) ? null : (
770 state.today.year +
771 ((state.future == null) ? 12 : state.future)
772 );
774 // hook into state.select_callback
775 var select_callback = state.select_callback;
776 state.select_callback = function(date) {
777 element.value = gregor_formatDate(state.format, date);
778 if (select_callback) select_callback(date);
779 };
781 // function to parse text field and update calendar sheet state
782 var updateSheet = function(terminated) {
783 var date = gregor_parseDate(
784 state.format, element.value, terminated, maxYear
785 );
786 if (date) {
787 state.year = null;
788 state.month = null;
789 }
790 state.selected = date;
791 gregor_sheet(state);
792 };
794 // Initial synchronization
795 if (state.selected === undefined) updateSheet(true);
796 element.value = gregor_formatDate(state.format, state.selected);
797 if (select_callback) select_callback(state.selected);
799 // variables storing popup status
800 var visible = false;
801 var focus = false;
802 var protection = false;
804 // event handlers for text field
805 element.onfocus = function() {
806 focus = true;
807 if (!visible) {
808 state.year = original_year;
809 state.month = original_month;
810 gregor_sheet(state);
811 state.element.style.position = "absolute";
812 state.element.style.top = gregor_getAbsoluteTop(element) + element.offsetHeight;
813 state.element.style.left = gregor_getAbsoluteLeft(element);
814 state.element.onmousedown = function() {
815 protection = true;
816 };
817 state.element.onmouseup = function() {
818 protection = false;
819 element.focus();
820 };
821 state.element.onmouseout = state.element.onmouseup;
822 element.parentNode.appendChild(state.element);
823 visible = true;
824 }
825 };
826 element.onblur = function() {
827 focus = false;
828 window.setTimeout(function() {
829 if (visible && !focus && !protection) {
830 updateSheet(true);
831 element.value = gregor_formatDate(state.format, state.selected);
832 if (select_callback) select_callback(state.selected);
833 state.element.parentNode.removeChild(state.element);
834 visible = false;
835 protection = false;
836 }
837 }, 1);
838 };
839 element.onkeyup = function() {
840 updateSheet(false);
841 if (select_callback) select_callback(state.selected);
842 };
844 }

Impressum / About Us