/* ph9datepicker.js ================ This file is for ph9's in-house date-picker. */ /* WHY CREATE OUR OWN? =================== Coming across modern, fast and cross platform date pickers is suprisingly hard, we could use jquery UI but it's hard to use on mobile and is even worse to try and customise, so instead have created our own! Date Pickers Look can be easily customised in "ph9datepicker-theme.css", please don't change the global version of the datepicker theme unless required. HOW TO USE! =========== This is built ontop of JQuery, so make sure you have JQuery Installed! Step 1) : Include ph9datepicker/js/ph9datepicker.js Step 2) : Include ph9datepicker/css/ph9datepicker.css Step 3) : Include ph9datepicker/css/ph9datepicker-theme.css Step 4) : Customise to fit the website's theme! Step 5) : Make any input you want to accept dates as type="date" and that's it! If you want to parse an input field back into a date you can use on our datebases, simply get the value of the input and then call fInputValueToPH9Date() with the input being the value of the input you wish to convert. */ /* FUNCTIONS ========= fOpenDatePicker ================ Called to open a date picker! Contains a bunch of internal functions -------------------------------------------- fGetAmountOfDaysInCurrentMonth ============================== Gets the amount of days in the current month! fOnDayChange(oSelectedDay) ========================== Called when the selected date has been changed, handles all input date assignment fGetAllPickerDays(oDate, nLength) ================================= Grabs every day from the start date + length! fConvertCurrentDateToPickerDays() ================================= Converts the current picker date to a selection of Pickable Days! fChangePickerDisplayDate(oNextDate) =================================== Changes the pickers month to display (called when arrows are pressed) fCreateTableBody() ================= Creates table body containing all pickable days of the selected month! fCreateTableHead() ================== Creates table head containing the days of the week and the navigation (month selection) fCreateButtons() =============== Creates the buttons at the bottom fCreateTable() ============== Creates table body containing all pickable days of the selected month! fCreateDiv(sClass) ================== Creates a div with the inputted classes string, this just stops duplicate code fCreateDatePicker() =================== Creates the date picker by joining everything together! -------------------------------------------- fCloseDatePicker() ================== Closes the datepicker! Call if you wish to close! fDestroyDatePicker() ==================== Destroys the root date picker object fInputValueToPH9Date(sInputDate) =============================== Converts an input's value into a data that can be stored on ph9's database. fHTMLDateToJavascriptDate(sDate) ================================ Converts an input field into a date object */ /* LOG === - 23/10/2019 - All Code Written and created! - Jed - 28/10/2019 - Made it so you can change months by pressing the month - Jed - Made it so you can change the year by typing in the year input field - Jed */ /* ANTIQUE BOTIQUE =============== We use fOnDateChangedCallback in antiques botique as a bindable function that is called when the date is changed, this is so we can do things anytime the date is changed, this will be included in the PH9 date picker in the future! For now this is the current workaround */ // Allow custom functions by calling this variable when a date is changed! var fOnDateChangedCallback = ""; /* fOpenDatePicker() ================= The main function for the PH9 date picker, call this from an input to create the date picker! - Param 1 : Nothing (void) - Returns : Nothing (void) */ function fOpenDatePicker() { /* LOCAL VARIABLE DECLORATION ========================== oClickedDate - The input object for the date picker that was clicked oDatePickedDate - The date picked by the user (Defaults to today's date) oDatePickerDate - The current date of the date picker (Default's to same as the user selected date) nDaysInWeek - The amount of days in the week we want to display nWeeksDisplayed - The amount of weeks we want to dispaly aMonthNames - An array of all the month names! (DON'T TOUCH!) */ // Store the date object / input that called this function var oClickedDate = $(this); // Store the date that has been picked by the user var oDatePickedDate = fHTMLDateToJavascriptDate( oClickedDate.val() ); // Store the current picker's date (Defaults to the current selected date ) var oDatePickerDate = fHTMLDateToJavascriptDate( oClickedDate.val() ); // Store the amount of days in the week we want var nDaysInWeek = 7; // Store the amount of weeks we want to display var nWeeksDisplayed = 6; // Store all the months in an array var aMonthNames = ["January", "February", "March" , "April" , "May" , "June" , "July" , "August" , "September", "October", "November", "December"]; /* fGetAmountOfDaysInCurrentMonth() ================================ Gets the amount of days in the current month! - Param 1 : Nothing (void!) - Returns : Amount of days in the current month! */ var fGetAmountOfDaysInCurrentMonth = function() { return new Date(oDatePickerDate.getFullYear(), oDatePickerDate.getMonth() + 1, 0).getDate(); }; /* fOnDayChange(oSelectedDay) ========================== Called when the selected date has been changed, handles all input date assignment - Param 1 : The selected day (Either a day object or a javascript date object0) - Returns : Nothing! (void) */ var fOnDayChange = function(oSelectedDay) { // Store the selected date string to be attatched to the clicked date input var sSelectedDate = ""; // Store the current selected date object var oCurrentSelected = $(".date-picker > .selection").find(".active"); // If the input is of type date if( typeof oSelectedDay.getMonth === 'function' ) { // Store the month and day! (We add 1 to counteract that javascript months start from 0) var sMonth = oSelectedDay.getMonth() + 1; var sDay = oSelectedDay.getDate(); // If the month's length is 1 if( sMonth.toString().length === 1 ) { // Add a 0 before the month sMonth = "0" + sMonth; } // If the day's length is 1 if( sDay.toString().length === 1 ) { // Add a 0 before the day sDay = "0" + sDay; } // Assign the selected date to the inputted date! sSelectedDate = sDay + "-" + sMonth + "-" + oSelectedDay.getFullYear(); } // If the input type isn't of type date else { // If the selected object contains an old class if( oSelectedDay.hasClass("old") ) { // Go back a month! oDatePickerDate.setMonth( oDatePickerDate.getMonth() - 1); } // Else If the selected object contains a new class else if( oSelectedDay.hasClass("new") ) { // Go forward a month! oDatePickerDate.setMonth( oDatePickerDate.getMonth() + 1); } // Store the month and day! (We add 1 to counteract that javascript months start from 0) var sMonth = oDatePickerDate.getMonth() + 1; var sDay = oSelectedDay.html(); // If the month's length is 1 if(sMonth.toString().length === 1) { // Add a 0 before the month sMonth = "0" + sMonth; } // If the day's length is 1 if(sDay.toString().length === 1) { // Add a 0 before the day sDay = "0" + sDay; } // Assign the selected date to equal the inputted date from the picker! sSelectedDate = sDay + "-" + sMonth + "-" + oDatePickerDate.getFullYear(); // Make this clicked day have the active class. oSelectedDay.addClass("active"); } // Remove the active class from the current selection oCurrentSelected.removeClass("active"); // Change The Date! oClickedDate.val( sSelectedDate ); // If the callback isn't empty then call it! if( fOnDateChangedCallback != "" ) fOnDateChangedCallback(); // Call fCloseDatePicker to close the date picker. fCloseDatePicker(); }; /* fGetAllPickerDays ================= Grabs every day from the start date + length! - Param 1 : The start date of the picker (Date object) - Param 2 : The length of the picker (int) - Returns : An array of all the dates in range (array of dates) */ var fGetAllPickerDays = function(oDate, nLength) { // Create an array variable to store all the days in var aAllDays = []; // Loop for the amount that the length is specified for(var nIndex = 0; nIndex < nLength; nIndex++ ) { // Add the current day to the array aAllDays.push( new Date(oDate) ); // Increment the date by 1 oDate.setDate( oDate.getDate() + 1 ); } // Return the result! return aAllDays; }; /* fConvertCurrentDateToPickerDays() ================================= Converts the current picker date to a selection of Pickable Days! - Param 1 : Nothing! (void) - Returns : Nothing! (void) */ var fConvertCurrentDateToPickerDays = function() { // Store the total amount of days we can load var nTotalAvailableDays = nDaysInWeek * nWeeksDisplayed; // Store the total amount of days in the selected month var nTotalDaysInSelectedMonth = fGetAmountOfDaysInCurrentMonth(); // Store an object thatwill be used to calculate the 1st sunday of the picker! var nMonthStartDate = new Date(oDatePickerDate.getFullYear(), oDatePickerDate.getMonth(), 1); // Set the date to the current date minus the current day number (This is so we can start from sunday! ) // Example, If the current day is tuesday, it would index as 2, that means if we do tuesday - 2 we get to sunday! nMonthStartDate.setDate( nMonthStartDate.getDate() - nMonthStartDate.getDay() ); // Return the result! return fGetAllPickerDays(nMonthStartDate, nTotalAvailableDays); }; /* fChangePickerDisplayDate(oNextDate) =================================== Changes the pickers month to display (called when arrows are pressed) - Param 1 : The date we are looking for - Returns : Nothing! (void) */ var fChangePickerDisplayDate = function( oNextDate = "" ) { // Create the table wrapper object var oPickerTableWrapper = fCreateDiv("", "PickerTableContentWrapper"); // If there has been a date inputted if(oNextDate != "") { // Assign the pickers date to the inputed date oDatePickerDate = oNextDate; } // Remove the table's content $("#PickerTableContentWrapper").remove(); // Add the new table's header and body oPickerTableWrapper.append( fCreateTableHead() ); oPickerTableWrapper.append( fCreateTableBody() ); // Append to the the actual table! $("#PickerTable").prepend(oPickerTableWrapper); }; /* fCreateTableBody() ================= Creates table body containing all pickable days of the selected month! Param 1 - Nothing! (void) Returns - Table Body Element (object) */ var fCreateTableBody = function() { // Store all the Pickable Days var aDisplayDays = fConvertCurrentDateToPickerDays(); // Create the tbody element and store it var oTableBody = $(""); // Store a table row string to append to the body var oRow = $(""); // For every element in the display dates array for( var nIndex = 0; nIndex < aDisplayDays.length; nIndex++ ) { // Store a variable for the class name of the day var sClass = 'day'; // If the current itterated month is the same month as the selected month and they are the same year if( aDisplayDays[nIndex].getMonth() == oDatePickedDate.getMonth() && aDisplayDays[nIndex].getFullYear() == oDatePickedDate.getFullYear() ) { // If the current itterated date is the same as the selected date if(aDisplayDays[nIndex].getDate() == oDatePickedDate.getDate()) { // Add the active class sClass += " active"; } } // if the current itterted date's month is greater than the picker date's month, and the dates are in the same year if( aDisplayDays[nIndex].getMonth() > oDatePickerDate.getMonth() && aDisplayDays[nIndex].getFullYear() ==oDatePickerDate.getFullYear() // Or if the current month is december and THIS ITTERATED month is January ||( aDisplayDays[nIndex].getMonth() == 0 && oDatePickerDate.getMonth() == 11) ) { // Add the new class sClass += " new"; } // Else if the current itterted date's month is less than the picker date's month or if the current month is January and THIS ITTERATED month is december else if( aDisplayDays[nIndex].getMonth() < oDatePickerDate.getMonth() || ( aDisplayDays[nIndex].getMonth() == 11 && oDatePickerDate.getMonth() == 0) ) { // Add the old class sClass += " old"; } // If the index is divisable by the days in the week and the index isn't 0, or if we are itterating on the last object if(nIndex % nDaysInWeek == 0 && nIndex != 0 || nIndex == ( aDisplayDays.length - 1 ) ) { // Append the row to the table body oTableBody.append(oRow); // If we have more rows to go if(nIndex != aDisplayDays.length - 1) { // Refresh the row variable to a new row! oRow = $(""); } } // Store the Day Element in a variable (jquery object) var oRowDayElement = $("" + aDisplayDays[nIndex].getDate() + ""); // Add function to click event to call function when user clicks the day element oRowDayElement.on("click", function() { // Call function to handle day change. fOnDayChange( $(this) ); }); // Add the td element to the row oRow.append(oRowDayElement); } // Add a space at the bottom of the table! oTableBody.append( $("") ); // Return the table body return oTableBody; }; /* fCreateTableHead() ================= Creates table head containing the days of the week and the navigation (month selection) Param 1 - Nothing! (void) Returns - Table Body Element (object) */ var fCreateTableHead = function() { // Create the thead element and store it var oTableHead = $(""); /* Generate the top of the header ============================== */ // Create a row element and store under oMonthSelectorRow var oMonthSelectorRow = $(""); // Create the back button var oPreviousButton = $("«"); // Create the next button var oNextButton = $("»"); // If the next button is clicked oNextButton.on("click", function() { // Change the picker date! fChangePickerDisplayDate( new Date( oDatePickerDate.getFullYear(), oDatePickerDate.getMonth() + 1 ) ); }); // If the back button is clicked oPreviousButton.on("click", function() { // Change the picker date! fChangePickerDisplayDate( new Date( oDatePickerDate.getFullYear(), oDatePickerDate.getMonth() - 1 ) ); }); // Create the month/year title var oCurrentMonth = $("" + aMonthNames[oDatePickerDate.getMonth() ] + ""); var oCurrentYear = $(""); var oCurrentDate = $(""); // Bind keypress event to the current year input field oCurrentYear.bind('keypress', function(oEvent) { // Store the character number pressed var nCharPressed = (oEvent.which) ? oEvent.which : oEvent.keyCode; // If the character pressed is a number if( nCharPressed > 31 && (nCharPressed < 48 || nCharPressed > 57) ) { // Stop the input field from adding text oEvent.preventDefault(); // Return False to stop input field if preventDefault didn't work return false; } // Otherwise if we haven't pressed the enter button else if(nCharPressed != 13) { // If the length of the input field is too big if( $(this).val().length > 3 ) { // Stop the input field from adding text oEvent.preventDefault(); // Return False to stop input field if preventDefault didn't work return false; } } // If the enter buttons is pressed else { $(this).blur(); } }); // Do some checks when the input is validated (When the input stroke is done, called after keypress) oCurrentYear.on('input', function() { // If the value of the input is more than 4 or if the input isn't a number if( $(this).val().length > 4 || isNaN( $(this).val() ) ) { // Set the value to the current year, this stops people pasting! $(this).val( oDatePickerDate.getFullYear() ); } // Else if the lenght of the input is 4 then update the year! else if($(this).val().length == 4) { // Update the year to the input year oDatePickerDate.setFullYear( $(this).val() ); // Delete the Month Display Picker $("#MonthDisplayPicker").remove(); // Generate the new table content and add it to the picker table! fChangePickerDisplayDate(); } }); // If the year is no longer in focus oCurrentYear.blur( function() { if( $(this).val().length == 0 ) { // Set the value to the current year, this stops people losing where the input field is! $(this).val( oDatePickerDate.getFullYear() ); } }); // Set the on click of the month header oCurrentMonth.on("click", function() { // Remove the date picker $("#PickerTableContentWrapper").remove(); // Create the month dislay picker and push it to the table! $("PickerTable").append( fCreateMonthDisplayPicker() ); }); // Add the year and date to the current date header! oCurrentDate.append(oCurrentMonth); oCurrentDate.append(oCurrentYear); // Append all the created items to the month selector row oMonthSelectorRow.append(oPreviousButton); oMonthSelectorRow.append(oCurrentDate ); oMonthSelectorRow.append(oNextButton ); /* Generate the bottom of the header ================================= */ // Create a row element and store under oDaysDisplayRow var oDaysDisplayRow = $(""); // Store an array of all the days in the week! var aDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; // Loop through all the days in the week for( nIndex = 0; nIndex < aDays.length; nIndex++ ) { // Create a new table header with the current week name and append to the row! oDaysDisplayRow.append( $("" + aDays[nIndex] + "") ); } /* Add Spaces, Append all to the table and Return the result ====================================================== */ // Create a row element for the spacing so we can add some space! var oSpaceRowTop = $(""); var oSpaceRowBottom = $(""); // Append rows to the table header oTableHead.append(oMonthSelectorRow); oTableHead.append(oSpaceRowTop); oTableHead.append(oDaysDisplayRow ); oTableHead.append(oSpaceRowBottom); // Return the table result return oTableHead; }; /* fCreateButtons() ================= Creates the buttons at the bottom Param 1 - Nothing! (void) Returns - Table Body Element (object) */ var fCreateButtons = function() { // Create a div with the class buttons-wrapper var oButtonsWrapper = fCreateDiv("buttons-wrapper"); // Create the close button var oButtonLeft = $("Close"); // Create the today button var oButtonRight = $("Today"); // Add the buttons to the button wrapper oButtonsWrapper.append(oButtonLeft ); oButtonsWrapper.append(oButtonRight); // Add event on click to the left button oButtonLeft.on("click", function() { // Call the close date picker function to handle it all! fCloseDatePicker(); }); // Add event on click to the right button oButtonRight.on("click", function() { // Call the on date change function to handle it all passing the new date which is today! fOnDayChange( new Date() ); }); // Return the generated buttons group return oButtonsWrapper; } /* fCreateTable() ============== Creates table containing the head and body of the table Param 1 - Nothing! (void) Returns - Table Element (object) */ var fCreateTable = function() { // Create the table element and store it var oTable = $("" ); var oContentWrapper = fCreateDiv("", "PickerTableContentWrapper"); // Append the table head and the table body to the content wrapper oContentWrapper.append( fCreateTableHead() ); oContentWrapper.append( fCreateTableBody() ); // Append the wrapper to the table oTable.append(oContentWrapper); // Return the table! return oTable; } /* fCreateDiv ========== Creates a div with the inputted classes string, this just stops duplicate code - Param 1 : The classes you want to attatch to the div (string) - Returns : Newly Created Div (Jquery Object) */ var fCreateDiv = function(sClass, sID = "") { // Create the DIV and return the object return $("
"); } /* fCreateDatePicker ================= Creates the date picker by joining everything together! - Param 1 : Nothing! (void) - Returns : Nothing! (void) */ var fCreateDatePicker = function() { // Generate all required elements for the date picker // Create the table var oTable = fCreateTable(); // Create the buttons group var oButtonsGroup = fCreateButtons(); // Create the date selection wrapper var oDateSelection = fCreateDiv("selection", "TableWrapper"); // Create the date picker wrapper var oDatePicker = fCreateDiv("date-picker"); // Create the picker wrapper var oDatePickerWrapper = fCreateDiv("date-picker-inner"); // Create the main container var oDatePickerContainer = fCreateDiv("ph9-date-picker-container"); // Create the background fill effect var oBackgroundFill = fCreateDiv("background-fill"); // Create the main global wrapper! (Root/parent) var oGlobalWrapper = fCreateDiv("ph9-date-picker-wrapper"); // Make it so when we click the background it closes the date picker oBackgroundFill.on("click", function() { // Call the close date picker function to handle it all! fCloseDatePicker(); }); /* Append the elements onto eachother (Starting from child to parent) */ oDateSelection .append(oTable ); oDateSelection .append(oButtonsGroup ); oDatePicker .append(oDateSelection ); oDatePickerWrapper .append(oDatePicker ); oDatePickerContainer.append(oDatePickerWrapper ); oGlobalWrapper .append(oBackgroundFill ); oGlobalWrapper .append(oDatePickerContainer); // Add table to the body $("body").append(oGlobalWrapper); } /* fCreateMonthDisplayPicker ========================= Creates the inner thead and tbody for the MonthDisplayPicker and adds it to the main table element! - Param 1 : Nothing (void!) - Returns : Nothing (void!) */ var fCreateMonthDisplayPicker = function() { // Create the wrapper for the month display table var oMonthDisplayPicker = fCreateDiv("month-display-picker", "MonthDisplayPicker"); /* CREATE TABLE HEAD! ================== */ // Create the table head element! var oTableHead = $("
"); var oTableHeadRow = $(""); var oTableHeadRowHeader = $(""); oTableHeadRow.append(oTableHeadRowHeader); oTableHead.append(oTableHeadRow); oTableHead.append($("") ); /* CREATE TABLE BODY! ================== */ // Create the table body! var oTableBody = $(""); // Create the table body! var oTableBodyRow = $(""); // Loop through all the months for( var nIndex = 0; nIndex < aMonthNames.length; nIndex++ ) { // Create the month and store in a variable var oMonth = $(""); // If this month is the current selected month if( nIndex == oDatePickerDate.getMonth() ) { // Add the active class to the element! oMonth.addClass("active"); } // Add a click event to the month buttons, so we can allow the user to change month oMonth.on("click", function() { // Delete the Month Display Picker $("#MonthDisplayPicker").remove(); // Set the month to the month id oDatePickerDate.setMonth( $(this).attr("id") ); // Generate the new table content and add it to the picker table! fChangePickerDisplayDate(); }); // If we aren't on the first element and we are ready to start a new line if(nIndex != 0 && nIndex % 3 == 0) { // Add the row to the table row oTableBody.append(oTableBodyRow); // Add a brand new table row! oTableBodyRow = $(""); } // Add the month to the table body oTableBodyRow.append(oMonth); } // Add the last table row to the table body oTableBody.append(oTableBodyRow); // Add a space to the bottom of the table row! oTableBody.append($("") ); // Add the table head to the wrapper oMonthDisplayPicker.append(oTableHead) // Add the table body to the wrapper oMonthDisplayPicker.append(oTableBody) // Add the month dislay picker to the picker table! $("#PickerTable").append(oMonthDisplayPicker); }; // Call the function to create the date picker! fCreateDatePicker(); } /* fCloseDatePicker() ================== Closes the datepicker! Call if you wish to close! - Param 1 : Nothing (void) - Returns : Nothing (void) */ function fCloseDatePicker() { // Add the close class to the container $(".ph9-date-picker-wrapper > .ph9-date-picker-container").addClass("close"); // Fade the opacity to 0, and destroy the date picker once done $(".ph9-date-picker-wrapper > .background-fill").fadeTo( "fast" , 0, function() { // Call Destroy Date Picker fDestroyDatePicker(); }); } /* fDestroyDatePicker() =================== Destroys the root date picker object - Param 1 : Nothing (void) - Returns : Nothing (void) */ function fDestroyDatePicker() { // Simply destroy the date picker wrapper $(".ph9-date-picker-wrapper").remove(); } /* fInputValueToPH9Date(sInputDate) =============================== Converts an input's value into a data that can be stored on ph9's database. - Param 1 : The value of the input we want to convert! (string) - Returns : The correct date format! (string) */ function fInputValueToPH9Date(sInputDate) { // Store the split values of the input var aDates = sInputDate.split(/\D/); // If the length of the array isn't 3 then we have an invalid input if(aDates.length != 3) { // Just return the input (Maybe change to exceptions later) return sInputDate; } // Return the result with correct format return aDates[2] + aDates[1] + aDates[0]; } /* fHTMLDateToJavascriptDate(sDate) ================================ Converts an input field into a date object - Param 1 : The input's date (string) - Returns : The date created (javascript date object) */ function fHTMLDateToJavascriptDate(sDate) { // If the date is empty if(sDate == "") { // Return today's date! return new Date(); } // Remove the dash from the dates and store all strings into an array var aDates = sDate.split(/\D/); // Minus 1 from the month as javascript dates start from 0 aDates[1] = parseInt( aDates[1] ) - 1; // Return the created date! return new Date(aDates[2], aDates[1], aDates[0]); } /* DOCUMENT READY! =============== When the document is ready, then make the date-picker work! */ $(document).ready( function() { // Grab all the date fields var oDateFields = $('[type="date"]'); // Swap the date fields out into text fields oDateFields.prop('type', 'text'); // Make the input read only oDateFields.prop("readonly", true); // Add the ph9-date class to all date fields oDateFields.addClass("ph9-date"); // Add on click function to all date fields oDateFields.on('click', function(oEvent) { // Stop the default date picker from showing up! oEvent.preventDefault(); }); // Make it so when we click the date picker it calls the fOpenDatePicker function! oDateFields.bind( "click" , fOpenDatePicker ); });
Select Month
" + aMonthNames[nIndex] + "