// --------------------- // INIT GLOBALS VARS // --------------------- var gDebug_On = false; // Debug mode - true for development, false for production var gBeforeLimit = 100; // limit on number of list events retrieved before target date var gAfterLimit = 100; // limit on number of list events retrieved after target date var g_rpt_master_id; // repeat master id of event being displayed, edited var g_cw_id; // event occurrence id of event being displayed or edited var gInitSerialize; // will hold serialized from data for ajax post var gPHPSESSID = "?PHPSESSID=" + '72t9nhr9ov6s6ctphleb0dgn64'; // php session id for maintaining state var gbanners_on = ""; // banners enabled flag var gCalendar = ""; // calendar name / identifier var gCalendarId = ""; // calendar database id var gMulticat_on = ""; // multiple category in category filter flag var gSkip_all = ""; // skip all option in category filter flag var gLoggedIn; // user is logged in flag var gCanAdd; // user can add events flag var gIsAdmin; // user is calendar admin flag var gIsManager; // user is category manager flag var gNumCatsCalendar; // Total number of categories in calendar var gNumCatsUser; // Number of categories viewable by user var gData; // data returned from ajax var cw_jsonStatus; // gData.status object returned from ajax var monthEvents; // object with month days having events and event count var gCameFromMonth = true; // flag that action came from month view var gCameFromDetail = false; // flag that action came from detail view var gCameFromUpdate = false; // flag that action came from update var gRefreshAfterEdit = false; // flag that event save was done, help reduce list refresh var gGetEventsDirection = 'beforeandafter'; // List view scroll lazy load direction (before, after and beforeandafter) var gNoEventsBefore = false; // flag that no events were found on lazy load before var gNoEventsAfter = false; // flag that no events were found on lazy load after var gDestinationScreen; // contains destination screen (#edit only MAY NOT BE ACTIVE AT THIS TIME) var introNoteMaxLength = 800; // limit for number of characters allowed in email note var jRemindBodyDIV; // object reference to #reminderform var gNoPublicCats = false; // flag if calendar has no public categories var setpassword = false; var last_saved_location_id = 0; var btnclicked = 'none'; // Used to detect button mousedown event when blur event preceeds click // From calendar options var gIsMilitary; // flag for calendar in military (24hr) mode var gLocationPrefix; // prefix for location display (e.g. @) var gTimeZone; // text timezone specifier var gTimeZoneOffset; // numeric timezone offset (e.g. -5 for EST) var gEventTitleGoMore; // flag for touch event in list go to more info url var gEventTitleGoAction; // action on going to more info link (e.g. target='_blank') var gCalShowBusy; // flag to show events as busy if not allowed to edit var gCalShowBusyText; // text to show in event title when show busy is on var gBannersOn; // flag for banner events enabled in calendar // Used to detect change in date for events list display var prior_occ_event_day = ''; var prior_occ_event_month = ''; var prior_occ_event_year = ''; // Today's date vars var today = new Date(); var todaydom = today.getDate(); var todaymonth = today.getMonth(); var todayyear = today.getFullYear(); var todaydatestr = ""+todayyear+('0' + (todaymonth+1)).slice(-2)+('0' + (todaydom)).slice(-2); // Init current view as calendar grid with list under // User can select 'list' view via icon touch var currentView = 'calendar'; var gselectedDateClass = ''; // class of selected date (enabled if events on day, disabled if no events on day) var gtodayDateClass = ''; var cal; // will become the calendar object (e.g. cal.date) var touchCapable = false; // Init element heights. May be reset by setElementHeights() var navTodayAddLogInOutht = 35; var calendarht = 272 + 8; // plus 8 for margin var listportraitfullht = window.innerHeight - navTodayAddLogInOutht - 10; var listlandscapefullht = window.innerWidth - navTodayAddLogInOutht; var listcalendarht = window.innerHeight - navTodayAddLogInOutht - calendarht - 30; var listcurrentfullht = listportraitfullht; // Init center of grid vars var gGridCenterX = 0; var gGridCenterY = 0; var gOrientation = 'portrait'; // Init as portrait setOrientation(); // Set orientation var based on initial orientation var gCurrentPlace = "events_cal_or_list"; // Init as calendar or list view var calendarSwipe = false; var dayListSwipe = false; var fullListSwipe = false; var gTimeLastAjax = new Date().getTime(); // Init - holds last time in msecs that server was called used for testing stale session // Fields to populate with values in edit event form var fieldsToPopulate = {"edittype":"input", "approved":"input", "rpt_last_flag":"input", "reminder_id":"input", "repeat_id":"input", "event_id":"input", "calendar_id":"input", "actiontype":"input", "imported":"input", "create_user_id":"input", "edit_user_id":"input", "editfrom":"input", "draft":"input", "old_draft":"input", "occ_changed":"input", "old_occ_changed":"input", "createtimestamp":"input", "title":"input", "allday":"checkbox", "noend":"checkbox", "rpt_sun":"checkbox", "rpt_mon":"checkbox", "rpt_tue":"checkbox", "rpt_wed":"checkbox", "rpt_thu":"checkbox", "rpt_fri":"checkbox", "rpt_sat":"checkbox", "rpt_noenddate":"checkbox", "description":"textarea", "privatenote":"textarea", "login_email":"span", "category_id":"select", "location_id":"select", "location_name":"input", "location_street":"input", "location_city":"input", "location_stateprovince":"input", "location_zippostal":"input", "location_country":"input", "emonth":"select", "eday":"select", "eyear":"select", "starthour":"select", "startminute":"select", "startampm":"select", "endhour":"select", "endminute":"select", "endampm":"select", "priortime":"select", "rpt_type":"select", "rpt_days":"select", "rpt_weeks":"select", "rpt_month_place":"select", "rpt_end_month":"select", "rpt_end_day":"select", "rpt_end_year":"select"}; // ---------------------------- // END OF INIT GLOBAL VARS // ---------------------------- // Function to set orientation global variable when called by orientation event listener function setOrientation() { if (Math.abs(window.orientation) === 90) { // Landscape gOrientation = 'landscape'; listcurrentfullht = listlandscapefullht; $("#loginlogodiv").hide(); } else { // Portrait gOrientation = 'portrait'; $("#loginlogodiv").show(); listcurrentfullht = listportraitfullht; } } function setElementHeights() { // Get list heights in calendar and list views navTodayAddLogInOutht = $("#navTodayAddLogInOut").height(); calendarht = $("#calendar").height() + 8; // plus 8 for margin listportraitfullht = window.innerHeight - navTodayAddLogInOutht - 10; listlandscapefullht = window.innerWidth - navTodayAddLogInOutht; listcalendarht = window.innerHeight - navTodayAddLogInOutht - calendarht - 30; listcurrentfullht = listportraitfullht; } // Listen for orientation changes. showCurrentView will always show list view if orientation landscape window.addEventListener("orientationchange", function() { setTimeout(orientationChanged, 150); } ); function orientationChanged() { setOrientation(); // Set new orientation, note: does not change currentView value //alert('cv:'+currentView+' or: '+gOrientation+' cp: '+gCurrentPlace); // If currently viewing calendar grid or full events list then do // showCurrentView to set list height and refresh list if needed if (gCurrentPlace == "events_cal_or_list") { if (currentView == 'list') { // If was already in list view and rotate to landscape then // showCurrentView without refresh of list since events list // not changed - save extra server hits showCurrentView(currentView, false); } else { // Else if prior view was calendar then show current view // with refresh of since events list changes between // calendar and list views when orientation changes showCurrentView(currentView, true); } } if (gCurrentPlace == 'eventdetails') { // Adjust height of event detail view div and set scroll to top $("#event").height(listcurrentfullht - 30).scrollTop(0); display_action_row(); } else if (gCurrentPlace == 'eventedit') { $("#eventform").height(listcurrentfullht -30).scrollTop(0); $("#eventform").hide(); $("#eventform").show(); display_action_row(); } else if (gCurrentPlace == 'categoryfilter') { $("#category_filter_list").height(listcurrentfullht - 30).scrollTop(0); display_action_row(); } } // Single place ot hide and show navigation bars for all views. This // is called often to keep navigation bars visible. iPhone virtual // keyboard keeps hiding navigation bars. Nobounce also helps keep // navigation bars from dissappearing function display_action_row() { $(".action_row").hide(); // First hide all acition rows if (gCurrentPlace == "events_cal_or_list") { // calendar or list view // Show / hide navigation icons and links based on custom url options if (nolognavbar == 1) { // This used to hide entire navigation bar but now // just hides add (+) icon and login link $("#navTodayAddLogInOut #a1").hide(); $("#navTodayAddLogInOut #loginlink").hide(); } else if ((gCalShowBusy == 1) && (!gLoggedIn)) { // Do not show add button if show busy set and not logged in $("#navTodayAddLogInOut #a1").hide(); } else { if (gLoggedIn) { $("#loginlink").hide(); $("#logoutlink").show(); $("#navTodayAddLogInOut #a1").show(); } else { $("#loginlink").show(); $("#logoutlink").hide(); $("#navTodayAddLogInOut #a1").hide(); } } // Show navigation bar $("#navTodayAddLogInOut").show(); } else if (gCurrentPlace == "eventdetails") { // event detail view $("#eventdetailactionrow").show(); } else if ((gCurrentPlace == "eventedit") || (gCurrentPlace == "eventadd")) { // adding or editing event $("#eventeditactionrow").show(); } else if (gCurrentPlace == "sendemail") { // sending event email $("#sendemailactionrow").show(); } else if (gCurrentPlace == "setreminder") { // setting event reminder $("#setreminderactionrow").show(); } else if (gCurrentPlace == "categoryfilter") { // showing category filter $("#categoryfilteractionrow").show(); } else if (gCurrentPlace == "chooseedit") { // choose edit occurrence or all repeats $("#chooseeditactionrow").show(); } // Scroll body to top in .5 seconds setTimeout(function(){ $("body").scrollTop(0); }, 500); } //##################################### Initialization ################################################ function init(){ // Display prompt to get calendar name if calendar not found // Or calendar identifier blank - this was also fixed by giving // templage calendars a value for calendar_redirect if ((gCalendarId == 0) || (gCalendar == '')) { $("#cal_id").val(gCalendar); if(cal){ $(cal.grid).hide(); } $("#promptCalendar").show(); $("#navTodayAddLogInOut").hide(); return false; } // Get calendar identifier from url into global if(window.location.href.match(/crd=([^&#]+)/i)){ gCalendar = RegExp.$1; } // Init Touch Controls if ('ontouchstart' in document.documentElement) { touchCapable = true; } if (touchCapable) { $("body").touchwipe({ wipeLeft: function() { swipeHandler("next"); }, wipeRight: function() { swipeHandler("prev"); }, preventDefaultEvents: false }); $("#calendar").touchwipe({ wipeLeft: function() { calendarSwipe = true; swipeHandler("next"); }, wipeRight: function() { calendarSwipe = true;; swipeHandler("prev"); }, preventDefaultEvents: false }); // Note: For some reason wipeUp is actually a wipe down of finger and wipeDown opposite $("#dayevents").touchwipe({ wipeLeft: function() { dayListSwipe = true; swipeHandler("next"); }, wipeRight: function() { dayListSwipe = true; swipeHandler("prev"); }, wipeUp: function() { //console.log('wipeUp'); // Only for full list, calendar not visible if ($("#calendar").is(":visible")) { return false; } // Only if list is scrolled to top scrollObj = $('#dayevents'); if(scrollObj.scrollTop() == 0) { //console.log('before'); fullListSwipe = true; swipeHandler("before"); } else { return false; } }, wipeDown: function() { //console.log('wipeDown'); // Only for full list, calendar not visible if ($("#calendar").is(":visible")) { return false; } // Only if list is scrolled to bottom scrollObj = $('#dayevents'); if(scrollObj.scrollTop() + scrollObj.innerHeight() >= scrollObj[0].scrollHeight) { //console.log('after'); fullListSwipe = true; swipeHandler("after"); } else { return false; } }, preventDefaultEvents: false }); } // ----------------------------------- // BIND EVENTS // ----------------------------------- // --------------------------- // Bind Main Navigation Events // --------------------------- // Login link $("#loginlink").bind("click", function(e){ if ($.active) { return false; } logInOut(e); }); // logout link $("#logoutlink").bind("click", function(e){ if ($.active) { return false; } logInOut(e); }); // Today link $(".todaylink").bind("click", function(){ if ($.active) { return false; } goToToday(); }); // View List icon $("#viewlist").bind("click", function(){ if ($.active) { return false; } showCurrentView('list', true); }); // View calendar icon $("#viewcalendar").bind("click", function(){ if ($.active) { return false; } $(".dayeventsA, .dayeventsB, .daydatedisplay, .noeventsonday").remove(); //emptying out the event list (note dayeventsB not being used) showCurrentView('calendar', true); }); // Add event icon $("a.addlink").bind("click", function(e){ if ($.active) { return false; } addEvent(e); }); // Refresh icon $("#refreshbtn").bind("click", function(){ if ($.active) { return false; } refreshCurrentView(); }); // ------------------------------------------------ // Bind Event List (calendar and list views) Events // ------------------------------------------------ // Display event detail $("#eventstemplate").bind("click", function(e){ if ($.active) { return false; } displayEvent(e); }); // ----------------------------- // Bind Event Detail View Events // ----------------------------- // Back link $("#eventdone").bind("click", function(){ if ($.active) { return false; } eventDone(); }); // Open email form $("#openNewEmail").bind("click", function(e){ if ($.active) { return false; } openNewEmail(e); }); // Get / open reminder form $("#getReminder").bind("click", function(e){ if ($.active) { return false; } getReminder(e); }); // Download event icon $("#downloadEvent").bind("click", function(e){ if ($.active) { return false; } downloadEvent(e); }); // Edit event link $("#editlink").bind("click", function(e){ if ($.active) { return false; } editEvent(e); }); // ----------------------------- // Bind Email Form Events // ----------------------------- // Email cancel link $("#emailform, #sendemailactionrow").find("[cwui=emailbtnback]").bind("click", function(){ if ($.active) { return false; } cancelEmail(); }); // Email send link $("#sendemail").bind("click", function(e){ if ($.active) { return false; } sendEmail(e); }); // Email body char counter display $("#emailform").find("[cwui=intronote]").bind("keyup", displayCharsRemaining); // Email clear body link $("#emailform").find("[cwui=nointro]").bind("click", clearIntro); // ----------------------------- // Reminder Form Events // ----------------------------- // Reminder cancel $("#setreminderbtnback").bind("click", function(){ if ($.active) { return false; } gCurrentPlace = "eventdetails"; display_action_row(); jDetailBodyDIV.show(); jRemindBodyDIV.hide(); }); $("#setreminder").bind("click", function(e){ if ($.active) { return false; } setReminder(e); }); $("#deletereminder").bind("click", function(e){ if ($.active) { return false; } deleteReminder(e); }); // ----------------------------- // Edit Form Events // ----------------------------- // Bind Editor Events $("#chooseeditbtnback").bind("click", function(){ $("#chooseedit").hide() gCurrentPlace = "eventdetails"; display_action_row(); jDetailBodyDIV.show(); }); $("#eventform #category_id").change(checkCatFiltered); $("#rpt_type").change(docontrols); // If banners on bind change of date components to doDateSync to sync dates if (gbanners_on == 1) { $("#eday, #emonth, #eyear, #end_eday, #end_emonth, #end_eyear").change(doDateSync); } // OTHER EDIT EVENT BINDS ARE BELOW ALSO // ----------------------------- // Category Filter Form // ----------------------------- // Bind Category Filter open $("#filterbtn").bind("click", function(){ if ($.active) { return false; } openFilter(); }); // Bind Category Filter cancel $("#filterbtnback").bind( "click", function() { if ($.active) { return false; } cancelFilter(); }); $("#filterbtnapply").bind( "click", function() { if ($.active) { return false; } if (applyCategoryFilter()) { $("#checkonecatmsg").hide(); $("#category_filter_list").hide(); showCurrentView (currentView, true); } }); // **************************************************************** // End binding // **************************************************************** // Create global of event detail container jDetailBodyDIV = $("#event"); // Conditional setup of html editor if (usehtmled) { if (typeof tinyMCE == 'undefined') { // Send event to Google Anaytics for tracking that tinymce did not load // This may be that cdn failed or blocked by firewall //_gaq.push(['_trackEvent', 'editor_mobile_tinymce_notloaded', gCalendar]); } else { // // Description editor - NOTE: EITHER SETUP OR ONINIT CAN GO AWAY tinyMCE.init({ selector: "#description", theme: "modern", width: "99%", height: 175, relative_urls : false, remove_script_host : false, forced_root_block: false, browser_spellcheck : true, plugins: 'lists advlist', branding: false, menubar: "", toolbar: "bold italic | alignleft aligncenter alignright | bullist numlist", autofocus: false, setup: function(editor) { editor.on('blur', function(e) { display_action_row(); }); editor.on('focus', function(e) { $(".action_row").hide(); }); } }); } } $('#eventform').scroll(function() { // Remove focus to make sure auto fill closed $(document.activeElement).blur(); display_action_row(); }); // Click on title sets focus on title $('#title').bind('click', function(event) { if (event.target.id == 'title') { $("#edit").focus(); $("#title").focus(); } return true; }); // Related to above commented out code. Keeping here for possible future developments addeditdisable = 0; // ---------------------------- // HIDE / SHOW LOCATION DETAILS // ---------------------------- // So they don't have to keep opening more location details each time when if ($.cookie("cw_locationdetails") == "visible") { $("#locationdetails").show(); $("#location_details_show").hide(); $("#location_details_hide").css("display","inline-block"); } // Event handler for showing/hiding location details $("#location_details_control").on("click", function(event) { if ($("#locationdetails").is(':visible')) { $("#locationdetails").hide(); $("#location_details_hide").hide(); $("#location_details_show").css("display","inline-block"); $.cookie("cw_locationdetails", "hidden"); } else { $("#locationdetails").show(); $("#location_details_show").hide(); $("#location_details_hide").css("display","inline-block"); $.cookie("cw_locationdetails", "visible"); } event.stopPropagation(); }); // Event handler for location field focus $(".locationfield").on("focus", function(event) { btnclicked = 'none'; }); // Event handler for location field change $(".locationfield").on("change", function(event) { locchange(); }); // ---------------------------- // HIDE / SHOW END DATE // ---------------------------- // So they don't have to keep opening more details each time when // adding multiple users at a time. if ($.cookie("cw_end_date_div") == "visible") { $("#end_date_div").show(); $("#end_date_show").hide(); $("#end_date_hide").css("display","inline-block"); } // Event handler for showing/hiding end date $("#end_date_control").on("click", function(event) { if ($("#end_date_div").is(':visible')) { $("#end_date_div").hide(); $("#end_date_hide").hide(); $("#end_date_show").css("display","inline-block"); $.cookie("cw_end_date_div", "hidden"); } else { $("#end_date_div").show(); $("#end_date_show").hide(); $("#end_date_hide").css("display","inline-block"); $.cookie("cw_end_date_div", "visible"); } event.stopPropagation(); }); // ---------------------------- // HIDE / SHOW PRIVATE NOTE // ---------------------------- // So they don't have to keep opening more private note each time when if ($.cookie("cw_privatenote") == "visible") { $("#privatenote, .privatenoteslabel").show(); $("#privatenote_show").hide(); $("#privatenote_hide").css("display","inline-block"); } else { $("#privatenote, .privatenoteslabel").hide(); $("#privatenote_hide").hide(); $("#privatenote_show").css("display","inline-block"); } // Event handler for showing/hiding private note $("#privatenote_control").on("click", function(event) { if ($("#privatenote").is(':visible')) { $("#privatenote, .privatenoteslabel").hide(); $("#privatenote_hide").hide(); $("#privatenote_show").css("display","inline-block"); $.cookie("cw_privatenote", "hidden"); } else { $("#privatenote, .privatenoteslabel").show(); $("#privatenote_show").hide(); $("#privatenote_hide").css("display","inline-block"); $.cookie("cw_privatenote", "visible"); } event.stopPropagation(); }); // Refresh link if launched as homescreen app if (window.matchMedia('(display-mode: standalone)').matches) { $("#refreshbtn").show(); } if (window.navigator.standalone === true) { $("#refreshbtn").show(); } // **************************************************************** // Try logging in with cookies // **************************************************************** // Get possible user cookies var usernameold = readCookie("cwUsername"); // Legacy cookie var usernamenew = readCookie("cw_user"); // Transitional single calendar cookie var calendar_specific_cookie_name = "cw_auth_" + $("#calendar_id").val(); var usernamemulticalcookie = readCookie(calendar_specific_cookie_name); // New multi-calendar cookie if ((usernameold) || (usernamenew) || (usernamemulticalcookie)) { // Cookies present so try login. getViewCategories will init calendar loginCookies(getViewCategories); } else { // No cookies for login so just getViewCategories will init calendar getViewCategories(); } } // End of function init // Handle touch swipes for different pages. For calendar grid this // goes to next or previous month. For other pages it is same as // touching on cancel link function swipeHandler(direction){ if ($.active) { return false; } if ($("#dayevents").is(":visible")) { if (currentView == 'calendar') { // These handle swipes of calendar or list below calendar if (calendarSwipe) { calendarSwipe = false; cal.navMonth(direction); // Go to previous or next month } else if (dayListSwipe) { dayListSwipe = false; navDay(direction); // Go to previous or next day } } else if (currentView == 'list') { if (fullListSwipe) { fullListSwipe = false; doListScroll(direction); // Get events before or after } } } else if (($("#event").is(":visible")) && (direction == 'prev')) { $("#eventdone").click(); } else if (($("#emailform").is(":visible")) && (direction == 'prev')) { $("#emailbtnback").click(); } else if (($("#reminderform").is(":visible")) && (direction == 'prev')) { $("#setreminderbtnback").click(); } else if (($("#chooseedit").is(":visible")) && (direction == 'prev')) { $("#chooseeditbtnback").click(); } else if (($("#eventform").is(":visible")) && (direction == 'prev')) { $("#editeventbtnback").click(); } else if (($("#loginform").is(":visible")) && (direction == 'prev')) { $("#logincancel").click(); } else if (($("#category_filter_list").is(":visible")) && (direction == 'prev')) { $("#filterbtnback").click(); } } // Called when full events list is scrolled. If list is at top or bottom // then gets last (bottom) or first (top) date in the list and then calls // getListEvents which handles get and display of events before or after list function doListScroll(direction) { if ($.active) { return false; } scrollObj = $('#dayevents'); if (direction == 'before') { // Get lists before top of full list (i.e. past events) var getdatestr = $("#dayevents > div[data-date]").first().attr("data-date"); var getyear = getdatestr.substring(0, 4); var getmonth = getdatestr.substring(4, 6); var getday = getdatestr.substring(6, 8); getdate = new Date(parseInt(getyear), parseInt(getmonth)-1, parseInt(getday)); getListEvents(gCalendar, getdate, 'before'); } if (direction == 'after') { // Get lists after bottom of full list (i.e. future events) var getdatestr = $("#dayevents > div[data-date]").last().attr("data-date"); var getyear = getdatestr.substring(0, 4); var getmonth = getdatestr.substring(4, 6); var getday = getdatestr.substring(6, 8); getdate = new Date(parseInt(getyear), parseInt(getmonth)-1, parseInt(getday)); getListEvents(gCalendar, getdate, 'after'); } // Scroll page body to top to prevent page bounce in iphones $("body").scrollTop(0); } //########################## Filter Helpers ##################################### function getcatlist() { var catlist = ''; // Categories filter if (((typeof cidarray != "undefined") && (cidarray.length > 0)) && ($(".catpermits").length != $(".catpermits:checked").length)) { for (var i = 0; i < cidarray.length; i++) { catlist += '&cid[]=' + cidarray[i]; } } else if (gNumCatsCalendar != gNumCatsUser) { $(".catpermits").each(function(index) { catlist += '&cid[]=' + this.value; }); } return catlist; } function getloclist() { // Locations filter if ((typeof lidarray != "undefined") && (lidarray.length > 0)) { var loclist = ''; for (var i = 0; i < lidarray.length; i++) { loclist += '&lid[]=' + lidarray[i]; } } else { var loclist = ''; } return loclist; } //########################## Month Display ##################################### function initMonthlyDisplay(data, result){ if(data){ commonAjaxCallback(data, result); } // Create initial month grid display, includes call to get number of events on each day (i.e. view = n) cal = new cwCal($("#calendar")[0], disabledDates, selectedDate, clearCache, "pleasewait"); if(cal.date == undefined){ cal.date = new Date(); } // Open to calendar view, shows single day event list below month grid showCurrentView('calendar', true); } // Gets number of events in each doy of month used to build grid with dots function getMonthEvents(calendar, pDate){ var date = new Date(pDate); clearCache(); date.setDate(1); date.setDate(1 - date.getDay()); var month = (date.getMonth() + 1); var year = date.getFullYear(); var day = date.getDate(); date.setDate(date.getDate() + 42); var emonth = (date.getMonth() + 1); var eyear = date.getFullYear(); var eday = date.getDate(); // Categories filter var catlist = getcatlist(); // Locations filter var loclist = getloclist(); $.getJSON("/cwapi.php" + gPHPSESSID + catlist + loclist, {fmt:"json", view:"n", bd:day, bm:month, by:year, ed:eday, em:emonth, ey:eyear, crd:calendar}, monthCallback, "json"); } // Callback from getMonthEvents to save monthEvents object with event counts on each day function monthCallback(data, result){ if(!commonAjaxCallback(data, result)){ return; } // Will contain list of dates with number of events in each day monthEvents = new Object(); if (data.status.code == 200) { // Load the dates into the monthEvents object for(var i = 0; i < data.dateswithevents.length; i++){ var cw_event = data.dateswithevents[i] if(cw_event.month.length == 1){ cw_event.month = "0" + cw_event.month; } if(cw_event.day.length == 1){ cw_event.day = "0" + cw_event.day; } monthEvents[parseInt(cw_event.year + cw_event.month + cw_event.day)] = cw_event; } setElementHeights(); } else { // Something wrong handleResponseError(data); } // Render the month grid for given date cal.render(cal.date, true); // Display action row here to make sure add (+) shows if applicable // Was not showing if logged in, no cookie set, and did full refresh display_action_row(); } // Clears monthEvents object with number of events in each day function clearCache(){ monthEvents = undefined; } //############# Display Days Events Below Grid ##################### // Get summaries of events on specific day for display in list below // month grid. Callback displays events in list below calendar month grid. function getDayEvents(calendar, date){ gCameFromDetail = false; cal.date = date; gCameFromMonth = false; var month = (date.getMonth() + 1); var year = date.getFullYear(); var day = date.getDate(); // Categories filter var catlist = getcatlist(); // Locations filter var loclist = getloclist(); $.getJSON("/cwapi.php" + gPHPSESSID + catlist + loclist, {fmt:"json", view:"s", bd:day, bm:month, by:year, ed:day, em:month, ey:year, crd:calendar}, dayCallback, "json"); } // Display list of events for given day below month grid function dayCallback(data, result){ $(".dayeventsA, .dayeventsB, .daydatedisplay, .noeventsonday").remove(); //emptying out the event list (note dayeventsB not being used) $("#dayevents").height(listcalendarht); if(!commonAjaxCallback(data, result)){ return; } if(data.status.code == 200 || data.status.code == 204){ $(".date").text(cal.date.format("ddd, mmm d, yyyy")); // Get this selected date year, month, day var sel_month = (cal.date.getMonth() + 1); var sel_year = cal.date.getFullYear(); var sel_day = cal.date.getDate(); var sel_monthstr = ("0"+sel_month).slice(-2); var sel_daystr = ("0"+sel_day).slice(-2); if(data.status.code == 204){ // No events found so display message using template var jNoEventsDiv = $("#noeventstemplate").clone(true); // Remove id attribute from template jNoEventsDiv.removeAttr("id"); $("#dayevents").prepend(jNoEventsDiv); var noeventsmsg = 'No events on this day'; gNoEventsBefore = true; jNoEventsDiv.attr("class", "noeventsonday"); jNoEventsDiv.attr("data-date", sel_year+sel_monthstr+sel_daystr); jNoEventsDiv.find(".noeventsmsg").html('

