几个月前因项目需要,用业余时间对Ajax control Toolkits里的日历控件(Calendar)进行了扩展。今天在使用时发现了点Bug,修改了一下,把代码都Copy上来:
先看效果吧:
(灰色删除线的日期,点击了是没有反应的)
扩展工程只需三个文件一个cs文件,一个js文件,一个css文件。其中,js和css的 Build Action都为Embedded Resource,另外别忘了把AjaxControlToolkit引入到工程中。
2.CalendarExtender.js
3.Calendar.css
1.CalendarExtender.cs
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Text;
- using System.Web.UI;
- using AjaxControlToolkit;
- [assembly: System.Web.UI.WebResource("Custom.CalendarExtender.js", "text/javascript")]
- [assembly: System.Web.UI.WebResource("Custom.Calendar.css", "text/css", PerformSubstitution = true)]
- namespace Custom
- {
- [ClientCssResource("Custom.Calendar.css")]
- [ClientScriptResource("Custom.CalendarExtender", "Custom.CalendarExtender.js")]
- [ToolboxData("<{0}:CalendarExtender runat=server></{0}:CalendarExtender>")]
- public class CalendarExtender : AjaxControlToolkit.CalendarExtender
- {
- [DefaultValue(null)]
- [ExtenderControlProperty]
- [ClientPropertyName("lowerBoundDate")]
- public virtual DateTime? LowerBoundDate
- {
- get { return GetPropertyValue("LowerBoundDate", (DateTime?)null); }
- set { SetPropertyValue("LowerBoundDate", value); }
- }
- [DefaultValue(null)]
- [ExtenderControlProperty]
- [ClientPropertyName("upperBoundDate")]
- public virtual DateTime? UpperBoundDate
- {
- get { return GetPropertyValue("UpperBoundDate", (DateTime?)null ); }
- set { SetPropertyValue("UpperBoundDate", value); }
- }
- public IEnumerable<ScriptReference> GetScriptReferences()
- {
- return new ScriptReference[] { new ScriptReference("Custom.CalendarExtender.js", "Custom") };
- }
- }
- }
- // Register the namespace for the control.
- Type.registerNamespace('Custom');
- Custom.CalendarExtender = function(element) {
- /// <summary>
- /// A behavior that attaches a calendar date selector to a textbox
- /// </summmary>
- /// <param name="element" type="Sys.UI.DomElement">The element to attach to</param>
- Custom.CalendarExtender.initializeBase(this, [element]);
- this._lowerBoundDate = null;
- this._upperBoundDate = null;
- }
- Custom.CalendarExtender.prototype = {
- initialize: function() {
- /// <summary>
- /// Initializes the components and parameters for this behavior
- /// </summary>
- Custom.CalendarExtender.callBaseMethod(this, "initialize");
- },
- dispose: function() {
- /// <summary>
- /// Disposes this behavior's resources
- /// </summary>
- Custom.CalendarExtender.callBaseMethod(this, "dispose");
- },
- get_lowerBoundDate: function() {
- /// <summary>
- /// The date currently visible in the calendar
- /// </summary>
- /// <value type="Date" />
- if (this._lowerBoundDate != null) {
- return this._lowerBoundDate;
- }
- },
- set_lowerBoundDate: function(value) {
- if (value && (String.isInstanceOfType(value)) && (value.length != 0)) {
- value = new Date(value);
- }
- if (value) value = value.getDateOnly();
- if (this._lowerBoundDate != value) {
- this._lowerBoundDate = value;
- this.raisePropertyChanged("lowerBoundDate");
- }
- },
- get_upperBoundDate: function() {
- /// <value type="Date">
- /// The date to use for "Today"
- /// </value>
- if (this._upperBoundDate != null) {
- return this._upperBoundDate;
- }
- },
- set_upperBoundDate: function(value) {
- if (value && (String.isInstanceOfType(value)) && (value.length != 0)) {
- value = new Date(value);
- }
- if (value) value = value.getDateOnly();
- if (this._upperBoundDate != value) {
- this._upperBoundDate = value;
- this.raisePropertyChanged("upperBoundDate");
- }
- },
- _performLayout: function() {
- /// <summmary>
- /// Updates the various views of the calendar to match the current selected and visible dates
- /// </summary>
- var elt = this.get_element();
- if (!elt) return;
- if (!this.get_isInitialized()) return;
- if (!this._isOpen) return;
- var dtf = Sys.CultureInfo.CurrentCulture.dateTimeFormat;
- var selectedDate = this.get_selectedDate();
- var visibleDate = this._getEffectiveVisibleDate();
- var todaysDate = this.get_todaysDate();
- switch (this._mode) {
- case "days":
- var firstDayOfWeek = this._getFirstDayOfWeek();
- var daysToBacktrack = visibleDate.getDay() - firstDayOfWeek;
- if (daysToBacktrack <= 0)
- daysToBacktrack += 7;
- var startDate = new Date(visibleDate.getFullYear(), visibleDate.getMonth(), visibleDate.getDate() - daysToBacktrack, this._hourOffsetForDst);
- var currentDate = startDate;
- for (var i = 0; i < 7; i++) {
- var dayCell = this._daysTableHeaderRow.cells[i].firstChild;
- if (dayCell.firstChild) {
- dayCell.removeChild(dayCell.firstChild);
- }
- dayCell.appendChild(document.createTextNode(dtf.ShortestDayNames[(i + firstDayOfWeek) % 7]));
- }
- for (var week = 0; week < 6; week++) {
- var weekRow = this._daysBody.rows[week];
- for (var dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
- var dayCell = weekRow.cells[dayOfWeek].firstChild;
- if (dayCell.firstChild) {
- dayCell.removeChild(dayCell.firstChild);
- }
- dayCell.appendChild(document.createTextNode(currentDate.getDate()));
- dayCell.title = currentDate.localeFormat("D");
- dayCell.date = currentDate;
- //modify by arden 2008.8.21
- $common.removeCssClasses(dayCell.parentNode, ["ajax__calendar_other", "ajax__calendar_disabled", "ajax__calendar_active", "custom__calendar_lower"]);
- if (this._lowerBoundDate == null && this._upperBoundDate == null) {
- Sys.UI.DomElement.addCssClass(dayCell.parentNode, this._getCssClass(dayCell.date, 'd'));
- }
- else if ((this._upperBoundDate != null && currentDate > this._upperBoundDate) ||
- (this._lowerBoundDate != null && currentDate < this._lowerBoundDate)) {
- Sys.UI.DomElement.addCssClass(dayCell.parentNode, "custom__calendar_lower");
- }
- //modify end
- currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1, this._hourOffsetForDst);
- }
- }
- this._prevArrow.date = new Date(visibleDate.getFullYear(), visibleDate.getMonth() - 1, 1, this._hourOffsetForDst);
- this._nextArrow.date = new Date(visibleDate.getFullYear(), visibleDate.getMonth() + 1, 1, this._hourOffsetForDst);
- if (this._title.firstChild) {
- this._title.removeChild(this._title.firstChild);
- }
- this._title.appendChild(document.createTextNode(visibleDate.localeFormat("MMMM, yyyy")));
- this._title.date = visibleDate;
- break;
- case "months":
- for (var i = 0; i < this._monthsBody.rows.length; i++) {
- var row = this._monthsBody.rows[i];
- for (var j = 0; j < row.cells.length; j++) {
- var cell = row.cells[j].firstChild;
- cell.date = new Date(visibleDate.getFullYear(), cell.month, 1, this._hourOffsetForDst);
- cell.title = cell.date.localeFormat("Y");
- $common.removeCssClasses(cell.parentNode, ["ajax__calendar_other", "ajax__calendar_disabled", "ajax__calendar_active"]);
- Sys.UI.DomElement.addCssClass(cell.parentNode, this._getCssClass(cell.date, 'M'));
- }
- }
- if (this._title.firstChild) {
- this._title.removeChild(this._title.firstChild);
- }
- this._title.appendChild(document.createTextNode(visibleDate.localeFormat("yyyy")));
- this._title.date = visibleDate;
- this._prevArrow.date = new Date(visibleDate.getFullYear() - 1, 0, 1, this._hourOffsetForDst);
- this._nextArrow.date = new Date(visibleDate.getFullYear() + 1, 0, 1, this._hourOffsetForDst);
- break;
- case "years":
- var minYear = (Math.floor(visibleDate.getFullYear() / 10) * 10);
- for (var i = 0; i < this._yearsBody.rows.length; i++) {
- var row = this._yearsBody.rows[i];
- for (var j = 0; j < row.cells.length; j++) {
- var cell = row.cells[j].firstChild;
- cell.date = new Date(minYear + cell.year, 0, 1, this._hourOffsetForDst);
- if (cell.firstChild) {
- cell.removeChild(cell.lastChild);
- } else {
- cell.appendChild(document.createElement("br"));
- }
- cell.appendChild(document.createTextNode(minYear + cell.year));
- $common.removeCssClasses(cell.parentNode, ["ajax__calendar_other", "ajax__calendar_disabled", "ajax__calendar_active"]);
- Sys.UI.DomElement.addCssClass(cell.parentNode, this._getCssClass(cell.date, 'y'));
- }
- }
- if (this._title.firstChild) {
- this._title.removeChild(this._title.firstChild);
- }
- this._title.appendChild(document.createTextNode(minYear.toString() + "-" + (minYear + 9).toString()));
- this._title.date = visibleDate;
- this._prevArrow.date = new Date(minYear - 10, 0, 1, this._hourOffsetForDst);
- this._nextArrow.date = new Date(minYear + 10, 0, 1, this._hourOffsetForDst);
- break;
- }
- if (this._today.firstChild) {
- this._today.removeChild(this._today.firstChild);
- }
- this._today.appendChild(document.createTextNode(String.format(AjaxControlToolkit.Resources.Calendar_Today, todaysDate.localeFormat("MMMM d, yyyy"))));
- this._today.date = todaysDate;
- },
- _isOutOfBounds: function(date, part) {
- /// <summary>
- /// Gets whether the supplied date is out of the lower / upper bound date limits
- /// </summary>
- /// <param name="date" type="Date">The date to match</param>
- /// <param name="part" type="String">The most significant part of the date to test</param>
- /// <returns type="Boolean" />
- switch (part) {
- case 'd':
- //modify by arden 2008.11.8
- if (this._lowerBoundDate && date < this._lowerBoundDate) {
- return true;
- }
- else if (this._upperBoundDate && date > this._upperBoundDate) {
- return true;
- }
- break;
- case 'M':
- //modify by arden 2008.11.8
- if (this._lowerBoundDate && ((date.getMonth() < this._lowerBoundDate.getMonth() &
- date.getFullYear() == this._lowerBoundDate.getFullYear()) || date.getFullYear() < this._lowerBoundDate.getFullYear() )) {
- return true;
- }
- else if (this._upperBoundDate &&
- ( (date.getFullYear() == this._upperBoundDate.getFullYear() && date.getMonth() > this._upperBoundDate.getMonth()) ||
- date.getFullYear() > this._upperBoundDate.getFullYear())) {
- return true;
- }
- break;
- case 'y':
- if (this._lowerBoundDate && date.getFullYear() < this._lowerBoundDate.getFullYear())
- return true;
- else if (this._upperBoundDate && date.getFullYear() > this._upperBoundDate.getFullYear())
- return true;
- break;
- }
- return false;
- },
- _getCssClass: function(date, part) {
- /// <summary>
- /// Gets the cssClass to apply to a cell based on a supplied date
- /// </summary>
- /// <param name="date" type="Date">The date to match</param>
- /// <param name="part" type="String">The most significant part of the date to test</param>
- /// <returns type="String" />
- if (this._isSelected(date, part)) {
- return "ajax__calendar_active";
- } else if (this._isOutOfBounds(date, part)) {
- return "ajax__calendar_disabled";
- } else if (this._isOther(date, part)) {
- return "ajax__calendar_other";
- } else {
- return "";
- }
- },
- _cell_onclick: function(e) {
- /// <summary>
- /// Handles the click event of a cell
- /// </summary>
- /// <param name="e" type="Sys.UI.DomEvent">The arguments for the event</param>
- e.stopPropagation();
- e.preventDefault();
- if (!this._enabled) return;
- var target = e.target;
- var visibleDate = this._getEffectiveVisibleDate();
- Sys.UI.DomElement.removeCssClass(target.parentNode, "ajax__calendar_hover");
- switch (target.mode) {
- case "prev":
- case "next":
- this._switchMonth(target.date);
- break;
- case "title":
- switch (this._mode) {
- case "days": this._switchMode("months"); break;
- case "months": this._switchMode("years"); break;
- }
- break;
- case "month":
- if (!this._isOutOfBounds(target.date, 'M')) {
- if (target.month == visibleDate.getMonth()) {
- this._switchMode("days");
- } else {
- this._visibleDate = target.date;
- this._switchMode("days");
- }
- }
- break;
- case "year":
- if (!this._isOutOfBounds(target.date, 'y')) {
- if (target.date.getFullYear() == visibleDate.getFullYear()) {
- this._switchMode("months");
- } else {
- this._visibleDate = target.date;
- this._switchMode("months");
- }
- }
- break;
- case "day":
- if (!this._isOutOfBounds(target.date, 'd')) {
- this.set_selectedDate(target.date);
- this._switchMonth(target.date);
- this._blur.post(true);
- this.raiseDateSelectionChanged();
- }
- break;
- case "today":
- this.set_selectedDate(target.date);
- this._switchMonth(target.date);
- this._blur.post(true);
- this.raiseDateSelectionChanged();
- break;
- }
- }
- }
- Custom.CalendarExtender.registerClass("Custom.CalendarExtender", AjaxControlToolkit.CalendarBehavior);
- .custom__calendar_lower{color: #C0C0C0;text-decoration: line-through;}
使用方法:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
- <%@ Register assembly="AjaxCustomCalendar" namespace="Custom" tagprefix="cc1" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head runat="server">
- <title></title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <asp:ScriptManager ID="ScriptManager1" runat="server">
- </asp:ScriptManager>
- <br />
- <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
- <cc1:CalendarExtender ID="TextBox1_CalendarExtender" runat="server"
- TargetControlID="TextBox1">
- </cc1:CalendarExtender>
- <br />
- <br />
- </div>
- </form>
- </body>
- </html>
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- public partial class _Default : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!IsPostBack)
- {
- this.TextBox1_CalendarExtender.LowerBoundDate = DateTime.Today;
- this.TextBox1_CalendarExtender.UpperBoundDate = DateTime.Today.AddMonths(3);
- }
- }
- }