// swad_layout.c: page layout /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. This file is part of SWAD core. Copyright (C) 1999-2019 Antonio Caņas Vargas 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 . */ /*****************************************************************************/ /********************************* Headers ***********************************/ /*****************************************************************************/ #include // For NULL #include // For exit #include // For string functions #include "swad_action.h" #include "swad_API.h" #include "swad_box.h" #include "swad_calendar.h" #include "swad_changelog.h" #include "swad_config.h" #include "swad_connected.h" #include "swad_database.h" #include "swad_exam.h" #include "swad_firewall.h" #include "swad_follow.h" #include "swad_form.h" #include "swad_global.h" #include "swad_help.h" #include "swad_hierarchy.h" #include "swad_HTML.h" #include "swad_language.h" #include "swad_logo.h" #include "swad_MFU.h" #include "swad_notice.h" #include "swad_notification.h" #include "swad_parameter.h" #include "swad_setting.h" #include "swad_tab.h" #include "swad_theme.h" #include "swad_timeline.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ /*****************************************************************************/ /******************************* Private types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Lay_WriteEndOfPage (void); static void Lay_WritePageTitle (void); static void Lay_WriteRedirToMyLangOnLogIn (void); static void Lay_WriteRedirToMyLangOnViewUsrAgd (void); static void Lay_WriteScripts (void); static void Lay_WriteScriptMathJax (void); static void Lay_WriteScriptInit (void); static void Lay_WriteScriptParamsAJAX (void); static void Lay_WriteScriptCustomDropzone (void); static void Lay_WritePageTopHeading (void); static void Lay_WriteBreadcrumb (void); static void Lay_WriteTitleAction (void); static void Lay_ShowLeftColumn (void); static void Lay_ShowRightColumn (void); static void Lay_WriteAboutZone (void); static void Lay_WriteFootFromHTMLFile (void); static void Lay_HelpTextEditor (const char *Text,const char *InlineMath,const char *Equation); /*****************************************************************************/ /*********************** Write the start of the page *************************/ /*****************************************************************************/ void Lay_WriteStartOfPage (void) { extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; extern const unsigned Txt_Current_CGI_SWAD_Language; extern const char *The_TabOnBgColors[The_NUM_THEMES]; static const char *LayoutMainZone[Mnu_NUM_MENUS] = { [Mnu_MENU_HORIZONTAL] = "main_horizontal", [Mnu_MENU_VERTICAL ] = "main_vertical", }; Act_BrowserTab_t BrowserTab; /***** If, when this function is called, the head is being written or the head is already written ==> don't do anything *****/ if (Gbl.Layout.WritingHTMLStart || Gbl.Layout.HTMLStartWritten) return; /***** Compute connected users to be displayed in right columns *****/ Con_ComputeConnectedUsrsBelongingToCurrentCrs (); /***** Send head width the file type for the HTTP protocol *****/ if (Gbl.Action.UsesAJAX) // Don't generate a full HTML page, only the content of a DIV or similar { HTM_Txt ("Content-Type: text/html; charset=windows-1252\r\n\r\n"); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.DivsEndWritten = true; return; } /***** If serving a web service ==> don't do anything *****/ if (Gbl.WebService.IsWebService) { Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.DivsEndWritten = true; return; } Gbl.Layout.WritingHTMLStart = true; /***** Write header to standard output to avoid timeout *****/ // Two \r\n are necessary fprintf (stdout,"Content-type: text/html; charset=windows-1252\r\n\r\n" "\n"); /***** Write start of HTML code *****/ // WARNING: It is necessary to comment the line 'AddDefaultCharset UTF8' // in httpd.conf to enable meta tag HTM_TxtF ("\n",Lan_STR_LANG_ID[Gbl.Prefs.Language]); HTM_Txt ("\n" "\n" "\n" "\n"); /* Viewport (used for responsive design) */ HTM_Txt ("\n"); /* Title */ Lay_WritePageTitle (); /* Canonical URL */ HTM_TxtF ("\n",Cfg_URL_SWAD_CGI); /* Favicon */ HTM_TxtF ("\n", Cfg_URL_ICON_PUBLIC); HTM_TxtF ("\n", Cfg_URL_ICON_PUBLIC); /* Style sheet for SWAD */ HTM_TxtF ("\n", Cfg_URL_SWAD_PUBLIC,CSS_FILE); /* Style sheets for Font Awesome */ HTM_TxtF ("\n", Cfg_URL_SWAD_PUBLIC); HTM_TxtF ("\n", Cfg_URL_SWAD_PUBLIC); /* Style sheet for Dropzone.js (http://www.dropzonejs.com/) */ // The public directory dropzone must hold: // dropzone.js // css/dropzone.css // images/spritemap@2x.png // images/spritemap.png switch (Gbl.Action.Act) { case ActFrmCreDocIns: // Brw_ADMI_DOC_INS case ActFrmCreShaIns: // Brw_ADMI_SHR_INS case ActFrmCreDocCtr: // Brw_ADMI_DOC_CTR case ActFrmCreShaCtr: // Brw_ADMI_SHR_CTR case ActFrmCreDocDeg: // Brw_ADMI_DOC_DEG case ActFrmCreShaDeg: // Brw_ADMI_SHR_DEG case ActFrmCreDocCrs: // Brw_ADMI_DOC_CRS case ActFrmCreDocGrp: // Brw_ADMI_DOC_GRP case ActFrmCreTchCrs: // Brw_ADMI_TCH_CRS case ActFrmCreTchGrp: // Brw_ADMI_TCH_GRP case ActFrmCreShaCrs: // Brw_ADMI_SHR_CRS case ActFrmCreShaGrp: // Brw_ADMI_SHR_GRP case ActFrmCreAsgUsr: // Brw_ADMI_ASG_USR case ActFrmCreAsgCrs: // Brw_ADMI_ASG_CRS case ActFrmCreWrkUsr: // Brw_ADMI_WRK_USR case ActFrmCreWrkCrs: // Brw_ADMI_WRK_CRS case ActFrmCreDocPrj: // Brw_ADMI_DOC_PRJ case ActFrmCreAssPrj: // Brw_ADMI_ASS_PRJ case ActFrmCreMrkCrs: // Brw_ADMI_MRK_CRS case ActFrmCreMrkGrp: // Brw_ADMI_MRK_GRP case ActFrmCreBrf: // Brw_ADMI_BRF_USR HTM_TxtF ("\n", Cfg_URL_SWAD_PUBLIC); break; default: break; } /* Redirect to correct language */ if (Gbl.Usrs.Me.Logged && // I am logged Gbl.Usrs.Me.UsrDat.Prefs.Language != Txt_Current_CGI_SWAD_Language) // My language != current language { if (Gbl.Action.Original == ActLogIn || // Regular log in Gbl.Action.Original == ActLogInNew) // Log in when checking account Lay_WriteRedirToMyLangOnLogIn (); else if (Gbl.Action.Original == ActLogInUsrAgd) // Log in to view another user's public agenda Lay_WriteRedirToMyLangOnViewUsrAgd (); } /* Write initial scripts depending on the action */ Lay_WriteScripts (); HTM_Txt ("\n"); /***** HTML body *****/ BrowserTab = Act_GetBrowserTab (Gbl.Action.Act); switch (BrowserTab) { case Act_BRW_1ST_TAB: HTM_Txt ("\n"); HTM_DIV_Begin ("id=\"zoomLyr\" class=\"ZOOM\""); HTM_IMG (Cfg_URL_ICON_PUBLIC,"usr_bl.jpg",NULL, "class=\"IMG_USR\" id=\"zoomImg\""); HTM_DIV_Begin ("id=\"zoomTxt\" class=\"CM\""); HTM_DIV_End (); HTM_DIV_End (); break; case Act_BRW_NEW_TAB: case Act_BRW_2ND_TAB: HTM_Txt ("\n"); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.DivsEndWritten = true; return; default: HTM_Txt ("\n"); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.DivsEndWritten = true; return; } /***** Begin box that contains the whole page except the foot *****/ HTM_DIV_Begin ("id=\"whole_page\""); /***** Header of layout *****/ Lay_WritePageTopHeading (); /***** 3rd. row (tabs) *****/ Tab_DrawTabs (); /***** 4th row: main zone *****/ HTM_DIV_Begin ("id=\"main_zone\""); /* Left column */ if (Gbl.Prefs.SideCols & Lay_SHOW_LEFT_COLUMN) // Left column visible { HTM_Txt (""); } /* Right column */ // Right column is written before central column // but it must be drawn at right using "position:absolute; right:0". // The reason to write right column before central column // is that central column may hold a lot of content drawn slowly. if (Gbl.Prefs.SideCols & Lay_SHOW_RIGHT_COLUMN) // Right column visible { HTM_Txt (""); } /* Central (main) column */ switch (Gbl.Prefs.SideCols) { case 0: HTM_DIV_Begin ("id=\"main_zone_central_none\""); break; case Lay_SHOW_LEFT_COLUMN: HTM_DIV_Begin ("id=\"main_zone_central_left\""); break; case Lay_SHOW_RIGHT_COLUMN: HTM_DIV_Begin ("id=\"main_zone_central_right\""); break; case (Lay_SHOW_LEFT_COLUMN | Lay_SHOW_RIGHT_COLUMN): HTM_DIV_Begin ("id=\"main_zone_central_both\""); break; } HTM_DIV_Begin ("id=\"main_zone_central_container\" class=\"%s\"", The_TabOnBgColors[Gbl.Prefs.Theme]); /* Layout with horizontal or vertical menu */ HTM_DIV_Begin ("id=\"%s\"",LayoutMainZone[Gbl.Prefs.Menu]); /* Menu */ Mnu_WriteMenuThisTab (); /* Start canvas: main zone for actions output */ HTM_MAIN_Begin ("MAIN_ZONE_CANVAS"); /* If it is mandatory to read any information about course */ if (Gbl.Crs.Info.ShowMsgMustBeRead) Inf_WriteMsgYouMustReadInfo (); /* Write title of the current action */ if (Gbl.Prefs.Menu == Mnu_MENU_VERTICAL && Act_GetIndexInMenu (Gbl.Action.Act) >= 0) Lay_WriteTitleAction (); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = true; /* Write message indicating number of clicks allowed before sending my photo */ Usr_InformAboutNumClicksBeforePhoto (); } /*****************************************************************************/ /*********************** Write status 204 No Content *************************/ /*****************************************************************************/ void Lay_WriteHTTPStatus204NoContent (void) { /***** The HTTP response is a code status *****/ /* Don't write HTML at all */ Gbl.Layout.HTMLStartWritten = Gbl.Layout.DivsEndWritten = Gbl.Layout.HTMLEndWritten = true; /* Start HTTP response */ fprintf (stdout,"Content-type: text/plain; charset=windows-1252\n"); /* Return HTTP status code 204 No Content: The server has successfully fulfilled the request and there is no additional content to send in the response payload body. */ fprintf (stdout,"Status: 204\r\n\r\n"); } /*****************************************************************************/ /************************ Write the end of the page **************************/ /*****************************************************************************/ static void Lay_WriteEndOfPage (void) { if (!Gbl.Layout.DivsEndWritten) { /***** End of central part of main zone *****/ HTM_MAIN_End (); // Canvas (main zone to output content of the current action) HTM_DIV_End (); // Layout with horizontal or vertical menu HTM_DIV_End (); // main_zone_central_container /***** Write page footer *****/ if (Act_GetBrowserTab (Gbl.Action.Act) == Act_BRW_1ST_TAB) Lay_WriteFootFromHTMLFile (); /***** End of main zone and page *****/ HTM_DIV_End (); // main_zone_central HTM_DIV_End (); // main_zone HTM_DIV_End (); // whole_page_* (box that contains the whole page except the foot) Gbl.Layout.DivsEndWritten = true; } } /*****************************************************************************/ /************************* Write the title of the page ***********************/ /*****************************************************************************/ static void Lay_WritePageTitle (void) { extern const char *Txt_TAGLINE; HTM_Txt (""); if (Gbl.Params.GetMethod && Gbl.Hierarchy.Deg.DegCod > 0) { HTM_TxtF ("%s > %s",Cfg_PLATFORM_SHORT_NAME,Gbl.Hierarchy.Deg.ShrtName); if (Gbl.Hierarchy.Level == Hie_CRS) HTM_TxtF (" > %s",Gbl.Hierarchy.Crs.ShrtName); } else HTM_TxtF ("%s: %s",Cfg_PLATFORM_SHORT_NAME,Txt_TAGLINE); HTM_Txt ("\n"); } /*****************************************************************************/ /************* Write script and meta to redirect to my language **************/ /*****************************************************************************/ static void Lay_WriteRedirToMyLangOnLogIn (void) { extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; HTM_TxtF ("", Cfg_URL_SWAD_CGI, Lan_STR_LANG_ID[Gbl.Usrs.Me.UsrDat.Prefs.Language], Act_GetActCod (ActLogInLan), Gbl.Session.Id); } static void Lay_WriteRedirToMyLangOnViewUsrAgd (void) { extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; HTM_TxtF ("", Cfg_URL_SWAD_CGI, Lan_STR_LANG_ID[Gbl.Usrs.Me.UsrDat.Prefs.Language], Act_GetActCod (ActLogInUsrAgdLan), Gbl.Session.Id, Gbl.Usrs.Other.UsrDat.Nickname); } /*****************************************************************************/ /************ Write some scripts depending on the current action *************/ /*****************************************************************************/ static void Lay_WriteScripts (void) { extern const char *Txt_DAYS_CAPS[7]; extern const char *Txt_DAYS_SMALL[7]; extern const char *Txt_Exam_of_X; unsigned DayOfWeek; /* 0, 1, 2, 3, 4, 5, 6 */ unsigned NumHld; unsigned NumExamAnnouncement; // Number of exam announcement /***** General scripts for swad *****/ HTM_SCRIPT_Begin (Cfg_URL_SWAD_PUBLIC "/" JS_FILE,NULL); HTM_SCRIPT_End (); /***** Script for MathJax *****/ Lay_WriteScriptMathJax (); /***** Write script with init function executed after loading page *****/ Lay_WriteScriptInit (); /***** Write script to set parameters needed by AJAX *****/ Lay_WriteScriptParamsAJAX (); /***** Write script to initialize variables used to draw dates *****/ HTM_SCRIPT_Begin (NULL,NULL); HTM_Txt ("\tvar DAYS = ["); for (DayOfWeek = 0; DayOfWeek < 7; DayOfWeek++) { if (DayOfWeek) HTM_Comma (); HTM_TxtF ("'%s'",Txt_DAYS_SMALL[DayOfWeek]); } HTM_Txt ("];\n"); HTM_SCRIPT_End (); /***** Prepare script to draw months *****/ if ((Gbl.Prefs.SideCols & Lay_SHOW_LEFT_COLUMN) || // Left column visible (Gbl.Hierarchy.Ins.InsCod > 0 && // Institution selected (Gbl.Action.Act == ActSeeCal || // Viewing calendar Gbl.Action.Act == ActPrnCal || // Printing calendar Gbl.Action.Act == ActChgCal1stDay))) // Changing first day { /***** Get list of holidays *****/ if (!Gbl.Hlds.LstIsRead) { Gbl.Hlds.SelectedOrder = Hld_ORDER_BY_START_DATE; Hld_GetListHolidays (); } /***** Create list of calls for examination *****/ Exa_CreateListDatesOfExamAnnouncements (); /***** Write script to initialize variables used to draw months *****/ HTM_SCRIPT_Begin (NULL,NULL); HTM_Txt ("\tvar DAYS_CAPS = ["); for (DayOfWeek = 0; DayOfWeek < 7; DayOfWeek++) { if (DayOfWeek) HTM_Comma (); HTM_TxtF ("'%c'",Txt_DAYS_CAPS[DayOfWeek][0]); } HTM_Txt ("];\n"); HTM_Txt ("\tvar STR_EXAM = '"); HTM_TxtF (Txt_Exam_of_X,Gbl.Hierarchy.Crs.FullName); HTM_Txt ("';\n"); HTM_Txt ("\tvar Hlds = [];\n"); for (NumHld = 0; NumHld < Gbl.Hlds.Num; NumHld++) HTM_TxtF ("\tHlds.push({ PlcCod: %ld, HldTyp: %u, StartDate: %s, EndDate: %s, Name: '%s' });\n", Gbl.Hlds.Lst[NumHld].PlcCod, (unsigned) Gbl.Hlds.Lst[NumHld].HldTyp, Gbl.Hlds.Lst[NumHld].StartDate.YYYYMMDD, Gbl.Hlds.Lst[NumHld].EndDate.YYYYMMDD, Gbl.Hlds.Lst[NumHld].Name); HTM_TxtF ("\tvar LstExamAnnouncements = [];\n"); for (NumExamAnnouncement = 0; NumExamAnnouncement < Gbl.ExamAnns.NumExaAnns; NumExamAnnouncement++) HTM_TxtF ("LstExamAnnouncements.push({ ExaCod: %ld, Year: %u, Month: %u, Day: %u });\n", Gbl.ExamAnns.Lst[NumExamAnnouncement].ExaCod, Gbl.ExamAnns.Lst[NumExamAnnouncement].ExamDate.Year, Gbl.ExamAnns.Lst[NumExamAnnouncement].ExamDate.Month, Gbl.ExamAnns.Lst[NumExamAnnouncement].ExamDate.Day); HTM_SCRIPT_End (); /***** Free list of dates of exam announcements *****/ Exa_FreeListExamAnnouncements (); } /***** Scripts depending on action *****/ switch (Gbl.Action.Act) { /***** Script to print world map *****/ case ActSeeCty: Cty_WriteScriptGoogleGeochart (); break; /***** Script for uploading files using Dropzone.js (http://www.dropzonejs.com/) *****/ // The public directory dropzone must hold: // dropzone.js // css/dropzone.css // images/spritemap@2x.png // images/spritemap.png case ActFrmCreDocIns: // Brw_ADMI_DOC_INS case ActFrmCreShaIns: // Brw_ADMI_SHR_INS case ActFrmCreDocCtr: // Brw_ADMI_DOC_CTR case ActFrmCreShaCtr: // Brw_ADMI_SHR_CTR case ActFrmCreDocDeg: // Brw_ADMI_DOC_DEG case ActFrmCreShaDeg: // Brw_ADMI_SHR_DEG case ActFrmCreDocCrs: // Brw_ADMI_DOC_CRS case ActFrmCreDocGrp: // Brw_ADMI_DOC_GRP case ActFrmCreTchCrs: // Brw_ADMI_TCH_CRS case ActFrmCreTchGrp: // Brw_ADMI_TCH_GRP case ActFrmCreShaCrs: // Brw_ADMI_SHR_CRS case ActFrmCreShaGrp: // Brw_ADMI_SHR_GRP case ActFrmCreAsgUsr: // Brw_ADMI_ASG_USR case ActFrmCreAsgCrs: // Brw_ADMI_ASG_CRS case ActFrmCreWrkUsr: // Brw_ADMI_WRK_USR case ActFrmCreWrkCrs: // Brw_ADMI_WRK_CRS case ActFrmCreDocPrj: // Brw_ADMI_DOC_PRJ case ActFrmCreAssPrj: // Brw_ADMI_ASS_PRJ case ActFrmCreMrkCrs: // Brw_ADMI_MRK_CRS case ActFrmCreMrkGrp: // Brw_ADMI_MRK_GRP case ActFrmCreBrf: // Brw_ADMI_BRF_USR // Use charset="windows-1252" to force error messages in windows-1252 (default is UTF-8) HTM_SCRIPT_Begin (Cfg_URL_SWAD_PUBLIC "/dropzone/dropzone.js","windows-1252"); HTM_SCRIPT_End (); Lay_WriteScriptCustomDropzone (); break; case ActReqAccGbl: case ActSeeAccGbl: case ActReqAccCrs: case ActSeeAccCrs: case ActSeeAllStaCrs: HTM_SCRIPT_Begin (Cfg_URL_SWAD_PUBLIC "/jstz/jstz.js",NULL); HTM_SCRIPT_End (); break; default: break; } /***** Script for Google Analytics *****/ HTM_Txt (Cfg_GOOGLE_ANALYTICS); } // Change page title //function changeTitle(title) { // document.title = title; //} /*****************************************************************************/ /************ Write some scripts depending on the current action *************/ /*****************************************************************************/ static void Lay_WriteScriptMathJax (void) { // MathJax configuration /* HTM_SCRIPT_Begin (NULL,NULL); fprintf (Gbl.F.Out," window.MathJax = {" " tex2jax: {" " inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ]," " processEscapes: true" " }" " };"); HTM_SCRIPT_End (); */ #ifdef Cfg_MATHJAX_LOCAL // Use the local copy of MathJax HTM_SCRIPT_Begin (Cfg_URL_SWAD_PUBLIC "/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML",NULL); #else // Use the MathJax Content Delivery Network (CDN) HTM_SCRIPT_Begin ("//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",NULL); #endif HTM_SCRIPT_End (); } /*****************************************************************************/ /******* Write script with init function executed after loading page *********/ /*****************************************************************************/ static void Lay_WriteScriptInit (void) { extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; bool RefreshConnected; bool RefreshNewTimeline = false; bool RefreshMatchStd = false; bool RefreshMatchTch = false; bool RefreshLastClicks = false; RefreshConnected = Act_GetBrowserTab (Gbl.Action.Act) == Act_BRW_1ST_TAB && (Gbl.Prefs.SideCols & Lay_SHOW_RIGHT_COLUMN); // Right column visible switch (Gbl.Action.Act) { case ActSeeSocTmlGbl: case ActRcvSocPstGbl: case ActRcvSocComGbl: case ActReqRemSocPubGbl: case ActRemSocPubGbl: case ActReqRemSocComGbl: case ActRemSocComGbl: RefreshNewTimeline = true; break; case ActJoiMch: case ActAnsMchQstStd: RefreshMatchStd = true; break; case ActNewMch: case ActResMch: case ActBckMch: case ActPlyPauMch: case ActFwdMch: case ActChgNumColMch: case ActChgVisResMchQst: RefreshMatchTch = true; break; case ActLstClk: RefreshLastClicks = true; break; default: break; } HTM_SCRIPT_Begin (NULL,NULL); Dat_WriteScriptMonths (); if (RefreshNewTimeline) // Refresh new timeline via AJAX HTM_TxtF ("\tvar delayNewTL = %lu;\n",Cfg_TIME_TO_REFRESH_TIMELINE); else if (RefreshMatchStd) // Refresh match via AJAX HTM_TxtF ("\tvar delayMatch = %lu;\n",Cfg_TIME_TO_REFRESH_MATCH_STD); else if (RefreshMatchTch) // Refresh match via AJAX HTM_TxtF ("\tvar delayMatch = %lu;\n",Cfg_TIME_TO_REFRESH_MATCH_TCH); /***** Function init () ******/ HTM_Txt ("function init(){\n"); HTM_TxtF ("\tActionAJAX = \"%s\";\n",Lan_STR_LANG_ID[Gbl.Prefs.Language]); if (RefreshConnected) // Refresh connected users via AJAX { Con_WriteScriptClockConnected (); HTM_TxtF ("\tsetTimeout(\"refreshConnected()\",%lu);\n", Gbl.Usrs.Connected.TimeToRefreshInMs); } if (RefreshLastClicks) // Refresh last clicks via AJAX HTM_TxtF ("\tsetTimeout(\"refreshLastClicks()\",%lu);\n", Cfg_TIME_TO_REFRESH_LAST_CLICKS); else if (RefreshMatchStd) // Refresh match for a student via AJAX HTM_Txt ("\tsetTimeout(\"refreshMatchStd()\",delayMatch);\n"); else if (RefreshMatchTch) // Refresh match for a teacher via AJAX HTM_Txt ("\tsetTimeout(\"refreshMatchTch()\",delayMatch);\n"); else if (RefreshNewTimeline) // Refresh timeline via AJAX HTM_Txt ("\tsetTimeout(\"refreshNewTL()\",delayNewTL);\n"); HTM_Txt ("}\n"); HTM_SCRIPT_End (); } /*****************************************************************************/ /************** Write script to set parameters needed by AJAX ****************/ /*****************************************************************************/ static void Lay_WriteScriptParamsAJAX (void) { /***** Start script *****/ HTM_SCRIPT_Begin (NULL,NULL); /***** Parameters with code of session and current course code *****/ // Refresh parameters HTM_TxtF ("var RefreshParamIdSes = \"ses=%s\";\n" "var RefreshParamCrsCod = \"crs=%ld\";\n", Gbl.Session.Id, Gbl.Hierarchy.Crs.CrsCod); /***** Parameter to refresh connected users *****/ if (Act_GetBrowserTab (Gbl.Action.Act) == Act_BRW_1ST_TAB) // Refresh parameter HTM_TxtF ("var RefreshParamNxtActCon = \"act=%ld\";\n", Act_GetActCod (ActRefCon)); /***** Parameters related with expanding/contracting folders in file browsers *****/ if (Gbl.FileBrowser.Type != Brw_UNKNOWN) /* In all the actions related to file browsers ==> put parameters used by AJAX */ // Refresh parameters HTM_TxtF ("var RefreshParamExpand = \"act=%ld\";\n" "var RefreshParamContract = \"act=%ld\";\n", Act_GetActCod (Brw_GetActionExpand ()), Act_GetActCod (Brw_GetActionContract ())); /***** Parameters related with other actions *****/ switch (Gbl.Action.Act) { /* Parameters related with global timeline refreshing */ case ActSeeSocTmlGbl: case ActRcvSocPstGbl: case ActRcvSocComGbl: case ActReqRemSocPubGbl: case ActRemSocPubGbl: case ActReqRemSocComGbl: case ActRemSocComGbl: /* In all the actions related to view or editing global timeline ==> put parameters used by AJAX */ // Refresh parameters HTM_TxtF ("var RefreshParamNxtActNewPub = \"act=%ld\";\n" "var RefreshParamNxtActOldPub = \"act=%ld\";\n" "var RefreshParamWho = \"Who=%u\";\n", Act_GetActCod (ActRefNewSocPubGbl), Act_GetActCod (ActRefOldSocPubGbl), (unsigned) Gbl.Timeline.Who); break; /* Parameters related with user timeline refreshing */ case ActSeeOthPubPrf: case ActRcvSocPstUsr: case ActRcvSocComUsr: case ActReqRemSocPubUsr: case ActRemSocPubUsr: case ActReqRemSocComUsr: case ActRemSocComUsr: /* In all the actions related to view or editing user's timeline ==> put parameters used by AJAX */ if (Gbl.Usrs.Other.UsrDat.UsrCod <= 0) Usr_GetParamOtherUsrCodEncryptedAndGetListIDs (); if (!Gbl.Usrs.Other.UsrDat.Nickname[0]) Nck_GetNicknameFromUsrCod (Gbl.Usrs.Other.UsrDat.UsrCod, Gbl.Usrs.Other.UsrDat.Nickname); // Refresh parameters HTM_TxtF ("var RefreshParamNxtActOldPub = \"act=%ld\";\n" "var RefreshParamUsr = \"OtherUsrCod=%s\";\n", Act_GetActCod (ActRefOldSocPubUsr), Gbl.Usrs.Other.UsrDat.EncryptedUsrCod); break; /* Parameters related with match refreshing (for students) */ case ActJoiMch: case ActAnsMchQstStd: // Refresh parameters HTM_TxtF ("var RefreshParamNxtActMch = \"act=%ld\";\n" "var RefreshParamMchCod = \"MchCod=%ld\";\n", Act_GetActCod (ActRefMchStd), Gbl.Games.MchCodBeingPlayed); break; /* Parameters related with match refreshing (for teachers) */ case ActNewMch: case ActResMch: case ActBckMch: case ActPlyPauMch: case ActFwdMch: case ActChgNumColMch: case ActChgVisResMchQst: // Handle keys in keyboard/presenter HTM_Txt ("document.addEventListener(\"keydown\",handleMatchKeys);\n"); // Refresh parameters HTM_TxtF ("var RefreshParamNxtActMch = \"act=%ld\";\n" "var RefreshParamMchCod = \"MchCod=%ld\";\n", Act_GetActCod (ActRefMchTch), Gbl.Games.MchCodBeingPlayed); break; /* Parameter related with clicks refreshing */ case ActLstClk: // Refresh parameter HTM_TxtF ("var RefreshParamNxtActLstClk = \"act=%ld\";\n", Act_GetActCod (ActRefLstClk)); break; default: break; } /***** End script *****/ HTM_SCRIPT_End (); } /*****************************************************************************/ /******* Write script to customize upload of files using Dropzone.js *********/ /*****************************************************************************/ // More info: http://www.dropzonejs.com/ static void Lay_WriteScriptCustomDropzone (void) { // "myAwesomeDropzone" is the camelized version of the HTML element's ID // Add a line "forceFallback: true,\n" to test classic upload HTM_SCRIPT_Begin (NULL,NULL); HTM_TxtF ("Dropzone.options.myAwesomeDropzone = {\n" "maxFiles: 100,\n" "parallelUploads: 100,\n" "maxFilesize: %lu,\n" "fallback: function() {\n" "document.getElementById('dropzone-upload').style.display='none';\n" "document.getElementById('classic-upload').style.display='block';\n" "}\n" "};\n", (unsigned long) (Fil_MAX_FILE_SIZE / (1024ULL * 1024ULL) - 1)); HTM_SCRIPT_End (); } /*****************************************************************************/ /************************ Write top heading of the page **********************/ /*****************************************************************************/ static void Lay_WritePageTopHeading (void) { extern const char *The_ClassTagline[The_NUM_THEMES]; extern const char *Txt_TAGLINE; extern const char *Txt_TAGLINE_BR; static const char *ClassHeadRow1[The_NUM_THEMES] = { [The_THEME_WHITE ] = "HEAD_ROW_1_WHITE", [The_THEME_GREY ] = "HEAD_ROW_1_GREY", [The_THEME_PURPLE] = "HEAD_ROW_1_PURPLE", [The_THEME_BLUE ] = "HEAD_ROW_1_BLUE", [The_THEME_YELLOW] = "HEAD_ROW_1_YELLOW", [The_THEME_PINK ] = "HEAD_ROW_1_PINK", }; static const char *ClassHeadRow2[The_NUM_THEMES] = { [The_THEME_WHITE ] = "HEAD_ROW_2_WHITE", [The_THEME_GREY ] = "HEAD_ROW_2_GREY", [The_THEME_PURPLE] = "HEAD_ROW_2_PURPLE", [The_THEME_BLUE ] = "HEAD_ROW_2_BLUE", [The_THEME_YELLOW] = "HEAD_ROW_2_YELLOW", [The_THEME_PINK ] = "HEAD_ROW_2_PINK", }; /***** Start header *****/ HTM_Txt ("
"); /***** 1st. row *****/ /* Start 1st. row */ HTM_DIV_Begin ("id=\"head_row_1\" class=\"%s\"",ClassHeadRow1[Gbl.Prefs.Theme]); /* 1st. row, 1st. column: logo, tagline and search */ HTM_DIV_Begin ("id=\"head_row_1_left\""); /* Begin form to go to home page */ Frm_StartFormGoTo (ActMnu); Par_PutHiddenParamUnsigned (NULL,"NxtTab",(unsigned) TabSys); HTM_DIV_Begin ("id=\"head_row_1_logo_small\""); HTM_INPUT_IMAGE (Cfg_URL_ICON_PUBLIC,Cfg_PLATFORM_LOGO_SMALL_FILENAME, Cfg_PLATFORM_SHORT_NAME,Cfg_PLATFORM_LOGO_SMALL_CLASS); HTM_DIV_End (); // head_row_1_logo_small HTM_DIV_Begin ("id=\"head_row_1_logo_big\""); HTM_INPUT_IMAGE (Cfg_URL_ICON_PUBLIC,Cfg_PLATFORM_LOGO_BIG_FILENAME, Cfg_PLATFORM_SHORT_NAME,Cfg_PLATFORM_LOGO_BIG_CLASS); HTM_DIV_End (); // head_row_1_logo_big HTM_DIV_Begin ("id=\"head_row_1_tagline\""); HTM_BUTTON_SUBMIT_Begin (Txt_TAGLINE,The_ClassTagline[Gbl.Prefs.Theme],NULL); HTM_Txt (Txt_TAGLINE_BR); HTM_BUTTON_End (); HTM_DIV_End (); // head_row_1_tagline /* End form to go to home page */ Frm_EndForm (); Sch_PutFormToSearchInPageTopHeading (); HTM_DIV_End (); // head_row_1_left /* 1st. row, 3rd. column: logged user or language selection, and link to open/close session */ HTM_DIV_Begin ("id=\"head_row_1_right\""); if (Gbl.Usrs.Me.Logged) Usr_WriteLoggedUsrHead (); else Lan_PutSelectorToSelectLanguage (); HTM_DIV_Begin ("id=\"login_box\""); if (Gbl.Usrs.Me.Logged) Usr_PutFormLogOut (); else Usr_PutFormLogIn (); HTM_DIV_End (); // login_box HTM_DIV_End (); // head_row_1_right /* End 1st. row */ HTM_DIV_End (); // head_row_1 /***** 2nd. row *****/ /* Start second row */ HTM_DIV_Begin ("id=\"head_row_2\" class=\"%s\"",ClassHeadRow2[Gbl.Prefs.Theme]); /* 2nd. row, 1st. column Clock with hour:minute (server hour is shown) */ HTM_DIV_Begin ("id=\"head_row_2_time\""); Dat_ShowClientLocalTime (); HTM_DIV_End (); // End first column /* 2nd. row, 2nd. column: degree and course */ HTM_DIV_Begin ("id=\"head_row_2_hierarchy\""); Lay_WriteBreadcrumb (); Hie_WriteBigNameCtyInsCtrDegCrs (); HTM_DIV_End (); /* 2nd. row, 3rd. column */ HTM_DIV_Begin ("id=\"msg\""); // Used for AJAX based refresh if (Gbl.Usrs.Me.Logged) Ntf_WriteNumberOfNewNtfs (); HTM_DIV_End (); // Used for AJAX based refresh /* End 2nd. row */ HTM_DIV_End (); /***** End header *****/ HTM_Txt ("
"); } /*****************************************************************************/ /*********** Write breadcrumb with the path to the current location **********/ /*****************************************************************************/ static void Lay_WriteBreadcrumb (void) { HTM_Txt (""); } /*****************************************************************************/ /*********** Write icon and title associated to the current action ***********/ /*****************************************************************************/ static void Lay_WriteTitleAction (void) { extern const char *The_ClassTitleAction[The_NUM_THEMES]; extern const char *The_ClassSubtitleAction[The_NUM_THEMES]; extern const char *Txt_TABS_TXT[Tab_NUM_TABS]; /***** Container start *****/ HTM_DIV_Begin ("id=\"action_title\" style=\"background-image:url('%s/%s');\"", Gbl.Prefs.URLIconSet, Act_GetIcon (Act_GetSuperAction (Gbl.Action.Act))); /***** Title *****/ HTM_DIV_Begin ("class=\"%s\"",The_ClassTitleAction[Gbl.Prefs.Theme]); HTM_TxtF ("%s > %s",Txt_TABS_TXT[Act_GetTab (Gbl.Action.Act)], Act_GetTitleAction (Gbl.Action.Act)); HTM_DIV_End (); /***** Subtitle *****/ HTM_DIV_Begin ("class=\"%s\"",The_ClassSubtitleAction[Gbl.Prefs.Theme]); HTM_Txt (Act_GetSubtitleAction (Gbl.Action.Act)); HTM_DIV_End (); /***** Container end *****/ HTM_DIV_End (); } /*****************************************************************************/ /***************************** Show left column ******************************/ /*****************************************************************************/ static void Lay_ShowLeftColumn (void) { struct MFU_ListMFUActions ListMFUActions; HTM_DIV_Begin ("style=\"width:160px;\""); HTM_DIV_Begin ("class=\"LEFT_RIGHT_CELL\""); if (Gbl.Usrs.Me.Logged) { /***** Most frequently used actions *****/ MFU_AllocateMFUActions (&ListMFUActions,6); MFU_GetMFUActions (&ListMFUActions,6); MFU_WriteSmallMFUActions (&ListMFUActions); MFU_FreeMFUActions (&ListMFUActions); } else /***** Institutional links *****/ Lnk_WriteMenuWithInstitutionalLinks (); HTM_DIV_End (); /***** Month *****/ HTM_DIV_Begin ("class=\"LEFT_RIGHT_CELL\""); Cal_DrawCurrentMonth (); HTM_DIV_End (); /***** Notices (yellow notes) *****/ if (Gbl.Hierarchy.Level == Hie_CRS) { HTM_DIV_Begin ("class=\"LEFT_RIGHT_CELL\""); Not_ShowNotices (Not_LIST_BRIEF_NOTICES, -1L); // No notice highlighted HTM_DIV_End (); } HTM_DIV_End (); } /*****************************************************************************/ /**************************** Show right column ******************************/ /*****************************************************************************/ static void Lay_ShowRightColumn (void) { extern const char *Txt_If_you_have_an_Android_device_try_SWADroid; // struct timeval tv1,tv2; // long tv_usecs; /***** Banners *****/ Ban_WriteMenuWithBanners (); /***** Number of connected users in the whole platform *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) { HTM_DIV_Begin ("id=\"globalconnected\" class=\"LEFT_RIGHT_CELL\""); // Used for AJAX based refresh Con_ShowGlobalConnectedUsrs (); HTM_DIV_End (); // Used for AJAX based refresh } /***** Number of connected users in the current course *****/ if (Gbl.Hierarchy.Level == Hie_CRS) // There is a course selected { HTM_DIV_Begin ("id=\"courseconnected\" class=\"LEFT_RIGHT_CELL\""); // Used for AJAX based refresh Gbl.Scope.Current = Hie_CRS; Con_ShowConnectedUsrsBelongingToCurrentCrs (); HTM_DIV_End (); // Used for AJAX based refresh } else if (Gbl.Usrs.Me.Logged) // I am logged { /* gettimeofday (&tv1,NULL); */ /***** Suggest one user to follow *****/ HTM_DIV_Begin ("class=\"LEFT_RIGHT_CELL\""); Fol_SuggestUsrsToFollowMainZoneOnRightColumn (); /* gettimeofday (&tv2,NULL); tv_usecs = (tv2.tv_sec - tv1.tv_sec ) * 1E6 + (tv2.tv_usec - tv1.tv_usec); DB_QueryINSERT ("can not debug", "INSERT INTO debug" " (DebugTime,Txt)" " VALUES" " (NOW(),'Fol_SuggestUsrsToFollowMainZoneOnRightColumn: %ld us')", tv_usecs); */ HTM_DIV_End (); } if (!Gbl.Usrs.Me.Logged) { /***** SWADroid advertisement *****/ HTM_DIV_Begin ("class=\"LEFT_RIGHT_CELL\""); HTM_A_Begin ("href=\"https://play.google.com/store/apps/details?id=es.ugr.swad.swadroid\"" " target=\"_blank\" title=\"%s\"", Txt_If_you_have_an_Android_device_try_SWADroid); HTM_IMG (Cfg_URL_ICON_PUBLIC,"SWADroid120x200.png","SWADroid", "style=\"width:150px; height:250px;\""); HTM_A_End (); HTM_DIV_End (); } } /*****************************************************************************/ /**************** Show an icon with a link in contextual menu ****************/ /*****************************************************************************/ void Lay_PutContextualLinkOnlyIcon (Act_Action_t NextAction,const char *Anchor, void (*FuncParams) (void), const char *Icon, const char *Title) { /***** Begin form *****/ Frm_StartFormAnchor (NextAction,Anchor); if (FuncParams) FuncParams (); /***** Put icon with link *****/ Ico_PutIconLink (Icon,Title); /***** End form *****/ Frm_EndForm (); } /*****************************************************************************/ /**************** Show an icon with a link in contextual menu ****************/ /*****************************************************************************/ void Lay_PutContextualLinkIconText (Act_Action_t NextAction,const char *Anchor, void (*FuncParams) (void), const char *Icon, const char *Text) { extern const char *The_ClassFormLinkOutBoxBold[The_NUM_THEMES]; /***** Separator *****/ HTM_Txt (" "); // This space is necessary to enable // jumping to the next line on narrow screens /***** Begin form *****/ Frm_StartFormAnchor (NextAction,Anchor); if (FuncParams) FuncParams (); /***** Put icon and text with link *****/ HTM_BUTTON_SUBMIT_Begin (Text,The_ClassFormLinkOutBoxBold[Gbl.Prefs.Theme],NULL); Ico_PutIconTextLink (Icon,Text); HTM_BUTTON_End (); /***** End form *****/ Frm_EndForm (); /***** Separator *****/ HTM_Txt (" "); // This space is necessary to enable // jumping to the next line on narrow screens } /*****************************************************************************/ /**************** Show an icon with a link in contextual menu ****************/ /*****************************************************************************/ void Lay_PutContextualLinkIconTextOnSubmit (Act_Action_t NextAction,const char *Anchor, void (*FuncParams) (void), const char *Icon, const char *Text, const char *OnSubmit) { extern const char *The_ClassFormLinkOutBoxBold[The_NUM_THEMES]; /***** Separator *****/ HTM_Txt (" "); // This space is necessary to enable // jumping to the next line on narrow screens /***** Begin form *****/ Frm_StartFormAnchor (NextAction,Anchor); if (FuncParams) FuncParams (); /***** Put icon with link *****/ HTM_BUTTON_SUBMIT_Begin (Text,The_ClassFormLinkOutBoxBold[Gbl.Prefs.Theme],OnSubmit); Ico_PutIconTextLink (Icon,Text); HTM_BUTTON_End (); /***** End form *****/ Frm_EndForm (); /***** Separator *****/ HTM_Txt (" "); // This space is necessary to enable // jumping to the next line on narrow screens } /*****************************************************************************/ /******************** Show a checkbox in contextual menu *********************/ /*****************************************************************************/ void Lay_PutContextualCheckbox (Act_Action_t NextAction, void (*FuncParams) (void), const char *CheckboxName, bool Checked,bool Disabled, const char *Title,const char *Text) { extern const char *The_ClassFormOutBoxBold[The_NUM_THEMES]; /***** Separator *****/ if (Text) HTM_Txt (" "); // This space is necessary to enable // jumping to the next line on narrow screens /***** Begin form *****/ Frm_StartForm (NextAction); if (FuncParams) FuncParams (); /***** Start container and label *****/ HTM_DIV_Begin ("class=\"CONTEXT_OPT %s %s\" title=\"%s\"", Checked ? "CHECKBOX_CHECKED" : "CHECKBOX_UNCHECKED", The_ClassFormOutBoxBold[Gbl.Prefs.Theme], Title); HTM_LABEL_Begin (NULL); /****** Checkbox *****/ HTM_INPUT_CHECKBOX (CheckboxName,true, "value=\"Y\"%s%s", Checked ? " checked=\"checked\"" : "", Disabled ? " disabled=\"disabled\"" : ""); /***** Text *****/ if (Text) if (Text[0]) HTM_TxtF (" %s",Text); /***** End label and container *****/ HTM_LABEL_End (); HTM_DIV_End (); /***** End form *****/ Frm_EndForm (); /***** Separator *****/ if (Text) HTM_Txt (" "); // This space is necessary to enable // jumping to the next line on narrow screens } /*****************************************************************************/ /********** Write error message and exit when not enough memory **************/ /*****************************************************************************/ void Lay_NotEnoughMemoryExit (void) { Lay_ShowErrorAndExit ("Not enough memory."); } /*****************************************************************************/ /************* Write error message and exit when wrong scope *****************/ /*****************************************************************************/ void Lay_WrongScopeExit (void) { Lay_ShowErrorAndExit ("Wrong scope."); } /*****************************************************************************/ /******* Write error message, close files, remove lock file, and exit ********/ /*****************************************************************************/ void Lay_ShowErrorAndExit (const char *Txt) { /***** Unlock tables if locked *****/ if (Gbl.DB.LockedTables) { Gbl.DB.LockedTables = false; mysql_query (&Gbl.mysql,"UNLOCK TABLES"); } if (!Gbl.WebService.IsWebService) { /****** If start of page is not written yet, do it now ******/ if (!Gbl.Layout.HTMLStartWritten) Lay_WriteStartOfPage (); /***** Write possible error message *****/ if (Txt) Ale_ShowAlert (Ale_ERROR,Txt); /***** Finish the page, except and *****/ Lay_WriteEndOfPage (); } /***** Free memory and close all the open files *****/ Gbl_Cleanup (); /***** Page is generated (except and ). Compute time to generate page *****/ if (!Gbl.Action.IsAJAXAutoRefresh) Sta_ComputeTimeToGeneratePage (); if (Gbl.WebService.IsWebService) // Serving a plugin request { /***** Log access *****/ Gbl.TimeSendInMicroseconds = 0L; Sta_LogAccess (Txt); } else { /***** Send page. The HTML output is now in Gbl.F.Out file ==> ==> copy it to standard output *****/ rewind (Gbl.F.Out); Fil_FastCopyOfOpenFiles (Gbl.F.Out,stdout); Fil_CloseAndRemoveFileForHTMLOutput (); if (!Gbl.Action.IsAJAXAutoRefresh) { /***** Compute time to send page *****/ Sta_ComputeTimeToSendPage (); /***** Log access *****/ Sta_LogAccess (Txt); /***** Update last data for next time *****/ if (Gbl.Usrs.Me.Logged) { Usr_UpdateMyLastData (); Crs_UpdateCrsLast (); } /***** End the output *****/ if (!Gbl.Layout.HTMLEndWritten) { // Here Gbl.F.Out is stdout if (Act_GetBrowserTab (Gbl.Action.Act) == Act_BRW_1ST_TAB) Lay_WriteAboutZone (); HTM_Txt ("\n" "\n"); Gbl.Layout.HTMLEndWritten = true; } } } /***** Close database connection *****/ DB_CloseDBConnection (); /***** Exit *****/ if (Gbl.WebService.IsWebService) API_Exit (Txt); exit (0); } /*****************************************************************************/ /***************** Write about zone at the end of the page *******************/ /*****************************************************************************/ static void Lay_WriteAboutZone (void) { extern const char *Txt_About_X; extern const char *Txt_Questions_and_problems; unsigned i; /***** Start about zone *****/ HTM_Txt ("
"); /***** Institution and centre hosting the platform *****/ HTM_A_Begin ("href=\"%s\" class=\"ABOUT\" target=\"_blank\"",Cfg_ABOUT_URL); HTM_IMG (Cfg_URL_ICON_PUBLIC,Cfg_ABOUT_LOGO,Cfg_ABOUT_NAME, "style=\"width:%upx; height:%upx;\"", Cfg_ABOUT_LOGO_WIDTH,Cfg_ABOUT_LOGO_HEIGHT); HTM_DIV_Begin (NULL); HTM_Txt (Cfg_ABOUT_NAME); HTM_DIV_End (); HTM_A_End (); /***** Questions and problems *****/ HTM_DIV_Begin (NULL); HTM_TxtF ("%s: ",Txt_Questions_and_problems); HTM_A_Begin ("href=\"mailto:%s\" class=\"ABOUT\" target=\"_blank\"", Cfg_PLATFORM_RESPONSIBLE_EMAIL); HTM_Txt (Cfg_PLATFORM_RESPONSIBLE_EMAIL); HTM_A_End (); HTM_DIV_End (); /***** About and time to generate and send page *****/ HTM_DIV_Begin (NULL); /* About */ HTM_A_Begin ("href=\"%s\" class=\"ABOUT\" target=\"_blank\"",Cfg_ABOUT_SWAD_URL); HTM_TxtF (Txt_About_X,Log_PLATFORM_VERSION); HTM_A_End (); for (i = 0; i < 5; i++) HTM_NBSP (); /* Time to generate and send page */ Sta_WriteTimeToGenerateAndSendPage (); HTM_DIV_End (); /***** End about zone *****/ HTM_Txt ("
"); // about_zone } /*****************************************************************************/ /*********** Refresh notifications and connected users via AJAX **************/ /*****************************************************************************/ void Lay_RefreshNotifsAndConnected (void) { unsigned NumUsr; bool ShowConnected = (Gbl.Prefs.SideCols & Lay_SHOW_RIGHT_COLUMN) && Gbl.Hierarchy.Level == Hie_CRS; // Right column visible && There is a course selected /***** Sometimes, someone must do this work, so who best than processes that refresh via AJAX? *****/ // We use (PID % prime-number) to do only one action as much if (!(Gbl.PID % 11)) Ntf_SendPendingNotifByEMailToAllUsrs (); // Send pending notifications by email else if (!(Gbl.PID % 19)) FW_PurgeFirewall (); // Remove old clicks from firewall else if (!(Gbl.PID % 23)) Fil_RemoveOldTmpFiles (Cfg_PATH_FILE_BROWSER_TMP_PUBLIC ,Cfg_TIME_TO_DELETE_BROWSER_TMP_FILES ,false); // Remove the oldest temporary public directories used for downloading else if (!(Gbl.PID % 101)) Brw_RemoveExpiredExpandedFolders (); // Remove old expanded folders (from all users) else if (!(Gbl.PID % 103)) Set_RemoveOldSettingsFromIP (); // Remove old settings from IP else if (!(Gbl.PID % 107)) Sta_RemoveOldEntriesRecentLog (); // Remove old entries in recent log table, it's a slow query else if (!(Gbl.PID % 109)) Fil_RemoveOldTmpFiles (Cfg_PATH_OUT_PRIVATE ,Cfg_TIME_TO_DELETE_HTML_OUTPUT ,false); else if (!(Gbl.PID % 113)) Fil_RemoveOldTmpFiles (Cfg_PATH_PHOTO_TMP_PUBLIC ,Cfg_TIME_TO_DELETE_PHOTOS_TMP_FILES ,false); else if (!(Gbl.PID % 127)) Fil_RemoveOldTmpFiles (Cfg_PATH_PHOTO_TMP_PRIVATE ,Cfg_TIME_TO_DELETE_PHOTOS_TMP_FILES ,false); else if (!(Gbl.PID % 131)) Fil_RemoveOldTmpFiles (Cfg_PATH_MEDIA_TMP_PRIVATE ,Cfg_TIME_TO_DELETE_MEDIA_TMP_FILES ,false); else if (!(Gbl.PID % 137)) Fil_RemoveOldTmpFiles (Cfg_PATH_ZIP_PRIVATE ,Cfg_TIME_TO_DELETE_BROWSER_ZIP_FILES ,false); else if (!(Gbl.PID % 139)) Fil_RemoveOldTmpFiles (Cfg_PATH_MARK_PRIVATE ,Cfg_TIME_TO_DELETE_MARKS_TMP_FILES ,false); else if (!(Gbl.PID % 149)) Fil_RemoveOldTmpFiles (Cfg_PATH_TEST_PRIVATE ,Cfg_TIME_TO_DELETE_TEST_TMP_FILES ,false); /***** Send, before the HTML, the refresh time *****/ HTM_TxtF ("%lu|",Gbl.Usrs.Connected.TimeToRefreshInMs); if (Gbl.Usrs.Me.Logged) Ntf_WriteNumberOfNewNtfs (); HTM_Txt ("|"); Con_ShowGlobalConnectedUsrs (); HTM_Txt ("|"); if (ShowConnected) { Gbl.Scope.Current = Hie_CRS; Con_ShowConnectedUsrsBelongingToCurrentCrs (); } HTM_Txt ("|"); if (ShowConnected) HTM_Unsigned (Gbl.Usrs.Connected.NumUsrsToList); HTM_Txt ("|"); if (ShowConnected) for (NumUsr = 0; NumUsr < Gbl.Usrs.Connected.NumUsrsToList; NumUsr++) HTM_TxtF ("%ld|",Gbl.Usrs.Connected.Lst[NumUsr].TimeDiff); } /*****************************************************************************/ /**************** Refresh last clicks in realtime via AJAX *******************/ /*****************************************************************************/ void Lay_RefreshLastClicks (void) { if (Gbl.Session.IsOpen) // If session has been closed, do not write anything { /***** Send, before the HTML, the refresh time *****/ HTM_TxtF ("%lu|",Cfg_TIME_TO_REFRESH_LAST_CLICKS); /***** Get and show last clicks *****/ Sta_GetAndShowLastClicks (); } } /*****************************************************************************/ /************************ Write the end of the page **************************/ /*****************************************************************************/ static void Lay_WriteFootFromHTMLFile (void) { FILE *FileHTML; /***** Open file with the HTML page for the chat *****/ if ((FileHTML = fopen (Cfg_PATH_AND_FILE_REL_HTML_PRIVATE,"rb"))) { HTM_Txt ("
"); /***** Copy HTML to output file *****/ Fil_FastCopyOfOpenFiles (FileHTML,Gbl.F.Out); fclose (FileHTML); HTM_Txt ("
"); } } /*****************************************************************************/ /****** Write header and footer of the class photo or academic calendar ******/ /*****************************************************************************/ void Lay_WriteHeaderClassPhoto (bool PrintView,bool DrawingClassPhoto, long InsCod,long DegCod,long CrsCod) { struct Instit Ins; struct Degree Deg; struct Course Crs; /***** Get data of institution *****/ Ins.InsCod = InsCod; Ins_GetDataOfInstitutionByCod (&Ins,Ins_GET_BASIC_DATA); /***** Get data of degree *****/ Deg.DegCod = DegCod; Deg_GetDataOfDegreeByCod (&Deg); /***** Get data of course *****/ Crs.CrsCod = CrsCod; Crs_GetDataOfCourseByCod (&Crs); /***** Begin table *****/ HTM_TABLE_BeginWidePadding (10); HTM_TR_Begin (NULL); /***** First column: institution logo *****/ HTM_TD_Begin ("class=\"LT\" style=\"width:60px;\""); if (InsCod > 0) { if (!PrintView) HTM_A_Begin ("href=\"%s\" target=\"_blank\"",Ins.WWW); Log_DrawLogo (Hie_INS,Ins.InsCod,Ins.ShrtName,40,NULL,true); if (!PrintView) HTM_A_End (); } HTM_TD_End (); /***** Second column: class photo title *****/ HTM_TD_Begin ("class=\"CLASSPHOTO_TITLE CM\""); if (InsCod > 0) { if (!PrintView) HTM_A_Begin ("href=\"%s\" target=\"_blank\" class=\"CLASSPHOTO_TITLE\"", Ins.WWW); HTM_Txt (Ins.FullName); if (!PrintView) HTM_A_End (); } if (DegCod > 0) { if (Ins.InsCod > 0) HTM_Txt (" - "); if (!PrintView) HTM_A_Begin ("href=\"%s\" target=\"_blank\" class=\"CLASSPHOTO_TITLE\"", Deg.WWW); HTM_Txt (Deg.FullName); if (!PrintView) HTM_A_End (); } HTM_BR (); if (CrsCod > 0) { HTM_Txt (Crs.FullName); if (DrawingClassPhoto && !Gbl.Usrs.ClassPhoto.AllGroups) { HTM_BR (); Grp_WriteNamesOfSelectedGrps (); } } HTM_TD_End (); /***** Third column: degree logo *****/ HTM_TD_Begin ("class=\"RT\" style=\"width:60px;\""); if (DegCod > 0) { if (!PrintView) HTM_A_Begin ("href=\"%s\" target=\"_blank\" class=\"CLASSPHOTO_TITLE\"", Deg.WWW); Log_DrawLogo (Hie_DEG,Deg.DegCod,Deg.ShrtName,40,NULL,true); if (!PrintView) HTM_A_End (); } HTM_TD_End (); /***** End table *****/ HTM_TR_End (); HTM_TABLE_End (); } /*****************************************************************************/ /**************** Show advertisement about mobile version ********************/ /*****************************************************************************/ #define Lay_SHOW_ADVERTISEMENT_ONE_TIME_OF_X 5 // n ==> show advertisement 1/n of the times void Lay_AdvertisementMobile (void) { extern const char *Txt_Stay_connected_with_SWADroid; if (!(rand () % Lay_SHOW_ADVERTISEMENT_ONE_TIME_OF_X)) { HTM_DIV_Begin ("style=\"margin-top:25px;\""); /***** Begin box and table *****/ Box_StartBoxTable (NULL,NULL,NULL, NULL,Box_NOT_CLOSABLE,8); /***** Show advertisement *****/ HTM_TR_Begin (NULL); HTM_TD_Begin ("class=\"DAT CM\""); HTM_A_Begin ("href=\"https://play.google.com/store/apps/details?id=es.ugr.swad.swadroid\"" " class=\"DAT\""); HTM_Txt (Txt_Stay_connected_with_SWADroid); HTM_BR (); HTM_BR (); HTM_IMG (Cfg_URL_ICON_PUBLIC,"SWADroid200x300.png",Txt_Stay_connected_with_SWADroid, "style=\"width:250px; height:375px;\""); HTM_A_End (); HTM_TD_End (); HTM_TR_End (); /***** End table and box *****/ Box_EndBoxTable (); HTM_DIV_End (); } } /*****************************************************************************/ /*********************** Indent forum or chat title **************************/ /*****************************************************************************/ // IsLastItemInLevel[] is a vector with at least 1 + Level booleans void Lay_IndentDependingOnLevel (unsigned Level,bool IsLastItemInLevel[]) { unsigned i; /***** Indent (from 1 to Level-1) *****/ for (i = 1; i < Level; i++) Ico_PutIcon (IsLastItemInLevel[i] ? "tr20x20.gif" : "subleft20x20.gif", "","ICO25x25"); /***** Level *****/ if (Level) Ico_PutIcon (IsLastItemInLevel[Level] ? "subend20x20.gif" : "submid20x20.gif", "","ICO25x25"); } /*****************************************************************************/ /************************** Help for the text editor *************************/ /*****************************************************************************/ void Lay_HelpPlainEditor (void) { extern const char *Txt_TEXT_plain; Lay_HelpTextEditor (Txt_TEXT_plain, "\\(LaTeX\\)", "$$LaTeX$$ \\[LaTeX\\]"); } void Lay_HelpRichEditor (void) { Lay_HelpTextEditor ("Markdown+Pandoc", "$LaTeX$", "$$LaTeX$$"); } static void Lay_HelpTextEditor (const char *Text,const char *InlineMath,const char *Equation) { extern const char *Txt_Text; extern const char *Txt_Inline_math; extern const char *Txt_Equation_centered; HTM_DIV_Begin ("class=\"HELP_EDIT\""); HTM_TxtF ("%s: %s" " " "%s: %s" " " "%s: %s", Txt_Text,Text, Txt_Inline_math,InlineMath, Txt_Equation_centered,Equation); HTM_DIV_End (); } /*****************************************************************************/ /************************** Help for the text editor *************************/ /*****************************************************************************/ void Lay_StartHTMLFile (FILE *File,const char *Title) { extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; fprintf (File,"\n" "\n" "\n" "\n" "%s\n" "\n", Lan_STR_LANG_ID[Gbl.Prefs.Language], // Language Title); // Page title }