From 2c9eb097b12e91be4de7c8cf6ccf9f8752aeb415 Mon Sep 17 00:00:00 2001 From: Rudy Huang Date: Thu, 13 Jan 2022 18:51:05 +0800 Subject: [PATCH] Add week numbers --- CHANGELOG.md | 3 + example/web/demo.html | 2 +- lib/css/bootjack-datepicker.css | 6 ++ lib/css/bootjack-datepicker.min.css | 2 +- lib/src/calendar.dart | 96 +++++++++++++++++++++++++---- tool/mincss | 2 +- 6 files changed, 95 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0550112..f600648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ #CHANGES +**2.0.1** +* Supported display week numbers + **2.0.0** * Migrate to null safety diff --git a/example/web/demo.html b/example/web/demo.html index a70158a..2235504 100644 --- a/example/web/demo.html +++ b/example/web/demo.html @@ -14,7 +14,7 @@
-
+
diff --git a/lib/css/bootjack-datepicker.css b/lib/css/bootjack-datepicker.css index 4222c5c..a19086b 100644 --- a/lib/css/bootjack-datepicker.css +++ b/lib/css/bootjack-datepicker.css @@ -119,6 +119,12 @@ background-color: #8c765a; } +.calendar .dayrow .wn { + pointer-events: none; + font-size: 12px; + color: #acacac; +} + .calendar .dow .wkend { color: #555; } diff --git a/lib/css/bootjack-datepicker.min.css b/lib/css/bootjack-datepicker.min.css index 276e9a0..1165060 100644 --- a/lib/css/bootjack-datepicker.min.css +++ b/lib/css/bootjack-datepicker.min.css @@ -1 +1 @@ -.calendar{font-family:"Open Sans",Arial,Sans-serif;font-size:14px;font-weight:600;font-style:normal;color:#555;min-width:280px;border:1px solid #e3e3e3;}.dropdown-menu .calendar{border:none;}.calendar a{text-decoration:none;}.calendar .header{height:40px;background-color:#7ea656;}.calendar .header th{position:relative;text-align:center;}.calendar .header a{display:inline-block;line-height:32px;cursor:pointer;}.calendar .header:hover,.calendar .header a:hover{background-color:#3f5925!important;}.calendar .title{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:16px;font-weight:600;font-style:normal;color:#fff;}.calendar .left-icon,.calendar .right-icon{font-size:16px;color:#fff;width:40px;height:40px;padding:4px;position:absolute;top:0;}.calendar .left-icon{border-right:1px solid #6b8c49;left:0;}.calendar .right-icon{border-left:1px solid #6b8c49;right:0;}.calendar-disabled{color:#acacac!important;background:#e3e3e3!important;cursor:default!important;}.calendar .dow th{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:11px;width:40px;height:32px;background-color:#ebebeb;text-align:center;}.calendar .cnt{table-layout:fixed;}.calendar .cell12row span{width:25%;display:inline-block;float:left;min-height:48px;line-height:48px;}.calendar .dayrow td{width:40px;height:40px;}.calendar .cell12row span,.calendar .dayrow td{border-width:1px 0 0 1px;border-style:solid;border-color:#e3e3e3;background:#fff;text-align:center;cursor:pointer;}.calendar .cell12row span:nth-child(4n+1),.calendar .dayrow td:first-child{border-left-width:0;}.calendar .cell12row span:hover,.calendar .dayrow td:hover{color:#fff;background-color:#8c765a;}.calendar .dow .wkend{color:#555;}.calendar td.outside{color:#acacac;background:#fff;}.calendar .cell12row span.seld,.calendar .dayrow td.seld{color:#8c765a;font-weight:700;background-color:#fff;}.calendar td.seld:hover,.calendar span.seld:hover{color:#fff;background-color:#8c765a;} \ No newline at end of file +.calendar{font-family:"Open Sans",Arial,Sans-serif;font-size:14px;font-weight:600;font-style:normal;color:#555;min-width:280px;border:1px solid #e3e3e3;}.dropdown-menu .calendar{border:none;}.calendar a{text-decoration:none;}.calendar .header{height:40px;background-color:#7ea656;}.calendar .header th{position:relative;text-align:center;}.calendar .header a{display:inline-block;line-height:32px;cursor:pointer;}.calendar .header:hover,.calendar .header a:hover{background-color:#3f5925!important;}.calendar .title{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:16px;font-weight:600;font-style:normal;color:#fff;}.calendar .left-icon,.calendar .right-icon{font-size:16px;color:#fff;width:40px;height:40px;padding:4px;position:absolute;top:0;}.calendar .left-icon{border-right:1px solid #6b8c49;left:0;}.calendar .right-icon{border-left:1px solid #6b8c49;right:0;}.calendar-disabled{color:#acacac!important;background:#e3e3e3!important;cursor:default!important;}.calendar .dow th{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:11px;width:40px;height:32px;background-color:#ebebeb;text-align:center;}.calendar .cnt{table-layout:fixed;}.calendar .cell12row span{width:25%;display:inline-block;float:left;min-height:48px;line-height:48px;}.calendar .dayrow td{width:40px;height:40px;}.calendar .cell12row span,.calendar .dayrow td{border-width:1px 0 0 1px;border-style:solid;border-color:#e3e3e3;background:#fff;text-align:center;cursor:pointer;}.calendar .cell12row span:nth-child(4n+1),.calendar .dayrow td:first-child{border-left-width:0;}.calendar .cell12row span:hover,.calendar .dayrow td:hover{color:#fff;background-color:#8c765a;}.calendar .dayrow .wn{pointer-events:none;font-size:12px;color:#acacac;}.calendar .dow .wkend{color:#555;}.calendar td.outside{color:#acacac;background:#fff;}.calendar .cell12row span.seld,.calendar .dayrow td.seld{color:#8c765a;font-weight:700;background-color:#fff;}.calendar td.seld:hover,.calendar span.seld:hover{color:#fff;background-color:#8c765a;} \ No newline at end of file diff --git a/lib/src/calendar.dart b/lib/src/calendar.dart index 85f58ba..ab3bade 100644 --- a/lib/src/calendar.dart +++ b/lib/src/calendar.dart @@ -30,16 +30,40 @@ class Calendar extends Base { +'''; + static const _dowWithWeekNumbersTemplate = ''' + + + + + + + + + + '''; static const _dayrowTemplate = ''' - - - - - - - + + + + + + + + +'''; + static const _dayrowWithWeekNumbersTemplate = ''' + + + + + + + + + '''; static const _cell12rowTemplate = ''' @@ -135,6 +159,8 @@ class Calendar extends Base { _markCal(); } } + + bool displayWeekNumbers = false; String? _dataTargetSelector; @@ -149,10 +175,12 @@ class Calendar extends Base { * * [value] - the selected [DateTime] value * * [dataTargetSelector] - the selector for [InputElement] to display date value * * [newDate] - the function to create [DateTime] value when select + * * [displayWeekNumbers] - whether to show week numbers, default: false * */ Calendar(Element element, {String? format, String? date, String? locale, int? firstDayOfWeek, - DateTime? value, String? dataTargetSelector, DateTime? newDate(y,m,d)?}) : + DateTime? value, String? dataTargetSelector, DateTime? newDate(y,m,d)?, + bool? displayWeekNumbers}) : this._format = _data(format, element, 'format', 'yyyy/MM/dd')!, this._locale = _data(locale, element, 'date-locale', Intl.systemLocale)!, this._view = day, @@ -162,6 +190,7 @@ class Calendar extends Base { this._value = value, this._currentValue = value, this._newDate = newDate, + this.displayWeekNumbers = displayWeekNumbers ?? element.dataset['weeknumbers'] == 'true', super(element, _name) { _initCalendar(); _initDatepicker(); @@ -201,7 +230,7 @@ class Calendar extends Base { ..on('click', _clickArrow, selector: '.left-icon') ..on('click', _clickArrow, selector: '.right-icon') - ..on('click', _clickDate, selector: '.dayrow td, .cell12row span'); + ..on('click', _clickDate, selector: '.dayrow .day, .cell12row span'); _setView(day); } @@ -284,6 +313,10 @@ class Calendar extends Base { e.remove(); } + //reset colspan + final header = element.querySelector('.header > th') as TableCellElement?; + header?.colSpan = 7; + this._view = view; switch (view) { case day: @@ -309,18 +342,25 @@ class Calendar extends Base { void _dayView() { final calBody = element.querySelector('.cnt') as TableElement, - dow = calBody.tBodies[0].createFragment(_dowTemplate).children[0], + dowTemplate = displayWeekNumbers ? _dowWithWeekNumbersTemplate : _dowTemplate, + dayrowTemplate = displayWeekNumbers ? _dayrowWithWeekNumbersTemplate : _dayrowTemplate, + startPos = displayWeekNumbers ? 1 : 0, + dow = calBody.tBodies[0].createFragment(dowTemplate).children[0], children = dow.children, swkDays = _dfmt.dateSymbols.SHORTWEEKDAYS, ofs = (_firstDayOfWeek + 1) % 7; + + final header = element.querySelector('.header > th') as TableCellElement; + header.colSpan = displayWeekNumbers ? 8 : 7; + //render week days for (var i = swkDays.length; --i >= 0;) { - children[i].text = swkDays[(i + ofs) % 7]; + children[startPos + i].text = swkDays[(i + ofs) % 7]; } final buffer = StringBuffer(); for (var i = 6; --i >= 0;) { - buffer.write(_dayrowTemplate); + buffer.write(dayrowTemplate); } calBody.tBodies[0] @@ -380,7 +420,15 @@ class Calendar extends Base { } for (final row in dayrow) { - for (final td in row.children) { + final len = row.children.length; + for (var i = 0; i < len; i++) { + final td = row.children[i]; + if (i == 0 && displayWeekNumbers) { // Week numbers + td.text = getWeekOfYear(beginDate, _firstDayOfWeek).toString(); + renderWeekNumber(td); + continue; + } + td.text = '${beginDate.day}'; renderDay(td, beginDate); @@ -477,6 +525,10 @@ class Calendar extends Base { } + void renderWeekNumber(Element elem) { + + } + DateTime? _wheelWhen; void _doMousewheel(WheelEvent event) { final now = DateTime.now(); @@ -634,3 +686,21 @@ class Calendar extends Base { _data(value, Element elem, String name, [defaultValue]) => value ?? elem.dataset[name] ?? defaultValue; + +/// Returns a 0-based [weekday] index, according to [firstDayOfWeek]. +/// * [weekday] should be [DateTime.weekday] (1-based) +/// * [firstDayOfWeek] is 0-based (0 is Monday, 6 is Sunday) +int weekDayReIndex(int weekday, int firstDayOfWeek) +=> (((weekday - DateTime.monday) - firstDayOfWeek) + 7) % 7; + +/// Get the week number of year of [date]. +/// ref: https://stackoverflow.com/a/6117889 +/// * [firstDayOfWeek] is 0-based (0 is Monday, 6 is Sunday), default is Monday (ISO 8601) +int getWeekOfYear(DateTime date, [int firstDayOfWeek = 0]) { + final midnight = DateTime.utc(date.year, date.month, date.day), + daysDiff = weekDayReIndex(DateTime.thursday, firstDayOfWeek) - weekDayReIndex(date.weekday, firstDayOfWeek), + thursday = midnight.add(Duration(days: daysDiff)), + yearStart = DateTime.utc(thursday.year, DateTime.january , 1), + millisDiff = thursday.millisecondsSinceEpoch - yearStart.millisecondsSinceEpoch; + return (((millisDiff / 86400000) + 1) / 7).ceil(); +} diff --git a/tool/mincss b/tool/mincss index 3411258..4d89a8f 100644 --- a/tool/mincss +++ b/tool/mincss @@ -25,7 +25,7 @@ if [ ! -f $jarfl ] ; then exit 1 fi -for fn in $(find -name *.css) ; do +for fn in $(find . -name '*.css') ; do if [ "$fn" != "${fn##*/packages/}" ] || [ "$fn" != "${fn%.min.css}" ] ; then #echo Skip $fn continue