Commit c29db654 authored by GuiΩ's avatar GuiΩ
Browse files

feat(seances): context menu: delete selected seances

parent 982e7ee8
......@@ -108,16 +108,16 @@ Events:
<style lang="sass">
.FeuilleList
vertical-align: top
overflow-y: scroll
display: flex
flex-direction: column
height: calc(100% - 4px)
border: solid 2px lightGray
overflow: scroll
scroll-behavior: smooth
text-align: center
/* width: 1200px; */
//align-content: flex-start
min-height: 100px
/* height: 600px; */
margin: 0
padding: 0
list-style: none
background-color: #ffdffb
.FeuilleList_newFeuilleBtn
......
......@@ -99,7 +99,7 @@ Events:
@seance-changed="$emit('seance-changed', $event)"
@show-question-tooltip="$emit('show-question-tooltip', $event)"
@show-context-menu="$emit('show-context-menu', $event)")/
button.Feuille_newFeuilleBtn(
button.Feuille_addSeanceBtn(
type="button"
@click="addSeance({feuille: props.feuilleId})"
) Ajouter une séance
......@@ -107,14 +107,17 @@ Events:
<style>
.Feuille {
min-width: 1062px;
border-bottom: solid 2px dimgray;
display: flex;
flex-direction: column;
border-bottom: solid 3px black;
padding: 0;
margin: 0;
}
.FeuilleHeader {
display: block;
/*display: block;*/
align-self: center;
flex: 0 0 auto;
font-size: 24px;
margin: 10px;
}
......@@ -130,8 +133,10 @@ Events:
}
.Feuille_newFeuilleBtn {
.Feuille_addSeanceBtn {
align-self: center;
margin: 20px;
max-width: fit-content;
}
</style>
\ No newline at end of file
......@@ -77,6 +77,16 @@ Events:
return true
})
const selectionIsDeletable = computed(() => {
for(const seanceId of props.selection.seances) {
const seance = feuilles.getSeance(seanceId)
for (const questionPosee of seance?.questionsPosees! )
if (questionPosee.score !== null)
return false
}
return true
})
const isSelected = computed(() => props.selection.seances.indexOf(props.seanceId)>-1)
const seance = computed(() => feuilles.getSeance(props.seanceId))
......@@ -198,6 +208,9 @@ Events:
emit('show-context-menu', {event:event, options:[
{ name: 'Copier ' + (multipleSel ? ' les seances' : 'la seance') ,
callback: () => emit('copy', event) },
{ name:'Supprimer' + (multipleSel ? ' les seances' : 'la seance'),
disabled: ! selectionIsDeletable,
callback: () => undoables.deleteSeances(props.selection.seances)},
{ name: 'Insérer '+ (multipleClip ? 'les seances' : 'la seance') + ' avant',
disabled: props.clipboard.seances.length < 1,
callback: () => pasteSeance(seance.value?.position!)},
......@@ -207,6 +220,7 @@ Events:
{name: 'Annuler'}]})
}
function pasteSeance(position: number) {
const seances: Partial<ISeanceR>[] = JSON.parse(JSON.stringify(props.clipboard.seances))
for (const s of seances) {
......@@ -234,9 +248,12 @@ Events:
:data-testid="'seance_' + props.seanceId"
v-if="seance"
@click="onClick")
.Seance_body(
:class="{selected: isSelected}")
| Seance {{ seance.position }}
.Seance_header Seance&nbsp;{{ seance.position }}
|&nbsp;
span.Seance_deleteBtn(
:disabled="! isDeletable"
@click="undoables.deleteSeance(seance)") &#x1F5D9;
.Seance_body(:class="{selected: isSelected}")
FeuilleListFeuilleSeanceSlot(
v-for="position in 5"
:key="'slot' + props.seanceId + '_' + position"
......@@ -254,7 +271,7 @@ Events:
@question-drop="$emit('question-drop', $event)"
@show-question-tooltip="$emit('show-question-tooltip', $event)"
@show-context-menu="$emit('show-context-menu', $event)")/
.tools
.Seance_footer
button(v-if="! state.scoresEditing" @click="showEvaluate") Saisir les notes
button.valider(v-if="state.scoresEditing" :ref="(el) => btnScoreSave=el" @click="save") Valider
br
......@@ -296,44 +313,69 @@ Events:
a(v-if="isDeletable" @click="undoables.deleteSeance(seance)") Supprimer la séance
</template>
<style>
.Seance {
display: table-row;
margin: 0;
padding: 0;
text-align: left;
vertical-align: middle;
}
.Seance_body.selected {
background: rgba(1,0,0,.05);
border: solid red 1px;
}
.Seance_date {
position: relative;
top: 50%;
cursor: pointer;
}
.seance > div {
display: inline-block;
vertical-align: top;
margin: 0;
<style lang="sass">
.Seance
display: flex
justify-content: flex-start
text-align: left
margin-left: 10px
padding: 0
}
padding-bottom: 5px
.Seance_header
height: min-content
margin-left: -60px
font-size: 90%
//border: solid 1px
transform-origin: top right
transform: translate(-27px,10px) rotate(-90deg)
.Seance_deleteBtn
font-size: 140%
color: red
cursor: pointer
&.disabled
color: gray
cursor: default
.Seance_body
flex: 0 0 auto
display: flex
&.selected
background: rgba(1,0,0,.05)
border: solid red 1px
& .questionSlot
flex: 0 0 auto
.Seance_date
position: relative
top: 50%
cursor: pointer
//
//.seance > div
// display: inline-block
// vertical-align: top
// margin: 0
// padding: 0
.Seance_footer
display: flex
flex-direction: column
min-width: 150px
.tools .button
//display: inline-block
//margin: auto
.tools {
display: inline-block;
}
.tools .button {
display: inline-block;
margin: auto;
}
a
cursor: pointer
a {
cursor: pointer;
}
</style>
\ No newline at end of file
......@@ -211,7 +211,7 @@ Events:
</script>
<template lang="pug">
.questionSlot(
.QuestionSlot(
ref="root"
:data-testid="'slot_' + props.seanceId + '_' + position"
@drop.prevent.stop="onDrop"
......@@ -220,14 +220,14 @@ Events:
@dragenter.prevent
@contextmenu.prevent
)
.questionPosee(
.QuestionSlot_questionPosee(
v-if="questionPosee"
@contextmenu.prevent="onContextMenu")
Score(:score="questionPosee.score")
.saise(v-if="scoreEditing")
input(ref="input" v-model.number.trim="newScore" size="2" @change="onInput($event)" @input="onInput($event)")
|&nbsp; / &nbsp; {{ bareme }}
.question(
.QuestionSlot_question(
v-if="question"
@click="onClick"
@dblclick="onDblClick"
......@@ -237,64 +237,58 @@ Events:
:alt="'question ' + questionPosee.question"
:src="'/static/thumbs/' + question.thumb_name"
@load="$emit('loaded', props.questionId)")
div.question_vide(v-else) Question {{ questionPosee.question }}
.QuestionSlot_questionVide(v-else) Question {{ questionPosee.question }}
</template>
<style scoped>
.questionSlot {
display: table-cell;
vertical-align: top;
width: 211px;
height: 50px;
border: solid 1px gray;
}
<style lang="sass">
.QuestionSlot
width: 211px
min-height: 50px
border: solid 1px gray
.QuestionSlot_questionPosee
text-align: center
.questionPosee {
text-align: center;
}
/* Affichage du score : */
/* si non évalué : gris */
.score {
display: block;
max-height: 5px;
width: 60%;
height: 3px;
background: lightgray;
border: 1px solid gray;
margin: auto;
margin-top: 4px;
}
/* si évalué : fond rouge */
.score.evaluee {
background: red;
}
.score
display: block
max-height: 5px
width: 60%
height: 3px
background: lightgray
border: 1px solid gray
margin: auto
margin-top: 4px
.evaluee
background: red
/* et score en vert */
.scorevalue {
height: 100%;
background: greenyellow;
}
.question_vide {
display: block;
text-align: center;
width: 209px;
height: 60px;
.scorevalue
height: 100%
background: greenyellow
.QuestionSlot_questionVide
display: block
text-align: center
width: 209px
height: 60px
/*padding-top: 20px;*/
border: 1px solid black;
border: 1px solid black
/*noinspection CssUnknownTarget*/
background: white center no-repeat url("/static/src/assets/loading.gif");
}
background: white center no-repeat url("/static/src/assets/loading.gif")
.saisie input {
max-width: 20px;
margin: auto;
}
.saisie input
max-width: 20px
margin: auto
img
background: rgba(255, 255, 255, .7)
img {
background: rgba(255, 255, 255, .7);
}
</style>
\ No newline at end of file
......@@ -289,12 +289,6 @@ body {
.FeuilleList {
flex: 10 10 auto;
display: flex;
flex-direction: column;
overflow: auto;
height: calc(100% - 4px);
padding: 10px;
border: solid 2px lightGray;
}
</style>
\ No newline at end of file
......@@ -254,6 +254,19 @@ export class SeanceDelActionR extends _SeanceAddDelActionR {
}
}
export class SeancesDelActionR extends MultipleAction {
constructor(seances: ISeanceR[], redoMsg?: string, undoMsg?: string) {
const actions = []
for (const seance of seances)
actions.push(new SeanceDelActionR(seance))
if (redoMsg === undefined)
redoMsg = 'Supprimer les séances'
if (undoMsg === undefined)
undoMsg = 'Restaurer les séances'
super(redoMsg, undoMsg, actions);
}
}
/* **********************
* Feuilles *
************************/
......
import {defineStore} from 'pinia'
import type {ClasseID, FeuilleID, IFeuille, IQuestionPosee, ISeanceR, IUndoable, QuestionID} from "@/types";
import type {ClasseID, FeuilleID, IFeuille, IQuestionPosee, ISeanceR, IUndoable, QuestionID, SeanceID} from "@/types";
import {useClassesStore} from "@/store/classes";
import {
FeuilleAddDelActionR,
......@@ -7,8 +7,9 @@ import {
QuestionPoseeAddDelAction,
QuestionPoseePatchAction,
SeanceAddActionR,
SeanceDelActionR, SeancesAddActionR
SeanceDelActionR, SeancesAddActionR, SeancesDelActionR
} from "@/store/undoableActions";
import {useFeuillesStore} from "@/store/feuilles";
export const QUESTION_SAVE_INIT = 'INIT_QUESTION_SAVE'
......@@ -167,6 +168,17 @@ export const useUndoablesStore = defineStore( 'undoablesStore',{
return this.redo()
},
deleteSeances(seancesId: SeanceID[]) {
const feuilles = useFeuillesStore()
console.debug('undoables.deleteSeances', seancesId)
const seances = []
for (const seanceId of seancesId)
seances.push(feuilles.getSeance(seanceId)!)
this.queuePush(new SeancesDelActionR(seances))
return this.redo()
},
/* ********************
* QuestionPosees
**********************/
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment