FullCalendar – jQuery Event Calendar in ASP.NET

https://github.com/esausilva/ASP.Net-EventCalendar

http://trentrichardson.com/examples/timepicker/

https://github.com/posabsolute/jQuery-Validation-Engine

https://github.com/xdan/datetimepicker

https://fullcalendar.io/docs1/event_rendering/Colors/

https://www.codeproject.com/articles/638674/full-calendar-a-complete-web-diary-system-for-jque

https://github.com/claviska/jquery-minicolors

http://www.whatibroke.com/2013/01/01/change-current-day-color-jquery-fullcalendar/ (自定背景色)

https://www.codeproject.com/articles/638674/full-calendar-a-complete-web-diary-system-for-jque

https://github.com/venkatbaggu/jqueryfullcalendaerasp.netmvc

http://www.venkatbaggu.com/calendar-in-asp-net-mvc/

https://github.com/fullcalendar/fullcalendar

https://github.com/fullcalendar/fullcalendar-scheduler

 

Libraries

sql:

CREATE TABLE [event]
(
	event_id INT IDENTITY(1,1) PRIMARY KEY,
	[description] NVARCHAR(100),
	title NVARCHAR(100),
	event_start DATETIME,
	event_end DATETIME,
	all_day BIT DEFAULT(0)
)
GO

  edit sql:

CREATE TABLE [event]
(
	event_id INT IDENTITY(1,1) PRIMARY KEY,
	[description] NVARCHAR(100),
	title NVARCHAR(100),
	event_start DATETIME,
	event_end DATETIME,
	all_day BIT DEFAULT(0),
	--overlap INT DEFAULT(0),
	--rendering VARCHAR(50),
	--color VARCHAR(10),
	typeid INT,
	adddate DATETIME DEFAULT(GETDATE()) 
)
GO

---日程事件類型(并自定義顯示的背景色,文本色)
CREATE TABLE eventType
(
	id INT IDENTITY(1,1) PRIMARY KEY,
	typename NVARCHAR(100),
	typedecs NVARCHAR(200),
	backgroundColor VARCHAR(20),
	textColor VARCHAR(20),
	borderColor VARCHAR(20)
)
GO

INSERT INTO eventType(typename,typedecs,backgroundColor,textColor,borderColor)VALUES(N'公司日程',N'公務','#ff9f89','#ff0000','#ffcccc')
INSERT INTO eventType(typename,typedecs,backgroundColor,textColor,borderColor)VALUES(N'私人日程',N'私務','green','black','red')

SELECT * FROM eventType

CREATE VIEW V_Event
AS
SELECT a.event_id, a.description, a.title, a.event_start, a.event_end, a.all_day,a.typeid,b.backgroundColor,b.textColor,b.borderColor FROM [event] AS a,eventType AS b WHERE a.typeid=b.id
GO

  

