Changeset 143867 in webkit
- Timestamp:
- Feb 24, 2013 8:42:41 AM (11 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r143865 r143867 1 2013-02-24 Keishi Hattori <keishi@webkit.org> 2 3 Add methods to date types for new calendar picker 4 https://bugs.webkit.org/show_bug.cgi?id=110454 5 6 Reviewed by Kent Tamura. 7 8 * platform/chromium/fast/forms/calendar-picker/calendar-picker-date-types-expected.txt: Added. 9 * platform/chromium/fast/forms/calendar-picker/calendar-picker-date-types.html: Added. Unit tests for date types. 10 1 11 2013-02-24 Hajime Morrita <morrita@google.com> 2 12 -
trunk/Source/WebCore/ChangeLog
r143865 r143867 1 2013-02-24 Keishi Hattori <keishi@webkit.org> 2 3 Add methods to date types for new calendar picker 4 https://bugs.webkit.org/show_bug.cgi?id=110454 5 6 Reviewed by Kent Tamura. 7 8 Adding some methods to date types as part of the calendar picker redesign (Bug 109439). 9 10 Test: platform/chromium/fast/forms/calendar-picker/calendar-picker-date-types.html 11 12 * Resources/pagepopups/calendarPicker.js: 13 (createUTCDate): 14 (DateType): Base class for Day, Week and Month. 15 (Day): Simplified constructor to only accept year, month, date. 16 (Day.createFromValue): Creates a new Day from a value. 17 (Day.createFromDate): Throw an error if the given date is invalid. 18 (Day.createFromDay): 19 (Day.prototype.equals): Accept non Day objects. 20 (Day.prototype.previous): Modified to take an offset value. 21 (Day.prototype.next): Ditto. 22 (Day.prototype.firstDay): Returns the first day in the range. For Day's case, returns itself. 23 (Day.prototype.middleDay): Returns the middle day in the range. For Day's case, returns itself. 24 (Day.prototype.lastDay): Returns the middle day in the range. For Day's case, returns itself. 25 (Day.prototype.valueOf): 26 (Day.prototype.weekDay): Returns the week day. 27 (Week): Simplified constructor to only accept year, month, date. 28 (Week.createFromValue): 29 (Week.createFromDate): 30 (Week.createFromDay): 31 (Week.weekOneStartDateForYear): 32 (Week.weekOneStartDayForYear): 33 (Week._numberOfWeeksSinceDate): 34 (Week.prototype.equals): 35 (Week.prototype.previous): 36 (Week.prototype.next): 37 (Week.prototype.firstDay): Returns the first day in the week. 38 (Week.prototype.middleDay): Returns the the day for Thursday. 39 (Week.prototype.lastDay): Returns the last day in the week. 40 (Week.prototype.valueOf): 41 (Month): 42 (Month.createFromValue): 43 (Month.createFromDate): 44 (Month.createFromDay): 45 (Month.prototype.containsDay): 46 (Month.prototype.equals): 47 (Month.prototype.previous): 48 (Month.prototype.next): 49 (Month.prototype.firstDay): Returns the first day in the month. 50 (Month.prototype.middleDay): Returns the middle day in the month. 51 (Month.prototype.lastDay): Returns the last day in the month. 52 (Month.prototype.valueOf): 53 (Month.prototype.toLocaleString): Moved location. 54 (Month.prototype.toShortLocaleString): Returns the month string in short format. 55 (CalendarPicker): Use createFromValue. 56 (YearMonthController.prototype.setMonth): Ditto. 57 (YearMonthController.prototype.moveRelatively): Ditto. 58 1 59 2013-02-24 Hajime Morrita <morrita@google.com> 2 60 -
trunk/Source/WebCore/Resources/pagepopups/calendarPicker.js
r143723 r143867 112 112 113 113 /** 114 * @enum {number} 115 */ 116 var WeekDay = { 117 Sunday: 0, 118 Monday: 1, 119 Tuesday: 2, 120 Wednesday: 3, 121 Thursday: 4, 122 Friday: 5, 123 Saturday: 6 124 }; 125 126 /** 114 127 * @const 115 128 * @type {number} … … 144 157 } 145 158 146 /**147 * @return {!string}148 */149 Month.prototype.toLocaleString = function() {150 if (isNaN(this.year) || isNaN(this.year))151 return "Invalid Month";152 if (getLanguage() == "ja")153 return "" + this.year + "年" + formatJapaneseImperialEra(this.year, this.month) + " " + (this.month + 1) + "月";154 return window.pagePopupController.formatMonth(this.year, this.month);155 };156 157 159 function createUTCDate(year, month, date) { 158 160 var newDate = new Date(0); … … 161 163 newDate.setUTCDate(date); 162 164 return newDate; 163 } ;165 } 164 166 165 167 /** … … 178 180 179 181 /** 182 * @const 183 * @type {number} 184 */ 185 var DaysPerWeek = 7; 186 187 /** 188 * @const 189 * @type {number} 190 */ 191 var MonthsPerYear = 12; 192 193 /** 194 * @const 195 * @type {number} 196 */ 197 var MillisecondsPerDay = 24 * 60 * 60 * 1000; 198 199 /** 200 * @const 201 * @type {number} 202 */ 203 var MillisecondsPerWeek = DaysPerWeek * MillisecondsPerDay; 204 205 /** 180 206 * @constructor 181 * @param {!number|Day} valueOrDayOrYear 182 * @param {!number=} month 183 * @param {!number=} date 184 */ 185 function Day(valueOrDayOrYear, month, date) { 186 var dateObject; 187 if (arguments.length == 3) 188 dateObject = createUTCDate(valueOrDayOrYear, month, date); 189 else if (valueOrDayOrYear instanceof Day) 190 dateObject = createUTCDate(valueOrDayOrYear.year, valueOrDayOrYear.month, valueOrDayOrYear.date); 191 else 192 dateObject = new Date(valueOrDayOrYear); 193 this.year = dateObject.getUTCFullYear(); 207 */ 208 function DateType() { 209 } 210 211 /** 212 * @constructor 213 * @extends DateType 214 * @param {!number} year 215 * @param {!number} month 216 * @param {!number} date 217 */ 218 function Day(year, month, date) { 219 var dateObject = createUTCDate(year, month, date); 220 if (isNaN(dateObject.valueOf())) 221 throw "Invalid date"; 222 /** 223 * @type {number} 224 * @const 225 */ 226 this.year = dateObject.getUTCFullYear(); 227 /** 228 * @type {number} 229 * @const 230 */ 194 231 this.month = dateObject.getUTCMonth(); 232 /** 233 * @type {number} 234 * @const 235 */ 195 236 this.date = dateObject.getUTCDate(); 196 237 }; 197 238 239 Day.prototype = Object.create(DateType.prototype); 240 198 241 Day.ISOStringRegExp = /^(\d+)-(\d+)-(\d+)/; 199 242 200 243 /** 201 244 * @param {!string} str 202 * @return {? Month}245 * @return {?Day} 203 246 */ 204 247 Day.parse = function(str) { … … 213 256 214 257 /** 258 * @param {!number} value 259 * @return {!Day} 260 */ 261 Day.createFromValue = function(millisecondsSinceEpoch) { 262 return Day.createFromDate(new Date(millisecondsSinceEpoch)) 263 }; 264 265 /** 215 266 * @param {!Date} date 216 267 * @return {!Day} 217 268 */ 218 269 Day.createFromDate = function(date) { 270 if (isNaN(date.valueOf())) 271 throw "Invalid date"; 219 272 return new Day(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); 273 }; 274 275 /** 276 * @param {!Day} day 277 * @return {!Day} 278 */ 279 Day.createFromDay = function(day) { 280 return day; 220 281 }; 221 282 … … 229 290 230 291 /** 231 * @param {!Da y} other232 * @return {!bool }292 * @param {!DateType} other 293 * @return {!boolean} 233 294 */ 234 295 Day.prototype.equals = function(other) { 235 return this.year === other.year && this.month === other.month && this.date === other.date; 236 }; 237 238 /** 296 return other instanceof Day && this.year === other.year && this.month === other.month && this.date === other.date; 297 }; 298 299 /** 300 * @param {!number=} offset 239 301 * @return {!Day} 240 302 */ 241 Day.prototype.previous = function() { 242 return new Day(this.year, this.month, this.date - 1); 243 }; 244 245 /** 303 Day.prototype.previous = function(offset) { 304 if (typeof offset === "undefined") 305 offset = 1; 306 return new Day(this.year, this.month, this.date - offset); 307 }; 308 309 /** 310 * @param {!number=} offset 246 311 * @return {!Day} 247 312 */ 248 Day.prototype.next = function() { 249 return new Day(this.year, this.month, this.date + 1); 313 Day.prototype.next = function(offset) { 314 if (typeof offset === "undefined") 315 offset = 1; 316 return new Day(this.year, this.month, this.date + offset); 250 317 }; 251 318 … … 265 332 266 333 /** 334 * @return {!Day} 335 */ 336 Day.prototype.firstDay = function() { 337 return this; 338 }; 339 340 /** 341 * @return {!Day} 342 */ 343 Day.prototype.middleDay = function() { 344 return this; 345 }; 346 347 /** 348 * @return {!Day} 349 */ 350 Day.prototype.lastDay = function() { 351 return this; 352 }; 353 354 /** 267 355 * @return {!number} 268 356 */ 269 357 Day.prototype.valueOf = function() { 270 return this.startDate().getTime(); 358 return createUTCDate(this.year, this.month, this.date).getTime(); 359 }; 360 361 /** 362 * @return {!WeekDay} 363 */ 364 Day.prototype.weekDay = function() { 365 return createUTCDate(this.year, this.month, this.date).getUTCDay(); 271 366 }; 272 367 … … 282 377 283 378 // See WebCore/platform/DateComponents.h. 284 Day.Minimum = new Day(-62135596800000.0); 285 Day.Maximum = new Day(8640000000000000.0); 379 Day.Minimum = Day.createFromValue(-62135596800000.0); 380 Day.Maximum = Day.createFromValue(8640000000000000.0); 381 286 382 // See WebCore/html/DayInputType.cpp. 287 383 Day.DefaultStep = 86400000; … … 290 386 /** 291 387 * @constructor 292 * @param {!number|Week} valueOrWeekOrYear 293 * @param {!number=} week 294 */ 295 function Week(valueOrWeekOrYear, week) { 296 if (arguments.length === 2) { 297 this.year = valueOrWeekOrYear; 298 this.week = week; 299 // Number of years per year is either 52 or 53. 300 if (this.week < 1 || (this.week > 52 && this.week > Week.numberOfWeeksInYear(this.year))) { 301 var normalizedWeek = Week.createFromDate(this.startDate()); 302 this.year = normalizedWeek.year; 303 this.week = normalizedWeek.week; 304 } 305 } else if (valueOrWeekOrYear instanceof Week) { 306 this.year = valueOrWeekOrYear.year; 307 this.week = valueOrWeekOrYear.week; 308 } else { 309 var week = Week.createFromDate(new Date(valueOrWeekOrYear)); 310 this.year = week.year; 311 this.week = week.week; 312 } 313 } 314 315 Week.MillisecondsPerWeek = 7 * 24 * 60 * 60 * 1000; 388 * @extends DateType 389 * @param {!number} year 390 * @param {!number} week 391 */ 392 function Week(year, week) { 393 /** 394 * @type {number} 395 * @const 396 */ 397 this.year = year; 398 /** 399 * @type {number} 400 * @const 401 */ 402 this.week = week; 403 // Number of years per year is either 52 or 53. 404 if (this.week < 1 || (this.week > 52 && this.week > Week.numberOfWeeksInYear(this.year))) { 405 var normalizedWeek = Week.createFromDay(this.firstDay()); 406 this.year = normalizedWeek.year; 407 this.week = normalizedWeek.week; 408 } 409 } 410 316 411 Week.ISOStringRegExp = /^(\d+)-[wW](\d+)$/; 412 317 413 // See WebCore/platform/DateComponents.h. 318 414 Week.Minimum = new Week(1, 1); 319 415 Week.Maximum = new Week(275760, 37); 416 320 417 // See WebCore/html/WeekInputType.cpp. 321 418 Week.DefaultStep = 604800000; 322 419 Week.DefaultStepBase = -259200000; 420 421 Week.EpochWeekDay = createUTCDate(1970, 0, 0).getUTCDay(); 323 422 324 423 /** … … 336 435 337 436 /** 437 * @param {!number} millisecondsSinceEpoch 438 * @return {!Week} 439 */ 440 Week.createFromValue = function(millisecondsSinceEpoch) { 441 return Week.createFromDate(new Date(millisecondsSinceEpoch)) 442 }; 443 444 /** 338 445 * @param {!Date} date 339 446 * @return {!Week} 340 447 */ 341 448 Week.createFromDate = function(date) { 449 if (isNaN(date.valueOf())) 450 throw "Invalid date"; 342 451 var year = date.getUTCFullYear(); 343 452 if (year <= Week.Maximum.year && Week.weekOneStartDateForYear(year + 1).getTime() <= date.getTime()) … … 350 459 351 460 /** 461 * @param {!Day} day 462 * @return {!Week} 463 */ 464 Week.createFromDay = function(day) { 465 var year = day.year; 466 if (year <= Week.Maximum.year && Week.weekOneStartDayForYear(year + 1) <= day) 467 year++; 468 else if (year > 1 && Week.weekOneStartDayForYear(year) > day) 469 year--; 470 var week = Math.floor(1 + (day.valueOf() - Week.weekOneStartDayForYear(year).valueOf()) / MillisecondsPerWeek); 471 return new Week(year, week); 472 }; 473 474 /** 352 475 * @return {!Week} 353 476 */ … … 366 489 // The week containing January 4th is week one. 367 490 var yearStartDay = createUTCDate(year, 0, 4).getUTCDay(); 368 return createUTCDate(year, 0, 4 - (yearStartDay + 6) % 7); 491 return createUTCDate(year, 0, 4 - (yearStartDay + 6) % DaysPerWeek); 492 }; 493 494 /** 495 * @param {!number} year 496 * @return {!Day} 497 */ 498 Week.weekOneStartDayForYear = function(year) { 499 if (year < 1) 500 return Day.Minimum; 501 // The week containing January 4th is week one. 502 var yearStartDay = createUTCDate(year, 0, 4).getUTCDay(); 503 return new Day(year, 0, 4 - (yearStartDay + 6) % DaysPerWeek); 369 504 }; 370 505 … … 387 522 */ 388 523 Week._numberOfWeeksSinceDate = function(baseDate, date) { 389 return Math.floor((date.getTime() - baseDate.getTime()) / Week.MillisecondsPerWeek);390 }; 391 392 /** 393 * @param {! Week} other394 * @return {!bool }524 return Math.floor((date.getTime() - baseDate.getTime()) / MillisecondsPerWeek); 525 }; 526 527 /** 528 * @param {!DateType} other 529 * @return {!boolean} 395 530 */ 396 531 Week.prototype.equals = function(other) { 397 return this.year === other.year && this.week === other.week; 398 }; 399 400 /** 532 return other instanceof Week && this.year === other.year && this.week === other.week; 533 }; 534 535 /** 536 * @param {!number=} offset 401 537 * @return {!Week} 402 538 */ 403 Week.prototype.previous = function() { 404 return new Week(this.year, this.week - 1); 405 }; 406 407 /** 539 Week.prototype.previous = function(offset) { 540 if (typeof offset === "undefined") 541 offset = 1; 542 return new Week(this.year, this.week - offset); 543 }; 544 545 /** 546 * @param {!number=} offset 408 547 * @return {!Week} 409 548 */ 410 Week.prototype.next = function() { 411 return new Week(this.year, this.week + 1); 549 Week.prototype.next = function(offset) { 550 if (typeof offset === "undefined") 551 offset = 1; 552 return new Week(this.year, this.week + offset); 412 553 }; 413 554 … … 431 572 432 573 /** 574 * @return {!Day} 575 */ 576 Week.prototype.firstDay = function() { 577 var weekOneStartDay = Week.weekOneStartDayForYear(this.year); 578 return weekOneStartDay.next((this.week - 1) * DaysPerWeek); 579 }; 580 581 /** 582 * @return {!Day} 583 */ 584 Week.prototype.middleDay = function() { 585 return this.firstDay().next(3); 586 }; 587 588 /** 589 * @return {!Day} 590 */ 591 Week.prototype.lastDay = function() { 592 if (this.equals(Week.Maximum)) 593 return Day.Maximum; 594 return this.next().firstDay().previous(); 595 }; 596 597 /** 433 598 * @return {!number} 434 599 */ 435 600 Week.prototype.valueOf = function() { 436 return this. startDate().getTime() - createUTCDate(1970, 0, 1).getTime();601 return this.firstDay().valueOf() - createUTCDate(1970, 0, 1).getTime(); 437 602 }; 438 603 … … 449 614 /** 450 615 * @constructor 451 * @param {!number|Month} valueOrMonthOrYear 452 * @param {!number=} month 453 */ 454 function Month(valueOrMonthOrYear, month) { 455 if (arguments.length == 2) { 456 this.year = valueOrMonthOrYear; 457 this.month = month; 458 } else if (valueOrMonthOrYear instanceof Month) { 459 this.year = valueOrMonthOrYear.year; 460 this.month = valueOrMonthOrYear.month; 461 } else { 462 this.year = 1970; 463 this.month = valueOrMonthOrYear; 464 } 465 this.year = this.year + Math.floor(this.month / 12); 466 this.month = this.month < 0 ? this.month % 12 + 12 : this.month % 12; 467 if (this.year <= 0 || Month.Maximum < this) { 468 this.year = NaN; 469 this.month = NaN; 470 } 616 * @extends DateType 617 * @param {!number} year 618 * @param {!number} month 619 */ 620 function Month(year, month) { 621 /** 622 * @type {number} 623 * @const 624 */ 625 this.year = year + Math.floor(month / MonthsPerYear); 626 /** 627 * @type {number} 628 * @const 629 */ 630 this.month = month % MonthsPerYear < 0 ? month % MonthsPerYear + MonthsPerYear : month % MonthsPerYear; 471 631 }; 472 632 … … 476 636 Month.Minimum = new Month(1, 0); 477 637 Month.Maximum = new Month(275760, 8); 638 478 639 // See WebCore/html/MonthInputType.cpp. 479 640 Month.DefaultStep = 1; … … 494 655 495 656 /** 657 * @param {!number} value 658 * @return {!Month} 659 */ 660 Month.createFromValue = function(monthsSinceEpoch) { 661 return new Month(1970, monthsSinceEpoch) 662 }; 663 664 /** 496 665 * @param {!Date} date 497 666 * @return {!Month} 498 667 */ 499 668 Month.createFromDate = function(date) { 669 if (isNaN(date.valueOf())) 670 throw "Invalid date"; 500 671 return new Month(date.getUTCFullYear(), date.getUTCMonth()); 672 }; 673 674 /** 675 * @param {!Day} day 676 * @return {!Month} 677 */ 678 Month.createFromDay = function(day) { 679 return new Month(day.year, day.month); 501 680 }; 502 681 … … 510 689 511 690 /** 691 * @return {!boolean} 692 */ 693 Month.prototype.containsDay = function(day) { 694 return this.year === day.year && this.month === day.month; 695 }; 696 697 /** 512 698 * @param {!Month} other 513 * @return {!bool }699 * @return {!boolean} 514 700 */ 515 701 Month.prototype.equals = function(other) { 516 return this.year === other.year && this.month === other.month; 517 }; 518 519 /** 702 return other instanceof Month && this.year === other.year && this.month === other.month; 703 }; 704 705 /** 706 * @param {!number=} offset 520 707 * @return {!Month} 521 708 */ 522 Month.prototype.previous = function() { 523 return new Month(this.year, this.month - 1); 524 }; 525 526 /** 709 Month.prototype.previous = function(offset) { 710 if (typeof offset === "undefined") 711 offset = 1; 712 return new Month(this.year, this.month - offset); 713 }; 714 715 /** 716 * @param {!number=} offset 527 717 * @return {!Month} 528 718 */ 529 Month.prototype.next = function() { 530 return new Month(this.year, this.month + 1); 719 Month.prototype.next = function(offset) { 720 if (typeof offset === "undefined") 721 offset = 1; 722 return new Month(this.year, this.month + offset); 531 723 }; 532 724 … … 548 740 549 741 /** 742 * @return {!Day} 743 */ 744 Month.prototype.firstDay = function() { 745 return new Day(this.year, this.month, 1); 746 }; 747 748 /** 749 * @return {!Day} 750 */ 751 Month.prototype.middleDay = function() { 752 return new Day(this.year, this.month, this.month === 2 ? 14 : 15); 753 }; 754 755 /** 756 * @return {!Day} 757 */ 758 Month.prototype.lastDay = function() { 759 if (this.equals(Month.Maximum)) 760 return Day.Maximum; 761 return this.next().firstDay().previous(); 762 }; 763 764 /** 550 765 * @return {!number} 551 766 */ 552 767 Month.prototype.valueOf = function() { 553 return (this.year - 1970) * 12+ this.month;768 return (this.year - 1970) * MonthsPerYear + this.month; 554 769 }; 555 770 … … 562 777 yearString = ("000" + yearString).substr(-4, 4); 563 778 return yearString + "-" + ("0" + (this.month + 1)).substr(-2, 2); 779 }; 780 781 /** 782 * @return {!string} 783 */ 784 Month.prototype.toLocaleString = function() { 785 if (global.params.locale === "ja") 786 return "" + this.year + "年" + formatJapaneseImperialEra(this.year, this.month) + " " + (this.month + 1) + "月"; 787 return window.pagePopupController.formatMonth(this.year, this.month); 788 }; 789 790 /** 791 * @return {!string} 792 */ 793 Month.prototype.toShortLocaleString = function() { 794 return window.pagePopupController.formatShortMonth(this.year, this.month); 564 795 }; 565 796 … … 1174 1405 initialSelection = this.selectionConstructor.createFromToday(); 1175 1406 if (initialSelection.valueOf() < this._minimumValue) 1176 initialSelection = new this.selectionConstructor (this._minimumValue);1407 initialSelection = new this.selectionConstructor.createFromValue(this._minimumValue); 1177 1408 else if (initialSelection.valueOf() > this._maximumValue) 1178 initialSelection = new this.selectionConstructor (this._maximumValue);1409 initialSelection = new this.selectionConstructor.createFromValue(this._maximumValue); 1179 1410 this.showMonth(Month.createFromDate(initialSelection.startDate())); 1180 1411 this._daysTable.selectRangeAndShowEntireRange(initialSelection); … … 1464 1695 var monthValue = month.valueOf(); 1465 1696 if (this._left3) 1466 this._left3.disabled = !this.picker.shouldShowMonth( new Month(monthValue - 13));1467 this._left2.disabled = !this.picker.shouldShowMonth( new Month(monthValue - 2));1468 this._left1.disabled = !this.picker.shouldShowMonth( new Month(monthValue - 1));1469 this._right1.disabled = !this.picker.shouldShowMonth( new Month(monthValue + 1));1470 this._right2.disabled = !this.picker.shouldShowMonth( new Month(monthValue + 2));1697 this._left3.disabled = !this.picker.shouldShowMonth(Month.createFromValue(monthValue - 13)); 1698 this._left2.disabled = !this.picker.shouldShowMonth(Month.createFromValue(monthValue - 2)); 1699 this._left1.disabled = !this.picker.shouldShowMonth(Month.createFromValue(monthValue - 1)); 1700 this._right1.disabled = !this.picker.shouldShowMonth(Month.createFromValue(monthValue + 1)); 1701 this._right2.disabled = !this.picker.shouldShowMonth(Month.createFromValue(monthValue + 2)); 1471 1702 if (this._right3) 1472 this._left3.disabled = !this.picker.shouldShowMonth( new Month(monthValue + 13));1703 this._left3.disabled = !this.picker.shouldShowMonth(Month.createFromValue(monthValue + 13)); 1473 1704 this._monthLabel.innerText = month.toLocaleString(); 1474 1705 while (this._monthPopupContents.hasChildNodes()) … … 1476 1707 1477 1708 for (var m = monthValue - 6; m <= monthValue + 6; m++) { 1478 var month = new Month(m);1709 var month = Month.createFromValue(m); 1479 1710 if (!this.picker.shouldShowMonth(month)) 1480 1711 continue; … … 1667 1898 YearMonthController.prototype.moveRelatively = function(amount) { 1668 1899 var current = this.picker.currentMonth().valueOf(); 1669 var updated = new Month(current + amount);1900 var updated = Month.createFromValue(current + amount); 1670 1901 this.picker.showMonth(updated, CalendarPicker.NavigationBehaviour.Animate | CalendarPicker.NavigationBehaviour.KeepSelectionPosition); 1671 1902 };
Note: See TracChangeset
for help on using the changeset viewer.