// swad.js: javascript functions /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. Copyright (C) 1999-2015 Antonio Caņas-Vargas University of Granada (SPAIN) (acanas@ugr.es) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Global variable (string) used to write HTML var Gbl_HTMLContent; // Global variable used in refreshConnected() var ActionAJAX; // Global variables used in writeLocalClock() var secondsSince1970UTC; // Global variables used in writeClockConnected() var NumUsrsCon; var ListSeconds = []; var countClockConnected = 0; /****************** Write a date in client local time ************************/ //id is the id of the HTML element in which date will be written //TimeUTC is the date-time to write in UTC UNIX time format function writeLocalDateFromUTC(id,TimeUTC) { var d = new Date; var Yea; var Mon; var Day; var StrMon; var StrDay; d.setTime(TimeUTC * 1000); Yea = d.getFullYear(); Mon = d.getMonth() + 1; Day = d.getDate(); StrMon = ((Mon < 10) ? '0' : '') + Mon; StrDay = ((Day < 10) ? '0' : '') + Day; document.getElementById(id).innerHTML = Yea + '-' + StrMon + '-' + StrDay; } /*************** Write a date-time in client local time **********************/ // id is the id of the HTML element in which date-time will be written // TimeUTC is the date-time to write in UTC UNIX time format // separator is HTML code to write between date and time function writeLocalDateTimeFromUTC(id,TimeUTC,separator,StrToday) { var today = new (Date); var todayYea = today.getFullYear(); var todayMon = today.getMonth()+1; var todayDay = today.getDate(); var d = new Date; var Yea; var Mon; var Day; var Hou; var Min; var Sec; var StrMon; var StrDay; var StrHou; var StrMin; var StrSec; d.setTime(TimeUTC * 1000); Yea = d.getFullYear(); Mon = d.getMonth() + 1; Day = d.getDate(); Hou = d.getHours(); Min = d.getMinutes(); Sec = d.getSeconds(); StrMon = ((Mon < 10) ? '0' : '') + Mon; StrDay = ((Day < 10) ? '0' : '') + Day; StrHou = ((Hou < 10) ? '0' : '') + Hou; StrMin = ((Min < 10) ? '0' : '') + Min; StrSec = ((Sec < 10) ? '0' : '') + Sec; if (Yea == todayYea && Mon == todayMon && Day == todayDay && // Today StrToday.length) document.getElementById(id).innerHTML = StrToday + separator + StrHou + ':' + StrMin + ':' + StrSec; else document.getElementById(id).innerHTML = Yea + '-' + StrMon + '-' + StrDay + separator + StrHou + ':' + StrMin + ':' + StrSec; } // Set local date-time form fields from UTC time function setLocalDateTimeFormFromUTC(id,TimeUTC) { var FormYea = document.getElementById(id+'Year' ); var FormMon = document.getElementById(id+'Month' ); var FormDay = document.getElementById(id+'Day' ); var FormHou = document.getElementById(id+'Hour' ); var FormMin = document.getElementById(id+'Minute'); var FormSec = document.getElementById(id+'Second'); var d; var Year; var YearIsValid = false; if (TimeUTC) { d = new Date; d.setTime(TimeUTC * 1000); Year = d.getFullYear(); for (var i=0; i= Days) FormDay.options[Days-1].selected = true; // Select last day in month for (var i=FormDay.options.length; i=Days; i--) // Remove days from the end FormDay.options[i] = null; } // Set a date range form to yesterday function setDateToYesterday() { var d = new (Date); d.setTime(d.getTime() - 24*60*60*1000); // Today - 1 day setDateRange(d); } // Set a date range form to today function setDateToToday() { var d = new (Date); setDateRange(d); } // Set a date range form to a specific day function setDateRange(d) { var FormYea; var Yea = d.getFullYear(); var Mon = d.getMonth()+1; var Day = d.getDate(); FormYea = document.getElementById('StartYear'); for (var i=0; i' + Hou + ':' + StrMin + ''; } function writeClockConnected() { var BoxClock; var H; var M; var S; var StrM; var StrS; var PrintableClock; countClockConnected++; countClockConnected %= 10; for (var i=0; i= 60) { H = Math.floor(M / 60); M %= 60; } else H = 0; S = ListSeconds[i] % 60; if (H != 0) { StrM = ((M < 10) ? '0' : '') + M; StrS = ((S < 10) ? '0' : '') + S; PrintableClock = H + ':' + StrM + ''' + StrS + '"'; } else if (M != 0) { StrS = ((S < 10) ? '0' : '') + S; PrintableClock = M + ''' + StrS + '"'; } else PrintableClock = S + '"'; BoxClock.innerHTML = PrintableClock; } } } setTimeout('writeClockConnected()',1000); // refresh after 1 second } // Automatic refresh of connected users using AJAX. This function must be called from time to time var objXMLHttpReqCon = false; function refreshConnected() { objXMLHttpReqCon = AJAXCreateObject(); if (objXMLHttpReqCon) { var RefreshParams = RefreshParamNxtActCon + '&' + RefreshParamIdSes + '&' + RefreshParamCrsCod; objXMLHttpReqCon.onreadystatechange = readConnUsrsData; // onreadystatechange must be lowercase objXMLHttpReqCon.open('POST',ActionAJAX,true); objXMLHttpReqCon.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqCon.send(RefreshParams); } } // Automatic refresh of last clicks using AJAX. This function must be called from time to time var objXMLHttpReqLog = false; function refreshLastClicks() { objXMLHttpReqLog = AJAXCreateObject(); if (objXMLHttpReqLog) { var RefreshParams = RefreshParamNxtActLog + '&' + RefreshParamIdSes + '&' + RefreshParamCrsCod; objXMLHttpReqLog.onreadystatechange = readLastClicksData; // onreadystatechange must be lowercase objXMLHttpReqLog.open('POST',ActionAJAX,true); objXMLHttpReqLog.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqLog.send(RefreshParams); } } // Create AJAX object (try is unknown in earlier versions of Netscape, but works in IE5) function AJAXCreateObject() { var obj = false; if (window.XMLHttpRequest) { // Mozilla, Safari,... obj = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { obj = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { obj = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } return obj; } // Receives and show connected users data function readConnUsrsData() { if (objXMLHttpReqCon.readyState == 4) { // Check if data have been received if (objXMLHttpReqCon.status == 200) { var endOfDelay = objXMLHttpReqCon.responseText.indexOf('|',0); // Get separator position var endOfNotif = objXMLHttpReqCon.responseText.indexOf('|',endOfDelay+1); // Get separator position var endOfGblCon = objXMLHttpReqCon.responseText.indexOf('|',endOfNotif+1); // Get separator position var endOfCrsCon = objXMLHttpReqCon.responseText.indexOf('|',endOfGblCon+1); // Get separator position var endOfNumUsrs = objXMLHttpReqCon.responseText.indexOf('|',endOfCrsCon+1); // Get separator position var delay = parseInt(objXMLHttpReqCon.responseText.substring(0,endOfDelay)); // Get refresh delay var htmlNotif = objXMLHttpReqCon.responseText.substring(endOfDelay +1,endOfNotif); // Get HTML code for new notifications var htmlGblCon = objXMLHttpReqCon.responseText.substring(endOfNotif +1,endOfGblCon); // Get HTML code for connected var htmlCrsCon = objXMLHttpReqCon.responseText.substring(endOfGblCon+1,endOfCrsCon); // Get HTML code for course connected var NumUsrsStr = objXMLHttpReqCon.responseText.substring(endOfCrsCon+1,endOfNumUsrs); // Get number of users var startOfUsr; var endOfUsr; NumUsrsCon = (NumUsrsStr.length ? parseInt(NumUsrsStr) : 0); var divNewNotif = document.getElementById('msg'); // Access to new notifications DIV if (divNewNotif) divNewNotif.innerHTML = (htmlNotif.length) ? htmlNotif : ''; // Update new notifications DIV var divGblConnected = document.getElementById('globalconnected'); // Access to global connected DIV if (divGblConnected) divGblConnected.innerHTML = htmlGblCon; // Update global connected DIV if (htmlCrsCon.length) { var divCrsConnected = document.getElementById('courseconnected'); // Access to course connected DIV if (divCrsConnected) { divCrsConnected.innerHTML = htmlCrsCon; // Update course connected DIV countClockConnected = 0; // Don't refresh again using writeClockConnected until past 10 seconds startOfUsr = endOfNumUsrs + 1; for (var NumUsr=0; NumUsr= 60000) // If refresh slower than 1 time each 60 seconds, do refresh; else abort setTimeout('refreshConnected()',delay); } } } // Receives and show last clicks data function readLastClicksData() { if (objXMLHttpReqLog.readyState == 4) { // Check if data have been received if (objXMLHttpReqLog.status == 200) { var endOfDelay = objXMLHttpReqLog.responseText.indexOf('|',0); // Get separator position var endOfLastClicks = objXMLHttpReqLog.responseText.indexOf('|',endOfDelay+1); // Get separator position var delay = parseInt(objXMLHttpReqLog.responseText.substring(0,endOfDelay)); // Get refresh delay var htmlLastClicks = objXMLHttpReqLog.responseText.substring(endOfDelay+1); // Get HTML code for last clicks var divLastClicks = document.getElementById('lastclicks'); // Access to last click DIV if (divLastClicks) divLastClicks.innerHTML = htmlLastClicks; // Update global connected DIV if (delay > 200) // If refresh slower than 1 time each 0.2 seconds, do refresh; else abort setTimeout('refreshLastClicks()',delay); } } } // Zoom a user's photograph function zoom(img,urlPhoto,shortName) { var zoomImgWidth = 186; // big photo var zoomImgHeight = 248; // big photo var padding = 7; // padding around big photo including border var xPos = img.offsetLeft; var yPos = img.offsetTop; var tempEl = img.offsetParent; while (tempEl != null) { xPos += tempEl.offsetLeft; yPos += tempEl.offsetTop; tempEl = tempEl.offsetParent; } if (xPos - (zoomImgWidth + padding*2) >= 0) xPos -= (zoomImgWidth + padding*2); // zoom at left of the photo else xPos += img.width + 1; // zoom at right of the photo yPos = yPos + img.height - zoomImgHeight - padding; if (yPos < 0) yPos = 0; document.getElementById('zoomLyr').style.left = xPos + 'px'; document.getElementById('zoomLyr').style.top = yPos + 'px'; document.getElementById('zoomImg').src = urlPhoto; document.getElementById('zoomTxt').innerHTML = '' + shortName + ''; } // Exit from zooming a user's photograph function noZoom() { var xPos = -(187+15); var yPos = -(250+15+110); document.getElementById('zoomTxt').innerHTML = ''; document.getElementById('zoomImg').src='/icon/_.gif'; document.getElementById('zoomLyr').style.left = xPos + 'px'; document.getElementById('zoomLyr').style.top = yPos + 'px'; } // Select or unselect a radio element in a form function selectUnselectRadio (radio,groupRadios,numRadiosInGroup){ if (radio.IsChecked) radio.checked = false; radio.IsChecked = !radio.IsChecked; for (var i=0; i October 10, // February --> October 10, // Mars --> October 1, // April --> January 1, // May --> January 1, // June --> January 4, // July --> April 4, // August --> April 4, // September --> April 7, // October --> July 7, // November --> July 7 // December --> July ]; var d = new Date; d.setTime(TimeUTC * 1000); var CurrentMonth = d.getMonth() + 1; var CurrentYear = d.getFullYear(); var CurrentDay = d.getDate(); var Month = StartingMonth[CurrentMonth - 1]; var Year = (Month < CurrentMonth) ? CurrentYear : CurrentYear - 1; var Row; var Col; var MonthIdNum = 0; var MonthId; /***** Draw several months *****/ Gbl_HTMLContent += ''; for (Row = 0; Row < 5; Row++) { Gbl_HTMLContent += ''; for (Col = 0; Col < 3; Col++) { MonthIdNum++; MonthId = id + '_month_' + MonthIdNum; Gbl_HTMLContent += ''; if (++Month == 13) { Month = 1; Year++; } } Gbl_HTMLContent += ''; } Gbl_HTMLContent += '
'; DrawMonth (MonthId,FirstDayOfWeek,Year,Month,CurrentMonth,CurrentDay, CurrentPlcCod,true,PrintView,CGI, FormGoToCalendarParams,FormEventParams); Gbl_HTMLContent += '
'; document.getElementById(id).innerHTML = Gbl_HTMLContent; } /*****************************************************************************/ /***************************** Draw current month ****************************/ /*****************************************************************************/ function DrawCurrentMonth (id,FirstDayOfWeek,TimeUTC,CurrentPlcCod, CGI,FormGoToCalendarParams,FormEventParams) { var d = new Date; d.setTime(TimeUTC * 1000); var Year = d.getFullYear(); var Month = d.getMonth() + 1; var CurrentDay = d.getDate(); DrawMonth (id,FirstDayOfWeek,Year,Month,Month,CurrentDay, CurrentPlcCod,false,false, CGI,FormGoToCalendarParams,FormEventParams); document.getElementById(id).innerHTML = Gbl_HTMLContent; } /*****************************************************************************/ /******************************* Draw a month ********************************/ /*****************************************************************************/ // FirstDayOfWeek == 0 ==> Weeks from Monday to Sunday // FirstDayOfWeek == 6 ==> Weeks from Sunday to Saturday function DrawMonth (id,FirstDayOfWeek,YearToDraw,MonthToDraw,CurrentMonth,CurrentDay, CurrentPlcCod,DrawingCalendar,PrintView, CGI,FormGoToCalendarParams,FormEventParams) { var NumDaysMonth = [ 0, 31, // 1: January 28, // 2: February 31, // 3: Mars 30, // 4: April 31, // 5: May 30, // 6: June 31, // 7: July 31, // 8: Agoust 30, // 9: September 31, // 10: October 30, // 11: November 31, // 12: December ]; var Hld_HOLIDAY = 0; var Hld_NON_SCHOOL_PERIOD = 1; var Week; var DayOfWeek; /* 0, 1, 2, 3, 4, 5, 6 */ var Day; var NumDaysInMonth; var Yea = YearToDraw; var Mon = MonthToDraw; var YYYYMMDD; var NumHld; var ClassForDay; // Class of day depending on type of day var TextForDay; // Text associated to a day, for example the name of the holiday var NumExamAnnouncement; // Number of exam announcement var ResultOfCmpStartDate; var ContinueSearching; var ThisDayHasEvent; var IsToday; var FormIdNum = 0; var FormId; /***** Compute number of day of month for the first box *****/ /* The initial day of month can be -5, -4, -3, -2, -1, 0, or 1 If it's -5 then write 6 boxes of the previous month. If it's -4 then write 5 boxes of the previous month. If it's -3 then write 4 boxes of the previous month. If it's -2 then write 3 boxes of the previous month. If it's -1 then write 2 boxes of the previous month. If it's 0 then write 1 box of the previous month. If it's 1 then write 0 boxes of the previous month. */ if ((DayOfWeek = (GetDayOfWeekMondayFirst (Yea,Mon,1) + 7 - FirstDayOfWeek) % 7) == 0) Day = 1; else { if (Mon <= 1) { Mon = 12; Yea--; } else Mon--; NumDaysInMonth = (Mon == 2) ? GetNumDaysFebruary(Yea) : NumDaysMonth[Mon]; Day = NumDaysInMonth - DayOfWeek + 1; } /***** Start of month *****/ Gbl_HTMLContent += '
'; /***** Month name *****/ if (DrawingCalendar) Gbl_HTMLContent += '
'; else { FormId = id + '_show_calendar'; Gbl_HTMLContent += '
' + FormGoToCalendarParams + ''; else Gbl_HTMLContent += '
'; /***** Month head: first letter for each day of week *****/ Gbl_HTMLContent += '' + ''; for (DayOfWeek = 0; DayOfWeek < 7; DayOfWeek++) Gbl_HTMLContent += ''; Gbl_HTMLContent += ''; /***** Draw every week of the month *****/ for (Week = 0; Week < 6; Week++) { Gbl_HTMLContent += ''; /***** Draw every day of the week *****/ for (DayOfWeek = 0; DayOfWeek < 7; DayOfWeek++) { /***** Set class for day being drawn *****/ ClassForDay = ((Mon == MonthToDraw) ? 'DAY_WRK' : 'DAY_WRK_LIGHT'); TextForDay = ''; /* Check if day is a holiday or a school day */ YYYYMMDD = Yea * 10000 + Mon * 100 + Day; for (NumHld = 0, ContinueSearching = true; NumHld < Hlds.length && ContinueSearching; NumHld++) if (Hlds[NumHld].PlcCod <= 0 || Hlds[NumHld].PlcCod == CurrentPlcCod) { if (Hlds[NumHld].StartDate > YYYYMMDD) // List is ordered by start date. If start date is greater than date being drawn, don't continue searching ContinueSearching = false; else // start date <= date being drawn switch (Hlds[NumHld].HldTyp) { case Hld_HOLIDAY: if (Hlds[NumHld].StartDate == YYYYMMDD) { // If start date == date being drawn ClassForDay = ((Mon == MonthToDraw) ? 'DAY_HLD' : 'DAY_HLD_LIGHT'); TextForDay = Hlds[NumHld].Name; ContinueSearching = false; } break; case Hld_NON_SCHOOL_PERIOD: if (Hlds[NumHld].EndDate >= YYYYMMDD) { // If start date <= date being drawn <= end date ClassForDay = ((Mon == MonthToDraw) ? 'DAY_NO_WORK' : 'DAY_NO_WORK_LIGHT'); TextForDay = Hlds[NumHld].Name; } break; } } /* Day being drawn is sunday? */ if (DayOfWeek == 6 - FirstDayOfWeek) // All the sundays are holidays ClassForDay = (Mon == MonthToDraw) ? 'DAY_HLD' : 'DAY_HLD_LIGHT'; /* Date being drawn is today? */ IsToday = (Yea == YearToDraw && Mon == MonthToDraw && Mon == CurrentMonth && Day == CurrentDay); /* Check if day has an exam announcement */ ThisDayHasEvent = false; if (!DrawingCalendar || Mon == MonthToDraw) // If drawing calendar and the month is not the real one, don't draw exam announcements for (NumExamAnnouncement = 0; NumExamAnnouncement < LstExamAnnouncements.length; NumExamAnnouncement++) if (Yea == LstExamAnnouncements[NumExamAnnouncement].Year && Mon == LstExamAnnouncements[NumExamAnnouncement].Month && Day == LstExamAnnouncements[NumExamAnnouncement].Day) { ThisDayHasEvent = true; if (!PrintView) TextForDay = STR_EXAM + ': ' + LstExamAnnouncements[NumExamAnnouncement].Year + '-' + LstExamAnnouncements[NumExamAnnouncement].Month + '-' + LstExamAnnouncements[NumExamAnnouncement].Day; break; } /***** Write the box with the day *****/ Gbl_HTMLContent += ''; } /***** End of month *****/ Gbl_HTMLContent += '
' + DAYS_CAPS[(DayOfWeek + FirstDayOfWeek) % 7] + '
'; /* If day has an exam announcement */ if (!PrintView && ThisDayHasEvent) { FormIdNum++; FormId = id + '_event_' + FormIdNum; Gbl_HTMLContent += '
' + FormEventParams + '
'; } else { Gbl_HTMLContent += '
NumDaysInMonth) { if (++Mon > 12) { Yea++; Mon = 1; } Day = 1; } } Gbl_HTMLContent += '
'; } /*****************************************************************************/ /* Compute day of the week from a given date (monday as first day of a week) */ /*****************************************************************************/ // Return 0 for monday, 1 for tuesday,... 6 for sunday function GetDayOfWeekMondayFirst (Year,Month,Day) { if (Month <= 2) { Month += 12; Year--; } return (((Day + (Month * 2) + Math.floor (((Month + 1) * 3) / 5) + Year + Math.floor (Year / 4) - Math.floor (Year/100) + Math.floor (Year/400) + 2) % 7) + 5) % 7; } /*****************************************************************************/ /****************** Return the number of days of february ********************/ /*****************************************************************************/ function GetNumDaysFebruary (Year) { return (GetIfLeapYear (Year) ? 29 : 28); } /*****************************************************************************/ /************************* Return true if year is leap ***********************/ /*****************************************************************************/ function GetIfLeapYear (Year) { return (Year % 4 == 0) && ((Year % 100 != 0) || (Year % 400 == 0)); }