Commit | Line | Data |
---|---|---|
4ecf423b | 1 | Vue.component('my-problems', { |
da06a6eb BA |
2 | data: function () { |
3 | return { | |
81da2786 | 4 | problems: [], //oldest first |
26b8e4f7 | 5 | myProblems: [], //same |
a9f262f3 BA |
6 | curProblems: [], //assigned to either of the ones above |
7 | curIdx: 0, //index in (current) problems array | |
45109880 | 8 | newProblem: { |
77fa6d1f | 9 | fen: "", |
45109880 BA |
10 | instructions: "", |
11 | solution: "", | |
a9f262f3 | 12 | preview: false, |
45109880 | 13 | }, |
da06a6eb BA |
14 | }; |
15 | }, | |
4ecf423b | 16 | template: ` |
a5d56686 BA |
17 | <div class="col-sm-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> |
18 | <div id="problemControls" class="button-group"> | |
81da2786 BA |
19 | <button :aria-label='translate("Load previous problem")' class="tooltip" |
20 | @click="showPreviousProblem()"> | |
a5d56686 BA |
21 | <i class="material-icons">skip_previous</i> |
22 | </button> | |
247356cd | 23 | <button :aria-label='translate("Add a problem")' class="tooltip" |
a5d56686 | 24 | @click="showNewproblemModal"> |
247356cd | 25 | {{ translate("New") }} |
a5d56686 | 26 | </button> |
81da2786 BA |
27 | <button :aria-label='translate("Load next problem")' class="tooltip" |
28 | @click="showNextProblem()"> | |
a5d56686 BA |
29 | <i class="material-icons">skip_next</i> |
30 | </button> | |
31 | </div> | |
a9f262f3 BA |
32 | --> OK, mais ces flèches n'ont pas la même action selon les vues |
33 | --> fetchN si liste, problème suivant/précédent sinon | |
81da2786 BA |
34 | |
35 | ||
26b8e4f7 BA |
36 | board qui bouge et activé que si #hash donnant numéro du problème |
37 | deux listes : tous les problèmes sauf les miens | |
38 | + les miens | |
39 | ||
40 | ||
41 | //TODO: filter "my problems" ==> liste séparée (lors de la requête serveur) | |
42 | --> bouton plutôt sous l'échiquier après soluce (sauf si anonymous) | |
43 | --> puis dans la vue "my problems (listing échiquier gauche / instrus + soluce cachée à droite | |
44 | if (this.mode == "problem") | |
81da2786 BA |
45 | { |
46 | // Show problem instructions | |
47 | elementArray.push( | |
48 | h('div', | |
49 | { | |
50 | attrs: { id: "instructions-div" }, | |
51 | "class": { | |
52 | "clearer": true, | |
53 | "section-content": true, | |
54 | }, | |
55 | }, | |
56 | [ | |
57 | h('p', | |
58 | { | |
59 | attrs: { id: "problem-instructions" }, | |
60 | domProps: { innerHTML: this.problem.instructions } | |
61 | } | |
62 | ) | |
63 | ] | |
64 | ) | |
65 | ); | |
66 | } | |
67 | ||
68 | ||
69 | // TODO ici :: instrus + diag interactif + solution | |
70 | my-board + pilotage via movesList + VariantRules ! | |
71 | ||
72 | <my-problem-preview v-show="stage=='preview'" | |
73 | v-for="(p,idx) in problems" | |
b5fb8e69 | 74 | v-bind:prob="p" v-bind:preview="false" v-bind:key="idx"> |
da06a6eb | 75 | </my-problem-summary> |
81da2786 BA |
76 | if (this.mode == "problem") |
77 | { | |
78 | // Show problem solution (on click) | |
79 | elementArray.push( | |
80 | h('div', | |
81 | { | |
82 | attrs: { id: "solution-div" }, | |
83 | "class": { "section-content": true }, | |
84 | }, | |
85 | [ | |
86 | h('h3', | |
87 | { | |
88 | "class": { clickable: true }, | |
89 | domProps: { innerHTML: translations["Show solution"] }, | |
90 | on: { click: this.toggleShowSolution }, | |
91 | } | |
92 | ), | |
93 | h('p', | |
94 | { | |
95 | attrs: { id: "problem-solution" }, | |
96 | domProps: { innerHTML: this.problem.solution } | |
97 | } | |
98 | ) | |
99 | ] | |
100 | ) | |
101 | ); | |
102 | } | |
103 | ||
da06a6eb BA |
104 | <input type="checkbox" id="modal-newproblem" class="modal"> |
105 | <div role="dialog" aria-labelledby="newProblemTxt"> | |
81da2786 | 106 | <div v-show="stage=='nothing'" class="card newproblem-form"> |
da06a6eb | 107 | <label for="modal-newproblem" class="modal-close"></label> |
247356cd | 108 | <h3 id="newProblemTxt">{{ translate("Add a problem") }}</h3> |
45109880 | 109 | <form @submit.prevent="previewNewProblem"> |
da06a6eb | 110 | <fieldset> |
247356cd | 111 | <label for="newpbFen">FEN</label> |
77fa6d1f | 112 | <input id="newpbFen" type="text" v-model="newProblem.fen" |
e081ffe3 | 113 | :placeholder='translate("Full FEN description")'/> |
da06a6eb BA |
114 | </fieldset> |
115 | <fieldset> | |
247356cd BA |
116 | <p class="emphasis">{{ translate("Safe HTML tags allowed") }}</p> |
117 | <label for="newpbInstructions">{{ translate("Instructions") }}</label> | |
45109880 | 118 | <textarea id="newpbInstructions" v-model="newProblem.instructions" |
d289b043 | 119 | :placeholder='translate("Describe the problem goal")'></textarea> |
247356cd | 120 | <label for="newpbSolution">{{ translate("Solution") }}</label> |
45109880 | 121 | <textarea id="newpbSolution" v-model="newProblem.solution" |
d289b043 | 122 | :placeholder='translate("How to solve the problem?")'></textarea> |
247356cd | 123 | <button class="center-btn">{{ translate("Preview") }}</button> |
da06a6eb | 124 | </fieldset> |
da06a6eb BA |
125 | </form> |
126 | </div> | |
81da2786 | 127 | <div v-show="stage=='preview'" class="card newproblem-preview"> |
b5fb8e69 | 128 | <label for="modal-newproblem" class="modal-close"></label> |
81da2786 | 129 | <my-problem-preview v-bind:prob="newProblem"></my-problem-summary> |
a5d56686 | 130 | <div class="button-group"> |
247356cd BA |
131 | <button @click="newProblem.stage='nothing'">{{ translate("Cancel") }}</button> |
132 | <button @click="sendNewProblem()">{{ translate("Send") }}</button> | |
b5fb8e69 | 133 | </div> |
45109880 | 134 | </div> |
da06a6eb | 135 | </div> |
4ecf423b BA |
136 | </div> |
137 | `, | |
da06a6eb BA |
138 | computed: { |
139 | sortedProblems: function() { | |
140 | // Newest problem first | |
da06a6eb | 141 | }, |
da06a6eb | 142 | }, |
298c42e6 | 143 | created: function() { |
81da2786 | 144 | // Analyse URL: if a single problem required, show it. Otherwise, |
298c42e6 | 145 | // TODO: fetch most recent problems from server |
26b8e4f7 | 146 | // If the requested problem is in the list, just show it |
a9f262f3 | 147 | this.tryNavigate(); |
298c42e6 | 148 | }, |
da06a6eb | 149 | methods: { |
247356cd BA |
150 | translate: function(text) { |
151 | return translations[text]; | |
152 | }, | |
298c42e6 BA |
153 | // TODO: obsolete: |
154 | // // Propagate "show problem" event to parent component (my-variant) | |
155 | // bubbleUp: function(problem) { | |
156 | // this.$emit('show-problem', JSON.stringify(problem)); | |
157 | // }, | |
81da2786 BA |
158 | toggleShowSolution: function() { |
159 | let problemSolution = document.getElementById("problem-solution"); | |
160 | problemSolution.style.display = | |
161 | !problemSolution.style.display || problemSolution.style.display == "none" | |
162 | ? "block" | |
163 | : "none"; | |
164 | }, | |
165 | showPreviousProblem: function() { | |
166 | if (this.curIdx == 0) | |
167 | this.fetchProblems("backward"); | |
168 | else | |
169 | this.curIdx--; | |
170 | }, | |
171 | showNextProblem: function() { | |
172 | if (this.curIdx == this.problems.length - 1) | |
173 | this.fetchProblems("forward"); | |
174 | else | |
175 | this.curIdx++; | |
176 | }, | |
177 | // TODO: modal "no more problems" | |
da06a6eb | 178 | fetchProblems: function(direction) { |
7931e479 BA |
179 | if (this.problems.length == 0) |
180 | return; //what could we do?! | |
181 | // Search for newest date (or oldest) | |
182 | let last_dt = this.problems[0].added; | |
183 | for (let i=0; i<this.problems.length; i++) | |
184 | { | |
185 | if ((direction == "forward" && this.problems[i].added > last_dt) || | |
186 | (direction == "backward" && this.problems[i].added < last_dt)) | |
187 | { | |
188 | last_dt = this.problems[i].added; | |
189 | } | |
190 | } | |
8d7e2786 | 191 | ajax("/problems/" + variant.name, "GET", { //TODO: use variant._id ? |
7931e479 BA |
192 | direction: direction, |
193 | last_dt: last_dt, | |
194 | }, response => { | |
195 | if (response.problems.length > 0) | |
81da2786 BA |
196 | { |
197 | this.problems = response.problems | |
198 | .sort((p1,p2) => { return p1.added - p2.added; }); | |
199 | this.curIdx = response.problems.length - 1; | |
200 | } | |
7931e479 | 201 | }); |
da06a6eb BA |
202 | }, |
203 | showNewproblemModal: function() { | |
204 | document.getElementById("modal-newproblem").checked = true; | |
205 | }, | |
45109880 BA |
206 | previewNewProblem: function() { |
207 | if (!V.IsGoodFen(this.newProblem.fen)) | |
e081ffe3 | 208 | return alert(translations["Bad FEN description"]); |
6b5517b4 BA |
209 | if (this.newProblem.instructions.trim().length == 0) |
210 | return alert(translations["Empty instructions"]); | |
211 | if (this.newProblem.solution.trim().length == 0) | |
212 | return alert(translations["Empty solution"]); | |
45109880 BA |
213 | this.newProblem.stage = "preview"; |
214 | }, | |
215 | sendNewProblem: function() { | |
216 | // Send it to the server and close modal | |
8d7e2786 | 217 | ajax("/problems/" + variant.name, "POST", { //TODO: with variant._id ? |
45109880 BA |
218 | fen: this.newProblem.fen, |
219 | instructions: this.newProblem.instructions, | |
220 | solution: this.newProblem.solution, | |
7931e479 | 221 | }, response => { |
b5fb8e69 BA |
222 | this.newProblem.added = Date.now(); |
223 | this.problems.push(JSON.parse(JSON.stringify(this.newProblem))); | |
7931e479 | 224 | document.getElementById("modal-newproblem").checked = false; |
45109880 | 225 | this.newProblem.stage = "nothing"; |
7931e479 | 226 | }); |
da06a6eb BA |
227 | }, |
228 | }, | |
4ecf423b | 229 | }) |
b6487fb9 BA |
230 | |
231 | // TODO: | |
232 | // possibilité de supprimer / éditer si peer ID reconnu comme celui du probleme (champ "uploader") |