'+noeventsmsg+'

') .css("text-align","center") .css("font-size","1.2em") .css("background-color", "#ffffff") .css("color","gray") .css("margin","100px 0"); jNoEventsDiv.show(); } else { // Loop thru events and create list for selected day for(var i = 0; i < data.eventsummaries.length; i++){ var cw_event = data.eventsummaries[i]; jEventDiv = getEventSummaryDiv(cw_event); // Add attribute of this occurrence date string in format accepted by js date function // This is so we can get the occurrence date when displaying details so we can reset cal.date jEventDiv.attr("data-date", sel_year+sel_monthstr+sel_daystr); $("#dayevents").append(jEventDiv); } // Add single spacer at bottom of list - needed for full scroll to bottom on iphone $("#dayevents").append("
"); } $("#dayevents").scrollTop(0); } else { // Something wrong handleResponseError(data); } } //###################### Full List Display ###################### // Get event summary data for display in full list (i.e. no month grid) // This is called for initial list display and also for lazy loading // triggered by scrolling to the top or bottom of the list function getListEvents(calendar, date, direction){ if (date == 'Invalid Date') { return false; } // Get lazy load direction. On inital load this is 'beforeandafter' // and can also be 'before' if scrolled to top or 'after' if scrolled // to bottom. The flags gNoEventsBefore and gNoEventsAfter are set // if lazy load cannot find events and flag prevents subsequent server // hits if nothing to find. gGetEventsDirection = direction; // Set api parameters for each type of lazy load. Values for // gBeforeLimit and gAfterLimit specify the maximum events to // get from database for each direction. if (direction == 'before') { // If not more events before the cancel if (gNoEventsBefore) { $("body").scrollTop(0); return; } // Get events before date var beforelimit = gBeforeLimit; var afterlimit = 0; var incbdate = false; // Do not include events on cd:day since already in list var incadate = false; // No affect since afterlimit zero, but needs a value } else if (direction == 'after') { // If not more events after then cancel if (gNoEventsAfter) { $("body").scrollTop(0); return; } // Get events after date var beforelimit = 0; var afterlimit = gAfterLimit; var incadate = false; // Do not include events on cd:day since already in list var incbdate = false; // No affect since before limit zero, but needs a value } else { // This is for direction = 'beforeandafter' // Reset no events flags gNoEventsBefore = false; gNoEventsAfter = false; // Get events before and after date (span) var beforelimit = gBeforeLimit; var afterlimit = gAfterLimit; var incadate = false; // Do not include events on cd:day so no duplicates var incbdate = true; // Include events on cd:day so get one copy only } gCameFromDetail = false; // Just in case not already false // Only set new calendar date if doing full event list before and after date // The gGetEventsDirection is only set to 'before' or 'after' for scrolling // the events list to get more events in list on scroll but the calendar date // for the month should not change. This prevents date getting screwed up. if (gGetEventsDirection == 'beforeandafter') { cal.date = date; // Empty out the event list so nothing left over from month view // (note dayeventsB not being used) $(".dayeventsA, .dayeventsB, .daydatedisplay, .noeventsonday").remove(); } gCameFromMonth = false; var month = (date.getMonth() + 1); var year = date.getFullYear(); var day = date.getDate(); // Categories filter var catlist = getcatlist(); // Locations filter var loclist = getloclist(); $.getJSON("/cwapi.php" + gPHPSESSID + catlist + loclist, {fmt:"json", view:"s",cd:day, cm:month, cy:year, bl:beforelimit, bi:incbdate, al:afterlimit, ai:incadate, crd:calendar}, listCallback, "json"); } // Display events summaries in full list (i.e. no month grid) function listCallback(data, result){ if(!commonAjaxCallback(data, result)){ return; } $("#dayevents").height(listcurrentfullht); // Make sure list div correct height if(data.status.code == 200 || data.status.code == 204){ // Either has events (200) or not (204) // Prepare for list generation and display // For full rewrite of list (i.e. 'beforeandafter') we totally clear list // and will later scroll to a given date. For 'before' and 'after' lazy // loads we remember last object to which we will scroll after list generated if (gGetEventsDirection == 'beforeandafter') { var scrollElement = ''; } else if (gGetEventsDirection == 'before') { var scrollElement = $("#dayevents div").first(); // First div ok } else { var scrollElement = $("#dayevents .dayeventsA").last(); // Must use class .dayeventsA so get full event div not inside divs } // Show list container, not updated yet $("#dayevents").show(); // Selected date vars used below var selmonth = ('0' + (cal.date.getMonth()+1)).slice(-2); var selyear = cal.date.getFullYear(); var selday = ('0' + cal.date.getDate()).slice(-2); var seldatestr = ""+selyear+selmonth+selday; if (data.status.code == 204) { // No events found // Get the no events message div var jNoEventsDiv = $("#noeventstemplate").clone(true); // Remove id attribute jNoEventsDiv.removeAttr("id").attr("class", "dayeventsA").css("border-width","0px"); // Set data-date atrribute for scrolling jNoEventsDiv.attr("data-date", seldatestr); // Some styling jNoEventsDiv.find(".noeventsmsg") .css("text-align","center") .css("font-size","1.2em") .css("background-color", "#ffffff") .css("color","gray") .css("margin","100px 0"); var noefmsg = ''; // Init message if ((gGetEventsDirection == 'before') && (!gNoEventsBefore)) { // If lazy load was for past events (i.e. 'before') and // 'before' no events found flag not already set $("#dayevents").prepend(jNoEventsDiv); noefmsg = '

No past events found
'; if ((typeof cidarray != "undefined") && (cidarray.length > 0)) { // Only if category filter set noefmsg += 'in filtered '; noefmsg += ''; noefmsg += ' categories
'; } jNoEventsDiv.find(".noeventsmsg").html(noefmsg); gNoEventsBefore = true; // Set flag so will not duplicate later } else if (!gNoEventsAfter) { // If lazy load was for future events (i.e. 'after') and // 'after' no events found flag not already set $("#dayevents").append(jNoEventsDiv); if (gGetEventsDirection == 'after') { noefmsg = '
No future events found
'; } else { noefmsg = '
No events found
'; } if ((typeof cidarray != "undefined") && (cidarray.length > 0)) { // Only if category filter set noefmsg += 'in filtered '; noefmsg += ''; noefmsg += ' categories
'; } noefmsg += '

