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] =