From d022f183c89bb54841baab787fcd4256ad39778e Mon Sep 17 00:00:00 2001 From: silas Date: Thu, 31 May 2018 15:44:13 +0200 Subject: [PATCH] update to pc --- public/js/app.js | 480 ++++++++++++++++-- .../Application/pwa/js/WordRotatorDb.js | 25 +- .../Application/pwa/js/site/LevelSite.js | 43 +- .../pwa/js/wordrotator/Level/LevelHelper.js | 21 + .../pwa/js/wordrotator/Level/SimpleLevel.js | 5 +- 5 files changed, 514 insertions(+), 60 deletions(-) create mode 100644 src/module/Application/pwa/js/wordrotator/Level/LevelHelper.js diff --git a/public/js/app.js b/public/js/app.js index a86a6d8..72d91a5 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -2997,6 +2997,439 @@ SystemSettings.setBasePath("/pwa/wordRotator/public/"); Translator.supportedLanguages = ["de", "en"]; Translator.markTranslations = false; +class Segment{ + constructor(element){ + this.rotation = 0; + this.element = element; + this.parent = null; + } + + setParent(parent) + { + this.parent = parent; + } + + getLevel() + { + if (this.parent!==null) + { + return this.parent.getLevel(); + } + } + + isSolved(){ + return (this.rotation === 0); + } + + async rotate(){ + return Promise.resolve(); + }; + + _updateElement(){}; + + applyRotations(rotations){ + return rotations; + } + + getElement() + { + return this.element; + } +} + +class DelayPromise extends Promise{ + constructor(delay) { + super((resolve) => { + setTimeout(resolve, delay); + }); + } +} + +class ParentSegment extends Segment { + constructor(element) { + super(element); + this.children = []; + this.class = "rotate-0"; + } + + async rotate() { + if (!this.getLevel().getHasWon()) { + this.rotation += 90; + this.rotation %= 360; + + this._updateRotationClass(); + this.getLevel().checkHasWon(new Promise((resolve, reject)=>{ + this.element.addEventListener("animationend", resolve); + })); + return new DelayPromise(250); + } + } + + applyRotations(rotations) { + // debugger; + this.rotation = rotations[0]; + rotations.splice(0, 1); + for (let i = 0, n = this.children.length; i < n; i++) { + rotations = this.children[i].applyRotations(rotations); + } + return rotations; + } + + isSolved() { + for (let i = 0, n = this.children.length; i < n; i++) { + if (!this.children[i].isSolved()) { + return false; + } + } + return super.isSolved(); + } + + setChildren(children) { + this.children = []; + for (let i = 0, n = children.length; i < n; i++) { + this.addChild(children[i]); + } + } + + addChild(child) { + this.children.push(child); + child.setParent(this); + this._updateElement(); + } + + _updateRotationClass() { + // this.style.transform = "rotate("+this.rotation+"deg)"; + this.element.classList.remove(this.class); + this.class = "rotate-" + this.rotation; + if (this.class === "rotate-0") { + this.class = "rotate-360"; + } + this.element.classList.add(this.class); + } + + _updateElement() { + const childContainer = this.element.querySelector(".child-container"); + childContainer.removeAllChildren(); + + this._updateRotationClass(); + + const self = this; + this.element.onclick = function () { + self.rotate(); + }; + + for (let i = 0, n = this.children.length; i < n; i++) { + this.children[i]._updateElement(); + childContainer.appendChild(this.children[i].getElement()); + } + } +} + +class LeafSegment extends Segment{ + + constructor(element, leaf) { + super(element); + this.leaf = 'A'; + if (Helper.isNotNull(leaf)) + { + this.setLeaf(leaf); + } + } + + setLeaf(leaf) + { + this.leaf = leaf; + } + + _updateElement() { + this.element.querySelector(".leaf-element").removeAllChildren().appendChild(document.createTextNode(this.leaf)); + } +} + +class TemplateContainer{ + constructor(leafTemplate, parentTemplate, rowTemplate){ + this.leafTemplate = leafTemplate; + this.parentTemplate = parentTemplate; + this.rowTemplate = rowTemplate; + } + + copyLeafTemplate() + { + return Helper.cloneNode(this.leafTemplate); + } + + copyParentTemplate() + { + return Helper.cloneNode(this.parentTemplate); + } + + copyRowTemplate() + { + return Helper.cloneNode(this.rowTemplate); + } +} + +class Level { + constructor(templateContainer) { + this.rootSegment = null; + this.words = []; + this.startRotations = []; + this.templateContainer = templateContainer; + + this.hasWon = false; + + this.wonResolver = null; + this.giveUpResolver = null; + + const self = this; + this.wonPromise = new Promise((resolve, reject) => { + self.wonResolver = resolve; + self.giveUpResolver = reject; + }); + } + + getLevel() + { + return this; + } + + setRootSegment(rootSegment) + { + this.rootSegment = rootSegment; + this.rootSegment.setParent(this); + } + + setWords(words) + { + this.words = []; + for (let i = 0, n = words.length; i < n; i++) { + this.words.push(words[i].toUpperCase()); + } + } + + setStartRotations(rotations) + { + this.startRotations = rotations; + } + + getHasWon() + { + return this.hasWon; + } + + checkHasWon(delayPromise) { + if (this.rootSegment.isSolved()){ + this.hasWon = true; + const self = this; + delayPromise.then(()=>{ + self.wonResolver(true); + }); + return true; + } + return false; + } + + getWonPromise(){ + return this.wonPromise; + } + + getRootSegment(){ + return this.rootSegment; + } + + createSegments() {}; + + static _createLeafsForWord(word, leafSegmentTemplate) + { + let leafSegments = []; + for (let i = 0, n = word.length; i < n; i++) { + leafSegments.push(new LeafSegment(Helper.cloneNode(leafSegmentTemplate), word.charAt(i))); + } + return leafSegments; + } +} + +class RowSegment extends ParentSegment{ + rotate() {} + + applyRotations(rotations) + { + for (let i = 0, n = this.children.length; i < n; i++) { + rotations = this.children[i].applyRotations(rotations); + } + return rotations; + } +} + +class RowLevel extends Level { + constructor(container, wordLength) { + super(container); + this.wordLength = wordLength; + } + + createSegments() { + if (this.words.length >= 2 && this.words[0].length >= this.wordLength && this.words[1].length >= this.wordLength) { + let leafsWordOne = Level._createLeafsForWord(this.words[0], this.templateContainer.copyLeafTemplate()); + let leafsWordTwo = Level._createLeafsForWord(this.words[1], this.templateContainer.copyLeafTemplate()); + + let rootSegment = new RowSegment(this.templateContainer.copyRowTemplate()); + for (let i = 0, n = this.wordLength / 2; i < n; i++) { + let parent = new ParentSegment(this.templateContainer.copyParentTemplate()); + parent.addChild(leafsWordOne[2 * i]); + parent.addChild(leafsWordOne[2 * i + 1]); + parent.addChild(leafsWordTwo[2 * i]); + parent.addChild(leafsWordTwo[2 * i + 1]); + rootSegment.addChild(parent); + } + + rootSegment.applyRotations(this.startRotations); + + this.setRootSegment(rootSegment); + } + } +} + +class LevelHelper{ + static setLevelType(typeId, level) + { + LevelHelper.types[typeId] = level; + } + + static getLevelClass(type) + { + return LevelHelper.types[type]; + } + + static inflateLevel(jsonLevel, templateContainer) + { + let level = new (LevelHelper.types[jsonLevel["rendererType"]])(templateContainer); + level.setWords(jsonLevel["words"]); + level.setStartRotations(jsonLevel["rotations"]); + return level; + } +} + +LevelHelper.types = {}; + +class SimpleLevel extends RowLevel{ + + constructor(container) { + super(container, 6); + } +} + +LevelHelper.setLevelType(20, SimpleLevel); + +class WordRotatorDb extends MyDb { + + static getInstance() { + if (Helper.isNull(WordRotatorDb.instance)) { + WordRotatorDb.instance = new WordRotatorDb(); + } + return WordRotatorDb.instance; + } + + constructor() { + super("wordRotator", 3); + } + + upgrade(db, oldVersion, newVersion, e) { + if (Helper.isNull(oldVersion) || oldVersion < 1 && newVersion >= 1) { + let levelObjectStore = db.createObjectStore(WordRotatorDb.OBJECT_STORE.LEVEL, {"keyPath": "id"}); + } + if (Helper.isNull(oldVersion) || oldVersion < 2 && newVersion >= 2) { + let levelObjectStore = e.target.transaction.objectStore(WordRotatorDb.OBJECT_STORE.LEVEL); + levelObjectStore.createIndex("played", ["deleted", "played", "difficulty", "id"], {"unique": false}); + } + if (Helper.isNull(oldVersion) || oldVersion < 3 && newVersion >= 3) { + let levelObjectStore = e.target.transaction.objectStore(WordRotatorDb.OBJECT_STORE.LEVEL); + levelObjectStore.createIndex("difficulty", "difficulty", {"unique": false}); + } + }; + + async saveManyLevels(levels) { + return this.saveMany(levels, WordRotatorDb.OBJECT_STORE.LEVEL); + } + + async loadLevel(levelId) { + return this.load(levelId, WordRotatorDb.OBJECT_STORE.LEVEL); + } + + async loadNextLevel() { + const levels = await this.loadMany("difficulty", IDBKeyRange.lowerBound(0), WordRotatorDb.OBJECT_STORE.LEVEL); + + let newLevels = []; + for (let i = 0, n = levels.length; i < n; i++) { + if (!levels[i].deleted && !levels[i].played) { + newLevels.push(levels[i]); + } + } + + if (newLevels.length === 0) { + return null; + } + + return newLevels[Math.round(Math.random() * newLevels.length) % newLevels.length]; + } +} + +WordRotatorDb.OBJECT_STORE = { + LEVEL: "level", +}; +WordRotatorDb.instance = null; + +class LevelSite extends AbstractSite$1 { + constructor(siteManager) { + super(siteManager, "html/application/level.html", "level"); + } + + onConstruct(args) { + this.setTitle("Level"); + return super.onConstruct(args); + } + + onFirstStart() { + super.onFirstStart(); + + let leafSegmentTemplate = this.findBy("#segment-leaf-template"); + let parentSegmentTemplate = this.findBy("#segment-parent-template"); + let rowSegmentTemplate = this.findBy("#segment-row-template"); + + leafSegmentTemplate.id = null; + parentSegmentTemplate.id = null; + rowSegmentTemplate.id = null; + + leafSegmentTemplate.remove(); + parentSegmentTemplate.remove(); + rowSegmentTemplate.remove(); + + this.templateContainer = new TemplateContainer(leafSegmentTemplate, parentSegmentTemplate, rowSegmentTemplate); + this.nextLevel(); + } + + async nextLevel() { + try { + const db = WordRotatorDb.getInstance(); + const nextLevelJson = await db.loadNextLevel(); + const level = LevelHelper.inflateLevel(nextLevelJson, this.templateContainer); + + const self = this; + level.getWonPromise().then(() => { + self.nextLevel(); + }); + + level.createSegments(); + level.getRootSegment()._updateElement(); + this.findBy("#level").appendChild(level.getRootSegment().getElement()); + + this.level = level; + } + catch (e) { + console.error(e); + } + } +} + class DataManager { static load(url, isCachable, raw) { isCachable = Helper.nonNull(isCachable, false); @@ -3144,50 +3577,22 @@ InitPromise.addPromise(function (app) { } }); -class WordRotatorDb extends MyDb { - - static getInstance() { - if (Helper.isNull(WordRotatorDb.instance)) { - WordRotatorDb.instance = new WordRotatorDb(); - } - return WordRotatorDb.instance; - } - - constructor() { - super("wordRotator", 1); - } - - upgrade(db, oldVersion, newVersion, e) { - if (Helper.isNull(oldVersion) || oldVersion < 1 && newVersion >= 1) { - let levelObjectStore = db.createObjectStore(WordRotatorDb.OBJECT_STORE.LEVEL, {"keyPath": "id"}); - } - }; - - async saveManyLevels(levels) { - return this.saveMany(levels, WordRotatorDb.OBJECT_STORE.LEVEL); - } - - async loadLevel(levelId) - { - return this.load(levelId, WordRotatorDb.OBJECT_STORE.LEVEL); - } - -} - -WordRotatorDb.OBJECT_STORE = { - LEVEL: "level", -}; -WordRotatorDb.instance = null; - class SynchronizeSite extends AbstractSite$1 { constructor(siteManager) { super(siteManager, "html/application/sync.html"); } + + async onConstruct(args) { + let res = await super.onConstruct(args); + await this.loadLevels(); + return res; + } + onFirstStart() { super.onFirstStart(); - this.loadLevels(); + this.startSite(LevelSite); } async loadLevels() { @@ -3220,10 +3625,9 @@ class SynchronizeSite extends AbstractSite$1 { } } let levels = await Promise.all(levelPromises); - console.log(levels); await db.saveManyLevels(levels); - // localStorage.setItem("date-last-sync", newLastSync); + localStorage.setItem("date-last-sync", newLastSync); } } diff --git a/src/module/Application/pwa/js/WordRotatorDb.js b/src/module/Application/pwa/js/WordRotatorDb.js index a363890..69b5c45 100644 --- a/src/module/Application/pwa/js/WordRotatorDb.js +++ b/src/module/Application/pwa/js/WordRotatorDb.js @@ -10,7 +10,7 @@ export class WordRotatorDb extends MyDb { } constructor() { - super("wordRotator", 2); + super("wordRotator", 3); } upgrade(db, oldVersion, newVersion, e) { @@ -19,7 +19,11 @@ export class WordRotatorDb extends MyDb { } if (Helper.isNull(oldVersion) || oldVersion < 2 && newVersion >= 2) { let levelObjectStore = e.target.transaction.objectStore(WordRotatorDb.OBJECT_STORE.LEVEL); - levelObjectStore.createIndex("played", ["played", "difficulty", "id"], {"unique": false}); + levelObjectStore.createIndex("played", ["deleted", "played", "difficulty", "id"], {"unique": false}); + } + if (Helper.isNull(oldVersion) || oldVersion < 3 && newVersion >= 3) { + let levelObjectStore = e.target.transaction.objectStore(WordRotatorDb.OBJECT_STORE.LEVEL); + levelObjectStore.createIndex("difficulty", "difficulty", {"unique": false}); } }; @@ -30,6 +34,23 @@ export class WordRotatorDb extends MyDb { async loadLevel(levelId) { return this.load(levelId, WordRotatorDb.OBJECT_STORE.LEVEL); } + + async loadNextLevel() { + const levels = await this.loadMany("difficulty", IDBKeyRange.lowerBound(0), WordRotatorDb.OBJECT_STORE.LEVEL); + + let newLevels = []; + for (let i = 0, n = levels.length; i < n; i++) { + if (!levels[i].deleted && !levels[i].played) { + newLevels.push(levels[i]); + } + } + + if (newLevels.length === 0) { + return null; + } + + return newLevels[Math.round(Math.random() * newLevels.length) % newLevels.length]; + } } WordRotatorDb.OBJECT_STORE = { diff --git a/src/module/Application/pwa/js/site/LevelSite.js b/src/module/Application/pwa/js/site/LevelSite.js index 345f5a4..082dfa3 100644 --- a/src/module/Application/pwa/js/site/LevelSite.js +++ b/src/module/Application/pwa/js/site/LevelSite.js @@ -3,8 +3,10 @@ import {ParentSegment} from "../wordrotator/Segment/ParentSegment"; import {LeafSegment} from "../wordrotator/Segment/LeafSegment"; import {TemplateContainer} from "../wordrotator/Segment/TemplateContainer"; import {SimpleLevel} from "../wordrotator/Level/SimpleLevel"; +import {LevelHelper} from "../wordrotator/Level/LevelHelper"; +import {WordRotatorDb} from "../WordRotatorDb"; -export class LevelSite extends AbstractSite{ +export class LevelSite extends AbstractSite { constructor(siteManager) { super(siteManager, "html/application/level.html", "level"); } @@ -29,26 +31,29 @@ export class LevelSite extends AbstractSite{ parentSegmentTemplate.remove(); rowSegmentTemplate.remove(); - let templateContainer = new TemplateContainer(leafSegmentTemplate, parentSegmentTemplate, rowSegmentTemplate); - - let level = new SimpleLevel(templateContainer); - level.setWords([ - "Dynamo", - "Abhang" - ]); - level.setStartRotations([0,90,180]); - - level.getWonPromise().then(()=>{ - console.log("has won"); - }); - - level.createSegments(); - level.getRootSegment()._updateElement(); - this.findBy("#level").appendChild(level.getRootSegment().getElement()); + this.templateContainer = new TemplateContainer(leafSegmentTemplate, parentSegmentTemplate, rowSegmentTemplate); + this.nextLevel(); } - async nextLevel() - { + async nextLevel() { + try { + const db = WordRotatorDb.getInstance(); + const nextLevelJson = await db.loadNextLevel(); + const level = LevelHelper.inflateLevel(nextLevelJson, this.templateContainer); + const self = this; + level.getWonPromise().then(() => { + self.nextLevel(); + }); + + level.createSegments(); + level.getRootSegment()._updateElement(); + this.findBy("#level").appendChild(level.getRootSegment().getElement()); + + this.level = level; + } + catch (e) { + console.error(e); + } } } \ No newline at end of file diff --git a/src/module/Application/pwa/js/wordrotator/Level/LevelHelper.js b/src/module/Application/pwa/js/wordrotator/Level/LevelHelper.js new file mode 100644 index 0000000..6676ccc --- /dev/null +++ b/src/module/Application/pwa/js/wordrotator/Level/LevelHelper.js @@ -0,0 +1,21 @@ +export class LevelHelper{ + static setLevelType(typeId, level) + { + LevelHelper.types[typeId] = level; + } + + static getLevelClass(type) + { + return LevelHelper.types[type]; + } + + static inflateLevel(jsonLevel, templateContainer) + { + let level = new (LevelHelper.types[jsonLevel["rendererType"]])(templateContainer); + level.setWords(jsonLevel["words"]); + level.setStartRotations(jsonLevel["rotations"]); + return level; + } +} + +LevelHelper.types = {}; \ No newline at end of file diff --git a/src/module/Application/pwa/js/wordrotator/Level/SimpleLevel.js b/src/module/Application/pwa/js/wordrotator/Level/SimpleLevel.js index 6d86519..d45f728 100644 --- a/src/module/Application/pwa/js/wordrotator/Level/SimpleLevel.js +++ b/src/module/Application/pwa/js/wordrotator/Level/SimpleLevel.js @@ -1,8 +1,11 @@ import {RowLevel} from "./RowLevel"; +import {LevelHelper} from "./LevelHelper"; export class SimpleLevel extends RowLevel{ constructor(container) { super(container, 6); } -} \ No newline at end of file +} + +LevelHelper.setLevelType(20, SimpleLevel); \ No newline at end of file