'; jNoEventsDiv.find(".noeventsmsg").html(noefmsg); gNoEventsAfter = true; // Set flag so will not duplicate later } jNoEventsDiv.show(); // Show the no events found message div // Scroll list to this div var scrollTopval = $(jNoEventsDiv).parent().scrollTop() + $(jNoEventsDiv).offset().top - $(jNoEventsDiv).parent().offset().top; $('#dayevents').animate({ scrollTop: scrollTopval }, { duration: 0, specialEasing: { width: 'linear', height: 'easeOutBounce' }, complete: function (e) { } }); } else { // Found events so create list of event summary divs var numberOfEvents = data.eventsummaries.length; // Total number of events found to be added to list // Used to detect change in date for events list display prior_occ_event_day = ''; prior_occ_event_month = ''; prior_occ_event_year = ''; for(var i = 0; i < data.eventsummaries.length; i++) { // loop thru each event var cw_event = data.eventsummaries[i]; // cw_event now holds this on event's data // Format event occurrence month and day as always two digits cw_event.occ_event_month = ("0"+cw_event.occ_event_month).slice(-2); cw_event.occ_event_day = ("0"+cw_event.occ_event_day).slice(-2); // Create date strings so are in alpha sortable format var occdatestralpha = ""+cw_event.occ_event_year+cw_event.occ_event_month+cw_event.occ_event_day; var priordatestralpha = ""+prior_occ_event_year+prior_occ_event_month+prior_occ_event_day; // Save date sring of first event if (i == 0) { var firstoccdatestralpha = occdatestralpha; } // If selected date is today then check if between prior and this events date. // This means that today has no events and need to set gselectedDateClass = 'disabled' // so we get a date div and no events on this day div for empty today date if ((todaydatestr > priordatestralpha) && (todaydatestr < occdatestralpha)) { gselectedDateClass = 'disabled'; } if (gGetEventsDirection == 'before') { // This was lazy load for past events only (not 'after' and not 'beforeandafter') // Check for change in event occurrence day from prior event if ((cw_event.occ_event_day != prior_occ_event_day) || (cw_event.occ_event_month != prior_occ_event_month) || (cw_event.occ_event_year != prior_occ_event_year)) { // Date changed so if this is not first event then prepend prevously created date div // This is because we need to put old date before events for that date. Remember we are // going back into past (prepending list) if (i > 0) { $("#dayevents").prepend(jDateDiv); // This is previously created data div because this is prepend (i.e. gGetEventsDirection == 'before') jDateDiv.length = 0; } // Create date div for this date change, will prepend in at later date change jDateDiv = getDateDiv(cw_event.occ_event_year, cw_event.occ_event_month, cw_event.occ_event_day); // Save month, day and year as prior for checking date transition prior_occ_event_month = cw_event.occ_event_month; prior_occ_event_day = cw_event.occ_event_day; prior_occ_event_year = cw_event.occ_event_year; } // If getting events before need to prepend events jEventDiv = getEventSummaryDiv(cw_event); // Add attribute of this occurrence date string in format accepted by js date function // This is so we can get the occurrence date when displaying details so we can reset cal.date jEventDiv.attr("data-date",cw_event.occ_event_year+cw_event.occ_event_month+cw_event.occ_event_day); $("#dayevents").prepend(jEventDiv); } else { // This is for initial load 'beforeandafter' or scroll to get 'after' for future events // Check for change in event occurrence day from prior event if ((cw_event.occ_event_day != prior_occ_event_day) || (cw_event.occ_event_month != prior_occ_event_month) || (cw_event.occ_event_year != prior_occ_event_year)) { // Check if need to insert target date div with no events message // This should only be for 'beforeandafter' full list load because // it comes with a specific date (i.e. from month view grid) if (gselectedDateClass.indexOf('disabled') !== -1) { // Create date strings so are in alpha sortable format var occdatestralpha = ""+cw_event.occ_event_year+cw_event.occ_event_month+cw_event.occ_event_day; var priordatestralpha = ""+prior_occ_event_year+prior_occ_event_month+prior_occ_event_day; // Does this event have different date from prior and current event (i.e. selected date // is between two events. If so then there is no event on this selected date so create msg div to indicate if ((gGetEventsDirection == 'beforeandafter') && (((seldatestr > priordatestralpha) && (seldatestr < occdatestralpha)) || ((seldatestr < occdatestralpha) && (i == 0)))) { // Create and append no events on this day div jDateDiv = getDateDiv(selyear, selmonth, selday); $("#dayevents").append(jDateDiv); jDateDiv.length = 0; var noeventonthisdayhtml = '
'; noeventonthisdayhtml += '
'; noeventonthisdayhtml += 'No events on this day
'; $("#dayevents").append(noeventonthisdayhtml); } // Save month, day and year as prior for checking date transition prior_occ_event_month = cw_event.occ_event_month; prior_occ_event_day = cw_event.occ_event_day; prior_occ_event_year = cw_event.occ_event_year; } // Here we append the date change spacer jDateDiv = getDateDiv(cw_event.occ_event_year, cw_event.occ_event_month, cw_event.occ_event_day); $("#dayevents").append(jDateDiv); jDateDiv.length = 0; } jEventDiv = getEventSummaryDiv(cw_event); // Add attribute of this occurrence date string in format accepted by js date function // This is so we can get the occurrence date when displaying details so we can reset cal.date jEventDiv.attr("data-date",cw_event.occ_event_year+cw_event.occ_event_month+cw_event.occ_event_day); $("#dayevents").append(jEventDiv); } } // End of loop thru all found events if (jDateDiv.length > 0) { if ((gGetEventsDirection == 'before')) { $("#dayevents").prepend(jDateDiv); // This is previously created data div because this is prepend (i.e. gGetEventsDirection == 'before') jDateDiv.length = 0; } else { $("#dayevents").append(jDateDiv); jDateDiv.length = 0; } } // If was not date change in list then all events on only one day // so need to prepend date spacer above // Get date sring of first event var lastoccdatestralpha = occdatestralpha; // If selected date was not shown because events did not span selected date // then need to show selected date with no events message if ((gGetEventsDirection == 'beforeandafter') && ((seldatestr < firstoccdatestralpha) || (seldatestr > lastoccdatestralpha))) { // Create and append no events on this day div jDateDiv = getDateDiv(selyear, selmonth, selday); var noeventonthisdayhtml = '
'; noeventonthisdayhtml += '
'; noeventonthisdayhtml += 'No events on this day
'; if (seldatestr > lastoccdatestralpha) { $("#dayevents").append(jDateDiv); jDateDiv.length = 0; $("#dayevents").append(noeventonthisdayhtml); } } if (g_cw_id > 0) { var scrollElement = $("#dayevents div[cw_id='"+g_cw_id+"']"); // Get div for event just viewed or edited for scroll to if (scrollElement.length > 0) { // If found the event // Get the scroll top value for this events div var scrollTopval = $(scrollElement).parent().scrollTop() + $(scrollElement).offset().top - $(scrollElement).parent().offset().top; scrollTopval = scrollTopval + 30; // Adding height of date div so shows date dive abobe event if just above event $('#dayevents').animate({ scrollTop: scrollTopval }, { duration: 0, specialEasing: { width: 'linear', height: 'easeOutBounce' }, complete: function (e) { g_cw_id = 0; // Clear the event id } }); } else { // Could not find event to scroll to } } else if (gGetEventsDirection == 'beforeandafter') { // This is camplete rewrite of list so scroll to current display date scrollToSelectedDate(); } else if ((gGetEventsDirection == 'before') || (gGetEventsDirection == 'after')) { // This was either lazy load for events before (past) or after (future) // Use scroll element from beginning of this function var scrollTopval = $(scrollElement).parent().scrollTop() + $(scrollElement).offset().top - $(scrollElement).parent().offset().top; $('#dayevents').animate({ scrollTop: scrollTopval }, { duration: 0, specialEasing: { width: 'linear', height: 'easeOutBounce' }, complete: function (e) { } }); } } } else { // Something wrong handleResponseError(data); } } // Create event summary div for display in lists either under calendar or full list views // Called by listCallback for each event being displayed in list function getEventSummaryDiv(cw_event) { jEventDiv = $("#eventstemplate").clone(true); // Get template for event summary div // Remove id from this event div jEventDiv.removeAttr("id"); jEventDiv.attr("cw_id", cw_event.event_id); // Add id of this event to attribute cw_id var dayClassName = "dayeventsA"; // For styles, dayeventsA used, dayeventsB not used jEventDiv.attr("class", dayClassName); jEventDiv.attr("repeat_id", cw_event.repeat_id); // Add repeat id as attribute jEventDiv.show(); // Event title var titletxt = cw_event.title; if (cw_event.draft) { titletxt = titletxt + '
draft
'; } jEventDiv.find(".title").html(titletxt); // Category color as vertical line if (cw_event.category_color == "" || cw_event.category_color == "#fff" || cw_event.category_color == "#FFFFFF") { var color = "#888"; var border = "1px solid #aaa"; } else { var color = "#fff"; var border = "none"; } jEventDiv.find(".category").css("background", cw_event.category_color); // Event location if(cw_event.location_name){ jEventDiv.find(".location").html("" + " " + cw_event.location_name); } else{ jEventDiv.find(".location").text(""); } // Event date(s) if (cw_event.isbanner == 1) { // For banner events only cal.banner_beg_date = new Date(parseInt(cw_event["event_year"]), parseInt(cw_event["event_month"])-1, parseInt(cw_event["event_day"])); // end date obj cal.banner_end_date = new Date(parseInt(cw_event["end_event_year"]), parseInt(cw_event["end_event_month"])-1, parseInt(cw_event["end_event_day"])); // end date obj if (cal.date.getFullYear() == cal.banner_beg_date.getFullYear()) { var bandatetimestr = cal.banner_beg_date.format("ddd, mmm d"); } else { var bandatetimestr = cal.banner_beg_date.format("ddd, mmm d, yyyy"); } if (gIsMilitary == '1') { var timeformatstr = "UTC:HH:MM"; } else { var timeformatstr = "UTC:h:MMtt"; } if (!cw_event["allday"]) { bandatetimestr += " " + dateFormat(tsToDate(cw_event, "start_timestamp_gmt", "start_tzoffset"), timeformatstr); } if (cal.date.getFullYear() == cal.banner_end_date.getFullYear()) { bandatetimestr += ' - ' + cal.banner_end_date.format("ddd, mmm d"); } else { bandatetimestr += ' - ' + cal.banner_end_date.format("ddd, mmm d, yyyy"); } if ((!cw_event["noend"]) && (!cw_event["allday"])) { bandatetimestr += " " + dateFormat(tsToDate(cw_event, "end_timestamp_gmt", "end_tzoffset"), timeformatstr); } jEventDiv.find(".startendtime").html("
Multi
Day
"); jEventDiv.find(".bannerdate").text(bandatetimestr); } else { // Non banner event (single or repeating occurrences) jEventDiv.find(".startendtime").html(getStartEndTime(cw_event, false)); } return jEventDiv; } // Creates date display div for list views with dow, month, day and if not current year then also year function getDateDiv(divyear, divmonth, divday) { // Create day spacer with date jDateDiv = $("#daydatetemplate").clone(true); // Remove id attribute jDateDiv.removeAttr("id"); displaydate = new Date(parseInt(divyear), parseInt(divmonth)-1, parseInt(divday)); if (divyear == todayyear) { // Do not display year if current year displaydatestr = displaydate.format("ddd, mmm d"); } else { // Display year if not current year displaydatestr = displaydate.format("ddd, mmm d, yyyy"); } jDateDiv.find(".daydate").html(displaydatestr); datadatestr = displaydate.format("yyyymmdd"); jDateDiv.attr("data-date", datadatestr); jDateDiv.attr("class", "daydatedisplay"); // Highlight if today if (datadatestr == todaydatestr) { jDateDiv.find("td").css("color","#d24e4e"); } jDateDiv.show(); // Save this dates info for use in date change detection in other scripts prior_occ_event_day = divday; // Reset prior day prior_occ_event_month = divmonth; // Reset prior day prior_occ_event_year = divyear; // Reset prior day return jDateDiv; } function scrollToSelectedDate (scrolldate) { // Scroll to currently selected date or next nearest date // starting with current display date and incrementing by one day var foundscrolldate = false; // Try going forward in time for(var i = 0; i < 365; i++) { scrolldate = new Date(cal.date); scrolldate.setDate(cal.date.getDate() + (i*1)); datadatestr = scrolldate.format("yyyymmdd"); scrollElement = $("div[data-date='"+datadatestr+"']" ); if (scrollElement.length != 0) { foundscrolldate = true; break; } } // Try going backwards in time if (!foundscrolldate) { for(var i = 0; i < 365; i++) { scrolldate = new Date(cal.date); scrolldate.setDate(cal.date.getDate() - (i*1)); datadatestr = scrolldate.format("yyyymmdd"); scrollElement = $("div[data-date='"+datadatestr+"']" ); if (scrollElement.length != 0) { foundscrolldate = true; break; } } } if (foundscrolldate) { // Found date div so get value to set scroll top var scrollTopval = $(scrollElement).parent().scrollTop() + $(scrollElement).offset().top - $(scrollElement).parent().offset().top } else { var scrollTopval = 1; // Did not find so scroll to top of event list } // Do the scroll $('#dayevents').animate({ scrollTop: scrollTopval }, { duration: 0, specialEasing: { width: 'linear', height: 'easeOutBounce' }, complete: function (e) { } }); } //######################### Event Display ############################### // Display event detail view, e should contain object from touch on event in summary list // or can contain the actual id of event to be displayed function displayEvent(e){ gCameFromDetail = true; if(typeof(e) == "object"){ // Came from touch on event div in list if ($.active) { return false; } // Do not respond to touch if ajax activly refreshing list // Event summary div was clicked to view details so get // event id and display event details // Check to make sure that an event was clicked on var cw_id = $(e.target).closest("[cw_id]").attr("cw_id"); if(cw_id){ g_cw_id = cw_id; } else { return; } // Get the repeat id (will be zero if not repeating) g_rpt_master_id = $(e.target).closest("[repeat_id]").attr("repeat_id"); // Set current date to that of selected event occurrence // This is so return from event goes to date of event // Important for list view so event still in view on return var occ_datestr = $(e.target).closest("[cw_id]").attr("data-date") cal.date = new Date(occ_datestr.substring(0, 4)+'/'+occ_datestr.substring(4, 6)+'/'+occ_datestr.substring(6, 8)); $("#dayevents").hide(); $("#calendar").hide(); gCurrentPlace = "eventdetails"; display_action_row(); } else { // Came from call with event id as parameter if ((typeof e == 'number') && (e > 0)) { // Return from editor for adding event g_cw_id = e; g_rpt_master_id = 0; } else { // Return from editor of existing event if edit was single event or single occurrence of repeat and not delete g_cw_id = $("#edit #event_id").val(); g_rpt_master_id = $("#edit #repeat_id").val(); } } // Go get event information for display getEvent(gCalendar, g_cw_id, g_rpt_master_id, eventCallback, ""); } //######################## Common Event Display and Edit Code ################################### // Makes call to server to retrieve individual event details function getEvent(calendar, id, repeat_id, callback, edittype){ if(callback == editEventCallback){ var op = "u"; //under new cwapi this has the same meaning of update } else{ op = "d"; //for a single event detail is now "d" } $.getJSON("/cwapi.php" + gPHPSESSID, {fmt:"json", view:op, "eid[]":id, edittype:edittype, "repeat_id":repeat_id, crd:calendar}, callback, "json"); } // Populate and display event detail function eventCallback(data, result){ commonAjaxCallback(data, result); if (data.status.code == 200) { // Found event var jEventDiv = $("#event"); // Get all event details into cw_event object var cw_event = data.eventdetails[0]; // Do not show email or download buttons if show busy set and not logged in if ((gCalShowBusy == 1) && (!cw_event.canedit)) { $("#openNewEmail").css({"display":"none"}); $("#downloadEvent").css({"display":"none"}); } else { $("#openNewEmail").css({"display":"inline"}); $("#downloadEvent").css({"display":"inline"}); } // Do not show remind button if show busy set and not logged in and event not is past if (((gCalShowBusy == 1) && (!cw_event.canedit)) || (data.eventdetails[0].inpast)) { $("#getReminder").css({"display":"none"}); } else { $("#getReminder").css({"display":"inline"}); } // Do not show edit link if not logged in or cannot edit if (!cw_event.canedit) { $("#editlink").css({"display":"none"}); } else { $("#editlink").css({"display":"inline"}); } // -------------------------- // Begin event detail display // -------------------------- // Event date(s) if (cw_event.isbanner) { // Banner events only cal.banner_beg_date = new Date(parseInt(cw_event.event_year), parseInt(cw_event.event_month)-1, parseInt(cw_event.event_day)); // end date obj cal.banner_end_date = new Date(parseInt(cw_event.end_event_year), parseInt(cw_event.end_event_month)-1, parseInt(cw_event.end_event_day)); // end date obj var bandatetimestr = cal.banner_beg_date.format("ddd, mmm d, yyyy"); if (data.settings.military == '1') { var timeformatstr = "UTC:HH:MM"; } else { var timeformatstr = "UTC:h:MMtt"; } if (!cw_event.allday) { bandatetimestr += " " + dateFormat(tsToDate(cw_event, "start_timestamp_gmt", "start_tzoffset"), timeformatstr); } bandatetimestr += ' - ' + cal.banner_end_date.format("ddd, mmm d, yyyy"); if ((!cw_event.noend) && (!cw_event.allday)) { bandatetimestr += "  " + dateFormat(tsToDate(cw_event, "end_timestamp_gmt", "end_tzoffset"), timeformatstr); } } else { // Non banner events (single or repeating occurrence) cal.event_beg_date = new Date(parseInt(cw_event["event_year"]), parseInt(cw_event["event_month"])-1, parseInt(cw_event["event_day"])); // end date obj } // Put this events id and repeat id into detail event display navbar for other actions usage $("#eventdetailactionrow").attr("cw_id", cw_event.event_id); $("#eventdetailactionrow").attr("repeat_id", cw_event.repeat_id); // ----------------------------------- // Put event values into place holders // ----------------------------------- // Clear all values from past event display $("#event .detailvalue").html(''); // Hide all labels for now, show later if has values $("#event .label").hide(); // Event title var titletxt = cw_event.title; if (cw_event.draft) { titletxt = titletxt + '
draft
'; } $("#value_title").html(titletxt); // Date and Time if (cw_event.isbanner) { $("#value_date").html(bandatetimestr); } else { $("#value_date").html(dateFormat(cal.event_beg_date, "ddd, mmm d, yyyy")+''+getStartEndTime(cw_event, true))+''; } // Location name var locationstr = cw_event.location_name; // Location map link var mapqscore = 0; // Will only show map link if map quality score is greater than or equal to 3 var mapurl = ''; if (cw_event.location_street) { mapurl += cw_event.location_street; mapqscore++;} if (cw_event.location_city) { mapurl += '+'+cw_event.location_city; mapqscore++;} if (cw_event.location_stateprovince) { mapurl += '+'+cw_event.location_stateprovince; mapqscore++;} if (cw_event.location_zippostal) { mapurl += '+'+cw_event.location_zippostal;} if (cw_event.location_country) { mapurl += '+'+cw_event.location_country; } if ((mapurl) && (mapqscore >= 3)) { // Encode map url components mapurl = encodeURIComponent(mapurl); var deviceOS = getMobileOperatingSystem(); if (deviceOS == 'iOS') { mapurl = 'http://maps.apple.com/maps?address='+mapurl; } else { mapurl = 'https://maps.google.com/?q='+mapurl; } var mapstr = ""; } // Location weather link var weatherqscore = 0; // Will only show weather link if weather quality score is greater than or equal to 3 var weatherurl = ''; // if (cw_event.location_city) { weatherurl += cw_event.location_city; weatherqscore++;} // if ((cw_event.location_stateprovince) && (cw_event.location_stateprovince.length == 2)) { // weatherurl += '+'+cw_event.location_stateprovince; // weatherqscore++; // } // if (cw_event.location_zippostal) { weatherurl += '+'+cw_event.location_zippostal; weatherqscore++;} // if (cw_event.location_country) { weatherurl += '+'+cw_event.location_country; } var weather_country = cw_event.location_country.toLowerCase(); var country_haystack = "us usa united states of america"; if (country_haystack.includes(weather_country)) { weather_country = 'us'; } //console.log(weather_country); if (weather_country) { weatherurl += '/'+ weather_country; weatherqscore++;} if ((cw_event.location_stateprovince) && (cw_event.location_stateprovince.length == 2)) { weatherurl += '/'+cw_event.location_stateprovince.toLowerCase(); weatherqscore++; } var weather_city = cw_event.location_city.replace(/\s+/g,' ').trim(); weather_city = weather_city.replace(" ", "-"); if (weather_city) { weatherurl += '/'+ weather_city.toLowerCase(); weatherqscore++;} if ((weatherurl) && (weatherqscore >= 3) ) { // Encode map url components //weatherurl = encodeURIComponent(weatherurl); //weatherurl = 'http://www.wunderground.com/cgi-bin/findweather/getForecast?bannertypeclick=htmlSticker&query='+weatherurl; weatherurl = 'https://www.wunderground.com/weather'+weatherurl; //console.log(weatherurl); var weatherstr = ""; } if (locationstr) { $("#label_location").show(); $("#value_location_name").html(locationstr); } // Clear any previous button HTML // then add the map link $("#value_map").html(""); if (typeof mapstr != "undefined") { $("#value_map").html(mapstr); } // Clear any previous button HTML // then add the weather link $("#value_weather").html(""); if (typeof weatherstr != "undefined") { $("#value_weather").html(weatherstr); } // Location address if (mapurl) { // If anything in map url then must be something in address fields if (cw_event.location_street) { $("#value_location_street").text(cw_event.location_street); } if ((cw_event.location_city) && (cw_event.location_stateprovince)) { $("#value_location_city").text(cw_event.location_city+','); } else if (cw_event.location_city) { $("#value_location_city").text(cw_event.location_city); } if (cw_event.location_stateprovince) { $("#value_location_stateprovince").text(cw_event.location_stateprovince); } if (cw_event.location_zippostal) { $("#value_location_zippostal").text(cw_event.location_zippostal); } if (cw_event.location_country) { $("#value_location_country").text(cw_event.location_country); } $("#container_citystatezip").show(); } else { $("#container_citystatezip").hide(); } // Category if (cw_event.category_color == "" || cw_event.category_color == "#fff" || cw_event.category_color == "#FFFFFF") { border_if_white = "border:1px solid #d3d3d3;"; } else { border_if_white = "border:none;"; } // Legend colored dot var legendhtml = ''; $("#label_category_name").show(); $("#value_category_name").html(legendhtml+cw_event.category_name); // Description // Check if description only html editor comment if (cw_event.description == ""){ cw_event.description = ''; // really no description text } if (cw_event.description) { if (cw_event.description.search("") != -1) { $("#value_description").html(cw_event.description.replace(/\n/g, "
")); // Not html so convert line ends to brs } else { $("#value_description").html(cw_event.description); } $("#label_description").show(); } // Event Contact if ((cw_event.contact) || (cw_event.email) || (cw_event.phone)) { if (cw_event.contact) { $("#value_contact").text(cw_event.contact); } if (cw_event.email) { if (checkemailaddress(cw_event.email)) { $("#value_email").html('' + cw_event.email + ''); } else { $("#value_email").text(cw_event.email); } } if (cw_event.phone) { $("#value_phone").html('' + cw_event.phone + ''); } $("#label_contact").show(); } // More info link var url = cw_event.url; var display_url = url; if(url){ if(!url.match(/^https?/)){ url = "http://" + url; } $("#value_url").html('' + cw_event.url + ''); $("#label_url").show(); } // Location Details if ((cw_event.location_contact) || (cw_event.location_phone) || (cw_event.location_directions) || (cw_event.location_guidelines)) { if (cw_event.location_contact) { $("#value_location_contact").html(cw_event.location_contact); $("#label_location_contact").show(); } if (cw_event.location_phone) { $("#value_location_phone").html('' + cw_event.location_phone + ''); } if (cw_event.location_directions) { $("#value_location_directions").html(nl2br(cw_event.location_directions, false)); $("#label_location_directions").show(); } if (cw_event.location_guidelines) { $("#value_location_guidelines").html(nl2br(cw_event.location_guidelines, false)); $("#label_location_guidelines").show(); } } // Private Note if (cw_event.privatenote) { $("#value_privatenote").html(nl2br(cw_event.privatenote, false)); $("#label_privatenote").show(); } $("#eventdetailactionrow").attr("cw_id"); $("#eventdetailactionrow").attr("repeat_id"); jEventDiv.show(); gCurrentPlace = "eventdetails"; display_action_row(); // Adjust height of event detail view div and set scroll to top $("#event").height(listcurrentfullht - 30).scrollTop(0); // // Hightlight reminder icon (bell) if reminder set for this event checkReminder() } else if (data.status.code == 204) { // Event not found. Might be caused by change of single event to repeating event // because the event is completely replaced and old event id not longer valid // Could also be caused by another user deleting the event in another session $.alert('Event not found. May have been changed by other user. Refreshing view now.','') // Skip event detail display and return to current view gCurrentPlace = "events_cal_or_list"; showCurrentView(currentView, true); } else { // Something wrong handleResponseError(data); } } // Handle back button from event detail view function eventDone(){ $("#event").hide(); $("#edit").hide(); gCurrentPlace = "events_cal_or_list"; display_action_row(); if (gRefreshAfterEdit) { // Refresh lists after event edit showCurrentView(currentView, true); gRefreshAfterEdit = false; // Reset to not refresh } else { showCurrentView(currentView, false); } } // Cancel event add / edit function eventEditDone(){ $("#edit").hide(); if (gCurrentPlace == "eventadd") { showCurrentView(currentView, false); } else { gCurrentPlace = "eventdetails"; $("#event").show(); display_action_row(); } } //######################### Add New Event ############################### function checkCalendarStatus() { // Check calendar type status var alertstr = ''; if (calendar_type == "Expired") { alertstr = "Sorry, your calendar trial has expired. \n\nAs a courtesy, your calendar is available for viewing. \nYou may restore the ability to add and edit events by purchasing a subscription."; } else if (calendar_type == "Billing-C") { alertstr = "Sorry, our records show a problem billing for your account. \n\nAs a courtesy, your calendar is available for viewing. \nYou may restore the ability to add and edit events by updating your billing information."; } else if (calendar_type == "Renewal-C") { alertstr = "Sorry, our records show your subscription renewal is past due. \n\nAs a courtesy, your calendar is available for viewing. \nYou may restore the ability to add and edit events by renewing your subscription"; } if (alertstr != '') { alertstr += "\n\nFor details, login to your calendar using a desktop or tablet and go to Account Details. \n\nOr, contact support@calendarwiz.com" $.alert(alertstr, "Calendar Status"); return false; } else { return true; } } function addEvent(e, skipCategories){ if (!checkCalendarStatus()) { return false; } endDateIsDirty = false; // For date picker control if(skipCategories == undefined){ // Need to populate the category drop down editEventEvent = undefined; getEditLocations(gCalendar, populateLocationDropDown); getEditCategories(gCalendar, populateCategoryDropDown); // Note: getEditCategories will do ajax call to populate category dropdown in editor // and then call addEvent again but with skipCategories defined so next time will skip return; } // Need to check here to see if we're logged in with // permission to add an event if(gLoggedIn){ if (gCanAdd) { $(cal.grid).hide(); $("#navTodayAddLogInOut").hide(); $("#dayevents").hide(); getNewEvent(gCalendar, cal.date); } else { $.alert('Sorry, this login not allowed to add events',''); } } else { if($("#loginform").is(":visible")) return; if($.confirm("Login required to add an event.\nDo you want to login?","")){ gDestinationScreen = "#edit"; $(cal.grid).hide(); $("#navTodayAddLogInOut").hide(); $("#dayevents").hide(); logincancelviz(); $("#loginform").show(); gCurrentPlace = "loginscreen"; display_action_row(); $("#navTodayAddLogInOut").hide(); $("#username")[0].focus(); } } } // Get default event values function getNewEvent(calendar, date){ var month = (date.getMonth() + 1); var year = date.getFullYear(); var day = date.getDate(); // Get default event values "view = a" $.getJSON("/cwapi.php" + gPHPSESSID, {fmt:"json", view:"a", aday:day, amonth:month, ayear:year, crd:calendar}, editEventCallback, "json"); } //############################ Display Event for Adding or Editing ############################### var editEventEvent; function editEvent(e, skipCategories){ if (!checkCalendarStatus()) { return false; } if(skipCategories == undefined){ // Populate the category drop down editEventEvent = e; getEditLocations(gCalendar, populateLocationDropDown); getEditCategories(gCalendar, populateCategoryDropDown); return false; } $("#chooseedit").hide(); $("#chooseeditactionrow").hide(); $("#dayevents").hide(); $("#event").hide(); var edittype = ""; if (typeof(e) == "string") { edittype = e; // Send in the repeat_id in here getEvent(gCalendar, g_cw_id, g_rpt_master_id, editEventCallback, edittype); return false; } else { g_cw_id = $("#eventdetailactionrow").attr("cw_id"); g_rpt_master_id = $("#eventdetailactionrow").attr("repeat_id"); } if (g_rpt_master_id > 0) { // Pop up a dialog to ask the user whether they want to do an // edit on a single event or all occurences of a repeating event $(".action_row").hide(); gCurrentPlace = "chooseedit"; display_action_row(); $("#chooseedit").show(); return false; } else { getEvent(gCalendar, g_cw_id, g_rpt_master_id, editEventCallback, edittype); return false; } } function editEventCallback(data, result){ commonAjaxCallback(data, result); if(data.status.code == 200){ var jEventDiv = $("#edit"); $("#eventform").height(listcurrentfullht - 30).scrollTop(0); jEventDiv.show(); if(data.status.view == "a"){ var cw_event = data.eventdefaults; } else if(data.status.view == "u"){ var cw_event = data.eventupdatedetails[0]; } else{ cw_event = data.eventdetails[0]; } // Display action text var actionheadertxt = ''; gCurrentPlace = "eventedit"; // may change to eventadd in next conditional if (data.status.view == "a") { actionheadertxt = 'New Event'; gCurrentPlace = "eventadd"; gCameFromDetail = false; // just in case } else if (data.status.view == "u") { if (cw_event.edittype == "single") { actionheadertxt = 'Edit Single Repeat'; } else if (cw_event.edittype == "repeats") { actionheadertxt = 'Edit All Repeats'; } else { actionheadertxt = 'Edit Single Event'; } } $("#addeditheader").text(actionheadertxt); if(cal.date == undefined){ cal.date = new Date(); } $(".date").text(cal.date.format("dddd, mmmm d, yyyy")); // Extract the day, month, year from the seconds // need to heed if this is military time var mil = data.settings.military == '1'; var startDate = tsToDate(cw_event, "start_timestamp_gmt", "start_tzoffset"); cw_event.emonth = dateFormat(startDate, "UTC:m"); cw_event.eyear = dateFormat(startDate, "UTC:yyyy"); cw_event.eday = dateFormat(startDate, "UTC:d"); var endDate = tsToDate(cw_event, "end_timestamp_gmt", "end_tzoffset"); var rptendDate = tsToDate(cw_event, "rpt_end_timestamp_gmt", "rpt_end_tzoffset"); // Begin for banner events // End for banner events if(mil){ $("#startampm").hide(); $("#endampm").hide(); $("#startampmlabel").hide(); $("#endampmlabel").hide(); cw_event.starthour = dateFormat(startDate, "UTC:H"); cw_event.endhour = dateFormat(endDate, "UTC:H"); } else{ $("#startampm").show(); $("#endampm").show(); $("#startampmlabel").show(); $("#endampmlabel").show(); cw_event.starthour = dateFormat(startDate, "UTC:h"); cw_event.endhour = dateFormat(endDate, "UTC:h"); } setHoursDropDown($("#starthour")[0], mil); setHoursDropDown($("#endhour")[0], mil); cw_event.startminute = dateFormat(startDate, "UTC:MM"); if(cw_event.startminute.match(/^[1-5][0,5]$/)){ cw_event.startminute = "+" + cw_event.startminute; } cw_event.startampm = dateFormat(startDate, "UTC:tt"); cw_event.endminute = dateFormat(endDate, "UTC:MM"); if(cw_event.endminute.match(/^[1-5][0,5]$/)){ cw_event.endminute = "+" + cw_event.endminute; } cw_event.endampm = dateFormat(endDate, "UTC:tt"); cw_event.draft = "0"; if(cw_event.login_email == ""){ $("#remindme").hide(); } else{ $("#remindme").show(); } // When a single event comes through here there are no rpt fields // so the rpt fields default to the last state they were in // so we need to come up with something to initialize their state // what we can do is just insert default values into cw_event right here cw_event.rpt_end_day = dateFormat(rptendDate, "UTC:d"); cw_event.rpt_end_month = dateFormat(rptendDate, "UTC:m"); cw_event.rpt_end_year = dateFormat(rptendDate, "UTC:yyyy"); if(cw_event.rpt_type == undefined){ cw_event.rpt_sun = false; cw_event.rpt_mon = false; cw_event.rpt_tue = false; cw_event.rpt_wed = false; cw_event.rpt_thu = false; cw_event.rpt_fri = false; cw_event.rpt_sat = false; cw_event.rpt_type = "none"; cw_event.rpt_weeks = "1"; cw_event.rpt_days = "2"; cw_event.rpt_month_place = "first"; cw_event.rpt_noenddate= false; } initControls(); //only for whether they are enabled or disabled. for(var p in fieldsToPopulate){ if ((p == 'privatenote') && (!data.status.canviewprivatenote)) { continue; } var thisInputControl = $("#"+p); if(fieldsToPopulate[p].match(/span/)){ thisInputControl.text(cw_event[p]); } else if(fieldsToPopulate[p].match(/checkbox/)){ if(cw_event[p]){ thisInputControl.attr("checked", true); } else { thisInputControl.attr("checked", false); } } else { thisInputControl.val(cw_event[p]); } if(cw_event.edittype == "single") { //in single event of a repeating series mode if(p.match(/^rpt_/) && !p.match(/^rpt_last_flag/)){ thisInputControl.attr("disabled", true); } } else { thisInputControl.attr("disabled", false); } } // If adding event then set category dropdown to first checked category in filter if(data.status.view == "a"){ // Set category dropdown to first category selected in filter if (cidarray.length > 0) { $("#eventform #category_id").val(cidarray[0]); } } // Store location_id in global DOM variable from location select list last_saved_location_id = $("#location_id").val(); // Set Saved Location zero option text if editing event already has Saved Location if (last_saved_location_id != 0) { $("#location_id option[value='0']").text('De-Select Saved Location'); } // If using html editor (i.e. tinymce) update the tinymce editor so has // content of the description text area and not left over from previous edit if ((usehtmled) && (typeof tinyMCE != 'undefined')) { // Get editor object var editor = tinyMCE.get('description'); // Get content of description text area var descriptionval = $("#description").val(); descriptionval = descriptionval.replace(//g, ""); editor.execCommand('mceSetContent', false, descriptionval); editor.startContent = tinymce.trim(editor.getContent({ format: 'raw' })); editor.isNotDirty = true; editor.nodeChanged(); } setNumDays('e'); setNumDays('rpt_end_'); timeOptions(); docontrols(); gInitSerialize = $("[name=eventform]").serialize(); display_action_row(); checkCatFiltered(); // Scroll form to top $("#eventform").scrollTop(0); // minus 30 for padding // Remove focus from active element just in case so // keyboard not opened on inital form display $(document.activeElement).blur(); } else { // Something wrong handleResponseError(data); } } //################################ Saving an Event ####################################### function SaveEvent(mode){ if (mode != 'delete') { var valid = validate(); if(!valid){ return false; } } // If using html editor (i.e. tinymce), need to get description into actual textarea for posting if ((usehtmled) && (typeof tinyMCE != 'undefined')) { var tinymce_description = tinymce.get('description').getContent(); if (tinymce_description != '') { $("#description").val('' + tinymce_description); // Only if description not blank } else { $("#description").val(''); } } else { // Remove html editor comment tag in case was edited by html editor and then html editor turned off in options // Note that other html tags are not removed at this time $("#description").val($("#description").val().replace(//g, "")); } var serialize = $("[name=eventform]").serialize(); var edittype = $("#edittype").val(); var event_id = $("#event_id").val(); var repeat_id = $("#repeat_id").val(); if(mode == "delete") { $.confirm("Are you sure you want to delete this event?", "This operation cannot be undone", function () { serialize += "&btndelete=Delete"; $("#edit").hide(); $.post("/calendars/editevent_savemobile.php" + gPHPSESSID + "&crd=" + gCalendar + "&view=u", serialize, eventSaveCallback, "json") .done(function() { }) .fail(function() { }); return; }); } if(mode == "draft"){ serialize = serialize.replace(/draft=0/, "draft=1"); } if(edittype == "single" || edittype == ""){ serialize = serialize.replace(/occ_changed=0/, "occ_changed=1"); } var dirty = gInitSerialize != serialize; if(dirty){ if(!validate()){ return; } if($("#old_occ_changed").val() == "1" && (edittype == 'repeats')){ if(!confirm("CAUTION: You are editing all occurrences of this repeating event. Saving will overwrite changes previously made to individual occurrences of this event.")){ return; } } } // CLIENT: Flag set when editing occurrence of a repeating series if any data was changed. This needs to be set by client and in POST serialize = serialize.replace(/minute=%2B/g, "minute="); // Get primary category name and put into serialize variable var selcatoption = $("#category_id option:selected"); var cat_name = selcatoption.text(); serialize += "&cat_name=" + cat_name; // Get category noconflict property value for the selected category var catnoconflicts = selcatoption.prop("noconflicts"); // If saved location selected, Get selected location noconflict property if ($("#location_id").val() != 0) { var sellocoption = $("#location_id option:selected"); var loc_name = sellocoption.text(); var locnoconflicts = sellocoption.prop("noconflicts"); } else { var locnoconflicts = '0'; var loc_name = ''; } if ((mode == "save") || (mode == 'draft')) { if ((mode != 'draft') && ((catnoconflicts == "1") || (locnoconflicts == "1"))) { // Check for category conflicts $.post("/calendars/editevent_conflictcheck.php"+gPHPSESSID+"&crd="+gCalendar+"&catnoconflicts="+catnoconflicts+"&locnoconflicts="+locnoconflicts, serialize, function(data) { if (data.status.code == 700) { var catconcount = parseInt(data.conflicts.catconcount); if (catconcount == 1) { var catcontxt = ""; } else { var catcontxt = "s"; } var locconcount = parseInt(data.conflicts.locconcount); if (locconcount <= 1) { var loccontxt = ""; } else { var loccontxt = "s"; } var numconflicts = parseInt(data.conflicts.eventconcount); if (numconflicts == 1) { var numcontxt = ""; } else { var numcontxt = "s"; } var conflictmsg = 'Sorry, this event conflicts with ' + numconflicts + ' event' + numcontxt + ' in the calendar. ' + "\n\n"; if (catconcount > 0) { conflictmsg += ' - ' + catconcount +' conflict' + catcontxt + ' in category ' + cat_name + "\n"; } if (locconcount > 0) { conflictmsg += ' - ' + locconcount +' conflict' + loccontxt + ' at location ' + loc_name + "\n"; } conflictmsg += "\n"; conflictmsg += 'Please Choose different time'; if (catconcount > 0) { if (locconcount > 0) { conflictmsg += ', category or location.'; } else { conflictmsg += ' or category.'; } } else { conflictmsg += ' or location.'; } conflictmsg += "\n\n"; $.alert(conflictmsg, 'Conflict Found'); return false; } else { // No conflicts found so save postSave(serialize); } }, "json"); } else { // No conflict check, just save postSave(serialize); } } } function postSave(serialize) { // Go ahead and save event - update or add, deletes done above var edited_event_id = $("#edit #event_id").val() // May be blank if this was add event if (edited_event_id == '') { var postview = 'a'; } else { var postview = 'u'; } $("#edit").hide(); $.post("/calendars/editevent_savemobile.php" + gPHPSESSID + "&crd=" + gCalendar + "&view=" + postview, serialize, eventSaveCallback, "json"); } function eventSaveCallback(data, result){ commonAjaxCallback(data, result); if (data.status.code == 200) { gRefreshAfterEdit = true; // flag to force refresh of lists on return from event detail // See if this was delete if (data.status.msg == 'Successful Delete Operation') { // Event was deleted var wasdelete = true; } else { // Not a delete var wasdelete = false; // Get id of first occurrence returned from save event if (typeof data.eventdetails.first_occ_event_id != 'undefined') { var first_occ_event_id = data.eventdetails.first_occ_event_id; } else { var first_occ_event_id = 0; } } var edittype = $("#edit #edittype").val(); var edited_event_id = $("#edit #event_id").val() // May be blank if this was add event var edited_repeat_id = $("#edit #repeat_id").val() // May be zero if this was edit of single event gCameFromUpdate = true; // ------------------------------------------------------ // Handle view return for different types of event saves // ------------------------------------------------------ // For new add event and deletes retun to current view if ((wasdelete) || ((edited_event_id == '') && (edittype == ''))) { g_cw_id = 0; showCurrentView (currentView, true); } else if (gCameFromDetail) { gCameFromDetail = false; gCurrentPlace = "eventdetails"; display_action_row(); if (first_occ_event_id > 0) { displayEvent(first_occ_event_id); } else { displayEvent(edited_event_id); } } else { g_cw_id = 0; showCurrentView (currentView, true); } } else { if (data.status.code == '855') { showCurrentView (currentView, true); $.alert('Sorry, you have exceeded allowed daily events. Contact support@calendarwiz.com', 'Limit Reached'); g_cw_id = 0; showCurrentView (currentView, true); } else { // Something wrong handleResponseError(data); } } } // Clean up event display list date seperators function cleanuplistdates() { var prevdatadate = ''; $("#dayevents").children().each(function(index) { var attr = $(this).attr('data-date'); if (typeof attr != 'undefined') { if (prevdatadate != '') { $("#dayevents div[data-date='"+prevdatadate+"']").remove(); } prevdatadate = attr; } else { prevdatadate = ''; } }); } //##################################### Category Filter Functions ################################# // Open category filter setting display function openFilter() { $("#navTodayAddLogInOut").hide(); $("#calendar").hide(); $("#dayevents").hide(); $("#category_filter_list").height(listcurrentfullht - 28).show().scrollTop(0); // minus 28 for padding gCurrentPlace = "categoryfilter"; display_action_row(); } // Cancel category filter setting and return to previous checked function cancelFilter() { // Set category filter checkboxes to previous values $('.catpermits').each(function() { if (jQuery.inArray($(this).val(), cidarray) !== -1) { $(this).attr("checked", true); } else { $(this).attr("checked", false); } }); // If all categories now checked then set all checkbox checked if ($(".catpermits").length == $(".catpermits:checked").length) { $("#toggleallcats").attr("checked", true); } else { $("#toggleallcats").attr("checked", false); } $("#checkonecatmsg").hide(); $("#category_filter_list").hide(); showCurrentView (currentView, false); } // // Get any filter categories saved in cookie function getCategoryFilterCookie() { // Init or clear array of cookie category ids cidcookiearray = []; // Get categories for filter from cookie if present cidcookie = readCookie('cw_cidarray_'+gCalendarId); if (cidcookie != "" && cidcookie != null) { cidcookiearray = cidcookie.split(','); } } // Get categories for filter list, respects private categories via login function getViewCategories(){ $.getJSON("/cwapi.php" + gPHPSESSID, {fmt:"json", view:"c", crd:gCalendar}, getViewCategoriesCallback, "json"); } // Loads categories into search select. Checks categories that are active function getViewCategoriesCallback(data, result){ if(!commonAjaxCallback(data, result)){ return; } if (data.categories != undefined) { // Clear any elements that might be in category list $("#category_filter_list .content *").remove(); // Insert 'All' checkbox if (gSkip_all == 0) { categoryhtml = '
'; $("#category_filter_list .content").append(categoryhtml); // If this category id is already in cidarray get it's index otherwise this gives -1 // NOTE: This inArray is strict (i.e. type sensitive - cidarray is string not numeric) if (cidurlarray.length > 0) { category_index = jQuery.inArray(""+categories[i].category_id, cidurlarray) // Will be -1 if not in array } else if (cidcookiearray.length > 0) { category_index = jQuery.inArray(""+categories[i].category_id, cidcookiearray) // Will be -1 if not in array } else { category_index = -1; } if ((category_index !== -1) || (allcatschecked)) { $("#"+categories[i].category_id).attr("checked", true); // Check this category checkbox // Only put into cidarray if in url or cookie if (category_index !== -1) { cidarray.push(categories[i].category_id); // Add this category id to cidarray } } } if ($(".catpermits").length == $(".catpermits:checked").length) { // If number of categories in filter array same as total number of categories // then set all check box checked and set filter icon color to normal $("#toggleallcats").attr("checked", true); cidarray = []; // Clear the array of checked categories $(".fa-filter").css("color","#fff"); // All checked so filter off = normal icon color white } else { $(".fa-filter").css("color","#cdffba"); // Not all checked so filter on = green } // Set up on click event for category filter checkboxes for setting all checkbox with all checked $(".catpermits").bind("click", setAllCatsCheckbox); // Hide category filter if only one category if ($(".catpermits").length == 1) { $("#filterbtn").hide(); } else { $("#filterbtn").show(); } // If multi categories not allowed and All is checked then uncheck other radio buttons // and set filter icon to filter off color (white) if (($("#toggleallcats").is(':checked')) && (gSkip_all == 0) && (gMulticat_on == 0)) { $(".catpermits").attr("checked",false); $(".fa-filter").css("color","#fff"); // filter off = normal icon color white } // Display view if (typeof cal == 'object') { // If calendar already init then just show current view with refresh showCurrentView(currentView, true); } else { // First time load, need to init calendar and show month grid with list below initMonthlyDisplay(); } } } // Function to check or uncheck All checkbox in category filter list on click to any checkbox in list function setAllCatsCheckbox() { var numnotchecked = $(".catpermits:not(:checked)").length; // Number of categories checked $("#checkonecatmsg").hide(); if (numnotchecked == 0) { $("#toggleallcats").attr("checked", true); } else { $("#toggleallcats").attr("checked", false); } display_action_row(); } function toggleAllCategories() { if ((this.checked) && (gMulticat_on == 1)) { $('.catpermits').each(function() { this.checked = true; }); } else { $('.catpermits').each(function() { this.checked = false; }); } display_action_row(); } // Function to create category filter array, set cookie, set icon color // Category filter checkboxes (catpermits[]) will always have at least // one checked, maybe all checked. function applyCategoryFilter() { // See if at least one categories checked, if not show message if ($(".categoryfilter").find('input[name="catpermits[]"]:checked, input[name="toggleallcats"]:checked').length == 0) { $("#checkonecatmsg").show(); // Show message if none are checked, at least one must be checked return false; } else { $("#checkonecatmsg").hide(); // In case was showing } // If All categories checked or if All radio checked when multi category selection is off if (($(".catpermits").length == $(".catpermits:checked").length) || ($("#toggleallcats:checked").length > 0)) { cidarray = []; // Clear the array of filter categories eraseCookie('cw_cidarray_'+gCalendarId); // Erase cookie for future session $(".fa-filter").css("color","#fff"); // filter off = normal icon color white return true; } // --------------------------------------------------------- // At least one but not all checked so apply category filter // --------------------------------------------------------- // Change to filter overrides url cid[] arguments cidurlarray = []; // Init categories filter array if (typeof cidarray != "undefined") { cidarray.length = 0; } else { cidarray = new Array(); } var catcookiestr = ''; // String to hold category ids separated by commas // Loog thru alls checked categories and create DOM array and cookie string // both containing category ids of checked categories $(".catpermits").each(function(index) { if (this.checked === true) { // Put category id into DOM array cidarray.push(this.value); // Put category id into cookie string catcookiestr += this.value + ','; } }); // Create cookie of category ids in filter createCookie('cw_cidarray_'+gCalendarId,catcookiestr.slice(0, -1),50); // Set filter icon to active color $(".fa-filter").css("color", "#cdffba"); // filter on = green return true; } // Check if selected in category is hidden in filter, show notice function checkCatFiltered() { if ((cidarray.length > 0) && (jQuery.inArray($("#eventform #category_id").val(), cidarray) < 0)) { // Will be -1 if not in array // Category selected in editor is hidden by filter so display notice $("#categoryhiddenmsg").show(); } else { $("#categoryhiddenmsg").hide(); } } //##################################### Email Functions ################################# function openNewEmail(e){ var jDetailDIV = $(e.target).closest("[cwui='detaildiv']"); $("#eventdetailactionrow").hide(); $("#event").hide(); var jEmailBodyDIV = $("#emailform"); jEmailBodyDIV.show(); jEmailBodyDIV.height(listcurrentfullht - 30); // minus 30 for padding $("#emailform").height(listcurrentfullht - 30); jEmailBodyDIV.find("[cwui=emailfrom]").val(gData.status.email); var prefillemailaddress = gData.status.email; // Just email address, no display name jEmailBodyDIV.find("[cwui=emailfrom]").val(prefillemailaddress); jEmailBodyDIV.find("[cwui=emailto]").val(prefillemailaddress); jEmailBodyDIV.find("[cwui=subject]").val("Calendar Note: " + $("#event #value_title").text()); jEmailBodyDIV.find("[cwui=intronote]").val("Check out this event.").trigger('keyup'); jEmailBodyDIV.show(); jEmailBodyDIV.scrollTop(0); gCurrentPlace = "sendemail"; display_action_row(); return false; } function clearIntro() { $("#emailform").find("[cwui=intronote]").val(''); displayCharsRemaining(); } function displayCharsRemaining() { var jIntroNote = $("#emailform").find("[cwui=intronote]"); var len = jIntroNote.val().length; if(len > introNoteMaxLength){ jIntroNote.val(jIntroNote.val().substr(0,introNoteMaxLength)); return false; } $("#emailform").find("[cwui=charleft]").text("Max " + introNoteMaxLength + " characters, " +(introNoteMaxLength - len) + " remaining"); return true; } function cancelEmail() { $("#sendemailactionrow").hide(); $("#emailform").hide(); gCurrentPlace = "eventdetails"; display_action_row(); jDetailBodyDIV.show(); } function sendEmail(e){ var jDetailDIV = $(e.target).closest("div"); var jEmailBodyDIV = $("#emailform"); var emailto = jEmailBodyDIV.find("[cwui=emailto]").val(); var emailfrom = jEmailBodyDIV.find("[cwui=emailfrom]").val(); if(!checkemailaddress(emailto)){ jEmailBodyDIV.find("[cwui=emailto]").focus(); $.alert("Please enter a valid to email address", ""); jDetailDIV.scrollTop(0); return; } if(!checkemailaddress(emailfrom)){ jEmailBodyDIV.find("[cwui=emailfrom]").focus(); $.alert("Please enter a valid from address", ""); jDetailDIV.scrollTop(0); return; } var subject = jEmailBodyDIV.find("[cwui=subject]").val(); var note = jEmailBodyDIV.find("[cwui=intronote]").val(); if(subject == ""){ jEmailBodyDIV.find("[cwui=subject]").focus(); $.alert("Please enter an email subject", ""); jDetailDIV.scrollTop(0); return; } if(note.length > introNoteMaxLength){ jEmailBodyDIV.find("[cwui=intronote]").focus(); $.alert("Please shorten your introduction to " + introNoteMaxLength + " characters.", ""); jDetailDIV.scrollTop(0); return; } $.post("/cwapi.php" + gPHPSESSID + "&callback=?", {subject:subject, intronote:note, fromemail:emailfrom, toemail:emailto, event_id:g_cw_id, repeat_id:g_rpt_master_id, fmt:"json", view:"sendevent", crd:gCalendar}, emailCallback, "json"); } function emailCallback(data, result){ commonAjaxCallback(data, result); if(data.status.code == "200"){ //here we show the status msg $.alert(data.status.msg, "Success"); var jEmailBodyDIV = $("#emailform"); jDetailBodyDIV.show(); jEmailBodyDIV.hide(); $("#emailform").hide(); gCurrentPlace = "eventdetails"; display_action_row(); }else{ // Something wrong handleResponseError(data); } } //##################################### Remind Functions ################################# // Check if a reminder set for event currently displayed in detail view function checkReminder() { $.getJSON("/cwapi.php" + gPHPSESSID + "&callback=?", {event_id:g_cw_id, repeat_id:g_rpt_master_id, fmt:"json", view:"getremind", crd:gCalendar}, checkreminderCallback); } // Callback to set reminder icon color to active color if reminder set for event in detail view function checkreminderCallback(data, result) { if (data.remindersettings.reminder_id > 0) { $(".fa-bell").css("color","#cdffba"); // Not all checked so filter on = green } else { $(".fa-bell").css("color","#fff"); // All checked so filter off = normal icon color white } } // Get reminder for event on click on reminder icon (bell) function getReminder(e) { var jDetailDIV = $(e.target).closest("div"); $.getJSON("/cwapi.php" + gPHPSESSID + "&callback=?", {event_id:g_cw_id, repeat_id:g_rpt_master_id, fmt:"json", view:"getremind", crd:gCalendar}, reminderCallback); return false; } // Set reminder from form displayed by click on reminder icon (bell) function setReminder(e) { var jDetailDIV = $(e.target).closest("div"); var priortime = jRemindBodyDIV.find("[cwui=priortime]").val(); var email = jRemindBodyDIV.find("[cwui=email]").val(); if(!jRemindBodyDIV.reminder_id){ jRemindBodyDIV.reminder_id = 0; } if(checkemailaddress(email)){ if (g_rpt_master_id > 0) { g_repeat_mode = 'all'; } else { g_repeat_mode = 'single'; } $.getJSON("/cwapi.php" + gPHPSESSID + "&callback=?", {reminder_id:jRemindBodyDIV.reminder_id, email:email, priortime:priortime, repeat_mode:g_repeat_mode, event_id:g_cw_id, repeat_id:g_rpt_master_id, fmt:"json", view:"setremind", crd:gCalendar}, reminderCallback); }else{ $.alert("Please enter a valid email address", ""); } } // Delete reminder for event from form displayed by click on reminder icon (bell) function deleteReminder(e) { var jDetailDIV = $(e.target).closest("div"); if (g_rpt_master_id > 0) { g_repeat_mode = 'all'; } else { g_repeat_mode = 'single'; } $.getJSON("/cwapi.php" + gPHPSESSID + "&callback=?", {reminder_id:jRemindBodyDIV.reminder_id, repeat_mode:g_repeat_mode, event_id:g_cw_id, repeat_id:g_rpt_master_id, fmt:"json", view:"delremind", crd:gCalendar}, reminderCallback); } // Confirm after reminder action function reminderCallback(data, result) { commonAjaxCallback(data, result); if(data.status.code == 200 || data.status.code == 201){ if(data.status.view == "getremind"){ //here we need to display the reminder form and hide the event display jDetailBodyDIV.hide(); jRemindBodyDIV = $("#reminderform"); jRemindBodyDIV.show(); display_action_row(); jRemindBodyDIV.find("[cwui=priortime]").val(data.remindersettings.priortime); jRemindBodyDIV.find("[cwui=email]").val(data.remindersettings.email); $("#reminderform").height(listcurrentfullht); if (data.status.code == 200) { jRemindBodyDIV.find("[cwui=email]").val(data.remindersettings.email); } else { // Get best default email, with display name if possible var prefillemailaddress = gData.status.email; // Just email address, no display name jRemindBodyDIV.find("[cwui=email]").val(prefillemailaddress); } jRemindBodyDIV.reminder_id = data.remindersettings.reminder_id; if(data.remindersettings.reminder_id){ $("#deletereminder").show(); $("setreminder").val("Update Reminder"); $("#setreminderheader").text('Editing Reminder'); }else{ $("setreminder").val("Set Reminder"); $("#deletereminder").hide(); $("#setreminderheader").text('Setting Reminder'); } gCurrentPlace = "setreminder"; display_action_row(); }else{ // Here we show the status msg - reminder set if (data.status.view == 'delremind') { $(".fa-bell").css("color","#fff"); // Change remonder icon (bell) to not set color $.alert('Reminder removed', ""); } else if (data.status.view == 'setremind') { $(".fa-bell").css("color","#cdffba"); // Change reminder icon (bell) to set color $.alert('Reminder saved', ""); } else { $.alert(data.status.msg, ""); } jDetailBodyDIV.show(); jRemindBodyDIV.hide(); gCurrentPlace = "eventdetails"; display_action_row(); } } else { // Something wrong handleResponseError(data); } } //##################################### Download Event ################################# // Downloads event ical by click on download icon in event detail view function downloadEvent(e) { location.href = "/calendars/popcal.php" + gPHPSESSID + "&eid=" + g_cw_id; return false; } //##################################### Edit Form Functions ################################# function setNumDays(prefix) { //we need to make the eday dropdown have the right number of days in it. //also have to change the selected day if it is greater than the number of days in the month var feb = 28; if((parseInt($("#"+prefix+"year").val()) % 4) == 0){ feb = 29; } var days = dateFormat.daysInMonth[parseInt($("#"+prefix+"month").val())]; if(days == 28){ days = feb; } var dayDD = $("#"+prefix+"day")[0]; var len = dayDD.options.length; if(len == days)return; if(len < days){ for(var i = len; i < days; i++){ dayDD[i] = new Option(i + 1, i + 1); } } else{ var selectedIndex = dayDD.selectedIndex; dayDD.options.length = days; if(selectedIndex > (days - 1)){ dayDD.selectedIndex = days - 1; } } } function setHoursDropDown(dd, military){ if(military){ if(dd.options.length == 24){ return; } else { dd.options.length = 0; for(var i = 0; i < 24; i++){ dd.options[i] = new Option(pad(i), i); } } } else{ // Handles scenario where if(dd.options.length == 12){ return; } else { dd.options.length = 0; for(var i = 0; i < 12; i++){ dd.options[i] = new Option(pad(i + 1), pad(i + 1)); } } } } function timeOptions(type){ var allday = $("#allday")[0].checked; var noend = $("#noend")[0].checked; if(type == "allday" && allday){ $("#noend")[0].checked = false; noend = false; } else if(type == "noend" && noend){ $("#allday")[0].checked = false; allday = false; } if(!allday && !noend){ $("#starthour").removeAttr("disabled"); $("#startminute").removeAttr("disabled"); $("#startampm").removeAttr("disabled"); $("#starttime").show(); $("#endhour").removeAttr("disabled"); $("#endminute").removeAttr("disabled"); $("#endampm").removeAttr("disabled"); $("#endtime").show(); } else if(noend){ $("#starthour").removeAttr("disabled"); $("#startminute").removeAttr("disabled"); $("#startampm").removeAttr("disabled"); $("#starttime").show(); $("#endhour").attr("disabled", true); $("#endminute").attr("disabled", true); $("#endampm").attr("disabled", true); $("#endtime").hide(); } else{ $("#starthour").attr("disabled", true); $("#startminute").attr("disabled", true); $("#startampm").attr("disabled", true); $("#starttime").hide(); $("#endhour").attr("disabled", true); $("#endminute").attr("disabled", true); $("#endampm").attr("disabled", true); $("#endtime").hide(); } } // Following function now used to get list of categories for add / edit // Note the subview parameter to be used in the get category list api // function to flag filtering of only categories allowed to edit for this // logged in user - introduced 120406 by Dennis Mulryan function getEditCategories(calendar, callback){ $.getJSON("/cwapi.php" + gPHPSESSID, {fmt:"json", view:"c", subview:"addedit", crd:calendar}, callback, "json"); } // Get locations for add / edit form function getEditLocations(calendar, callback){ $.getJSON("/cwapi.php" + gPHPSESSID, {fmt:"json", view:"l", subview:"addedit", crd:calendar}, callback, "json"); } // Loads categories into editor select function populateCategoryDropDown(data, result){ if (data.categories != undefined) { var categories = data.categories; var jEventDiv = $("#edit"); var catDD = jEventDiv.find(":input[name='category_id']")[0]; catDD.options.length = 0; for(var i = 0; i < categories.length; i++){ // This put in because API sends any category name with special characters as null // Need to fix this in API since affects all category name from API (e.g. search widgets) if(!categories[i].category_name) { categories[i].category_name = 'unknown'; } if(categories[i].category_name.length > 45){ categories[i].category_name = categories[i].category_name.substr(0, 45) + "..."; } catDD.options[catDD.options.length] = new Option(categories[i].category_name, categories[i].category_id); // Add noconflicts attribute to this category option, note need to use length-1 // because we just created option so length changed and need to backup one index catDD.options[catDD.options.length-1].noconflicts = categories[i].noconflicts; } } if(editEventEvent == undefined){ addEvent(editEventEvent, true); } else{ editEvent(editEventEvent, true); } } // Loads locations into select function populateLocationDropDown(data, result){ if (data.locations != undefined) { // Clear any remnants of prior add or edit last_saved_location_id = 0; $("#locmsg").hide(); // Put location data into var var locations = data.locations; var jEventDiv = $("#edit"); var locDD = jEventDiv.find(":input[name='location_id']")[0]; locDD.options.length = 0; if (data.locations.length > 0) { // First option is no saved location locDD.options[0] = new Option("Choose Saved Location", "0"); for(var i = 0; i < locations.length; i++){ // This put in because API sends any location name with special characters as null // Need to fix this in API since affects all location name from API (e.g. search widgets) if(!locations[i].location_name) { locations[i].location_name = 'unknown'; } if(locations[i].location_name.length > 45){ locations[i].location_name = locations[i].location_name.substr(0, 45) + "..."; } locDD.options[locDD.options.length] = new Option(locations[i].location_name, locations[i].location_id); // Add noconflicts attribute to this category option, note need to use length-1 // because we just created option so length changed and need to backup one index locDD.options[locDD.options.length-1].noconflicts = locations[i].location_no_conflicts; } } else { // No current saved locations locDD.options[0] = new Option("No Saved Locations Yet", "0"); } } } //######################### Refresh ############################### var gTimeoutHandle; var timeoutMilliseconds = 60000 * 115; // 115 minutes //var timeoutMilliseconds = 10000 * 1; // 10 seconds for testing gTimeoutHandle = window.setTimeout(refresh, timeoutMilliseconds); // This only refreshes the session on server function refresh() { // Clear any existing timeout if(gTimeoutHandle){ window.clearTimeout(gTimeoutHandle); gTimeoutHandle = undefined; gTimeoutHandle = window.setTimeout(refresh, timeoutMilliseconds); } if ($.active) { return false; } // Do post to refresh session on server $.post("/cwapi.php" + gPHPSESSID, {view:"refresh", fmt:"json", crd:gCalendar}, refreshCallback, "json"); } function refreshCallback(data, result){ commonAjaxCallback(data, result); } // This refreshes current view to get up-to-date info function refreshCurrentView() { showCurrentView(currentView, true); } //######################### Authorization ############################### function createCookie(name,value,days) { if (days) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString(); } else var expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } function eraseCookie(name) { createCookie(name,"",-1); } function login(username, password, callback){ // Hide wrong case message $("#passwordmsg").hide(); var rememberme = $("#rememberme:checked").val(); var parameters = {scr:username, psw:password, crd:gCalendar, remlogin:rememberme}; $.post("/cwapi.php" + gPHPSESSID + "&auth=login&fmt=json", parameters, callback, "json"); } function loginFromForm(){ var username = $.trim($("#username").val()); if(username == ""){ $.alert("Please enter Username or Email", ""); return; } var password = $.trim($("#password").val()); if(password == ""){ $.alert("Please enter a Password", ""); return; } var parameters = {login:username, password:password, setpassword:setpassword}; login(username, password, loginCallback); } function loginCookies(callback){ var rememberme = true; $.post("/cwapi.php" + gPHPSESSID + "&auth=cookies&view=auth&fmt=json", {fmt:"json", crd:gCalendar, rememberme:true}, callback, "json"); } function showLoginScreen(){ var username = readCookie("cw_user"); if(username){ $("#username").val(unescape(username)); $("#password").val(""); $("#rememberme").attr("checked", true); } else{ $("#username").val(""); $("#password").val(""); } $("#navTodayAddLogInOut").hide(); $(cal.grid).hide(); logincancelviz(); $("#loginform").show(); if(username){ $("#password")[0].focus(); } else{ $("#username")[0].focus(); } gCurrentPlace = "loginscreen"; display_action_row(); } function logincancelviz() { if (gNoPublicCats) { $("#logincancel").hide(); } else { $("#logincancel").show(); } } function logInOut(e){ // Ignore login / out touch if ajax still actively // retrieving else may show list with login screen // also open below if ($.active > 0) { return false; } if (e.target.id == "loginlink") { $("#dayevents").hide(); showLoginScreen(); gDestinationScreen = undefined; } else { // Call the cwapi.php to logout session. $.post("/cwapi.php" + gPHPSESSID + "&auth=logout&fmt=json", {crd:gCalendar}, logoutCallback, "json"); } } function logoutCallback(data, result) { if ((commonAjaxCallback(data, result)) && (data.status["code"] == 200)) { // Need to get categories for filter to remove any private getViewCategories(); } } function loginCallback(data, result) { commonAjaxCallback(data, result); if(data.status.code == 200){ $("#loginform").hide(); $("#loginlink").hide(); // Need to get categories for filter in case all were private // which triggered login before this could be done //getViewCategories(); // Do not show add button if show busy set and not logged in if ((gCalShowBusy == 1) && (!gLoggedIn)) { $("#navTodayAddLogInOut #a1").hide(); } else { $("#navTodayAddLogInOut #a1").show(); } gCanAdd = data.status.canadd; // Can this use add events true or false gIsAdmin = data.status.isadmin; // Is this user an admin gIsManager = data.status.ismanager; // Is this user a manager // Reset to initial value so will check case again setpassword = false; // Need to get categories for filter in case all were private // which triggered login before this could be done // Note this will show current view after getting categories getViewCategories(); } else if (data.status.code == 400){ $.alert(data.status.msg, ""); return false; } else { // Something wrong handleResponseError(data); } } function loginformcancel() { $("#loginform").hide(); showCurrentView (currentView, false); } function setCalendar(){ var calendar = $("#cal_id").val(); if(calendar == ""){ $("#cal_id")[0].focus(); $.alert("Please enter a calendar name", ""); return; } window.location.href = "/mobile.html?crd=" + calendar; return; } //#################################### Format Functions ############################## function getStartEndTime(cw_event, stringonly){ if(cw_event.allday){ if (stringonly) { return "All Day"; } else { return "
"+"All"+"
"+"
"+"Day"+"
"; } } else{ var mil = gIsMilitary == '1'; if(mil){ var endText = ""; if(!cw_event.noend){ endText = " " + dateFormat(tsToDate(cw_event, "end_timestamp_gmt", "end_tzoffset"), "UTC:HH:MM"); } var startText = dateFormat(tsToDate(cw_event, "start_timestamp_gmt", "start_tzoffset"), "UTC:HH:MM"); if (stringonly) { return startText+" - "+endText; } else { return '
'+startText+"
"+'
'+endText+"
"; } } else{ endText = ""; if(!cw_event.noend){ if (stringonly) { endText = " - "; } endText += dateFormat(tsToDate(cw_event, "end_timestamp_gmt", "end_tzoffset"), "UTC:h:MMtt"); } startText = dateFormat(tsToDate(cw_event, "start_timestamp_gmt", "start_tzoffset"), "UTC:h:MMtt"); if (stringonly) { return startText+endText; } else { return '
'+startText+"
"+'
'+endText+"
"; } } } } function tsToDate(cw_event, tsPropertyName, timeZoneOffsetPropertyName){ return new Date((parseInt(cw_event[tsPropertyName]) + 3600*parseFloat(cw_event[timeZoneOffsetPropertyName])) * 1000) } //################################################## Navigation Functions ########################################## function goToToday(){ cal.date = new Date(); g_cw_id = 0; // Clear the event id so does not scroll to event if (currentView == 'calendar') { // Display calendar and today's events below if ($(".today").hasClass("disabled")) { gselectedDateClass = 'disabled'; } else { gselectedDateClass = 'enabled'; } showCurrentView (currentView, true); } else { // List view showCurrentView (currentView, true); } } //################################################## View Functions ########################################## function showCurrentView (currentView, refresh) { if(cal.date == undefined){ cal.date = new Date(); } if ((gOrientation == 'landscape') && ($("#dayevents .daydatedisplay").length == 0)) { // If orientation is landscape but no date spacers then show current view // with refresh because may have been rotated to landscape after opening // event detail view and need to make sure full list view is shown refresh = true; } if ((currentView == 'list') || (gOrientation == 'landscape')) { viewList(refresh); } else { viewCalendar(refresh); } gCurrentPlace = "events_cal_or_list"; display_action_row(); } function viewList(refresh){ $("#filterdiv").hide(); $("#viewlist").hide(); if (gOrientation == 'landscape') { $("#viewcalendar").hide(); } else { currentView = 'list'; $("#viewcalendar").show(); } $("#calendar").hide(); $("#dayevents").height(listcurrentfullht).show(); if (refresh) { getListEvents(gCalendar, cal.date, 'beforeandafter'); } // Note: Do not set current view to list because // may just be in landscape orientation which forces // full list view but want to keep currentView if it // is calendar so re-orientation to portrait shows calendar } function viewCalendar(refresh){ $("#filterdiv").hide(); $("#viewlist").show(); $("#viewcalendar").hide(); $("#calendar").show(); $("#dayevents").css("height",listcalendarht).show(); if (refresh) { getMonthEvents(gCalendar, cal.date); getDayEvents(gCalendar, cal.date); } // Always set currentView to calendar here currentView = 'calendar'; } //###################### AJAX Functions ###################### function commonAjaxCallback(data, result){ if(data == undefined){ return false; } if(data.status.PHPSESSID){ gPHPSESSID = "?PHPSESSID=" + data.status.PHPSESSID; gData = data; } cw_jsonStatus = data.status; calendar_type = data.status.calendar_type; gNoPublicCats = data.status.nopubliccats; gLoggedIn = data.status.loggedin; gCanAdd = data.status.canadd; gIsAdmin = data.status.isadmin; gIsManager = data.status.ismanager; gNumCatsCalendar = data.status.numcatscalendar; gNumCatsUser = data.status.numcatsuser; //showPopup(); // Commented out so does not show popup message after login if(data.status.code == 404){ $("#cal_id").val(gCalendar); if (cal) { $(cal.grid).hide(); } $("#promptCalendar").show(); $("#navTodayAddLogInOut").hide(); return false; } else if ((data.status.code == 401) || ((gNoPublicCats) && (!gLoggedIn))) { $("#cal_id").val(gCalendar); if (cal) { $(cal.grid).hide(); } $("#dayevents").hide(); $("#navTodayAddLogInOut").hide(); logincancelviz(); $("#loginform").show(); $("#username")[0].focus(); gDestinationScreen = undefined; return false; } if (typeof data.settings != 'undefined') { // Not present if coming back from edit gIsMilitary = data.settings.military; gLocationPrefix = data.settings.location_prefix; gTimeZone = data.settings.tz_env_name; gTimeZoneOffset = data.settings.tzoffsetnodst; gEventTitleGoMore = data.settings.etitle_gomore; gEventTitleGoAction = data.settings.gomore_action; gCalShowBusy = data.settings.calshowbusy; gCalShowBusyText = data.settings.calshowbusytxt; gBannersOn = data.settings.banners_on; locations_only_admins = data.settings.locations_only_admins; allowed_locations = data.settings.allowed_locations; } gLoggedIn = data.status.loggedin; gCanAdd = data.status.canadd; gIsAdmin = data.status.isadmin; gIsManager = data.status.ismanager; if (nolognavbar != 1) { if(gLoggedIn){ $("#loginlink").hide(); $("#logoutlink").show(); } else{ $("#loginlink").show(); $("#logoutlink").hide(); } } else { $("#loginlink").hide(); $("#logoutlink").hide(); } return true; } //------------------ // ERROR HANDLING // ----------------- function handleAjaxError(XMLHttpRequest, textStatus, errorThrown) { $.hideIndicator(); // Juset in case still showing if (gDebug_On) { // Display error for diagnostic document.write(textStatus + " " + errorThrown); document.write("response: " + XMLHttpRequest.response + "
"); document.write("responseType: " + XMLHttpRequest.responseType + "
"); document.write("responseText: " + XMLHttpRequest.responseText + "
"); document.write("status: " + XMLHttpRequest.status + "
"); document.write("statusText: " + XMLHttpRequest.statusText + "
"); } else { if (XMLHttpRequest.readyState == 4) { // HTTP error (can be checked by XMLHttpRequest.status and XMLHttpRequest.statusText) $.alert('Touch OK to continue','Processing Problem'); } else if (XMLHttpRequest.readyState == 0) { // Network error (i.e. connection refused, access denied due to CORS, etc.) $.alert('Check internet connection','Connection Problem'); } else { // Unknown error $.alert('Try again in a moment','Error Encountered'); } } } function handleResponseError (data) { $.hideIndicator(); // Just in case still showing // Down for maintenance if (data.status.code == 999) { // Show alert $.alert('Try again after maintenance completed','Offline For Maintenance'); // Show down for maintenance div $('#downformaintenance').show(); } else if (data.status.code == 400) { // Argument error, rate limit error, others? $.alert(data.status.msg, 'Problem Found'); } else if (data.status.code == 401) { // Hit rate limit, slow down $.alert('Private calendar requires login.',''); } else { // Display error alert $.alert("Wait a minute and try again", "Server Error: "+data.status.code); // Attempt to show current view (i.e. month grid with list or full list) showCurrentView(currentView, false); } } //------------------ // GLOBAL AJAX SETUP // ----------------- // Checks time since last server access to determing if session // is 'stale' (i.e. if session most likely ended on server). This // is to prevent Android home screen app error when opened but not // full refresh (i.e. warm or hot open on Android). Uses same var // timeoutMilliseconds as conditional to determine if session stale // This is called beforeSend for each ajax call by ajaxSetup function sessionStale(){ var gNowTime = new Date().getTime(); // Get now data/time in milliseconds // Check if over timeoutMilliseconds have passed since last ajax call // and if so then do complete refresh of the mobile app. Uses the same // var timeoutMilliseconds plus one minute (60000) as test since refresh // should occur every timeoutMilliseconds if ((gNowTime - gTimeLastAjax) > (timeoutMilliseconds + 60000)) { location.reload(true); return true; } else { gTimeLastAjax = new Date().getTime(); // move to commonajaxcallback? return false; } } $.ajaxSetup({ cache : false, beforeSend: function (jqXHR) { // Check if session older than session time out on server // and if 'stale' then if (sessionStale()) { return false; } }, error:function(XMLHttpRequest, textStatus, errorThrown) { handleAjaxError(XMLHttpRequest, textStatus, errorThrown); } }); // For diagnostics // $( document ).ajaxSend(function( event, request, settings ) { // alert(settings.url); // }); // Show please wait image on ajaxt start $(document).ajaxStart(function() { $.showIndicator(); }); // Hide please wait image on ajaxt end $( document ).ajaxStop(function() { $.hideIndicator(); }); // ---------------------------------------------------------------------------------------------- // Function to get and set selected location // ---------------------------------------------------------------------------------------------- function getlocation() { var selectedValue = $("#location_id").val(); // DOM Global, remember last selected saved location id last_saved_location_id = selectedValue; if (selectedValue == 0) { // If location id is zero then blank all location fields $("#location_name").val(''); $("#location_city").val(''); $("#location_country").val(''); $("#location_stateprovince").val(''); $("#location_street").val(''); $("#location_zippostal").val(''); $("#location_no_conflicts").val(0); // Change text in Saved Locations zero option to un-select $("#location_id option[value='0']").text('Choose Saved Location'); } else { // Event has saved location so get details from server var parameters = {crd:gCalendar}; var theurl = "/calendars/editevent_getlocation.php" + gPHPSESSID + "&location_id=" + selectedValue; $.getJSON(theurl, parameters,"json") .done(function(data) { statusObj = data.status; $("#location_name").val(data.location.location_name); $("#location_city").val(data.location.location_city); $("#location_country").val(data.location.location_country); $("#location_stateprovince").val(data.location.location_stateprovince); $("#location_street").val(data.location.location_street); $("#location_zippostal").val(data.location.location_zippostal); // Clear location message span just in case warning was present from previous // change to saved event information $("#locmsg").hide(); // Note: Only setting flag for location not allowing conflicts, this is single location // at this time but future needs to support multiple locations so if any location does // not allow conflicts then flag is set. $("#location_no_conflicts").val(data.location.location_no_conflicts); // Change text in Saved Locations zero option to un-select $("#location_id option[value='0']").text('De-Select Saved Location'); }); } } // If location text changes then set id to zero so no longer saved location // Also display message offering to save new location as reusable Saved Location function locchange(event) { var locmsgdivid = 'locmsg'; // Default, location change message will show below location details // See change event was triggered by click on button. // The value of btnclicked is set onmousedown for each button // because the onchange event will trigger before the click event // on a button and we want to know which button is clicked here so // we can adjust the behavior of the save location message depending // on the button that was clicked. For example the cancel button just // closes the editor, the save button just shows the Save Location // message and does not save until touch Save again if (btnclicked == 'cancelbtn') { eventDone(); return true; } else if (btnclicked == 'deletebtn') { SaveEvent('delete'); return true; } // Reset btnclicked = 'none'; var btntxt_add = ''; btntxt_add_1 = btntxt_add + 'Add as new Saved Location'; btntxt_add_2 = btntxt_add + 'Add ' + $("#location_name").val() + ' as new Saved Location'; var celltxt = ''; if (last_saved_location_id != 0) { var btntxt_update = ''; btntxt_update += 'Update this Saved Location'; // This is a saved location that has been changed $("#location_id").val(0); // Set location id to zeror, no longer saved location $("#location_no_conflicts").val(0); // Only saved locations can have no conflicts set celltxt = "Changes to saved location, " + $("#location_id option[value='" + last_saved_location_id + "']").text() + ", will only apply to this event."; if ((gIsAdmin == '1') || (locations_only_admins == 0)) { // Aways allow admins to add / update locations or any who edit if only admins option not set celltxt += ' You may:
' + btntxt_add_1 + '
' + btntxt_update; // append add and/or update links to saved locations message // Show location message and save as new location button $("#"+locmsgdivid).css("display","block").html(celltxt); return; } else { // Just show location message with no save as new location button $("#"+locmsgdivid).css({"display":"block","background-color":"#fcf8e3","color":"#c09853"}).html(celltxt); } } else { // Not a saved location changed, just location entered for event // Show suggestion to add to Saved Locations if ((gIsAdmin == '1') || ((locations_only_admins == 0))) { // If allowed to manage locations // This is new location not derived from Saved Location celltxt = "Suggestion: "; celltxt += btntxt_add_2; // append add link to saved locations message // Show location message and save as new location button $("#"+locmsgdivid).css("display","inline-block").html(celltxt); } } } // Add location to reusable Save Location list function addlocation(update_location_id) { var current_locations = $("#location_id option").length; if (current_locations >= allowed_locations) { var alertstr = "You've exceeded your subscripiton limit of " + allowed_locations + " locations.
"; alertstr += 'Email support@calendarwiz.com for more locations.'; $.alert(alertstr, "Location Limit Exceeded"); return false; } var location_name = escape($("#location_name").val()); if (location_name == '') { $.alert("Please enter a Location Name", ""); return false; } var location_street = escape($("#location_street").val()); var location_city = escape($("#location_city").val()); var location_stateprovince = escape($("#location_stateprovince").val()); var location_zippostal = escape($("#location_zippostal").val()); var location_country = escape($("#location_country").val()); var theurl = "calendars/ajax/save_location_from_editor.php?crd=" + gCalendar; theurl += "&location_id=" + update_location_id; theurl += "&location_name=" + location_name; theurl += "&location_street=" + location_street; theurl += "&location_city=" + location_city; theurl += "&location_stateprovince=" + location_stateprovince; theurl += "&location_zippostal=" + location_zippostal; theurl += "&location_country=" + location_country; theurl += "&PHPSESSID=" + gPHPSESSID; // Do post to save the location $.getJSON(theurl, function(data){ if (data.status.code == 200) { // Get info for new location var location_id = data.locationdetails.location_id; var location_name = unescape(data.locationdetails.location_name); if (update_location_id != 0) { // ---------------------------------------- // UPDATED: Update location name in select // ---------------------------------------- $('#location_id').find('option[value="' + location_id + '"]').text(location_name); $('#location_id').val(location_id); } else { // ----------------------------------------------- // ADDED: Insert new location into location select // ----------------------------------------------- // Insert new location into locations select options in alpha order // Note value != 0 is for first 'Select From...' dummy option var numsavedlocoptions = $('#location_id option').length; if (numsavedlocoptions == 1) { // This is first saved location so just append $('#location_id').append(''); $('#location_id').val(location_id); } else { // Already one or more saved locations so insert in alphabetic order or to end var locoptioncount = 0; $('#location_id option').each(function() { locoptioncount++; if (locoptioncount == numsavedlocoptions){ // Just append to end $('#location_id').append(''); $('#location_id').val(location_id); return false; } else if ((this.text.toLowerCase() > location_name.toLowerCase()) && (this.value != 0)) { // Insert in alpha order $(this).before(''); $('#location_id').val(location_id); return false; } }); } } // Show brief success message - this div is defined in header.inc.php if (data.locationdetails.result == 'added') { // Added saved location if($("#locmsg").is(":visible")){ $("#locmsg").html('Location Added Successfully').show().delay(4000).fadeOut(); } } else { // Updated saved location if($("#locmsg").is(":visible")){ $("#locmsg").html('Location Updated Successfully').show().delay(4000).fadeOut(); } } numsavedlocoptions++; // KEEP THIS CODE FOR FUTURE USE //----------------------------- // Update mirror locations list //----------------------------- /* // Build item html var mirrorlochtml = '
'; mirrorlochtml += ' ' + location_name + '
'; // Insert item into mirror locations list var nummirrorlocoptions = $('#mirrorloc_dialog .mirrorlocitem').length; if (nummirrorlocoptions == 1) { // This is first saved location so just append $('#mirrorloc_dialog').append(mirrorlochtml); } else { // Already one or more saved locations so insert in alphabetic order or to end var mirrorlocoptioncount = 0; $('#mirrorloc_dialog .mirrorlocitem').each(function() { mirrorlocoptioncount++; if (mirrorlocoptioncount == nummirrorlocoptions){ // Just append to end $('#mirrorloc_dialog').append(mirrorlochtml); return false; } else if ($(this).find(".mirrorlocname").text().toLowerCase().trim() > location_name.toLowerCase()) { // Insert in alpha order $(this).before(mirrorlochtml); return false; } }); } $("#mlocid_" + location_id).uniform(); $.uniform.update("#mlocid_" + location_id); hidemirrorloc(); // Show mirror locations select button if more than two saved locations if (numsavedlocoptions > 2) { $("#mirrorlocdiv").show(); $("#mirrorloctoofew").hide(); } */ } else { // Something went wrong $.alert(data.status.msg, ""); } }); } //####################### Monthly Calendar ################################## // Returns if date in calendar grid is disabled (i.e. has no events) // Will call getMonthEvents to get data from server if no already stored // in monthEvents object is not yet defined function disabledDates(date){ //here we need to see if the date is already here. If not we need to get it // if ($.active > 0) { // return cwCal.FETCHING; // } if (monthEvents == undefined) { getMonthEvents(gCalendar, cal.date); return cwCal.FETCHING; } else { if(monthEvents[cal.dateToInt(date)] == undefined){ return cwCal.DISABLED; } else { return cwCal.ENABLED; } } } // Handle touch on calendar grid date. Highlights selected date // and calls getDayEvents which gets and displays events on that day function selectedDate(e){ var jCell = $(e.target); // Set all day numbers to white background $(".day_number").css("background","#fff") .css("box-shadow","none") .css("font-weight","normal"); if (typeof(jCell[0].date) == 'undefined') { var jCell = $(e.currentTarget); if (typeof(jCell[0].date) == 'undefined') { var jCell = $(e.target).closest("td"); if (typeof(jCell[0].date) == 'undefined') { return false; } } } // Set the selected day number to gray jCell.find(".day_number").css("background","#fff") .css("font-weight","bold") .css("box-shadow","#dcdcdc 0 6px 9px 2px inset"); // Set his global variable for later gselectedDateClass = jCell.find(".day_number").parent().attr('class'); // Go get events on this day and display in list below calendar grid getDayEvents(gCalendar, jCell[0].date); } // Navigate to previous or next day based on swipe on list under // calendar grid. Go to previous month if needed function navDay(direction) { if (direction == 'prev') { cal.date.setDate(cal.date.getDate() - 1); } else if (direction == 'next') { cal.date.setDate(cal.date.getDate() + 1); } showCurrentView(currentView, true); return; } // Begin Calendar Grid Functions var cwCal = function(grid, disabledDates, selectedDate, clearCache, pleaseWait){ this.grid = grid; this.date = null; this.disabledDates = disabledDates; this.selectedDate = selectedDate; this.clearCache = clearCache; var that = this; this.navMonth = function(e){ if(typeof(e) == "string"){ var direction = e; }else{ var direction = $(e.target).closest(".nav").attr("id"); } // Get date object for middle of currently displayed month var middate = new Date(that.date.getFullYear(),that.date.getMonth(),15,0,0,0,0); if(direction.match(/next/i)){ // Add one month middate.setMonth(middate.getMonth() + 1); } else { // Subtract one month middate.setMonth(middate.getMonth() - 1); } // Reset currently displayed month to first of month that.date = new Date(middate.getFullYear(),middate.getMonth(),1,0,0,0,0); // Get calendar grid number of events on each day for new month getMonthEvents(gCalendar, that.date); // If new month is current month then go to today var todayDate = new Date(); var todayMonth = todayDate.getMonth() - 1; var thatMonth = that.date.getMonth() - 1; var todayYear = todayDate.getFullYear(); var thatYear = that.date.getFullYear(); if ((todayMonth == thatMonth) && (todayYear == thatYear)) { that.date = todayDate; } // Get events on current display date getDayEvents(gCalendar, that.date); } // Bind previous and next month event to grid arrows $(".nav").bind("click", this.navMonth); this.dateToInt = function(date){ var month = date.getMonth() + 1; if(month < 10){ month = "0" + month; } else{ month = month.toString(); } var day = date.getDate(); if(day < 10){ day = "0" + day; } else{ day = day.toString(); } return parseInt(date.getFullYear().toString() + month + day); } }; cwCal.months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; //cwCal.days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; cwCal.days = ["S", "M", "T", "W", "T", "F", "S"]; cwCal.ENABLED = 1; cwCal.DISABLED = 0; cwCal.FETCHING = -1; // CALENDAR GRID RENDERING cwCal.prototype.render = function(date, preserveCache){ gCameFromMonth = true; if(!preserveCache){ clearCache(); } if(date == undefined){ this.date = new Date(); } else{ this.date = date; } // Set todays date vars today = new Date(); todaydom = today.getDate(); todaymonth = today.getMonth(); todayyear = today.getFullYear(); todaydatestr = ""+todayyear+('0' + (todaymonth+1)).slice(-2)+('0' + (todaydom)).slice(-2); // Set currently viewed months date vars var initmonth = this.date.getMonth(); $("#month").text(dateFormat.i18n.monthNames[initmonth + 12] + " " + this.date.getFullYear()); // Note that start is incremented for each day being displayed in grid var start = new Date(this.date); var startmonth = start.getMonth(); start.setDate(1); var dow = start.getDay(); start.setDate(start.getDate() - dow); for(var i = 2; i < 8; i++){ for(var j = 0; j < 7; j++){ var dom = start.getDate(); var moy = start.getMonth(); var cell = this.grid.rows[i].cells[j]; var jCell = $(cell); // Unbind click event, otherwise multiple bind occur // on the jCell causing mutiple request to the server jCell.unbind("click"); var cellspanhtml = ''; cell.innerHTML = cellspanhtml; cell.className = ""; if((dom == todaydom) && (todaymonth == moy) && (todayyear == start.getFullYear())){ cell.className = "today "; } else if(moy != startmonth){ cell.className = "offmonth "; } if(j == 0 || j == 6){ cell.className += "weekend "; } if((dom == 1) && (moy == this.date.getMonth())) { cell.className += "firstofmonth "; } var dateStatus = this.disabledDates(start); // Get date for this cell, note that start is incremented at end of this loop cell.date = new Date(start); jCell.bind("click", this.selectedDate); // Handle display if cell has events (ENABLED) or no events (DISABLED) if(dateStatus == cwCal.DISABLED){ cell.className += "disabled"; cell.innerHTML += "
 
