Скрыть строки без дат в текущем месяце (Помощник по настраиваемому календарю) - PullRequest
0 голосов
/ 02 марта 2020

После этой статьи: https://cpratt.co/bootstrap-4-responsive-calendar-asp-net-core-taghelper/ Мне удалось реализовать пользовательский помощник по тегам Календаря, который принимает в качестве параметров месяц и год и отображает календарь на этот месяц.

Он отображает стандартный календарь с несколькими днями из предыдущих месяцев и днями в будущем. Я хочу скрыть все строки, у которых нет дней в текущем месяце, поэтому в некоторых месяцах может быть только 5 строк вместо 6, как в стандартном календаре.

Я пытался скрыть некоторые ячейки, используя css, но это все равно дает мне 6 строк с пустыми ячейками.

см. Пример кода, как описано в статье:

https://codepen.io/chrisdpratt/pen/OOybam Как видите, есть строка с датами не в этом месяце. Я хочу отображать только те строки, в которых есть несколько включительных дней в текущем месяце.

А вот код в помощнике по тегам c#, который отображает html.

[HtmlTargetElement("calendar", TagStructure = TagStructure.NormalOrSelfClosing)]
public class CalendarTagHelper : TagHelper  
{
    public int Month { get; set; }

    public int Year { get; set; }

    public List<CalendarEvent> Events { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "section";
        output.Attributes.Add("class", "calendar");
        output.Content.SetHtmlContent(GetHtml());
        output.TagMode = TagMode.StartTagAndEndTag;
    }

    private string GetHtml()
    {
        var monthStart = new DateTime(Year, Month, 1);
        var events = Events?.GroupBy(e => e.Date);

        var html = new XDocument(
            new XElement("div",
                new XAttribute("class", "container-fluid"),
                new XElement("header",
                    new XElement("h4",
                        new XAttribute("class", "display-4 mb-2 text-center"),
                        monthStart.ToString("MMMM yyyy")
                    ),
                    new XElement("div",
                        new XAttribute("class", "row d-none d-lg-flex p-1 bg-dark text-white"),
                        Enum.GetValues(typeof(DayOfWeek)).Cast<DayOfWeek>().Select(d =>
                            new XElement("h5",
                                new XAttribute("class", "col-lg p-1 text-center"),
                                d.ToString()
                            )
                        )
                    )
                ),
                new XElement("div",
                    new XAttribute("class", "row border border-right-0 border-bottom-0"),
                    GetDatesHtml()
                )
            )
        );

        return html.ToString();

        IEnumerable<XElement> GetDatesHtml()
        {
            var startDate = monthStart.AddDays(-(int)monthStart.DayOfWeek);
            var dates = Enumerable.Range(0, 42).Select(i => startDate.AddDays(i));

            foreach (var d in dates)
            {
                if (d.DayOfWeek == DayOfWeek.Sunday && d != startDate)
                {
                    yield return new XElement("div",
                        new XAttribute("class", "w-100"),
                        String.Empty
                    );
                }

                var mutedClasses = "d-none d-lg-inline-block bg-light text-muted";
                yield return new XElement("div",
                    new XAttribute("class", $"day col-lg p-2 border border-left-0 border-top-0 text-truncate {(d.Month != monthStart.Month ? mutedClasses : null)}"),
                    new XElement("h5",
                        new XAttribute("class", "row align-items-center"),
                        new XElement("span",
                            new XAttribute("class", "date col-1"),
                            d.Day
                        ),
                        new XElement("small",
                            new XAttribute("class", "col d-lg-none text-center text-muted"),
                            d.DayOfWeek.ToString()
                        ),
                        new XElement("span",
                            new XAttribute("class", "col-1"),
                            String.Empty
                        )
                    ),
                    GetEventHtml(d)
                );
            }
        }

        IEnumerable<XElement> GetEventHtml(DateTime d)
        {
            return events?.SingleOrDefault(e => e.Key == d)?.Select(e =>
                new XElement("a",
                    new XAttribute("class", $"event d-block p-1 pl-2 pr-2 mb-1 rounded text-truncate small bg-{e.Type} text-white"),
                    new XAttribute("title", e.Title),
                    e.Title
                )
            ) ?? new[] {
                new XElement("p",
                    new XAttribute("class", "d-lg-none"),
                    "No events"
                )
            };
        }
    }
}

Я знаю, что мне нужно настроить эту строку var dates = Enumerable.Range(0, 42).Select(i => startDate.AddDays(i));, чтобы получить правильный диапазон, чтобы строки без дней в текущем месяце вообще не отображались, но, похоже, я не могу обернуть его вокруг.

1 Ответ

1 голос
/ 02 марта 2020

Вам просто нужно определить, сколько дней показывать, исходя из количества необходимых недель, то есть 42 (дня) для 6 недель. Я просто выбрал стандарт 42, потому что хотел, чтобы календарь всегда поддерживал одинаковую визуальную высоту.

В любом случае, чтобы рассчитать количество отображаемых недель, вы можете использовать что-то вроде:

var weeks = (int)Math.Ceiling((DateTime.DaysInMonth(Year, Month) + (int)monthStart.DayOfWeek) / 7f);

Затем просто замените инициализацию dates на:

var dates = Enumerable.Range(0, weeks * 7).Select(i => startDate.AddDays(i));
...