Merge pull request #148 from ThomasRubini/client_admin-pages-improvements-part-2
[Client] Second part of admin pages improvements
This commit is contained in:
		
						commit
						7e64dc69d3
					
				| @ -9,10 +9,12 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :root { | :root { | ||||||
|  |     --admin-black-color: #000000; | ||||||
|     --admin-grey-color: #5A5656; |     --admin-grey-color: #5A5656; | ||||||
|     --admin-red-color: #FF0000; |     --admin-red-color: #FF0000; | ||||||
|     --admin-white-color: #FFFFFF; |     --admin-white-color: #FFFFFF; | ||||||
|     --adming-yellow-color: #FFC800; |     --adming-yellow-color: #D6A851; | ||||||
|  |     --alert-dialog-background-color: #000000DF; | ||||||
|     --body-margin: 0.375em; |     --body-margin: 0.375em; | ||||||
|     font-family: "Roboto Mono", sans-serif; |     font-family: "Roboto Mono", sans-serif; | ||||||
| } | } | ||||||
| @ -25,6 +27,15 @@ a, body { | |||||||
|     color: var(--admin-white-color); |     color: var(--admin-white-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | a:focus, a:hover { | ||||||
|  |     background-color: var(--admin-white-color); | ||||||
|  |     color: var(--admin-grey-color) !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | a:focus > .action_icon, .action_button:focus > .action_icon, a:hover > .action_icon, .action_button:hover > .action_icon { | ||||||
|  |     fill: var(--admin-grey-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| a:visited { | a:visited { | ||||||
|     color: unset; |     color: unset; | ||||||
| } | } | ||||||
| @ -33,9 +44,24 @@ body { | |||||||
|     margin: var(--body-margin); |     margin: var(--body-margin); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| button, input { | button { | ||||||
|  |     align-items: center; | ||||||
|  |     border-radius: 1em; | ||||||
|  |     cursor: pointer; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | button, input, select { | ||||||
|  |     background-color: transparent; | ||||||
|  |     border-color: var(--admin-white-color); | ||||||
|  |     border-style: solid; | ||||||
|  |     border-width: 0.125em; | ||||||
|  |     color: var(--admin-white-color); | ||||||
|     font-family: "Roboto Mono", sans-serif; |     font-family: "Roboto Mono", sans-serif; | ||||||
|     font-size: 1em; |     font-size: 1em; | ||||||
|  |     margin: 1em; | ||||||
|  |     padding: 0.25em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| header { | header { | ||||||
| @ -56,20 +82,74 @@ header a { | |||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| header a:hover { |  | ||||||
|     background-color: var(--admin-white-color); |  | ||||||
|     color: var(--admin-grey-color); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| html { | html { | ||||||
|     background-color: var(--admin-grey-color); |     background-color: var(--admin-grey-color); | ||||||
|     margin: 0; |     margin: 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | noscript dialog { | ||||||
|  |     align-items: center; | ||||||
|  |     background-color: var(--admin-grey-color); | ||||||
|  |     border-color: var(--admin-white-color); | ||||||
|  |     border-radius: 1em; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     flex-wrap: nowrap; | ||||||
|  |     justify-content: center; | ||||||
|  |     left: 50%; | ||||||
|  |     overflow: auto; | ||||||
|  |     padding: 2em; | ||||||
|  |     position: fixed; | ||||||
|  |     text-align: center; | ||||||
|  |     top: 50%; | ||||||
|  |     transform: translate(-50%, -50%); | ||||||
|  |     z-index: 2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| svg { | svg { | ||||||
|     fill: var(--admin-white-color); |     fill: var(--admin-white-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .action_button:focus, .action_button:hover { | ||||||
|  |     background-color: var(--admin-white-color); | ||||||
|  |     color: var(--admin-grey-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .action_icon { | ||||||
|  |     height: 2em; | ||||||
|  |     transition-property: fill !important; | ||||||
|  |     width: 2em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .alert_dialog_background { | ||||||
|  |     background-color: var(--alert-dialog-background-color); | ||||||
|  |     display: block; | ||||||
|  |     height: 100vh; | ||||||
|  |     left: 0; | ||||||
|  |     position: fixed; | ||||||
|  |     top: 0; | ||||||
|  |     width: 100vw; | ||||||
|  |     z-index: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .alert_dialog_bottom_link { | ||||||
|  |     font-size: 1.125em; | ||||||
|  |     padding: 0.25em; | ||||||
|  |     text-decoration: underline; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .alert_dialog_msg { | ||||||
|  |     font-size: 1.25em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .alert_dialog_msg, .alert_dialog_title { | ||||||
|  |     margin: 1em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .alert_dialog_title { | ||||||
|  |     font-size: 1.75em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .page_category { | .page_category { | ||||||
|     font-size: 2em; |     font-size: 2em; | ||||||
| } | } | ||||||
| @ -102,30 +182,3 @@ svg { | |||||||
|     transition-duration: 0.25s; |     transition-duration: 0.25s; | ||||||
|     transition-timing-function: linear; |     transition-timing-function: linear; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #places>section { |  | ||||||
|     border: thin solid red; |  | ||||||
|     padding: 5px; |  | ||||||
|     margin-top: 20px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #section>input{ |  | ||||||
|     width: 100%; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .questionTypeTag{ |  | ||||||
|     border: thin solid red; |  | ||||||
|     margin-top: 20px; |  | ||||||
| } |  | ||||||
| .questionTypeTag input{ |  | ||||||
|     width: 100%; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .questionType{ |  | ||||||
|     border: thin solid red; |  | ||||||
|     margin-top: 20px; |  | ||||||
| } |  | ||||||
| .question input{ |  | ||||||
|     width: 100%; |  | ||||||
|     margin: 10px; |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,13 +1,3 @@ | |||||||
| .add_npc_icon { |  | ||||||
|     height: 2em; |  | ||||||
|     transition-property: fill; |  | ||||||
|     width: 2em; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .add_npc_icon:hover { |  | ||||||
|     transition-property: fill; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .add_npc_link { | .add_npc_link { | ||||||
|     align-items: center; |     align-items: center; | ||||||
|     border-color: var(--admin-white-color); |     border-color: var(--admin-white-color); | ||||||
| @ -24,26 +14,22 @@ | |||||||
|     padding: 0.25em; |     padding: 0.25em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .add_npc_link:hover { |  | ||||||
|     background-color: var(--admin-white-color); |  | ||||||
|     color: var(--admin-grey-color); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .add_npc_link:hover > .add_npc_icon { |  | ||||||
|     fill: var(--admin-grey-color); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .character_item { | .character_item { | ||||||
|     font-size: 1.5em; |     font-size: 1.5em; | ||||||
|     list-style-type: none; |     list-style-type: none; | ||||||
|     margin: 1em; |     margin: 0.5em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .character_item a { | .character_item a { | ||||||
|  |     padding: 0.25em; | ||||||
|     text-decoration: underline; |     text-decoration: underline; | ||||||
|     text-decoration-color: var(--admin-white-color); |     text-decoration-color: var(--admin-white-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .character_item a:hover { | ||||||
|  |     text-decoration-color: var(--admin-grey-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .character_list { | .character_list { | ||||||
|     align-content: center; |     align-content: center; | ||||||
|     align-items: center; |     align-items: center; | ||||||
|  | |||||||
| @ -31,3 +31,9 @@ input { | |||||||
|     flex-direction: row; |     flex-direction: row; | ||||||
|     justify-content: center; |     justify-content: center; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #login_input_button { | ||||||
|  |     cursor: pointer; | ||||||
|  |     border-radius: 1em; | ||||||
|  |     padding: 0.25em; | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,55 +1,36 @@ | |||||||
| button { | img[alt] { | ||||||
|     display: flex; |     font-size: 1em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| button, input { | img[alt], .info_item, .section_title { | ||||||
|     background-color: transparent; |     text-align: center; | ||||||
|     border-color: var(--admin-white-color); |  | ||||||
|     border-style: solid; |  | ||||||
|     border-width: 0.125em; |  | ||||||
|     color: var(--admin-white-color); |  | ||||||
|     margin: 1em; |  | ||||||
|     padding: 0.25em; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| input[type="text"] { | input[type="text"] { | ||||||
|     width: 20em; |     width: 20em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .action_buttons, .answer_groups { | option { | ||||||
|     align-content: center; |  | ||||||
|     display: flex; |  | ||||||
|     flex-wrap: wrap; |  | ||||||
|     justify-content: center; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .action_button { |  | ||||||
|     align-items: center; |  | ||||||
|     border-radius: 1em; |  | ||||||
|     cursor: pointer; |  | ||||||
|     display: flex; |  | ||||||
|     flex-direction: row; |  | ||||||
|     justify-content: center; |  | ||||||
|     padding: 0.25em; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .action_button:hover { |  | ||||||
|     background-color: var(--admin-white-color); |     background-color: var(--admin-white-color); | ||||||
|     color: var(--admin-grey-color); |     color: var(--admin-black-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .action_button:hover > .action_icon { | .action_buttons, .answer_groups, .reaction, #add_reactions { | ||||||
|     fill: var(--admin-grey-color); |     flex-wrap: wrap; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .action_icon { | .action_buttons, .answer_group, .answer_groups, .reaction, #add_reactions { | ||||||
|     height: 2em; |     display: flex; | ||||||
|     transition-property: fill; |     justify-content: center; | ||||||
|     width: 2em; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .character_image { | .answer_group, .reaction, #add_reactions { | ||||||
|     width: 15em; |     align-items: center; | ||||||
|  |     flex-direction: column; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .character_image, .reaction_image { | ||||||
|  |     width: 20em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .character_image, #npc_name { | .character_image, #npc_name { | ||||||
| @ -65,8 +46,8 @@ input[type="text"] { | |||||||
|     font-size: 1.25em; |     font-size: 1.25em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .info_item, .section_title { | .reaction, #add_reactions { | ||||||
|     text-align: center; |     align-content: center; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .section_title { | .section_title { | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								truthinquiry/static/css/admin_ui_places.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								truthinquiry/static/css/admin_ui_places.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | .place { | ||||||
|  |     align-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     display: flex; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |     justify-content: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .place_input { | ||||||
|  |     flex-grow: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #add_place, #save_changes { | ||||||
|  |     margin-left: auto; | ||||||
|  |     margin-right: auto; | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								truthinquiry/static/css/admin_ui_questions.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								truthinquiry/static/css/admin_ui_questions.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | .add_question_btn, #save_changes { | ||||||
|  |     margin-left: auto; | ||||||
|  |     margin-right: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .delete_question_btn, .question_input { | ||||||
|  |     margin: 1em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .question { | ||||||
|  |     align-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     display: flex; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |     justify-content: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .question_input { | ||||||
|  |     flex-grow: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .question_type { | ||||||
|  |     border-color: var(--admin-white-color); | ||||||
|  |     border-radius: 1em; | ||||||
|  |     border-style: solid; | ||||||
|  |     margin: 1em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .question_type_title { | ||||||
|  |     font-size: 1.5em; | ||||||
|  |     text-align: center; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								truthinquiry/static/css/admin_ui_traits.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								truthinquiry/static/css/admin_ui_traits.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | .delete_trait_btn, #add_trait, #save_changes { | ||||||
|  |     margin-left: auto; | ||||||
|  |     margin-right: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .trait_description_container, .trait_name_container { | ||||||
|  |     display: flex; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |     align-content: center; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     flex-direction: row; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .trait_description_input, .trait_name_input { | ||||||
|  |     width: 30em; | ||||||
|  | } | ||||||
| @ -1,89 +0,0 @@ | |||||||
| //functions for places.html
 |  | ||||||
| 
 |  | ||||||
| function addInputPlaces(){ |  | ||||||
|     let newPlace = places.lastElementChild.cloneNode(true); |  | ||||||
|     newPlace.id = ""; |  | ||||||
|     newPlace.querySelector("input").value = ""; |  | ||||||
|     places.appendChild(newPlace); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function deleteInputPlaces(buttonNode){ |  | ||||||
|     let placeNode = buttonNode.parentNode; |  | ||||||
|     placeNode.parentNode.removeChild(placeNode); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function saveFormPlaces(){ |  | ||||||
|     let data = []; |  | ||||||
|     for(let section of places.querySelectorAll("section")){ |  | ||||||
|         let place = {}; |  | ||||||
|         place["id"] = section.id |  | ||||||
|         place["name"] = section.querySelector("input").value |  | ||||||
|         data.push(place); |  | ||||||
|     } |  | ||||||
|     makeAPIRequest("admin/setPlaces", {"places": data, "lang": "FR"}, {"content": "json"}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| //functions for traits.html
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function addInputTraits(){ |  | ||||||
|     let newTrait = traits.lastElementChild.cloneNode(true); |  | ||||||
|     newTrait.id = ""; |  | ||||||
|     newTrait.querySelector(".name_input").value = ""; |  | ||||||
|     newTrait.querySelector(".desc_input").value = ""; |  | ||||||
|     traits.appendChild(newTrait); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function deleteInputTraits(buttonNode){ |  | ||||||
|     let traitNode = buttonNode.parentNode; |  | ||||||
|     traitNode.parentNode.removeChild(traitNode); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function saveFormTraits(){ |  | ||||||
|     let data = []; |  | ||||||
|     for(let section of traits.querySelectorAll("section")){ |  | ||||||
|         let trait = {}; |  | ||||||
|         trait["id"] = section.id |  | ||||||
|         trait["name"] = section.querySelector(".name_input").value |  | ||||||
|         trait["desc"] = section.querySelector(".desc_input").value |  | ||||||
|         data.push(trait); |  | ||||||
|     } |  | ||||||
|     makeAPIRequest("admin/setTraits", {"traits": data, "lang": "FR"}, {"content": "json"}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| //functions for questions.html
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function addInputQuestions(button){ |  | ||||||
|     let questionTypeContent = button.parentNode.querySelector(".questionTypeContent"); |  | ||||||
|     let newQuestion = questionTypeContent.querySelector(".question").cloneNode(true); |  | ||||||
|     newQuestion.id = ""; |  | ||||||
|     newQuestion.querySelector("input").value = ""; |  | ||||||
|     questionTypeContent.appendChild(newQuestion); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function deleteInputQuestions(buttonNode){ |  | ||||||
|     let placeNode = buttonNode.parentNode; |  | ||||||
|     placeNode.parentNode.removeChild(placeNode); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function saveFormQuestions(){ |  | ||||||
|     let data = []; |  | ||||||
| 
 |  | ||||||
|     for(let questionTypeNode of allQuestions.querySelectorAll(".questionType")){ |  | ||||||
|         let questionsJson = []; |  | ||||||
|         let questionTypeJson = {"questions": questionsJson}; |  | ||||||
|         data.push(questionTypeJson); |  | ||||||
| 
 |  | ||||||
|         for(let questionNode of questionTypeNode.querySelectorAll("input")){ |  | ||||||
|             questionsJson.push({"text": questionNode.value}) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     makeAPIRequest("admin/setQuestions", {"questions": data, "lang": "FR"}, {"content": "json"}) |  | ||||||
| } |  | ||||||
| @ -1,5 +1,5 @@ | |||||||
| 
 | 
 | ||||||
| const reactionsDelta = {} | const reactionsDelta = {}; | ||||||
| 
 | 
 | ||||||
| async function createOrUpdateNpc() { | async function createOrUpdateNpc() { | ||||||
|     const data = {}; |     const data = {}; | ||||||
| @ -9,7 +9,7 @@ async function createOrUpdateNpc() { | |||||||
|     const allAnswersJson = []; |     const allAnswersJson = []; | ||||||
|     data["allAnswers"] = allAnswersJson; |     data["allAnswers"] = allAnswersJson; | ||||||
|      |      | ||||||
|     for (let answerTypeNode of document.querySelector(".answer_groups").children) { |     for (const answerTypeNode of document.querySelector(".answer_groups").children) { | ||||||
|         const answersJson = []; |         const answersJson = []; | ||||||
|         const answerTypeJson = {"answers": answersJson}; |         const answerTypeJson = {"answers": answersJson}; | ||||||
|         allAnswersJson.push(answerTypeJson); |         allAnswersJson.push(answerTypeJson); | ||||||
| @ -20,35 +20,33 @@ async function createOrUpdateNpc() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await makeAPIRequest("admin/setNpc", {"npc": data, "lang": "FR"}, {"content": "json"}); |     await makeAPIRequest("admin/setNpc", {"npc": data, "lang": "FR"}, {"content": "json"}); | ||||||
| 
 |  | ||||||
|     await uploadReactionsDelta(); |     await uploadReactionsDelta(); | ||||||
| 
 | 
 | ||||||
|     alert("Opération effectuée avec succès"); |     alert("Opération effectuée avec succès"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function uploadReactionsDelta() { | async function uploadReactionsDelta() { | ||||||
|     let requests = []; |     const requests = []; | ||||||
|  |     const npcId = document.querySelector("#npc_id").value; | ||||||
| 
 | 
 | ||||||
| 
 |     for (const [traitId, reactionNode] of Object.entries(reactionsDelta)) { | ||||||
|     for(const [traitId, reactionNode] of Object.entries(reactionsDelta)){ |  | ||||||
|         const formData = new FormData(); |         const formData = new FormData(); | ||||||
|         formData.append("npc_id", npc_id.value); |         formData.append("npc_id", npcId); | ||||||
|         formData.append("trait_id", traitId); |         formData.append("trait_id", traitId); | ||||||
|          |          | ||||||
|         if(reactionNode === null) formData.append("file", "null"); |         if (reactionNode === null) { | ||||||
|         else{ |             formData.append("file", "null"); | ||||||
|             const file = reactionNode.querySelector(".img_input").files[0] |         } else { | ||||||
|  |             const file = reactionNode.querySelector(".img_input").files[0]; | ||||||
|             formData.append("file", file ? file : ""); |             formData.append("file", file ? file : ""); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         requests.push(makeAPIRequest("admin/setReaction", formData, {"content": "form"})); |         requests.push(makeAPIRequest("admin/setReaction", formData, {"content": "form"})); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for(request of requests){ |     for (const request of requests) { | ||||||
|         await request; |         await request; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|      |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function deleteNpc() { | async function deleteNpc() { | ||||||
| @ -62,51 +60,141 @@ async function deleteNpc() { | |||||||
|     document.location = "/admin"; |     document.location = "/admin"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function changeReaction(inputNode){ | function changeImageReaction(imageInputElement) { | ||||||
|     const parentNode = inputNode.parentNode; |     const parentNode = imageInputElement.parentNode; | ||||||
|     const imgNode = parentNode.querySelector('img'); |     const imgNode = parentNode.querySelector('img'); | ||||||
|     const traitId = parentNode.querySelector('.trait_id').value; |     const traitId = parentNode.querySelector('.trait_id').value; | ||||||
|      |      | ||||||
|     const reader = new FileReader(); |     const reader = new FileReader(); | ||||||
|     reader.onload = (e)=>{ |     reader.addEventListener("load", event => { | ||||||
|         imgNode.src = e.target.result |         imgNode.src = event.target.result | ||||||
|     } |     }); | ||||||
|     reader.readAsDataURL(inputNode.files[0]); |     reader.readAsDataURL(imageInputElement.files[0]); | ||||||
| 
 | 
 | ||||||
|     reactionsDelta[traitId] = parentNode; |     reactionsDelta[traitId] = parentNode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function deleteReaction(node){ | function deleteImageReaction(reactionDeletionButton) { | ||||||
|     const reactionNode = node.parentNode; |     if (!confirm("Voulez-vous vraiment supprimer l'image de cette réaction ?")) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const reactionNode = reactionDeletionButton.parentNode; | ||||||
|     const traitId = reactionNode.querySelector(".trait_id").value; |     const traitId = reactionNode.querySelector(".trait_id").value; | ||||||
|     const reactionName = reactionNode.querySelector("p").innerText; |     const reactionName = reactionNode.querySelector(".reaction_name").innerText; | ||||||
| 
 | 
 | ||||||
|     reactionNode.parentNode.removeChild(reactionNode); |     reactionNode.parentNode.removeChild(reactionNode); | ||||||
|      |      | ||||||
|     const option = document.createElement("option"); |     const option = document.createElement("option"); | ||||||
|     option.value = traitId |     option.value = traitId; | ||||||
|     option.innerText = reactionName |     option.innerText = reactionName; | ||||||
| 
 | 
 | ||||||
|     reactions_to_add.appendChild(option); |     const addReactionsSelectorElement = document.getElementById("add_reactions_selector"); | ||||||
|  |     if (addReactionsSelectorElement === null) { | ||||||
|  |         // No add_reactions_selector element, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     addReactionsSelectorElement.appendChild(option); | ||||||
| 
 | 
 | ||||||
|     reactionsDelta[traitId] = null; |     reactionsDelta[traitId] = null; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function addReaction(selectNode){ | function addReaction(addReactionsSelectorElement) { | ||||||
|     const selectedOptionNode = selectNode.selectedOptions[0]; |     const selectedOptionNode = addReactionsSelectorElement.selectedOptions[0]; | ||||||
|      |      | ||||||
|     const traitId = selectedOptionNode.value; |     const traitId = selectedOptionNode.value; | ||||||
|     const reactionName = selectedOptionNode.innerText; |     const reactionName = selectedOptionNode.innerText; | ||||||
| 
 | 
 | ||||||
|     selectNode.removeChild(selectedOptionNode); |     addReactionsSelectorElement.removeChild(selectedOptionNode); | ||||||
| 
 | 
 | ||||||
|     const newReaction = reactions.querySelector("div").cloneNode(true); |     const newReactionElement = document.createElement("section"); | ||||||
|     newReaction.querySelector("img").src = ""; |     newReactionElement.classList.add("reaction"); | ||||||
|     newReaction.querySelector(".img_input").value = null; |  | ||||||
|     newReaction.querySelector(".trait_id").value = traitId |  | ||||||
|     newReaction.querySelector("p").innerText = reactionName |  | ||||||
|      |  | ||||||
|     reactions.appendChild(newReaction); |  | ||||||
| 
 | 
 | ||||||
|     reactionsDelta[traitId] = newReaction; |     const reactionNameElement = document.createElement("h3"); | ||||||
| } |     reactionNameElement.classList.add("reaction_name"); | ||||||
|  |     reactionNameElement.textContent = reactionName; | ||||||
|  | 
 | ||||||
|  |     newReactionElement.appendChild(reactionNameElement); | ||||||
|  | 
 | ||||||
|  |     const imageElement = document.createElement("img"); | ||||||
|  |     imageElement.classList.add("reaction_image"); | ||||||
|  |     imageElement.setAttribute("alt", "Image d'une réaction d'un personnage"); | ||||||
|  |     imageElement.src = "/static/images/no_photography_white.svg"; | ||||||
|  | 
 | ||||||
|  |     newReactionElement.appendChild(imageElement); | ||||||
|  | 
 | ||||||
|  |     const imageInputElement = document.createElement("input"); | ||||||
|  |     imageInputElement.classList.add("img_input"); | ||||||
|  |     imageInputElement.setAttribute("type", "file"); | ||||||
|  |     imageInputElement.setAttribute("accept", "image/png, image/jpg, image/jpeg"); | ||||||
|  |     imageInputElement.addEventListener("change", () => changeImageReaction(imageInputElement)); | ||||||
|  | 
 | ||||||
|  |     newReactionElement.appendChild(imageInputElement); | ||||||
|  | 
 | ||||||
|  |     const traitIdInputElement = document.createElement("input"); | ||||||
|  |     traitIdInputElement.classList.add("trait_id"); | ||||||
|  |     traitIdInputElement.setAttribute("type", "hidden"); | ||||||
|  |     traitIdInputElement.setAttribute("value", traitId); | ||||||
|  | 
 | ||||||
|  |     newReactionElement.appendChild(traitIdInputElement); | ||||||
|  | 
 | ||||||
|  |     const buttonElement = document.createElement("button"); | ||||||
|  |     buttonElement.classList.add("delete_question_btn", "action_button", "short_color_transition"); | ||||||
|  |     buttonElement.setAttribute("title", "Cliquez ici pour supprimer l'image de cette réaction"); | ||||||
|  |     buttonElement.addEventListener("click", () => deleteImageReaction(buttonElement)); | ||||||
|  | 
 | ||||||
|  |     const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||||||
|  |     svgElement.classList.add("action_icon", "short_color_transition"); | ||||||
|  |     svgElement.setAttribute("viewBox", "0 0 48 48"); | ||||||
|  | 
 | ||||||
|  |     const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); | ||||||
|  |     pathElement.setAttribute("d", | ||||||
|  |         "M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"); | ||||||
|  | 
 | ||||||
|  |     svgElement.appendChild(pathElement); | ||||||
|  | 
 | ||||||
|  |     buttonElement.appendChild(svgElement); | ||||||
|  |     buttonElement.appendChild(document.createTextNode("Supprimer l'image de la réaction")); | ||||||
|  | 
 | ||||||
|  |     newReactionElement.appendChild(buttonElement); | ||||||
|  | 
 | ||||||
|  |     const reactionsElement = document.getElementById("reactions"); | ||||||
|  |     if (reactionsElement === null) { | ||||||
|  |         // No add_reactions_selector element, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     reactionsElement.appendChild(newReactionElement); | ||||||
|  | 
 | ||||||
|  |     reactionsDelta[traitId] = newReactionElement; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToImageInputs() { | ||||||
|  |     for (const imageInput of document.getElementsByClassName("img_input")) { | ||||||
|  |         imageInput.addEventListener("change", () => changeImageReaction(imageInput)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToImageReactionsRemovalButtons() { | ||||||
|  |     for (const imageReactionRemovalButton of document.getElementsByClassName("delete_image_reaction_btn")) { | ||||||
|  |         imageReactionRemovalButton.addEventListener("click", () => deleteImageReaction(imageReactionRemovalButton)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToAddReactionsSelector() { | ||||||
|  |     const addReactionsSelectorElement = document.getElementById("add_reactions_selector"); | ||||||
|  |     if (addReactionsSelectorElement === null) { | ||||||
|  |         // No add_reactions_selector element, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     addReactionsSelectorElement.addEventListener("change", () => addReaction(addReactionsSelectorElement)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | setListenersToImageReactionsRemovalButtons(); | ||||||
|  | setListenersToImageInputs(); | ||||||
|  | setListenersToAddReactionsSelector(); | ||||||
|  | |||||||
							
								
								
									
										95
									
								
								truthinquiry/static/js/admin_places.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								truthinquiry/static/js/admin_places.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | |||||||
|  | function addPlace() { | ||||||
|  |     const placeElement = document.createElement("div"); | ||||||
|  |     placeElement.classList.add("place"); | ||||||
|  | 
 | ||||||
|  |     const inputElement = document.createElement("input"); | ||||||
|  |     inputElement.classList.add("place_input"); | ||||||
|  |     inputElement.setAttribute("type", "text"); | ||||||
|  |     inputElement.setAttribute("id", ""); | ||||||
|  | 
 | ||||||
|  |     placeElement.appendChild(inputElement); | ||||||
|  | 
 | ||||||
|  |     const buttonElement = document.createElement("button"); | ||||||
|  |     buttonElement.classList.add("delete_place_btn", "action_button", "short_color_transition"); | ||||||
|  |     buttonElement.setAttribute("title", "Cliquez ici pour supprimer ce lieu"); | ||||||
|  | 
 | ||||||
|  |     const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||||||
|  |     svgElement.classList.add("action_icon", "short_color_transition"); | ||||||
|  |     svgElement.setAttribute("viewBox", "0 0 48 48"); | ||||||
|  | 
 | ||||||
|  |     const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); | ||||||
|  |     pathElement.setAttribute("d", | ||||||
|  |         "M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"); | ||||||
|  | 
 | ||||||
|  |     svgElement.appendChild(pathElement); | ||||||
|  | 
 | ||||||
|  |     buttonElement.appendChild(svgElement); | ||||||
|  |     buttonElement.appendChild(document.createTextNode("Supprimer le lieu")); | ||||||
|  |     buttonElement.addEventListener("click", () => deletePlace(buttonElement)); | ||||||
|  | 
 | ||||||
|  |     placeElement.appendChild(buttonElement); | ||||||
|  | 
 | ||||||
|  |     const placesElement = document.getElementById("places"); | ||||||
|  |     if (placesElement === null) { | ||||||
|  |         // No places element, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     placesElement.appendChild(placeElement); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function deletePlace(placeRemoveButton) { | ||||||
|  |     if (!confirm("Voulez-vous vraiement supprimer ce lieu ?")) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const placeElement = placeRemoveButton.parentNode; | ||||||
|  |     placeElement.parentNode.removeChild(placeElement); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function saveChanges() { | ||||||
|  |     const data = []; | ||||||
|  |     for (const section of document.getElementsByClassName("place")) { | ||||||
|  |         const place = {}; | ||||||
|  |         place["id"] = section.id; | ||||||
|  |         place["name"] = section.querySelector("input").value; | ||||||
|  |         data.push(place); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     makeAPIRequest("admin/setPlaces", {"places": data, "lang": "FR"}, {"content": "json"}).then(() => { | ||||||
|  |         alert("Opération effectuée avec succès"); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToPlaceAdditionButton() { | ||||||
|  |     const addPlaceButton = document.getElementById("add_place"); | ||||||
|  |     if (addPlaceButton === null) { | ||||||
|  |         // There is no add_place button, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     addPlaceButton.addEventListener("click", addPlace); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToPlaceDeletionButtons() { | ||||||
|  |     for (const deletePlaceButton of document.getElementsByClassName("delete_place_btn")) { | ||||||
|  |         deletePlaceButton.addEventListener("click", () => deletePlace(deletePlaceButton)); | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToSaveChangesButton() { | ||||||
|  |     const saveChangesButton = document.getElementById("save_changes"); | ||||||
|  |     if (saveChangesButton === null) { | ||||||
|  |         // There is no save_changes button, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     saveChangesButton.addEventListener("click", saveChanges); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | setListenersToPlaceDeletionButtons(); | ||||||
|  | setListenersToPlaceAdditionButton(); | ||||||
|  | setListenersToSaveChangesButton(); | ||||||
							
								
								
									
										95
									
								
								truthinquiry/static/js/admin_questions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								truthinquiry/static/js/admin_questions.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | |||||||
|  | function addQuestion(questionAddButton) { | ||||||
|  |     const questionElement = document.createElement("div"); | ||||||
|  |     questionElement.classList.add("question"); | ||||||
|  | 
 | ||||||
|  |     const inputElement = document.createElement("input"); | ||||||
|  |     inputElement.classList.add("question_input"); | ||||||
|  |     inputElement.setAttribute("type", "text"); | ||||||
|  | 
 | ||||||
|  |     questionElement.appendChild(inputElement); | ||||||
|  | 
 | ||||||
|  |     const buttonElement = document.createElement("button"); | ||||||
|  |     buttonElement.classList.add("delete_question_btn", "action_button", "short_color_transition"); | ||||||
|  |     buttonElement.setAttribute("title", "Cliquez ici pour supprimer cette question"); | ||||||
|  | 
 | ||||||
|  |     const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||||||
|  |     svgElement.classList.add("action_icon", "short_color_transition"); | ||||||
|  |     svgElement.setAttribute("viewBox", "0 0 48 48"); | ||||||
|  | 
 | ||||||
|  |     const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); | ||||||
|  |     pathElement.setAttribute("d", | ||||||
|  |         "M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"); | ||||||
|  | 
 | ||||||
|  |     svgElement.appendChild(pathElement); | ||||||
|  | 
 | ||||||
|  |     buttonElement.appendChild(svgElement); | ||||||
|  |     buttonElement.appendChild(document.createTextNode("Supprimer la question")); | ||||||
|  |     buttonElement.addEventListener("click", () => deleteQuestion(buttonElement)); | ||||||
|  | 
 | ||||||
|  |     questionElement.appendChild(buttonElement); | ||||||
|  | 
 | ||||||
|  |     const questionTypeListElements = questionAddButton.parentNode.getElementsByClassName("question_type_list"); | ||||||
|  |     if (questionTypeListElements.length == 0) { | ||||||
|  |         // No question_type_list element, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // There should be at most one question_type_list element per question type
 | ||||||
|  |     questionTypeListElements[0].appendChild(questionElement); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function deleteQuestion(questionRemoveButton) { | ||||||
|  |     if (!confirm("Voulez-vous vraiement supprimer ce lieu ?")) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const questionElement = questionRemoveButton.parentNode; | ||||||
|  |     questionElement.parentNode.removeChild(questionElement); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function saveChanges() { | ||||||
|  |     const data = []; | ||||||
|  | 
 | ||||||
|  |     for (const questionTypeNode of document.getElementsByClassName("question_type")) { | ||||||
|  |         const questionsJson = []; | ||||||
|  | 
 | ||||||
|  |         for (const questionNode of questionTypeNode.querySelectorAll( | ||||||
|  |             ".question_type_list .question .question_input")) { | ||||||
|  |             questionsJson.push({"text": questionNode.value}); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const questionTypeJson = {"questions": questionsJson}; | ||||||
|  |         data.push(questionTypeJson); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     makeAPIRequest("admin/setQuestions", {"questions": data, "lang": "FR"}, {"content": "json"}).then(() => { | ||||||
|  |         alert("Opération effectuée avec succès"); | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToQuestionAdditionButtons() { | ||||||
|  |     for (const deleteQuestionButton of document.getElementsByClassName("add_question_btn")) { | ||||||
|  |         deleteQuestionButton.addEventListener("click", () => addQuestion(deleteQuestionButton)); | ||||||
|  |     };   | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToQuestionDeletionButtons() { | ||||||
|  |     for (const deleteQuestionButton of document.getElementsByClassName("delete_question_btn")) { | ||||||
|  |         deleteQuestionButton.addEventListener("click", () => deleteQuestion(deleteQuestionButton)); | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToSaveChangesButton() { | ||||||
|  |     const saveChangesButton = document.getElementById("save_changes"); | ||||||
|  |     if (saveChangesButton === null) { | ||||||
|  |         // There is no save_changes button, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     saveChangesButton.addEventListener("click", saveChanges); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | setListenersToQuestionAdditionButtons(); | ||||||
|  | setListenersToQuestionDeletionButtons(); | ||||||
|  | setListenersToSaveChangesButton(); | ||||||
							
								
								
									
										127
									
								
								truthinquiry/static/js/admin_traits.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								truthinquiry/static/js/admin_traits.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | |||||||
|  | function addTrait() { | ||||||
|  |     const traitElement = document.createElement("div"); | ||||||
|  |     traitElement.classList.add("trait"); | ||||||
|  |     traitElement.setAttribute("data-id", ""); | ||||||
|  | 
 | ||||||
|  |     const traitNameContainerElement = document.createElement("div"); | ||||||
|  |     traitNameContainerElement.classList.add("trait_name_container"); | ||||||
|  | 
 | ||||||
|  |     const traitNameTitleElement = document.createElement("h3"); | ||||||
|  |     traitNameTitleElement.classList.add("trait_name"); | ||||||
|  |     traitNameTitleElement.appendChild(document.createTextNode("Nom de la réaction\u00A0:")); | ||||||
|  | 
 | ||||||
|  |     traitNameContainerElement.appendChild(traitNameTitleElement); | ||||||
|  | 
 | ||||||
|  |     const traitNameInputElement = document.createElement("input"); | ||||||
|  |     traitNameInputElement.classList.add("trait_name_input"); | ||||||
|  |     traitNameInputElement.setAttribute("type", "text"); | ||||||
|  |     traitNameInputElement.setAttribute("value", ""); | ||||||
|  | 
 | ||||||
|  |     traitNameContainerElement.appendChild(traitNameInputElement); | ||||||
|  | 
 | ||||||
|  |     traitElement.appendChild(traitNameContainerElement); | ||||||
|  | 
 | ||||||
|  |     const traitDescriptionElement = document.createElement("div"); | ||||||
|  |     traitDescriptionElement.classList.add("trait_description_container"); | ||||||
|  | 
 | ||||||
|  |     const traitDescriptionTitleElement = document.createElement("h3"); | ||||||
|  |     traitDescriptionTitleElement.classList.add("trait_description"); | ||||||
|  |     traitDescriptionTitleElement.appendChild(document.createTextNode("Description de la réaction\u00A0:")); | ||||||
|  | 
 | ||||||
|  |     traitDescriptionElement.appendChild(traitDescriptionTitleElement); | ||||||
|  | 
 | ||||||
|  |     const traitDescriptionInputElement = document.createElement("input"); | ||||||
|  |     traitDescriptionInputElement.classList.add("trait_description_input"); | ||||||
|  |     traitDescriptionInputElement.setAttribute("type", "text"); | ||||||
|  |     traitDescriptionInputElement.setAttribute("value", ""); | ||||||
|  | 
 | ||||||
|  |     traitDescriptionElement.appendChild(traitDescriptionInputElement); | ||||||
|  | 
 | ||||||
|  |     traitElement.appendChild(traitDescriptionElement); | ||||||
|  | 
 | ||||||
|  |     const buttonElement = document.createElement("button"); | ||||||
|  |     buttonElement.classList.add("delete_trait_btn", "action_button", "short_color_transition"); | ||||||
|  |     buttonElement.setAttribute("title", "Cliquez ici pour supprimer cette réaction"); | ||||||
|  | 
 | ||||||
|  |     const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||||||
|  |     svgElement.classList.add("action_icon", "short_color_transition"); | ||||||
|  |     svgElement.setAttribute("viewBox", "0 0 48 48"); | ||||||
|  | 
 | ||||||
|  |     const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); | ||||||
|  |     pathElement.setAttribute("d", | ||||||
|  |         "M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"); | ||||||
|  | 
 | ||||||
|  |     svgElement.appendChild(pathElement); | ||||||
|  | 
 | ||||||
|  |     buttonElement.appendChild(svgElement); | ||||||
|  |     buttonElement.appendChild(document.createTextNode("Supprimer la réaction")); | ||||||
|  |     buttonElement.addEventListener("click", () => deleteTrait(buttonElement)); | ||||||
|  | 
 | ||||||
|  |     traitElement.appendChild(buttonElement); | ||||||
|  | 
 | ||||||
|  |     const traitsElement = document.getElementById("traits"); | ||||||
|  |     if (traitsElement === null) { | ||||||
|  |         // No places element, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     traitsElement.appendChild(traitElement); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function deleteTrait(traitDeletionButton) { | ||||||
|  |     if (!confirm("Voulez-vous vraiement supprimer cette réaction ?")) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const traitNode = traitDeletionButton.parentNode; | ||||||
|  |     traitNode.parentNode.removeChild(traitNode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function saveChanges() { | ||||||
|  |     const data = []; | ||||||
|  | 
 | ||||||
|  |     for (const traitElement of document.getElementsByClassName("trait")) { | ||||||
|  |         const trait = {}; | ||||||
|  |         trait["id"] = traitElement.getAttribute("data-id"); | ||||||
|  |         trait["name"] = traitElement.querySelector(".trait_name_input").value; | ||||||
|  |         trait["desc"] = traitElement.querySelector(".trait_description_input").value; | ||||||
|  |         data.push(trait); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     makeAPIRequest("admin/setTraits", {"traits": data, "lang": "FR"}, {"content": "json"}).then(() => { | ||||||
|  |         alert("Opération effectuée avec succès"); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToTraitDeletionButtons() { | ||||||
|  |     for (const deleteTraitButton of document.getElementsByClassName("delete_trait_btn")) { | ||||||
|  |         deleteTraitButton.addEventListener("click", () => deleteTrait(deleteTraitButton)); | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToTraitAdditionButton() { | ||||||
|  |     const addTraitButton = document.getElementById("add_trait"); | ||||||
|  |     if (addTraitButton === null) { | ||||||
|  |         // There is no add_place button, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     addTraitButton.addEventListener("click", addTrait); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setListenersToSaveChangesButton() { | ||||||
|  |     const saveChangesButton = document.getElementById("save_changes"); | ||||||
|  |     if (saveChangesButton === null) { | ||||||
|  |         // There is no save_changes button, this should never happen
 | ||||||
|  |         // Do nothing in this case
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     saveChangesButton.addEventListener("click", saveChanges); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | setListenersToTraitDeletionButtons(); | ||||||
|  | setListenersToTraitAdditionButton(); | ||||||
|  | setListenersToSaveChangesButton(); | ||||||
| @ -22,7 +22,12 @@ | |||||||
|                 <label for="password" class="password_label">Mot de passe :</label> |                 <label for="password" class="password_label">Mot de passe :</label> | ||||||
|                 <input id="password" name="password" type="password" placeholder="Mot de passe" required="required" title="Saisissez votre mot de passe"> |                 <input id="password" name="password" type="password" placeholder="Mot de passe" required="required" title="Saisissez votre mot de passe"> | ||||||
|             </div> |             </div> | ||||||
|             <input type="submit" value="Connexion"> |             <button id="login_input_button" class="action_button short_color_transition" type="submit" title="Cliquez ici pour vous connecter à l'interface d'administration de Truth Inquiry"> | ||||||
|  |                 <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewBox="0 96 960 960"> | ||||||
|  |                     <path d="M483 959v-91h298V284H483v-92h298q36.125 0 63.562 27.206Q872 246.412 872 284v584q0 37.175-27.438 64.088Q817.125 959 781 959H483Zm-90-177-66-63 96-97H89v-91h332l-96-97 66-64 207 207-205 205Z"/> | ||||||
|  |                 </svg> | ||||||
|  |                 Connexion | ||||||
|  |             </button> | ||||||
|         </form> |         </form> | ||||||
|         {% if failed %} |         {% if failed %} | ||||||
|         <p class="invalid_password">Mot de passe invalide !</p> |         <p class="invalid_password">Mot de passe invalide !</p> | ||||||
|  | |||||||
| @ -29,12 +29,12 @@ | |||||||
|         <ul class="character_list"> |         <ul class="character_list"> | ||||||
|             {%for npc in npcs%} |             {%for npc in npcs%} | ||||||
|             <li class="character_item"> |             <li class="character_item"> | ||||||
|                 <a href="/admin/npc/{{npc['id']}}" title="Cliquez ici pour gérer le personnage « {{npc['name']}} »">{{npc['name']}}</a> |                 <a class="short_color_transition" href="/admin/npc/{{npc['id']}}" title="Cliquez ici pour gérer le personnage « {{npc['name']}} »">{{npc['name']}}</a> | ||||||
|             </li> |             </li> | ||||||
|             {%endfor%} |             {%endfor%} | ||||||
|         </ul> |         </ul> | ||||||
|         <a class="add_npc_link short_color_transition" href="/admin/npc/new" title="Cliquez ici pour créer un nouveau personnage"> |         <a class="add_npc_link short_color_transition" href="/admin/npc/new" title="Cliquez ici pour créer un nouveau personnage"> | ||||||
|             <svg class="add_npc_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewBox="0 96 960 960"> |             <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewBox="0 96 960 960"> | ||||||
|                 <path d="M435 871V622H185v-91h250V281h91v250h250v91H526v249h-91Z"/> |                 <path d="M435 871V622H185v-91h250V281h91v250h250v91H526v249h-91Z"/> | ||||||
|             </svg> |             </svg> | ||||||
|             Nouveau personnage |             Nouveau personnage | ||||||
|  | |||||||
| @ -26,37 +26,41 @@ | |||||||
|         <h1 class="page_title">Truth Inquiry - Interface d'administration</h1> |         <h1 class="page_title">Truth Inquiry - Interface d'administration</h1> | ||||||
|         <h2 class="page_category">{{'Gestion' if npc.get('id') else 'Ajout'}} d'un personnage</h2> |         <h2 class="page_category">{{'Gestion' if npc.get('id') else 'Ajout'}} d'un personnage</h2> | ||||||
|         <p class="page_description">Cliquez sur les champs pour éditer les informations. Dans les réponses aux questions lors de l'interrogation, utilisez « {NPC} » pour faire référence au nom d'un personnage et « {SALLE} » pour faire référence au nom d'une salle.</p> |         <p class="page_description">Cliquez sur les champs pour éditer les informations. Dans les réponses aux questions lors de l'interrogation, utilisez « {NPC} » pour faire référence au nom d'un personnage et « {SALLE} » pour faire référence au nom d'une salle.</p> | ||||||
|         <section> |         <section id="character_info"> | ||||||
|             <h2 class="section_title">Informations sur le personnage</h2> |             <h2 class="section_title">Informations sur le personnage</h2> | ||||||
|             <input id="npc_id" value="{{ npc.get('id') or ''}}" hidden="hidden"> |             <input id="npc_id" value="{{ npc.get('id') or ''}}" type="hidden"> | ||||||
|             <p class="info_item">Nom du personnage</p> |             <p class="info_item">Nom du personnage</p> | ||||||
|             <input type="text" id="npc_name" value="{{ npc.get('name') or ''}}" title="Saisissez le nom du personnage" aria-label="Nom du personnage"> |             <input type="text" id="npc_name" value="{{ npc.get('name') or ''}}" title="Saisissez le nom du personnage" aria-label="Nom du personnage"> | ||||||
|             <p class="info_item">Image du personnage</p> |             <p class="info_item">Image du personnage</p> | ||||||
|             <img class="character_image" alt="{{'Image du personnage' + (' ' + npc.get('name') if npc.get('name') else '')}}" src="{{'/static/images/no_photography_white.svg' if npc.get('img') == None else '/api/v1/getNpcImage?npcid=' + npc.get('img')|string}}"> |             <img class="character_image" alt="{{'Image du personnage' + (' ' + npc.get('name') if npc.get('name') else '')}}" src="{{'/static/images/no_photography_white.svg' if npc.get('img') == None else '/api/v1/getNpcImage?npcid=' + npc.get('img')|string}}"> | ||||||
|         </section> |         </section> | ||||||
|          |  | ||||||
|         <section id="reactions"> |         <section id="reactions"> | ||||||
|             <h2 class="section_title">Réactions</h2> |             <h2 class="section_title">Images des réactions</h2> | ||||||
|              |             {%for reaction in npc.get("reactions") or []%} | ||||||
|                 {%for reaction in npc.get("reactions") or []%} |             <section class="reaction"> | ||||||
|                 <div> |                 <h3 class="reaction_name">{{reaction.get('name')}}</h3> | ||||||
|                     <p> {{reaction.get('name')}} </p> |                 <img class="reaction_image" alt="Image d'une réaction d'un personnage" src="{{reaction.get('url')}}"> | ||||||
|                     <img src="{{reaction.get('url')}}" style="max-width: 100; max-height: 100px"> |                 <input class="img_input" type="file" accept="image/png, image/jpg, image/jpeg"> | ||||||
|                     <input class="img_input", type="file" accept="image/png, image/jpeg" onchange="changeReaction(this)"> |                 <input class="trait_id" type="hidden" value="{{reaction.get('trait_id')}}"> | ||||||
|                     <input class="trait_id", type="hidden" value="{{reaction.get('trait_id')}}"> |                 <button class="delete_image_reaction_btn action_button short_color_transition" title="Cliquez ici pour supprimer l'image de cette réaction"> | ||||||
|                     <button onclick="deleteReaction(this)">Delete reaction</button> |                     <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|                 </div> |                         <path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"/> | ||||||
|                 {%endfor%} |                     </svg> | ||||||
|         </section> |                     Supprimer l'image de la réaction | ||||||
| 
 |                 </button> | ||||||
|         <select id="reactions_to_add" onchange="addReaction(this)"> |             </section> | ||||||
|             <option value="" default></option> |  | ||||||
|             {%for reaction_to_add in npc.get("reactions_to_add") or []%} |  | ||||||
|             <option value="{{reaction_to_add.get('trait_id')}}">{{reaction_to_add.get('name')}}</option> |  | ||||||
|             {%endfor%} |             {%endfor%} | ||||||
|         </select> |         </section> | ||||||
| 
 |         <section id="add_reactions"> | ||||||
|         <section> |             <h2 class="section_title">Réactions à ajouter</h2> | ||||||
|  |             <select id="add_reactions_selector"> | ||||||
|  |                 <option value="" selected="selected">Sélectionnez une réaction à ajouter</option> | ||||||
|  |                 {%for reaction_to_add in npc.get("reactions_to_add") or []%} | ||||||
|  |                 <option value="{{reaction_to_add.get('trait_id')}}">{{reaction_to_add.get('name')}}</option> | ||||||
|  |                 {%endfor%} | ||||||
|  |             </select> | ||||||
|  |         </section> | ||||||
|  |         <section id="interrogation_answers"> | ||||||
|             <h2 class="section_title">Réponses aux questions lors de l'interrogation</h2> |             <h2 class="section_title">Réponses aux questions lors de l'interrogation</h2> | ||||||
|             <div class="answer_groups"> |             <div class="answer_groups"> | ||||||
|                 {%for answer_type in npc.get("answers") or []%} |                 {%for answer_type in npc.get("answers") or []%} | ||||||
| @ -95,7 +99,8 @@ | |||||||
|             <div class="alert_dialog_background"></div> |             <div class="alert_dialog_background"></div> | ||||||
|             <dialog> |             <dialog> | ||||||
|                 <h3 class="alert_dialog_title">JavaScript nécessaire</h3> |                 <h3 class="alert_dialog_title">JavaScript nécessaire</h3> | ||||||
|                 <p class="alert_dialog_msg unsupported_browser_msg">Désolé, mais JavaScript est nécessaire pour faire fonctionner cette page. Veuillez l'activer dans votre navigateur ou en utiliser un qui le supporte afin de pouvoir ajouter ou gérer un personnage.</p> |                 <p class="alert_dialog_msg">Désolé, mais JavaScript est nécessaire pour faire fonctionner cette page. Veuillez l'activer dans votre navigateur ou en utiliser un qui le supporte afin de pouvoir ajouter ou gérer un personnage.</p> | ||||||
|  |                 <a class="alert_dialog_bottom_link short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Se déconnecter de l'interface d'administration du jeu</a> | ||||||
|             </dialog> |             </dialog> | ||||||
|         </noscript> |         </noscript> | ||||||
|         <script src="/static/js/api.js"></script> |         <script src="/static/js/api.js"></script> | ||||||
|  | |||||||
| @ -1,26 +1,65 @@ | |||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="fr"> | <html lang="fr"> | ||||||
|     <head> |     <head> | ||||||
|         <title>Places</title> |  | ||||||
|         <meta charset="UTF-8"> |         <meta charset="UTF-8"> | ||||||
|         <link rel="stylesheet" href="admin_ui.css"> |         <title>Truth Inquiry - Gestion des lieux</title> | ||||||
|         <script src="/static/js/admin.js"></script> |         <link rel="stylesheet" href="/static/css/admin_ui.css"> | ||||||
|         <script src="/static/js/api.js"></script> |         <link rel="stylesheet" href="/static/css/admin_ui_places.css"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_32.png" type="image/png" sizes="32x32"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_64.png" type="image/png" sizes="64x64"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_96.png" type="image/png" sizes="96x96"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_128.png" type="image/png" sizes="128x128"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_192.png" type="image/png" sizes="192x192"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_256.png" type="image/png" sizes="256x256"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_256.png" type="image/png" sizes="512x512"> | ||||||
|  |         <meta name="color-scheme" content="dark light"> | ||||||
|  |         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     </head> |     </head> | ||||||
|     <body> |     <body> | ||||||
|         <a href="/admin"> go Back </a> <br> |         <header> | ||||||
| 
 |             <a class="short_color_transition" href="/admin" title="Cliquez ici pour revenir à l'accueil de l'interface d'administration du jeu">Accueil</a> | ||||||
| 
 |             <a class="short_color_transition" href="/admin/questions" title="Cliquez ici pour gérer les questions du jeu">Gestion des questions</a> | ||||||
|         <section id="places"> |             <a class="short_color_transition" href="/admin/places" title="Cliquez ici pour gérer les lieux du jeu">Gestion des lieux</a> | ||||||
|  |             <a class="short_color_transition" href="/admin/traits" title="Cliquez ici pour gérer les réactions du jeu">Gestion des réactions</a> | ||||||
|  |             <a class="short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Déconnexion</a> | ||||||
|  |         </header> | ||||||
|  |         <h1 class="page_title">Truth Inquiry - Interface d'administration</h1> | ||||||
|  |         <h2 class="page_category">Gestion des lieux</h2> | ||||||
|  |         <p class="page_description">Cliquez sur les champs pour éditer les lieux.</p> | ||||||
|  |         <div id="places"> | ||||||
|         {%for place in places%} |         {%for place in places%} | ||||||
|             <section id="{{place['id']}}"> |             <div id="{{place['id']}}" class="place"> | ||||||
|                 <input value="{{place['name']}}"> |                 <input class="place_input" type="text" value="{{place['name']}}"> | ||||||
|                 <button onclick="deleteInputPlaces(this)">Delete place</button> |                 <button class="delete_place_btn action_button short_color_transition" title="Cliquez ici pour supprimer ce lieu"> | ||||||
|             </section> |                     <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|  |                         <path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"/> | ||||||
|  |                     </svg> | ||||||
|  |                     Supprimer le lieu | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|         {%endfor%} |         {%endfor%} | ||||||
|         </section> |         </div> | ||||||
|         <button onclick="addInputPlaces()">Add new</button> |         <button id="add_place" class="action_button short_color_transition" title="Cliquez ici pour ajouter un lieu"> | ||||||
|         <button onclick="saveFormPlaces()">Save changes</button> |             <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewBox="0 96 960 960"> | ||||||
| 
 |                 <path d="M435 871V622H185v-91h250V281h91v250h250v91H526v249h-91Z"/> | ||||||
|  |             </svg> | ||||||
|  |             Ajouter un lieu | ||||||
|  |         </button> | ||||||
|  |         <button id="save_changes" class="action_button short_color_transition" title="Cliquez ici pour enregistrer vos changements"> | ||||||
|  |             <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|  |                 <path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"/> | ||||||
|  |             </svg> | ||||||
|  |             Sauvegarder les changements | ||||||
|  |         </button> | ||||||
|  |         <noscript> | ||||||
|  |             <div class="alert_dialog_background"></div> | ||||||
|  |             <dialog> | ||||||
|  |                 <h3 class="alert_dialog_title">JavaScript nécessaire</h3> | ||||||
|  |                 <p class="alert_dialog_msg">Désolé, mais JavaScript est nécessaire pour faire fonctionner cette page. Veuillez l'activer dans votre navigateur ou en utiliser un qui le supporte afin de pouvoir gérer les lieux.</p> | ||||||
|  |                 <a class="alert_dialog_bottom_link short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Se déconnecter de l'interface d'administration du jeu</a> | ||||||
|  |             </dialog> | ||||||
|  |         </noscript> | ||||||
|  |         <script src="/static/js/api.js"></script> | ||||||
|  |         <script src="/static/js/admin_places.js"></script> | ||||||
|     </body> |     </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -1,34 +1,70 @@ | |||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="fr"> | <html lang="fr"> | ||||||
|     <head> |     <head> | ||||||
|         <title>Admin Page</title> |  | ||||||
|         <meta charset="UTF-8"> |         <meta charset="UTF-8"> | ||||||
|         <link rel="stylesheet" href="admin_ui.css"> |         <title>Truth Inquiry - Gestion des questions</title> | ||||||
|         <script src="/static/js/admin.js"></script> |         <link rel="stylesheet" href="/static/css/admin_ui.css"> | ||||||
|         <script src="/static/js/api.js"></script> |         <link rel="stylesheet" href="/static/css/admin_ui_questions.css"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_32.png" type="image/png" sizes="32x32"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_64.png" type="image/png" sizes="64x64"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_96.png" type="image/png" sizes="96x96"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_128.png" type="image/png" sizes="128x128"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_192.png" type="image/png" sizes="192x192"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_256.png" type="image/png" sizes="256x256"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_256.png" type="image/png" sizes="512x512"> | ||||||
|  |         <meta name="color-scheme" content="dark light"> | ||||||
|  |         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     </head> |     </head> | ||||||
|     <body> |     <body> | ||||||
|      |         <header> | ||||||
|         <a href="/admin"> go Back </a> <br> |             <a class="short_color_transition" href="/admin" title="Cliquez ici pour revenir à l'accueil de l'interface d'administration du jeu">Accueil</a> | ||||||
| 
 |             <a class="short_color_transition" href="/admin/questions" title="Cliquez ici pour gérer les questions du jeu">Gestion des questions</a> | ||||||
|         <section id="allQuestions"> |             <a class="short_color_transition" href="/admin/places" title="Cliquez ici pour gérer les lieux du jeu">Gestion des lieux</a> | ||||||
|             {%for questionType in questions%} |             <a class="short_color_transition" href="/admin/traits" title="Cliquez ici pour gérer les réactions du jeu">Gestion des réactions</a> | ||||||
|             <div class="questionType"> |             <a class="short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Déconnexion</a> | ||||||
|                 <section class="questionTypeContent"> |         </header> | ||||||
|                     {%for question in questionType["questions"]%} |         <h1 class="page_title">Truth Inquiry - Interface d'administration</h1> | ||||||
|                     <section class="question"> |         <h2 class="page_category">Gestion des questions</h2> | ||||||
|                         <input value="{{question['text']}}"> |         <p class="page_description">Cliquez sur les champs pour éditer les questions.</p> | ||||||
|                         <button onclick="deleteInputQuestions(this)">Delete question</button> |         {%for questionType in questions%} | ||||||
|                     </section> |         <section class="question_type"> | ||||||
|                     {%endfor%} |             <h3 class="question_type_title">Type de question {{loop.index0}}</h3> | ||||||
|                 </section> |             <div class="question_type_list"> | ||||||
|                 <button onclick="addInputQuestions(this)">Add new</button> |                 {%for question in questionType["questions"]%} | ||||||
|  |                 <div class="question"> | ||||||
|  |                     <input class="question_input" type="text" value="{{question['text']}}"> | ||||||
|  |                     <button class="delete_question_btn action_button short_color_transition" title="Cliquez ici pour supprimer cette question"> | ||||||
|  |                         <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|  |                             <path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"/> | ||||||
|  |                         </svg> | ||||||
|  |                         Supprimer la question | ||||||
|  |                     </button> | ||||||
|  |                 </div> | ||||||
|  |                 {%endfor%} | ||||||
|             </div> |             </div> | ||||||
|             {%endfor%} |             <button class="add_question_btn action_button short_color_transition" title="Cliquez ici pour ajouter une question au type {{loop.index0}}"> | ||||||
|  |                 <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewBox="0 96 960 960"> | ||||||
|  |                     <path d="M435 871V622H185v-91h250V281h91v250h250v91H526v249h-91Z"/> | ||||||
|  |                 </svg> | ||||||
|  |                 Ajouter une question | ||||||
|  |             </button> | ||||||
|         </section> |         </section> | ||||||
| 
 |         {%endfor%} | ||||||
|         <br> |         <button id="save_changes" class="action_button short_color_transition" title="Cliquez ici pour enregistrer vos changements"> | ||||||
| 
 |             <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|         <button onclick="saveFormQuestions()"> Save changes </button> |                 <path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"/> | ||||||
|  |             </svg> | ||||||
|  |             Sauvegarder les changements | ||||||
|  |         </button> | ||||||
|  |         <noscript> | ||||||
|  |             <div class="alert_dialog_background"></div> | ||||||
|  |             <dialog> | ||||||
|  |                 <h3 class="alert_dialog_title">JavaScript nécessaire</h3> | ||||||
|  |                 <p class="alert_dialog_msg">Désolé, mais JavaScript est nécessaire pour faire fonctionner cette page. Veuillez l'activer dans votre navigateur ou en utiliser un qui le supporte afin de pouvoir gérer les questions.</p> | ||||||
|  |                 <a class="alert_dialog_bottom_link short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Se déconnecter de l'interface d'administration du jeu</a> | ||||||
|  |             </dialog> | ||||||
|  |         </noscript> | ||||||
|  |         <script src="/static/js/api.js"></script> | ||||||
|  |         <script src="/static/js/admin_questions.js"></script> | ||||||
|     </body> |     </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -1,29 +1,72 @@ | |||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="fr"> | <html lang="fr"> | ||||||
|     <head> |     <head> | ||||||
|         <title>Traits</title> |  | ||||||
|         <meta charset="UTF-8"> |         <meta charset="UTF-8"> | ||||||
|         <link rel="stylesheet" href="admin_ui.css"> |         <title>Truth Inquiry - Gestion des réactions</title> | ||||||
|         <script src="/static/js/api.js"></script> |         <link rel="stylesheet" href="/static/css/admin_ui.css"> | ||||||
|         <script src="/static/js/admin.js"></script> |         <link rel="stylesheet" href="/static/css/admin_ui_traits.css"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_32.png" type="image/png" sizes="32x32"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_64.png" type="image/png" sizes="64x64"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_96.png" type="image/png" sizes="96x96"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_128.png" type="image/png" sizes="128x128"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_192.png" type="image/png" sizes="192x192"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_256.png" type="image/png" sizes="256x256"> | ||||||
|  |         <link rel="icon" href="/static/images/favicon/favicon_256.png" type="image/png" sizes="512x512"> | ||||||
|  |         <meta name="color-scheme" content="dark light"> | ||||||
|  |         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     </head> |     </head> | ||||||
|     <body> |     <body> | ||||||
|         <a href="/admin"> go Back </a> <br> |         <header> | ||||||
| 
 |             <a class="short_color_transition" href="/admin" title="Cliquez ici pour revenir à l'accueil de l'interface d'administration du jeu">Accueil</a> | ||||||
|         <section id="traits"> |             <a class="short_color_transition" href="/admin/questions" title="Cliquez ici pour gérer les questions du jeu">Gestion des questions</a> | ||||||
|  |             <a class="short_color_transition" href="/admin/places" title="Cliquez ici pour gérer les lieux du jeu">Gestion des lieux</a> | ||||||
|  |             <a class="short_color_transition" href="/admin/traits" title="Cliquez ici pour gérer les réactions du jeu">Gestion des réactions</a> | ||||||
|  |             <a class="short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Déconnexion</a> | ||||||
|  |         </header> | ||||||
|  |         <h1 class="page_title">Truth Inquiry - Interface d'administration</h1> | ||||||
|  |         <h2 class="page_category">Gestion des réactions</h2> | ||||||
|  |         <p class="page_description">Cliquez sur les champs pour éditer les informations. Les images des émotions sont disponibles par personnage dans leur page de gestion dédiée.</p> | ||||||
|  |         <div id="traits"> | ||||||
|         {%for trait in traits%} |         {%for trait in traits%} | ||||||
|             <section id="{{trait['id']}}"> |             <div data-id="{{trait['id']}}" class="trait"> | ||||||
|                 <p> Name: </p> |                 <div class="trait_name_container"> | ||||||
|                 <input class="name_input" value="{{trait['name']}}"> |                     <h3 class="trait_name">Nom de la réaction :</h3> | ||||||
|                 <p> Description: </p> |                     <input type="text" class="trait_name_input" value="{{trait['name']}}"> | ||||||
|                 <input class="desc_input" value="{{trait['desc']}}"> |                 </div> | ||||||
|                 <button onclick="deleteInputTraits(this)">Delete trait</button> |                 <div class="trait_description_container"> | ||||||
|             </section> |                     <h3 class="trait_description">Description de la réaction :</h3> | ||||||
|  |                     <input type="text" class="trait_description_input" value="{{trait['desc']}}"> | ||||||
|  |                 </div> | ||||||
|  |                 <button class="delete_trait_btn action_button short_color_transition"> | ||||||
|  |                     <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|  |                         <path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"/> | ||||||
|  |                     </svg> | ||||||
|  |                     Supprimer la réaction | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|             {%endfor%} |             {%endfor%} | ||||||
|         </section> |         </div> | ||||||
|         <button onclick="addInputTraits()">Add new</button> |         <button id="add_trait" class="action_button short_color_transition"> | ||||||
|         <button onclick="saveFormTraits()">Save changes</button> |             <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewBox="0 96 960 960"> | ||||||
| 
 |                 <path d="M435 871V622H185v-91h250V281h91v250h250v91H526v249h-91Z"/> | ||||||
|         <p>Images are viewable in the npc views</p> |             </svg> | ||||||
|  |             Ajouter une nouvelle réaction | ||||||
|  |         </button> | ||||||
|  |         <button id="save_changes" class="action_button short_color_transition"> | ||||||
|  |             <svg class="action_icon short_color_transition" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"> | ||||||
|  |                 <path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"/> | ||||||
|  |             </svg> | ||||||
|  |             Sauvegarder les changements | ||||||
|  |         </button> | ||||||
|  |         <noscript> | ||||||
|  |             <div class="alert_dialog_background"></div> | ||||||
|  |             <dialog> | ||||||
|  |                 <h3 class="alert_dialog_title">JavaScript nécessaire</h3> | ||||||
|  |                 <p class="alert_dialog_msg">Désolé, mais JavaScript est nécessaire pour faire fonctionner cette page. Veuillez l'activer dans votre navigateur ou en utiliser un qui le supporte afin de pouvoir gérer les émotions.</p> | ||||||
|  |                 <a class="alert_dialog_bottom_link short_color_transition" href="/api/v1/admin/logout" title="Cliquez ici pour vous déconnecter de l'interface d'administration du jeu">Se déconnecter de l'interface d'administration du jeu</a> | ||||||
|  |             </dialog> | ||||||
|  |         </noscript> | ||||||
|  |         <script src="/static/js/api.js"></script> | ||||||
|  |         <script src="/static/js/admin_traits.js"></script> | ||||||
|     </body> |     </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user