UNPKG

blumjs

Version:
307 lines (268 loc) 8.6 kB
import { Component, Input, Output, EventEmitter, HostListener, ElementRef, Inject, OnChanges, SimpleChanges } from "@angular/core"; import {DateUnit} from "./dateunit"; import {CalendarBase, Calendar} from "./calendarbase"; import {Gregorian} from "./calendars/gregorian"; import {Jalali} from "./calendars/jalali"; import {Row, Cell} from "./elements"; import {DateToStringPipe, NameOfMonthPipe} from "./pipes"; @Component({ selector: 'bl-datepicker', template: ` <div class="datepicker"> <div class="datepicker-input"> <input type="text" [value]="model | dateToString:'shortDate':c" (click)="pickerClick()" readonly> </div> <div class="calendar-container" [hidden]="!pickerOpen"> <div class="calendar-title"> <a type="button" class="navigation-arrow left" (click)="prevMonth()"> <i class="fa fa-chevron-left" aria-hidden="true"></i> </a> <span class="current-date"> {{currentViewDate.month | nameOfMonth:c.calendar}} <span class="year"> {{currentViewDate.year}} </span> </span> <a type="button" class="navigation-arrow right" (click)="nextMonth()"> <i class="fa fa-chevron-right" aria-hidden="true"></i> </a> </div> <table> <thead> <tr> <th *ngFor="let cell of header.cells">{{cell.content}}</th> </tr> </thead> <tbody> <tr *ngFor="let row of rows"> <td *ngFor="let cell of row.cells" [ngClass]="{'selected': selectedDate.day == cell.content && selectedDate.year == currentViewDate.year && selectedDate.month == currentViewDate.month, 'not-empty': cell.content}" (click)="setDate(cell)" > <a *ngIf="cell.content">{{cell.content}}</a> </td> </tr> </tbody> </table> {{selectedDate.year}}/{{selectedDate.month+1}}/{{selectedDate.day}} <button (click)="today()" class="today-button">امروز</button> </div> </div> `, styles: [` a { text-decoration: none !important; color: black !important; } .datepicker { font-family: 'Roboto', sans-serif; box-sizing: border-box; width: 100%; } .today-button { background-color: rgb(34,116,71); border: 0; color: white; float: left; } .datepicker-input input { min-height: 23.3333px; padding: 2px; border: 1px solid rgb(34,116,71); } .datepicker-input input:hover { cursor: pointer; } .today-button:hover { cursor: pointer; background-color: rgb(67, 148, 103); } .calendar-container { width: 250px; padding: 10px; margin: 5px; background-color: white; border: 0; border-radius: 5px; overflow: hidden; box-shadow: 0 19px 38px rgba(0, 0, 0, 0.30), 0 15px 12px rgba(0, 0, 0, 0.22); position: fixed; z-index: 9999; } .calendar-title { text-align: center; font-weight: bold; } .calendar-title > .current-date { font-size: 1.1em; line-height: 2em; } .calendar-title > .current-date > .year { color: rgb(34,116,71);; } .calendar-title > .navigation-arrow:hover { cursor: pointer; } .calendar-title > .navigation-arrow { color: grey; font-size: 2em; } .calendar-title > .navigation-arrow.left { float: left; } .calendar-title > .navigation-arrow.right { float: right; } .calendar-container > table { table-layout: fixed; text-align: center; vertical-align: middle; width: 98%; font-size: 0.5vw; } .calendar-container > table > tbody > tr > td, .calendar-container > table > thead > tr > th { width: 14%; position: relative; margin: 10px; } .calendar-container > table > tbody > tr > td:after { content: ''; display: block; margin-top: 100%; } .calendar-container > table > tbody > tr > td > a { position: absolute; top: 50%; line-height: 50%; bottom: 0; left: 0; right: 0; } .calendar-container > table > thead { font-weight: bold; } .calendar-container > table > tbody { font-size: 2em; } .calendar-container > table > tbody > tr > td.selected { background-color: rgb(34,116,71);; color: white; border-radius: 100%; } .calendar-container > table > tbody > tr > td.not-empty:hover { cursor: pointer; border: 1px solid rgb(34,116,71);; border-radius: 100%; } `], providers: [DateToStringPipe, NameOfMonthPipe] }) export class DatepickerComponent implements OnChanges { @Input() calendar: string; @Input() width: number = 200; @Output() modelChange: EventEmitter<Date> = new EventEmitter<Date>(); @Input() model: Date; private selectedDate: DateUnit; private currentViewDate: DateUnit; private pickerOpen: boolean = false; private rows: Row[]; private header: Row; private c: Calendar<CalendarBase>; constructor(@Inject(ElementRef) private _elementRef: ElementRef) { this.init(); }; ngOnChanges(changes: SimpleChanges): void { this.init(); } init() { if (!this.model) { return; } if (this.calendar && this.calendar.toLowerCase() == 'jalali') { this.c = new Calendar<Jalali>(Jalali); } else { this.c = new Calendar<Gregorian>(Gregorian); } this.currentViewDate = this.c.calendar.dateToDateUnit(this.model); this.selectedDate = this.c.calendar.dateToDateUnit(this.model); this.resetView(); } resetView() { this.header = this.c.weekHeaders(); let currentMonthLength = this.c.calendar.getMonthLength(this.currentViewDate); let dayNumberOfMonthFirst = this.c.calendar.dayNumberOfMonthFirst(this.currentViewDate); this.rows = []; let cellIndex = 0; for (let weekIndex = 0; weekIndex < Math.ceil((currentMonthLength + dayNumberOfMonthFirst) / 7); weekIndex++) { this.rows[weekIndex] = new Row(); for (let colIndex = 0; colIndex < 7; colIndex++) { this.rows[weekIndex].cells[colIndex] = new Cell(); if (weekIndex == 0 && colIndex < dayNumberOfMonthFirst) { continue; } if (cellIndex < currentMonthLength) { this.rows[weekIndex].cells[colIndex].content = (cellIndex + 1).toString(); } cellIndex++; } } } private setDate(cell: Cell) { this.selectedDate.year = this.currentViewDate.year; this.selectedDate.month = this.currentViewDate.month; this.selectedDate.day = +cell.content; this.confirm(); } private confirm() { this.model = this.c.calendar.dateUnitToDate(this.selectedDate); if(this.calendar === 'jalali') { this.model.setMonth(this.model.getMonth()+1); this.model = Jalali.jalaliToGregorian(this.model.getFullYear(), this.model.getMonth(), this.model.getDate()); this.model.setMonth(this.model.getMonth()-1); } this.modelChange.emit(this.model); this.pickerOpen = false; } private today() { this.model = new Date(); this.modelChange.emit(this.model); this.pickerOpen = false; } private nextMonth() { this.currentViewDate.addMonth(); this.resetView(); } private prevMonth() { this.currentViewDate.subMonth(); this.resetView(); } private pickerClick() { this.pickerOpen = true; this.init(); }; private cancel() { this.pickerOpen = false; } @HostListener('document:click', ['$event', '$event.target']) public onClick(event: MouseEvent, targetElement: HTMLElement): void { if (!targetElement) { return; } if (!this._elementRef.nativeElement.contains(targetElement)) { this.cancel(); } }; }