// 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-2015 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, system, malloc, calloc, free, etc
#include // For string functions
#include "swad_action.h"
#include "swad_calendar.h"
#include "swad_changelog.h"
#include "swad_config.h"
#include "swad_connected.h"
#include "swad_database.h"
#include "swad_global.h"
#include "swad_logo.h"
#include "swad_notice.h"
#include "swad_notification.h"
#include "swad_parameter.h"
#include "swad_preference.h"
#include "swad_tab.h"
#include "swad_theme.h"
#include "swad_web_service.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
extern struct Act_Actions Act_Actions[Act_NUM_ACTIONS];
/*****************************************************************************/
/****************************** Public constants *****************************/
/*****************************************************************************/
const char *Lay_LayoutIcons[Lay_NUM_LAYOUTS] =
{
"desktop",
"mobile",
};
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
static void Lay_WriteEndOfPage (void);
static void Lay_WritePageTitle (void);
static void Lay_WriteRedirectionToMyLanguage (void);
static void Lay_WriteScripts (void);
static void Lay_WriteScriptInit (void);
static void Lay_WriteScriptConnectedUsrs (void);
static void Lay_WriteScriptCustomDropzone (void);
static void Lay_WritePageTopHeading (void);
static void Lay_WriteTitleAction (void);
static void Lay_ShowLeftColumn (void);
static void Lay_ShowRightColumn (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 *Txt_STR_LANG_ID[Txt_NUM_LANGUAGES];
extern const unsigned Txt_Current_CGI_SWAD_Language;
extern const char *The_TabOnBgColors[The_NUM_THEMES];
extern const char *Txt_NEW_YEAR_GREETING;
unsigned ColspanCentralPart = 3; // Initialized to avoid warnning
/***** 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 *****/
if (Gbl.CurrentAct == ActLstCon ||
(Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP &&
(Gbl.Prefs.SideCols & Lay_SHOW_RIGHT_COLUMN) &&
Gbl.CurrentCrs.Crs.CrsCod > 0))
// Right column visible && There is a course selected
Con_ComputeConnectedUsrsBelongingToCurrentCrs ();
/***** Send head width the file type for the HTTP protocol *****/
if (Gbl.CurrentAct == ActRefCon ||
Gbl.CurrentAct == ActRefLstClk)
// Don't generate a full HTML page, only refresh connected users
{
fprintf (Gbl.F.Out,"Content-Type: text/html; charset=windows-1252\r\n\r\n");
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = true;
return;
}
/***** If serving a web service ==> don't do anything *****/
if (Gbl.WebService.IsWebService)
{
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = 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
fprintf (Gbl.F.Out,"\n"
"\n"
"\n"
"\n"
"\n",
Txt_STR_LANG_ID[Gbl.Prefs.Language],
Cfg_PLATFORM_SHORT_NAME);
/* Title */
Lay_WritePageTitle ();
/* Canonical URL */
fprintf (Gbl.F.Out,"\n",
Cfg_HTTPS_URL_SWAD_CGI);
/* Favicon */
fprintf (Gbl.F.Out,"\n"
"\n",
Gbl.Prefs.IconsURL,
Gbl.Prefs.IconsURL);
/* Style sheet for SWAD */
fprintf (Gbl.F.Out,"\n",
Cfg_HTTPS_URL_SWAD_PUBLIC,
(Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) ? "swad_desktop.css" :
"swad_mobile.css");
/* 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
if (Gbl.CurrentAct == ActFrmCreDocIns || // Brw_ADMI_DOCUM_INS
Gbl.CurrentAct == ActFrmCreComIns || // Brw_ADMI_SHARE_INS
Gbl.CurrentAct == ActFrmCreDocCtr || // Brw_ADMI_DOCUM_CTR
Gbl.CurrentAct == ActFrmCreComCtr || // Brw_ADMI_SHARE_CTR
Gbl.CurrentAct == ActFrmCreDocDeg || // Brw_ADMI_DOCUM_DEG
Gbl.CurrentAct == ActFrmCreComDeg || // Brw_ADMI_SHARE_DEG
Gbl.CurrentAct == ActFrmCreDocCrs || // Brw_ADMI_DOCUM_CRS
Gbl.CurrentAct == ActFrmCreDocGrp || // Brw_ADMI_DOCUM_GRP
Gbl.CurrentAct == ActFrmCreComCrs || // Brw_ADMI_SHARE_CRS
Gbl.CurrentAct == ActFrmCreComGrp || // Brw_ADMI_SHARE_GRP
Gbl.CurrentAct == ActFrmCreAsgUsr || // Brw_ADMI_ASSIG_USR
Gbl.CurrentAct == ActFrmCreAsgCrs || // Brw_ADMI_ASSIG_CRS
Gbl.CurrentAct == ActFrmCreWrkUsr || // Brw_ADMI_WORKS_USR
Gbl.CurrentAct == ActFrmCreWrkCrs || // Brw_ADMI_WORKS_CRS
Gbl.CurrentAct == ActFrmCreMrkCrs || // Brw_ADMI_MARKS_CRS
Gbl.CurrentAct == ActFrmCreMrkGrp || // Brw_ADMI_MARKS_GRP
Gbl.CurrentAct == ActFrmCreBrf) // Brw_ADMI_BRIEF_USR
fprintf (Gbl.F.Out,"\n",
Cfg_HTTPS_URL_SWAD_PUBLIC);
/* Redirect to correct language */
if ((Gbl.CurrentAct == ActAutUsrInt ||
Gbl.CurrentAct == ActAutUsrExt) && // Action is log in
Gbl.Usrs.Me.Logged && // I am just logged
Gbl.Usrs.Me.UsrDat.Prefs.Language != Txt_Current_CGI_SWAD_Language) // My language != current language
Lay_WriteRedirectionToMyLanguage ();
/* Write initial scripts depending on the action */
Lay_WriteScripts ();
fprintf (Gbl.F.Out,"\n");
/***** HTML body *****/
fprintf (Gbl.F.Out,"\n");
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten =
Gbl.Layout.TablEndWritten = true;
return;
}
fprintf (Gbl.F.Out," onload=\"init()\">\n");
if (Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW)
fprintf (Gbl.F.Out,"
"
""
"
"
"
"
"
",
Gbl.Prefs.IconsURL);
/***** Header of layout *****/
fprintf (Gbl.F.Out,"
");
Lay_WritePageTopHeading ();
switch (Gbl.Prefs.Layout)
{
case Lay_LAYOUT_DESKTOP:
if (Gbl.Prefs.SideCols == Lay_SHOW_BOTH_COLUMNS)
ColspanCentralPart = 1; // 11: both side columns visible, left and right
else if (Gbl.Prefs.SideCols == Lay_HIDE_BOTH_COLUMNS)
ColspanCentralPart = 3; // 00: both side columns hidden
else
ColspanCentralPart = 2; // 10 or 01: only one side column visible, left or right
break;
case Lay_LAYOUT_MOBILE:
ColspanCentralPart = 3;
break;
default:
break;
}
fprintf (Gbl.F.Out,"
"
"
"
"
"
"
",
ColspanCentralPart,
The_TabOnBgColors[Gbl.Prefs.Theme]);
/***** Central (main) part *****/
switch (Gbl.Prefs.Layout)
{
case Lay_LAYOUT_DESKTOP:
/* Left bar used to expand-contract central zone */
fprintf (Gbl.F.Out,"
");
Usr_WarningWhenDegreeTypeDoesntAllowDirectLogin ();
if (Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu < 0) // Write vertical menu
{
if (Gbl.CurrentAct == ActMnu)
Mnu_WriteMenuThisTabMobile ();
else
Tab_DrawTabsMobile ();
}
break;
default:
break;
}
/***** Main zone *****/
/* Start of main zone for actions output */
fprintf (Gbl.F.Out,"
");
if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP &&
Gbl.Prefs.Menu == Mnu_MENU_HORIZONTAL)
Mnu_WriteHorizontalMenuThisTabDesktop ();
Usr_WarningWhenDegreeTypeDoesntAllowDirectLogin ();
/* If it is mandatory to read any information about course */
if (Gbl.CurrentCrs.Info.ShowMsgMustBeRead)
Inf_WriteMsgYouMustReadInfo ();
/* Write title of the current action */
if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP &&
Gbl.Prefs.Menu == Mnu_MENU_VERTICAL &&
Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu >= 0)
Lay_WriteTitleAction ();
Gbl.Layout.WritingHTMLStart = false;
Gbl.Layout.HTMLStartWritten = true;
/* Write new year greeting */
if (Gbl.CurrentAct == ActAutUsrInt ||
Gbl.CurrentAct == ActAutUsrExt ||
Gbl.CurrentAct == ActAutUsrChgLan)
if (Gbl.Now.Date.Month == 1 &&
Gbl.Now.Date.Day == 1)
{
fprintf (Gbl.F.Out,"
");
}
/* Write message indicating number of clicks allowed before sending my photo */
Usr_InformAboutNumClicksBeforePhoto ();
}
/*****************************************************************************/
/************************ Write the end of the page **************************/
/*****************************************************************************/
static void Lay_WriteEndOfPage (void)
{
if (!Gbl.Layout.TablEndWritten)
{
Gbl.Layout.TablEndWritten = true;
fprintf (Gbl.F.Out,"
");
if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP)
{
/* Right bar used to expand-contract central zone */
fprintf (Gbl.F.Out,"
");
Act_FormStart (ActLstCon);
Act_LinkFormSubmit (Txt_Connected_users,The_ClassConnected[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s",Txt_Connected_PLURAL);
Act_FormEnd ();
/***** Number of connected users in the whole platform *****/
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
Con_ShowGlobalConnectedUsrs ();
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
/***** Number of connected users in the current course *****/
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
if (Gbl.CurrentCrs.Crs.CrsCod > 0) // There is a course selected
{
Gbl.Scope.Current = Sco_SCOPE_CRS;
Con_ShowConnectedUsrsBelongingToScope ();
}
fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh
fprintf (Gbl.F.Out,"
");
}
/*****************************************************************************/
/**************** Put a icon with a text to submit a form ********************/
/*****************************************************************************/
void Lay_PutIconWithText (const char *Icon,const char *Alt,const char *Text)
{
// margin is used because this form link may be placed after another one
fprintf (Gbl.F.Out,"
"
"",
Gbl.Prefs.IconsURL,Icon,Alt);
if (Text)
if (Text[0])
fprintf (Gbl.F.Out," %s",
Text);
fprintf (Gbl.F.Out,"
"
"");
}
/*****************************************************************************/
/********** Put a icon with a text to submit a form. **********/
/********** When clicked, the icon will be replaced by an animation **********/
/*****************************************************************************/
void Lay_PutCalculateIconWithText (const char *Alt,const char *Text)
{
fprintf (Gbl.F.Out,"
"
""
"" // Animated icon hidden
" %s"
"
"
"",
Gbl.NumForm,Gbl.Prefs.IconsURL,Alt,
Gbl.NumForm,Gbl.Prefs.IconsURL,Alt,
Text);
}
/*****************************************************************************/
/********************** Put a button to submit a form ************************/
/*****************************************************************************/
void Lay_PutCreateButton (const char *Text)
{
fprintf (Gbl.F.Out,"
",
Text);
}
/*****************************************************************************/
/************ Write a centered message with the title of a table *************/
/*****************************************************************************/
void Lay_WriteTitle (const char *Title)
{
fprintf (Gbl.F.Out,"
"
"%s"
"
",
Title);
}
/*****************************************************************************/
/****************** Start and end a table with rounded frame *****************/
/*****************************************************************************/
// CellPadding must be 0, 1, 2, 4 or 8
void Lay_StartRoundFrameTable (const char *Width,unsigned CellPadding,const char *Title)
{
Lay_StartRoundFrame (Width,Title);
fprintf (Gbl.F.Out,"