X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fviews%2FProblems.vue;h=ae918b95a8d303bb24f81c1cdc94b9328a150c36;hb=32f6285ee325a14286562a53baefc647201df2af;hp=1c990649bf2256825930d7960e47661feaa27f88;hpb=0cd026057235122150be0f1eb4c72e5f5902a447;p=vchess.git diff --git a/client/src/views/Problems.vue b/client/src/views/Problems.vue index 1c990649..ae918b95 100644 --- a/client/src/views/Problems.vue +++ b/client/src/views/Problems.vue @@ -2,7 +2,7 @@ main input#modalNewprob.modal( type="checkbox" - @change="infoMsg=''" + @change="fenFocusIfOpened($event)" ) div#newprobDiv( role="dialog" @@ -47,19 +47,16 @@ main .row(v-if="showOne") .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 #topPage + .button-group(v-if="st.user.id == curproblem.uid") + button(@click="editProblem(curproblem)") {{ st.tr["Edit"] }} + button(@click="deleteProblem(curproblem)") {{ st.tr["Delete"] }} span.vname {{ curproblem.vname }} span.uname ({{ curproblem.uname }}) button.marginleft(@click="backToList()") {{ st.tr["Back to list"] }} - button.nomargin( - v-if="st.user.id == curproblem.uid" - @click="editProblem(curproblem)" - ) - | {{ st.tr["Edit"] }} - button.nomargin( - v-if="st.user.id == curproblem.uid" - @click="deleteProblem(curproblem)" - ) - | {{ st.tr["Delete"] }} + button.nomargin(@click="gotoPrevNext($event,curproblem,1)") + | {{ st.tr["Previous"] }} + button.nomargin(@click="gotoPrevNext($event,curproblem,-1)") + | {{ st.tr["Next_p"] }} p.oneInstructions.clickable( v-html="parseHtml(curproblem.instruction)" @click="curproblem.showSolution=!curproblem.showSolution" @@ -72,7 +69,7 @@ main .row(v-else) .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 #controls - button#newProblem(onClick="window.doClick('modalNewprob')") + button#newProblem(@click="prepareNewProblem()") | {{ st.tr["New problem"] }} label(for="checkboxMine") {{ st.tr["My problems"] }} input#checkboxMine( @@ -86,7 +83,7 @@ main :value="v.id" ) | {{ v.name }} - table + table#tProblems tr th {{ st.tr["Variant"] }} th {{ st.tr["Instructions"] }} @@ -99,10 +96,15 @@ main td {{ p.vname }} td {{ firstChars(p.instruction) }} td {{ p.id }} + button#loadMoreBtn( + v-if="hasMore" + @click="loadMore()" + ) + | {{ st.tr["Load more"] }} BaseGame( + ref="basegame" v-if="showOne" :game="game" - :vr="vr" ) @@ -139,10 +141,13 @@ export default { loadedVar: 0, //corresponding to loaded V selectedVar: 0, //to filter problems based on variant problems: [], + // timestamp of oldest showed problem: + cursor: Number.MAX_SAFE_INTEGER, + // hasMore == TRUE: a priori there could be more problems to load + hasMore: true, onlyMines: false, showOne: false, infoMsg: "", - vr: null, //"variant rules" object initialized from FEN game: { players: [{ name: "Problem" }, { name: "Problem" }], mode: "analyze" @@ -150,36 +155,28 @@ export default { }; }, created: function() { - ajax("/problems", "GET", res => { - // Show newest problem first: - this.problems = res.problems.sort((p1, p2) => p2.added - p1.added); - if (this.st.variants.length > 0) - this.problems.forEach(p => this.setVname(p)); - // Retrieve all problems' authors' names - let names = {}; - this.problems.forEach(p => { - if (p.uid != this.st.user.id) names[p.uid] = ""; - //unknwon for now - else p.uname = this.st.user.name; - }); - const showOneIfPid = () => { - const pid = this.$route.query["id"]; - if (pid) this.showProblem(this.problems.find(p => p.id == pid)); - }; - if (Object.keys(names).length > 0) { - ajax("/users", "GET", { ids: Object.keys(names).join(",") }, res2 => { - res2.users.forEach(u => { - names[u.id] = u.name; - }); - this.problems.forEach(p => (p.uname = names[p.uid])); - showOneIfPid(); - }); - } else showOneIfPid(); - }); + ajax( + "/problems", + "GET", + { + data: { cursor: this.cursor }, + success: (res) => { + // The returned list is sorted from most recent to oldest + this.problems = res.problems; + const L = res.problems.length; + if (L > 0) this.cursor = res.problems[L - 1].added; + else this.hasMore = false; + const showOneIfPid = () => { + const pid = this.$route.query["id"]; + if (!!pid) this.showProblem(this.problems.find(p => p.id == pid)); + }; + this.decorate(this.problems, showOneIfPid); + } + } + ); }, mounted: function() { - document - .getElementById("newprobDiv") + document.getElementById("newprobDiv") .addEventListener("click", processModalClick); }, watch: { @@ -191,14 +188,50 @@ export default { }, $route: function(to) { const pid = to.query["id"]; - if (pid) this.showProblem(this.problems.find(p => p.id == pid)); + if (!!pid) this.showProblem(this.problems.find(p => p.id == pid)); else this.showOne = false; } }, methods: { + fenFocusIfOpened: function(event) { + if (event.target.checked) { + this.infoMsg = ""; + document.getElementById("inputFen").focus(); + } + }, setVname: function(prob) { prob.vname = this.st.variants.find(v => v.id == prob.vid).name; }, + // Add vname and user names: + decorate: function(problems, callback) { + if (this.st.variants.length > 0) + problems.forEach(p => this.setVname(p)); + // Retrieve all problems' authors' names + let names = {}; + problems.forEach(p => { + if (p.uid != this.st.user.id) names[p.uid] = ""; + else p.uname = this.st.user.name; + }); + if (Object.keys(names).length > 0) { + ajax( + "/users", + "GET", + { + data: { ids: Object.keys(names).join(",") }, + success: (res2) => { + res2.users.forEach(u => { + names[u.id] = u.name; + }); + problems.forEach(p => { + if (!p.uname) + p.uname = names[p.uid]; + }); + if (!!callback) callback(); + } + } + ); + } else if (!!callback) callback(); + }, firstChars: function(text) { let preparedText = text // Replace line jumps and
by spaces @@ -251,10 +284,12 @@ export default { // Condition: vid is a valid variant ID this.loadedVar = 0; const variant = this.st.variants.find(v => v.id == vid); - const vModule = await import("@/variants/" + variant.name + ".js"); - window.V = vModule.VariantRules; - this.loadedVar = vid; - cb(); + await import("@/variants/" + variant.name + ".js") + .then((vModule) => { + window.V = vModule[variant.name + "Rules"]; + this.loadedVar = vid; + cb(); + }); }, trySetDiagram: function(prob) { // Problem edit: FEN could be wrong or incomplete, @@ -281,15 +316,36 @@ export default { showProblem: function(p) { this.loadVariant(p.vid, () => { // The FEN is already checked at this stage: - this.vr = new V(p.fen); this.game.vname = p.vname; - this.game.mycolor = this.vr.turn; //diagram orientation + this.game.mycolor = V.ParseFen(p.fen).turn; //diagram orientation + this.game.fenStart = p.fen; this.game.fen = p.fen; - this.$set(this.game, "fenStart", p.fen); - this.copyProblem(p, this.curproblem); this.showOne = true; + // $nextTick to be sure $refs["basegame"] exists + this.$nextTick(() => { + this.$refs["basegame"].re_setVariables(this.game); }); + this.copyProblem(p, this.curproblem); }); }, + gotoPrevNext: function(e, prob, dir) { + const startIdx = this.problems.findIndex(p => p.id == prob.id); + let nextIdx = startIdx + dir; + while ( + nextIdx >= 0 && + nextIdx < this.problems.length && + ((this.onlyMines && this.problems[nextIdx].uid != this.st.user.id) || + (!this.onlyMines && this.problems[nextIdx].uid == this.st.user.id)) + ) + nextIdx += dir; + if (nextIdx >= 0 && nextIdx < this.problems.length) + this.setHrefPid(this.problems[nextIdx]); + else + alert(this.st.tr["No more problems"]); + }, + prepareNewProblem: function() { + this.resetCurProb(); + window.doClick("modalNewprob"); + }, sendProblem: function() { const error = checkProblem(this.curproblem); if (error) { @@ -301,37 +357,64 @@ export default { ajax( "/problems", edit ? "PUT" : "POST", - { prob: this.curproblem }, - ret => { - if (edit) { - let editedP = this.problems.find(p => p.id == this.curproblem.id); - this.copyProblem(this.curproblem, editedP); - } - else { - // New problem - let newProblem = Object.assign({}, this.curproblem); - newProblem.id = ret.id; - newProblem.uid = this.st.user.id; - newProblem.uname = this.st.user.name; - this.problems = this.problems.concat(newProblem); - this.resetCurProb(); + { + data: { prob: this.curproblem }, + success: (ret) => { + if (edit) { + let editedP = this.problems.find(p => p.id == this.curproblem.id); + this.copyProblem(this.curproblem, editedP); + this.showProblem(editedP); + } + else { + let newProblem = Object.assign({}, this.curproblem); + newProblem.id = ret.id; + newProblem.uid = this.st.user.id; + newProblem.uname = this.st.user.name; + this.problems = [newProblem].concat(this.problems); + } + document.getElementById("modalNewprob").checked = false; + this.infoMsg = ""; } - this.infoMsg = ""; } ); }, editProblem: function(prob) { - if (!prob.diag) this.setDiagram(prob); //V is loaded at this stage + // prob.diag might correspond to some other problem or be empty: + this.setDiagram(prob); //V is loaded at this stage this.copyProblem(prob, this.curproblem); window.doClick("modalNewprob"); }, deleteProblem: function(prob) { if (confirm(this.st.tr["Are you sure?"])) { - ajax("/problems", "DELETE", { id: prob.id }, () => { - ArrayFun.remove(this.problems, p => p.id == prob.id); - this.backToList(); - }); + ajax( + "/problems", + "DELETE", + { + data: { id: prob.id }, + success: () => { + ArrayFun.remove(this.problems, p => p.id == prob.id); + this.backToList(); + } + } + ); } + }, + loadMore: function() { + ajax( + "/problems", + "GET", + { + data: { cursor: this.cursor }, + success: (res) => { + const L = res.problems.length; + if (L > 0) { + this.decorate(res.problems); + this.problems = this.problems.concat(res.problems); + this.cursor = res.problems[L - 1].added; + } else this.hasMore = false; + } + } + ); } } }; @@ -352,6 +435,13 @@ textarea margin: 0 auto max-width: 400px +table#tProblems + max-height: 100% + +button#loadMoreBtn + display: block + margin: 0 auto + #controls margin: 0 width: 100%