diff --git a/css/swad22.16.css b/css/swad22.18.css
similarity index 99%
rename from css/swad22.16.css
rename to css/swad22.18.css
index 9a17f206..c3d485b2 100644
--- a/css/swad22.16.css
+++ b/css/swad22.18.css
@@ -1679,7 +1679,7 @@ a:hover img.CENTER_PHOTO_SHOW
.PRG_COL1
{
box-sizing:border-box;
- width:88px;
+ width:44px;
}
.PRG_TITLE_DESCRIPTION_WIDTH
diff --git a/js/swad21.100.js b/js/swad21.100.js
index 81b1ce73..bff1d497 100644
--- a/js/swad21.100.js
+++ b/js/swad21.100.js
@@ -4,7 +4,7 @@
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-2021 Antonio Cañas-Vargas
+ Copyright (C) 1999-2022 Antonio Cañas-Vargas
University of Granada (SPAIN) (acanas@ugr.es)
This program is free software: you can redistribute it and/or modify
diff --git a/swad_action.c b/swad_action.c
index 460984cd..dfec807d 100644
--- a/swad_action.c
+++ b/swad_action.c
@@ -443,6 +443,10 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] =
[ActDwnPrgItm ] = {1832,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_MoveDownItem ,NULL},
[ActLftPrgItm ] = {1834,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_MoveLeftItem ,NULL},
[ActRgtPrgItm ] = {1833,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_MoveRightItem ,NULL},
+ [ActExpSeePrgItm ] = {1944,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_ExpandItem ,NULL},
+ [ActExpEdiPrgItm ] = {1946,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_ExpandItem ,NULL},
+ [ActConSeePrgItm ] = {1945,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_ContractItem ,NULL},
+ [ActConEdiPrgItm ] = {1947,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_ContractItem ,NULL},
[ActFrmSeePrgRsc ] = {1925,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,PrgRsc_ViewResourcesAfterEdit ,NULL},
[ActFrmEdiPrgRsc ] = {1918,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,PrgRsc_EditResources ,NULL},
@@ -3798,6 +3802,10 @@ Act_Action_t Act_FromActCodToAction[1 + Act_MAX_ACTION_COD] = // Do not reuse un
ActReqLnkForCrsUsr, // #1941
ActSeeOneAsg, // #1942
ActReqLnkAsg, // #1943
+ ActExpSeePrgItm, // #1944
+ ActConSeePrgItm, // #1945
+ ActExpEdiPrgItm, // #1946
+ ActConEdiPrgItm, // #1947
};
/*****************************************************************************/
diff --git a/swad_action.h b/swad_action.h
index f9a4ff46..985f9693 100644
--- a/swad_action.h
+++ b/swad_action.h
@@ -65,7 +65,7 @@ typedef enum
typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to indicate obsolete action
-#define Act_MAX_ACTION_COD 1943
+#define Act_MAX_ACTION_COD 1947
#define Act_MAX_OPTIONS_IN_MENU_PER_TAB 13
@@ -410,119 +410,123 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to
#define ActDwnPrgItm (ActChgCrsSta + 27)
#define ActLftPrgItm (ActChgCrsSta + 28)
#define ActRgtPrgItm (ActChgCrsSta + 29)
-#define ActFrmSeePrgRsc (ActChgCrsSta + 30)
-#define ActFrmEdiPrgRsc (ActChgCrsSta + 31)
-#define ActNewPrgRsc (ActChgCrsSta + 32)
-#define ActRenPrgRsc (ActChgCrsSta + 33)
-#define ActReqRemPrgRsc (ActChgCrsSta + 34)
-#define ActRemPrgRsc (ActChgCrsSta + 35)
-#define ActHidPrgRsc (ActChgCrsSta + 36)
-#define ActUnhPrgRsc (ActChgCrsSta + 37)
-#define ActUp_PrgRsc (ActChgCrsSta + 38)
-#define ActDwnPrgRsc (ActChgCrsSta + 39)
-#define ActSeeCliPrgRsc (ActChgCrsSta + 40)
-#define ActChgLnkPrgRsc (ActChgCrsSta + 41)
-#define ActEdiTchGui (ActChgCrsSta + 42)
-#define ActSeeSylLec (ActChgCrsSta + 43)
-#define ActSeeSylPra (ActChgCrsSta + 44)
-#define ActEdiSylLec (ActChgCrsSta + 45)
-#define ActEdiSylPra (ActChgCrsSta + 46)
-#define ActDelItmSylLec (ActChgCrsSta + 47)
-#define ActDelItmSylPra (ActChgCrsSta + 48)
-#define ActUp_IteSylLec (ActChgCrsSta + 49)
-#define ActUp_IteSylPra (ActChgCrsSta + 50)
-#define ActDwnIteSylLec (ActChgCrsSta + 51)
-#define ActDwnIteSylPra (ActChgCrsSta + 52)
-#define ActRgtIteSylLec (ActChgCrsSta + 53)
-#define ActRgtIteSylPra (ActChgCrsSta + 54)
-#define ActLftIteSylLec (ActChgCrsSta + 55)
-#define ActLftIteSylPra (ActChgCrsSta + 56)
-#define ActInsIteSylLec (ActChgCrsSta + 57)
-#define ActInsIteSylPra (ActChgCrsSta + 58)
-#define ActModIteSylLec (ActChgCrsSta + 59)
-#define ActModIteSylPra (ActChgCrsSta + 60)
+#define ActExpSeePrgItm (ActChgCrsSta + 30)
+#define ActConSeePrgItm (ActChgCrsSta + 31)
+#define ActExpEdiPrgItm (ActChgCrsSta + 32)
+#define ActConEdiPrgItm (ActChgCrsSta + 33)
+#define ActFrmSeePrgRsc (ActChgCrsSta + 34)
+#define ActFrmEdiPrgRsc (ActChgCrsSta + 35)
+#define ActNewPrgRsc (ActChgCrsSta + 36)
+#define ActRenPrgRsc (ActChgCrsSta + 37)
+#define ActReqRemPrgRsc (ActChgCrsSta + 38)
+#define ActRemPrgRsc (ActChgCrsSta + 39)
+#define ActHidPrgRsc (ActChgCrsSta + 40)
+#define ActUnhPrgRsc (ActChgCrsSta + 41)
+#define ActUp_PrgRsc (ActChgCrsSta + 42)
+#define ActDwnPrgRsc (ActChgCrsSta + 43)
+#define ActSeeCliPrgRsc (ActChgCrsSta + 44)
+#define ActChgLnkPrgRsc (ActChgCrsSta + 45)
+#define ActEdiTchGui (ActChgCrsSta + 46)
+#define ActSeeSylLec (ActChgCrsSta + 47)
+#define ActSeeSylPra (ActChgCrsSta + 48)
+#define ActEdiSylLec (ActChgCrsSta + 49)
+#define ActEdiSylPra (ActChgCrsSta + 50)
+#define ActDelItmSylLec (ActChgCrsSta + 51)
+#define ActDelItmSylPra (ActChgCrsSta + 52)
+#define ActUp_IteSylLec (ActChgCrsSta + 53)
+#define ActUp_IteSylPra (ActChgCrsSta + 54)
+#define ActDwnIteSylLec (ActChgCrsSta + 55)
+#define ActDwnIteSylPra (ActChgCrsSta + 56)
+#define ActRgtIteSylLec (ActChgCrsSta + 57)
+#define ActRgtIteSylPra (ActChgCrsSta + 58)
+#define ActLftIteSylLec (ActChgCrsSta + 59)
+#define ActLftIteSylPra (ActChgCrsSta + 60)
+#define ActInsIteSylLec (ActChgCrsSta + 61)
+#define ActInsIteSylPra (ActChgCrsSta + 62)
+#define ActModIteSylLec (ActChgCrsSta + 63)
+#define ActModIteSylPra (ActChgCrsSta + 64)
-#define ActEdiBib (ActChgCrsSta + 61)
-#define ActEdiFAQ (ActChgCrsSta + 62)
-#define ActEdiCrsLnk (ActChgCrsSta + 63)
+#define ActEdiBib (ActChgCrsSta + 65)
+#define ActEdiFAQ (ActChgCrsSta + 66)
+#define ActEdiCrsLnk (ActChgCrsSta + 67)
-#define ActChgFrcReaCrsInf (ActChgCrsSta + 64)
-#define ActChgFrcReaTchGui (ActChgCrsSta + 65)
-#define ActChgFrcReaSylLec (ActChgCrsSta + 66)
-#define ActChgFrcReaSylPra (ActChgCrsSta + 67)
-#define ActChgFrcReaBib (ActChgCrsSta + 68)
-#define ActChgFrcReaFAQ (ActChgCrsSta + 69)
-#define ActChgFrcReaCrsLnk (ActChgCrsSta + 70)
+#define ActChgFrcReaCrsInf (ActChgCrsSta + 68)
+#define ActChgFrcReaTchGui (ActChgCrsSta + 69)
+#define ActChgFrcReaSylLec (ActChgCrsSta + 70)
+#define ActChgFrcReaSylPra (ActChgCrsSta + 71)
+#define ActChgFrcReaBib (ActChgCrsSta + 72)
+#define ActChgFrcReaFAQ (ActChgCrsSta + 73)
+#define ActChgFrcReaCrsLnk (ActChgCrsSta + 74)
-#define ActChgHavReaCrsInf (ActChgCrsSta + 71)
-#define ActChgHavReaTchGui (ActChgCrsSta + 72)
-#define ActChgHavReaSylLec (ActChgCrsSta + 73)
-#define ActChgHavReaSylPra (ActChgCrsSta + 74)
-#define ActChgHavReaBib (ActChgCrsSta + 75)
-#define ActChgHavReaFAQ (ActChgCrsSta + 76)
-#define ActChgHavReaCrsLnk (ActChgCrsSta + 77)
+#define ActChgHavReaCrsInf (ActChgCrsSta + 75)
+#define ActChgHavReaTchGui (ActChgCrsSta + 76)
+#define ActChgHavReaSylLec (ActChgCrsSta + 77)
+#define ActChgHavReaSylPra (ActChgCrsSta + 78)
+#define ActChgHavReaBib (ActChgCrsSta + 79)
+#define ActChgHavReaFAQ (ActChgCrsSta + 80)
+#define ActChgHavReaCrsLnk (ActChgCrsSta + 81)
-#define ActSelInfSrcCrsInf (ActChgCrsSta + 78)
-#define ActSelInfSrcTchGui (ActChgCrsSta + 79)
-#define ActSelInfSrcSylLec (ActChgCrsSta + 80)
-#define ActSelInfSrcSylPra (ActChgCrsSta + 81)
-#define ActSelInfSrcBib (ActChgCrsSta + 82)
-#define ActSelInfSrcFAQ (ActChgCrsSta + 83)
-#define ActSelInfSrcCrsLnk (ActChgCrsSta + 84)
-#define ActRcvURLCrsInf (ActChgCrsSta + 85)
-#define ActRcvURLTchGui (ActChgCrsSta + 86)
-#define ActRcvURLSylLec (ActChgCrsSta + 87)
-#define ActRcvURLSylPra (ActChgCrsSta + 88)
-#define ActRcvURLBib (ActChgCrsSta + 89)
-#define ActRcvURLFAQ (ActChgCrsSta + 90)
-#define ActRcvURLCrsLnk (ActChgCrsSta + 91)
-#define ActRcvPagCrsInf (ActChgCrsSta + 92)
-#define ActRcvPagTchGui (ActChgCrsSta + 93)
-#define ActRcvPagSylLec (ActChgCrsSta + 94)
-#define ActRcvPagSylPra (ActChgCrsSta + 95)
-#define ActRcvPagBib (ActChgCrsSta + 96)
-#define ActRcvPagFAQ (ActChgCrsSta + 97)
-#define ActRcvPagCrsLnk (ActChgCrsSta + 98)
-#define ActEditorCrsInf (ActChgCrsSta + 99)
-#define ActEditorTchGui (ActChgCrsSta + 100)
-#define ActEditorSylLec (ActChgCrsSta + 101)
-#define ActEditorSylPra (ActChgCrsSta + 102)
-#define ActEditorBib (ActChgCrsSta + 103)
-#define ActEditorFAQ (ActChgCrsSta + 104)
-#define ActEditorCrsLnk (ActChgCrsSta + 105)
-#define ActPlaTxtEdiCrsInf (ActChgCrsSta + 106)
-#define ActPlaTxtEdiTchGui (ActChgCrsSta + 107)
-#define ActPlaTxtEdiSylLec (ActChgCrsSta + 108)
-#define ActPlaTxtEdiSylPra (ActChgCrsSta + 109)
-#define ActPlaTxtEdiBib (ActChgCrsSta + 110)
-#define ActPlaTxtEdiFAQ (ActChgCrsSta + 111)
-#define ActPlaTxtEdiCrsLnk (ActChgCrsSta + 112)
-#define ActRchTxtEdiCrsInf (ActChgCrsSta + 113)
-#define ActRchTxtEdiTchGui (ActChgCrsSta + 114)
-#define ActRchTxtEdiSylLec (ActChgCrsSta + 115)
-#define ActRchTxtEdiSylPra (ActChgCrsSta + 116)
-#define ActRchTxtEdiBib (ActChgCrsSta + 117)
-#define ActRchTxtEdiFAQ (ActChgCrsSta + 118)
-#define ActRchTxtEdiCrsLnk (ActChgCrsSta + 119)
-#define ActRcvPlaTxtCrsInf (ActChgCrsSta + 120)
-#define ActRcvPlaTxtTchGui (ActChgCrsSta + 121)
-#define ActRcvPlaTxtSylLec (ActChgCrsSta + 122)
-#define ActRcvPlaTxtSylPra (ActChgCrsSta + 123)
-#define ActRcvPlaTxtBib (ActChgCrsSta + 124)
-#define ActRcvPlaTxtFAQ (ActChgCrsSta + 125)
-#define ActRcvPlaTxtCrsLnk (ActChgCrsSta + 126)
-#define ActRcvRchTxtCrsInf (ActChgCrsSta + 127)
-#define ActRcvRchTxtTchGui (ActChgCrsSta + 128)
-#define ActRcvRchTxtSylLec (ActChgCrsSta + 129)
-#define ActRcvRchTxtSylPra (ActChgCrsSta + 130)
-#define ActRcvRchTxtBib (ActChgCrsSta + 131)
-#define ActRcvRchTxtFAQ (ActChgCrsSta + 132)
-#define ActRcvRchTxtCrsLnk (ActChgCrsSta + 133)
+#define ActSelInfSrcCrsInf (ActChgCrsSta + 82)
+#define ActSelInfSrcTchGui (ActChgCrsSta + 83)
+#define ActSelInfSrcSylLec (ActChgCrsSta + 84)
+#define ActSelInfSrcSylPra (ActChgCrsSta + 85)
+#define ActSelInfSrcBib (ActChgCrsSta + 86)
+#define ActSelInfSrcFAQ (ActChgCrsSta + 87)
+#define ActSelInfSrcCrsLnk (ActChgCrsSta + 88)
+#define ActRcvURLCrsInf (ActChgCrsSta + 89)
+#define ActRcvURLTchGui (ActChgCrsSta + 90)
+#define ActRcvURLSylLec (ActChgCrsSta + 91)
+#define ActRcvURLSylPra (ActChgCrsSta + 92)
+#define ActRcvURLBib (ActChgCrsSta + 93)
+#define ActRcvURLFAQ (ActChgCrsSta + 94)
+#define ActRcvURLCrsLnk (ActChgCrsSta + 95)
+#define ActRcvPagCrsInf (ActChgCrsSta + 96)
+#define ActRcvPagTchGui (ActChgCrsSta + 97)
+#define ActRcvPagSylLec (ActChgCrsSta + 98)
+#define ActRcvPagSylPra (ActChgCrsSta + 99)
+#define ActRcvPagBib (ActChgCrsSta + 100)
+#define ActRcvPagFAQ (ActChgCrsSta + 101)
+#define ActRcvPagCrsLnk (ActChgCrsSta + 102)
+#define ActEditorCrsInf (ActChgCrsSta + 103)
+#define ActEditorTchGui (ActChgCrsSta + 104)
+#define ActEditorSylLec (ActChgCrsSta + 105)
+#define ActEditorSylPra (ActChgCrsSta + 106)
+#define ActEditorBib (ActChgCrsSta + 107)
+#define ActEditorFAQ (ActChgCrsSta + 108)
+#define ActEditorCrsLnk (ActChgCrsSta + 109)
+#define ActPlaTxtEdiCrsInf (ActChgCrsSta + 110)
+#define ActPlaTxtEdiTchGui (ActChgCrsSta + 111)
+#define ActPlaTxtEdiSylLec (ActChgCrsSta + 112)
+#define ActPlaTxtEdiSylPra (ActChgCrsSta + 113)
+#define ActPlaTxtEdiBib (ActChgCrsSta + 114)
+#define ActPlaTxtEdiFAQ (ActChgCrsSta + 115)
+#define ActPlaTxtEdiCrsLnk (ActChgCrsSta + 116)
+#define ActRchTxtEdiCrsInf (ActChgCrsSta + 117)
+#define ActRchTxtEdiTchGui (ActChgCrsSta + 118)
+#define ActRchTxtEdiSylLec (ActChgCrsSta + 119)
+#define ActRchTxtEdiSylPra (ActChgCrsSta + 120)
+#define ActRchTxtEdiBib (ActChgCrsSta + 121)
+#define ActRchTxtEdiFAQ (ActChgCrsSta + 122)
+#define ActRchTxtEdiCrsLnk (ActChgCrsSta + 123)
+#define ActRcvPlaTxtCrsInf (ActChgCrsSta + 124)
+#define ActRcvPlaTxtTchGui (ActChgCrsSta + 125)
+#define ActRcvPlaTxtSylLec (ActChgCrsSta + 126)
+#define ActRcvPlaTxtSylPra (ActChgCrsSta + 127)
+#define ActRcvPlaTxtBib (ActChgCrsSta + 128)
+#define ActRcvPlaTxtFAQ (ActChgCrsSta + 129)
+#define ActRcvPlaTxtCrsLnk (ActChgCrsSta + 130)
+#define ActRcvRchTxtCrsInf (ActChgCrsSta + 131)
+#define ActRcvRchTxtTchGui (ActChgCrsSta + 132)
+#define ActRcvRchTxtSylLec (ActChgCrsSta + 133)
+#define ActRcvRchTxtSylPra (ActChgCrsSta + 134)
+#define ActRcvRchTxtBib (ActChgCrsSta + 135)
+#define ActRcvRchTxtFAQ (ActChgCrsSta + 136)
+#define ActRcvRchTxtCrsLnk (ActChgCrsSta + 137)
-#define ActPrnCrsTT (ActChgCrsSta + 134)
-#define ActEdiCrsTT (ActChgCrsSta + 135)
-#define ActChgCrsTT (ActChgCrsSta + 136)
-#define ActChgCrsTT1stDay (ActChgCrsSta + 137)
+#define ActPrnCrsTT (ActChgCrsSta + 138)
+#define ActEdiCrsTT (ActChgCrsSta + 139)
+#define ActChgCrsTT (ActChgCrsSta + 140)
+#define ActChgCrsTT1stDay (ActChgCrsSta + 141)
/*****************************************************************************/
/***************************** Assessment tab ********************************/
diff --git a/swad_assignment_resource.c b/swad_assignment_resource.c
new file mode 100644
index 00000000..e8f33780
--- /dev/null
+++ b/swad_assignment_resource.c
@@ -0,0 +1,130 @@
+// swad_assignment_resource.c: links to assignments as program resources
+
+/*
+ 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-2022 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 "swad_alert.h"
+#include "swad_assignment.h"
+#include "swad_assignment_database.h"
+#include "swad_error.h"
+#include "swad_form.h"
+#include "swad_pagination.h"
+#include "swad_program_database.h"
+
+/*****************************************************************************/
+/************************** Get link to assignment ***************************/
+/*****************************************************************************/
+
+void AsgRsc_GetLinkToAssignment (void)
+ {
+ extern const char *Txt_Link_to_resource_X_copied_into_clipboard;
+ struct Asg_Assignments Assignments;
+ char Title[Asg_MAX_BYTES_ASSIGNMENT_TITLE + 1];
+
+ /***** Reset assignments *****/
+ Asg_ResetAssignments (&Assignments);
+
+ /***** Get parameters *****/
+ Assignments.SelectedOrder = Asg_GetParamAsgOrder ();
+ Grp_GetParamWhichGroups ();
+ Assignments.CurrentPage = Pag_GetParamPagNum (Pag_ASSIGNMENTS);
+
+ /***** Get assignment code *****/
+ if ((Assignments.AsgCod = Asg_GetParamAsgCod ()) <= 0)
+ Err_WrongAssignmentExit ();
+
+ /***** Get assignment title *****/
+ Asg_DB_GetAssignmentTitleByCod (Assignments.AsgCod,Title);
+
+ /***** Copy link to assignment into resource clipboard *****/
+ Prg_DB_CopyToClipboard (PrgRsc_ASSIGNMENT,Assignments.AsgCod);
+
+ /***** Write sucess message *****/
+ Ale_ShowAlert (Ale_SUCCESS,Txt_Link_to_resource_X_copied_into_clipboard,
+ Title);
+
+ /***** Show selected assignment in a box *****/
+ Asg_ShowOneAssignmentInBox (&Assignments);
+
+ /***** Show current assignments, if any *****/
+ Asg_ShowAllAssignments (&Assignments);
+ }
+
+/*****************************************************************************/
+/********************* Write assignment in course program ********************/
+/*****************************************************************************/
+
+void AsgRsc_WriteAssignmentInCrsProgram (long AsgCod,bool PutFormToGo,
+ const char *Icon,const char *IconTitle)
+ {
+ extern const char *Txt_Actions[Act_NUM_ACTIONS];
+ char Title[Asg_MAX_BYTES_ASSIGNMENT_TITLE + 1];
+
+ /***** Get assignment title *****/
+ Asg_DB_GetAssignmentTitleByCod (AsgCod,Title);
+
+ /***** Begin form to go to assignment *****/
+ if (PutFormToGo)
+ {
+ Frm_BeginForm (ActSeeOneAsg);
+ Asg_PutParamAsgCod (AsgCod);
+ // TODO: In the listing of assignments, the page is always the first.
+ // The page should be that corresponding to the selected assignment.
+ HTM_BUTTON_Submit_Begin (Txt_Actions[ActSeeOneAsg],
+ "class=\"LM BT_LINK PRG_RSC_%s\"",
+ The_GetSuffix ());
+ }
+
+ /***** Icon depending on type ******/
+ if (PutFormToGo)
+ Ico_PutIconLink (Icon,Ico_BLACK,ActSeeOneAsg);
+ else
+ Ico_PutIconOn (Icon,Ico_BLACK,IconTitle);
+
+ /***** Write assignment title of exam *****/
+ HTM_Txt (Title);
+
+ /***** End form to download file *****/
+ if (PutFormToGo)
+ {
+ /* End form */
+ HTM_BUTTON_End ();
+
+ Frm_EndForm ();
+ }
+ }
+
+/*****************************************************************************/
+/**************** Get assignment title from assignment code ******************/
+/*****************************************************************************/
+
+void AsgRsc_GetTitleFromAsgCod (long AsgCod,char *Title,size_t TitleSize)
+ {
+ char TitleFromDB[Asg_MAX_BYTES_ASSIGNMENT_TITLE + 1];
+
+ /***** Get assignment title *****/
+ Asg_DB_GetAssignmentTitleByCod (AsgCod,TitleFromDB);
+ Str_Copy (Title,TitleFromDB,TitleSize);
+ }
diff --git a/swad_assignment_resource.h b/swad_assignment_resource.h
new file mode 100644
index 00000000..527030cb
--- /dev/null
+++ b/swad_assignment_resource.h
@@ -0,0 +1,42 @@
+// swad_assignment_resource.h: links to assignments as program resources
+
+#ifndef _SWAD_ASG_RSC
+#define _SWAD_ASG_RSC
+/*
+ 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-2022 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 boolean type
+#include // For size_t
+
+/*****************************************************************************/
+/***************************** Public prototypes *****************************/
+/*****************************************************************************/
+
+void Asg_GetLinkToAssignment (void);
+void Asg_WriteAssignmentInCrsProgram (long AsgCod,bool PutFormToGo,
+ const char *Icon,const char *IconTitle);
+void Asg_GetTitleFromAsgCod (long AsgCod,char *Title,size_t TitleSize);
+
+#endif
diff --git a/swad_browser.c b/swad_browser.c
index ad1933fd..ba02cfed 100644
--- a/swad_browser.c
+++ b/swad_browser.c
@@ -4901,9 +4901,11 @@ static void Brw_PutIconToExpandFolder (const char *FileBrowserId,const char *Row
/***** Begin container *****/
if (Hidden)
- HTM_DIV_Begin ("id=\"expand_%s_%s\" style=\"display:none;\"",FileBrowserId,RowId);
+ HTM_DIV_Begin ("id=\"expand_%s_%s\" style=\"display:none;\"",
+ FileBrowserId,RowId);
else
- HTM_DIV_Begin ("id=\"expand_%s_%s\"",FileBrowserId,RowId);
+ HTM_DIV_Begin ("id=\"expand_%s_%s\"",
+ FileBrowserId,RowId);
/***** Form and icon *****/
snprintf (JavaScriptFuncToExpandFolder,sizeof (JavaScriptFuncToExpandFolder),
@@ -4913,7 +4915,8 @@ static void Brw_PutIconToExpandFolder (const char *FileBrowserId,const char *Row
FileBrowserId,
JavaScriptFuncToExpandFolder); // JavaScript function to unhide rows
Brw_PutImplicitParamsFileBrowser (&Gbl.FileBrowser.FilFolLnk);
- Ico_PutIconLink ("caret-right.svg",Ico_BLACK,Brw_ActExpandFolder[Gbl.FileBrowser.Type]);
+ Ico_PutIconLink ("caret-right.svg",Ico_BLACK,
+ Brw_ActExpandFolder[Gbl.FileBrowser.Type]);
Frm_EndForm ();
/***** End container *****/
@@ -4931,8 +4934,7 @@ static void Brw_PutIconToContractFolder (const char *FileBrowserId,const char *R
/***** Begin container *****/
if (Hidden)
- HTM_DIV_Begin ("id=\"contract_%s_%s\""
- " style=\"display:none;\"",
+ HTM_DIV_Begin ("id=\"contract_%s_%s\" style=\"display:none;\"",
FileBrowserId,RowId);
else
HTM_DIV_Begin ("id=\"contract_%s_%s\"",
@@ -4946,7 +4948,8 @@ static void Brw_PutIconToContractFolder (const char *FileBrowserId,const char *R
FileBrowserId,
JavaScriptFuncToContractFolder); // JavaScript function to hide rows
Brw_PutImplicitParamsFileBrowser (&Gbl.FileBrowser.FilFolLnk);
- Ico_PutIconLink ("caret-down.svg",Ico_BLACK,Brw_ActContractFolder[Gbl.FileBrowser.Type]);
+ Ico_PutIconLink ("caret-down.svg",Ico_BLACK,
+ Brw_ActContractFolder[Gbl.FileBrowser.Type]);
Frm_EndForm ();
/***** End container *****/
diff --git a/swad_browser_database.c b/swad_browser_database.c
index cac5ba0e..75097923 100644
--- a/swad_browser_database.c
+++ b/swad_browser_database.c
@@ -2429,7 +2429,7 @@ bool Brw_DB_GetIfExpandedFolder (const char Path[PATH_MAX + 1])
{
if (WorksUsrCod > 0)
return
- DB_QueryEXISTS ("can not check check if a folder is expanded",
+ DB_QueryEXISTS ("can not check if a folder is expanded",
"SELECT EXISTS"
"(SELECT *"
" FROM brw_expanded"
@@ -2445,7 +2445,7 @@ bool Brw_DB_GetIfExpandedFolder (const char Path[PATH_MAX + 1])
Path);
else
return
- DB_QueryEXISTS ("can not get check if a folder is expanded",
+ DB_QueryEXISTS ("can not check if a folder is expanded",
"SELECT EXISTS"
"(SELECT *"
" FROM brw_expanded"
@@ -2460,7 +2460,7 @@ bool Brw_DB_GetIfExpandedFolder (const char Path[PATH_MAX + 1])
}
else // Briefcase
return
- DB_QueryEXISTS ("can not get check if a folder is expanded",
+ DB_QueryEXISTS ("can not check if a folder is expanded",
"SELECT EXISTS"
"(SELECT *"
" FROM brw_expanded"
diff --git a/swad_changelog.h b/swad_changelog.h
index 24cc22a8..cd4c33f0 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -606,10 +606,16 @@ TODO: Fix bug: error al enviar un mensaje a dos recipientes, error on duplicate
TODO: Attach pdf files in multimedia.
*/
-#define Log_PLATFORM_VERSION "SWAD 22.17 (2022-09-21)"
-#define CSS_FILE "swad22.16.css"
+#define Log_PLATFORM_VERSION "SWAD 22.18 (2022-09-21)"
+#define CSS_FILE "swad22.18.css"
#define JS_FILE "swad21.100.js"
/*
+ Version 22.18: Sep 22, 2022 Expand/contract program items. (331877 lines)
+ 1 change necessary in database:
+CREATE TABLE IF NOT EXISTS prg_expanded (UsrCod INT NOT NULL,ItmCod INT NOT NULL,ClickTime DATETIME NOT NULL,UNIQUE INDEX(UsrCod,ItmCod),INDEX(ItmCod),INDEX(ClickTime));
+ If you want to use MyISAM:
+ALTER TABLE prg_expanded ENGINE=MyISAM;
+
Version 22.17: Sep 21, 2022 New module swad_assignment_resource. (331524 lines)
Version 22.16.1: Sep 21, 2022 Changes in program layout. (331462 lines)
Version 22.16: Sep 21, 2022 Changes in program layout. (331455 lines)
diff --git a/swad_database.c b/swad_database.c
index 099d67a1..38ab575d 100644
--- a/swad_database.c
+++ b/swad_database.c
@@ -2484,6 +2484,27 @@ mysql> DESCRIBE prg_clipboards;
"INDEX(CrsCod,Type,Cod),"
"INDEX(CopyTime))");
+ /***** Table prg_expanded *****/
+/*
+mysql> DESCRIBE prg_expanded;
++-----------+----------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++-----------+----------+------+-----+---------+-------+
+| UsrCod | int | NO | PRI | NULL | |
+| ItmCod | int | NO | PRI | NULL | |
+| ClickTime | datetime | NO | MUL | NULL | |
++-----------+----------+------+-----+---------+-------+
+3 rows in set (0,00 sec)
+
+*/
+ DB_CreateTable ("CREATE TABLE IF NOT EXISTS prg_expanded ("
+ "UsrCod INT NOT NULL,"
+ "ItmCod INT NOT NULL,"
+ "ClickTime DATETIME NOT NULL,"
+ "UNIQUE INDEX(UsrCod,ItmCod),"
+ "INDEX(ItmCod),"
+ "INDEX(ClickTime))");
+
/***** Table prg_items *****/
/*
mysql> DESCRIBE prg_items;
diff --git a/swad_icon.c b/swad_icon.c
index f3d1b4d0..3732795a 100644
--- a/swad_icon.c
+++ b/swad_icon.c
@@ -299,6 +299,22 @@ void Ico_PutContextualIconToHideUnhide (const Act_Action_t NextAction[2],const c
Icon[Hidden],Color[Hidden]);
}
+void Ico_PutContextualIconToExpand (const Act_Action_t NextAction,const char *Anchor,
+ void (*FuncParams) (void *Args),void *Args)
+ {
+ Lay_PutContextualLinkOnlyIcon (NextAction,Anchor,
+ FuncParams,Args,
+ "caret-right.svg",Ico_BLACK);
+ }
+
+void Ico_PutContextualIconToContract (const Act_Action_t NextAction,const char *Anchor,
+ void (*FuncParams) (void *Args),void *Args)
+ {
+ Lay_PutContextualLinkOnlyIcon (NextAction,Anchor,
+ FuncParams,Args,
+ "caret-down.svg",Ico_BLACK);
+ }
+
void Ico_PutContextualIconToPrint (Act_Action_t NextAction,
void (*FuncParams) (void *Args),void *Args)
{
diff --git a/swad_icon.h b/swad_icon.h
index 6013ee19..6bf8df32 100644
--- a/swad_icon.h
+++ b/swad_icon.h
@@ -79,6 +79,10 @@ void Ico_PutContextualIconToConfigure (Act_Action_t NextAction,
void Ico_PutContextualIconToHideUnhide (const Act_Action_t NextAction[2],const char *Anchor,
void (*FuncParams) (void *Args),void *Args,
bool Hidden);
+void Ico_PutContextualIconToExpand (const Act_Action_t NextAction,const char *Anchor,
+ void (*FuncParams) (void *Args),void *Args);
+void Ico_PutContextualIconToContract (const Act_Action_t NextAction,const char *Anchor,
+ void (*FuncParams) (void *Args),void *Args);
void Ico_PutContextualIconToPrint (Act_Action_t NextAction,
void (*FuncParams) (void *Args),void *Args);
void Ico_PutContextualIconToGetLink (Act_Action_t NextAction,const char *Anchor,
diff --git a/swad_program.c b/swad_program.c
index 4a3d6feb..6ca9488d 100644
--- a/swad_program.c
+++ b/swad_program.c
@@ -71,6 +71,7 @@ typedef enum
struct Level
{
unsigned Number; // Numbers for each level from 1 to maximum level
+ bool Expanded; // If each level from 1 to maximum level is expanded
bool Hidden; // If each level from 1 to maximum level is hidden
};
@@ -102,6 +103,7 @@ static struct
};
static const char *Prg_ITEM_SECTION_ID = "item_section";
+static const char *Prg_HIGHLIGHTED_SECTION_ID = "prg_highlighted";
/*****************************************************************************/
/***************************** Private prototypes ****************************/
@@ -116,7 +118,12 @@ static void Prg_PutButtonToCreateNewItem (void);
static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
unsigned NumItem,struct Prg_Item *Item,
+ bool HasChildren,
+ bool Expanded,
+ long SelectedItmCod,
long SelectedRscCod);
+static void Prg_PutIconToContractExpandItem (struct Prg_Item *Item,
+ bool Expanded,bool Editing);
static void Prg_WriteItemText (long ItmCod,bool LightStyle);
static void Prg_WriteRowToCreateItem (long ParentItmCod,unsigned FormLevel);
static void Prg_SetTitleClass (char **TitleClass,unsigned Level,bool LightStyle);
@@ -132,8 +139,12 @@ static unsigned Prg_GetCurrentNumberInLevel (unsigned Level);
static void Prg_WriteNumItem (unsigned Level);
static void Prg_WriteNumNewItem (unsigned Level);
+static void Prg_SetExpandedLevel (unsigned Level,bool Expanded);
static void Prg_SetHiddenLevel (unsigned Level,bool Hidden);
+static bool Prg_GetExpandedLevel (unsigned Level);
static bool Prg_GetHiddenLevel (unsigned Level);
+
+static bool Prg_CheckIfAllHigherLevelsAreExpanded (unsigned CurrentLevel);
static bool Prg_CheckIfAnyHigherLevelIsHidden (unsigned CurrentLevel);
static void Prg_PutFormsToRemEditOneItem (Prg_ListingType_t ListingType,
@@ -158,6 +169,8 @@ static int Prg_GetNextBrother (int NumItem);
static void Prg_MoveLeftRightItem (Prg_MoveLeftRight_t LeftRight);
+static void Prg_ExpandContractItem (Prg_ExpandContract_t ExpandContract);
+
static void Prg_SetItemRangeOnlyItem (unsigned NumItem,struct Prg_ItemRange *ItemRange);
static void Prg_SetItemRangeWithAllChildren (unsigned NumItem,struct Prg_ItemRange *ItemRange);
static unsigned Prg_GetLastChild (int NumItem);
@@ -211,9 +224,10 @@ void Prg_ShowAllItems (Prg_ListingType_t ListingType,
long ParentItmCod = -1L; // Initialized to avoid warning
unsigned NumItem;
unsigned FormLevel = 0; // Initialized to avoid warning
- Prg_ListingType_t LT;
struct Prg_Item Item;
struct Prg_ItemRange ToHighlight;
+ bool HasChildren;
+ bool Expanded;
char *Title;
static bool FirstTBodyOpen = false;
static void (*FunctionToDrawContextualIcons[Prg_NUM_LISTING_TYPES]) (void *Args) =
@@ -241,6 +255,7 @@ void Prg_ShowAllItems (Prg_ListingType_t ListingType,
ToHighlight.End = 0;
switch (ListingType)
{
+ case Prg_VIEW:
case Prg_EDIT_ITEMS:
if (SelectedItmCod > 0)
Prg_SetItemRangeWithAllChildren (Prg_GetNumItemFromItmCod (SelectedItmCod),
@@ -258,7 +273,7 @@ void Prg_ShowAllItems (Prg_ListingType_t ListingType,
case Prg_FORM_NEW_CHILD_ITEM:
ParentItmCod = SelectedItmCod; // Item code here is parent of the item to create
NumItem = Prg_GetNumItemFromItmCod (SelectedItmCod);
- SelectedItmCod = Prg_Gbl.List.Items[Prg_GetLastChild (NumItem)].ItmCod;
+ SelectedItmCod = Prg_GetItmCodFromNumItem (Prg_GetLastChild (NumItem));
FormLevel = Prg_GetLevelFromNumItem (NumItem) + 1;
break;
default:
@@ -286,11 +301,19 @@ void Prg_ShowAllItems (Prg_ListingType_t ListingType,
/***** Write all program items *****/
for (NumItem = 0, The_ResetRowColor ();
NumItem < Prg_Gbl.List.NumItems;
- NumItem++, The_ChangeRowColor ())
+ NumItem++)
{
/* Get data of this program item */
- Item.Hierarchy.ItmCod = Prg_Gbl.List.Items[NumItem].ItmCod;
+ Item.Hierarchy.ItmCod = Prg_GetItmCodFromNumItem (NumItem);
Prg_GetDataOfItemByCod (&Item);
+ if (NumItem == Prg_Gbl.List.NumItems - 1)
+ // The last item
+ HasChildren = false; // Last item has no children
+ else
+ // Not the last item
+ // This item has children if its level is lower than the level of the following item
+ HasChildren = (Prg_GetLevelFromNumItem (NumItem) <
+ Prg_GetLevelFromNumItem (NumItem + 1));
/* Begin range to highlight? */
if (Item.Hierarchy.ItmInd == ToHighlight.Begin) // Begin of the highlighted range
@@ -300,32 +323,29 @@ void Prg_ShowAllItems (Prg_ListingType_t ListingType,
HTM_TBODY_End (); // 1st tbody end
FirstTBodyOpen = false;
}
- HTM_TBODY_Begin ("id=\"prg_highlighted\""); // Highlighted tbody start
+ HTM_TBODY_Begin ("id=\"%s\"",
+ Prg_HIGHLIGHTED_SECTION_ID); // Highlighted tbody start
}
- /* Write row with this item */
- LT = ListingType;
- switch (ListingType)
- {
- case Prg_FORM_EDIT_ITEM:
- case Prg_EDIT_RESOURCES:
- case Prg_EDIT_RESOURCE_LINK:
- case Prg_CHANGE_RESOURCE_LINK:
- case Prg_END_EDIT_RES:
- if (Item.Hierarchy.ItmCod != SelectedItmCod)
- LT = Prg_EDIT_ITEMS;
- break;
- default:
- break;
- }
- Prg_WriteRowItem (LT,NumItem,&Item,SelectedRscCod);
+ /* Set if this level is expanded */
+ Expanded = Prg_DB_GetIfExpandedItem (Item.Hierarchy.ItmCod);
+ Prg_SetExpandedLevel (Item.Hierarchy.Level,Expanded);
- /* Show form to create child item? */
- if (ListingType == Prg_FORM_NEW_CHILD_ITEM &&
- Item.Hierarchy.ItmCod == SelectedItmCod)
+ /* Show this row only if all higher levels are expanded */
+ if (Prg_CheckIfAllHigherLevelsAreExpanded (Item.Hierarchy.Level))
{
- The_ChangeRowColor ();
- Prg_WriteRowToCreateItem (ParentItmCod,FormLevel);
+ /* Write row with this item */
+ Prg_WriteRowItem (ListingType,NumItem,&Item,HasChildren,Expanded,
+ SelectedItmCod,SelectedRscCod);
+ The_ChangeRowColor ();
+
+ /* Show form to create child item? */
+ if (ListingType == Prg_FORM_NEW_CHILD_ITEM &&
+ Item.Hierarchy.ItmCod == SelectedItmCod)
+ {
+ Prg_WriteRowToCreateItem (ParentItmCod,FormLevel);
+ The_ChangeRowColor ();
+ }
}
/* End range to highlight? */
@@ -346,8 +366,16 @@ void Prg_ShowAllItems (Prg_ListingType_t ListingType,
HTM_TABLE_End ();
/***** Button to create a new program item *****/
- if (Prg_CheckIfICanEditProgram ())
- Prg_PutButtonToCreateNewItem ();
+ switch (ListingType)
+ {
+ case Prg_PRINT:
+ case Prg_VIEW:
+ break;
+ default:
+ if (Prg_CheckIfICanEditProgram ())
+ Prg_PutButtonToCreateNewItem ();
+ break;
+ }
/***** End box *****/
Box_BoxEnd ();
@@ -450,10 +478,13 @@ static void Prg_PutButtonToCreateNewItem (void)
static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
unsigned NumItem,struct Prg_Item *Item,
+ bool HasChildren,
+ bool Expanded,
+ long SelectedItmCod,
long SelectedRscCod)
{
static unsigned UniqueId = 0;
- static bool PutFormsToRemEditOneItem[Prg_NUM_LISTING_TYPES] =
+ static bool Editing[Prg_NUM_LISTING_TYPES] =
{
[Prg_PRINT ] = false,
[Prg_VIEW ] = false,
@@ -474,6 +505,7 @@ static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
unsigned NumCol;
char *TitleClass;
Dat_StartEndTime_t StartEndTime;
+ bool HighlightItem;
/***** Check if this item should be shown as hidden *****/
Prg_SetHiddenLevel (Item->Hierarchy.Level,Item->Hierarchy.Hidden);
@@ -488,18 +520,14 @@ static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
/***** Increase number in level *****/
Prg_IncreaseNumberInLevel (Item->Hierarchy.Level);
+ /***** Is this the item selected? *****/
+ HighlightItem = Item->Hierarchy.ItmCod == SelectedItmCod &&
+ (ListingType == Prg_FORM_EDIT_ITEM ||
+ ListingType == Prg_END_EDIT_ITEM);
+
/***** Begin row *****/
HTM_TR_Begin (NULL);
- /***** Forms to remove/edit this program item *****/
- if (PutFormsToRemEditOneItem[ListingType])
- {
- HTM_TD_Begin ("rowspan=\"2\" class=\"PRG_COL1 LT %s\"",
- The_GetColorRows ());
- Prg_PutFormsToRemEditOneItem (ListingType,NumItem,Item);
- HTM_TD_End ();
- }
-
/***** Indent depending on the level *****/
for (NumCol = 1;
NumCol < Item->Hierarchy.Level;
@@ -509,6 +537,22 @@ static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
HTM_TD_End ();
}
+ /***** Expand/contract this program item *****/
+ HTM_TD_Begin ("rowspan=\"2\" class=\"LT %s\"",The_GetColorRows ());
+ /* Only if this item has children ==> show icon to contract/expand */
+ if (HasChildren)
+ Prg_PutIconToContractExpandItem (Item,Expanded,Editing[ListingType]);
+ HTM_TD_End ();
+
+ /***** Forms to remove/edit this program item *****/
+ if (Editing[ListingType])
+ {
+ HTM_TD_Begin ("rowspan=\"2\" class=\"PRG_COL1 LT %s\"",
+ The_GetColorRows ());
+ Prg_PutFormsToRemEditOneItem (ListingType,NumItem,Item);
+ HTM_TD_End ();
+ }
+
/***** Item number *****/
HTM_TD_Begin ("rowspan=\"2\" class=\"PRG_NUM %s RT %s\"",
TitleClass,The_GetColorRows ());
@@ -528,12 +572,10 @@ static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
default:
HTM_TD_Begin ("colspan=\"%u\" class=\"PRG_MAIN %s %s\"",
ColSpan,TitleClass,The_GetColorRows ());
- if (ListingType == Prg_FORM_EDIT_ITEM ||
- ListingType == Prg_END_EDIT_ITEM)
+ if (HighlightItem)
HTM_ARTICLE_Begin (Prg_ITEM_SECTION_ID);
HTM_Txt (Item->Title);
- if (ListingType == Prg_FORM_EDIT_ITEM ||
- ListingType == Prg_END_EDIT_ITEM)
+ if (HighlightItem)
HTM_ARTICLE_End ();
HTM_TD_End ();
break;
@@ -597,17 +639,12 @@ static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
}
/* Item text / form */
- switch (ListingType)
- {
- case Prg_FORM_EDIT_ITEM:
- /* Form to change item title, dates and text */
- Prg_ShowFormToChangeItem (Item->Hierarchy.ItmCod);
- break;
- default:
- /* Text */
- Prg_WriteItemText (Item->Hierarchy.ItmCod,LightStyle);
- break;
- }
+ if (ListingType == Prg_FORM_EDIT_ITEM && HighlightItem)
+ /* Form to change item title, dates and text */
+ Prg_ShowFormToChangeItem (Item->Hierarchy.ItmCod);
+ else
+ /* Text */
+ Prg_WriteItemText (Item->Hierarchy.ItmCod,LightStyle);
/* List of resources */
PrgRsc_ListItemResources (ListingType,Item,SelectedRscCod);
@@ -622,6 +659,32 @@ static void Prg_WriteRowItem (Prg_ListingType_t ListingType,
Prg_FreeTitleClass (TitleClass);
}
+/*****************************************************************************/
+/************************ Put icon to expand an item *************************/
+/*****************************************************************************/
+
+static void Prg_PutIconToContractExpandItem (struct Prg_Item *Item,
+ bool Expanded,bool Editing)
+ {
+ static Act_Action_t NextAction[2][2] =
+ {
+ [false][false] = ActExpSeePrgItm, // Contracted, Not editing ==> action to expand
+ [false][true ] = ActExpEdiPrgItm, // Contracted, Editing ==> action to expand
+ [true ][false] = ActConSeePrgItm, // Expanded , Not editing ==> action to contract
+ [true ][true ] = ActConEdiPrgItm, // Expanded , Editing ==> action to contract
+ };
+ static void (*PutContextualIcon[2]) (const Act_Action_t NextAction,const char *Anchor,
+ void (*FuncParams) (void *Args),void *Args) =
+ {
+ [false] = Ico_PutContextualIconToExpand, // Contracted ==> function to expand
+ [true ] = Ico_PutContextualIconToContract, // Expanded ==> function to contract
+ };
+
+ /***** Icon to hide/unhide program item *****/
+ PutContextualIcon[Expanded] (NextAction[Expanded][Editing],Prg_HIGHLIGHTED_SECTION_ID,
+ Prg_PutParamItmCod,&Item->Hierarchy.ItmCod);
+ }
+
/*****************************************************************************/
/**************************** Show item text *********************************/
/*****************************************************************************/
@@ -659,6 +722,10 @@ static void Prg_WriteRowToCreateItem (long ParentItmCod,unsigned FormLevel)
/***** Begin row *****/
HTM_TR_Begin (NULL);
+ /***** Column under expand/contract icon *****/
+ HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ());
+ HTM_TD_End ();
+
/***** Column under icons *****/
HTM_TD_Begin ("class=\"PRG_COL1 LT %s\"",The_GetColorRows ());
HTM_TD_End ();
@@ -764,7 +831,7 @@ static void Prg_CreateLevels (void)
MaxLevel = 4
Level Number
----- ------
- 0 <--- Not used
+ 0 N.A. <--- Root level
1 2
2 5
3 2
@@ -836,14 +903,36 @@ static void Prg_WriteNumNewItem (unsigned Level)
/********************** Set / Get if a level is hidden ***********************/
/*****************************************************************************/
+static void Prg_SetExpandedLevel (unsigned Level,bool Expanded)
+ {
+ if (Prg_Gbl.Levels)
+ Prg_Gbl.Levels[Level].Expanded = Expanded;
+ }
+
static void Prg_SetHiddenLevel (unsigned Level,bool Hidden)
{
if (Prg_Gbl.Levels)
Prg_Gbl.Levels[Level].Hidden = Hidden;
}
+static bool Prg_GetExpandedLevel (unsigned Level)
+ {
+ /* Level 0 (root) is always expanded */
+ if (Level == 0)
+ return true;
+
+ if (Prg_Gbl.Levels)
+ return Prg_Gbl.Levels[Level].Expanded;
+
+ return false;
+ }
+
static bool Prg_GetHiddenLevel (unsigned Level)
{
+ /* Level 0 (root) is always visible */
+ if (Level == 0)
+ return false;
+
if (Prg_Gbl.Levels)
return Prg_Gbl.Levels[Level].Hidden;
@@ -854,6 +943,19 @@ static bool Prg_GetHiddenLevel (unsigned Level)
/********* Check if any level higher than the current one is hidden **********/
/*****************************************************************************/
+static bool Prg_CheckIfAllHigherLevelsAreExpanded (unsigned CurrentLevel)
+ {
+ unsigned Level;
+
+ for (Level = 1;
+ Level < CurrentLevel;
+ Level++)
+ if (!Prg_GetExpandedLevel (Level)) // Contracted?
+ return false; // A level is contracted. Not all are expanded
+
+ return true; // None is contracted. All are expanded
+ }
+
static bool Prg_CheckIfAnyHigherLevelIsHidden (unsigned CurrentLevel)
{
unsigned Level;
@@ -895,7 +997,7 @@ static void Prg_PutFormsToRemEditOneItem (Prg_ListingType_t ListingType,
Prg_PutParamItmCod,&Item->Hierarchy.ItmCod);
/***** Icon to hide/unhide program item *****/
- Ico_PutContextualIconToHideUnhide (ActionHideUnhide,"prg_highlighted",
+ Ico_PutContextualIconToHideUnhide (ActionHideUnhide,Prg_HIGHLIGHTED_SECTION_ID,
Prg_PutParamItmCod,&Item->Hierarchy.ItmCod,
Item->Hierarchy.Hidden);
@@ -920,7 +1022,7 @@ static void Prg_PutFormsToRemEditOneItem (Prg_ListingType_t ListingType,
/***** Icon to move up the item *****/
if (Prg_CheckIfMoveUpIsAllowed (NumItem))
- Lay_PutContextualLinkOnlyIcon (ActUp_PrgItm,"prg_highlighted",
+ Lay_PutContextualLinkOnlyIcon (ActUp_PrgItm,Prg_HIGHLIGHTED_SECTION_ID,
Prg_PutParamItmCod,&Item->Hierarchy.ItmCod,
"arrow-up.svg",Ico_BLACK);
else
@@ -928,7 +1030,7 @@ static void Prg_PutFormsToRemEditOneItem (Prg_ListingType_t ListingType,
/***** Icon to move down the item *****/
if (Prg_CheckIfMoveDownIsAllowed (NumItem))
- Lay_PutContextualLinkOnlyIcon (ActDwnPrgItm,"prg_highlighted",
+ Lay_PutContextualLinkOnlyIcon (ActDwnPrgItm,Prg_HIGHLIGHTED_SECTION_ID,
Prg_PutParamItmCod,&Item->Hierarchy.ItmCod,
"arrow-down.svg",Ico_BLACK);
else
@@ -936,7 +1038,7 @@ static void Prg_PutFormsToRemEditOneItem (Prg_ListingType_t ListingType,
/***** Icon to move left item (increase level) *****/
if (Prg_CheckIfMoveLeftIsAllowed (NumItem))
- Lay_PutContextualLinkOnlyIcon (ActLftPrgItm,"prg_highlighted",
+ Lay_PutContextualLinkOnlyIcon (ActLftPrgItm,Prg_HIGHLIGHTED_SECTION_ID,
Prg_PutParamItmCod,&Item->Hierarchy.ItmCod,
"arrow-left.svg",Ico_BLACK);
else
@@ -944,7 +1046,7 @@ static void Prg_PutFormsToRemEditOneItem (Prg_ListingType_t ListingType,
/***** Icon to move right item (indent, decrease level) *****/
if (Prg_CheckIfMoveRightIsAllowed (NumItem))
- Lay_PutContextualLinkOnlyIcon (ActRgtPrgItm,"prg_highlighted",
+ Lay_PutContextualLinkOnlyIcon (ActRgtPrgItm,Prg_HIGHLIGHTED_SECTION_ID,
Prg_PutParamItmCod,&Item->Hierarchy.ItmCod,
"arrow-right.svg",Ico_BLACK);
else
@@ -1098,7 +1200,7 @@ void Prg_GetListItems (void)
/* Get index of the program item (row[1])
and level of the program item (row[2]) */
Prg_Gbl.List.Items[NumItem].ItmInd = Str_ConvertStrToUnsigned (row[1]);
- Prg_Gbl.List.Items[NumItem].Level = Str_ConvertStrToUnsigned (row[2]);
+ Prg_Gbl.List.Items[NumItem].Level = Str_ConvertStrToUnsigned (row[2]);
/* Get whether the program item is hidden or not (row[3]) */
Prg_Gbl.List.Items[NumItem].Hidden = (row[3][0] == 'Y');
@@ -1249,7 +1351,7 @@ unsigned Prg_GetNumItemFromItmCod (long ItmCod)
for (NumItem = 0;
NumItem < Prg_Gbl.List.NumItems;
NumItem++)
- if (Prg_Gbl.List.Items[NumItem].ItmCod == ItmCod) // Found!
+ if (Prg_GetItmCodFromNumItem (NumItem) == ItmCod) // Found!
return NumItem;
/***** Not found *****/
@@ -1257,6 +1359,24 @@ unsigned Prg_GetNumItemFromItmCod (long ItmCod)
return 0; // Not reached
}
+/*****************************************************************************/
+/******************** Get item code from number of item **********************/
+/*****************************************************************************/
+
+inline long Prg_GetItmCodFromNumItem (unsigned NumItem)
+ {
+ return Prg_Gbl.List.Items[NumItem].ItmCod;
+ }
+
+/*****************************************************************************/
+/******************** Get item index from number of item *********************/
+/*****************************************************************************/
+
+inline unsigned Prg_GetItmIndFromNumItem (unsigned NumItem)
+ {
+ return Prg_Gbl.List.Items[NumItem].ItmInd;
+ }
+
/*****************************************************************************/
/****************** Get level of item from number of item ********************/
/*****************************************************************************/
@@ -1539,7 +1659,7 @@ static int Prg_GetPrevBrother (int NumItem)
if (Prg_GetLevelFromNumItem (i) == Level)
return i; // Previous brother before item found
if (Prg_GetLevelFromNumItem (i) < Level)
- return -1; // Previous lower level found ==> there are no brothers before item
+ return -1; // Previous lower level found ==> there are no brothers before item
}
return -1; // Start reached ==> there are no brothers before item
}
@@ -1636,6 +1756,63 @@ static void Prg_MoveLeftRightItem (Prg_MoveLeftRight_t LeftRight)
Prg_FreeListItems ();
}
+/*****************************************************************************/
+/************** Move a subtree to left/right in a course program *************/
+/*****************************************************************************/
+
+void Prg_ExpandItem (void)
+ {
+ Prg_ExpandContractItem (Prg_EXPAND);
+ }
+
+void Prg_ContractItem (void)
+ {
+ Prg_ExpandContractItem (Prg_CONTRACT);
+ }
+
+static void Prg_ExpandContractItem (Prg_ExpandContract_t ExpandContract)
+ {
+ struct Prg_Item Item;
+ Prg_ListingType_t ListingType;
+
+ /***** Get list of program items *****/
+ Prg_GetListItems ();
+
+ /***** Get program item *****/
+ Prg_GetParams (&Item);
+ if (Item.Hierarchy.ItmCod <= 0)
+ Err_WrongItemExit ();
+
+ /***** Add/remove item to/from table of expanded items *****/
+ switch (ExpandContract)
+ {
+ case Prg_EXPAND:
+ Prg_DB_InsertItemInExpandedItems (Item.Hierarchy.ItmCod);
+ break;
+ case Prg_CONTRACT:
+ Prg_DB_RemoveItemFromExpandedItems (Item.Hierarchy.ItmCod);
+ break;
+ }
+
+ /***** Show program items highlighting subtree *****/
+ switch (Gbl.Action.Act)
+ {
+ case ActExpEdiPrgItm:
+ case ActConEdiPrgItm:
+ ListingType = Prg_EDIT_ITEMS;
+ break;
+ case ActExpSeePrgItm:
+ case ActConSeePrgItm:
+ default:
+ ListingType = Prg_VIEW;
+ break;
+ }
+ Prg_ShowAllItems (ListingType,Item.Hierarchy.ItmCod,-1L);
+
+ /***** Free list of program items *****/
+ Prg_FreeListItems ();
+ }
+
/*****************************************************************************/
/****** Set subtree begin and end from number of item in course program ******/
/*****************************************************************************/
@@ -1652,7 +1829,7 @@ static void Prg_SetItemRangeOnlyItem (unsigned NumItem,struct Prg_ItemRange *Ite
/***** Range includes only this item *****/
ItemRange->Begin =
- ItemRange->End = Prg_Gbl.List.Items[NumItem].ItmInd;
+ ItemRange->End = Prg_GetItmIndFromNumItem (NumItem);
}
static void Prg_SetItemRangeWithAllChildren (unsigned NumItem,struct Prg_ItemRange *ItemRange)
@@ -1666,8 +1843,8 @@ static void Prg_SetItemRangeWithAllChildren (unsigned NumItem,struct Prg_ItemRan
Err_WrongItemExit ();
/***** Range includes this item and all its children *****/
- ItemRange->Begin = Prg_Gbl.List.Items[NumItem ].ItmInd;
- ItemRange->End = Prg_Gbl.List.Items[Prg_GetLastChild (NumItem)].ItmInd;
+ ItemRange->Begin = Prg_GetItmIndFromNumItem (NumItem);
+ ItemRange->End = Prg_GetItmIndFromNumItem (Prg_GetLastChild (NumItem));
}
/*****************************************************************************/
@@ -1753,6 +1930,10 @@ void Prg_RequestCreateItem (void)
/***** Get program item *****/
Prg_GetParams (&Item);
+ /***** Add item to table of expanded items
+ to ensure that child items are displayed *****/
+ Prg_DB_InsertItemInExpandedItems (Item.Hierarchy.ItmCod);
+
/***** Show current program items, if any *****/
Prg_ShowAllItems (Item.Hierarchy.ItmCod > 0 ? Prg_FORM_NEW_CHILD_ITEM :
Prg_FORM_NEW_END_ITEM,
@@ -1793,7 +1974,7 @@ static void Prg_ShowFormToCreateItem (long ParentItmCod)
Ale_ShowAlerts (NULL);
/***** Begin form *****/
- Frm_BeginFormAnchor (ActNewPrgItm,"prg_highlighted");
+ Frm_BeginFormAnchor (ActNewPrgItm,Prg_HIGHLIGHTED_SECTION_ID);
Prg_PutParamItmCod (&ParentItem.Hierarchy.ItmCod);
/***** Begin box and table *****/
@@ -1837,7 +2018,7 @@ static void Prg_ShowFormToChangeItem (long ItmCod)
// Ale_ShowAlerts (NULL);
/***** Begin form *****/
- Frm_BeginFormAnchor (ActChgPrgItm,"prg_highlighted");
+ Frm_BeginFormAnchor (ActChgPrgItm,Prg_HIGHLIGHTED_SECTION_ID);
Prg_PutParamItmCod (&Item.Hierarchy.ItmCod);
/***** Begin box and table *****/
@@ -2028,14 +2209,14 @@ static void Prg_InsertItem (const struct Prg_Item *ParentItem,
if (NumItemLastChild < Prg_Gbl.List.NumItems - 1)
{
/***** New program item will be inserted after last child of parent *****/
- Item->Hierarchy.ItmInd = Prg_Gbl.List.Items[NumItemLastChild + 1].ItmInd;
+ Item->Hierarchy.ItmInd = Prg_GetItmIndFromNumItem (NumItemLastChild + 1);
/***** Move down all indexes of after last child of parent *****/
Prg_DB_MoveDownItems (Item->Hierarchy.ItmInd);
}
else
/***** New program item will be inserted at the end *****/
- Item->Hierarchy.ItmInd = Prg_Gbl.List.Items[Prg_Gbl.List.NumItems - 1].ItmInd + 1;
+ Item->Hierarchy.ItmInd = Prg_GetItmIndFromNumItem (Prg_Gbl.List.NumItems - 1) + 1;
/***** Child ==> parent level + 1 *****/
Item->Hierarchy.Level = ParentItem->Hierarchy.Level + 1;
@@ -2043,7 +2224,7 @@ static void Prg_InsertItem (const struct Prg_Item *ParentItem,
else // No parent specified
{
/***** New program item will be inserted at the end *****/
- Item->Hierarchy.ItmInd = Prg_Gbl.List.Items[Prg_Gbl.List.NumItems - 1].ItmInd + 1;
+ Item->Hierarchy.ItmInd = Prg_GetItmIndFromNumItem (Prg_Gbl.List.NumItems - 1) + 1;
/***** First level *****/
Item->Hierarchy.Level = 1;
diff --git a/swad_program.h b/swad_program.h
index b8b8eb6a..a7b5e0cb 100644
--- a/swad_program.h
+++ b/swad_program.h
@@ -116,6 +116,13 @@ typedef enum
Prg_MOVE_RIGHT,
} Prg_MoveLeftRight_t;
+#define Prg_NUM_MOVEMENTS_EXPAND_CONTRACT 2
+typedef enum
+ {
+ Prg_EXPAND,
+ Prg_CONTRACT,
+ } Prg_ExpandContract_t;
+
#define Prg_NUM_LISTING_TYPES 12
typedef enum
{
@@ -157,6 +164,8 @@ void Prg_FreeListItems (void);
void Prg_ResetItem (struct Prg_Item *Item);
unsigned Prg_GetNumItemFromItmCod (long ItmCod);
+long Prg_GetItmCodFromNumItem (unsigned NumItem);
+unsigned Prg_GetItmIndFromNumItem (unsigned NumItem);
unsigned Prg_GetLevelFromNumItem (unsigned NumItem);
void Prg_ViewItemAfterEdit (void);
@@ -175,6 +184,9 @@ void Prg_MoveDownItem (void);
void Prg_MoveLeftItem (void);
void Prg_MoveRightItem (void);
+void Prg_ExpandItem (void);
+void Prg_ContractItem (void);
+
//-------------------------------- Figures ------------------------------------
void Prg_GetAndShowCourseProgramStats (void); // TODO: Change function from assignments to schedule
diff --git a/swad_program_database.c b/swad_program_database.c
index a652d73c..842f9451 100644
--- a/swad_program_database.c
+++ b/swad_program_database.c
@@ -720,3 +720,49 @@ void Prg_DB_RemoveLinkFromClipboard (struct Prg_Link *Link)
Prg_ResourceTypesDB[Link->Type],
Link->Cod);
}
+
+/*****************************************************************************/
+/************************ Insert item in expanded items **********************/
+/*****************************************************************************/
+
+void Prg_DB_InsertItemInExpandedItems (long ItmCod)
+ {
+ DB_QueryREPLACE ("can not expand item",
+ "REPLACE INTO prg_expanded"
+ " (UsrCod,ItmCod,ClickTime)"
+ " VALUES"
+ " (%ld,%ld,NOW())",
+ Gbl.Usrs.Me.UsrDat.UsrCod,
+ ItmCod);
+ }
+
+/*****************************************************************************/
+/******************** Check if a program item is expanded ********************/
+/*****************************************************************************/
+
+bool Prg_DB_GetIfExpandedItem (long ItmCod)
+ {
+ return
+ DB_QueryEXISTS ("can not check if an item is expanded",
+ "SELECT EXISTS"
+ "(SELECT *"
+ " FROM prg_expanded"
+ " WHERE UsrCod=%ld"
+ " AND ItmCod=%ld)",
+ Gbl.Usrs.Me.UsrDat.UsrCod,
+ ItmCod);
+ }
+
+/*****************************************************************************/
+/********************** Remove item from expanded items **********************/
+/*****************************************************************************/
+
+void Prg_DB_RemoveItemFromExpandedItems (long ItmCod)
+ {
+ DB_QueryDELETE ("can not contract item",
+ "DELETE FROM prg_expanded"
+ " WHERE UsrCod=%ld"
+ " AND ItmCod=%ld",
+ Gbl.Usrs.Me.UsrDat.UsrCod,
+ ItmCod);
+ }
diff --git a/swad_program_database.h b/swad_program_database.h
index de737ad3..f72387fc 100644
--- a/swad_program_database.h
+++ b/swad_program_database.h
@@ -81,4 +81,8 @@ void Prg_DB_CopyToClipboard (PrgRsc_Type_t Type,long Cod);
unsigned Prg_DB_GetClipboard (MYSQL_RES **mysql_res);
void Prg_DB_RemoveLinkFromClipboard (struct Prg_Link *Link);
+void Prg_DB_InsertItemInExpandedItems (long ItmCod);
+bool Prg_DB_GetIfExpandedItem (long ItmCod);
+void Prg_DB_RemoveItemFromExpandedItems (long ItmCod);
+
#endif
diff --git a/swad_program_resource.c b/swad_program_resource.c
index e69d47d8..d9054ce5 100644
--- a/swad_program_resource.c
+++ b/swad_program_resource.c
@@ -27,6 +27,7 @@
#define _GNU_SOURCE // For asprintf
#include // For asprintf
+#include // For free
#include // For string functions
#include "swad_assignment_resource.h"
diff --git a/swad_text_action.c b/swad_text_action.c
index d6c9dc8f..5d65162e 100644
--- a/swad_text_action.c
+++ b/swad_text_action.c
@@ -6040,6 +6040,98 @@ const char *Txt_Actions[Act_NUM_ACTIONS] =
"Move right program item" // Precisa de tradução
#elif L==10 // tr
"Move right program item" // Çeviri lazim!
+#endif
+ ,
+ [ActExpSeePrgItm] =
+#if L==1 // ca
+ "Expand program item" // Necessita traducció
+#elif L==2 // de
+ "Expand program item" // Need Übersetzung
+#elif L==3 // en
+ "Expand program item"
+#elif L==4 // es
+ "Expandir ítem del programa"
+#elif L==5 // fr
+ "Expand program item" // Besoin de traduction
+#elif L==6 // gn
+ "Expandir ítem del programa" // Okoteve traducción
+#elif L==7 // it
+ "Expand program item" // Bisogno di traduzione
+#elif L==8 // pl
+ "Expand program item" // Potrzebujesz tlumaczenie
+#elif L==9 // pt
+ "Expand program item" // Precisa de tradução
+#elif L==10 // tr
+ "Expand program item" // Çeviri lazim!
+#endif
+ ,
+ [ActConSeePrgItm] =
+#if L==1 // ca
+ "Contract program item" // Necessita traducció
+#elif L==2 // de
+ "Contract program item" // Need Übersetzung
+#elif L==3 // en
+ "Contract program item"
+#elif L==4 // es
+ "Contraer ítem del programa"
+#elif L==5 // fr
+ "Contract program item" // Besoin de traduction
+#elif L==6 // gn
+ "Contraer ítem del programa" // Okoteve traducción
+#elif L==7 // it
+ "Contract program item" // Bisogno di traduzione
+#elif L==8 // pl
+ "Contract program item" // Potrzebujesz tlumaczenie
+#elif L==9 // pt
+ "Contract program item" // Precisa de tradução
+#elif L==10 // tr
+ "Contract program item" // Çeviri lazim!
+#endif
+ ,
+ [ActExpEdiPrgItm] =
+#if L==1 // ca
+ "Expand program item when editing" // Necessita traducció
+#elif L==2 // de
+ "Expand program item when editing" // Need Übersetzung
+#elif L==3 // en
+ "Expand program item when editing"
+#elif L==4 // es
+ "Expandir ítem del programa editando"
+#elif L==5 // fr
+ "Expand program item when editing" // Besoin de traduction
+#elif L==6 // gn
+ "Expandir ítem del programa editando" // Okoteve traducción
+#elif L==7 // it
+ "Expand program item when editing" // Bisogno di traduzione
+#elif L==8 // pl
+ "Expand program item when editing" // Potrzebujesz tlumaczenie
+#elif L==9 // pt
+ "Expand program item when editing" // Precisa de tradução
+#elif L==10 // tr
+ "Expand program item when editing" // Çeviri lazim!
+#endif
+ ,
+ [ActConEdiPrgItm] =
+#if L==1 // ca
+ "Contract program item when editing" // Necessita traducció
+#elif L==2 // de
+ "Contract program item when editing" // Need Übersetzung
+#elif L==3 // en
+ "Contract program item when editing"
+#elif L==4 // es
+ "Contraer ítem del programa editando"
+#elif L==5 // fr
+ "Contract program item when editing" // Besoin de traduction
+#elif L==6 // gn
+ "Contraer ítem del programa editando" // Okoteve traducción
+#elif L==7 // it
+ "Contract program item when editing" // Bisogno di traduzione
+#elif L==8 // pl
+ "Contract program item when editing" // Potrzebujesz tlumaczenie
+#elif L==9 // pt
+ "Contract program item when editing" // Precisa de tradução
+#elif L==10 // tr
+ "Contract program item when editing" // Çeviri lazim!
#endif
,
[ActFrmSeePrgRsc] =