Default.aspx:
<%@ Page  Language="C#"  AutoEventWireup="true"   CodeBehind="Default.aspx.cs" Inherits="fullcalendardemo._Default" %>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>ASP.NET FullCalendar</title>
    <link href="ajax/libs/jqueryui/1.12.1/themes/cupertino/jquery-ui.min.css" rel="stylesheet" />
    <link href="ajax/libs/fullcalendar/3.1.1/fullcalendar.min.css" rel="stylesheet" />
    <link href="ajax/libs/qtip2/3.0.3/jquery.qtip.min.css" rel="stylesheet" />

    <style type='text/css'>
        body
        {
            margin-top: 40px;
            text-align: center;
            font-size: 14px;
            font-family: "Lucida Grande" ,Helvetica,Arial,Verdana,sans-serif;
        }
        #calendar
        {
            width: 900px;
            margin: 0 auto;
        }
        /* css for timepicker */
        .ui-timepicker-div dl
        {
            text-align: left;
        }
        .ui-timepicker-div dl dt
        {
            height: 25px;
        }
        .ui-timepicker-div dl dd
        {
            margin: -25px 0 10px 65px;
        }
        .style1
        {
            width: 100%;
        }
        
        /* table fields alignment*/
        .alignRight
        {
        	text-align:right;
        	padding-right:10px;
        	padding-bottom:10px;
        }
        .alignLeft
        {
        	text-align:left;
        	padding-bottom:10px;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
    </asp:ScriptManager>
    <div id="calendar">
    </div>
    <div id="updatedialog" style="font: 70% 'Trebuchet MS', sans-serif; margin: 50px;display: none;"
        title="Update or Delete Event">
        <table class="style1">
            <tr>
                <td class="alignRight">
                    Name:</td>
                <td class="alignLeft">
                    <input id="eventName" type="text" size="33" /><br /></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Description:</td>
                <td class="alignLeft">
                    <textarea id="eventDesc" cols="30" rows="3" ></textarea></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Start:</td>
                <td class="alignLeft">
                    <span id="eventStart"></span></td>
            </tr>
            <tr>
                <td class="alignRight">
                    End: </td>
                <td class="alignLeft">
                    <span id="eventEnd"></span><input type="hidden" id="eventId" /></td>
            </tr>
        </table>
    </div>
    <div id="addDialog" style="font: 70% 'Trebuchet MS', sans-serif; margin: 50px;" title="Add Event">
    <table class="style1">
            <tr>
                <td class="alignRight">
                    Name:</td>
                <td class="alignLeft">
                    <input id="addEventName" type="text" size="33" /><br /></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Description:</td>
                <td class="alignLeft">
                    <textarea id="addEventDesc" cols="30" rows="3" ></textarea></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Start:</td>
                <td class="alignLeft">
                    <span id="addEventStartDate" ></span></td>
            </tr>
            <tr>
                <td class="alignRight">
                    End:</td>
                <td class="alignLeft">
                    <span id="addEventEndDate" ></span></td>
            </tr>
        </table>
        
    </div>
    <div runat="server" id="jsonDiv" />
    <input type="hidden" id="hdClient" runat="server" />
    </form>

    <script src="ajax/libs/moment.js/2.18.1/moment.min.js" type="text/javascript"></script>
    <script src="ajax/libs/jquery/3.1.1/jquery.min.js" type="text/javascript"></script>
    <script src="ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" type="text/javascript"></script>
    <script src="ajax/libs/qtip2/3.0.3/jquery.qtip.min.js" type="text/javascript"></script>
    <script src="ajax/libs/fullcalendar/3.1.1/fullcalendar.min.js" type="text/javascript"></script>
    <script src='ajax/libs/fullcalendar/3.1.1/locale-all.js' type="text/javascript"></script>
    <script src="scripts/calendarscript.js" type="text/javascript"></script>
</body>
</html>

  

Default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;

namespace DuFullCalendar
{
    public partial class _Default : System.Web.UI.Page
    {

        //this method only updates title and description
        //this is called when a event is clicked on the calendar
        [System.Web.Services.WebMethod(true)]
        public static string UpdateEvent(CalendarEvent cevent)
        {
            List<int> idList = (List<int>)System.Web.HttpContext.Current.Session["idList"];
            if (idList != null && idList.Contains(cevent.id))
            {
                if (CheckAlphaNumeric(cevent.title) && CheckAlphaNumeric(cevent.description))
                {
                    EventDAO.updateEvent(cevent.id, cevent.title, cevent.description);

                    return "updated event with id:" + cevent.id + " update title to: " + cevent.title +
                    " update description to: " + cevent.description;
                }

            }

            return "unable to update event with id:" + cevent.id + " title : " + cevent.title +
                " description : " + cevent.description;
        }

        //this method only updates start and end time
        //this is called when a event is dragged or resized in the calendar
        [System.Web.Services.WebMethod(true)]
        public static string UpdateEventTime(ImproperCalendarEvent improperEvent)
        {
            List<int> idList = (List<int>)System.Web.HttpContext.Current.Session["idList"];
            if (idList != null && idList.Contains(improperEvent.id))
            {
                EventDAO.updateEventTime(improperEvent.id,
                                         Convert.ToDateTime(improperEvent.start),
                                         Convert.ToDateTime(improperEvent.end),
                                         improperEvent.allDay);  //allDay parameter added for FullCalendar 2.x

                return "updated event with id:" + improperEvent.id + " update start to: " + improperEvent.start +
                    " update end to: " + improperEvent.end;
            }

            return "unable to update event with id: " + improperEvent.id;
        }

        //called when delete button is pressed
        [System.Web.Services.WebMethod(true)]
        public static String deleteEvent(int id)
        {
            //idList is stored in Session by JsonResponse.ashx for security reasons
            //whenever any event is update or deleted, the event id is checked
            //whether it is present in the idList, if it is not present in the idList
            //then it may be a malicious user trying to delete someone elses events
            //thus this checking prevents misuse
            List<int> idList = (List<int>)System.Web.HttpContext.Current.Session["idList"];
            if (idList != null && idList.Contains(id))
            {
                EventDAO.deleteEvent(id);
                return "deleted event with id:" + id;
            }

            return "unable to delete event with id: " + id;
        }

        //called when Add button is clicked
        //this is called when a mouse is clicked on open space of any day or dragged 
        //over mutliple days
        [System.Web.Services.WebMethod]
        public static int addEvent(ImproperCalendarEvent improperEvent)
        {
            CalendarEvent cevent = new CalendarEvent()
            {
                title = improperEvent.title,
                description = improperEvent.description,
                start = Convert.ToDateTime(improperEvent.start),
                end = Convert.ToDateTime(improperEvent.end),
                allDay = improperEvent.allDay
            };

            if (CheckAlphaNumeric(cevent.title) && CheckAlphaNumeric(cevent.description))
            {
                int key = EventDAO.addEvent(cevent);

                List<int> idList = (List<int>)System.Web.HttpContext.Current.Session["idList"];

                if (idList != null)
                {
                    idList.Add(key);
                }

                return key; //return the primary key of the added cevent object
            }

            return -1; //return a negative number just to signify nothing has been added
        }
        /// <summary>
        ///隻可輸入 數字,字母,中文,中文標點符號
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static bool CheckAlphaNumeric(string str)
        {
            return Regex.IsMatch(str, @"^[a-zA-Z0-9 |\u4e00-\u9fa5|\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]*$");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}

  calendarscript.js

var currentUpdateEvent;
var addStartDate;
var addEndDate;
var globalAllDay;

function updateEvent(event, element) {
    //alert(event.description);

    if ($(this).data("qtip")) $(this).qtip("destroy");

    currentUpdateEvent = event;

    $('#updatedialog').dialog('open');
    $("#eventName").val(event.title);
    $("#eventDesc").val(event.description);
    $("#eventId").val(event.id);
    $("#eventStart").text("" + event.start.toLocaleString());

    if (event.end === null) {
        $("#eventEnd").text("");
    }
    else {
        $("#eventEnd").text("" + event.end.toLocaleString());
    }

    return false;
}

function updateSuccess(updateResult) {
    //alert(updateResult);
}

function deleteSuccess(deleteResult) {
    //alert(deleteResult);
}

function addSuccess(addResult) {
// if addresult is -1, means event was not added
//    alert("added key: " + addResult);

    if (addResult != -1) {
        $('#calendar').fullCalendar('renderEvent',
						{
						    title: $("#addEventName").val(),
						    start: addStartDate,
						    end: addEndDate,
						    id: addResult,
						    description: $("#addEventDesc").val(),
						    allDay: globalAllDay
						},
						true // make the event "stick"
					);


        $('#calendar').fullCalendar('unselect');
    }
}

function UpdateTimeSuccess(updateResult) {
    //alert(updateResult);
}

function selectDate(start, end, allDay) {

    $('#addDialog').dialog('open');
    $("#addEventStartDate").text("" + start.toLocaleString());
    $("#addEventEndDate").text("" + end.toLocaleString());

    addStartDate = start;
    addEndDate = end;
    globalAllDay = allDay;
    //alert(allDay);
}

function updateEventOnDropResize(event, allDay) {

    //alert("allday: " + allDay);
    var eventToUpdate = {
        id: event.id,
        start: event.start
    };

    if (event.end === null) {
        eventToUpdate.end = eventToUpdate.start;
    }
    else {
        eventToUpdate.end = event.end;
    }

    var endDate;
    if (!event.allDay) {
        endDate = new Date(eventToUpdate.end + 60 * 60000);
        endDate = endDate.toJSON();
    }
    else {
        endDate = eventToUpdate.end.toJSON();
    }

    eventToUpdate.start = eventToUpdate.start.toJSON();
    eventToUpdate.end = eventToUpdate.end.toJSON(); //endDate;
    eventToUpdate.allDay = event.allDay;

    PageMethods.UpdateEventTime(eventToUpdate, UpdateTimeSuccess);
}

function eventDropped(event, dayDelta, minuteDelta, allDay, revertFunc) {
    if ($(this).data("qtip")) $(this).qtip("destroy");

    updateEventOnDropResize(event);
}

function eventResized(event, dayDelta, minuteDelta, revertFunc) {
    if ($(this).data("qtip")) $(this).qtip("destroy");

    updateEventOnDropResize(event);
}
//隻可輸入數字,字母,中文,中文標點符號 20170417 塗聚文 EDIT
function checkForSpecialChars(stringToCheck) {
    var pattern = /[^A-Za-z0-9 |\u4e00-\u9fa5|\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]/;  //A-Za-z0-9 
    return pattern.test(stringToCheck); 
}
//是否整天時間
function isAllDay(startDate, endDate) {
    var allDay;

    if (startDate.format("HH:mm:ss") == "00:00:00" && endDate.format("HH:mm:ss") == "00:00:00") {
        allDay = true;
        globalAllDay = true;
    }
    else {
        allDay = false;
        globalAllDay = false;
    }
    
    return allDay;
}
//提示內容
function qTipText(start, end, description) {
    var text;

    if (end !== null)
        text =  "<strong>Start:</strong> " + start.format("MM/DD/YYYY hh:mm T") + "<br/><strong>End:</strong> " + end.format("MM/DD/YYYY hh:mm T") + "<br/><br/>" + description;
    else
        text =  "<strong>Start:</strong> " + start.format("MM/DD/YYYY hh:mm T") + "<br/><strong>End:</strong><br/><br/>" + description;

    return text;
}

$(document).ready(function() {
    // update Dialog
    $('#updatedialog').dialog({
        autoOpen: false,
        width: 470,
        buttons: {
            "update": function() {
                //alert(currentUpdateEvent.title);
                var eventToUpdate = {
                    id: currentUpdateEvent.id,
                    title: $("#eventName").val(),
                    description: $("#eventDesc").val()
                };

                if (checkForSpecialChars(eventToUpdate.title) || checkForSpecialChars(eventToUpdate.description)) {
                    alert("please enter characters: 可輸入數字,字母,中文,中文標點符號, 空格");
                }
                else {
                    PageMethods.UpdateEvent(eventToUpdate, updateSuccess);
                    $(this).dialog("close");

                    currentUpdateEvent.title = $("#eventName").val();
                    currentUpdateEvent.description = $("#eventDesc").val();
                    $('#calendar').fullCalendar('updateEvent', currentUpdateEvent);
                }

            },
            "delete": function() {

                if (confirm("do you really want to delete this event?")) {

                    PageMethods.deleteEvent($("#eventId").val(), deleteSuccess);
                    $(this).dialog("close");
                    $('#calendar').fullCalendar('removeEvents', $("#eventId").val());
                }
            }
        }
    });

    //add dialog
    $('#addDialog').dialog({
        autoOpen: false,
        width: 470,
        buttons: {
            "Add": function() {
                //alert("sent:" + addStartDate.format("dd-MM-yyyy hh:mm:ss tt") + "==" + addStartDate.toLocaleString());
                var eventToAdd = {
                    title: $("#addEventName").val(),
                    description: $("#addEventDesc").val(),
                    start: addStartDate.toJSON(),
                    end: addEndDate.toJSON(),

                    allDay: isAllDay(addStartDate, addEndDate)
                };
                
                if (checkForSpecialChars(eventToAdd.title) || checkForSpecialChars(eventToAdd.description)) {
                    alert("please enter characters: 可輸入數字,字母,中文,中文標點符號, 空格");
                }
                else {
                    //alert("sending " + eventToAdd.title);

                    PageMethods.addEvent(eventToAdd, addSuccess);
                    $(this).dialog("close");
                }
            }
        }
    });

    var date = new Date();
    var d = date.getDate();
    var m = date.getMonth();
    var y = date.getFullYear();
    var options = {
        weekday: "long", year: "numeric", month: "short",
        day: "numeric", hour: "2-digit", minute: "2-digit"
    };

    $('#calendar').fullCalendar({
        theme: true,
        header: {
            left: 'prev,next today customBtn',
            center: 'title',
            right: 'month,agendaWeek,agendaDay,listWeek' //顯示日程列表
        },
        customButtons: {
            customBtn: {
                text: 'Custom Button',
                click: function() {
                    alert('This custom button is hot! 🔥\nNow go have fun!');
                }
            }
        },
        defaultView: 'agendaWeek',
        eventClick: updateEvent,
        selectable: true,
        selectHelper: true,
        select: selectDate,
        editable: true,
        navLinks: true, // can click day/week names to navigate views
        weekNumbers: true, //顯示第几周
        weekNumbersWithinDays: true,
        weekNumberCalculation: 'zh-cn',
        locale: 'zh-cn',
        events: "JsonResponse.ashx",
        eventDrop: eventDropped,
        eventResize: eventResized,
        eventRender: function(event, element) {
            //alert(event.title);
            element.qtip({
                content: {
                    text: qTipText(event.start, event.end, event.description),
                    title: '<strong>' + event.title + '</strong>'
                },
                position: {
                    my: 'bottom left',
                    at: 'top right'
                },
                style: { classes: 'qtip-shadow qtip-rounded' }
            });
        }
    });
});

  

 JsonResponse.ashx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;
using System.Web.Services;


namespace DuFullCalendar
{
    /// <summary>
    /// JsonResponse 的摘要说明
    /// </summary>
    public class JsonResponse : IHttpHandler, IRequiresSessionState 
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            DateTime start = Convert.ToDateTime(context.Request.QueryString["start"]);
            DateTime end = Convert.ToDateTime(context.Request.QueryString["end"]);

            List<int> idList = new List<int>();
            List<ImproperCalendarEvent> tasksList = new List<ImproperCalendarEvent>();

            //Generate JSON serializable events
            foreach (CalendarEvent cevent in EventDAO.getEvents(start, end))
            {
                tasksList.Add(new ImproperCalendarEvent
                {
                    id = cevent.id,
                    title = cevent.title,
                    start = String.Format("{0:s}", cevent.start),
                    end = String.Format("{0:s}", cevent.end),

                    description = cevent.description,
                    allDay = cevent.allDay,
                });
                idList.Add(cevent.id);
            }

            context.Session["idList"] = idList;

            //Serialize events to string
            System.Web.Script.Serialization.JavaScriptSerializer oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            string sJSON = oSerializer.Serialize(tasksList);

            //Write JSON to response object
            context.Response.Write(sJSON);

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cevent"></param>
        /// <returns></returns>
        private String convertCalendarEventIntoString(CalendarEvent cevent)
        {
            String allDay = "true";
            if (ConvertToTimestamp(cevent.start).ToString().Equals(ConvertToTimestamp(cevent.end).ToString()))
            {

                if (cevent.start.Hour == 0 && cevent.start.Minute == 0 && cevent.start.Second == 0)
                {
                    allDay = "true";
                }
                else
                {
                    allDay = "false";
                }
            }
            else
            {
                if (cevent.start.Hour == 0 && cevent.start.Minute == 0 && cevent.start.Second == 0
                    && cevent.end.Hour == 0 && cevent.end.Minute == 0 && cevent.end.Second == 0)
                {
                    allDay = "true";
                }
                else
                {
                    allDay = "false";
                }
            }
            return "{" +
                      "id: '" + cevent.id + "'," +
                      "title: '" + HttpContext.Current.Server.HtmlEncode(cevent.title) + "'," +
                      "start:  " + ConvertToTimestamp(cevent.start).ToString() + "," +
                      "end: " + ConvertToTimestamp(cevent.end).ToString() + "," +
                      "allDay:" + allDay + "," +
                      "description: '" + HttpContext.Current.Server.HtmlEncode(cevent.description) + "'" +
                      "},";
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private long ConvertToTimestamp(DateTime value)
        {


            long epoch = (value.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
            return epoch;

        }
        /// <summary>
        /// 
        /// </summary>
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

 自定義樣式:

fullCalendarTimepicker.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="fullCalendarTimepicker.aspx.cs" Inherits="fullcalendardemo.fullCalendarTimepicker" %>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>ASP.NET FullCalendar</title>
    <link href="ajax/libs/jqueryui/1.12.1/themes/cupertino/jquery-ui.min.css" rel="stylesheet" />
    <link href="ajax/libs/fullcalendar/3.1.1/fullcalendar.min.css" rel="stylesheet" />
    <link href="ajax/libs/qtip2/3.0.3/jquery.qtip.min.css" rel="stylesheet" />   
    <link rel="stylesheet" media="all" type="text/css" href="ajax/libs/timepicker/jquery-ui-timepicker-addon.css" /> 
    <link rel="stylesheet" href="ajax/libs/formValidator/css/validationEngine.jquery.css" type="text/css"  media="screen" charset="utf-8" />

    <style type='text/css'>
        body
        {
            margin-top: 40px;
            text-align: center;
            font-size: 14px;
            font-family: "Lucida Grande" ,Helvetica,Arial,Verdana,sans-serif;
        }
        #calendar
        {
            width: 900px;
            margin: 0 auto;
        }
        /* css for timepicker */
        .ui-timepicker-div dl
        {
            text-align: left;
        }
        .ui-timepicker-div dl dt
        {
            height: 25px;
        }
        .ui-timepicker-div dl dd
        {
            margin: -25px 0 10px 65px;
        }
        .style1
        {
            width: 100%;
        }
        
        /* table fields alignment*/
        .alignRight
        {
        	text-align:right;
        	padding-right:10px;
        	padding-bottom:10px;
        }
        .alignLeft
        {
        	text-align:left;
        	padding-bottom:10px;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
    </asp:ScriptManager>
    <div id="calendar">
    </div>
    <div id="updatedialog" style="font: 70% 'Trebuchet MS', sans-serif; margin: 50px;display: none;"
        title="Update or Delete Event">
        <table class="style1">
            <tr>
                <td class="alignRight">
                    Name:</td>
                <td class="alignLeft">
                    <input id="eventName" type="text" size="33" /><br /></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Description:</td>
                <td class="alignLeft">
                    <textarea id="eventDesc" cols="30" rows="3" ></textarea></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Start:</td>
                <td class="alignLeft">
                    <input id="eventStart"  name="eventStart" value="" /></td>
            </tr>
            <tr>
                <td class="alignRight">
                    End: </td>
                <td class="alignLeft">
                    <input id="eventEnd" name="eventEnd" value=""/><input type="hidden" id="eventId" /></td>
            </tr>
        </table>
    </div>
    <div id="addDialog" style="font: 70% 'Trebuchet MS', sans-serif; margin: 50px;" title="Add Event">
    <table class="style1">
            <tr>
                <td class="alignRight">
                    Name:</td>
                <td class="alignLeft">
                    <input id="addEventName" type="text" size="33" /><br /></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Description:</td>
                <td class="alignLeft">
                    <textarea id="addEventDesc" cols="30" rows="3" ></textarea></td>
            </tr>
            <tr>
                <td class="alignRight">
                    Start:</td>
                <td class="alignLeft">
                    <input id="addEventStartDate" class="validate[required,funcCall[validate2time]]" name="addEventStartDate" value=""/></td>
            </tr>
            <tr>
                <td class="alignRight">
                    End:</td>
                <td class="alignLeft">
                    <input id="addEventEndDate" class="validate[required,funcCall[validate2time]]" name="addEventEndDate" value=""/></td>
            </tr>
        </table>
        
    </div>
    <div runat="server" id="jsonDiv" />
    <input type="hidden" id="hdClient" runat="server" />
    </form>

    <script src="ajax/libs/moment.js/2.18.1/moment.min.js" type="text/javascript"></script>
    <script src="ajax/libs/jquery/3.1.1/jquery.min.js" type="text/javascript"></script>
    <script src="ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" type="text/javascript"></script>
    <script src="ajax/libs/qtip2/3.0.3/jquery.qtip.min.js" type="text/javascript"></script>
     <script type="text/javascript" src="ajax/libs/timepicker/jquery-ui-timepicker-addon.js"></script>
     <script type="text/javascript" src="ajax/libs/timepicker/i18n/jquery-ui-timepicker-addon-i18n.min.js"></script>
     <script type="text/javascript" src="ajax/libs/timepicker/i18n/jquery-ui-timepicker-zh-CN.js"></script>
     <script type="text/javascript" src="ajax/libs/timepicker/jquery-ui-sliderAccess.js"></script>
    <script src="ajax/libs/fullcalendar/3.1.1/fullcalendar.min.js" type="text/javascript"></script>
    <script src='ajax/libs/fullcalendar/3.1.1/locale-all.js' type="text/javascript"></script>
        <script src="ajax/libs/formValidator/js/jquery.validationEngine.js" type="text/javascript"></script>
     <script src="ajax/libs/formValidator/js/languages/jquery.validationEngine-zh_CN.js" type="text/javascript"></script>  
     <script src="ajax/libs/jqueryui/1.12.1/ui/i18n/datepicker-zh-CN.js" type="text/javascript"></script>
    <script src="scripts/calendarscriptTime.js" type="text/javascript"></script>
</body>
</html>

  

calendarscriptTime.js:

var currentUpdateEvent;
var addStartDate;
var addEndDate;
var globalAllDay;

//修改時,穫取值
// 涂聚文 Geovin Du edit 20170417
function updateEvent(event, element) {
    //alert(event.description);

    if ($(this).data("qtip")) $(this).qtip("destroy");

    currentUpdateEvent = event;

    $('#updatedialog').dialog('open');
    $("#eventName").val(event.title);
    $("#eventDesc").val(event.description);
    $("#eventId").val(event.id);
    $("#eventStart").val("" + $.fullCalendar.formatDate(event.start, "YYYY-MM-DD HH:mm")); //text $.fullCalendar.formatDate(event.start, "YYYY-MM-DD HH:mm")
    $("#eventStart").datetimepicker({ timeInput: true, changeMonth: true, changeYear: true, dateFormat: 'yy-mm-dd', timeFormat: 'HH:mm', hourMin: 5, hourMax: 24, hourGrid: 3, minuteGrid: 15 }); //timeInput: true,
    //$("#eventStart").datetimepicker('setDate', (new Date())); 
    if (event.end === null) {
        $("#eventEnd").val(""); //text
    }
    else {
        $("#eventEnd").val("" + $.fullCalendar.formatDate(event.end, "YYYY-MM-DD HH:mm")); //text  event.end.toLocaleString()
        $("#eventEnd").datetimepicker({ timeInput: true, changeMonth: true, changeYear: true, dateFormat: 'yy-mm-dd', timeFormat: 'HH:mm', hourMin: 5, hourMax: 24, hourGrid: 3, minuteGrid: 15 }); //
    }

    return false;
}

function updateSuccess(updateResult) {
    //alert(updateResult);
}

function deleteSuccess(deleteResult) {
    //alert(deleteResult);
}

function addSuccess(addResult) {
    // if addresult is -1, means event was not added
    //    alert("added key: " + addResult);

    if (addResult != -1) {
        $('#calendar').fullCalendar('renderEvent',
						{
						    title: $("#addEventName").val(),
						    start: addStartDate,
						    end: addEndDate,
						    id: addResult,
						    description: $("#addEventDesc").val(),
						    allDay: globalAllDay
						},
						true // make the event "stick"
					);


        $('#calendar').fullCalendar('unselect');
    }
}

function UpdateTimeSuccess(updateResult) {
    //alert(updateResult);
}
//
$("#addEventStartDate").datetimepicker({
        timeInput: true,
        changeMonth: true,
        changeYear: true,
        dateFormat: 'yy-mm-dd',

        timeFormat: 'HH:mm', hourMin: 5, hourMax: 24, hourGrid: 3, minuteGrid: 15
});
//
$("#addEventEndDate").datetimepicker({
    timeInput: true,
    changeMonth: true,
    changeYear: true,
    dateFormat: 'yy-mm-dd',
    timeFormat: 'HH:mm', hourMin: 5, hourMax: 24, hourGrid: 3, minuteGrid: 15
}); 

//選擇時,穫取值
function selectDate(start, end, allDay) {
    //$('#addEventStartDate').datetimepicker();
    $('#addDialog').dialog('open');
    $("#addEventStartDate").val("" + $.fullCalendar.formatDate(start, "YYYY-MM-DD HH:mm")); //text //標簽span $.fullCalendar.formatDate(start, "yyyy/MM/dd HH:mm");
    $("#addEventEndDate").val("" + $.fullCalendar.formatDate(end, "YYYY-MM-DD HH:mm")); //text $.fullCalendar.formatDate(end, "yyyy/MM/dd HH:mm");
    //$("#addEventStartDate").datetimepicker('setDate', $.fullCalendar.formatDate(start, "YYYY-MM-DD HH:mm")); //設置值,日期格式還存在不相符問題
    addStartDate = start;
    addEndDate = end;
    globalAllDay = allDay;
    //alert(allDay);
}

function updateEventOnDropResize(event, allDay) {

    //alert("allday: " + allDay);
    var eventToUpdate = {
        id: event.id,
        start: event.start
    };

    if (event.end === null) {
        eventToUpdate.end = eventToUpdate.start;
    }
    else {
        eventToUpdate.end = event.end;
    }

    var endDate;
    if (!event.allDay) {
        endDate = new Date(eventToUpdate.end + 60 * 60000);
        endDate = endDate.toJSON();
    }
    else {
        endDate = eventToUpdate.end.toJSON();
    }

    eventToUpdate.start = eventToUpdate.start.toJSON();
    eventToUpdate.end = eventToUpdate.end.toJSON(); //endDate;
    eventToUpdate.allDay = event.allDay;

    PageMethods.UpdateEventTime(eventToUpdate, UpdateTimeSuccess);
}

function eventDropped(event, dayDelta, minuteDelta, allDay, revertFunc) {
    if ($(this).data("qtip")) $(this).qtip("destroy");

    updateEventOnDropResize(event);
}

function eventResized(event, dayDelta, minuteDelta, revertFunc) {
    if ($(this).data("qtip")) $(this).qtip("destroy");

    updateEventOnDropResize(event);
}
//隻可輸入數字,字母,中文,中文標點符號 20170417 塗聚文 EDIT
function checkForSpecialChars(stringToCheck) {
    var pattern = /[^A-Za-z0-9 |\u4e00-\u9fa5|\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]/;  //A-Za-z0-9 
    return pattern.test(stringToCheck);
}
//是否整天時間
function isAllDay(startDate, endDate) {
    var allDay;

    if (startDate.format("HH:mm:ss") == "00:00:00" && endDate.format("HH:mm:ss") == "00:00:00") {
        allDay = true;
        globalAllDay = true;
    }
    else {
        allDay = false;
        globalAllDay = false;
    }

    return allDay;
}
//提示內容
function qTipText(start, end, description) {
    var text;

    if (end !== null)
        text = "<strong>Start:</strong> " + start.format("YYYY-MM-DD hh:mm T") + "<br/><strong>End:</strong> " + end.format("YYYY-MM-DD hh:mm T") + "<br/><br/>" + description;
    else
        text = "<strong>Start:</strong> " + start.format("YYYY-MM-DD hh:mm T") + "<br/><strong>End:</strong><br/><br/>" + description;

    return text;
}

$(document).ready(function () { 

    // update Dialog 修改,刪除
    $('#updatedialog').dialog({
        autoOpen: false,
        width: 470,
        buttons: {
            "update": function () {
                //alert(currentUpdateEvent.title);
                var eventToUpdate = {
                    id: currentUpdateEvent.id,
                    title: $("#eventName").val(),
                    description: $("#eventDesc").val()
                };

                if (checkForSpecialChars(eventToUpdate.title) || checkForSpecialChars(eventToUpdate.description)) {
                    alert("please enter characters: 可輸入數字,字母,中文,中文標點符號, 空格");
                }
                else {
                    PageMethods.UpdateEvent(eventToUpdate, updateSuccess);
                    $(this).dialog("close");

                    currentUpdateEvent.title = $("#eventName").val();
                    currentUpdateEvent.description = $("#eventDesc").val();
                    $('#calendar').fullCalendar('updateEvent', currentUpdateEvent);
                }

            },
            "delete": function () {

                if (confirm("do you really want to delete this event?")) {

                    PageMethods.deleteEvent($("#eventId").val(), deleteSuccess);
                    $(this).dialog("close");
                    $('#calendar').fullCalendar('removeEvents', $("#eventId").val());
                }
            }
        }
    });

    //add dialog 添加
    $('#addDialog').dialog({
        autoOpen: false,
        width: 470,
        buttons: {
            "Add": function () {
                //alert("sent:" + addStartDate.format("dd-MM-yyyy hh:mm:ss tt") + "==" + addStartDate.toLocaleString());
                var eventToAdd = {
                    title: $("#addEventName").val(),
                    description: $("#addEventDesc").val(),
                    start: addStartDate.toJSON(), //addStartDate.toJSON()
                    end:addEndDate.toJSON(),
                    allDay: isAllDay(addStartDate, addEndDate)
                };

                if (checkForSpecialChars(eventToAdd.title) || checkForSpecialChars(eventToAdd.description)) {
                    alert("please enter characters: 可輸入數字,字母,中文,中文標點符號, 空格");
                }
                else {
                    //alert("sending " + eventToAdd.title);

                    PageMethods.addEvent(eventToAdd, addSuccess);
                    $(this).dialog("close");
                }
            }
        }
    });

    var date = new Date();
    var d = date.getDate();
    var m = date.getMonth();
    var y = date.getFullYear();
    var options = {
        weekday: "long", year: "numeric", month: "short",
        day: "numeric", hour: "2-digit", minute: "2-digit"
    };

    $('#calendar').fullCalendar({
        theme: true,
        header: {
            left: 'prev,next today customBtn',
            center: 'title',
            right: 'month,agendaWeek,agendaDay,listWeek' //顯示日程列表
        },
        customButtons: {
            customBtn: {
                text: 'Custom Button',
                click: function () {
                    alert('This custom button is hot! 🔥\nNow go have fun!');
                }
            }
        },
        defaultView: 'agendaWeek',
        eventClick: updateEvent,
        selectable: true,
        selectHelper: true,
        select: selectDate,
        editable: true,
        navLinks: true, // can click day/week names to navigate views
        weekNumbers: true, //顯示第几周
        //weekNumbersWithinDays: true,
        weekNumberCalculation: 'zh-cn',
        locale: 'zh-cn',
        events: "JsonResponse.ashx",
        eventDrop: eventDropped, //可以拖動
        eventResize: eventResized, //可以改變大小
        eventRender: function (event, element) {
            //alert(event.title);
            element.qtip({
                content: {
                    text: qTipText(event.start, event.end, event.description), //提示顯示的內容
                    title: '<strong>' + event.title + '</strong>'
                },
                position: {
                    my: 'bottom left',
                    at: 'top right'
                },
                style: { classes: 'qtip-shadow qtip-rounded' }
            });
        }
    });
});




function validate2time() {
    //alert("debug");

    var start = $("#addEventStartDate").val();
    var end = $("#addEventEndDate").val();
    var cresult = 0;
    if (new Date(start) < new Date(end)) {
        cresult = 0;
    }
    else {
        cresult = 1;
    }

    //     alert(cresult);
    if (cresult == 0) {
        return false;
    } else if (cresult == 1) {
        $.validationEngine.closePrompt("#addEventStartDate");
        return true;
    }

}

  jquery-ui-timepicker-addon.js (時間刻度格式修改)

			// Prevent displaying twice 顯示時間標題
			if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
				var noDisplay = ' ui_tpicker_unit_hide',
					html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + (o.oneLine && o.controlType === 'select' ? ' ui-timepicker-oneLine' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label' + ((o.showTime) ? '' : noDisplay) + '">' + o.timeText + '</dt>' +
								'<dd class="ui_tpicker_time '+ ((o.showTime) ? '' : noDisplay) + '"><input class="ui_tpicker_time_input" ' + (o.timeInput ? '' : 'disabled') + '/></dd>';

				// Create the markup
				for (i = 0, l = this.units.length; i < l; i++) {
					litem = this.units[i];
					uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
					show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];

					// Added by Peter Medeiros:
					// - Figure out what the hour/minute/second max should be based on the step values.
					// - Example: if stepMinute is 15, then minMax is 45. 分鐘顯示刻度
					max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
					gridSize[litem] = 0;

					html += '<dt class="ui_tpicker_' + litem + '_label' + (show ? '' : noDisplay) + '">' + o[litem + 'Text'] + '</dt>' +
								'<dd style="margin-top:2px;" class="ui_tpicker_' + litem + (show ? '' : noDisplay) + '"><div class="ui_tpicker_' + litem + '_slider' + (show ? '' : noDisplay) + '"></div>';//更改小時,分鐘刻度之間行距

					if (show && o[litem + 'Grid'] > 0) {
						html += '<div style="padding-left: 1px;"><table class="ui-tpicker-grid-label"><tr>'; //顯示小時,分鐘的刻度值的文本

						if (litem === 'hour') {
							for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
								gridSize[litem]++;
								var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
								html += '<td style="padding-left: 1px;margin-top:20px;" data-for="' + litem + '">' + tmph + '</td>';
							}
						}
						else {
							for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
								gridSize[litem]++;
								html += '<td style="padding-left: 1px;margin-top:20px;" data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
							}
						}

						html += '</tr></table></div>';
					}
					html += '</dd>';
				}

  jquery-ui-timepicker-addon.css:

.ui-timepicker-div .ui-widget-header { margin-bottom: 10px; margin-top:5px; }
.ui-timepicker-div dl { text-align: left; }
.ui-timepicker-div dl dt { float: left; clear:left; padding: 0 0 0 5px; }
.ui-timepicker-div dl dd { margin: 10px 10px 10px 40%; }
.ui-timepicker-div td { font-size: 90%; }
.ui-tpicker-grid-label { background: none; border: none; margin: 5px 15px 0px 0px; padding: 0; }
.ui-timepicker-div .ui_tpicker_unit_hide{ display: none; }

.ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input { background: none; color: inherit; border: none; outline: none; border-bottom: solid 1px #555; width: 95%; margin-top:15px;} /*把選擇的顯示時間文本和刻度條拉開開了*/
.ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input:focus { border-bottom-color: #aaa; }

.ui-timepicker-rtl{ direction: rtl; margin-top:20px; }
.ui-timepicker-rtl dl { text-align: right; padding: 0 5px 0 0; }
.ui-timepicker-rtl dl dt{ float: right; clear: right; color:#cccccc; }
.ui-timepicker-rtl dl dd { margin: 0 40% 10px 10px; }

/* Shortened version style ui_tpicker_timezone_label*/
.ui-timepicker-div.ui-timepicker-oneLine { padding-right: 2px;color:#cccccc;}
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time, 
.ui-timepicker-div.ui-timepicker-oneLine dt { display: none; }
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label { display: block; padding-top: 2px; padding-bottom:0px; }
.ui-timepicker-div.ui-timepicker-oneLine dl { text-align: right; }
.ui-timepicker-div.ui-timepicker-oneLine dl dd, 
.ui-timepicker-div.ui-timepicker-oneLine dl dd > div { display:inline-block; margin:0; }
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_minute:before,
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before { content:':'; display:inline-block; }
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_millisec:before,
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_microsec:before { content:'.'; display:inline-block; }
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide,
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide:before{ display: none; }

.ui-timepicker-div{}
.ui_tpicker_timezone_label { margin-top:10px; color:#000000;}
.ui_tpicker_time_label{ margin-top:20px; color:#000000;} /*"小時"文本格式*/
.ui-tpicker-grid-label{ color:#000000;} /*顯示小時,分鐘的刻度值的文本*/
.ui-datepicker-title{  margin-top:20px;   }

  

 

posted @ 2017-04-14 11:20  ®Geovin Du Dream Park™  阅读(2038)  评论(0编辑  收藏  举报