"; if (this.date.getTime() == start.getTime()) { gselectedDateClass = 'disabled'; } }else if(dateStatus == cwCal.ENABLED){ cell.className += "enabled"; // Add html for small dot in cell indicating there are events on that cells day cell.innerHTML +="
 
"; if (this.date.getTime() == start.getTime()) { gselectedDateClass = 'enabled'; } } else{ break; } start.setDate(dom + 1); // Increment start date object for next cell } if(dateStatus == cwCal.FETCHING)break; } for(j = 0; j < 7; j++){ this.grid.rows[1].cells[j].innerHTML = cwCal.days[j]; } if(preserveCache){ $(this.grid).show(); } // Calculate center of month grid var offset = $(cal.grid).offset(); var width = $(cal.grid).width(); var height = $(cal.grid).height(); gGridCenterX = (offset.left + width / 2) - 15; gGridCenterY = offset.top + height / 2; } // ------------------------------------ // EDIT EVENT FORM CONTROLS FUNCTIONS // ------------------------------------ // Master function to set controls states depending on repeat // type selected on page load or user selection function initControls(){ enablerptchoices(); enableweekdays(); enablerptdate(); enablerptfields(); if(cw_jsonStatus.view == "a"){ $("#deleteButton").hide(); $("#deleteButtonTop").hide(); } else{ $("#deleteButton").show(); $("#deleteButtonTop").show(); } } function docontrols() { // Single occurrence of repeating event if (document.eventform.edittype.value == "single") { disablerptchoices(); disablerptdate(); disablerptfields(); disableweekdays(); donoenddate(); return; } // No repeating event if (document.eventform.rpt_type.selectedIndex == 0) { // No repeats disablerptdate(); disablerptfields(); disableweekdays(); clearweekdays(); donoenddate(); disablerptdate(); } // Repeat options below if (document.eventform.rpt_type.selectedIndex == 1) { // Daily disablerptfields(); disableweekdays(); clearweekdays(); donoenddate(); } if (document.eventform.rpt_type.selectedIndex == 2){ // Once Every # Days disableweekdays(); clearweekdays(); disablerptfields(); document.eventform.rpt_days.disabled = false; $("#rpt_days").show(); donoenddate(); $(document.eventform.rpt_type.options[2]).text("Every..."); } else{ $(document.eventform.rpt_type.options[2]).text("Every # days"); } if (document.eventform.rpt_type.selectedIndex == 3){ // Every # weeks by day disablerptfields(); enableweekdays(); document.eventform.rpt_weeks.disabled = false; $("#rpt_weeks").show(); donoenddate(); $(document.eventform.rpt_type.options[3]).text("Every..."); } else{ $(document.eventform.rpt_type.options[3]).text("Every # weeks"); } if (document.eventform.rpt_type.selectedIndex == 4) { // Monthly by day disablerptfields(); enableweekdays(); document.eventform.rpt_month_place.disabled = false; $("#rpt_month_place").show(); donoenddate(); } if (document.eventform.rpt_type.selectedIndex == 5) { // Monthly by date disablerptfields(); disableweekdays(); clearweekdays(); donoenddate(); } if (document.eventform.rpt_type.selectedIndex == 6) { // Yearly by date disablerptfields(); disableweekdays(); clearweekdays(); donoenddate(); } return; } // Additional Controls Context Function Called By docontrols // Disable repeat fields function disablerptfields() { document.eventform.rpt_weeks.disabled=true; $("#rpt_weeks").hide(); document.eventform.rpt_days.disabled=true; $("#rpt_days").hide(); document.eventform.rpt_month_place.disabled=true; $("#rpt_month_place").hide(); } // Enable repeat fields - for posting function enablerptfields() { document.eventform.rpt_weeks.disabled=false; $("#rpt_weeks").show(); document.eventform.rpt_days.disabled=false; $("#rpt_days").show(); document.eventform.rpt_month_place.disabled=false; $("#rpt_month_place").show(); } // Disable repeat date function disablerptdate() { document.eventform.rpt_end_day.disabled=true; document.eventform.rpt_end_month.disabled=true; document.eventform.rpt_end_year.disabled=true; $("#enddate").hide(); } // Enable repeat date function enablerptdate() { document.eventform.rpt_end_day.disabled=false; document.eventform.rpt_end_month.disabled=false; document.eventform.rpt_end_year.disabled=false; $("#enddate").show(); } //Disable weekdays function disableweekdays() { // Disable check boxes document.eventform.rpt_sun.disabled=true; document.eventform.rpt_mon.disabled=true; document.eventform.rpt_tue.disabled=true; document.eventform.rpt_wed.disabled=true; document.eventform.rpt_thu.disabled=true; document.eventform.rpt_fri.disabled=true; document.eventform.rpt_sat.disabled=true; $("#selectbydays").hide(); } // Enable weekdays function enableweekdays() { document.eventform.rpt_sun.disabled=false; document.eventform.rpt_mon.disabled=false; document.eventform.rpt_tue.disabled=false; document.eventform.rpt_wed.disabled=false; document.eventform.rpt_thu.disabled=false; document.eventform.rpt_fri.disabled=false; document.eventform.rpt_sat.disabled=false; $("#selectbydays").show(); } // Clear weekdays function clearweekdays () { document.eventform.rpt_sun.checked=false; document.eventform.rpt_mon.checked=false; document.eventform.rpt_tue.checked=false; document.eventform.rpt_wed.checked=false; document.eventform.rpt_thu.checked=false; document.eventform.rpt_fri.checked=false; document.eventform.rpt_sat.checked=false; } // Disable all repeat choices function disablerptchoices() { $("#repeat_disabled_note").show(); $("#rpt_type").removeClass("dropdown-small").addClass("dropdown-disabled").attr("disabled", true); } // Enable all repeat choices function enablerptchoices() { $("#repeat_disabled_note").hide(); $("#rpt_type").removeClass("dropdown-disabled").addClass("dropdown-small").attr("disabled", false); } // Process click on allday checkbox function doallday() { if (document.eventform.allday.checked) { document.eventform.noend.checked = false; disabletimes(); return; } else if (!document.eventform.noend.checked) { enabletimes(); return; } } // Process click on noend (time) checkbox function donoend() { if (document.eventform.noend.checked) { document.eventform.allday.checked = false; document.eventform.endhour.disabled = true; document.eventform.endminute.disabled = true; if (document.eventform.endampm) { document.eventform.endampm.disabled = true; } document.eventform.starthour.disabled = false; document.eventform.startminute.disabled = false; if (document.eventform.startampm) { document.eventform.startampm.disabled = false; } return; } else if (!document.eventform.allday.checked) { enabletimes(); return; } } // Process change to no end date checkbox function donoenddate() { // If editing single occurrence of repeating event if (document.eventform.edittype.value == "single") { document.eventform.rpt_noenddate.disabled = true; $("#noenddate").hide(); return; } // If yearly repeats not checked then disable if (document.eventform.rpt_type.selectedIndex != 6) { document.eventform.rpt_noenddate.checked = false; document.eventform.rpt_noenddate.disabled = true; $("#noenddate").hide(); } else { //yearly repeats is checked document.eventform.rpt_noenddate.disabled = false; $("#noenddate").show(); } if (document.eventform.rpt_noenddate.checked) { disablerptdate(); } else { enablerptdate(); } } function disabletimes() { document.eventform.starthour.disabled = true; document.eventform.startminute.disabled = true; if (document.eventform.startampm) { document.eventform.startampm.disabled = true; } document.eventform.endhour.disabled = true; document.eventform.endminute.disabled = true; if (document.eventform.endampm) { document.eventform.endampm.disabled = true; } } function enabletimes() { document.eventform.starthour.disabled = false; document.eventform.startminute.disabled = false; if (document.eventform.startampm) { document.eventform.startampm.disabled = false; } document.eventform.endhour.disabled = false; document.eventform.endminute.disabled = false; if (document.eventform.endampm) { document.eventform.endampm.disabled = false; } } endDateIsDirty = false; // Init, used by doDateSync function // Function to sync start and end dates when banners on function doDateSync(e) { var targetId = e.target.id; // Make sure start date is before End Date (single event or banner end date) var startday = Number(document.eventform.eday.value); var startmonth = Number(document.eventform.emonth.value); var startyear = Number(document.eventform.eyear.value); var starthour = Number(document.eventform.starthour.value); var startminute = Number(document.eventform.startminute.value); var endday = Number(document.eventform.end_eday.value); var endmonth = Number(document.eventform.end_emonth.value); var endyear = Number(document.eventform.end_eyear.value); var endhour = Number(document.eventform.endhour.value); var endminute = Number(document.eventform.endminute.value); var starttimestamp = new Date(startyear,startmonth,startday); var endtimestamp = new Date(endyear,endmonth,endday); if (starttimestamp != endtimestamp) { if ((targetId == 'eday') || (targetId == 'emonth') || (targetId == 'eyear')) { var startDateChanged = true; setNumDays('e'); } else if ((targetId == 'end_eday') || (targetId == 'end_emonth') || (targetId == 'end_eyear')) { var endDateChanged = true; endDateIsDirty = true; setNumDays('end_e'); } if ((startDateChanged) && (!endDateIsDirty)) { $("#end_eday").val(startday); $("#end_emonth").val(startmonth); $("#end_eyear").val(startyear); setNumDays('end_e'); return; } } } function weeksDaysUpdate(){ var weeks = $("#rpt_weeks").val(); if(weeks == "1"){ weeks = "week"; } else{ weeks = weeks + " weeks"; } $("#rpt_type option:eq(3)").text("Every " + weeks + " on these days"); var days = $("#rpt_days").val(); if(days == "2"){ days = "other day"; } else{ days = days + " days"; } $("#rpt_type option:eq(2)").text("Every " + days); } // END OF EDIT EVENT FORM CONTROLS // // BEGIN EDIT EVENT FORM VALIDATION FUNCTIONS // Utility function to display validation message function cwscroll (positionselector) { var offset = $(positionselector).offset(); $('html,body').animate({ scrollTop: offset.top - 100 }, { duration: 'slow', easing: 'swing'}); } // Validate edit event fields before saving function validate() { // -------------------------------------------------------- // Dates and Times Validation // -------------------------------------------------------- // Check text fields var value = $("#title").val(); if (value == "") { document.eventform.title.focus(); $.alert("Please enter an event Title", ""); return false; } // Check that category was selected var value = document.eventform.category_id.value; if (value == "0") { document.eventform.category_id.focus(); $.alert("Please select a Category", ""); return false; } var isMilitaryTime = !$("#startampm").is(":visible"); // If startam field visible then NOT military if (gbanners_on == '1') { // ----------- // BANNERS ON // ----------- // Get date and time vars var startday = Number(document.eventform.eday.value); var startmonth = Number(document.eventform.emonth.value); var startyear = Number(document.eventform.eyear.value); var starthour = Number(document.eventform.starthour.value); var startminute = Number(document.eventform.startminute.value); var endday = Number(document.eventform.end_eday.value); var endmonth = Number(document.eventform.end_emonth.value); var endyear = Number(document.eventform.end_eyear.value); var endhour = Number(document.eventform.endhour.value); var endminute = Number(document.eventform.endminute.value); if (!isMilitaryTime) { // If not military or 24 hour format // Need to convert to 24 hour format var startampm = document.eventform.startampm.value; var endampm = document.eventform.endampm.value; // Convert start hour to military time if ((startampm == "am") && (starthour == 12)) { starthour = starthour - 12; } else if ((startampm == "pm") && (starthour != 12)) { starthour = starthour + 12; } // Convert end hour to military time if ((endampm == "am") && (endhour == 12)) { endhour = endhour - 12; } else if ((endampm == "pm") && (endhour != 12)) { endhour = endhour + 12; } } else { var startampm = ""; var endampm = ""; } // Get just date timestamps not times var startdaytimestamp = new Date(startyear,startmonth,startday); var enddaytimestamp = new Date(endyear,endmonth,endday); // If overnight shift then make end on next day if ((starthour >= 12) && (endhour < 12)) { var tendstamp = enddaytimestamp.getTime() + (1 * 24 * 60 * 60 * 1000); enddaytimestamp.setTime(tendstamp); } // Make sure end date not before start date if (enddaytimestamp < startdaytimestamp) { cwscroll ("#eday"); $.alert("Start Date is after End Date",""); return false; } // Get number of days spanned var days_span = ((enddaytimestamp - startdaytimestamp) / 86400000) + 1; // Get days spanned by event if (days_span == 1) { // if not banner event if ((document.eventform.noend.checked == false) && (document.eventform.allday.checked == false)) { // Not banner and not allday or not end so need to check event times // Get start and end timestamps including times var starttimetimestamp = new Date(startyear,startmonth,startday,starthour,startminute); var endtimetimestamp = new Date(endyear,endmonth,endday,endhour,endminute); // Make sure single day / non banner event start time not equal or after end time if (endtimetimestamp <= starttimetimestamp) { cwscroll ("#starthour"); $.alert("Start Time is same or after End Time",""); return false; } } } else { // If banner event // Is banner event so check not exceeding maximum days span // Check the date range, 86400000 is the number of milliseconds in one day var ban_days_back = ""; if (days_span > ban_days_back) { cwscroll ("#eyear"); $.alert("Individual events cannot span more than " + ban_days_back + " days",""); return false; } } } else { // BANNERS OFF // Check event start time is before end time on a day // Modified to skip pm to am event times to allow // events starting at say 11:00pm and ending at 2:00am // the next day. veday = Number(document.eventform.eday.value); vemonth = Number(document.eventform.emonth.value) - 1; // Months are 0-11 in javascript veyear = Number(document.eventform.eyear.value); vstarthour = Number(document.eventform.starthour.value); vstartminute = Number(document.eventform.startminute.value); vendhour = Number(document.eventform.endhour.value); vendminute = Number(document.eventform.endminute.value); if (!isMilitaryTime) { vstartampm = document.eventform.startampm.value; vendampm = document.eventform.endampm.value; // Convert start hour to military time if ((vstartampm == "am") && (vstarthour == 12)) { vstarthour = vstarthour - 12; } else if ((vstartampm == "pm") && (vstarthour != 12)) { vstarthour = vstarthour + 12; } // Convert end hour to military time if ((vendampm == "am") && (vendhour == 12)) { vendhour = vendhour - 12; } else if ((vendampm == "pm") && (vendhour != 12)) { vendhour = vendhour + 12; } } vstartstamp = new Date(veyear,vemonth,veday,vstarthour,vstartminute,0); vendstamp = new Date(veyear,vemonth,veday,vendhour,vendminute,0); // If overnight shift then make end on next day if ((vstarthour >= 12) && (vendhour < 12)) { var tendstamp = vendstamp.getTime(); tendstamp = tendstamp + (1 * 24 * 60 * 60 * 1000); vendstamp.setTime(tendstamp); } if ((document.eventform.noend.checked == false) && (document.eventform.allday.checked == false)) { // Skip if no end time or allday if (vstartstamp.getTime() >= vendstamp.getTime()) { $.alert("Start Time is equal to or after End Time",""); return false; } } } // If repeating and not editing single occurrence, check start date is before end date if ((!document.eventform.rpt_type.selectedIndex == 0) && (document.eventform.edittype.value != "single") && (!document.eventform.rpt_noenddate.checked)) { var startday = Number(document.eventform.eday.value); var startmonth = Number(document.eventform.emonth.value) - 1; var startyear = Number(document.eventform.eyear.value); var starthour = Number(document.eventform.starthour.value); var startminute = Number(document.eventform.startminute.value); var rptendday = Number(document.eventform.rpt_end_day.value); var rptendmonth = Number(document.eventform.rpt_end_month.value) - 1; var rptendyear = Number(document.eventform.rpt_end_year.value); var endhour = Number(document.eventform.endhour.value); var endminute = Number(document.eventform.endminute.value); var starttimestamp = new Date(startyear,startmonth,startday); var rptendtimestamp = new Date(rptendyear,rptendmonth,rptendday); if (starttimestamp >= rptendtimestamp) { $.alert("Start Date is equal to or later than Repeat End Date",""); return false; } } // For applicable options, maker sure day of week(s) are checked if ((document.eventform.rpt_type.selectedIndex == 3) || (document.eventform.rpt_type.selectedIndex == 4)) { var nd = 0; if (document.eventform.rpt_sun.checked) { nd++; } if (document.eventform.rpt_mon.checked) { nd++; } if (document.eventform.rpt_tue.checked) { nd++; } if (document.eventform.rpt_wed.checked) { nd++; } if (document.eventform.rpt_thu.checked) { nd++; } if (document.eventform.rpt_fri.checked) { nd++; } if (document.eventform.rpt_sat.checked) { nd++; } if (nd == 0) { $.alert("Please select days of week to complete repeating event",""); return false; } } return true; } // END OF EDIT EVENT FORM VALIDATION /** * Determine the mobile operating system. * This function returns one of 'iOS', 'Android', 'Windows Phone', or 'unknown'. * * @returns {String} */ function getMobileOperatingSystem() { var userAgent = navigator.userAgent || navigator.vendor || window.opera; // Windows Phone must come first because its UA also contains "Android" if (/windows phone/i.test(userAgent)) { return "Windows Phone"; } if (/android/i.test(userAgent)) { return "Android"; } // iOS detection from: http://stackoverflow.com/a/9039885/177710 if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) { return "iOS"; } return "unknown"; } // Ulility function to change newlines to
function nl2br (str, is_xhtml) { var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '
' : '
'; return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2'); } // A call to this function is in commonAjaxCallback() NOW COMMENTED OUT OF COMMONAJAXCALLBACK // just after gLoggedIn is assigned. function showPopup() { if (gLoggedIn && readCookie("cw_mobile_pop_dismissed") != "true") { $("#popup_message").fadeIn("slow"); } } function dismissPopup() { $("#popup_message").fadeOut(); createCookie("cw_mobile_pop_dismissed", "true",1000); } // As last resort puts debug text into div at bottom of page function debug(txt){ $("#debug").text($("#debug").text() + " " + txt); } /* * Date Format 1.2.3 * (c) 2007-2009 Steven Levithan * MIT license * * Includes enhancements by Scott Trenda * and Kris Kowal * * Accepts a date, a mask, or a date and a mask. * Returns a formatted version of the given date. * The date defaults to the current date/time. * The mask defaults to dateFormat.masks.default. */ function pad(val, len) { val = String(val); len = len || 2; while (val.length < len) val = "0" + val; return val; }; var dateFormat = function () { var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, timezoneClip = /[^-+\dA-Z]/g; // Regexes and supporting functions are cached through closure return function (date, mask, utc) { var dF = dateFormat; // You can't provide utc if you skip other args (use the "UTC:" mask prefix) if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { mask = date; date = undefined; } // Passing date through Date applies Date.parse, if necessary date = date ? new Date(date) : new Date; if (isNaN(date)) throw SyntaxError("invalid date"); mask = String(dF.masks[mask] || mask || dF.masks["default"]); // Allow setting the utc argument via the mask if (mask.slice(0, 4) == "UTC:") { mask = mask.slice(4); utc = true; } var _ = utc ? "getUTC" : "get", d = date[_ + "Date"](), D = date[_ + "Day"](), m = date[_ + "Month"](), y = date[_ + "FullYear"](), H = date[_ + "Hours"](), M = date[_ + "Minutes"](), s = date[_ + "Seconds"](), L = date[_ + "Milliseconds"](), o = utc ? 0 : date.getTimezoneOffset(), flags = { d: d, dd: pad(d), ddd: dF.i18n.dayNames[D], dddd: dF.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: dF.i18n.monthNames[m], mmmm: dF.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, h: H % 12 || 12, hh: pad(H % 12 || 12), H: H, HH: pad(H), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; return mask.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; }(); // Some common format strings dateFormat.masks = { "default": "ddd mmm dd yyyy HH:MM:ss", shortDate: "m/d/yy", mediumDate: "mmm d, yyyy", longDate: "mmmm d, yyyy", fullDate: "dddd, mmmm d, yyyy", shortTime: "h:MM TT", mediumTime: "h:MM:ss TT", longTime: "h:MM:ss TT Z", isoDate: "yyyy-mm-dd", isoTime: "HH:MM:ss", isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; // Internationalization strings dateFormat.i18n = { dayNames: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], monthNames: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ] }; dateFormat.daysInMonth = [0,31,28,31,30,31,30,31,31,30,31,30,31]; // For convenience... Date.prototype.format = function (mask, utc) { return dateFormat(this, mask, utc); }; // END OF Date Format 1.2.3 /** * jQuery Plugin to obtain touch gestures from iPhone, iPod Touch and iPad, should also work with Android mobile phones (not tested yet!) * Common usage: wipe images (left and right to show the previous or next image) * * @author Andreas Waltl, netCU Internetagentur (http://www.netcu.de) * @version 1.1.1 (9th December 2010) - fix bug (older IE's had problems) * @version 1.1 (1st September 2010) - support wipe up and wipe down * @version 1.0 (15th July 2010) * THIS MODIFIED BY DWM 161031 TO FIX INCORRECT SWIPE RIGHT WHEN DAY VIEW WITH * LONG LIST OF EVENTS WHEN SLIGHT DIAGONAL IN SWIPE DOWN CAUSING SWIPE ON X AXIS */ (function($) { $.fn.touchwipe = function(settings) { var config = { min_move_x: 75, min_move_y: 75, wipeLeft: function() { }, wipeRight: function() { }, wipeUp: function() { }, wipeDown: function() { }, preventDefaultEvents: true }; if (settings) $.extend(config, settings); this.each(function() { var startX; var startY; var isMoving = false; var wasWipe = false; var target; function cancelTouch() { this.removeEventListener('touchmove', onTouchMove); isMoving = false; wasWipe = true; } function wipeX(dx) { wasWipe = true; cancelTouch(); if(dx > 0) { config.wipeLeft(); } else { config.wipeRight(); } } function wipeY(dy) { wasWipe = true; cancelTouch(); if(dy > 0) { config.wipeDown(); } else { config.wipeUp(); } } function onTouchMove(e) { if(config.preventDefaultEvents) { e.preventDefault(); } if(isMoving) { var x = e.touches[0].pageX; var y = e.touches[0].clientY; var dx = startX - x; var dy = startY - y; var dxabs = Math.abs(dx); var dyabs = Math.abs(dy); if (dxabs >= config.min_move_x) { var dxmax = true; } else { var dxmax = false; } if (dyabs >= config.min_move_y) { var dymax = true; } else { var dymax = false; } if ((dxmax) && (dymax)) { if (dxabs > dyabs) { wipeX(dx); } else { wipeY(dy); } } else if (dxmax) { wipeX(dx); } else if (dymax) { wipeY(dy); } } } function onTouchEnd(e){ if(!wasWipe){ config.click({target:target}); } this.removeEventListener('touchend', onTouchEnd); } function onTouchStart(e) { if (e.touches.length == 1) { startX = e.touches[0].pageX; startY = e.touches[0].clientY; target = e.touches[0].target; isMoving = true; wasWipe = false; this.addEventListener('touchmove', onTouchMove, false); if(config.click){ this.addEventListener('touchend', onTouchEnd, false); } } } if ('ontouchstart' in document.documentElement) { this.addEventListener('touchstart', onTouchStart, false); } }); // END OF jQuery Plugin to obtain touch gestures // Detects focus and blur on form fields and corrects visibility // issues with navigtion bars - maybe only needed for iOS if(/ipad|iphone|ipod/i.test(navigator.userAgent.toLowerCase())) { $(document).on('focus', 'input, textarea, select', function() { $(".action_row").hide(); }); $(document).on('blur', 'input, textarea, select', function() { if ($("#loginform").is(':hidden')) { // login form does not have action_row display_action_row(); } }); } return this; }; })(jQuery); // Include email validaton script // email-addresses.js - RFC 5322 email address parser // v 3.0.1 // From: https://github.com/jackbearheart/email-addresses // // http://tools.ietf.org/html/rfc5322 // // This library does not validate email addresses. // emailAddresses attempts to parse addresses using the (fairly liberal) // grammar specified in RFC 5322. // // email-addresses returns { // ast: , // addresses: [{ // node: , // name: , // address: , // local: , // domain: // }, ...] // } // // emailAddresses.parseOneAddress and emailAddresses.parseAddressList // work as you might expect. Try it out. // // Many thanks to Dominic Sayers and his documentation on the is_email function, // http://code.google.com/p/isemail/ , which helped greatly in writing this parser. function checkemailaddress(emailstr) { if (emailstr == '') { return false; } // Get parts of email address emailobj = emailAddresses.parseOneAddress(emailstr); //emailobj = MyCwCal.emailAddresses.parseOneAddress(emailstr) //emailobj = this.emailAddresses.parseOneAddress(emailstr); if (emailobj && emailobj !== 'null' && emailobj !== 'undefined') { nodisplaynameemailstr = emailobj.address; } else { nodisplaynameemailstr = 'invalid'; } // Check for correct email address format var filter = /^([a-zA-Z0-9_+'\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; if (!filter.test(nodisplaynameemailstr)) { return false; } else { return true; } } (function (global) { "use strict"; function parse5322(opts) { // tokenizing functions function inStr() { return pos < len; } function curTok() { return parseString[pos]; } function getPos() { return pos; } function setPos(i) { pos = i; } function nextTok() { pos += 1; } function initialize() { pos = 0; len = parseString.length; } // parser helper functions function o(name, value) { return { name: name, tokens: value || "", semantic: value || "", children: [] }; } function wrap(name, ast) { var n; if (ast === null) { return null; } n = o(name); n.tokens = ast.tokens; n.semantic = ast.semantic; n.children.push(ast); return n; } function add(parent, child) { if (child !== null) { parent.tokens += child.tokens; parent.semantic += child.semantic; } parent.children.push(child); return parent; } function compareToken(fxnCompare) { var tok; if (!inStr()) { return null; } tok = curTok(); if (fxnCompare(tok)) { nextTok(); return o('token', tok); } return null; } function literal(lit) { return function literalFunc() { return wrap('literal', compareToken(function (tok) { return tok === lit; })); }; } function and() { var args = arguments; return function andFunc() { var i, s, result, start; start = getPos(); s = o('and'); for (i = 0; i < args.length; i += 1) { result = args[i](); if (result === null) { setPos(start); return null; } add(s, result); } return s; }; } function or() { var args = arguments; return function orFunc() { var i, result, start; start = getPos(); for (i = 0; i < args.length; i += 1) { result = args[i](); if (result !== null) { return result; } setPos(start); } return null; }; } function opt(prod) { return function optFunc() { var result, start; start = getPos(); result = prod(); if (result !== null) { return result; } else { setPos(start); return o('opt'); } }; } function invis(prod) { return function invisFunc() { var result = prod(); if (result !== null) { result.semantic = ""; } return result; }; } function colwsp(prod) { return function collapseSemanticWhitespace() { var result = prod(); if (result !== null && result.semantic.length > 0) { result.semantic = " "; } return result; }; } function star(prod, minimum) { return function starFunc() { var s, result, count, start, min; start = getPos(); s = o('star'); count = 0; min = minimum === undefined ? 0 : minimum; while ((result = prod()) !== null) { count = count + 1; add(s, result); } if (count >= min) { return s; } else { setPos(start); return null; } }; } // One expects names to get normalized like this: // " First Last " -> "First Last" // "First Last" -> "First Last" // "First Last" -> "First Last" function collapseWhitespace(s) { return s.replace(/([ \t]|\r\n)+/g, ' ').replace(/^\s*/, '').replace(/\s*$/, ''); } // UTF-8 pseudo-production (RFC 6532) // RFC 6532 extends RFC 5322 productions to include UTF-8 // using the following productions: // UTF8-non-ascii = UTF8-2 / UTF8-3 / UTF8-4 // UTF8-2 = // UTF8-3 = // UTF8-4 = // // For reference, the extended RFC 5322 productions are: // VCHAR =/ UTF8-non-ascii // ctext =/ UTF8-non-ascii // atext =/ UTF8-non-ascii // qtext =/ UTF8-non-ascii // dtext =/ UTF8-non-ascii function isUTF8NonAscii(tok) { // In JavaScript, we just deal directly with Unicode code points, // so we aren't checking individual bytes for UTF-8 encoding. // Just check that the character is non-ascii. return tok.charCodeAt(0) >= 128; } // common productions (RFC 5234) // http://tools.ietf.org/html/rfc5234 // B.1. Core Rules // CR = %x0D // ; carriage return function cr() { return wrap('cr', literal('\r')()); } // CRLF = CR LF // ; Internet standard newline function crlf() { return wrap('crlf', and(cr, lf)()); } // DQUOTE = %x22 // ; " (Double Quote) function dquote() { return wrap('dquote', literal('"')()); } // HTAB = %x09 // ; horizontal tab function htab() { return wrap('htab', literal('\t')()); } // LF = %x0A // ; linefeed function lf() { return wrap('lf', literal('\n')()); } // SP = %x20 function sp() { return wrap('sp', literal(' ')()); } // VCHAR = %x21-7E // ; visible (printing) characters function vchar() { return wrap('vchar', compareToken(function vcharFunc(tok) { var code = tok.charCodeAt(0); var accept = (0x21 <= code && code <= 0x7E); if (opts.rfc6532) { accept = accept || isUTF8NonAscii(tok); } return accept; })); } // WSP = SP / HTAB // ; white space function wsp() { return wrap('wsp', or(sp, htab)()); } // email productions (RFC 5322) // http://tools.ietf.org/html/rfc5322 // 3.2.1. Quoted characters // quoted-pair = ("\" (VCHAR / WSP)) / obs-qp function quotedPair() { var qp = wrap('quoted-pair', or( and(literal('\\'), or(vchar, wsp)), obsQP )()); if (qp === null) { return null; } // a quoted pair will be two characters, and the "\" character // should be semantically "invisible" (RFC 5322 3.2.1) qp.semantic = qp.semantic[1]; return qp; } // 3.2.2. Folding White Space and Comments // FWS = ([*WSP CRLF] 1*WSP) / obs-FWS function fws() { return wrap('fws', or( obsFws, and( opt(and( star(wsp), invis(crlf) )), star(wsp, 1) ) )()); } // ctext = %d33-39 / ; Printable US-ASCII // %d42-91 / ; characters not including // %d93-126 / ; "(", ")", or "\" // obs-ctext function ctext() { return wrap('ctext', or( function ctextFunc1() { return compareToken(function ctextFunc2(tok) { var code = tok.charCodeAt(0); var accept = (33 <= code && code <= 39) || (42 <= code && code <= 91) || (93 <= code && code <= 126); if (opts.rfc6532) { accept = accept || isUTF8NonAscii(tok); } return accept; }); }, obsCtext )()); } // ccontent = ctext / quoted-pair / comment function ccontent() { return wrap('ccontent', or(ctext, quotedPair, comment)()); } // comment = "(" *([FWS] ccontent) [FWS] ")" function comment() { return wrap('comment', and( literal('('), star(and(opt(fws), ccontent)), opt(fws), literal(')') )()); } // CFWS = (1*([FWS] comment) [FWS]) / FWS function cfws() { return wrap('cfws', or( and( star( and(opt(fws), comment), 1 ), opt(fws) ), fws )()); } // 3.2.3. Atom //atext = ALPHA / DIGIT / ; Printable US-ASCII // "!" / "#" / ; characters not including // "$" / "%" / ; specials. Used for atoms. // "&" / "'" / // "*" / "+" / // "-" / "/" / // "=" / "?" / // "^" / "_" / // "`" / "{" / // "|" / "}" / // "~" function atext() { return wrap('atext', compareToken(function atextFunc(tok) { var accept = ('a' <= tok && tok <= 'z') || ('A' <= tok && tok <= 'Z') || ('0' <= tok && tok <= '9') || (['!', '#', '$', '%', '&', '\'', '*', '+', '-', '/', '=', '?', '^', '_', '`', '{', '|', '}', '~'].indexOf(tok) >= 0); if (opts.rfc6532) { accept = accept || isUTF8NonAscii(tok); } return accept; })); } // atom = [CFWS] 1*atext [CFWS] function atom() { return wrap('atom', and(colwsp(opt(cfws)), star(atext, 1), colwsp(opt(cfws)))()); } // dot-atom-text = 1*atext *("." 1*atext) function dotAtomText() { var s, maybeText; s = wrap('dot-atom-text', star(atext, 1)()); if (s === null) { return s; } maybeText = star(and(literal('.'), star(atext, 1)))(); if (maybeText !== null) { add(s, maybeText); } return s; } // dot-atom = [CFWS] dot-atom-text [CFWS] function dotAtom() { return wrap('dot-atom', and(invis(opt(cfws)), dotAtomText, invis(opt(cfws)))()); } // 3.2.4. Quoted Strings // qtext = %d33 / ; Printable US-ASCII // %d35-91 / ; characters not including // %d93-126 / ; "\" or the quote character // obs-qtext function qtext() { return wrap('qtext', or( function qtextFunc1() { return compareToken(function qtextFunc2(tok) { var code = tok.charCodeAt(0); var accept = (33 === code) || (35 <= code && code <= 91) || (93 <= code && code <= 126); if (opts.rfc6532) { accept = accept || isUTF8NonAscii(tok); } return accept; }); }, obsQtext )()); } // qcontent = qtext / quoted-pair function qcontent() { return wrap('qcontent', or(qtext, quotedPair)()); } // quoted-string = [CFWS] // DQUOTE *([FWS] qcontent) [FWS] DQUOTE // [CFWS] function quotedString() { return wrap('quoted-string', and( invis(opt(cfws)), invis(dquote), star(and(opt(colwsp(fws)), qcontent)), opt(invis(fws)), invis(dquote), invis(opt(cfws)) )()); } // 3.2.5 Miscellaneous Tokens // word = atom / quoted-string function word() { return wrap('word', or(atom, quotedString)()); } // phrase = 1*word / obs-phrase function phrase() { return wrap('phrase', or(obsPhrase, star(word, 1))()); } // 3.4. Address Specification // address = mailbox / group function address() { return wrap('address', or(mailbox, group)()); } // mailbox = name-addr / addr-spec function mailbox() { return wrap('mailbox', or(nameAddr, addrSpec)()); } // name-addr = [display-name] angle-addr function nameAddr() { return wrap('name-addr', and(opt(displayName), angleAddr)()); } // angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / // obs-angle-addr function angleAddr() { return wrap('angle-addr', or( and( invis(opt(cfws)), literal('<'), addrSpec, literal('>'), invis(opt(cfws)) ), obsAngleAddr )()); } // group = display-name ":" [group-list] ";" [CFWS] function group() { return wrap('group', and( displayName, literal(':'), opt(groupList), literal(';'), invis(opt(cfws)) )()); } // display-name = phrase function displayName() { return wrap('display-name', function phraseFixedSemantic() { var result = phrase(); if (result !== null) { result.semantic = collapseWhitespace(result.semantic); } return result; }()); } // mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list function mailboxList() { return wrap('mailbox-list', or( and( mailbox, star(and(literal(','), mailbox)) ), obsMboxList )()); } // address-list = (address *("," address)) / obs-addr-list function addressList() { return wrap('address-list', or( and( address, star(and(literal(','), address)) ), obsAddrList )()); } // group-list = mailbox-list / CFWS / obs-group-list function groupList() { return wrap('group-list', or( mailboxList, invis(cfws), obsGroupList )()); } // 3.4.1 Addr-Spec Specification // local-part = dot-atom / quoted-string / obs-local-part function localPart() { // note: quoted-string, dotAtom are proper subsets of obs-local-part // so we really just have to look for obsLocalPart, if we don't care about the exact parse tree return wrap('local-part', or(obsLocalPart, dotAtom, quotedString)()); } // dtext = %d33-90 / ; Printable US-ASCII // %d94-126 / ; characters not including // obs-dtext ; "[", "]", or "\" function dtext() { return wrap('dtext', or( function dtextFunc1() { return compareToken(function dtextFunc2(tok) { var code = tok.charCodeAt(0); var accept = (33 <= code && code <= 90) || (94 <= code && code <= 126); if (opts.rfc6532) { accept = accept || isUTF8NonAscii(tok); } return accept; }); }, obsDtext )() ); } // domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS] function domainLiteral() { return wrap('domain-literal', and( invis(opt(cfws)), literal('['), star(and(opt(fws), dtext)), opt(fws), literal(']'), invis(opt(cfws)) )()); } // domain = dot-atom / domain-literal / obs-domain function domain() { return wrap('domain', function domainCheckTLD() { var result = or(obsDomain, dotAtom, domainLiteral)(); if (opts.rejectTLD) { if (result && result.semantic && result.semantic.indexOf('.') < 0) { return null; } } // strip all whitespace from domains if (result) { result.semantic = result.semantic.replace(/\s+/g, ''); } return result; }()); } // addr-spec = local-part "@" domain function addrSpec() { return wrap('addr-spec', and( localPart, literal('@'), domain )()); } // 3.6.2 Originator Fields // Below we only parse the field body, not the name of the field // like "From:", "Sender:", or "Reply-To:". Other libraries that // parse email headers can parse those and defer to these productions // for the "RFC 5322" part. // RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields // from = "From:" (mailbox-list / address-list) CRLF function fromSpec() { return wrap('from', or( mailboxList, addressList )()); } // RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields // sender = "Sender:" (mailbox / address) CRLF function senderSpec() { return wrap('sender', or( mailbox, address )()); } // RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields // reply-to = "Reply-To:" address-list CRLF function replyToSpec() { return wrap('reply-to', addressList()); } // 4.1. Miscellaneous Obsolete Tokens // obs-NO-WS-CTL = %d1-8 / ; US-ASCII control // %d11 / ; characters that do not // %d12 / ; include the carriage // %d14-31 / ; return, line feed, and // %d127 ; white space characters function obsNoWsCtl() { return opts.strict ? null : wrap('obs-NO-WS-CTL', compareToken(function (tok) { var code = tok.charCodeAt(0); return ((1 <= code && code <= 8) || (11 === code || 12 === code) || (14 <= code && code <= 31) || (127 === code)); })); } // obs-ctext = obs-NO-WS-CTL function obsCtext() { return opts.strict ? null : wrap('obs-ctext', obsNoWsCtl()); } // obs-qtext = obs-NO-WS-CTL function obsQtext() { return opts.strict ? null : wrap('obs-qtext', obsNoWsCtl()); } // obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR) function obsQP() { return opts.strict ? null : wrap('obs-qp', and( literal('\\'), or(literal('\0'), obsNoWsCtl, lf, cr) )()); } // obs-phrase = word *(word / "." / CFWS) function obsPhrase() { return opts.strict ? null : wrap('obs-phrase', and( word, star(or(word, literal('.'), colwsp(cfws))) )()); } // 4.2. Obsolete Folding White Space // NOTE: read the errata http://www.rfc-editor.org/errata_search.php?rfc=5322&eid=1908 // obs-FWS = 1*([CRLF] WSP) function obsFws() { return opts.strict ? null : wrap('obs-FWS', star( and(invis(opt(crlf)), wsp), 1 )()); } // 4.4. Obsolete Addressing // obs-angle-addr = [CFWS] "<" obs-route addr-spec ">" [CFWS] function obsAngleAddr() { return opts.strict ? null : wrap('obs-angle-addr', and( invis(opt(cfws)), literal('<'), obsRoute, addrSpec, literal('>'), invis(opt(cfws)) )()); } // obs-route = obs-domain-list ":" function obsRoute() { return opts.strict ? null : wrap('obs-route', and( obsDomainList, literal(':') )()); } // obs-domain-list = *(CFWS / ",") "@" domain // *("," [CFWS] ["@" domain]) function obsDomainList() { return opts.strict ? null : wrap('obs-domain-list', and( star(or(invis(cfws), literal(','))), literal('@'), domain, star(and( literal(','), invis(opt(cfws)), opt(and(literal('@'), domain)) )) )()); } // obs-mbox-list = *([CFWS] ",") mailbox *("," [mailbox / CFWS]) function obsMboxList() { return opts.strict ? null : wrap('obs-mbox-list', and( star(and( invis(opt(cfws)), literal(',') )), mailbox, star(and( literal(','), opt(and( mailbox, invis(cfws) )) )) )()); } // obs-addr-list = *([CFWS] ",") address *("," [address / CFWS]) function obsAddrList() { return opts.strict ? null : wrap('obs-addr-list', and( star(and( invis(opt(cfws)), literal(',') )), address, star(and( literal(','), opt(and( address, invis(cfws) )) )) )()); } // obs-group-list = 1*([CFWS] ",") [CFWS] function obsGroupList() { return opts.strict ? null : wrap('obs-group-list', and( star(and( invis(opt(cfws)), literal(',') ), 1), invis(opt(cfws)) )()); } // obs-local-part = word *("." word) function obsLocalPart() { return opts.strict ? null : wrap('obs-local-part', and(word, star(and(literal('.'), word)))()); } // obs-domain = atom *("." atom) function obsDomain() { return opts.strict ? null : wrap('obs-domain', and(atom, star(and(literal('.'), atom)))()); } // obs-dtext = obs-NO-WS-CTL / quoted-pair function obsDtext() { return opts.strict ? null : wrap('obs-dtext', or(obsNoWsCtl, quotedPair)()); } ///////////////////////////////////////////////////// // ast analysis function findNode(name, root) { var i, stack, node; if (root === null || root === undefined) { return null; } stack = [root]; while (stack.length > 0) { node = stack.pop(); if (node.name === name) { return node; } for (i = node.children.length - 1; i >= 0; i -= 1) { stack.push(node.children[i]); } } return null; } function findAllNodes(name, root) { var i, stack, node, result; if (root === null || root === undefined) { return null; } stack = [root]; result = []; while (stack.length > 0) { node = stack.pop(); if (node.name === name) { result.push(node); } for (i = node.children.length - 1; i >= 0; i -= 1) { stack.push(node.children[i]); } } return result; } function findAllNodesNoChildren(names, root) { var i, stack, node, result, namesLookup; if (root === null || root === undefined) { return null; } stack = [root]; result = []; namesLookup = {}; for (i = 0; i < names.length; i += 1) { namesLookup[names[i]] = true; } while (stack.length > 0) { node = stack.pop(); if (node.name in namesLookup) { result.push(node); // don't look at children (hence findAllNodesNoChildren) } else { for (i = node.children.length - 1; i >= 0; i -= 1) { stack.push(node.children[i]); } } } return result; } function giveResult(ast) { var addresses, groupsAndMailboxes, i, groupOrMailbox, result; if (ast === null) { return null; } addresses = []; // An address is a 'group' (i.e. a list of mailboxes) or a 'mailbox'. groupsAndMailboxes = findAllNodesNoChildren(['group', 'mailbox'], ast); for (i = 0; i < groupsAndMailboxes.length; i += 1) { groupOrMailbox = groupsAndMailboxes[i]; if (groupOrMailbox.name === 'group') { addresses.push(giveResultGroup(groupOrMailbox)); } else if (groupOrMailbox.name === 'mailbox') { addresses.push(giveResultMailbox(groupOrMailbox)); } } result = { ast: ast, addresses: addresses, }; if (opts.simple) { result = simplifyResult(result); } if (opts.oneResult) { return oneResult(result); } if (opts.simple) { return result && result.addresses; } else { return result; } } function giveResultGroup(group) { var i; var groupName = findNode('display-name', group); var groupResultMailboxes = []; var mailboxes = findAllNodesNoChildren(['mailbox'], group); for (i = 0; i < mailboxes.length; i += 1) { groupResultMailboxes.push(giveResultMailbox(mailboxes[i])); } return { node: group, parts: { name: groupName, }, type: group.name, // 'group' name: grabSemantic(groupName), addresses: groupResultMailboxes, }; } function giveResultMailbox(mailbox) { var name = findNode('display-name', mailbox); var aspec = findNode('addr-spec', mailbox); var comments = findAllNodes('cfws', mailbox); var local = findNode('local-part', aspec); var domain = findNode('domain', aspec); return { node: mailbox, parts: { name: name, address: aspec, local: local, domain: domain, comments: comments }, type: mailbox.name, // 'mailbox' name: grabSemantic(name), address: grabSemantic(aspec), local: grabSemantic(local), domain: grabSemantic(domain), groupName: grabSemantic(mailbox.groupName), }; } function grabSemantic(n) { return n !== null && n !== undefined ? n.semantic : null; } function simplifyResult(result) { var i; if (result && result.addresses) { for (i = 0; i < result.addresses.length; i += 1) { delete result.addresses[i].node; } } return result; } function oneResult(result) { if (!result) { return null; } if (!opts.partial && result.addresses.length > 1) { return null; } return result.addresses && result.addresses[0]; } ///////////////////////////////////////////////////// var parseString, pos, len, parsed, startProduction; opts = handleOpts(opts, {}); if (opts === null) { return null; } parseString = opts.input; startProduction = { 'address': address, 'address-list': addressList, 'angle-addr': angleAddr, 'from': fromSpec, 'group': group, 'mailbox': mailbox, 'mailbox-list': mailboxList, 'reply-to': replyToSpec, 'sender': senderSpec, }[opts.startAt] || addressList; if (!opts.strict) { initialize(); opts.strict = true; parsed = startProduction(parseString); if (opts.partial || !inStr()) { return giveResult(parsed); } opts.strict = false; } initialize(); parsed = startProduction(parseString); if (!opts.partial && inStr()) { return null; } return giveResult(parsed); } /* function checkemailaddress(emailstr) { if (emailstr == '') { return false; } // Get parts of email address emailobj = emailAddresses.parseOneAddress(emailstr); //emailobj = MyCwCal.emailAddresses.parseOneAddress(emailstr) //emailobj = this.emailAddresses.parseOneAddress(emailstr); if (emailobj && emailobj !== 'null' && emailobj !== 'undefined') { nodisplaynameemailstr = emailobj.address; } else { nodisplaynameemailstr = 'invalid'; } // Check for correct rsvp email address format var filter = /^([a-zA-Z0-9_+'\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; if (!filter.test(nodisplaynameemailstr)) { return false; } else { return true; } } */ function parseOneAddressSimple(opts) { return parse5322(handleOpts(opts, { oneResult: true, rfc6532: true, simple: true, startAt: 'address-list', })); } function parseAddressListSimple(opts) { return parse5322(handleOpts(opts, { rfc6532: true, simple: true, startAt: 'address-list', })); } function parseFromSimple(opts) { return parse5322(handleOpts(opts, { rfc6532: true, simple: true, startAt: 'from', })); } function parseSenderSimple(opts) { return parse5322(handleOpts(opts, { oneResult: true, rfc6532: true, simple: true, startAt: 'sender', })); } function parseReplyToSimple(opts) { return parse5322(handleOpts(opts, { rfc6532: true, simple: true, startAt: 'reply-to', })); } function handleOpts(opts, defs) { function isString(str) { return Object.prototype.toString.call(str) === '[object String]'; } function isObject(o) { return o === Object(o); } function isNullUndef(o) { return o === null || o === undefined; } var defaults, o; if (isString(opts)) { opts = { input: opts }; } else if (!isObject(opts)) { return null; } if (!isString(opts.input)) { return null; } if (!defs) { return null; } defaults = { oneResult: false, partial: false, rejectTLD: false, rfc6532: false, simple: false, startAt: 'address-list', strict: false, }; for (o in defaults) { if (isNullUndef(opts[o])) { opts[o] = !isNullUndef(defs[o]) ? defs[o] : defaults[o]; } } return opts; } parse5322.parseOneAddress = parseOneAddressSimple; parse5322.parseAddressList = parseAddressListSimple; parse5322.parseFrom = parseFromSimple; parse5322.parseSender = parseSenderSimple; parse5322.parseReplyTo = parseReplyToSimple; if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { module.exports = parse5322; } else { global.emailAddresses = parse5322; } }(this)); $(init);