liquid_feedback_frontend

annotate static/gregor.js/gregor.js @ 413:336476245f3f

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

Impressum / About Us