Showing preview only (254K chars total). Download the full file or copy to clipboard to get everything.
Repository: jdtcn/BlazorDateRangePicker
Branch: master
Commit: aed96245e779
Files: 78
Total size: 233.2 KB
Directory structure:
gitextract_q7_l1jjh/
├── .gitignore
├── BlazorDateRangePicker/
│ ├── BlazorDateRangePicker.csproj
│ ├── Calendar.razor
│ ├── Calendar.razor.cs
│ ├── Calendar.razor.css
│ ├── CalendarType.cs
│ ├── DateRange.cs
│ ├── DateRangePicker.razor
│ ├── DateRangePicker.razor.cs
│ ├── DateRangePicker.razor.css
│ ├── DateRangePickerConfig.cs
│ ├── DateRangePickerExtensions.cs
│ ├── Enums.cs
│ ├── IConfigurableOptions.cs
│ ├── PickerContainer.razor
│ ├── TimePicker.razor
│ ├── TimePicker.razor.cs
│ ├── TimePicker.razor.css
│ ├── TimeSettings.cs
│ ├── _Imports.razor
│ └── wwwroot/
│ └── clickAndPositionHandler.js
├── BlazorDateRangePicker.sln
├── Demo.ClientSideApp/
│ ├── App.razor
│ ├── Demo.ClientSideApp.csproj
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── _Imports.razor
│ └── wwwroot/
│ └── index.html
├── Demo.ServerSideApp/
│ ├── App.razor
│ ├── Demo.ServerSideApp.csproj
│ ├── Pages/
│ │ └── _Host.cshtml
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── _Imports.razor
│ ├── appsettings.Development.json
│ └── appsettings.json
├── Demo.Shared/
│ ├── BlazorClipboard.cs
│ ├── Demo.Shared.csproj
│ ├── Pages/
│ │ ├── BothSidesSelection.razor
│ │ ├── Container.razor
│ │ ├── CustomButtons.razor
│ │ ├── CustomClickHandler.razor
│ │ ├── CustomDate.razor
│ │ ├── CustomDay.razor
│ │ ├── CustomInput.razor
│ │ ├── DateInput.razor
│ │ ├── Disable.razor
│ │ ├── Example.razor
│ │ ├── Form.razor
│ │ ├── HandleEvents.razor
│ │ ├── Highlight.razor
│ │ ├── Index.razor
│ │ ├── Inline.razor
│ │ ├── Licence.razor
│ │ ├── Limits.razor
│ │ ├── Localization.razor
│ │ ├── Positioning.razor
│ │ ├── PredefinedRanges.razor
│ │ ├── Single.razor
│ │ └── Time.razor
│ ├── Shared/
│ │ ├── MainLayout.razor
│ │ └── Sidebar.razor
│ ├── _Imports.razor
│ └── wwwroot/
│ ├── css/
│ │ ├── open-iconic/
│ │ │ ├── FONT-LICENSE
│ │ │ ├── ICON-LICENSE
│ │ │ ├── README.md
│ │ │ └── font/
│ │ │ └── fonts/
│ │ │ └── open-iconic.otf
│ │ └── site.css
│ └── highlight/
│ ├── cshtml-razor.js
│ ├── default.css
│ ├── highlight.pack.js
│ ├── highlightInterop.js
│ └── vs.css
├── LICENSE
├── README.md
└── SourceGenerators/
├── AddPropertiesGenerator.cs
├── CopyPropertiesGenerator.cs
└── SourceGenerators.csproj
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
x64/
build/
bld/
[Bb]in/
[Oo]bj/
# Roslyn cache directories
*.ide/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
#VS2015 local configuration files
.vs/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
#*.pubxml
# NuGet Packages Directory
packages/*
## TODO: If the tool you use requires repositories.config
## uncomment the next line
#!packages/repositories.config
# Enable "build/" folder in the NuGet Packages folder since
# NuGet packages use it for MSBuild targets.
# This line needs to be after the ignore of the build folder
# (and the packages folder if the line above has been uncommented)
!packages/build/
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
bower_packages/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
GeoRoute/packages/*
CardsReports/
InstrReports/
.vscode
/GeoRoute/GR.Admin/grAdmin/FrontApp/dist/
Demo.ClientSideApp/Properties/PublishProfiles/*.pubxml
ServiceDependencies
================================================
FILE: BlazorDateRangePicker/BlazorDateRangePicker.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>net6;net7;net8;net9;net10.0</TargetFrameworks>
<OutputType>Library</OutputType>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<IsPackable>true</IsPackable>
<LangVersion>preview</LangVersion>
<RazorLangVersion>latest</RazorLangVersion>
<Version>6.2.0</Version>
<Authors>Sergey Zaikin</Authors>
<PackageId>BlazorDateRangePicker</PackageId>
<Title>Blazor Date Range Picker</Title>
<Description>A fully managed port of daterangepicker.js for Blazor</Description>
<PackageProjectUrl>https://github.com/jdtcn/BlazorDateRangePicker</PackageProjectUrl>
<RepositoryUrl>https://github.com/jdtcn/BlazorDateRangePicker</RepositoryUrl>
<PackageTags>blazor;daterangepicker;datepicker</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net6'))">
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.29" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net7'))">
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net8'))">
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net9'))">
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net10.0'))">
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.0-rc.1.25451.107" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SourceGenerators\SourceGenerators.csproj"
ReferenceOutputAssembly="false"
OutputItemType="Analyzer" />
</ItemGroup>
</Project>
================================================
FILE: BlazorDateRangePicker/Calendar.razor
================================================
@*
* author: Sergey Zaikin zaikinsr@yandex.ru
* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*@
<table class="table-condensed">
<thead>
<tr>
@if (Picker.ShowWeekNumbers == true || Picker.ShowISOWeekNumbers == true)
{
<th></th>
}
<th class="@(PrevBtnVisible ? "prev available" : "")" @onclick="@(_ => PreviousMonth(PrevBtnVisible))"><span></span></th>
<th colspan="5" class="month">
@if (Picker.ShowDropdowns == true)
{
var inMinYear = CurrentYear == MinYear;
var inMaxYear = CurrentYear == MaxYear;
<select class="monthselect" @bind="@CurrentMonth">
@for (var m = 1; m < 13; m++)
{
var enabled = (!inMinYear || (m >= Picker.MinDate?.Month)) && (!inMaxYear || (m <= Picker.MaxDate?.Month)) && CurrentYear <= MaxYear;
var selected = m == CurrentMonth;
<option @key="m" selected="@selected" disabled="@(!enabled)" value="@m">
@Picker.Culture.DateTimeFormat.GetMonthName(m)
</option>
}
</select>
<select class="yearselect" @bind="CurrentYear">
@for (var y = MinYear; y <= MaxYear; y++)
{
<option @key="y" value="@y" selected="@(y == CurrentYear)">@y</option>
}
@if(CurrentYear > MaxYear)
{
<option @key="CurrentYear" value="@CurrentYear" selected="true">@CurrentYear</option>
}
</select>
}
else
{
@Picker.Culture.DateTimeFormat.GetMonthName(CalendarData.Month.Month)<text> </text>@CalendarData.Month.Year
}
</th>
<th class="@(NextBtnVisible ? "next available" : "")" @onclick="@(_ => NextMonth(NextBtnVisible))"><span></span></th>
</tr>
<tr>
@if (Picker.ShowWeekNumbers == true || Picker.ShowISOWeekNumbers == true)
{
<th class="week">@Picker.WeekAbbreviation</th>
}
@foreach (var dayOfWeekName in DayNames)
{
<th>@dayOfWeekName</th>
}
</tr>
</thead>
<tbody>
@foreach (var row in CalendarData.Calendar)
{
<tr>
@if (Picker.ShowWeekNumbers == true)
{
<td class="week">
@GetWeekOfYear(row[0].Day.DateTime)
</td>
}
else if (Picker.ShowISOWeekNumbers == true)
{
<td class="week">
@GetIso8601WeekOfYear(row[0].Day.DateTime)
</td>
}
@foreach (var dt in row)
{
if (dt.OutOfRange)
{
@if (Picker.DayTemplate != null)
{
@Picker.DayTemplate(dt)
}
else
{
<td class="disabled">-</td>
}
continue;
}
if (dt.Hover == null) dt.Hover = () => OnMouseOverDate(dt.Day);
if (dt.Click == null) dt.Click = () => ClickDate(dt);
<td class="@(Picker.Loading ? "disabled" : dt.ClassNames)"
@onmouseover="@dt.Hover"
@onclick="@dt.Click">
@if (Picker.DayTemplate != null)
{
@Picker.DayTemplate(dt)
}
else
{
@dt.Day.Day
}
</td>
}
</tr>
}
</tbody>
</table>
================================================
FILE: BlazorDateRangePicker/Calendar.razor.cs
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using System;
using System.Linq;
using System.Globalization;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
namespace BlazorDateRangePicker
{
public partial class Calendar : ComponentBase
{
[CascadingParameter] public DateRangePicker Picker { get; set; }
[Parameter] public CalendarType CalendarData { get; set; }
[Parameter] public List<string> CustomDayNames { get; set; }
[Parameter] public SideType? Side { get; set; }
[Parameter] public EventCallback<DateTimeOffset> OnMonthChanged { get; set; }
[Parameter] public EventCallback<DateTimeOffset> OnClickDate { get; set; }
[Parameter] public EventCallback<DateTimeOffset> OnHoverDate { get; set; }
private int MinYear => Picker.MinDate?.Year ?? 1950;
private int MaxYear => Picker.MaxDate?.Year ?? DateTime.Now.AddYears(50).Year;
private int CurrentMonth
{
get => CalendarData.Month.Month;
set => MonthSelected(value);
}
private int CurrentYear
{
get => CalendarData.Month.Year;
set => YearSelected(value);
}
private bool PrevBtnVisible =>
(!Picker.MinDate.HasValue || Picker.MinDate < CalendarData.FirstDay)
&& CalendarData.FirstDay.Date > DateTime.MinValue.Date
&& (Picker.LinkedCalendars != true || Side == SideType.Left);
private bool NextBtnVisible =>
(!Picker.MaxDate.HasValue || Picker.MaxDate > CalendarData.LastDay)
&& CalendarData.LastDay.Date < DateTime.MaxValue.Date
&& (Picker.LinkedCalendars != true || Side == SideType.Right || Picker.ShowOnlyOneCalendar == true);
private List<string> DayNames => GetDayNames();
private List<string> GetDayNames()
{
if (CustomDayNames?.Count == 7) return CustomDayNames;
var dayNames = Picker.Culture.DateTimeFormat.ShortestDayNames.ToList();
var firstDayNumber = (int)Picker.FirstDayOfWeek;
if (firstDayNumber > 0)
{
for (int i = 0; i < firstDayNumber; i++)
{
var item = dayNames[0];
dayNames.Insert(dayNames.Count, item);
dayNames.RemoveAt(0);
}
}
return dayNames;
}
private Task PreviousMonth(bool enabled)
{
if (!enabled) return Task.CompletedTask;
return OnMonthChanged.InvokeAsync(CalendarData.Month.Subtract(CalendarData.Month.Offset).ToOffset(TimeSpan.Zero).AddMonths(-1));
}
private Task NextMonth(bool enabled)
{
if (!enabled) return Task.CompletedTask;
return OnMonthChanged.InvokeAsync(CalendarData.Month.Subtract(CalendarData.Month.Offset).ToOffset(TimeSpan.Zero).AddMonths(1));
}
private Task MonthSelected(int month)
{
var d = CalendarData.Month;
return OnMonthChanged.InvokeAsync(new DateTime(d.Year, month, 1, 12, 0, 0));
}
private Task YearSelected(int year)
{
var d = CalendarData.Month;
var newMonth = new DateTimeOffset(year, d.Month, 1, 12, 0, 0, d.Offset);
if (newMonth > Picker.MaxDate) newMonth = Picker.MaxDate.Value;
else if (newMonth < Picker.MinDate) newMonth = Picker.MinDate.Value;
return OnMonthChanged.InvokeAsync(newMonth);
}
private Task ClickDate(CalendarItem dt)
{
if (dt.Disabled) return Task.CompletedTask;
return OnClickDate.InvokeAsync(dt.Day);
}
private Task OnMouseOverDate(DateTimeOffset date)
{
if (Picker.HoverDate != date)
{
return OnHoverDate.InvokeAsync(date);
}
return Task.CompletedTask;
}
private int GetWeekOfYear(DateTime time)
{
var weekRule = Picker.Culture.DateTimeFormat.CalendarWeekRule;
var firstDayOfWeek = CalendarData.FirstDayOfWeek;
return DateTimeFormatInfo.CurrentInfo.Calendar.GetWeekOfYear(time, weekRule, firstDayOfWeek);
}
private int GetIso8601WeekOfYear(DateTime time)
{
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
}
}
================================================
FILE: BlazorDateRangePicker/Calendar.razor.css
================================================
.next span, .prev span {
color: #fff;
border: solid black;
border-width: 0 2px 2px 0;
border-radius: 0;
display: inline-block;
padding: 3px;
}
.next span {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.prev span {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
th, td {
white-space: nowrap;
text-align: center;
vertical-align: middle;
min-width: 32px;
width: 32px;
height: 24px;
line-height: 24px;
font-size: 12px;
border-radius: 4px;
border: 1px solid transparent;
white-space: nowrap;
cursor: pointer;
}
table {
width: 100%;
margin: 0;
border-spacing: 0;
border-collapse: collapse;
}
td.available:hover, th.available:hover {
background-color: #eee;
border-color: transparent;
color: inherit;
}
td.week, th.week {
font-size: 80%;
color: #ccc;
}
td.disabled, option.disabled {
color: #999;
cursor: not-allowed;
text-decoration: line-through;
}
td.off, td.off.in-range, td.off.start-date, td.off.end-date {
background-color: #fff;
border-color: transparent;
color: #999;
}
td.in-range {
background-color: #ebf4f8;
border-color: transparent;
color: #000;
border-radius: 0;
}
td.start-date {
border-radius: 4px 0 0 4px;
}
td.end-date {
border-radius: 0 4px 4px 0;
}
td.start-date.end-date {
border-radius: 4px;
}
td.active, td.active:hover {
background-color: #357ebd;
border-color: transparent;
color: #fff;
}
th.month {
width: auto;
}
select.monthselect, select.yearselect {
font-size: 12px;
padding: 1px;
height: auto;
margin: 0;
cursor: default;
}
select.monthselect {
margin-right: 2%;
width: 56%;
}
select.yearselect {
width: 40%;
}
.daterangepicker .drp-buttons {
clear: both;
text-align: right;
padding: 8px;
border-top: 1px solid #ddd;
display: none;
line-height: 12px;
vertical-align: middle;
}
================================================
FILE: BlazorDateRangePicker/CalendarType.cs
================================================
/**
* author: Sergey Zaikin zaikinsr@yandex.ru
* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorDateRangePicker
{
public class CalendarType
{
private int DaysInMonth => DateTime.DaysInMonth(Month.Year, Month.Month);
private DayOfWeek DayOfWeek => FirstDay.DayOfWeek;
internal DayOfWeek FirstDayOfWeek { get; set; }
internal SideType Side { get; private set; }
internal DateTimeOffset FirstDay => new(Month.Year, Month.Month, 1, 0, 0, 0, TimeSpan.Zero);
internal DateTimeOffset LastDay => new DateTime(Month.Year, Month.Month, DaysInMonth);
public DateTimeOffset Month { get; private set; } = DateTime.Today;
public List<List<CalendarItem>> Calendar { get; set; } = [];
private DateRangePicker Picker { get; set; }
public CalendarType(DateRangePicker picker, SideType side)
{
Picker = picker;
Side = side;
FirstDayOfWeek = Picker.FirstDayOfWeek.Value;
}
public async Task ChangeMonth(DateTimeOffset month)
{
Month = month;
await CalculateCalendar();
}
public async Task CalculateCalendar()
{
var calendar = Calendar ?? [];
for (var i = calendar.Count; i < 6; i++)
{
calendar.Add([]);
}
var startDayOffset = (int)FirstDayOfWeek - (int)DayOfWeek;
if (startDayOffset > 0) startDayOffset -= 7;
if (DayOfWeek == FirstDayOfWeek) startDayOffset = -7;
int col = 0, row = 0;
for (var i = 0; i < 42; i++, col++)
{
if (i > 0 && col % 7 == 0)
{
col = 0;
row++;
}
if (calendar[row].Count <= col)
calendar[row].Add(new CalendarItem { Side = Side });
var outOfRange =
(Month.Year == 1 && Month.Month == 1 && startDayOffset + i < 0) ||
(Month.Year == 9999 && Month.Month == 12 && startDayOffset + i >= DaysInMonth);
calendar[row][col].OutOfRange = outOfRange;
if (outOfRange)
{
continue;
}
var day = new DateTimeOffset(Month.Year, Month.Month, 1, 12, 0, 0, TimeSpan.Zero).AddDays(startDayOffset + i);
if (calendar[row][col].Day != day)
calendar[row][col].Day = day;
await UpdateCellClasses(calendar[row][col]);
}
Calendar = calendar;
}
private async Task UpdateCellClasses(CalendarItem day)
{
var classes = new List<string>();
var disabled = false;
var dt = day.Day;
// Highlight today's date
if (dt.Date == DateTime.Today)
{ classes.Add("today"); }
// Highlight weekends
if (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
{ classes.Add("weekend"); }
// Grey out the dates in other months displayed at beginning and end of this calendar
if (dt.Month != Month.Month)
{
classes.Add("off");
classes.Add("ends");
}
// Don't allow selection of dates before the minimum date
if (Picker.MinDate.HasValue && dt.Date < Picker.MinDate.Value.Date)
{
classes.Add("off");
classes.Add("disabled");
disabled = true;
}
// Don't allow selection of dates after the maximum date
if (Picker.MaxDate.HasValue && dt.Date > Picker.MaxDate.Value.Date)
{
classes.Add("off");
classes.Add("disabled");
disabled = true;
}
if (Picker.MinSpan.HasValue && Picker.TStartDate.HasValue && Picker.TEndDate == null
&& dt - Picker.TStartDate >= TimeSpan.Zero && dt - Picker.TStartDate < Picker.MinSpan)
{
classes.Add("disabled");
disabled = true;
}
if (Picker.MaxSpan.HasValue && Picker.TStartDate.HasValue && Picker.TEndDate == null
&& dt - Picker.TStartDate > Picker.MaxSpan)
{
classes.Add("off");
classes.Add("disabled");
disabled = true;
}
// Don't allow selection of date if a custom function decides it's invalid
if (await IsDayDisabled(dt))
{
classes.Add("disabled");
disabled = true;
}
// Highlight the currently selected start date
if (dt.ToString("yyyy-MM-dd") == Picker.TStartDate?.ToString("yyyy-MM-dd"))
{
classes.Add("active");
classes.Add("start-date");
}
// Highlight the currently selected end date
if (Picker.TEndDate != null && dt.ToString("yyyy-MM-dd") == Picker.TEndDate?.ToString("yyyy-MM-dd"))
{
classes.Add("active");
classes.Add("end-date");
}
// Highlight dates in-between the selected dates
if (Picker.TEndDate != null && dt > Picker.TStartDate && dt < Picker.TEndDate)
{
classes.Add("in-range");
}
// Apply custom classes for this date
if (Picker.CustomDateFunction != null)
{
classes.Add(await GetCustomDateClass(dt));
}
// Highlight dates in-between the selected dates when hover
if ((dt > Picker.TStartDate && dt < Picker.HoverDate) || dt.Date == Picker.HoverDate?.Date)
{
classes.Add("in-range");
}
if (!disabled)
{
classes.Add("available");
}
day.Disabled = disabled;
day.ClassNames = string.Join(" ", classes.Distinct());
}
private async Task<bool> IsDayDisabled(DateTimeOffset date)
{
if (Picker.DaysEnabledFunction != null)
{
return !Picker.DaysEnabledFunction(date);
}
else if (Picker.DaysEnabledFunctionAsync != null)
{
return !await Picker.DaysEnabledFunctionAsync(date);
}
return false;
}
private async Task<string> GetCustomDateClass(DateTimeOffset date)
{
if (Picker.CustomDateFunction == null) return string.Empty;
var customFunctionResult = Picker.CustomDateFunction(date);
return customFunctionResult switch
{
string className => className ?? string.Empty,
bool addName => addName ? Picker.CustomDateClass ?? string.Empty : string.Empty,
Task<string> task => await task,
Task<bool> task => await task ? Picker.CustomDateClass ?? string.Empty : string.Empty,
Task<object> task => await task switch
{
string className => className ?? string.Empty,
bool addName => addName ? Picker.CustomDateClass ?? string.Empty : string.Empty,
_ => string.Empty
},
_ => string.Empty
};
}
}
public class CalendarItem
{
public SideType Side { get; set; }
public DateTimeOffset Day { get; set; }
public Action Hover { get; set; }
public Action Click { get; set; }
public string ClassNames { get; set; }
public bool Disabled { get; set; }
public bool OutOfRange { get; set; }
}
}
================================================
FILE: BlazorDateRangePicker/DateRange.cs
================================================
/**
* author: Sergey Zaikin zaikinsr@yandex.ru
* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using System;
namespace BlazorDateRangePicker
{
public class DateRange
{
public DateTimeOffset Start { get; set; }
public DateTimeOffset End { get; set; }
}
}
================================================
FILE: BlazorDateRangePicker/DateRangePicker.razor
================================================
@*
* author: Sergey Zaikin zaikinsr@yandex.ru
* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*@
@if (PickerTemplate == null && Inline != true)
{
<input id="@Id" type="text" @attributes="CombinedAttributes" value="@FormattedRange" @oninput="OnTextInput" @onfocusin="Open" @onfocusout="LostFocus" />
}
else if (PickerTemplate != null)
{
@PickerTemplate(this)
}
@{ RenderFragment picker =
@<div class="daterangepicker-visibility-@(Inline == true || Visible ? "visible" : "hidden")">
<div id="@ContainerId" class="daterangepicker @RootStyles">
<div class="ranges">
@if (Ranges != null && Ranges.Any())
{
<ul>
@foreach (var range in Ranges)
{
<li class="@(range.Key == ChosenLabel ? "active" : "")" @onclick="@(args => ClickRange(args, range.Key))">@range.Key</li>
}
@if (ShowCustomRangeLabel == true)
{
<li class="@(CustomRangeLabel == ChosenLabel ? "active" : "")" @onclick="@(args => ClickRange(args, CustomRangeLabel))">@CustomRangeLabel</li>
}
</ul>
}
</div>
<CascadingValue Value="this">
<div class="drp-calendar left @(ShowOnlyOneCalendar == true ? "single" : "")">
<div class="calendar-table">
<Calendar Side="@SideType.Left"
CustomDayNames="@CustomDayNames"
CalendarData="@LeftCalendar"
OnMonthChanged="LeftMonthChanged"
OnClickDate="ClickDate"
OnHoverDate="OnHoverDate" />
</div>
@if (TimePicker == true)
{
<div class="calendar-time">
<TimePicker Side="@SideType.Left" Day="TStartDate" TimePicker24Hour="TimePicker24Hour"
Time="StartTime" TimeChanged="StartTimeChanged" />
</div>
}
</div>
@if (ShowOnlyOneCalendar != true)
{
<div class="drp-calendar right">
<div class="calendar-table">
<Calendar Side="@SideType.Right"
CustomDayNames="@CustomDayNames"
CalendarData="@RightCalendar"
OnMonthChanged="RightMonthChanged"
OnClickDate="ClickDate"
OnHoverDate="OnHoverDate" />
</div>
@if (TimePicker == true)
{
<div class="calendar-time">
<TimePicker Side="@SideType.Right" Day="TEndDate" TimePicker24Hour="TimePicker24Hour"
Time="EndTime" TimeChanged="EndTimeChanged" />
</div>
}
</div>
}
</CascadingValue>
<div class="drp-buttons">
@if (ButtonsTemplate == null)
{
<span class="drp-selected"></span>
<button class="cancelBtn @ButtonClasses @CancelButtonClasses" @onclick="ClickCancel" type="button">@CancelLabel</button>
<button class="applyBtn @ButtonClasses @ApplyButtonClasses" @onclick="ClickApply" disabled="@(TStartDate == null || TEndDate == null)" type="button">@ApplyLabel</button>
}
else
{
@ButtonsTemplate(this)
}
</div>
</div>
</div>;
}
@if(Render == true)
{
@if(Container == null)
{
@picker
}
else
{
Container.SetContent(picker);
}
}
================================================
FILE: BlazorDateRangePicker/DateRangePicker.razor.cs
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace BlazorDateRangePicker
{
public partial class DateRangePicker : ComponentBase, IConfigurableOptions
{
[Inject]
protected IJSRuntime JSRuntime { get; set; }
[Inject]
protected IServiceProvider ServiceProvider { get; set; }
/// <summary>
/// Guid for container id used for JSInterop
/// </summary>
public string ContainerId { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// Id for input field used for JSInterop
/// </summary>
[Parameter]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string ParentId => Id;
public delegate (bool startDateParsed, bool endDateParsed) DateParsingDelegate(string value, out DateTimeOffset startDate, out DateTimeOffset endDate);
/// <summary>
/// Attach a named properties config object to this instance of datepicker
/// </summary>
[Parameter]
public string Config { get; set; }
private Dictionary<string, object> ConfigAttributes { get; set; }
protected private Dictionary<string, object> CombinedAttributes
{
get
{
var combined = new Dictionary<string, object>();
if (ConfigAttributes != null)
{
foreach (var attr in ConfigAttributes)
{
combined[attr.Key] = attr.Value;
}
}
if (Attributes != null)
{
foreach (var attr in Attributes)
{
combined[attr.Key] = attr.Value;
}
}
return combined;
}
}
/// <summary>
/// Picker positioning container
/// </summary>
[Parameter]
public PickerContainer Container { get; set; }
/// <summary>
/// Custom picker input template
/// </summary>
[Parameter]
public RenderFragment<DateRangePicker> PickerTemplate { get; set; }
/// <summary>
/// Custom picker buttons template
/// </summary>
[Parameter]
public RenderFragment<DateRangePicker> ButtonsTemplate { get; set; }
/// <summary>
/// Custom picker input template
/// </summary>
[Parameter]
public RenderFragment<CalendarItem> DayTemplate { get; set; }
/// <summary>
/// Picker popup visibility. Use Open() instead.
/// </summary>
[Parameter]
public bool Visible { get; set; }
public DateTimeOffset? TStartDate { get; set; }
[Parameter]
public EventCallback<DateTimeOffset?> StartDateChanged { set; get; }
public DateTimeOffset? TEndDate { get; set; }
[Parameter]
public EventCallback<DateTimeOffset?> EndDateChanged { set; get; }
/// <summary>
/// Triggered when the apply button is clicked, or when a predefined range is clicked
/// </summary>
[Parameter]
public EventCallback<DateRange> OnRangeSelect { get; set; }
/// <summary>
/// Triggered when the picker reset by user
/// </summary>
[Parameter]
public EventCallback OnReset { get; set; }
/// <summary>An event that is invoked when the DatePicker is opened.</summary>
[Parameter]
public EventCallback OnOpened { get; set; }
/// <summary>An event that is invoked when the DatePicker is closed.</summary>
[Parameter]
public EventCallback OnClosed { get; set; }
/// <summary>An event that is invoked on backdrop click (false) or cancel button click (true).</summary>
[Parameter]
public EventCallback<bool> OnCancel { get; set; }
/// <summary>An event that is invoked when left or right calendar's month changed.</summary>
[Parameter]
public EventCallback OnMonthChanged { get; set; }
/// <summary>An event that is invoked when left or right calendar's month changed.</summary>
[Parameter]
public EventCallback<CancellationToken> OnMonthChangedAsync { get; set; }
/// <summary>An event that is invoked when StartDate is selected</summary>
[Parameter]
public EventCallback<DateTimeOffset> OnSelectionStart { get; set; }
/// <summary>An event that is invoked when EndDate is selected but before apply button is clicked</summary>
[Parameter]
public EventCallback<DateTimeOffset> OnSelectionEnd { get; set; }
/// <summary>
/// An event that is invoked when the StartDate is changed when TimePicker is enabled
/// </summary>
[Parameter]
public EventCallback<TimeSpan> OnStartTimeChanged { set; get; }
/// <summary>
/// An event that is invoked when the EndDate is changed when TimePicker is enabled
/// </summary>
[Parameter]
public EventCallback<TimeSpan> OnEndTimeChanged { set; get; }
private DateParsingDelegate ParseFunction => CustomParseFunction ?? TryParseDates;
public CalendarType LeftCalendar { get; set; }
public CalendarType RightCalendar { get; set; }
public string ChosenLabel { get; private set; }
internal bool CalendarsVisible { get; set; }
internal bool Loading { get; set; }
public DateTimeOffset? HoverDate { get; set; }
private string EditText { get; set; }
private TimeSpan StartTime { get; set; }
private TimeSpan EndTime { get; set; }
public bool Render { get; set; }
private Task<IJSObjectReference> _module;
private readonly string ImportPath = $"./_content/BlazorDateRangePicker/clickAndPositionHandler.js?v=" +
typeof(DateRangePicker).Assembly.GetName().Version.ToString();
private Task<IJSObjectReference> Module => _module ??= JSRuntime.InvokeAsync<IJSObjectReference>("import", ImportPath).AsTask();
protected override void OnInitialized()
{
var configs = ServiceProvider.GetServices<DateRangePickerConfig>();
var config = configs?.FirstOrDefault();
if (!string.IsNullOrEmpty(Config) && configs.Any(c => c.Name == Config))
{
config = configs.First(c => c.Name == Config);
}
config ??= new DateRangePickerConfig();
config.CopyProperties(this);
ConfigAttributes = config.Attributes;
if (string.IsNullOrEmpty(DateFormat))
{
DateFormat = Culture.DateTimeFormat.ShortDatePattern;
}
if (!TimePicker24Hour.HasValue)
{
TimePicker24Hour = !Culture.DateTimeFormat.LongTimePattern.EndsWith("tt");
}
StartTime = TStartDate.HasValue
? TStartDate.Value.TimeOfDay
: InitialStartTime ?? TimeSpan.Zero;
EndTime = TEndDate.HasValue
? TEndDate.Value.TimeOfDay
: InitialEndTime ?? TimeSpan.FromDays(1).Add(TimeSpan.FromTicks(-1));
if (SingleDatePicker == true && TimePicker == false && !AutoApply.HasValue) AutoApply = true;
if (SingleDatePicker == true && !ShowOnlyOneCalendar.HasValue) ShowOnlyOneCalendar = true;
if (!FirstDayOfWeek.HasValue)
{
FirstDayOfWeek = Culture.DateTimeFormat.FirstDayOfWeek;
}
if (Inline == true) Prerender = true;
Render = Prerender == true;
LeftCalendar = new CalendarType(this, SideType.Left);
RightCalendar = new CalendarType(this, SideType.Right);
TStartDate = StartDate?.Date.Add(StartTime);
TEndDate = EndDate?.Date.Add(EndTime);
}
protected override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && Prerender == true) return AdjustCalendars();
return Task.CompletedTask;
}
public override async Task SetParametersAsync(ParameterView parameters)
{
if (parameters.TryGetValue(nameof(EndDate), out DateTimeOffset? endDate) && endDate != EndDate)
{
TEndDate = endDate;
}
if (parameters.TryGetValue(nameof(StartDate), out DateTimeOffset? startDate) && startDate != StartDate)
{
TStartDate = startDate;
var singleDatePicker = parameters.TryGetValue(nameof(SingleDatePicker), out bool? enabled) && enabled == true;
if (SingleDatePicker == true || singleDatePicker)
{
EndDate = TStartDate;
TEndDate = TStartDate;
}
}
if (parameters.TryGetValue(nameof(Culture), out CultureInfo culture))
{
if (!parameters.TryGetValue(nameof(DateFormat), out string _))
DateFormat = culture.DateTimeFormat.ShortDatePattern;
if (!parameters.TryGetValue(nameof(TimePicker24Hour), out bool? _))
TimePicker24Hour = culture.DateTimeFormat.LongTimePattern.EndsWith("tt");
if (!parameters.TryGetValue(nameof(FirstDayOfWeek), out DayOfWeek? _))
FirstDayOfWeek = culture.DateTimeFormat.FirstDayOfWeek;
}
if (LeftCalendar != null && RightCalendar != null && FirstDayOfWeek.HasValue && LeftCalendar.FirstDayOfWeek != FirstDayOfWeek)
{
LeftCalendar.FirstDayOfWeek = FirstDayOfWeek.Value;
RightCalendar.FirstDayOfWeek = FirstDayOfWeek.Value;
}
await base.SetParametersAsync(parameters);
}
protected override async Task OnParametersSetAsync()
{
if (TimePicker == true && AutoApply == true) AutoApply = false;
await LeftCalendar.CalculateCalendar();
await RightCalendar.CalculateCalendar();
}
public string FormattedRange
{
get
{
if (!string.IsNullOrEmpty(EditText))
{
return EditText;
}
if (SingleDatePicker == true && TStartDate != null)
{
return $"{TStartDate.Value.ToString(DateFormat, Culture)}";
}
if (TStartDate != null && TEndDate != null)
{
return $"{TStartDate.Value.ToString(DateFormat, Culture)} - " +
$"{TEndDate.Value.ToString(DateFormat, Culture)}";
}
else
{
return string.Empty;
}
}
}
private string RootStyles
{
get
{
var result = new List<string>();
if (Ranges?.Count > 0) { result.Add("show-ranges"); }
if (AutoApply == true) { result.Add("auto-apply"); }
if (Loading == true) { result.Add("loading"); }
if (Ranges == null || Ranges.Count == 0 || AlwaysShowCalendars == true || CalendarsVisible)
{
result.Add("show-calendar");
}
if (Inline != true)
{
if (Drops == DropsType.Up) { result.Add("drop-up"); }
result.Add($"opens{Enum.GetName(typeof(SideType), Opens).ToLower()}");
}
else
{
result.Add("inline");
}
return string.Join(" ", result);
}
}
public virtual Task OnTextInput(ChangeEventArgs e)
{
EditText = e.Value.ToString();
(bool startDateParsed, bool endDateParsed) = ParseFunction(EditText, out DateTimeOffset startDate, out DateTimeOffset endDate);
if (startDateParsed && startDate < MinDate)
{
startDate = MinDate.Value.Date;
}
var maxDate = MaxDate;
if (MaxSpan.HasValue)
{
var maxLimit = startDate.Add(MaxSpan.Value).AddTicks(-1);
if (!maxDate.HasValue || maxLimit < maxDate)
{
maxDate = maxLimit;
}
}
var minDate = MinDate;
if (MinSpan.HasValue)
{
var minLimit = startDate.Add(MinSpan.Value);
if (!minDate.HasValue || minLimit > minDate)
{
minDate = minLimit;
}
}
if (endDateParsed)
{
if (endDate > maxDate) endDate = maxDate.Value.Date;
if (endDate < minDate) endDate = minDate.Value.Date;
}
if (startDateParsed && SingleDatePicker == true)
{
if (startDate.TimeOfDay == TimeSpan.Zero) startDate = SafeSetStartTime(startDate);
TStartDate = startDate;
TEndDate = startDate;
EditText = null;
return ClickApply(null);
}
else if (startDateParsed && endDateParsed && startDate <= endDate
&& (!minDate.HasValue || startDate >= MinDate)
&& (!maxDate.HasValue || endDate <= MaxDate))
{
if (startDate.TimeOfDay == TimeSpan.Zero) startDate = SafeSetStartTime(startDate);
if (endDate.TimeOfDay == TimeSpan.Zero) endDate = SafeSetEndTime(endDate);
TStartDate = startDate;
TEndDate = endDate;
EditText = null;
return ClickApply(null);
}
else if (string.IsNullOrEmpty(EditText) && ResetOnClear == true)
{
EditText = null;
return Reset();
}
return Task.CompletedTask;
}
private (bool startDateParsed, bool endDateParsed) TryParseDates(string value, out DateTimeOffset startDate, out DateTimeOffset endDate)
{
var dateStrings = value.Split('-').Select(s => s.Trim()).ToList();
if (dateStrings.Count != 2)
{
dateStrings = [value, string.Empty];
}
var startDateParsed = DateTimeOffset.TryParseExact(dateStrings[0], DateFormat, Culture,
System.Globalization.DateTimeStyles.AssumeUniversal, out startDate);
var endDateParsed = DateTimeOffset.TryParseExact(dateStrings[1], DateFormat, Culture,
System.Globalization.DateTimeStyles.AssumeUniversal, out endDate);
return (startDateParsed, endDateParsed);
}
public void LostFocus(FocusEventArgs _)
{
EditText = null;
}
public virtual async Task Reset()
{
TStartDate = null;
TEndDate = null;
await ClickApply(null);
await OnReset.InvokeAsync(null);
}
private Task ClickRange(MouseEventArgs e, string label)
{
ChosenLabel = label;
if (label == CustomRangeLabel)
{
CalendarsVisible = true;
return Task.CompletedTask;
}
else
{
var dates = Ranges[label];
if (TimePicker == true)
{
StartTime = dates.Start.TimeOfDay;
EndTime = dates.End.TimeOfDay;
}
TStartDate = SafeSetStartTime(dates.Start);
TEndDate = SafeSetEndTime(dates.End.Date);
if (AlwaysShowCalendars != true)
{
CalendarsVisible = false;
}
return ClickApply(e);
}
}
private Task LeftMonthChanged(DateTimeOffset date)
{
var leftMonth = date;
var rightMonth = LinkedCalendars == true
? date.AddMonths(1)
: (DateTimeOffset?)null;
return MonthChanged(leftMonth, rightMonth);
}
private Task RightMonthChanged(DateTimeOffset date)
{
var rightMonth = date;
var leftMonth = LinkedCalendars == true
? date.AddMonths(-1)
: (DateTimeOffset?)null;
return MonthChanged(leftMonth, rightMonth);
}
private CancellationTokenSource RunningTaskToken;
private async Task MonthChanged(DateTimeOffset? leftDate, DateTimeOffset? rightDate)
{
Loading = true;
if (leftDate.HasValue)
{
await LeftCalendar.ChangeMonth(leftDate.Value);
}
if (rightDate.HasValue)
{
await RightCalendar.ChangeMonth(rightDate.Value);
}
if (RunningTaskToken != null)
{
RunningTaskToken.Cancel();
RunningTaskToken.Dispose();
RunningTaskToken = null;
}
RunningTaskToken = new CancellationTokenSource();
var cts = RunningTaskToken;
await OnMonthChanged.InvokeAsync(null);
var task = OnMonthChangedAsync.InvokeAsync(RunningTaskToken.Token);
await task;
if (!cts.IsCancellationRequested)
{
Loading = false;
StateHasChanged();
}
}
private async Task StartTimeChanged(TimeSpan start)
{
StartTime = start;
TStartDate = TStartDate.HasValue ? SafeSetStartTime(TStartDate.Value) : null;
await OnStartTimeChanged.InvokeAsync(start);
}
private async Task EndTimeChanged(TimeSpan end)
{
EndTime = end;
TEndDate = TEndDate.HasValue ? SafeSetEndTime(TEndDate.Value) : null;
await OnEndTimeChanged.InvokeAsync(end);
}
public virtual async Task ClickDate(DateTimeOffset date)
{
HoverDate = null;
if (TEndDate.HasValue || TStartDate == null || date.Date.Add(EndTime) < TStartDate)
{
// picking start
TEndDate = null;
TStartDate = SafeSetStartTime(date);
await OnSelectionStart.InvokeAsync(TStartDate.Value);
}
else
{
// picking end
TEndDate = SafeSetEndTime(date);
await OnSelectionEnd.InvokeAsync(TEndDate.Value);
if (AutoApply == true)
{
await ClickApply(null);
}
}
if (SingleDatePicker == true)
{
TStartDate = SafeSetStartTime(date);
TEndDate = TStartDate;
if (AutoApply == true) await ClickApply(null);
}
await LeftCalendar.CalculateCalendar();
await RightCalendar.CalculateCalendar();
}
private DateTimeOffset SafeSetStartTime(DateTimeOffset date) => SafeSetTime(date, true);
private DateTimeOffset SafeSetEndTime(DateTimeOffset date) => SafeSetTime(date, false);
private DateTimeOffset SafeSetTime(DateTimeOffset date, bool startTime)
{
var time = TimePicker == true
? startTime ? StartTime : EndTime
: startTime ? TimeSpan.Zero : TimeSpan.FromDays(1).Add(TimeSpan.FromTicks(-1));
var isFirstDay = date.Day == 1 && date.Year == 0001 && date.Month == 1;
var isLastDay = date.Day == 31 && date.Year == 9999 && date.Month == 12;
if (isFirstDay)
{
var offset = new DateTimeOffset(date.Date.AddDays(1)).Offset;
return date.Date.Add(time < offset ? time + offset : time);
}
else if (isLastDay)
{
var offset = new DateTimeOffset(date.Date.AddDays(-1)).Offset;
return date.Date.Add(time - offset > TimeSpan.FromDays(1) ? time + offset : time);
}
else
{
return date.Date.Add(time);
}
}
private async Task OnHoverDate(DateTimeOffset date)
{
if (!TEndDate.HasValue)
{
HoverDate = date;
await LeftCalendar.CalculateCalendar();
await RightCalendar.CalculateCalendar();
}
}
public async Task ClickApply(MouseEventArgs e)
{
await Close();
StartDate = TStartDate;
await StartDateChanged.InvokeAsync(TStartDate);
EndDate = TEndDate;
await EndDateChanged.InvokeAsync(TEndDate);
if (TStartDate.HasValue && TEndDate.HasValue)
{
await OnRangeSelect.InvokeAsync(new DateRange
{
Start = TStartDate.Value,
End = TEndDate.Value
});
}
}
public async Task ClickCancel(MouseEventArgs e)
{
TStartDate = StartDate;
TEndDate = EndDate;
HoverDate = null;
await Close();
await OnCancel.InvokeAsync(e != null);
}
/// <summary>
/// Show picker popup
/// </summary>
public async Task Open()
{
Render = true;
await Task.Yield();
if (Visible) return;
StartTime = TStartDate.HasValue
? TStartDate.Value.TimeOfDay
: InitialStartTime ?? TimeSpan.Zero;
EndTime = TEndDate.HasValue
? TEndDate.Value.TimeOfDay
: InitialEndTime ?? TimeSpan.FromDays(1).Add(TimeSpan.FromTicks(-1));
var selectedRange = Ranges?.FirstOrDefault(r =>
r.Value.Start.Date == TStartDate?.Date &&
r.Value.End.Date == TEndDate?.Date);
if (selectedRange?.Value != null)
{
ChosenLabel = selectedRange.Value.Key;
if (AlwaysShowCalendars != true) CalendarsVisible = false;
}
else if (CalendarsVisible || AlwaysShowCalendars == true)
{
ChosenLabel = CustomRangeLabel;
CalendarsVisible = true;
}
var module = await Module;
await module.InvokeVoidAsync("addClickOutsideEvent", ContainerId, Id, DotNetObjectReference.Create(this));
await module.InvokeVoidAsync("getPickerPosition", ContainerId, Id,
Enum.GetName(typeof(DropsType), Drops).ToLower(), Enum.GetName(typeof(SideType), Opens).ToLower());
Visible = true;
await OnOpened.InvokeAsync(null);
if (AutoAdjustCalendars == true || Prerender != true) await AdjustCalendars();
}
public virtual async Task AdjustCalendars()
{
Prerender = true;
var newLeftMonth = TStartDate ?? DateTime.Today;
var newRightMonth = LinkedCalendars == true
? newLeftMonth.AddMonths(1)
: (TEndDate ?? newLeftMonth.AddMonths(1));
if (newLeftMonth.Month == newRightMonth.Month
&& newLeftMonth.Year == newRightMonth.Year)
{
if (newRightMonth < DateTime.MaxValue.AddMonths(-1))
{
newRightMonth = newRightMonth.AddMonths(1);
}
}
var needAdjust =
LeftCalendar?.Month.Month != newLeftMonth.Month
|| LeftCalendar?.Month.Year != newLeftMonth.Year
|| RightCalendar?.Month.Month != newRightMonth.Month
|| RightCalendar?.Month.Year != newRightMonth.Year;
if (needAdjust)
{
await MonthChanged(newLeftMonth, newRightMonth);
}
}
/// <summary>
/// Toggle picker popup state
/// </summary>
public async Task Toggle()
{
if (Visible) await Close();
else await Open();
}
/// <summary>
/// Close picker popup
/// </summary>
public async Task Close()
{
await LeftCalendar.CalculateCalendar();
await RightCalendar.CalculateCalendar();
Visible = false;
await OnClosed.InvokeAsync(null);
}
/// <summary>
/// JSInvokable callback to handle outside click
/// </summary>
[JSInvokable]
public virtual async Task InvokeClickOutside()
{
if (Visible && CloseOnOutsideClick == true)
{
await ClickCancel(null);
StateHasChanged();
}
}
public async ValueTask DisposeAsync()
{
if (_module != null)
{
var module = await _module;
await module.DisposeAsync();
}
}
}
}
================================================
FILE: BlazorDateRangePicker/DateRangePicker.razor.css
================================================
.daterangepicker {
position: fixed;
color: inherit;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ddd;
width: 278px;
max-width: none;
padding: 0;
margin-top: 7px;
top: 0px;
left: 0px;
right: auto;
z-index: 3001;
font-family: arial;
font-size: 15px;
line-height: 1em;
}
.daterangepicker:before, .daterangepicker:after {
position: absolute;
display: inline-block;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker:before {
top: -7px;
border-right: 7px solid transparent;
border-left: 7px solid transparent;
border-bottom: 7px solid #ccc;
}
.daterangepicker:after {
top: -6px;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
}
.daterangepicker.inline:before, .daterangepicker.inline:after {
content: none;
}
.daterangepicker.inline {
position: inherit;
display: inline-block;
}
.daterangepicker.opensleft:before {
right: 9px;
}
.daterangepicker.opensleft:after {
right: 10px;
}
.daterangepicker.openscenter:before {
left: 0;
right: 0;
width: 0;
margin-left: auto;
margin-right: auto;
}
.daterangepicker.openscenter:after {
left: 0;
right: 0;
width: 0;
margin-left: auto;
margin-right: auto;
}
.daterangepicker.opensright:before {
left: 9px;
}
.daterangepicker.opensright:after {
left: 10px;
}
.daterangepicker.drop-up {
margin-top: -7px;
}
.daterangepicker.drop-up:before {
top: initial;
bottom: -7px;
border-bottom: initial;
border-top: 7px solid #ccc;
}
.daterangepicker.drop-up:after {
top: initial;
bottom: -6px;
border-bottom: initial;
border-top: 6px solid #fff;
}
.daterangepicker.single .daterangepicker .ranges, .daterangepicker.single .drp-calendar {
float: none;
}
.daterangepicker.single .drp-selected {
display: none;
}
.daterangepicker.show-calendar .drp-calendar {
display: block;
}
.daterangepicker.show-calendar .drp-buttons {
display: block;
}
.daterangepicker.auto-apply .drp-buttons {
display: none;
}
.daterangepicker .drp-calendar {
display: none;
max-width: 270px;
}
.daterangepicker .drp-calendar.left {
padding: 8px 0 8px 8px;
}
.daterangepicker .drp-calendar.right {
padding: 8px;
}
.daterangepicker .drp-calendar.single .calendar-table {
border: none;
}
.daterangepicker .calendar-table {
border: 1px solid #fff;
border-radius: 4px;
background-color: #fff;
}
.daterangepicker .calendar-time {
text-align: center;
margin: 4px auto 0 auto;
line-height: 30px;
position: relative;
}
.daterangepicker .drp-buttons {
clear: both;
text-align: right;
padding: 8px;
border-top: 1px solid #ddd;
display: none;
line-height: 12px;
vertical-align: middle;
}
.daterangepicker .drp-selected {
display: inline-block;
font-size: 12px;
padding-right: 8px;
}
.daterangepicker .drp-buttons .btn {
margin-left: 8px;
font-size: 12px;
font-weight: bold;
padding: 4px 8px;
}
.daterangepicker.show-ranges.single.rtl .drp-calendar.left {
border-right: 1px solid #ddd;
}
.daterangepicker.show-ranges.single.ltr .drp-calendar.left {
border-left: 1px solid #ddd;
}
.daterangepicker.show-ranges.rtl .drp-calendar.right {
border-right: 1px solid #ddd;
}
.daterangepicker.show-ranges.ltr .drp-calendar.left {
border-left: 1px solid #ddd;
}
.daterangepicker .ranges {
float: none;
text-align: left;
margin: 0;
}
.daterangepicker.show-calendar .ranges {
margin-top: 8px;
}
.daterangepicker .ranges ul {
list-style: none;
margin: 0 auto;
padding: 0;
width: 100%;
}
.daterangepicker .ranges li {
font-size: 12px;
padding: 8px 12px;
cursor: pointer;
}
.daterangepicker .ranges li:hover {
background-color: #eee;
}
.daterangepicker .ranges li.active {
background-color: #08c;
color: #fff;
}
.daterangepicker-visibility-hidden {
visibility: hidden;
}
.daterangepicker-visibility-visible {
visibility: visible;
}
/* Larger Screen Styling */
@media (min-width: 564px) {
.daterangepicker {
width: auto;
}
.daterangepicker .ranges ul {
width: 140px;
}
.daterangepicker.single .ranges ul {
width: 100%;
}
.daterangepicker.single .drp-calendar.left {
clear: none;
}
.daterangepicker.single .ranges, .daterangepicker.single .drp-calendar {
float: left;
}
.daterangepicker {
direction: ltr;
text-align: left;
}
.daterangepicker .drp-calendar.left {
clear: left;
margin-right: 0;
}
.daterangepicker .drp-calendar.left .calendar-table {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.daterangepicker .drp-calendar.right {
margin-left: 0;
}
.daterangepicker .drp-calendar.right .calendar-table {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.daterangepicker .drp-calendar.left .calendar-table {
padding-right: 8px;
}
.daterangepicker .ranges, .daterangepicker .drp-calendar {
float: left;
}
}
@media (min-width: 730px) {
.daterangepicker .ranges {
width: auto;
}
.daterangepicker .ranges {
float: left;
}
.daterangepicker.rtl .ranges {
float: right;
}
.daterangepicker .drp-calendar.left {
clear: none !important;
}
}
================================================
FILE: BlazorDateRangePicker/DateRangePickerConfig.cs
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
namespace BlazorDateRangePicker
{
public partial class DateRangePickerConfig : IConfigurableOptions
{
public DateRangePickerConfig()
{
// Set default values
ButtonClasses = "btn btn-sm";
ApplyButtonClasses = "btn-primary";
CancelButtonClasses = "btn-default";
ApplyLabel = "Apply";
CancelLabel = "Cancel";
CustomRangeLabel = "Custom Range";
WeekAbbreviation = string.Empty;
ShowDropdowns = true;
ShowCustomRangeLabel = true;
Inline = false;
CloseOnOutsideClick = true;
AutoAdjustCalendars = true;
ResetOnClear = true;
TimePicker = false;
TimePickerSeconds = false;
Prerender = true;
TimePickerIncrement = 1;
Culture = System.Globalization.CultureInfo.CurrentCulture;
Opens = SideType.Right;
Drops = DropsType.Down;
CustomDateFunction = _ => false;
}
}
}
================================================
FILE: BlazorDateRangePicker/DateRangePickerExtensions.cs
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using System;
using Microsoft.Extensions.DependencyInjection;
namespace BlazorDateRangePicker
{
public static class DateRangePickerExtensions
{
/// <summary>
/// Adds a singleton <see cref="DateRangePickerConfig"/> instance to the DI
/// </summary>
public static IServiceCollection AddDateRangePicker(this IServiceCollection services,
DateRangePickerConfig configuration,
string configName = null)
{
ArgumentNullException.ThrowIfNull(configuration);
configuration.Name = configName;
services.AddSingleton(configuration);
return services;
}
/// <summary>
/// Adds a singleton <see cref="DateRangePickerConfig"/> instance to the DI
/// </summary>
public static IServiceCollection AddDateRangePicker(this IServiceCollection services,
Action<DateRangePickerConfig> configure,
string configName = null)
{
ArgumentNullException.ThrowIfNull(configure);
var options = new DateRangePickerConfig();
configure(options);
return AddDateRangePicker(services, options, configName);
}
}
}
================================================
FILE: BlazorDateRangePicker/Enums.cs
================================================
/**
* author: Sergey Zaikin zaikinsr@yandex.ru
* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
namespace BlazorDateRangePicker
{
public enum SideType
{
Right,
Left,
Center
}
public enum DropsType
{
Down,
Up
}
}
================================================
FILE: BlazorDateRangePicker/IConfigurableOptions.cs
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using static BlazorDateRangePicker.DateRangePicker;
namespace BlazorDateRangePicker
{
internal interface IConfigurableOptions
{
/// <summary>
/// Unique name of the configuration
/// </summary>
public string Name { get; set; }
/// <summary>
/// All unmatched parameters will be passed to parent element
/// </summary>
public Dictionary<string, object> Attributes { get; set; }
/// <summary>
/// Set predefined date ranges the user can select from. Each RangeItem.Name is the label for the range, and its Start and End value representing the bounds of the range.
/// </summary>
public Dictionary<string, DateRange> Ranges { get; set; }
/// <summary>
/// Hide the apply and cancel buttons, and automatically apply a new date range as soon as two dates are clicked.
/// </summary>
public bool? AutoApply { get; set; }
/// <summary>
/// Show only a single calendar to choose one date, instead of a range picker with two calendars. The start and end dates provided to your callback will be the same single date chosen.
/// </summary>
public bool? SingleDatePicker { get; set; }
/// <summary>
/// Show only one calendar in the picker instead of two calendars.
/// </summary>
public bool? ShowOnlyOneCalendar { get; set; }
/// <summary>
/// Normally, if you use the ranges option to specify pre-defined date ranges, calendars for choosing a custom date range are not shown until the user clicks "Custom Range". When this option is set to true, the calendars for choosing a custom date range are always shown instead.
/// </summary>
public bool? AlwaysShowCalendars { get; set; }
/// <summary>
/// CSS class names that will be added to both the apply and cancel buttons.
/// </summary>
public string ButtonClasses { get; set; }
/// <summary>
/// CSS class names that will be added only to the apply button.
/// </summary>
public string ApplyButtonClasses { get; set; }
/// <summary>
/// CSS class names that will be added only to the cancel button.
/// </summary>
public string CancelButtonClasses { get; set; }
public string ApplyLabel { get; set; }
public string CancelLabel { get; set; }
public string CustomRangeLabel { get; set; }
/// <summary>
/// The beginning date of the initially selected date range.
/// </summary>
public DateTimeOffset? StartDate { get; set; }
/// <summary>
/// The end date of the initially selected date range
/// </summary>
public DateTimeOffset? EndDate { get; set; }
/// <summary>
/// Specify the format string to display dates, default is Culture.DateTimeFormat.ShortDatePattern
/// </summary>
public string DateFormat { get; set; }
/// <summary>
/// Show localized week numbers at the start of each week on the calendars.
/// </summary>
public bool? ShowWeekNumbers { get; set; }
/// <summary>
/// Show ISO week numbers at the start of each week on the calendars.
/// </summary>
public bool? ShowISOWeekNumbers { get; set; }
/// <summary>
/// When enabled, the two calendars displayed will always be for two sequential months (i.e. January and February), and both will be advanced when clicking the left or right arrows above the calendars. When disabled, the two calendars can be individually advanced and display any month/year.
/// </summary>
public bool? LinkedCalendars { get; set; }
/// <summary>
/// Show year and month select boxes above calendars to jump to a specific month and year.
/// </summary>
public bool? ShowDropdowns { get; set; }
/// <summary>
/// Displays "Custom Range" at the end of the list of predefined ranges, when the ranges option is used. This option will be highlighted whenever the current date range selection does not match one of the predefined ranges. Clicking it will display the calendars to select a new range.
/// </summary>
public bool? ShowCustomRangeLabel { get; set; }
/// <summary>
/// Inline mode
/// </summary>
public bool? Inline { get; set; }
/// <summary>
/// Whether the picker should close on outside click
/// </summary>
public bool? CloseOnOutsideClick { get; set; }
/// <summary>
/// Whether the picker should pick months based on selected range
/// </summary>
public bool? AutoAdjustCalendars { get; set; }
/// <summary> Specify the culture to display dates and text in. Default is CultureInfo.CurrentCulture.</summary>
public CultureInfo Culture { get; set; }
/// <summary>The text to display on the Week number heading</summary>
public string WeekAbbreviation { get; set; }
/// <summary>The day of the week to start from</summary>
public DayOfWeek? FirstDayOfWeek { get; set; }
/// <summary>The earliest date that can be selected, inclusive. A value of null indicates that there is no minimum date.</summary>
public DateTimeOffset? MinDate { get; set; }
/// <summary>The latest date that can be selected, inclusive. A value of null indicates that there is no maximum date.</summary>
public DateTimeOffset? MaxDate { get; set; }
/// <summary>
/// The maximum TimeSpan between the selected start and end dates. A value of null indicates that there is no limit.
/// </summary>
public TimeSpan? MaxSpan { get; set; }
/// <summary>
/// The minimum TimeSpan between the selected start and end dates. A value of null indicates that there is no limit.
/// </summary>
public TimeSpan? MinSpan { get; set; }
/// <summary>
/// Whether the picker appears aligned to the left, to the right, or centered under the HTML element it's attached to.
/// </summary>
public SideType? Opens { get; set; }
/// <summary>
/// Whether the picker appears below (default) or above the HTML element it's attached to.
/// </summary>
public DropsType? Drops { get; set; }
/// <summary>
/// A function that is passed each date in the two calendars before they are displayed, and may return true or false to indicate whether that date should be available for selection or not.
/// </summary>
public Func<DateTimeOffset, bool> DaysEnabledFunction { get; set; }
/// <summary>
/// A function that is passed each date in the two calendars before they are displayed, and may return true or false to indicate whether that date should be available for selection or not.
/// </summary>
public Func<DateTimeOffset, Task<bool>> DaysEnabledFunctionAsync { get; set; }
/// <summary>
/// String of CSS class name to apply to calendar cell when <seealso cref="CustomDateFunction"/> returns true
/// </summary>
public string CustomDateClass { get; set; }
/// <summary>
/// A function to which each date from the calendars is passed before they are displayed,
/// may return a bool value indicates whether <seealso cref="CustomDateClass"/> will be added to the cell,
/// or a string with CSS class name to add to that date's calendar cell.
/// </summary>
public Func<DateTimeOffset, object> CustomDateFunction { get; set; }
/// <summary>
/// Whether the picker should set dates to null when the user cleans the input
/// </summary>
public bool? ResetOnClear { get; set; }
/// <summary>
/// Adds select boxes to choose times in addition to dates.
/// </summary>
public bool? TimePicker { get; set; }
/// <summary>
/// Use 24-hour instead of 12-hour times, removing the AM/PM selection.
/// </summary>
public bool? TimePicker24Hour { get; set; }
/// <summary>
/// Increment of the minutes selection list for times (i.e. 30 to allow only selection of times ending in 0 or 30).
/// </summary>
public int? TimePickerIncrement { get; set; }
/// <summary>
/// Show seconds in the timePicker.
/// </summary>
public bool? TimePickerSeconds { get; set; }
/// <summary>
/// Initial time value to show in the picker before any date selected
/// </summary>
public TimeSpan? InitialStartTime { get; set; }
/// <summary>
/// Initial time value to show in the picker before any date selected
/// </summary>
public TimeSpan? InitialEndTime { get; set; }
/// <summary>
/// Prerender component html before picker opening.
/// </summary>
public bool? Prerender { get; set; }
/// <summary>List of day names to be displayed instead of those defined in the Culture</summary>
public List<string> CustomDayNames { get; set; }
/// <summary>Custom date parsing function</summary>
public DateParsingDelegate CustomParseFunction { get; set; }
/// <summary>
/// Returns time available for selection.
/// </summary>
public Func<DateTimeOffset?, Task<TimeSettings>> TimeEnabledFunction { get; set; }
}
}
================================================
FILE: BlazorDateRangePicker/PickerContainer.razor
================================================
@Content
@code{
RenderFragment Content { get; set; }
public void SetContent(RenderFragment content)
{
Content = content;
StateHasChanged();
}
}
================================================
FILE: BlazorDateRangePicker/TimePicker.razor
================================================
<select class="hourselect" @bind="Hour">
@foreach (var hour in HoursRange)
{
<option value="@hour" selected="@(Hour == hour)">@hour.ToString().PadLeft(2, '0')</option>
}
</select>
<span> : </span>
<select class="minuteselect" @bind="Minute">
@foreach (var minute in MinutesRange)
{
if (minute % Picker.TimePickerIncrement != 0) continue;
<option value="@minute" selected="@(Minute == minute)">@minute.ToString().PadLeft(2, '0')</option>
}
</select>
@if (Picker.TimePickerSeconds == true)
{
<span> : </span>
<select class="minuteselect" @bind="Second">
@foreach (var sec in SecondsRange)
{
<option value="@sec" selected="@(Second == sec)">@sec.ToString().PadLeft(2, '0')</option>
}
</select>
}
@if (Picker.TimePicker24Hour == false)
{
<span> </span>
<select class="ampmselect" @bind="AmPm">
<option value="@(AmPmEnum.AM)">AM</option>
<option value="@(AmPmEnum.PM)">PM</option>
</select>
}
================================================
FILE: BlazorDateRangePicker/TimePicker.razor.cs
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
using System.Threading.Tasks;
namespace BlazorDateRangePicker
{
public partial class TimePicker
{
[CascadingParameter] public DateRangePicker Picker { get; set; }
[Parameter] public SideType Side { get; set; }
[Parameter] public TimeSpan Time { get; set; }
[Parameter] public EventCallback<TimeSpan> TimeChanged { get; set; }
[Parameter] public DateTimeOffset? Day { get; set; }
[Parameter] public bool? TimePicker24Hour { get; set; }
private readonly IEnumerable<int> HoursRange24 = Enumerable.Range(0, 24);
private readonly IEnumerable<int> HoursRange12 = Enumerable.Range(1, 12);
private IEnumerable<int> CustomHoursRange;
protected override void OnInitialized()
{
MinutesRange = Enumerable.Range(0, 60);
SecondsRange = Enumerable.Range(0, 60);
}
protected override async Task OnParametersSetAsync()
{
if (Picker.TimeEnabledFunction != null)
{
var timeEnabled = await Picker.TimeEnabledFunction(Day);
CustomHoursRange = timeEnabled.Hours;
MinutesRange = timeEnabled.Minutes;
SecondsRange = timeEnabled.Seconds;
}
else
{
CustomHoursRange = null;
MinutesRange = Enumerable.Range(0, 60);
SecondsRange = Enumerable.Range(0, 60);
}
}
private IEnumerable<int> HoursRange => CustomHoursRange ?? (TimePicker24Hour != false ? HoursRange24 : HoursRange12);
private IEnumerable<int> MinutesRange { get; set; }
private IEnumerable<int> SecondsRange { get; set; }
private AmPmEnum AmPm
{
get => Time.Hours >= 12 ? AmPmEnum.PM : AmPmEnum.AM;
set
{
Set(h: value switch
{
AmPmEnum.AM when Time.Hours >= 12 => Time.Hours - 12,
AmPmEnum.PM when Time.Hours < 12 => Time.Hours + 12,
_ => Time.Hours
});
}
}
private int Hour
{
get
{
if (Picker.TimePicker24Hour == true) return Time.Hours;
return int.Parse(DateTime.Today.Add(Time).ToString("hh"));
}
set
{
Set(h: AmPm switch
{
AmPmEnum.AM when TimePicker24Hour == false && value >= 12 => value - 12,
AmPmEnum.PM when TimePicker24Hour == false && value < 12 => value + 12,
_ => value
});
}
}
private int Minute { get => Time.Minutes; set => Set(m: value); }
private int Second { get => Time.Seconds; set => Set(s: value); }
private void Set(int? h = null, int? m = null, int? s = null)
{
Time = TimeSpan.FromHours(h ?? Time.Hours)
+ TimeSpan.FromMinutes(m ?? Minute)
+ TimeSpan.FromSeconds(s ?? Second);
TimeChanged.InvokeAsync(Time);
}
}
public enum AmPmEnum
{
AM, PM
}
}
================================================
FILE: BlazorDateRangePicker/TimePicker.razor.css
================================================
select.hourselect, select.minuteselect, select.secondselect, select.ampmselect {
width: 50px;
margin: 0 auto;
background: #eee;
border: 1px solid #eee;
padding: 2px;
outline: 0;
font-size: 12px;
}
select.disabled {
color: #ccc;
cursor: not-allowed;
}
================================================
FILE: BlazorDateRangePicker/TimeSettings.cs
================================================
using System.Collections.Generic;
namespace BlazorDateRangePicker
{
public class TimeSettings
{
public IEnumerable<int> Hours { get; set; }
public IEnumerable<int> Minutes { get; set; }
public IEnumerable<int> Seconds { get; set; }
}
}
================================================
FILE: BlazorDateRangePicker/_Imports.razor
================================================
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Web
================================================
FILE: BlazorDateRangePicker/wwwroot/clickAndPositionHandler.js
================================================
/**
* @author: Sergey Zaikin zaikinsr@yandex.ru
* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*/
var clickAndPositionHandler = {
listeners: []
};
export function addClickOutsideEvent(elementId, parentId, dotnetHelper) {
if (clickAndPositionHandler.listeners.indexOf(elementId) > -1) return;
window.addEventListener("click", function (e) {
if ((document.getElementById(elementId) != null && !document.getElementById(elementId).contains(e.target)) &&
(document.getElementById(parentId) != null && !document.getElementById(parentId).contains(e.target)) &&
(document.getElementById(elementId).parentElement == null ||
document.getElementById(elementId).parentElement.style == null ||
window.getComputedStyle(document.getElementById(elementId).parentElement).visibility == "visible")) {
dotnetHelper.invokeMethodAsync("InvokeClickOutside");
}
});
clickAndPositionHandler.listeners.push(elementId);
};
export function getPickerPosition(elementId, parentId, drops, opens, skipAddListener) {
var resizeFunction = function () {
getPickerPosition(elementId, parentId, drops, opens, true);
};
var parentOffset = { top: 0, left: 0 },
containerTop;
var parentRightEdge = window.innerWidth;
var container = document.getElementById(elementId);
var parentEl = document.getElementById(parentId);
var element = parentEl;
if (element == null || container == null) {
window.removeEventListener('resize', resizeFunction, true);
window.removeEventListener('onwheel', resizeFunction, true);
window.removeEventListener('onmousewheel', resizeFunction, true);
window.removeEventListener('scroll', resizeFunction, true);
return;
}
if (parentEl === document.body) {
var rect = parentEl.getBoundingClientRect();
parentOffset = {
top: rect.top,
left: rect.left
};
parentRightEdge = parentEl[0].clientWidth + rect.left;
}
var elementRect = element.getBoundingClientRect();
var outerHeight = function (el) {
return el.offsetHeight;
}
var outerWidth = function (el) {
return el.offsetWidth;
}
var setStylesOnElement = function (styles, element) {
for (var prop in styles) {
element.style[prop] = styles[prop];
}
}
if (drops == 'up')
containerTop = elementRect.top - outerHeight(container) - parentOffset.top;
else
containerTop = elementRect.top + outerHeight(element) - parentOffset.top;
var containerWidth = outerWidth(container);
if (opens == 'left') {
var containerRight = parentRightEdge - elementRect.left - outerWidth(element);
if (containerWidth + containerRight > window.innerWidth) {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
right: 'auto',
left: 9 + 'px'
}, container);
} else {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
right: containerRight + 'px',
left: 'auto'
}, container);
}
} else if (opens == 'center') {
var containerLeft = elementRect.left - parentOffset.left + outerWidth(element) / 2 - containerWidth / 2;
if (containerLeft < 0) {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
right: 'auto',
left: 9 + 'px'
}, container);
} else if (containerLeft + containerWidth > window.innerWidth) {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
left: 'auto',
right: 0 + 'px'
}, container);
} else {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
left: containerLeft + 'px',
right: 'auto'
}, container);
}
} else {
var containerLeft = elementRect.left - parentOffset.left;
if (containerLeft + containerWidth > window.innerWidth) {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
left: 'auto',
right: 0 + 'px'
}, container);
} else {
setStylesOnElement({
position: 'fixed',
top: containerTop + 'px',
left: containerLeft + 'px',
right: 'auto'
}, container);
}
}
if (skipAddListener !== true) {
window.addEventListener('resize', resizeFunction, true);
window.addEventListener('onwheel', resizeFunction, true);
window.addEventListener('onmousewheel', resizeFunction, true);
window.addEventListener('scroll', resizeFunction, true);
};
}
================================================
FILE: BlazorDateRangePicker.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35716.79
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorDateRangePicker", "BlazorDateRangePicker\BlazorDateRangePicker.csproj", "{C463A3EB-E515-46C2-B520-18E964A69E32}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ClientSideApp", "Demo.ClientSideApp\Demo.ClientSideApp.csproj", "{901603F4-C51B-4B98-9E98-F85DAE6E8A2F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ServerSideApp", "Demo.ServerSideApp\Demo.ServerSideApp.csproj", "{94594133-2735-40F5-B336-9019A60E873D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Shared", "Demo.Shared\Demo.Shared.csproj", "{C643FA35-336A-4620-9153-8D4A3DBFE92C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenerators", "SourceGenerators\SourceGenerators.csproj", "{2655151C-2184-C7B9-CAB3-727E2FA0BBFC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C463A3EB-E515-46C2-B520-18E964A69E32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C463A3EB-E515-46C2-B520-18E964A69E32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C463A3EB-E515-46C2-B520-18E964A69E32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C463A3EB-E515-46C2-B520-18E964A69E32}.Release|Any CPU.Build.0 = Release|Any CPU
{901603F4-C51B-4B98-9E98-F85DAE6E8A2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{901603F4-C51B-4B98-9E98-F85DAE6E8A2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{901603F4-C51B-4B98-9E98-F85DAE6E8A2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{901603F4-C51B-4B98-9E98-F85DAE6E8A2F}.Release|Any CPU.Build.0 = Release|Any CPU
{94594133-2735-40F5-B336-9019A60E873D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94594133-2735-40F5-B336-9019A60E873D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94594133-2735-40F5-B336-9019A60E873D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94594133-2735-40F5-B336-9019A60E873D}.Release|Any CPU.Build.0 = Release|Any CPU
{C643FA35-336A-4620-9153-8D4A3DBFE92C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C643FA35-336A-4620-9153-8D4A3DBFE92C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C643FA35-336A-4620-9153-8D4A3DBFE92C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C643FA35-336A-4620-9153-8D4A3DBFE92C}.Release|Any CPU.Build.0 = Release|Any CPU
{2655151C-2184-C7B9-CAB3-727E2FA0BBFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2655151C-2184-C7B9-CAB3-727E2FA0BBFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2655151C-2184-C7B9-CAB3-727E2FA0BBFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2655151C-2184-C7B9-CAB3-727E2FA0BBFC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D897D349-9D43-44E6-A9F8-8D10BBA2DBFD}
EndGlobalSection
EndGlobal
================================================
FILE: Demo.ClientSideApp/App.razor
================================================
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(CustomDate).Assembly }">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="typeof(MainLayout)">
<h1>Page not found</h1>
<p>Sorry, but there's nothing here!</p>
</LayoutView>
</NotFound>
</Router>
================================================
FILE: Demo.ClientSideApp/Demo.ClientSideApp.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net9</TargetFramework>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.1" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BlazorDateRangePicker\BlazorDateRangePicker.csproj" />
<ProjectReference Include="..\Demo.Shared\Demo.Shared.csproj" />
</ItemGroup>
</Project>
================================================
FILE: Demo.ClientSideApp/Program.cs
================================================
using BlazorDateRangePicker;
using Demo.ClientSideApp;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped<Demo.Shared.IClipboard, Demo.Shared.BlazorClipboard>();
builder.Services.AddDateRangePicker(config =>
{
config.Attributes = new Dictionary<string, object>
{
{ "class", "form-control form-control-sm" }
};
});
await builder.Build().RunAsync();
================================================
FILE: Demo.ClientSideApp/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:51104/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Demo.ClientSideApp": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:5110/"
}
}
}
================================================
FILE: Demo.ClientSideApp/_Imports.razor
================================================
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using Demo.ClientSideApp
@using Demo.Shared.Shared
@using Demo.Shared.Pages
@using BlazorDateRangePicker
================================================
FILE: Demo.ClientSideApp/wwwroot/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>BlazorDateRangePicker</title>
<base href="/" />
<link rel="stylesheet" href="_content/Demo.Shared/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="_content/Demo.Shared/css/bootstrap/docs.min.css" />
<link rel="stylesheet" href="_content/Demo.Shared/highlight/vs.css" />
<link rel="stylesheet" href="_content/Demo.Shared/css/site.css" />
<link rel="stylesheet" href="Demo.ClientSideApp.styles.css" />
</head>
<body>
<app>
<style>
body {
background: #eff3f8;
}
.preloader {
margin: 200px auto;
}
.preloader img {
display: block;
margin-left: auto;
margin-right: auto;
}
h1 {
color: #FFF;
font-size: 16px;
letter-spacing: 1px;
font-weight: 200;
text-align: center;
}
.loader span {
width: 16px;
height: 16px;
border-radius: 50% !important;
display: inline-block;
position: absolute;
left: 50%;
margin-left: -10px;
animation: 3s infinite linear;
-webkit-animation: 3s infinite linear;
-moz-animation: 3s infinite linear;
-o-animation: 3s infinite linear;
}
.loader span:nth-child(2) {
background: #E84C3D;
animation: kiri 1.2s infinite linear;
-webkit-animation: kiri 1.2s infinite linear;
-moz-animation: kiri 1.2s infinite linear;
-o-animation: kiri 1.2s infinite linear;
}
.loader span:nth-child(3) {
background: #F1C40F;
z-index: 100;
}
.loader span:nth-child(4) {
background: #2FCC71;
animation: kanan 1.2s infinite linear;
-webkit-animation: kanan 1.2s infinite linear;
-moz-animation: kanan 1.2s infinite linear;
-o-animation: kanan 1.2s infinite linear;
}
@keyframes kanan {
0% {
-webkit-transform: translateX(20px);
}
50% {
-webkit-transform: translateX(-20px);
}
100% {
-webkit-transform: translateX(20px);
}
}
@-webkit-keyframes kanan {
0% {
-webkit-transform: translateX(20px);
}
50% {
-webkit-transform: translateX(-20px);
}
100% {
-webkit-transform: translateX(20px);
}
}
@-moz-keyframes kanan {
0% {
-moz-transform: translateX(20px);
}
50% {
-moz-transform: translateX(-20px);
}
100% {
-moz-transform: translateX(20px);
z-index: 200;
}
}
@-o-keyframes kanan {
0% {
-o-transform: translateX(20px);
}
50% {
-o-transform: translateX(-20px);
}
100% {
-o-transform: translateX(20px);
z-index: 200;
}
}
@keyframes kiri {
0% {
-webkit-transform: translateX(-20px);
}
50% {
-webkit-transform: translateX(20px);
}
100% {
-webkit-transform: translateX(-20px);
}
}
@-webkit-keyframes kiri {
0% {
-webkit-transform: translateX(-20px);
}
50% {
-webkit-transform: translateX(20px);
}
100% {
-webkit-transform: translateX(-20px);
}
}
@-moz-keyframes kiri {
0% {
-moz-transform: translateX(-20px);
z-index: 200;
}
50% {
-moz-transform: translateX(20px);
}
100% {
-moz-transform: translateX(-20px);
}
}
@-o-keyframes kiri {
0% {
-o-transform: translateX(-20px);
z-index: 200;
}
50% {
-o-transform: translateX(20px);
}
100% {
-o-transform: translateX(-20px);
}
}
</style>
<div class="preloader">
<blockquote class="blockquote text-center">
<p>Loading WebAssembly application...</p>
</blockquote>
<div class="loader">
<h1></h1>
<span></span>
<span></span>
<span></span>
</div>
</div>
</app>
<script src="_framework/blazor.webassembly.js" integrity=""></script>
<script src="_content/Demo.Shared/highlight/highlight.pack.js"></script>
<script src="_content/Demo.Shared/highlight/cshtml-razor.js"></script>
<script src="_content/Demo.Shared/highlight/highlightInterop.js"></script>
<script>
hljs.registerLanguage('cshtml-razor', window.hljsDefineCshtmlRazor);
hljs.initHighlightingOnLoad();
</script>
</body>
</html>
================================================
FILE: Demo.ServerSideApp/App.razor
================================================
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(CustomDate).Assembly }">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="typeof(MainLayout)">
<h1>Page not found</h1>
<p>Sorry, but there's nothing here!</p>
</LayoutView>
</NotFound>
</Router>
================================================
FILE: Demo.ServerSideApp/Demo.ServerSideApp.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\BlazorDateRangePicker\BlazorDateRangePicker.csproj" />
<ProjectReference Include="..\Demo.Shared\Demo.Shared.csproj" />
</ItemGroup>
</Project>
================================================
FILE: Demo.ServerSideApp/Pages/_Host.cshtml
================================================
@page "/"
@namespace Demo.ServerSideApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BlazorDateRangePicker</title>
<base href="~/" />
<link rel="stylesheet" href="_content/Demo.Shared/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="_content/Demo.Shared/css/bootstrap/docs.min.css" />
<link rel="stylesheet" href="_content/Demo.Shared/highlight/vs.css" />
<link rel="stylesheet" href="_content/Demo.Shared/css/site.css" />
<link rel="stylesheet" href="Demo.ServerSideApp.styles.css" />
</head>
<body>
<component type="typeof(App)" render-mode="Server" />
<script src="_framework/blazor.server.js"></script>
<script src="_content/Demo.Shared/highlight/highlight.pack.js"></script>
<script src="_content/Demo.Shared/highlight/cshtml-razor.js"></script>
<script src="_content/Demo.Shared/highlight/highlightInterop.js"></script>
<script>
hljs.registerLanguage('cshtml-razor', window.hljsDefineCshtmlRazor);
hljs.initHighlightingOnLoad();
</script>
</body>
</html>
================================================
FILE: Demo.ServerSideApp/Program.cs
================================================
using BlazorDateRangePicker;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Collections.Generic;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<Demo.Shared.IClipboard, Demo.Shared.BlazorClipboard>();
builder.Services.AddDateRangePicker(config =>
{
config.Attributes = new Dictionary<string, object>
{
{ "class", "form-control form-control-sm" }
};
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
================================================
FILE: Demo.ServerSideApp/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3888",
"sslPort": 44313
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Demo.ServerSideApp": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}
================================================
FILE: Demo.ServerSideApp/_Imports.razor
================================================
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using Demo.Shared
@using Demo.Shared.Shared
@using Demo.Shared.Pages
@using Demo.ServerSideApp
@using BlazorDateRangePicker
================================================
FILE: Demo.ServerSideApp/appsettings.Development.json
================================================
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
================================================
FILE: Demo.ServerSideApp/appsettings.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
================================================
FILE: Demo.Shared/BlazorClipboard.cs
================================================
using Microsoft.JSInterop;
using System.Threading;
using System.Threading.Tasks;
#nullable enable
namespace Demo.Shared
{
/// <summary>
/// Provides methods to place text on and retrieve text from the system Clipboard.
/// </summary>
public interface IClipboard
{
/// <summary>
/// Retrieves text data from the Clipboard.
/// </summary>
public Task<string?> GetTextAsync(CancellationToken cancellation = default);
/// <summary>
/// Retrieves text data from the Clipboard.
/// </summary>
public string? GetText();
/// <summary>
/// Clears the Clipboard and then adds text data to it.
/// </summary>
public Task SetTextAsync(string text, CancellationToken cancellation = default);
/// <summary>
/// Clears the Clipboard and then adds text data to it.
/// </summary>
public void SetText(string text);
}
/// <summary>
/// Construct a new instance.
/// </summary>
public class BlazorClipboard(IJSRuntime jsRuntime) : IClipboard
{
protected readonly IJSRuntime jsRuntime = jsRuntime;
/// <inheritdoc />
public virtual async Task<string?> GetTextAsync(CancellationToken cancellation = default)
{
return await jsRuntime.InvokeAsync<string>("navigator.clipboard.readText", cancellation, []);
}
/// <inheritdoc />
public virtual string? GetText()
{
return GetTextAsync().GetAwaiter().GetResult();
}
/// <inheritdoc />
public virtual async Task SetTextAsync(string text, CancellationToken cancellation = default)
{
await jsRuntime.InvokeAsync<string>("navigator.clipboard.writeText", cancellation, [text]);
}
/// <inheritdoc />
public virtual void SetText(string text)
{
SetTextAsync(text).GetAwaiter().GetResult();
}
}
}
#nullable disable
================================================
FILE: Demo.Shared/Demo.Shared.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net9</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\BlazorDateRangePicker\BlazorDateRangePicker.csproj" />
</ItemGroup>
</Project>
================================================
FILE: Demo.Shared/Pages/BothSidesSelection.razor
================================================
@page "/bothSidesSelection"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/BothSidesSelection.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Both sides selection</h3>
</div>
<p>
This example demonstrates how to enable both sides range selection by overring day click function.
</p>
<Example Text="@ExampleText">
<DateRangePicker @ref="Picker" OnMonthChanged="MonthChanged" CustomDateFunction="CustomHover" />
</Example>
@code {
DateRangePicker Picker { get; set; }
private void MonthChanged()
{
UpdateClickHandlers();
}
private string CustomHover(DateTimeOffset dt)
{
if (dt >= Picker?.HoverDate && dt < Picker?.TStartDate)
{
return "in-range";
}
return string.Empty;
}
private void UpdateClickHandlers()
{
var days = Enumerable
.Concat(Picker.LeftCalendar.Calendar, Picker.RightCalendar.Calendar)
.SelectMany(d => d);
foreach (var day in days)
{
var dayClick = day.Click;
day.Click = async () =>
{
if (Picker.TStartDate.HasValue && !Picker.TEndDate.HasValue && day.Day < Picker.TStartDate)
{
Picker.TEndDate = Picker.TStartDate;
Picker.TStartDate = day.Day;
await Picker.LeftCalendar.CalculateCalendar();
await Picker.RightCalendar.CalculateCalendar();
StateHasChanged();
}
else
{
dayClick.Invoke();
}
};
}
}
private string ExampleText = "<DateRangePicker @ref=\"Picker\" OnMonthChanged=\"MonthChanged\" CustomDateFunction=\"CustomHover\" />" +
@"
DateRangePicker Picker { get; set; }
private void MonthChanged()
{
UpdateClickHandlers();
}
private string CustomHover(DateTimeOffset dt)
{
if (dt >= Picker?.HoverDate && dt < Picker?.TStartDate)
{
" + "return \"in-range\";" + @"
}
return string.Empty;
}
private void UpdateClickHandlers()
{
var days = Enumerable
.Concat(Picker.LeftCalendar.Calendar, Picker.RightCalendar.Calendar)
.SelectMany(d => d);
foreach (var day in days)
{
var dayClick = day.Click;
day.Click = async () =>
{
if (Picker.TStartDate.HasValue && !Picker.TEndDate.HasValue && day.Day < Picker.TStartDate)
{
Picker.TEndDate = Picker.TStartDate;
Picker.TStartDate = day.Day;
await Picker.LeftCalendar.CalculateCalendar();
await Picker.RightCalendar.CalculateCalendar();
StateHasChanged();
}
else
{
dayClick.Invoke();
}
};
}
}
";
}
================================================
FILE: Demo.Shared/Pages/Container.razor
================================================
@page "/container"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Container.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Resolving positioning issues</h3>
</div>
<Example Text="@ExampleText">
<p>When the picker is placed inside absolutely positioned container position calculations may be incorrect.</p>
<p>In that case you should use <b>PickerContainer</b> component placed outside promblem node</p>
<div class="popover fade show bs-popover-right" role="tooltip" x-placement="right"
style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(120px, 330px, 0px);">
<div class="arrow" style="top: 34px;"></div>
<h3 class="popover-header">Popover title</h3>
<div class="popover-body">
<DateRangePicker Container="CustomContainer" Drops="DropsType.Up" class="form-control form-control-sm" SingleDatePicker="true" />
And here's some amazing content. It's very engaging. Right?
</div>
</div>
</Example>
<PickerContainer @ref="CustomContainer" />
@code {
PickerContainer CustomContainer { get; set; }
private string ExampleText =
"<div class=\"popover\">\n <DateRangePicker Container=\"CustomContainer\" />\n</div>\n\n" +
"<PickerContainer @ref=\"CustomContainer\" />";
}
================================================
FILE: Demo.Shared/Pages/CustomButtons.razor
================================================
@page "/customButtons"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/CustomButtons.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Custom buttons template</h3>
</div>
<p>
Override
<code class="language-plaintext highlighter-rouge">ButtonsTemplate</code>
template if you want to add additional buttons.
</p>
<Example Text="@ExampleText">
<DateRangePicker @ref="Picker" @bind-StartDate="StartDate" @bind-EndDate="EndDate">
<ButtonsTemplate>
<button class="btn btn-sm btn-outline-success" type="button">
Some button
</button>
<button class="cancelBtn btn btn-sm btn-default"
@onclick="@context.ClickCancel" type="button">
Cancel
</button>
<button class="cancelBtn btn btn-sm btn-default"
@onclick="@(e => ResetClick(e, context))" type="button">
Reset
</button>
<button class="applyBtn btn btn-sm btn-primary" @onclick="@context.ClickApply"
disabled="@(context.TStartDate == null || context.TEndDate == null)"
type="button">
Apply
</button>
</ButtonsTemplate>
</DateRangePicker>
</Example>
@code {
DateRangePicker Picker;
DateTimeOffset? StartDate { get; set; }
DateTimeOffset? EndDate { get; set; }
async Task ResetClick(MouseEventArgs e, DateRangePicker picker)
{
StartDate = null;
EndDate = null;
// Close the picker
await Picker.Close();
// Fire OnRangeSelectEvent
await Picker.OnRangeSelect.InvokeAsync(new DateRange());
}
private string ExampleText =
"<DateRangePicker @ref=\"Picker\" @bind-StartDate=\"StartDate\" @bind-EndDate=\"EndDate\">\n" +
" <ButtonsTemplate>\n" +
" <button class=\"btn btn-sm btn-outline-success\" type=\"button\">\n" +
" Some button\n" +
" </button>\n" +
" <button class=\"cancelBtn btn btn-sm btn-default\"\n" +
" @onclick=\"@context.ClickCancel\" type=\"button\">\n" +
" Cancel\n" +
" </button>\n" +
" <button class=\"cancelBtn btn btn-sm btn-default\"\n" +
" @onclick=\"@(e => ResetClick(e, context))\" type=\"button\">\n" +
" Reset\n" +
" </button>\n" +
" <button class=\"applyBtn btn btn-sm btn-primary\" @onclick=\"@context.ClickApply\"\n" +
" disabled=\"@(context.TStartDate == null || context.TEndDate == null)\"\n" +
" type=\"button\">\n" +
" Apply\n" +
" </button>\n" +
" </ButtonsTemplate>\n" +
"</DateRangePicker>\n\n" +
"@code {\n" +
" DateRangePicker Picker;\n\n" +
" DateTimeOffset? StartDate { get; set; }\n" +
" DateTimeOffset? EndDate { get; set; }\n\n" +
" async Task ResetClick(MouseEventArgs e, DateRangePicker picker)\n" +
" {\n" +
" StartDate = null;\n" +
" EndDate = null;\n" +
" // Close the picker\n" +
" await Picker.Close();\n" +
" // Fire OnRangeSelectEvent\n" +
" await Picker.OnRangeSelect.InvokeAsync(new DateRange());\n" +
" }\n" +
"}";
}
================================================
FILE: Demo.Shared/Pages/CustomClickHandler.razor
================================================
@page "/customClickHandler"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/CustomClickHandler.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>CustomClickHandler</h3>
</div>
<p>
This example demonstrates how to override day click function to build custom functionality.
</p>
<p>
In this example the start date can only be selected in the left calendar and the end date can only be selected in the right calendar.
</p>
<Example Text="@ExampleText">
<DateRangePicker @ref="Picker" OnMonthChanged="MonthChanged" />
</Example>
@code {
DateRangePicker Picker { get; set; }
private void MonthChanged()
{
UpdateClickHandlers();
}
private void UpdateClickHandlers()
{
var days = Enumerable
.Concat(Picker.LeftCalendar.Calendar, Picker.RightCalendar.Calendar)
.SelectMany(d => d);
foreach (var day in days)
{
var dayClick = day.Click;
day.Click = () =>
{
if (day.Side == SideType.Right && !Picker.TEndDate.HasValue)
{
if (day.Day > Picker.TStartDate) dayClick.Invoke();
}
else if (day.Side == SideType.Left)
{
Picker.TStartDate = null;
Picker.TEndDate = null;
dayClick.Invoke();
}
};
}
}
private string ExampleText = "<DateRangePicker @ref=\"Picker\" OnMonthChanged=\"MonthChanged\" />" +
@"
@code {
DateRangePicker Picker { get; set; }
private void MonthChanged()
{
UpdateClickHandlers();
}
private void UpdateClickHandlers()
{
var days = Enumerable
.Concat(Picker.LeftCalendar.Calendar, Picker.RightCalendar.Calendar)
.SelectMany(d => d);
foreach (var day in days)
{
var dayClick = day.Click;
day.Click = () =>
{
if (day.Side == SideType.Right && !Picker.TEndDate.HasValue)
{
if (day.Day > Picker.TStartDate) dayClick.Invoke();
}
else if (day.Side == SideType.Left)
{
Picker.TStartDate = null;
Picker.TEndDate = null;
dayClick.Invoke();
}
};
}
}
";
}
================================================
FILE: Demo.Shared/Pages/CustomDate.razor
================================================
@page "/customDate"
@using System.Threading
<style>
.dthighlight {
background-color: aquamarine !important;
}
</style>
<DateRangePicker @ref="Picker" style="width: 300px;"
LinkedCalendars="true"
AutoAdjustCalendars="false"
MinDate="DateTime.Now.AddYears(-1)"
MaxDate="DateTime.Now.AddYears(1)"
ShowDropdowns="true"
ShowWeekNumbers="true"
WeekAbbreviation="НE"
MinSpan="TimeSpan.FromDays(5)"
MaxSpan="TimeSpan.FromDays(15)"
DaysEnabledFunction="DaysEnabledFunction"
OnMonthChangedAsync="OnMonthChanged"
CustomDateFunction="CustomDateFunction"
OnSelectionStart="OnSelectionStart"
OnRangeSelect="OnRangeSelect"
@bind-StartDate="StartDate"
@bind-EndDate="EndDate">
<DayTemplate Context="dt">
D-@(dt.Day.Day)
<br/>
$ 200
</DayTemplate>
</DateRangePicker>
<hr />
<p>Start: @StartDate</p>
<p>End: @EndDate</p>
<p>Events:</p>
<ul>
@foreach (var ev in Events)
{
<li>@ev</li>
}
</ul>
<button @onclick="SetDates">set</button>
@code {
DateRangePicker Picker;
DateTimeOffset? StartDate { get; set; }
DateTimeOffset? EndDate { get; set; }
List<string> Events { get; set; } = new List<string>();
List<DateTimeOffset> DisabledDays { get; set; } = new List<DateTimeOffset>();
private bool DaysEnabledFunction(DateTimeOffset day)
{
return !DisabledDays.Any(d => d.Day == day.Day);
}
private object CustomDateFunction(DateTimeOffset day)
{
//await Task.Delay(1);
if (DisabledDays.Any(d => d.Day == day.Day - 1)) return "dthighlight";
return string.Empty;
}
private async Task OnMonthChanged(CancellationToken ct)
{
var leftMonth = Picker.LeftCalendar.Month;
var rightMonth = Picker.RightCalendar.Month;
Events.Add($"OnMonthChanged: {leftMonth:MM.yyyy} & {rightMonth:MM.yyyy}");
await Task.Delay(500, ct);
Events.Add($"Completed OnMonthChanged: {leftMonth:MM.yyyy} & {rightMonth:MM.yyyy}");
DisabledDays = new List<DateTimeOffset> {
new DateTime(leftMonth.Year, leftMonth.Month, leftMonth.Month),
new DateTime(rightMonth.Year, rightMonth.Month, rightMonth.Month)
};
}
private void OnSelectionStart(DateTimeOffset date)
{
Events.Add($"On selection start = {date}");
}
private void OnRangeSelect(DateRange range)
{
Events.Add($"On range select");
}
private void SetDates()
{
StartDate = DateTime.Now;
EndDate = DateTime.Now.AddDays(10);
}
}
================================================
FILE: Demo.Shared/Pages/CustomDay.razor
================================================
@page "/customDay"
<style>
.daterangepicker .drp-calendar {
max-width: 298px;
}
.daterangepicker .calendar-table td {
width: 40px;
}
</style>
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/CustomDay.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Custom day template</h3>
</div>
<p>
Override
<code class="language-plaintext highlighter-rouge">DayTemplate</code>
template to display additional information in the day cells.
</p>
<Example Text="@ExampleText">
<DateRangePicker>
<DayTemplate Context="dt">
D-<b>@(dt.Day.Day)</b>
<br />
$@(dt.Day.Day + dt.Day.Month * 10)
</DayTemplate>
</DateRangePicker>
</Example>
@code {
private string ExampleText =
"<DateRangePicker>\n" +
" <DayTemplate Context=\"dt\">\n" +
" D-<b>@(dt.Day.Day)</b>\n" +
" <br />\n" +
" $@(dt.Day.Day + dt.Day.Month * 10)\n" +
" </DayTemplate>\n" +
"</DateRangePicker>";
}
================================================
FILE: Demo.Shared/Pages/CustomInput.razor
================================================
@page "/customInput"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/CustomInput.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Custom input markup</h3>
</div>
<Example Text="@ExampleSource">
<DateRangePicker>
<PickerTemplate>
<div id="@context.Id" @onclick="context.Toggle" style="background: #fff; cursor: pointer; padding: .45rem 10px; border: 1px solid #ccc; border-radius: 5px;">
<i class="oi oi-calendar"></i>
<span>
@if (context.TStartDate == null && context.TEndDate == null)
{
<span>Select dates...</span>
}
else if (context.TStartDate != null && context.TEndDate == null)
{
if (context.HoverDate > context.TStartDate)
{
@($"{context.TStartDate.Value.ToString(context.DateFormat)} - {context.HoverDate.Value.ToString(context.DateFormat)}")
@($" - ({(context.HoverDate.Value.Subtract(context.TStartDate.Value).Days).ToString()} nights)")
}
else
{
<span>@context.TStartDate.Value.ToString("dd/MM/yyyy")</span>
}
}
else
{
<span>
@context.FormattedRange @($" - ({(context.TEndDate.Value.Subtract(context.TStartDate.Value).Days).ToString()} nights)")
</span>
}
</span>
<i class="oi oi-chevron-bottom float-right"></i>
</div>
</PickerTemplate>
</DateRangePicker>
</Example>
@code {
private string ExampleSource =
"<DateRangePicker>\n" +
" <PickerTemplate>\n" +
" <div id=\"@context.Id\" @onclick=\"context.Toggle\" style=\"background: #fff; cursor: pointer; padding: .45rem 10px; border: 1px solid #ccc; border-radius: 5px;\">\n" +
" <i class=\"oi oi-calendar\"></i> \n" +
" <span>\n" +
" @if (context.TStartDate == null && context.TEndDate == null)\n" +
" {\n" +
" <span>Select dates...</span>\n" +
" }\n" +
" else if (context.TStartDate != null && context.TEndDate == null)\n" +
" {\n" +
" if (context.HoverDate > context.TStartDate)\n" +
" {\n" +
" @($\"{context.TStartDate.Value.ToString(context.DateFormat)} - {context.HoverDate.Value.ToString(context.DateFormat)}\")\n" +
" @($\" - ({(context.HoverDate.Value.Subtract(context.TStartDate.Value).Days).ToString()} nights)\")\n" +
" }\n" +
" else\n" +
" {\n" +
" <span>@context.TStartDate.Value.ToString(\"dd/MM/yyyy\")</span>\n" +
" }\n" +
" }\n" +
" else\n" +
" {\n" +
" <span>\n" +
" @context.FormattedRange @($\" - ({(context.TEndDate.Value.Subtract(context.TStartDate.Value).Days).ToString()} nights)\")\n" +
" </span>\n" +
" }\n" +
" </span>\n" +
" <i class=\"oi oi-chevron-bottom float-right\"></i>\n" +
" </div>\n" +
" </PickerTemplate>\n" +
"</DateRangePicker>";
}
================================================
FILE: Demo.Shared/Pages/DateInput.razor
================================================
@inherits InputBase<DateRange>
<DateRangePicker class="@("is-" + CssClass + " form-control")"
StartDate="Value?.Start" EndDate="Value?.End"
OnRangeSelect="OnRangeSelect" OnReset="OnReset" />
@code {
private Task OnReset()
{
Value = null;
return ValueChanged.InvokeAsync(Value);
}
private Task OnRangeSelect(DateRange range)
{
if (Value == null) Value = new DateRange();
Value.Start = range.Start;
Value.End = range.End;
return ValueChanged.InvokeAsync(Value);
}
protected override bool TryParseValueFromString(string value, out DateRange result, out string validationErrorMessage)
{
result = new DateRange();
validationErrorMessage = string.Empty;
return false;
}
}
================================================
FILE: Demo.Shared/Pages/Disable.razor
================================================
@page "/disable"
@using System.Threading
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Disable.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Disable some days</h3>
</div>
<p>
There is a function
<code class="language-plaintext highlighter-rouge">DaysEnabledFunction</code>
(and <code class="language-plaintext highlighter-rouge">DaysEnabledFunctionAsync</code>)
that is passed each date in the two calendars before they are displayed,
and it may return true or false to indicate whether that date should be available for selection or not.
</p>
<p>
<code class="language-plaintext highlighter-rouge">OnMonthChanged</code>
event is used to prepare data for
<code class="language-plaintext highlighter-rouge">DaysEnabledFunction</code>
</p>
<Example Text="@ExampleText">
<DateRangePicker @ref="Picker"
DaysEnabledFunction="DaysEnabledFunction"
OnMonthChangedAsync="OnMonthChangedAsync" />
</Example>
@code {
DateRangePicker Picker;
List<DateTimeOffset> DisabledDays { get; set; } = new List<DateTimeOffset>();
private bool DaysEnabledFunction(DateTimeOffset day)
{
return !DisabledDays.Any(d => d.Day == day.Day);
}
private async Task OnMonthChangedAsync(CancellationToken ct)
{
var leftMonth = Picker.LeftCalendar.Month;
var rightMonth = Picker.RightCalendar.Month;
// Simulate hard work (db request, etc)
await Task.Delay(500, ct);
// For example, disable the dates that matching with selected month numbers
DisabledDays = new List<DateTimeOffset> {
new DateTime(leftMonth.Year, leftMonth.Month, leftMonth.Month),
new DateTime(rightMonth.Year, rightMonth.Month, rightMonth.Month)
};
}
private string ExampleText =
"<DateRangePicker @ref=\"Picker\"\n" +
" DaysEnabledFunction=\"DaysEnabledFunction\"\n" +
" OnMonthChangedAsync=\"OnMonthChangedAsync\" />\n\n" +
"@code {\n" +
" DateRangePicker Picker;\n\n" +
" List<DateTimeOffset> DisabledDays { get; set; } = new List<DateTimeOffset>();\n\n" +
" private bool DaysEnabledFunction(DateTimeOffset day)\n" +
" {\n" +
" return !DisabledDays.Any(d => d.Day == day.Day);\n" +
" }\n\n" +
" private async Task OnMonthChangedAsync(CancellationToken ct)\n" +
" {\n" +
" var leftMonth = Picker.LeftCalendar.Month;\n" +
" var rightMonth = Picker.RightCalendar.Month;\n\n" +
" // Simulate hard work (db request, etc)\n" +
" await Task.Delay(500, ct);\n\n" +
" // For example, disable the dates that matching with selected month numbers\n" +
" DisabledDays = new List<DateTimeOffset> {\n" +
" new DateTime(leftMonth.Year, leftMonth.Month, leftMonth.Month),\n" +
" new DateTime(rightMonth.Year, rightMonth.Month, rightMonth.Month)\n" +
" };\n" +
" }\n" +
"}";
}
================================================
FILE: Demo.Shared/Pages/Example.razor
================================================
@inject IClipboard Clipboard
@if (ChildContent != null)
{
<div class="bd-example">
@ChildContent
</div>
}
<div class="bd-clipboard">
<button type="button" class="btn-clipboard" title="Copy to clipboard" @onclick="CopyText">Copy</button>
</div>
@if (!string.IsNullOrEmpty(Text))
{
<figure class="highlight">
<pre><code lang="html">@Text</code></pre>
</figure>
}
@code{
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Text { get; set; }
private Task CopyText()
{
return Clipboard.SetTextAsync(Text);
}
}
================================================
FILE: Demo.Shared/Pages/Form.razor
================================================
@page "/form"
@using System.ComponentModel.DataAnnotations;
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Form.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Example of DateRangePicker usage as a form control</h3>
</div>
<Example Text="@ExampleText">
<EditForm Model="@exampleModel" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<DateInput @bind-Value="@exampleModel.Range" />
<div class="invalid-feedback">
<ValidationMessage For="@(()=>exampleModel.Range)" />
</div>
<button class="btn btn-primary mt-2 mb-2" type="submit">Submit</button>
</EditForm>
<p>Form value:</p>
<pre>@System.Text.Json.JsonSerializer.Serialize(exampleModel)</pre>
</Example>
@code {
private ExampleModel exampleModel = new ExampleModel();
private void HandleValidSubmit()
{
// Do stuff...
}
public class ExampleModel
{
[Required]
public DateRange Range { get; set; }
}
private string ExampleText = "<DateInput @bind-Value=\"@exampleModel.Range\" />";
}
================================================
FILE: Demo.Shared/Pages/HandleEvents.razor
================================================
@page "/handleEvents"
<style>
.bd-example > .alert + .alert {
margin-top: 0.3rem;
}
.alert {
padding: 0.15rem 0.65rem;
margin-bottom: 0.2rem;
}
</style>
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/HandleEvents.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Subscribe to events</h3>
</div>
<p>You can get notified when the user interacts with picker by subscribing to events.</p>
<table>
<thead>
<tr>
<th>Event</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnRangeSelect</code></td>
<td>DateRange</td>
<td>Triggered when the apply button is clicked, or when a predefined range is clicked.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnReset</code></td>
<td>void</td>
<td>Triggered when the apply button is clicked, or when a predefined range is clicked.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnOpened</code></td>
<td>void</td>
<td>An event that is invoked when the DatePicker is opened.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnClosed</code></td>
<td>void</td>
<td>An event that is invoked when the DatePicker is closed.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnCancel</code></td>
<td>bool</td>
<td>An event that is invoked when user cancels the selection (true if by pressing "Cancel" button, false if by backdrop click).</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnMonthChanged</code></td>
<td>void</td>
<td>An event that is invoked when left or right calendar's month changed.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnMonthChangedAsync</code></td>
<td>Task</td>
<td>
An event that is invoked when left or right calendar's month changed and supports CancellationToken.
Use this event handler to prepare the data for CustomDateFunction because it's supports loading indication.
</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnSelectionStart</code></td>
<td>DateTimeOffset</td>
<td>An event that is invoked when StartDate is selected.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">OnSelectionEnd</code></td>
<td>DateTimeOffset</td>
<td>An event that is invoked when EndDate is selected but before the user clicks apply button.</td>
</tr>
</tbody>
</table>
<Example Text="@ExampleText">
<DateRangePicker @ref="Picker"
OnRangeSelect="OnRangeSelect"
OnMonthChanged="OnMonthChanged"
OnSelectionStart="OnSelectionStart"
OnSelectionEnd="OnSelectionEnd"
OnReset="OnReset"
OnOpened="OnOpened"
OnClosed="OnClosed"
OnCancel="OnCancel" />
@if (events.Count > 0)
{
<h6 class="pt-2">Events:</h6>
}
@foreach (var e in events)
{
<div class="alert alert-secondary" role="alert"><small>@e.Item2</small><small class="float-right">@e.Item1</small></div>
}
</Example>
@code {
DateRangePicker Picker;
List<(DateTime, string)> events { get; set; } = new List<(DateTime, string)>();
private void OnOpened()
{
events.Add((DateTime.Now, $"OnOpened"));
}
private void OnClosed()
{
events.Add((DateTime.Now, $"OnClosed"));
}
private void OnReset()
{
events.Add((DateTime.Now, $"OnReset"));
}
private void OnCancel(bool byButton)
{
events.Add((DateTime.Now, $"OnCancel: {(byButton ? "by 'cancel' button" : "by backdrop click")}"));
}
private void OnMonthChanged()
{
var leftMonth = Picker.LeftCalendar.Month;
var rightMonth = Picker.RightCalendar.Month;
events.Add((DateTime.Now, $"OnMonthChanged: LeftMonth = {leftMonth:MM.yyyy}, RightMonth = {rightMonth:MM.yyyy}"));
}
private void OnSelectionStart(DateTimeOffset date)
{
events.Add((DateTime.Now, $"OnSelectionStart: {date}"));
}
private void OnSelectionEnd(DateTimeOffset date)
{
events.Add((DateTime.Now, $"OnSelectionEnd: {date}"));
}
public void OnRangeSelect(DateRange range)
{
events.Add((DateTime.Now, $"OnRangeSelect: {range.Start} - {range.End}"));
}
private string ExampleText =
"<DateRangePicker @ref=\"Picker\"\n" +
" OnRangeSelect=\"OnRangeSelect\"\n" +
" OnMonthChanged=\"OnMonthChanged\"\n" +
" OnSelectionStart=\"OnSelectionStart\"\n" +
" OnReset=\"OnReset\"\n" +
" OnOpened=\"OnOpened\"\n" +
" OnClosed=\"OnClosed\"\n" +
" OnCancel=\"OnCancel\" />\n\n" +
"@code {\n" +
" DateRangePicker Picker;\n\n" +
" List<(DateTime, string)> events { get; set; } = new List<(DateTime, string)>();\n\n" +
" private void OnOpened()\n" +
" {\n" +
" events.Add((DateTime.Now, $\"OnOpened\"));\n" +
" }\n\n" +
" private void OnReset()\n" +
" {\n" +
" events.Add((DateTime.Now, $\"OnReset\"));\n" +
" }\n\n" +
" private void OnClosed()\n" +
" {\n" +
" events.Add((DateTime.Now, $\"OnClosed\"));\n" +
" }\n\n" +
" private void OnCancel(bool byButton)\n" +
" {\n" +
" events.Add((DateTime.Now, $\"OnCancel: {(byButton ? \"by 'cancel' button\" : \"by backdrop click\")}\"));\n" +
" }\n\n" +
" private void OnMonthChanged()\n" +
" {\n" +
" var leftMonth = Picker.LeftCalendar.Month;\n" +
" var rightMonth = Picker.RightCalendar.Month;\n" +
" events.Add((DateTime.Now, $\"OnMonthChanged: LeftMonth = {leftMonth:MM.yyyy}, RightMonth = {rightMonth:MM.yyyy}\"));\n" +
" }\n\n" +
" private void OnSelectionStart(DateTimeOffset date)\n" +
" {\n" +
" events.Add((DateTime.Now, $\"OnSelectionStart: {date}\"));\n" +
" }\n\n" +
" public void OnRangeSelect(DateRange range)\n" +
" {\n" +
" events.Add((DateTime.Now, $\"OnRangeSelect: {range.Start} - {range.End}\"));\n" +
" }\n" +
"}";
}
================================================
FILE: Demo.Shared/Pages/Highlight.razor
================================================
@page "/highlight"
@using System.Threading
<style>
.dthighlight {
background-color: aquamarine !important;
}
</style>
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Highlight.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Highlight some days</h3>
</div>
<p>
You can add any css classes to dates with
<code class="language-plaintext highlighter-rouge">CustomDateFunction</code>
function, it uses same approach as <a href="disable">disable function</a>.
</p>
<p>
Define custom css classes somewhere in your stylesheets.
</p>
<Example Text="@ExampleText">
<DateRangePicker @ref="Picker"
CustomDateFunction="CustomDateFunction"
OnMonthChangedAsync="OnMonthChangedAsync" />
</Example>
@code {
DateRangePicker Picker;
List<DateTimeOffset> HighlightDays { get; set; } = new List<DateTimeOffset>();
private object CustomDateFunction(DateTimeOffset day)
{
if (HighlightDays.Any(d => d.Day == day.Day)) return "dthighlight";
return string.Empty;
}
private async Task OnMonthChangedAsync(CancellationToken ct)
{
var leftMonth = Picker.LeftCalendar.Month;
var rightMonth = Picker.RightCalendar.Month;
// Simulate hard work (db request, etc)
await Task.Delay(500, ct);
// For example, highlight the dates that matching with selected month numbers
HighlightDays = new List<DateTimeOffset> {
new DateTime(leftMonth.Year, leftMonth.Month, leftMonth.Month),
new DateTime(rightMonth.Year, rightMonth.Month, rightMonth.Month)
};
}
private string ExampleText =
"<style>\n" +
" .dthighlight {\n" +
" background-color: aquamarine !important;\n" +
" }\n" +
"</style>\n\n" +
"<DateRangePicker @ref=\"Picker\"\n" +
" CustomDateFunction=\"CustomDateFunction\"\n" +
" OnMonthChangedAsync=\"OnMonthChangedAsync\" />\n\n" +
"@code {\n" +
" DateRangePicker Picker;\n\n" +
" List<DateTimeOffset> HighlightDays { get; set; } = new List<DateTimeOffset>();\n\n" +
" private object CustomDateFunction(DateTimeOffset day)\n" +
" {\n" +
" if (HighlightDays.Any(d => d.Day == day.Day - 1)) return \"dthighlight\";\n" +
" return string.Empty;\n" +
" }\n\n" +
" private async Task OnMonthChangedAsync(CancellationToken ct)\n" +
" {\n" +
" var leftMonth = Picker.LeftCalendar.Month;\n" +
" var rightMonth = Picker.RightCalendar.Month;\n\n" +
" // Simulate hard work (db request, etc)\n" +
" await Task.Delay(500, ct);\n\n" +
" // For example, highlight the dates that matching with selected month numbers\n" +
" HighlightDays = new List<DateTimeOffset> {\n" +
" new DateTime(leftMonth.Year, leftMonth.Month, leftMonth.Month),\n" +
" new DateTime(rightMonth.Year, rightMonth.Month, rightMonth.Month)\n" +
" };\n" +
" }\n" +
"}";
}
================================================
FILE: Demo.Shared/Pages/Index.razor
================================================
@page "/"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Index.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h1 class="bd-title">Date Range Picker</h1>
</div>
<p class="bd-lead">
Features include limiting the selectable date range, localizable strings and date formats, a single date picker mode, an inline mode, customizable picker layout, and predefined date ranges.
</p>
<h2><span class="bd-content-title">Quick start</span></h2>
<p>To add the picker to your project download library from NuGet in the NuGet Package Manager, or by executing the following command in the Package Manager Console:</p>
<Example Text="Install-Package BlazorDateRangePicker" />
<h3><span class="bd-content-title">CSS</span></h3>
<p>
Then Copy-paste the stylesheet
<code class="language-plaintext highlighter-rouge"><link></code>
into your <code class="language-plaintext highlighter-rouge"><head></code>
to load CSS. For complex implementations, custom CSS may be necessary.
</p>
<Example Text="@Css" />
<h3><span class="bd-content-title">JS</span></h3>
<p>
This library require the use of JavaScript for popup positioning and outside click handling. Place the following
<code class="language-plaintext highlighter-rouge"><script></code>
near the end of your _Host.cshtml (or index.html for Blazor WebAssembly) pages, right before the closing
<code class="language-plaintext highlighter-rouge"></body></code>.
</p>
<Example Text="@Js" />
<h3>Using directive</h3>
<p>Add this line to the page where you want to use the picker. If you're using the picker on many pages add this line to <code class="language-plaintext highlighter-rouge">_Imports.razor</code>.</p>
<Example Text="@Import" />
<h3>Use the component</h3>
<p>Then attach a date range picker to whatever page you want.</p>
<Example Text="<DateRangePicker />">
<DateRangePicker Drops="DropsType.Up" />
</Example>
<p>
You can customize Date Range Picker with <a target="_blank" href="https://github.com/jdtcn/BlazorDateRangePicker#properties">options</a>,
and get notified when the user interacts with picker by subscribing to <a href="/handleEvents">events</a>.
</p>
@code {
private string Css = "<link rel=\"stylesheet\" href=\"_content/BlazorDateRangePicker/daterangepicker.min.css\" />";
private string Js = "<script src=\"_content/BlazorDateRangePicker/clickAndPositionHandler.js\"></script>";
private string Import = "@using BlazorDateRangePicker";
}
================================================
FILE: Demo.Shared/Pages/Inline.razor
================================================
@page "/inline"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Inline.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Inline mode</h3>
</div>
<Example Text="@ExampleText">
<DateRangePicker Inline="true" AutoApply="true" ShowOnlyOneCalendar="true" />
</Example>
@code {
private string ExampleText = "<DateRangePicker Inline=\"true\" AutoApply=\"true\" ShowOnlyOneCalendar=\"true\" />";
}
================================================
FILE: Demo.Shared/Pages/Licence.razor
================================================
<h4>Licence</h4>
<p>The MIT License (MIT)</p>
<p>Copyright (c) @DateTime.Now.Year Sergey Zaikin</p>
<p>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
</p>
<p>
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</p>
================================================
FILE: Demo.Shared/Pages/Limits.razor
================================================
@page "/limits"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Limits.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Limiting the selectable date range</h3>
</div>
<p>Use these properties to limit selectable date range</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">MinDate</code></td>
<td>DateTimeOffset?</td>
<td>The earliest date a user may select.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">MaxDate</code></td>
<td>DateTimeOffset?</td>
<td>The latest date a user may select.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">MinSpan</code></td>
<td>TimeSpan?</td>
<td>The minimum span between the selected start and end dates.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">MaxSpan</code></td>
<td>TimeSpan?</td>
<td>The maximum span between the selected start and end dates.</td>
</tr>
</tbody>
</table>
<Example Text="@ExampleText">
<DateRangePicker MinDate="DateTime.Now.AddYears(-1)"
MaxDate="DateTime.Now.AddYears(1)"
MinSpan="TimeSpan.FromDays(5)"
MaxSpan="TimeSpan.FromDays(15)" />
</Example>
@code {
private string ExampleText =
"<DateRangePicker MinDate=\"DateTime.Now.AddYears(-1)\"\n" +
" MaxDate=\"DateTime.Now.AddYears(1)\"\n" +
" MinSpan=\"TimeSpan.FromDays(5)\"\n" +
" MaxSpan=\"TimeSpan.FromDays(15)\" />";
}
================================================
FILE: Demo.Shared/Pages/Localization.razor
================================================
@page "/localization"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Localization.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Localization</h3>
</div>
<p>
Use
<code class="language-plaintext highlighter-rouge">ApplyLabel</code>,
<code class="language-plaintext highlighter-rouge">CancelLabel</code> and
<code class="language-plaintext highlighter-rouge">CustomRangeLabel</code>
to change picker labels. Alternatively one can use custom
<code class="language-plaintext highlighter-rouge">ButtonsTemplate</code>.
</p>
<p>
Use
<code class="language-plaintext highlighter-rouge">Culture</code>
property to set picker culture other than CurrentUICulture.
</p>
<Example Text="@ExampleText">
<DateRangePicker Culture="@(System.Globalization.CultureInfo.GetCultureInfo("fr-FR"))"
ApplyLabel="Appliquer"
CancelLabel="Annuler"
CustomRangeLabel="Ma gamme personnalisée" />
</Example>
<p>It's convenient to set these properties application-wide in one place:</p>
<Example Text="@ExampleConfig" />
@code {
private string ExampleText =
"<DateRangePicker Culture=\"@(System.Globalization.CultureInfo.GetCultureInfo(\"fr-FR\"))\">\n" +
" ApplyLabel=\"Appliquer\"\n" +
" CancelLabel=\"Annuler\"\n" +
" CustomRangeLabel=\"Ma gamme personnalisée\" />";
private string ExampleConfig =
"#Startup.cs\n\n" +
"using BlazorDateRangePicker;\n\n" +
"//ConfigureServices\n" +
"services.AddDateRangePicker(config =>\n" +
"{\n" +
" config.ApplyLabel = \"My Apply Label\";\n" +
" ...\n" +
"});";
}
================================================
FILE: Demo.Shared/Pages/Positioning.razor
================================================
@page "/positioning"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Positioning.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Popup alignment</h3>
</div>
<p>The picker can be aligned to the left, to the right (default), or centered under the HTML element it's attached to</p>
<Example Text="@ExampleTextLeft">
<DateRangePicker Opens="SideType.Left" />
</Example>
<Example Text="@ExampleTextCenter">
<DateRangePicker Opens="SideType.Center" />
</Example>
<Example Text="@ExampleTextRight">
<DateRangePicker Opens="SideType.Right" />
</Example>
<h4>Popup direction</h4>
<p>Whether the picker appears below (default) or above the HTML element it's attached to</p>
<Example Text="@ExampleTextUp">
<DateRangePicker Drops="DropsType.Up" />
</Example>
@code {
private string ExampleTextLeft = "<DateRangePicker Opens=\"SideType.Left\" />";
private string ExampleTextCenter = "<DateRangePicker Opens=\"SideType.Center\" />";
private string ExampleTextRight = "<DateRangePicker Opens=\"SideType.Right\" />";
private string ExampleTextUp = "<DateRangePicker Drops=\"DropsType.Up\" />";
}
================================================
FILE: Demo.Shared/Pages/PredefinedRanges.razor
================================================
@page "/predefinedRanges"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/PredefinedRanges.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Predefined Date Ranges</h3>
</div>
<Example Text="@ExampleText">
<DateRangePicker Ranges="DateRanges" />
</Example>
@code{
Dictionary<string, DateRange> DateRanges => new Dictionary<string, DateRange> {
{ "This month", new DateRange
{
Start = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1),
End = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(1).AddTicks(-1)
}
} ,
{ "Previous month" , new DateRange
{
Start = new DateTime(DateTime.Now.AddMonths(-1).Year, DateTime.Now.AddMonths(-1).Month, 1),
End = new DateTime(DateTime.Now.AddMonths(-1).Year, DateTime.Now.AddMonths(-1).Month, 1).AddMonths(1).AddTicks(-1)
}
}
};
private string ExampleText =
"<DateRangePicker Ranges=\"DateRanges\" />\n\n" +
"@code { \n Dictionary<string, DateRange> DateRanges => new Dictionary<string, DateRange> {\n" +
" { \"This month\", new DateRange\n" +
" {\n" +
" Start = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1),\n" +
" End = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(1).AddTicks(-1)\n" +
" }\n" +
" }, ...\n" +
" };\n }\n}";
}
================================================
FILE: Demo.Shared/Pages/Single.razor
================================================
@page "/single"
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Single.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Single Date Picker</h3>
</div>
<Example Text="@ExampleText">
<DateRangePicker SingleDatePicker="true" />
</Example>
@code {
private string ExampleText = "<DateRangePicker SingleDatePicker=\"true\" />";
}
================================================
FILE: Demo.Shared/Pages/Time.razor
================================================
@page "/time"
@using System.Globalization
<div class="d-md-flex flex-md-row-reverse align-items-center justify-content-between">
<a class="btn btn-sm btn-bd-light my-2 my-md-0" href="https://github.com/jdtcn/BlazorDateRangePicker/blob/master/Demo.Shared/Pages/Time.razor"
title="View this file on GitHub" target="_blank" rel="noopener">View on GitHub</a>
<h3>Time picker</h3>
</div>
<p>TimePicker 12 Hour</p>
<Example Text="@ExampleText1">
<DateRangePicker Culture="@CultureInfo.GetCultureInfo("en-US")" TimePicker="true" TimePicker24Hour="false"
DateFormat="@($"{DateFormat} hh:mm tt")" />
</Example>
<p>TimePicker 24 Hour</p>
<Example Text="@ExampleText2">
<DateRangePicker TimePicker="true" TimePicker24Hour="true" DateFormat="@($"{DateFormat} HH:mm")" />
</Example>
<p>TimePicker minutes increment</p>
<Example Text="@ExampleText3">
<DateRangePicker TimePicker="true" TimePicker24Hour="true" TimePickerIncrement="15"
InitialStartTime="RundStartTime" InitialEndTime="RoundEndTime"
StartDate="RoundStartDate" EndDate="RoundEndDate"
DateFormat="@($"{DateFormat} HH:mm")" OnRangeSelect="RoundOnRangeSelect" />
</Example>
<p>TimePicker with seconds</p>
<Example Text="@ExampleText4">
<DateRangePicker TimePicker="true" TimePicker24Hour="true" TimePickerSeconds="true"
DateFormat="@($"{DateFormat} HH:mm:ss")" />
</Example>
<p>Initial StartTime & EndTime</p>
<Example Text="@ExampleText5">
<DateRangePicker TimePicker="true" TimePicker24Hour="true"
InitialStartTime="StartTime" InitialEndTime="EndTime"
DateFormat="@($"{DateFormat} HH:mm")" />
</Example>
<p>Initial StartTime & EndTime set by StartDate & EndDate</p>
<Example Text="@ExampleText6">
<DateRangePicker TimePicker="true" TimePicker24Hour="true"
@bind-StartDate="InitialStartDate" @bind-EndDate="InitialEndDate"
DateFormat="@($"{DateFormat} HH:mm")" />
</Example>
<p>Single picker with time</p>
<Example Text="@ExampleText7">
<DateRangePicker SingleDatePicker="true" TimePicker="true" TimePicker24Hour="true"
DateFormat="@($"{DateFormat} HH:mm")" />
</Example>
<p>TimeEnabled function</p>
<Example Text="@ExampleText8">
<DateRangePicker TimePicker="true" TimePicker24Hour="true" TimeEnabledFunction="TimeEnabledFunction"
InitialStartTime="StartTime" InitialEndTime="EndTime"
DateFormat="@($"{DateFormat} HH:mm")" Drops="DropsType.Up" />
</Example>
@code {
private string DateFormat => CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
private TimeSpan RundStartTime = TimeSpan.FromHours(2).Add(TimeSpan.FromMinutes(15));
private TimeSpan RoundEndTime = TimeSpan.FromHours(15).Add(TimeSpan.FromMinutes(45));
private TimeSpan StartTime = TimeSpan.FromHours(8);
private TimeSpan EndTime = TimeSpan.FromHours(11);
private DateTimeOffset? InitialStartDate { get; set; } = DateTime.Now.AddDays(-1).Date.Add(TimeSpan.FromHours(2));
private DateTimeOffset? InitialEndDate { get; set; } = DateTime.Now.AddDays(1).Date.Add(TimeSpan.FromHours(15));
private DateTimeOffset? RoundStartDate { get; set; }
private DateTimeOffset? RoundEndDate { get; set; }
private void RoundOnRangeSelect(DateRange range)
{
RoundStartDate = range.Start.Date.Add(TimeSpan.FromHours(range.Start.Hour).Add(TimeSpan.FromMinutes((range.Start.Minute / 15) * 15)));
RoundEndDate = range.End.Date.Add(TimeSpan.FromHours(range.End.Hour).Add(TimeSpan.FromMinutes((range.End.Minute / 15) * 15)));
}
private Task<TimeSettings> TimeEnabledFunction(DateTimeOffset? day)
{
var res = new TimeSettings
{
Hours = day?.Day % 2 == 0
? new int[] { 7, 8, 9, 10, 11, 12 }
: new int[] { 8, 9, 10, 11 },
Minutes = new int[] { 0, 15, 30, 45 },
Seconds = new int[] { 0, 60 }
};
return Task.FromResult(res);
}
private string ExampleText1 = "<DateRangePicker Culture=\"@CultureInfo.GetCultureInfo(\"en-US\")\" \n TimePicker=\"true\" TimePicker24Hour=\"false\" \n DateFormat=\"@($\"{DateFormat} hh:mm tt\")\" />";
private string ExampleText2 = "<DateRangePicker TimePicker=\"true\" TimePicker24Hour=\"true\" \n DateFormat=\"@($\"{DateFormat} HH:mm\")\" />";
private string ExampleText3 = "<DateRangePicker TimePicker=\"true\" TimePicker24Hour=\"true\" TimePickerIncrement=\"15\"\n" +
" InitialStartTime=\"RundStartTime\" InitialEndTime=\"RoundEndTime\"\n" +
" StartDate=\"RoundStartDate\" EndDate=\"RoundEndDate\"\n" +
" DateFormat=\"@($\"{DateFormat} HH:mm\")\" OnRangeSelect=\"RoundOnRangeSelect\" />";
private string ExampleText4 = "<DateRangePicker TimePicker=\"true\" TimePicker24Hour=\"true\" \n TimePickerSeconds=\"true\" DateFormat=\"@($\"{DateFormat} HH:mm:ss\")\" />";
private string ExampleText5 = "<DateRangePicker TimePicker=\"true\" TimePicker24Hour=\"true\" \n InitialStartTime=\"StartTime\" InitialEndTime=\"EndTime\" DateFormat=\"@($\"{DateFormat} HH:mm\")\" />";
private string ExampleText6 = "<DateRangePicker TimePicker=\"true\" TimePicker24Hour=\"true\" \n @bind-StartDate=\"InitialStartDate\" @bind-EndDate=\"InitialEndDate\" \n DateFormat=\"@($\"{DateFormat} HH:mm\")\" />";
private string ExampleText7 = "<DateRangePicker SingleDatePicker=\"true\" TimePicker=\"true\" TimePicker24Hour=\"true\" \n DateFormat=\"@($\"{DateFormat} HH:mm\")\" />";
private string ExampleText8 = "<DateRangePicker TimeEnabledFunction=\"TimeEnabledFunction\" />\n" +
@"private Task<TimeSettings> TimeEnabledFunction(DateTimeOffset? day)\n
{
var res = new TimeSettings
{
Hours = day?.Day % 2 == 0
? new int[] { 8, 9, 10, 11 },
: new int[] { 7, 8, 9, 10, 11, 12 }
Minutes = new int[] { 0, 15, 30, 45 },
Seconds = new int[] { 0, 60 }
};
return Task.FromResult(res);
}";
}
================================================
FILE: Demo.Shared/Shared/MainLayout.razor
================================================
@inherits LayoutComponentBase
@inject IJSRuntime JSRuntime
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bd-navbar">
<a class="navbar-brand" href="/">DateRangePicker</a>
<ul class="navbar-nav ml-md-auto">
<li class="nav-item">
<a class="nav-link pl-2 pr-1 mx-1 py-3 my-n2" href="https://github.com/jdtcn/BlazorDateRangePicker" target="_blank" rel="noopener" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" class="navbar-nav-svg" viewBox="0 0 512 499.36" role="img" focusable="false"><title>GitHub</title><path fill="currentColor" fill-rule="evenodd" d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z"></path></svg>
</a>
</li>
</ul>
</header>
<div class="container-fluid">
<div class="row flex-xl-nowrap">
<Sidebar />
<main class="col-md-9 col-xl-8 py-md-3 pl-md-5 bd-content" role="main">
@Body
</main>
</div>
</div>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JSRuntime.InvokeAsync<object>("highlightInterop.highlight");
await base.OnAfterRenderAsync(firstRender);
}
}
================================================
FILE: Demo.Shared/Shared/Sidebar.razor
================================================
<div class="col-md-3 col-xl-2 bd-sidebar">
<button class="btn bd-search-docs-toggle d-md-none p-0 mt-3 mb-3 collapsed" type="button" data-toggle="collapse" @onclick="@(_ => Collased = !Collased)"
data-target="#bd-docs-nav" aria-controls="bd-docs-nav" aria-expanded="false" aria-label="Toggle docs navigation">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img" focusable="false">
<title>Menu</title>
<path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path>
</svg>
</button>
<nav class="collapse bd-links @(Collased ? "" : "show")" aria-label="Main navigation">
<div class="bd-toc-item active">
<a class="bd-toc-link" href="/">
Examples
</a>
<ul class="nav bd-sidenav">
<NavLink href="/" Match="NavLinkMatch.All">Quick start</NavLink>
<NavLink href="/positioning">Positioning</NavLink>
<NavLink href="/handleEvents">Handle events</NavLink>
<NavLink href="/single">Single date picker</NavLink>
<NavLink href="/predefinedRanges">Predefined date ranges</NavLink>
<NavLink href="/localization">Localization</NavLink>
<NavLink href="/inline">Inline mode</NavLink>
<NavLink href="/limits">Limits</NavLink>
<NavLink href="/disable">Disable dates</NavLink>
<NavLink href="/highlight">Highlight dates</NavLink>
<NavLink href="/customInput">Custom input layout</NavLink>
<NavLink href="/customDay">Custom day layout</NavLink>
<NavLink href="/customButtons">Custom buttons layout</NavLink>
<NavLink href="/customClickHandler">Custom click handler</NavLink>
<NavLink href="/bothSidesSelection">Both sides selection</NavLink>
<NavLink href="/form">Form</NavLink>
<NavLink href="/time">Time</NavLink>
<NavLink href="/container">DOM Container</NavLink>
</ul>
</div>
</nav>
</div>
@code{
private bool Collased { get; set; } = true;
}
================================================
FILE: Demo.Shared/_Imports.razor
================================================
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using Demo.Shared
@using Demo.Shared.Pages
@using BlazorDateRangePicker
================================================
FILE: Demo.Shared/wwwroot/css/open-iconic/FONT-LICENSE
================================================
SIL OPEN FONT LICENSE Version 1.1
Copyright (c) 2014 Waybury
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
================================================
FILE: Demo.Shared/wwwroot/css/open-iconic/ICON-LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Waybury
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: Demo.Shared/wwwroot/css/open-iconic/README.md
================================================
[Open Iconic v1.1.1](http://useiconic.com/open)
===========
### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
## What's in Open Iconic?
* 223 icons designed to be legible down to 8 pixels
* Super-light SVG files - 61.8 for the entire set
* SVG sprite—the modern replacement for icon fonts
* Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
* Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
* PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
## Getting Started
#### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
### General Usage
#### Using Open Iconic's SVGs
We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
```
<img src="/open-iconic/svg/icon-name.svg" alt="icon name">
```
#### Using Open Iconic's SVG Sprite
Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `<svg>` *tag and a unique class name for each different icon in the* `<use>` *tag.*
```
<svg class="icon">
<use xlink:href="open-iconic.svg#account-login" class="icon-account-login"></use>
</svg>
```
Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `<svg>` tag with equal width and height dimensions.
```
.icon {
width: 16px;
height: 16px;
}
```
Coloring icons is even easier. All you need to do is set the `fill` rule on the `<use>` tag.
```
.icon-account-login {
fill: #f00;
}
```
To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
#### Using Open Iconic's Icon Font...
##### …with Bootstrap
You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
```
<link href="/open-iconic/font/css/open-iconic-bootstrap.css" rel="stylesheet">
```
```
<span class="oi oi-icon-name" title="icon name" aria-hidden="true"></span>
```
##### …with Foundation
You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
```
<link href="/open-iconic/font/css/open-iconic-foundation.css" rel="stylesheet">
```
```
<span class="fi-icon-name" title="icon name" aria-hidden="true"></span>
```
##### …on its own
You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
```
<link href="/open-iconic/font/css/open-iconic.css" rel="stylesheet">
```
```
<span class="oi" data-glyph="icon-name" title="icon name" aria-hidden="true"></span>
```
## License
### Icons
All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
### Fonts
All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
================================================
FILE: Demo.Shared/wwwroot/css/site.css
================================================
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
.bd-navbar {
background-color: #336fb0;
z-index: 990;
}
.bd-navbar .navbar-nav-svg {
width: 24px;
height: 24px;
}
.bd-sidebar .nav > .active:hover > a, .bd-sidebar .nav > a.active {
font-weight: 600;
color: rgba(0,0,0,.85);
background-color: transparent;
}
.bd-sidebar .nav > a:hover {
color: rgba(0,0,0,.85);
text-decoration: none;
background-color: transparent;
}
.bd-sidebar .nav > a {
display: block;
padding: .25rem 1.5rem;
font-size: 90%;
color: rgba(0,0,0,.65);
}
.btn-bd-light:active, .btn-bd-light:hover, .show > .btn-bd-light {
color: #336fb0;
background-color: #fff;
border-color: #336fb0;
}
.hljs {
padding: 0;
background: transparent;
}
================================================
FILE: Demo.Shared/wwwroot/highlight/cshtml-razor.js
================================================
/*
* Language: cshtml-razor
* Requires: xml.js, cs.js, css.js, javascript.js
* Author: Roman Resh <romanresh@live.com>
*/
var module = module ? module : {};
function getXmlBlocks(hljs, additional_blocks) {
var xml_comment = hljs.COMMENT(
'<!--',
'-->',
{
relevance: 10
}
);
var string = {
className: 'string',
variants: [
{ begin: /"/, end: /"/ },
{ begin: /'/, end: /'/ },
{ begin: /[^\s"'=<>`]+/ }
],
contains: additional_blocks
};
var xml_tag_internal = {
endsWithParent: true,
illegal: /</,
relevance: 0,
contains: [
{
className: 'attr',
begin: '[A-Za-z0-9\\._:-]+',
relevance: 0
},
{
begin: /=\s*/,
relevance: 0,
contains: [string]
}
]
};
return [
{
className: 'meta',
begin: '<!DOCTYPE', end: '>',
relevance: 10,
contains: [{ begin: '\\[', end: '\\]' }]
},
xml_comment,
{
begin: '<\\!\\[CDATA\\[', end: '\\]\\]>',
relevance: 10
},
{
className: 'meta',
begin: /<\?xml/, end: /\?>/, relevance: 10
},
{
className: 'tag',
begin: '<style(?=\\s|>|$)', end: '>',
keywords: { name: 'style' },
contains: [xml_tag_internal],
starts: {
end: '</style>', returnEnd: true,
subLanguage: ['css', 'xml']
}
},
{
className: 'tag',
begin: '<script(?=\\s|>|$)', end: '>',
keywords: { name: 'script' },
contains: [xml_tag_internal],
starts: {
end: '\<\/script\>', returnEnd: true,
subLanguage: ['actionscript', 'javascript', 'handlebars', 'xml']
}
},
{
className: 'tag',
begin: '</?', end: '/?>',
contains: [
{
className: 'name', begin: /[^\/><\s]+/, relevance: 0
},
xml_tag_internal
]
}
].concat(additional_blocks);
}
function hljsDefineCshtmlRazor(hljs) {
var SPECIAL_SYMBOL_CLASSNAME = "built_in";
var CONTENT_REPLACER = {};
var closed_brace = {
begin: "}",
className: SPECIAL_SYMBOL_CLASSNAME,
endsParent: true
};
var braces = {
begin: "{",
end: "}",
contains: [hljs.QUOTE_STRING_MODE, 'self']
};
var razor_comment = hljs.COMMENT(
'@\\*',
'\\*@',
{
relevance: 10
}
);
var razor_inline_expresion = {
begin: "@[a-zA-Z]+",
returnBegin: true,
subLanguage: 'csharp',
end: "(\\r|\\n|<|\\s|\"|')",
contains: [
{
begin: '@',
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: '".*(?!$)"',
skip: true
},
{
begin: '"',
endsParent: true
}
],
returnEnd: true
};
var razor_text_block = {
begin: "[@]{0,1}<text>",
returnBegin: true,
end: "</text>",
returnEnd: true,
subLanguage: "cshtml-razor",
contains: [
{
begin: "[@]{0,1}<text>",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: "</text>",
className: SPECIAL_SYMBOL_CLASSNAME,
endsParent: true
}
]
};
var razor_escape_at = {
variants: [
{ begin: "@@" },
{ begin: "[a-zA-Z]+@" }
],
skip: true
};
var razor_parentheses_block = {
begin: "@\\(",
end: "\\)",
returnBegin: true,
returnEnd: true,
subLanguage: "csharp",
contains: [
{
begin: "@\\(",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: "\\(",
end: "\\)",
subLanguage: 'csharp',
contains: [hljs.QUOTE_STRING_MODE, 'self', razor_text_block]
},
razor_text_block,
{
begin: "\\)",
className: SPECIAL_SYMBOL_CLASSNAME,
endsParent: true
}
]
};
var xml_blocks = getXmlBlocks(hljs, [razor_inline_expresion, razor_parentheses_block]);
var razor_directives = {
begin: "^\\s*@(page|model|using|inherits|inject)[^\\r\\n{\\(]*$",
end: "$",
returnBegin: true,
returnEnd: true,
contains: [
{
begin: "^\\s*@(page|model|using|inherits|inject)",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
variants: [
{ begin: "\\r|\\n", endsParent: true},
{ begin: "\\s[^\\r\\n]+", end: "$" },
{ begin: "$" }
],
className: "type",
endsParent: true
}
]
};
var razor_block = {
begin: "@\\{",
returnBegin: true,
returnEnd: true,
end: "\\}",
subLanguage: 'csharp',
contains: [
{
begin: "@\\{",
className: SPECIAL_SYMBOL_CLASSNAME
},
CONTENT_REPLACER,
closed_brace
]
};
var razor_helper_block = {
begin: "^\\s*@helper[\\s]*[^{]+[\\s]*{",
returnBegin: true,
returnEnd: true,
end: "}",
subLanguage: "cshtml-razor",
contains: [
{ begin: "@helper", className: SPECIAL_SYMBOL_CLASSNAME },
{ begin: "{", className: SPECIAL_SYMBOL_CLASSNAME },
closed_brace
]
};
var razor_code_block_variants = [
{ begin: "@for[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@if[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@switch[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@while[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@using[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@lock[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@foreach[\\s]*\\([^{]+[\\s]*{", end: "}" }
];
var razor_code_block = {
variants: razor_code_block_variants,
returnBegin: true,
returnEnd: true,
end: "}",
subLanguage: 'csharp',
contains: [
{
variants: razor_code_block_variants.map(function (v) { return { begin: v.begin }; }),
returnBegin: true,
contains: [
{ begin: "@", className: SPECIAL_SYMBOL_CLASSNAME },
{
variants: razor_code_block_variants.map(function (v) { return { begin: v.begin.substr(1, v.begin.length - 2) }; }),
subLanguage: "csharp"
},
{ begin: "{", className: SPECIAL_SYMBOL_CLASSNAME }
]
},
CONTENT_REPLACER,
{
variants: [
{ begin: "}[\\s]*else\\sif[\\s]*\\([^{]+[\\s]*{" },
{ begin: "}[\\s]*else[\\s]*{" }
],
returnBegin: true,
contains: [
{ begin: "}", className: SPECIAL_SYMBOL_CLASSNAME },
{
variants: [
{ begin: "[\\s]*else\\sif[\\s]*\\([^{]+[\\s]*{" },
{ begin: "[\\s]*else[\\s]*" }
],
subLanguage: "csharp"
},
{
begin: "{",
className: SPECIAL_SYMBOL_CLASSNAME
}
]
},
braces,
closed_brace
]
};
var section_begin = "@section[\\s]+[a-zA-Z0-9]+[\\s]*{";
var razor_try_block = {
begin: "@try[\\s]*{",
end: "}",
returnBegin: true,
returnEnd: true,
subLanguage: "csharp",
contains: [
{ begin: "@", className: SPECIAL_SYMBOL_CLASSNAME },
{ begin: "try[\\s]*{", subLanguage: "csharp" },
{
variants: [
{ begin: "}[\\s]*catch[\\s]*\\([^\\)]+\\)[\\s]*{" },
{ begin: "}[\\s]*finally[\\s]*{" }
],
returnBegin: true,
contains: [
{ begin: "}", className: SPECIAL_SYMBOL_CLASSNAME },
{
variants: [
{ begin: "[\\s]*catch[\\s]*\\([^\\)]+\\)[\\s]*", },
{ begin: "[\\s]*finally[\\s]*", },
],
subLanguage: "csharp"
},
{ begin: "{", className: SPECIAL_SYMBOL_CLASSNAME }
]
},
CONTENT_REPLACER,
braces,
closed_brace
]
};
var razor_section_block = {
begin: section_begin,
returnBegin: true,
returnEnd: true,
end: "}",
subLanguage: 'cshtml-razor',
contains: [
{
begin: section_begin,
className: SPECIAL_SYMBOL_CLASSNAME
},
braces,
closed_brace
]
};
var rasor_await = {
begin: "@await ",
returnBegin: true,
subLanguage: 'csharp',
end: "(\\r|\\n|<|\\s)",
contains: [
{
begin: "@await ",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: "[<\\r\\n]",
endsParent: true
}
]
};
var result = {
aliases: ['cshtml', 'razor', 'razor-cshtml'],
contains: [
razor_directives,
razor_helper_block,
razor_block,
razor_code_block,
razor_section_block,
rasor_await,
razor_try_block,
razor_escape_at,
razor_text_block,
razor_comment,
razor_parentheses_block,
{
className: 'meta',
begin: '<!DOCTYPE', end: '>',
relevance: 10,
contains: [{ begin: '\\[', end: '\\]' }]
},
{
begin: '<\\!\\[CDATA\\[', end: '\\]\\]>',
relevance: 10
}
]
};
result.contains = result.contains.concat(xml_blocks);
[razor_block, razor_code_block, razor_try_block]
.forEach(function (mode) {
var razorModes = result.contains.filter(function (c) { return c !== mode; });
var replacerIndex = mode.contains.indexOf(CONTENT_REPLACER);
mode.contains.splice.apply(mode.contains, [replacerIndex, 1].concat(razorModes));
});
return result;
}
module.exports = function (hljs) {
hljs.registerLanguage('cshtml-razor', hljsDefineCshtmlRazor);
};
module.exports.definer = hljsDefineCshtmlRazor;
================================================
FILE: Demo.Shared/wwwroot/highlight/default.css
================================================
/*
Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #F0F0F0;
}
/* Base color: saturation 0; */
.hljs,
.hljs-subst {
color: #444;
}
.hljs-comment {
color: #888888;
}
.hljs-keyword,
.hljs-attribute,
.hljs-selector-tag,
.hljs-meta-keyword,
.hljs-doctag,
.hljs-name {
font-weight: bold;
}
/* User color: hue: 0 */
.hljs-type,
.hljs-string,
.hljs-number,
.hljs-selector-id,
.hljs-selector-class,
.hljs-quote,
.hljs-template-tag,
.hljs-deletion {
color: #880000;
}
.hljs-title,
.hljs-section {
color: #880000;
font-weight: bold;
}
.hljs-regexp,
.hljs-symbol,
.hljs-variable,
.hljs-template-variable,
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #BC6060;
}
/* Language color: hue: 90; */
.hljs-literal {
color: #78A960;
}
.hljs-built_in,
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #397300;
}
/* Meta color: hue: 200 */
.hljs-meta {
color: #1f7199;
}
.hljs-meta-string {
color: #4d99bf;
}
/* Misc effects */
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
================================================
FILE: Demo.Shared/wwwroot/highlight/highlight.pack.js
================================================
/*
Highlight.js 10.2.0 (da7d149b)
License: BSD-3-Clause
Copyright (c) 2006-2020, Ivan Sagalaev
*/
var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset<n[0].offset?e:n:"start"===n[0].event?e:n:e.length?e:n}function c(e){s+="<"+a(e)+[].map.call(e.attributes,(function(e){return" "+e.nodeName+'="'+t(e.value)+'"'})).join("")+">"}function u(e){s+="</"+a(e)+">"}function g(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var d=l();if(s+=t(r.substring(i,d[0].offset)),i=d[0].offset,d===e){o.reverse().forEach(u);do{g(d.splice(0,1)[0]),d=l()}while(d===e&&d.length&&d[0].offset===i);o.reverse().forEach(c)}else"start"===d[0].event?o.push(d[0].node):o.pop(),g(d.splice(0,1)[0])}return s+t(r.substr(i))}});const s="</span>",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=`<span class="${e}">`}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function g(e){return e?"string"==typeof e?e:e.source:null}const d="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},m={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},b=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(m),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=b("//","$"),x=b("/\\*","\\*/"),E=b("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:d,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>g(e)).join("")}(n,
gitextract_q7_l1jjh/
├── .gitignore
├── BlazorDateRangePicker/
│ ├── BlazorDateRangePicker.csproj
│ ├── Calendar.razor
│ ├── Calendar.razor.cs
│ ├── Calendar.razor.css
│ ├── CalendarType.cs
│ ├── DateRange.cs
│ ├── DateRangePicker.razor
│ ├── DateRangePicker.razor.cs
│ ├── DateRangePicker.razor.css
│ ├── DateRangePickerConfig.cs
│ ├── DateRangePickerExtensions.cs
│ ├── Enums.cs
│ ├── IConfigurableOptions.cs
│ ├── PickerContainer.razor
│ ├── TimePicker.razor
│ ├── TimePicker.razor.cs
│ ├── TimePicker.razor.css
│ ├── TimeSettings.cs
│ ├── _Imports.razor
│ └── wwwroot/
│ └── clickAndPositionHandler.js
├── BlazorDateRangePicker.sln
├── Demo.ClientSideApp/
│ ├── App.razor
│ ├── Demo.ClientSideApp.csproj
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── _Imports.razor
│ └── wwwroot/
│ └── index.html
├── Demo.ServerSideApp/
│ ├── App.razor
│ ├── Demo.ServerSideApp.csproj
│ ├── Pages/
│ │ └── _Host.cshtml
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── _Imports.razor
│ ├── appsettings.Development.json
│ └── appsettings.json
├── Demo.Shared/
│ ├── BlazorClipboard.cs
│ ├── Demo.Shared.csproj
│ ├── Pages/
│ │ ├── BothSidesSelection.razor
│ │ ├── Container.razor
│ │ ├── CustomButtons.razor
│ │ ├── CustomClickHandler.razor
│ │ ├── CustomDate.razor
│ │ ├── CustomDay.razor
│ │ ├── CustomInput.razor
│ │ ├── DateInput.razor
│ │ ├── Disable.razor
│ │ ├── Example.razor
│ │ ├── Form.razor
│ │ ├── HandleEvents.razor
│ │ ├── Highlight.razor
│ │ ├── Index.razor
│ │ ├── Inline.razor
│ │ ├── Licence.razor
│ │ ├── Limits.razor
│ │ ├── Localization.razor
│ │ ├── Positioning.razor
│ │ ├── PredefinedRanges.razor
│ │ ├── Single.razor
│ │ └── Time.razor
│ ├── Shared/
│ │ ├── MainLayout.razor
│ │ └── Sidebar.razor
│ ├── _Imports.razor
│ └── wwwroot/
│ ├── css/
│ │ ├── open-iconic/
│ │ │ ├── FONT-LICENSE
│ │ │ ├── ICON-LICENSE
│ │ │ ├── README.md
│ │ │ └── font/
│ │ │ └── fonts/
│ │ │ └── open-iconic.otf
│ │ └── site.css
│ └── highlight/
│ ├── cshtml-razor.js
│ ├── default.css
│ ├── highlight.pack.js
│ ├── highlightInterop.js
│ └── vs.css
├── LICENSE
├── README.md
└── SourceGenerators/
├── AddPropertiesGenerator.cs
├── CopyPropertiesGenerator.cs
└── SourceGenerators.csproj
SYMBOL INDEX (141 symbols across 16 files)
FILE: BlazorDateRangePicker/Calendar.razor.cs
class Calendar (line 16) | public partial class Calendar : ComponentBase
method GetDayNames (line 54) | private List<string> GetDayNames()
method PreviousMonth (line 72) | private Task PreviousMonth(bool enabled)
method NextMonth (line 78) | private Task NextMonth(bool enabled)
method MonthSelected (line 84) | private Task MonthSelected(int month)
method YearSelected (line 90) | private Task YearSelected(int year)
method ClickDate (line 99) | private Task ClickDate(CalendarItem dt)
method OnMouseOverDate (line 105) | private Task OnMouseOverDate(DateTimeOffset date)
method GetWeekOfYear (line 114) | private int GetWeekOfYear(DateTime time)
method GetIso8601WeekOfYear (line 121) | private int GetIso8601WeekOfYear(DateTime time)
FILE: BlazorDateRangePicker/CalendarType.cs
class CalendarType (line 14) | public class CalendarType
method CalendarType (line 30) | public CalendarType(DateRangePicker picker, SideType side)
method ChangeMonth (line 37) | public async Task ChangeMonth(DateTimeOffset month)
method CalculateCalendar (line 43) | public async Task CalculateCalendar()
method UpdateCellClasses (line 87) | private async Task UpdateCellClasses(CalendarItem day)
method IsDayDisabled (line 184) | private async Task<bool> IsDayDisabled(DateTimeOffset date)
method GetCustomDateClass (line 197) | private async Task<string> GetCustomDateClass(DateTimeOffset date)
class CalendarItem (line 219) | public class CalendarItem
FILE: BlazorDateRangePicker/DateRange.cs
class DateRange (line 12) | public class DateRange
FILE: BlazorDateRangePicker/DateRangePicker.razor.cs
class DateRangePicker (line 20) | public partial class DateRangePicker : ComponentBase, IConfigurableOptions
method OnInitialized (line 187) | protected override void OnInitialized()
method OnAfterRenderAsync (line 237) | protected override Task OnAfterRenderAsync(bool firstRender)
method SetParametersAsync (line 243) | public override async Task SetParametersAsync(ParameterView parameters)
method OnParametersSetAsync (line 280) | protected override async Task OnParametersSetAsync()
method OnTextInput (line 340) | public virtual Task OnTextInput(ChangeEventArgs e)
method TryParseDates (line 407) | private (bool startDateParsed, bool endDateParsed) TryParseDates(strin...
method LostFocus (line 423) | public void LostFocus(FocusEventArgs _)
method Reset (line 428) | public virtual async Task Reset()
method ClickRange (line 437) | private Task ClickRange(MouseEventArgs e, string label)
method LeftMonthChanged (line 466) | private Task LeftMonthChanged(DateTimeOffset date)
method RightMonthChanged (line 475) | private Task RightMonthChanged(DateTimeOffset date)
method MonthChanged (line 486) | private async Task MonthChanged(DateTimeOffset? leftDate, DateTimeOffs...
method StartTimeChanged (line 518) | private async Task StartTimeChanged(TimeSpan start)
method EndTimeChanged (line 525) | private async Task EndTimeChanged(TimeSpan end)
method ClickDate (line 532) | public virtual async Task ClickDate(DateTimeOffset date)
method SafeSetStartTime (line 564) | private DateTimeOffset SafeSetStartTime(DateTimeOffset date) => SafeSe...
method SafeSetEndTime (line 566) | private DateTimeOffset SafeSetEndTime(DateTimeOffset date) => SafeSetT...
method SafeSetTime (line 568) | private DateTimeOffset SafeSetTime(DateTimeOffset date, bool startTime)
method OnHoverDate (line 593) | private async Task OnHoverDate(DateTimeOffset date)
method ClickApply (line 603) | public async Task ClickApply(MouseEventArgs e)
method ClickCancel (line 623) | public async Task ClickCancel(MouseEventArgs e)
method Open (line 636) | public async Task Open()
method AdjustCalendars (line 676) | public virtual async Task AdjustCalendars()
method Toggle (line 709) | public async Task Toggle()
method Close (line 718) | public async Task Close()
method InvokeClickOutside (line 729) | [JSInvokable]
method DisposeAsync (line 739) | public async ValueTask DisposeAsync()
FILE: BlazorDateRangePicker/DateRangePickerConfig.cs
class DateRangePickerConfig (line 9) | public partial class DateRangePickerConfig : IConfigurableOptions
method DateRangePickerConfig (line 11) | public DateRangePickerConfig()
FILE: BlazorDateRangePicker/DateRangePickerExtensions.cs
class DateRangePickerExtensions (line 12) | public static class DateRangePickerExtensions
method AddDateRangePicker (line 17) | public static IServiceCollection AddDateRangePicker(this IServiceColle...
method AddDateRangePicker (line 31) | public static IServiceCollection AddDateRangePicker(this IServiceColle...
FILE: BlazorDateRangePicker/Enums.cs
type SideType (line 9) | public enum SideType
type DropsType (line 16) | public enum DropsType
FILE: BlazorDateRangePicker/IConfigurableOptions.cs
type IConfigurableOptions (line 15) | internal interface IConfigurableOptions
FILE: BlazorDateRangePicker/TimePicker.razor.cs
class TimePicker (line 15) | public partial class TimePicker
method OnInitialized (line 28) | protected override void OnInitialized()
method OnParametersSetAsync (line 34) | protected override async Task OnParametersSetAsync()
method Set (line 90) | private void Set(int? h = null, int? m = null, int? s = null)
type AmPmEnum (line 100) | public enum AmPmEnum
FILE: BlazorDateRangePicker/TimeSettings.cs
class TimeSettings (line 5) | public class TimeSettings
FILE: BlazorDateRangePicker/wwwroot/clickAndPositionHandler.js
function addClickOutsideEvent (line 10) | function addClickOutsideEvent(elementId, parentId, dotnetHelper) {
function getPickerPosition (line 24) | function getPickerPosition(elementId, parentId, drops, opens, skipAddLis...
FILE: Demo.Shared/BlazorClipboard.cs
type IClipboard (line 12) | public interface IClipboard
method GetTextAsync (line 17) | public Task<string?> GetTextAsync(CancellationToken cancellation = def...
method GetText (line 22) | public string? GetText();
method SetTextAsync (line 27) | public Task SetTextAsync(string text, CancellationToken cancellation =...
method SetText (line 32) | public void SetText(string text);
class BlazorClipboard (line 38) | public class BlazorClipboard(IJSRuntime jsRuntime) : IClipboard
method GetTextAsync (line 43) | public virtual async Task<string?> GetTextAsync(CancellationToken canc...
method GetText (line 49) | public virtual string? GetText()
method SetTextAsync (line 55) | public virtual async Task SetTextAsync(string text, CancellationToken ...
method SetText (line 61) | public virtual void SetText(string text)
FILE: Demo.Shared/wwwroot/highlight/cshtml-razor.js
function getXmlBlocks (line 9) | function getXmlBlocks(hljs, additional_blocks) {
function hljsDefineCshtmlRazor (line 91) | function hljsDefineCshtmlRazor(hljs) {
FILE: Demo.Shared/wwwroot/highlight/highlight.pack.js
function e (line 6) | function e(n){Object.freeze(n);var t="function"==typeof n;return Object....
class n (line 6) | class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ign...
method constructor (line 6) | constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}
method ignoreMatch (line 6) | ignoreMatch(){this.ignore=!0}
function t (line 6) | function t(e){return e.replace(/&/g,"&").replace(/</g,"<").replac...
function r (line 6) | function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach(...
function a (line 6) | function a(e){return e.nodeName.toLowerCase()}
function l (line 6) | function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].of...
method constructor (line 6) | constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(...
method addText (line 6) | addText(e){this.buffer+=t(e)}
method openNode (line 6) | openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.cla...
method closeNode (line 6) | closeNode(e){o(e)&&(this.buffer+=s)}
method value (line 6) | value(){return this.buffer}
method span (line 6) | span(e){this.buffer+=`<span class="${e}">`}
function c (line 6) | function c(e){s+="<"+a(e)+[].map.call(e.attributes,(function(e){return" ...
method constructor (line 6) | constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}
method top (line 6) | get top(){return this.stack[this.stack.length-1]}
method root (line 6) | get root(){return this.rootNode}
method add (line 6) | add(e){this.top.children.push(e)}
method openNode (line 6) | openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}
method closeNode (line 6) | closeNode(){if(this.stack.length>1)return this.stack.pop()}
method closeAllNodes (line 6) | closeAllNodes(){for(;this.closeNode(););}
method toJSON (line 6) | toJSON(){return JSON.stringify(this.rootNode,null,4)}
method walk (line 6) | walk(e){return this.constructor._walk(e,this.rootNode)}
method _walk (line 6) | static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e...
method _collapse (line 6) | static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(...
function u (line 6) | function u(e){s+="</"+a(e)+">"}
method constructor (line 6) | constructor(e){super(),this.options=e}
method addKeyword (line 6) | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNo...
method addText (line 6) | addText(e){""!==e&&this.add(e)}
method addSublanguage (line 6) | addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}
method toHTML (line 6) | toHTML(){return new l(this,this.options).value()}
method finalize (line 6) | finalize(){return!0}
function g (line 6) | function g(e){("start"===e.event?c:u)(e.node)}
class l (line 6) | class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e...
method constructor (line 6) | constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(...
method addText (line 6) | addText(e){this.buffer+=t(e)}
method openNode (line 6) | openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.cla...
method closeNode (line 6) | closeNode(e){o(e)&&(this.buffer+=s)}
method value (line 6) | value(){return this.buffer}
method span (line 6) | span(e){this.buffer+=`<span class="${e}">`}
class c (line 6) | class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootN...
method constructor (line 6) | constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}
method top (line 6) | get top(){return this.stack[this.stack.length-1]}
method root (line 6) | get root(){return this.rootNode}
method add (line 6) | add(e){this.top.children.push(e)}
method openNode (line 6) | openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}
method closeNode (line 6) | closeNode(){if(this.stack.length>1)return this.stack.pop()}
method closeAllNodes (line 6) | closeAllNodes(){for(;this.closeNode(););}
method toJSON (line 6) | toJSON(){return JSON.stringify(this.rootNode,null,4)}
method walk (line 6) | walk(e){return this.constructor._walk(e,this.rootNode)}
method _walk (line 6) | static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e...
method _collapse (line 6) | static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(...
class u (line 6) | class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){...
method constructor (line 6) | constructor(e){super(),this.options=e}
method addKeyword (line 6) | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNo...
method addText (line 6) | addText(e){""!==e&&this.add(e)}
method addSublanguage (line 6) | addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}
method toHTML (line 6) | toHTML(){return new l(this,this.options).value()}
method finalize (line 6) | finalize(){return!0}
function g (line 6) | function g(e){return e?"string"==typeof e?e:e.source:null}
function N (line 6) | function N(e,n){return n?+n:function(e){return w.includes(e.toLowerCase(...
method className (line 6) | className(){return this.unknownLanguage?"":"hljs "+this.detectedLanguage}
method highlighted (line 6) | highlighted(){if(!this.autoDetect&&!hljs.getLanguage(this.language))retu...
method autoDetect (line 6) | autoDetect(){return!(this.language&&(e=this.autodetect,!e&&""!==e));var e}
method render (line 6) | render(e){return e("pre",{},[e("code",{class:this.className,domProps:{in...
method install (line 6) | install(e){e.component("highlightjs",y)}
function p (line 6) | function p(e){return f.noHighlightRe.test(e)}
function m (line 6) | function m(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);va...
function b (line 6) | function b(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0...
function v (line 6) | function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const...
function x (line 6) | function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.use...
function E (line 6) | function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e....
function y (line 6) | function y(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
function j (line 6) | function j(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>...
function A (line 6) | function A(e){var n=y(e);return n&&!n.disableAutodetect}
function S (line 6) | function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}
FILE: SourceGenerators/AddPropertiesGenerator.cs
class AddPropertiesGenerator (line 7) | [Generator]
method Initialize (line 10) | public void Initialize(IncrementalGeneratorInitializationContext context)
method IsIConfigurableOptionsInterface (line 26) | private static bool IsIConfigurableOptionsInterface(SyntaxNode node) =>
method GetInterfaceSymbol (line 29) | private static INamedTypeSymbol? GetInterfaceSymbol(GeneratorSyntaxCon...
method GenerateSource (line 36) | private static void GenerateSource(SourceProductionContext context, (C...
method GenerateProperties (line 70) | private static string GenerateProperties(INamedTypeSymbol configurable...
FILE: SourceGenerators/CopyPropertiesGenerator.cs
class CopyPropertiesGenerator (line 7) | [Generator]
method Initialize (line 10) | public void Initialize(IncrementalGeneratorInitializationContext context)
method IsClassWithProperties (line 24) | private static bool IsClassWithProperties(SyntaxNode node)
method GetClassWithProperties (line 30) | private static ClassDeclarationSyntax GetClassWithProperties(Generator...
method Execute (line 35) | private static void Execute(Compilation compilation, ImmutableArray<Cl...
method GenerateCopyPropertiesMethod (line 44) | private static string GenerateCopyPropertiesMethod(INamedTypeSymbol cl...
Condensed preview — 78 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (256K chars).
[
{
"path": ".gitignore",
"chars": 3036,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
},
{
"path": "BlazorDateRangePicker/BlazorDateRangePicker.csproj",
"chars": 2176,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Razor\">\r\n\r\n <PropertyGroup>\r\n <TargetFrameworks>net6;net7;net8;net9;net10.0</TargetF"
},
{
"path": "BlazorDateRangePicker/Calendar.razor",
"chars": 4419,
"preview": "@*\n * author: Sergey Zaikin zaikinsr@yandex.ru\n * copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserve"
},
{
"path": "BlazorDateRangePicker/Calendar.razor.cs",
"chars": 5075,
"preview": "/**\r\n* @author: Sergey Zaikin zaikinsr@yandex.ru\r\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\r"
},
{
"path": "BlazorDateRangePicker/Calendar.razor.css",
"chars": 2009,
"preview": ".next span, .prev span {\n color: #fff;\n border: solid black;\n border-width: 0 2px 2px 0;\n border-radius: 0;"
},
{
"path": "BlazorDateRangePicker/CalendarType.cs",
"chars": 8127,
"preview": "/**\n* author: Sergey Zaikin zaikinsr@yandex.ru\n* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* li"
},
{
"path": "BlazorDateRangePicker/DateRange.cs",
"chars": 407,
"preview": "/**\n* author: Sergey Zaikin zaikinsr@yandex.ru\n* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* li"
},
{
"path": "BlazorDateRangePicker/DateRangePicker.razor",
"chars": 4099,
"preview": "@*\r\n * author: Sergey Zaikin zaikinsr@yandex.ru\r\n * copyright: Copyright (c) 2019 Sergey Zaikin. All rights reser"
},
{
"path": "BlazorDateRangePicker/DateRangePicker.razor.cs",
"chars": 26693,
"preview": "/**\r\n* @author: Sergey Zaikin zaikinsr@yandex.ru\r\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\r\n"
},
{
"path": "BlazorDateRangePicker/DateRangePicker.razor.css",
"chars": 6582,
"preview": ".daterangepicker {\n position: fixed;\n color: inherit;\n background-color: #fff;\n border-radius: 4px;\n bor"
},
{
"path": "BlazorDateRangePicker/DateRangePickerConfig.cs",
"chars": 1278,
"preview": "/**\n* @author: Sergey Zaikin zaikinsr@yandex.ru\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* "
},
{
"path": "BlazorDateRangePicker/DateRangePickerExtensions.cs",
"chars": 1451,
"preview": "/**\n* @author: Sergey Zaikin zaikinsr@yandex.ru\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* "
},
{
"path": "BlazorDateRangePicker/Enums.cs",
"chars": 399,
"preview": "/**\n* author: Sergey Zaikin zaikinsr@yandex.ru\n* copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* li"
},
{
"path": "BlazorDateRangePicker/IConfigurableOptions.cs",
"chars": 9972,
"preview": "/**\n* @author: Sergey Zaikin zaikinsr@yandex.ru\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* "
},
{
"path": "BlazorDateRangePicker/PickerContainer.razor",
"chars": 178,
"preview": "@Content\n\n@code{\n RenderFragment Content { get; set; }\n\n public void SetContent(RenderFragment content)\n {\n "
},
{
"path": "BlazorDateRangePicker/TimePicker.razor",
"chars": 1019,
"preview": "<select class=\"hourselect\" @bind=\"Hour\">\n @foreach (var hour in HoursRange)\n {\n <option value=\"@hour\" sele"
},
{
"path": "BlazorDateRangePicker/TimePicker.razor.cs",
"chars": 3642,
"preview": "/**\r\n* @author: Sergey Zaikin zaikinsr@yandex.ru\r\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\r"
},
{
"path": "BlazorDateRangePicker/TimePicker.razor.css",
"chars": 288,
"preview": "select.hourselect, select.minuteselect, select.secondselect, select.ampmselect {\n width: 50px;\n margin: 0 auto;\n "
},
{
"path": "BlazorDateRangePicker/TimeSettings.cs",
"chars": 274,
"preview": "using System.Collections.Generic;\n\nnamespace BlazorDateRangePicker\n{\n public class TimeSettings\n {\n public"
},
{
"path": "BlazorDateRangePicker/_Imports.razor",
"chars": 82,
"preview": "@using Microsoft.AspNetCore.Components\n@using Microsoft.AspNetCore.Components.Web"
},
{
"path": "BlazorDateRangePicker/wwwroot/clickAndPositionHandler.js",
"chars": 5203,
"preview": "/**\n* @author: Sergey Zaikin zaikinsr@yandex.ru\n* @copyright: Copyright (c) 2019 Sergey Zaikin. All rights reserved.\n* @"
},
{
"path": "BlazorDateRangePicker.sln",
"chars": 3123,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.13.357"
},
{
"path": "Demo.ClientSideApp/App.razor",
"chars": 434,
"preview": "<Router AppAssembly=\"typeof(Program).Assembly\" AdditionalAssemblies=\"new[] { typeof(CustomDate).Assembly }\">\n <Found"
},
{
"path": "Demo.ClientSideApp/Demo.ClientSideApp.csproj",
"chars": 657,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.BlazorWebAssembly\">\r\n\r\n <PropertyGroup>\r\n <TargetFramework>net9</TargetFramework>\r\n"
},
{
"path": "Demo.ClientSideApp/Program.cs",
"chars": 588,
"preview": "using BlazorDateRangePicker;\nusing Demo.ClientSideApp;\nusing Microsoft.AspNetCore.Components.WebAssembly.Hosting;\nusing"
},
{
"path": "Demo.ClientSideApp/Properties/launchSettings.json",
"chars": 571,
"preview": "{\n \"iisSettings\": {\n \"windowsAuthentication\": false,\n \"anonymousAuthentication\": true,\n \"iisExpress\": {\n "
},
{
"path": "Demo.ClientSideApp/_Imports.razor",
"chars": 290,
"preview": "@using System.Net.Http\n@using Microsoft.AspNetCore.Components.Forms\n@using Microsoft.AspNetCore.Components.Routing\n@usin"
},
{
"path": "Demo.ClientSideApp/wwwroot/index.html",
"chars": 6148,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width\" />\n "
},
{
"path": "Demo.ServerSideApp/App.razor",
"chars": 434,
"preview": "<Router AppAssembly=\"typeof(Program).Assembly\" AdditionalAssemblies=\"new[] { typeof(CustomDate).Assembly }\">\n <Found"
},
{
"path": "Demo.ServerSideApp/Demo.ServerSideApp.csproj",
"chars": 321,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n <PropertyGroup>\n <TargetFramework>net9</TargetFramework>\n </PropertyGroup>"
},
{
"path": "Demo.ServerSideApp/Pages/_Host.cshtml",
"chars": 1219,
"preview": "@page \"/\"\n@namespace Demo.ServerSideApp.Pages\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n\n<!DOCTYPE html>\n<ht"
},
{
"path": "Demo.ServerSideApp/Program.cs",
"chars": 879,
"preview": "using BlazorDateRangePicker;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing M"
},
{
"path": "Demo.ServerSideApp/Properties/launchSettings.json",
"chars": 595,
"preview": "{\n \"iisSettings\": {\n \"windowsAuthentication\": false,\n \"anonymousAuthentication\": true,\n \"iisExpress\": {\n "
},
{
"path": "Demo.ServerSideApp/_Imports.razor",
"chars": 352,
"preview": "@using System.Net.Http\n@using Microsoft.AspNetCore.Authorization\n@using Microsoft.AspNetCore.Components.Forms\n@using Mi"
},
{
"path": "Demo.ServerSideApp/appsettings.Development.json",
"chars": 163,
"preview": "{\n \"DetailedErrors\": true,\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Debug\",\n \"System\": \"Information\",\n "
},
{
"path": "Demo.ServerSideApp/appsettings.json",
"chars": 182,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft\": \"Warning\",\n \"Microsoft.Hostin"
},
{
"path": "Demo.Shared/BlazorClipboard.cs",
"chars": 2000,
"preview": "using Microsoft.JSInterop;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#nullable enable\n\nnamespace Demo.Shar"
},
{
"path": "Demo.Shared/Demo.Shared.csproj",
"chars": 299,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Razor\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net9</TargetFramework>\n\t\t<AddRazorSupportFo"
},
{
"path": "Demo.Shared/Pages/BothSidesSelection.razor",
"chars": 3077,
"preview": "@page \"/bothSidesSelection\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n "
},
{
"path": "Demo.Shared/Pages/Container.razor",
"chars": 1553,
"preview": "@page \"/container\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a class"
},
{
"path": "Demo.Shared/Pages/CustomButtons.razor",
"chars": 3690,
"preview": "@page \"/customButtons\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a c"
},
{
"path": "Demo.Shared/Pages/CustomClickHandler.razor",
"chars": 2527,
"preview": "@page \"/customClickHandler\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n "
},
{
"path": "Demo.Shared/Pages/CustomDate.razor",
"chars": 2814,
"preview": "@page \"/customDate\"\n\n@using System.Threading\n\n<style>\n .dthighlight {\n background-color: aquamarine !importan"
},
{
"path": "Demo.Shared/Pages/CustomDay.razor",
"chars": 1266,
"preview": "@page \"/customDay\"\n\n<style>\n .daterangepicker .drp-calendar {\n max-width: 298px;\n }\n\n .daterangepicker "
},
{
"path": "Demo.Shared/Pages/CustomInput.razor",
"chars": 4018,
"preview": "@page \"/customInput\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a cla"
},
{
"path": "Demo.Shared/Pages/DateInput.razor",
"chars": 814,
"preview": "@inherits InputBase<DateRange>\n\n<DateRangePicker class=\"@(\"is-\" + CssClass + \" form-control\")\" \n StartD"
},
{
"path": "Demo.Shared/Pages/Disable.razor",
"chars": 3367,
"preview": "@page \"/disable\"\n\n@using System.Threading\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content"
},
{
"path": "Demo.Shared/Pages/Example.razor",
"chars": 620,
"preview": "@inject IClipboard Clipboard\n\n@if (ChildContent != null)\n{\n <div class=\"bd-example\">\n @ChildContent\n </div"
},
{
"path": "Demo.Shared/Pages/Form.razor",
"chars": 1318,
"preview": "@page \"/form\"\n@using System.ComponentModel.DataAnnotations;\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-cent"
},
{
"path": "Demo.Shared/Pages/HandleEvents.razor",
"chars": 7235,
"preview": "@page \"/handleEvents\"\n\n<style>\n .bd-example > .alert + .alert {\n margin-top: 0.3rem;\n }\n\n .alert {\n "
},
{
"path": "Demo.Shared/Pages/Highlight.razor",
"chars": 3428,
"preview": "@page \"/highlight\"\n\n@using System.Threading\n\n<style>\n .dthighlight {\n background-color: aquamarine !important"
},
{
"path": "Demo.Shared/Pages/Index.razor",
"chars": 2730,
"preview": "@page \"/\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a class=\"btn btn"
},
{
"path": "Demo.Shared/Pages/Inline.razor",
"chars": 631,
"preview": "@page \"/inline\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a class=\"b"
},
{
"path": "Demo.Shared/Pages/Licence.razor",
"chars": 1163,
"preview": "<h4>Licence</h4>\n\n<p>The MIT License (MIT)</p>\n\n<p>Copyright (c) @DateTime.Now.Year Sergey Zaikin</p>\n\n<p>\n Permissi"
},
{
"path": "Demo.Shared/Pages/Limits.razor",
"chars": 2082,
"preview": "@page \"/limits\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a class=\"b"
},
{
"path": "Demo.Shared/Pages/Localization.razor",
"chars": 1972,
"preview": "@page \"/localization\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a cl"
},
{
"path": "Demo.Shared/Pages/Positioning.razor",
"chars": 1354,
"preview": "@page \"/positioning\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a cla"
},
{
"path": "Demo.Shared/Pages/PredefinedRanges.razor",
"chars": 1827,
"preview": "@page \"/predefinedRanges\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <"
},
{
"path": "Demo.Shared/Pages/Single.razor",
"chars": 565,
"preview": "@page \"/single\"\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-content-between\">\n <a class=\"b"
},
{
"path": "Demo.Shared/Pages/Time.razor",
"chars": 6181,
"preview": "@page \"/time\"\n\n@using System.Globalization\n\n<div class=\"d-md-flex flex-md-row-reverse align-items-center justify-conten"
},
{
"path": "Demo.Shared/Shared/MainLayout.razor",
"chars": 1916,
"preview": "@inherits LayoutComponentBase\n@inject IJSRuntime JSRuntime\n\n<header class=\"navbar navbar-expand navbar-dark flex-column"
},
{
"path": "Demo.Shared/Shared/Sidebar.razor",
"chars": 2275,
"preview": "<div class=\"col-md-3 col-xl-2 bd-sidebar\">\n\n <button class=\"btn bd-search-docs-toggle d-md-none p-0 mt-3 mb-3 collap"
},
{
"path": "Demo.Shared/_Imports.razor",
"chars": 259,
"preview": "@using System.Net.Http\n@using Microsoft.AspNetCore.Components.Forms\n@using Microsoft.AspNetCore.Components.Routing\n@usi"
},
{
"path": "Demo.Shared/wwwroot/css/open-iconic/FONT-LICENSE",
"chars": 4017,
"preview": "SIL OPEN FONT LICENSE Version 1.1\n\nCopyright (c) 2014 Waybury\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to "
},
{
"path": "Demo.Shared/wwwroot/css/open-iconic/ICON-LICENSE",
"chars": 1073,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Waybury\n\nPermission is hereby granted, free of charge, to any person obtaining"
},
{
"path": "Demo.Shared/wwwroot/css/open-iconic/README.md",
"chars": 3495,
"preview": "[Open Iconic v1.1.1](http://useiconic.com/open)\n===========\n\n### Open Iconic is the open source sibling of [Iconic](http"
},
{
"path": "Demo.Shared/wwwroot/css/site.css",
"chars": 817,
"preview": "@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');\n\n.bd-navbar {\n background-color: #336fb0;\n z-in"
},
{
"path": "Demo.Shared/wwwroot/highlight/cshtml-razor.js",
"chars": 11561,
"preview": "/*\n * Language: cshtml-razor\n * Requires: xml.js, cs.js, css.js, javascript.js\n * Author: Roman Resh <romanresh@live.com"
},
{
"path": "Demo.Shared/wwwroot/highlight/default.css",
"chars": 1159,
"preview": "/*\n\nOriginal highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>\n\n*/\n\n.hljs {\n display: block;\n overflow"
},
{
"path": "Demo.Shared/wwwroot/highlight/highlight.pack.js",
"chars": 25666,
"preview": "/*\n Highlight.js 10.2.0 (da7d149b)\n License: BSD-3-Clause\n Copyright (c) 2006-2020, Ivan Sagalaev\n*/\nvar hljs=functio"
},
{
"path": "Demo.Shared/wwwroot/highlight/highlightInterop.js",
"chars": 184,
"preview": "window.highlightInterop = {\n highlight: function () {\n document.querySelectorAll('pre code').forEach((block) "
},
{
"path": "Demo.Shared/wwwroot/highlight/vs.css",
"chars": 837,
"preview": "/*\n\nVisual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>\n\n*/\n.hljs {\n display: "
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2019 Sergey Zaikin\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 18044,
"preview": "Date Range Picker for [Blazor](https://blazor.net/)\r\n=====================\r\n\r\n[
About this extraction
This page contains the full source code of the jdtcn/BlazorDateRangePicker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 78 files (233.2 KB), approximately 60.5k tokens, and a symbol index with 141 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.