diff --git a/.idea/wordRotator.iml b/.idea/wordRotator.iml index 649fc88..86ac3ff 100755 --- a/.idea/wordRotator.iml +++ b/.idea/wordRotator.iml @@ -4,6 +4,7 @@ + diff --git a/bin/build.js b/bin/build.js index 198c753..7070198 100755 --- a/bin/build.js +++ b/bin/build.js @@ -66,7 +66,7 @@ async function build() { if (shouldMangleAndTranspile) { const uglifyRes = uglifyJs.minify(code, uglifyOptions); code = uglifyRes.code; - fs.writeFileSync('transpiled.js', code); + // fs.writeFileSync('transpiled.js', code); const babelRes = babel.transform(code, babelOptions); code = babelRes.code; code = regenerator.compile(code, regeneratorOptions).code; diff --git a/public/css/wordRotator.css b/public/css/wordRotator.css index 7dab7ff..b271439 100755 --- a/public/css/wordRotator.css +++ b/public/css/wordRotator.css @@ -1,2 +1,2 @@ -nav.top-bar.title-bar{padding:.3rem .6rem 0}#action-bar .top-bar-right .menu .action.img a{padding-bottom:0}#action-bar .top-bar-right .menu .action.img a img{max-height:1.8rem}.dropdown.menu a,.menu a{padding:.2rem .5rem}#level-number-container{-webkit-transition:none;transition:none;position:absolute;left:50%;-webkit-transform:translate(-50%);transform:translate(-50%);border:3px solid #fff;border-radius:50%;visibility:hidden;display:table-cell;height:35px;width:35px;text-align:center;vertical-align:middle}#level-number-container.visible{visibility:visible}#level-number-container #level-number{-webkit-transition:none;transition:none;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-weight:700}.coin-counter{display:inline-block;position:relative;font-size:1.6rem}.coin-counter :after{background-image:url(../img/coinTower.png);background-size:28px 28px;width:28px;height:28px;display:inline-block;content:""}#coin-container{height:30px}#coin-container .coin{margin-left:3px;margin-right:3px;max-width:30px;display:inline-block}.height-10{height:10%}.width-10{width:10%}.height-20{height:20%}.width-20{width:20%}.height-30{height:30%}.width-30{width:30%}.height-40{height:40%}.width-40{width:40%}.height-50{height:50%}.width-50{width:50%}.height-60{height:60%}.width-60{width:60%}.height-70{height:70%}.width-70{width:70%}.height-80{height:80%}.width-80{width:80%}.height-90{height:90%}.width-90{width:90%}.height-100{height:100%}.width-100{width:100%}@-webkit-keyframes rotate-90{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}@keyframes rotate-90{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}@-webkit-keyframes rotate-180{0%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}to{-webkit-transform:rotate(180deg);transform:rotate(180deg)}}@keyframes rotate-180{0%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}to{-webkit-transform:rotate(180deg);transform:rotate(180deg)}}@-webkit-keyframes rotate-270{0%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@keyframes rotate-270{0%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@-webkit-keyframes rotate-360{0%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate-360{0%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.segment:not(.segment-row):not(.segment-triangle).rotating{z-index:10!important;overflow:hidden}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-90{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-180{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-270{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-360{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180,.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-90{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-180{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-270{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-360{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-90{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-180{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-270{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-360{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment{-webkit-transform:rotate(0deg);transform:rotate(0deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-360{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}#level{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap;max-width:100%;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow-y:visible}#level,#level *,.segment{-webkit-transition:none;transition:none}.segment{vertical-align:top;white-space:normal;cursor:pointer;display:inline-block;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1;background-color:#fff;line-height:0}.segment.segment-row{display:block;width:100%;-webkit-animation:none!important;animation:none!important;white-space:nowrap}.segment.segment-leaf{background-color:transparent;min-width:1em;padding:.8em}.segment.segment-leaf:before{content:" ";display:block;padding-top:100%}.segment.segment-leaf .leaf-element{position:absolute;width:100%;height:100%;line-height:1.5em;top:0;left:0}.segment.segment-parent{border:1px solid #a9a9a9;border-radius:3px;padding:1px}.segment.segment-parent.layer-2{border:3px solid #000}#site-content>:not(.won) .segment.locked,#site-content>:not(.won) .segment.locked>.child-container>.segment-leaf{border-color:#3adb76;background-color:#9ffbb5!important}#site-content>:not(.won) .show-when-won{display:none}.level-container{-webkit-transition:none;transition:none}.won .show-while-playing{display:none}.text-right{text-align:right}#continue-button{margin-bottom:2px} +nav.top-bar.title-bar{padding:.3rem .6rem 0}#action-bar .top-bar-right .menu .action.img a{padding-bottom:0}#action-bar .top-bar-right .menu .action.img a img{max-height:1.8rem}.dropdown.menu a,.menu a{padding:.2rem .5rem}#level-number-container{z-index:1;-webkit-transition:none;transition:none;position:absolute;left:50%;-webkit-transform:translate(-50%);transform:translate(-50%);border:3px solid #fff;border-radius:50%;visibility:hidden;display:table-cell;height:35px;width:35px;text-align:center;vertical-align:middle}#level-number-container.visible{visibility:visible}#level-number-container.in-main-menu{background:#fff;border-color:#000;height:1em;width:1em;min-height:1em;min-width:1em;max-height:1em;max-width:1em}#level-number-container #level-number{-webkit-transition:none;transition:none;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-weight:700}.coin-counter{display:inline-block;position:relative;font-size:1.6rem}.coin-counter :after{background-image:url(../img/coinTower.png);background-size:28px 28px;width:28px;height:28px;display:inline-block;content:""}#coin-container{height:30px}#coin-container .coin{margin-left:3px;margin-right:3px;max-width:30px;display:inline-block}.height-10{height:10%}.width-10{width:10%}.height-20{height:20%}.width-20{width:20%}.height-30{height:30%}.width-30{width:30%}.height-40{height:40%}.width-40{width:40%}.height-50{height:50%}.width-50{width:50%}.height-60{height:60%}.width-60{width:60%}.height-70{height:70%}.width-70{width:70%}.height-80{height:80%}.width-80{width:80%}.height-90{height:90%}.width-90{width:90%}.height-100{height:100%}.width-100{width:100%}@-webkit-keyframes rotate-90{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}@keyframes rotate-90{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}@-webkit-keyframes rotate-180{0%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}to{-webkit-transform:rotate(180deg);transform:rotate(180deg)}}@keyframes rotate-180{0%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}to{-webkit-transform:rotate(180deg);transform:rotate(180deg)}}@-webkit-keyframes rotate-270{0%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@keyframes rotate-270{0%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@-webkit-keyframes rotate-360{0%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate-360{0%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.segment:not(.segment-row):not(.segment-triangle).rotating{z-index:10!important;overflow:hidden}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-90>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-180>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-270>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;animation-direction:reverse;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-90{-webkit-animation-name:rotate-180;animation-name:rotate-180}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-180{-webkit-animation-name:rotate-270;animation-name:rotate-270}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-270{-webkit-animation-name:rotate-360;animation-name:rotate-360}.segment:not(.segment-row):not(.segment-triangle).rotating.rotate-360>.child-container>.segment.rotate-360{-webkit-animation-name:rotate-90;animation-name:rotate-90}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-90{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-180{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-270{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-360{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-90>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180,.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-90{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-180{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-270{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-360{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-180>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-90{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-180{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-270{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-360{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-270>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment{-webkit-transform:rotate(0deg);transform:rotate(0deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-90.rotating{-webkit-animation-name:rotate-90;animation-name:rotate-90;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-180.rotating{-webkit-animation-name:rotate-180;animation-name:rotate-180;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-270.rotating{-webkit-animation-name:rotate-270;animation-name:rotate-270;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-360{-webkit-transform:rotate(1turn);transform:rotate(1turn);background-color:#fff;z-index:1}.segment:not(.segment-row):not(.segment-triangle):not(.rotating).rotate-360>.child-container>.segment.rotate-360.rotating{-webkit-animation-name:rotate-360;animation-name:rotate-360;-webkit-animation-duration:.25s;animation-duration:.25s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:linear;animation-timing-function:linear}#level{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap;max-width:100%;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow-y:visible}#level,#level *,.segment{-webkit-transition:none;transition:none}.segment{vertical-align:top;white-space:normal;cursor:pointer;display:inline-block;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1;background-color:#fff;line-height:0}.segment.segment-row{display:block;width:100%;-webkit-animation:none!important;animation:none!important;white-space:nowrap}.segment.segment-leaf{background-color:transparent;min-width:1em;padding:.8em}.segment.segment-leaf:before{content:" ";display:block;padding-top:100%}.segment.segment-leaf .leaf-element{position:absolute;width:100%;height:100%;line-height:1.5em;top:0;left:0}.segment.segment-parent{border:1px solid #a9a9a9;border-radius:3px;padding:1px}.segment.segment-parent.layer-2{border:3px solid #000}#site-content>:not(.won) .segment.locked,#site-content>:not(.won) .segment.locked>.child-container>.segment-leaf{border-color:#3adb76;background-color:#9ffbb5!important}#site-content>:not(.won) .show-when-won{display:none}.level-container{-webkit-transition:none;transition:none}.won .show-while-playing{display:none}.text-right{text-align:right}#continue-button{margin-bottom:2px} /*# sourceMappingURL=wordRotator.css.map */ \ No newline at end of file diff --git a/public/html/application/menu.html b/public/html/application/menu.html index d0343fa..e139ecc 100644 --- a/public/html/application/menu.html +++ b/public/html/application/menu.html @@ -1 +1 @@ -
WordRotator
W
O

R
 
R
D

 
 

O
 

T
A
 
R

T
O
\ No newline at end of file +
W
O

R
 
R
D

 
 

O
 

T
A
 
R

T
O
999
\ No newline at end of file diff --git a/public/js/app.js b/public/js/app.js index 50cdf83..5a6b823 100755 --- a/public/js/app.js +++ b/public/js/app.js @@ -1 +1,6085 @@ -!function(t){"use strict";var e,n=Object.prototype,r=n.hasOwnProperty,i="function"==typeof Symbol?Symbol:{},o=i.iterator||"@@iterator",s=i.asyncIterator||"@@asyncIterator",a=i.toStringTag||"@@toStringTag",u="object"==typeof module,l=t.regeneratorRuntime;if(l)u&&(module.exports=l);else{(l=t.regeneratorRuntime=u?module.exports:{}).wrap=k;var c="suspendedStart",h="suspendedYield",f="executing",d="completed",v={},p={};p[o]=function(){return this};var y=Object.getPrototypeOf,m=y&&y(y(C([])));m&&m!==n&&r.call(m,o)&&(p=m);var g=O.prototype=_.prototype=Object.create(p);b.prototype=g.constructor=O,O.constructor=b,O[a]=b.displayName="GeneratorFunction",l.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===b||"GeneratorFunction"===(e.displayName||e.name))},l.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,O):(t.__proto__=O,a in t||(t[a]="GeneratorFunction")),t.prototype=Object.create(g),t},l.awrap=function(t){return{__await:t}},L(P.prototype),P.prototype[s]=function(){return this},l.AsyncIterator=P,l.async=function(t,e,n,r){var i=new P(k(t,e,n,r));return l.isGeneratorFunction(e)?i:i.next().then(function(t){return t.done?t.value:i.next()})},L(g),g[a]="Generator",g[o]=function(){return this},g.toString=function(){return"[object Generator]"},l.keys=function(t){var e=[];for(var n in t)e.push(n);return e.reverse(),function n(){for(;e.length;){var r=e.pop();if(r in t)return n.value=r,n.done=!1,n}return n.done=!0,n}},l.values=C,S.prototype={constructor:S,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=e,this.done=!1,this.delegate=null,this.method="next",this.arg=e,this.tryEntries.forEach(A),!t)for(var n in this)"t"===n.charAt(0)&&r.call(this,n)&&!isNaN(+n.slice(1))&&(this[n]=e)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var n=this;function i(r,i){return a.type="throw",a.arg=t,n.next=r,i&&(n.method="next",n.arg=e),!!i}for(var o=this.tryEntries.length-1;o>=0;--o){var s=this.tryEntries[o],a=s.completion;if("root"===s.tryLoc)return i("end");if(s.tryLoc<=this.prev){var u=r.call(s,"catchLoc"),l=r.call(s,"finallyLoc");if(u&&l){if(this.prev=0;--n){var i=this.tryEntries[n];if(i.tryLoc<=this.prev&&r.call(i,"finallyLoc")&&this.prev=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),A(n),v}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var r=n.completion;if("throw"===r.type){var i=r.arg;A(n)}return i}}throw new Error("illegal catch attempt")},delegateYield:function(t,n,r){return this.delegate={iterator:C(t),resultName:n,nextLoc:r},"next"===this.method&&(this.arg=e),v}}}function k(t,e,n,r){var i=e&&e.prototype instanceof _?e:_,o=Object.create(i.prototype),s=new S(r||[]);return o._invoke=function(t,e,n){var r=c;return function(i,o){if(r===f)throw new Error("Generator is already running");if(r===d){if("throw"===i)throw o;return j()}for(n.method=i,n.arg=o;;){var s=n.delegate;if(s){var a=x(s,n);if(a){if(a===v)continue;return a}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(r===c)throw r=d,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);r=f;var u=w(t,e,n);if("normal"===u.type){if(r=n.done?d:h,u.arg===v)continue;return{value:u.arg,done:n.done}}"throw"===u.type&&(r=d,n.method="throw",n.arg=u.arg)}}}(t,n,s),o}function w(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}function _(){}function b(){}function O(){}function L(t){["next","throw","return"].forEach(function(e){t[e]=function(t){return this._invoke(e,t)}})}function P(t){var e;this._invoke=function(n,i){function o(){return new Promise(function(e,o){!function e(n,i,o,s){var a=w(t[n],t,i);if("throw"!==a.type){var u=a.arg,l=u.value;return l&&"object"==typeof l&&r.call(l,"__await")?Promise.resolve(l.__await).then(function(t){e("next",t,o,s)},function(t){e("throw",t,o,s)}):Promise.resolve(l).then(function(t){u.value=t,o(u)},function(t){return e("throw",t,o,s)})}s(a.arg)}(n,i,e,o)})}return e=e?e.then(o,o):o()}}function x(t,n){var r=t.iterator[n.method];if(r===e){if(n.delegate=null,"throw"===n.method){if(t.iterator.return&&(n.method="return",n.arg=e,x(t,n),"throw"===n.method))return v;n.method="throw",n.arg=new TypeError("The iterator does not provide a 'throw' method")}return v}var i=w(r,t.iterator,n.arg);if("throw"===i.type)return n.method="throw",n.arg=i.arg,n.delegate=null,v;var o=i.arg;return o?o.done?(n[t.resultName]=o.value,n.next=t.nextLoc,"return"!==n.method&&(n.method="next",n.arg=e),n.delegate=null,v):o:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,v)}function E(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function A(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function S(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(E,this),this.reset(!0)}function C(t){if(t){var n=t[o];if(n)return n.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var i=-1,s=function n(){for(;++i0){this.G.splice(e,1);for(var n=this.ut(t),r=0,i=n.length;r0){var t=arguments[0],n=Array.prototype.slice.call(arguments,1);return e.A(t)&&(0===n.length||e.Qt.apply(null,[t[n[0]]].concat(n.slice(1))))}return!1}},{key:"ct",value:function(t){return null===t||void 0===t}},{key:"A",value:function(t){return!e.ct(t)}},{key:"t",value:function(t,n){return e.A(t)?t:n}},{key:"Yt",value:function(t){return!e.empty(t)}},{key:"Zt",value:function(t){var e=[];for(var n in t)e.push(encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return"?"+e.join("&")}},{key:"empty",value:function(t){return e.ct(t)||"string"==typeof t&&""===t.trim()}},{key:"te",value:function(t){var e=document.createElement("template");return e.innerHTML=t,e.content.childNodes}},{key:"ee",value:function(){var t="http://www.w3.org/2000/svg",e=document.createElement("div");e.className="loader";var n=document.createElementNS(t,"svg");n.setAttribute("viewBox","0 0 32 32"),n.setAttribute("widh","32"),n.setAttribute("height","32");var r=document.createElementNS(t,"circle");return r.setAttribute("id","spinner"),r.setAttribute("cx","16"),r.setAttribute("cy","16"),r.setAttribute("r","14"),r.setAttribute("fill","none"),n.appendChild(r),e.appendChild(n),e}},{key:"Nt",value:function(t){return v.ne()+t}},{key:"se",value:function(){return navigator.userAgent.match(/iPhone|iPad|iPod/i)}},{key:"ie",value:function(){return null!==navigator.userAgent.match(/Android|BlackBerry|Opera Mini|IEMobile/i)||e.se()||void 0!==window.orientation||!1===window.orientation||null===window.orientation}},{key:"select",value:function(t){var e=document.createRange();e.selectNodeContents(t);var n=window.getSelection();n.removeAllRanges(),n.addRange(e)}},{key:"format",value:function(t,e){for(t=""+t;t.length0&&(o=new Array(r+1-s).join("0")+o),n+=o}return n}},{key:"oe",value:function(t,e){for(var n=Math.floor(Math.log(265)/Math.log(e)),r=t.match(new RegExp(".{1,"+n+"}","g"))||[],i="",o=0,s=r.length;o1&&0==(3&a)&&(a%100!=0||a%400==0)?1:0),3),"%k":""+u,"%l":(u+11)%12+1,"%m":v(s+1,2),"%M":v(n.getMinutes(),2),"%p":u<12?"AM":"PM","%P":u<12?"am":"pm","%s":Math.round(n.getTime()/1e3),"%S":v(n.getSeconds(),2),"%u":i||7,"%V":function(){var t=d(),e=t.valueOf();t.setMonth(0,1);var n=t.getDay();return 4!==n&&t.setMonth(0,1+(4-n+7)%7),v(1+Math.ceil((e-t)/6048e5),2)}(),"%w":""+i,"%x":n.toLocaleDateString(),"%X":n.toLocaleTimeString(),"%y":(""+a).slice(2),"%Y":a,"%z":n.toTimeString().replace(/.+GMT([+-]\d+).+/,"$1"),"%Z":n.toTimeString().replace(/.+\((.+?)\)$/,"$1")}[t]||t})}},{key:"he",value:function(n){var r=void 0;if(e.ct(n)||"object"!=(void 0===n?"undefined":t(n)))return n;if(n instanceof Array){var i=[];for(r=0;r",""":'"',"'":"'","’":"’","‘":"‘","–":"–","—":"—","…":"…","”":"”"};return e.A(t)&&"function"==typeof t.replace?t.replace(/\&[\w\d\#]{2,5}\;/g,function(t){return n[t]}):t}},{key:"ce",value:function(t){var e=new FormData;for(var n in t)e.set(n,t[n]);return e}},{key:"de",value:function(t,n){var r=window.getComputedStyle(t),i=window.getComputedStyle(n);if(i.height>r.height||i.width>r.width)return e.ge(t,n)}},{key:"ge",value:function(t,n){e.me(t);for(var r=window.getComputedStyle(t),i=window.getComputedStyle(n),o=0,s=parseFloat(i.getPropertyValue("font-size")),a=i.width,u=i.height;i.height>r.height||i.width>r.width;)if(s*=.95,u>r.height&&(u*=.95),a>i.width&&(a*=.95),n.style["font-size"]=s+"px",n.style["max-height"]=u+"px",n.style["max-width"]=a+"px",++o>2e3){console.log("breaked");break}e.pe(n),i=window.getComputedStyle(n),n.style["font-size"]=parseFloat(i.getPropertyValue("font-size"))/parseFloat(document.documentElement.clientHeight)*100+"vh"}},{key:"me",value:function(t){for(var n=t.childNodes,r=0,i=n.length;r-1,i=e.userAgent.indexOf("Edge")>-1;return!!e.userAgent.match("CriOS")||null!==t&&void 0!==t&&"Google Inc."===n&&!1===r&&!1===i}},{key:"Se",value:function(t,e){for(var n={},r=0,i=t.length;r0&&(n=r[0])}else-1!==t.Pe.indexOf(e)&&(n=e);if(d.A(n)){localStorage.setItem("currentTheme",n.Le);var i=new Promise(function(t){document.querySelector("nav.top-bar").addEventListener("transitionend",function(){t()})});document.body.className=n.be,t.Ae=n;for(var o=0,s=t.Fe.length;o0?t.Te(n[0]):t.Pe.length>0&&t.Te(t.Pe[0])}}},{key:"Re",value:function(){return new a(t.Ae.Le,function(e){var n=(t.Pe.indexOf(t.Ae)+1)%t.Pe.length;t.Te(t.Pe[n]),e.title=t.Ae.Le,e.h.k()},l.V)}},{key:"addChangeListener",value:function(e){t.Fe.push(e)}}]),t}();p.Pe=[],p.Fe=[];var y=function(){function t(e){s(this,t),this.xe=e,this.De=!0,this.Be=3650,this.ke="complianceCookie",this.Ie="true"}return n(t,[{key:"Ue",value:function(){t.Ee(this.ke)!==this.Ie&&this.show()}},{key:"We",value:function(){this.Oe(this.ke,this.Ie,this.Be)}},{key:"Oe",value:function(t,e,n){var r=void 0;if(d.A(n)){var i=new Date;i.setTime(i.getTime()+24*n*60*60*1e3),r="; expires="+i.toGMTString()}else r="";this.De&&(document.cookie=t+"="+e+r+"; path=/")}},{key:"Ne",value:function(t){this.Oe(t,"",-1)}},{key:"show",value:function(){var t=this,e=document.getElementById(this.xe);e.style.display="block",e.querySelector("#close-cookie-msg").onclick=function(){t.We(),e.remove()}}}],[{key:"Ee",value:function(t){for(var e=t+"=",n=document.cookie.split(";"),r=0;r0||("smedium"===t||"small"===t)&&r.ze(e.getElementsByClassName(l.o)).length>0||"small"===t&&r.ze(e.getElementsByClassName(l.dt)).length>0||r.ze(e.getElementsByClassName(l.q)).length>0?document.getElementById("responsive-menu-toggle").style.display="block":(document.getElementById("responsive-menu-toggle").style.display="none",d.A(r._e)&&r._e.close())}},{key:"ot",value:function(){var t=e(r.prototype.__proto__||Object.getPrototypeOf(r.prototype),"ot",this).call(this);return function(e){t(e)instanceof u||!d.A(r._e)||r._e.close()}}},{key:"nt",value:function(t){var n=e(r.prototype.__proto__||Object.getPrototypeOf(r.prototype),"nt",this).call(this,t);return this.je(),r._e=this,n}},{key:"close",value:function(){document.getElementById("responsive-menu").style.display="none";for(var t=0,e=this.Y.length;t0;){var i=this.ts.firstChild;i.remove(),r.appendChild(i)}this.es={mn:r,title:document.title};var o=this;window.onpopstate=function(){if(o.Xn.length>=1){var t=o.Xn[o.Xn.length-1].En();!1!==t.Rn()&&o.Hn(t)}}}return n(t,[{key:"gn",value:function(){return this.es}},{key:"ns",value:function(t){this.Zn=t}},{key:"wn",value:function(){return this.Zn}},{key:"ss",value:function(t){this.Yn.push(t)}},{key:"Pn",value:function(){return this.Yn}},{key:"Sn",value:function(){var t=r(regeneratorRuntime.mark(function t(e,n){var i,o,s,a,u=this;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:if(e.prototype instanceof w){t.next=2;break}throw{error:"wrong class given! Expected AbstractSite, given "+e.name};case 2:return i=new e(this),o={},s=new Promise(function(t,e){o.resolve=t,o.reject=e}),a=new _(i,o),t.abrupt("return",(this.Kn.removeAllChildren().appendChild(d.ee()),this.Qn=Promise.resolve(n).then(function(){var t=r(regeneratorRuntime.mark(function t(e){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return a.Jn(e),t.next=3,Promise.all([i.Ze(e),i.$e]);case 3:return i.un=i.Tn(u.rs()),t.abrupt("return",u.show(a));case 5:case"end":return t.stop()}},t,u)}));return function(){return t.apply(this,arguments)}}()).catch(function(t){console.error("site start error:",t)}),s));case 4:case"end":return t.stop()}},t,this)}));return function(){return t.apply(this,arguments)}}()},{key:"Hn",value:function(t,e){var n=this;this.Qn.then(function(){var r=n.os(t),i=n.Xn.splice(r,1),o=null;if((i=i[0])===n.$n){n.$n.En().sn(),n.$n=null;var s=n.Xn.length-1;if(s<0)return n.as(),void n.Sn(n.Zn);n.Kn.removeAllChildren().appendChild(d.ee()),o=n.Xn[s]}i.En().in(),Promise.resolve(e).then(function(t){i.zn().resolve(t),d.A(o)&&n.show(o)})})}},{key:"addListener",value:function(t,e,n,r){this.Kn.addEventListener(e,function(e){var i=e.target;t.an&&i.matches(n)&&r(i,e)})}},{key:"Dn",value:function(t,e,n,r,i){this.addListener(t,n,r,i),this.xn(t,e,i)}},{key:"xn",value:function(t,e,n){window.addEventListener("keydown",function(r){t.an&&r.which===e&&n(this,r)})}},{key:"yn",value:function(t){var e=this.os(t),n=this.Xn.splice(e,1);n=n[0],this.show(n)}},{key:"refreshCurrentSite",value:function(){return this.show(this.$n)}},{key:"show",value:function(t){d.A(this.$n)&&(this.$n.jn(this.$n.En().sn()),this.$n.Nn(this.Kn.innerHTML)),this.Kn.removeAllChildren().appendChild(d.ee());var e=this;return this.$n=t,-1===this.Xn.indexOf(t)&&this.Xn.push(t),t.En().$e.then(function(n){return t.En().un.k(),e.Kn.removeAllChildren().appendChild(n),e.pn(),f._t().jt(),n}).then(function(n){t.En().tn(t._n()),history.pushState({siteName:t.En().constructor.name,siteData:n.outerHTML,stackPosition:e.Xn.length-1},t.En().constructor.name,t.En().Cn())})}},{key:"bn",value:function(t){if(d.A(this.$n)&&this.$n.En()===t){history.replaceState({siteName:t.constructor.name,siteData:t.Ke.outerHTML,stackPosition:this.Xn.length-1},t.constructor.name,t.Cn())}}},{key:"ls",value:function(){if(null!=this.$n)return this.$n.En()}},{key:"hs",value:function(){null!=this.$n&&this.$n.En().un.k()}},{key:"pn",value:function(){var t=this.ls().title;this.ts.removeAllChildren().appendChild(t.mn),document.title=d.t(t.title,this.es.title)}},{key:"os",value:function(t){for(var e=0,n=this.Xn.length;e=0&&(this.ps[e].remove(!0),this.ps.splice(e,1))}},{key:"Sn",value:function(t,e){return this.cs.Sn(t,e)}},{key:"start",value:function(e){v.Me(this.He);var n=d.t(this.Fs(),e),r=t.Ds();this.ws=e,f.init(),p.init(),this.fs&&this.ss(p.Re()),this.cs=new b(this.gs,this.ds),this.cs.Yn=this.ps,this.cs.ns(e),this.cs.Sn(n,r),this.Cs(),this.Ss&&new y("cookie-compliance").Ue()}}],[{key:"Rs",value:function(t){if(d.ct(t))return null;for(var e={},n=[],r=t.split("&"),i=0;i0&&(e[n[0]]=decodeURIComponent(n[1]));return e}},{key:"Ds",value:function(){return t.Rs(window.location.search.substr(1))}}]),t}(),P=function(){function t(e,n){s(this,t),this.Bs=null,this.content=null,this.ks=null,this.cancelable=!0,this.title=d.t(n,""),this.Is=!0,this.Us="",this.buttons=[],this.result=null,d.A(e)&&this.Es(e)}return n(t,[{key:"H",value:function(t){return this.title=t,this}},{key:"Ws",value:function(t){this.Is=t}},{key:"Os",value:function(t){this.Us=t}},{key:"P",value:function(){return this.title}},{key:"Ns",value:function(t){return this.cancelable=!0===t,this}},{key:"Es",value:function(){var t=r(regeneratorRuntime.mark(function t(e){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return this._s=Promise.resolve(e),t.next=3,this._s;case 3:return this.content=t.sent,t.abrupt("return",this);case 5:case"end":return t.stop()}},t,this)}));return function(){return t.apply(this,arguments)}}()},{key:"js",value:function(t,e,n){n=d.t(n,!0);var r=null;"string"==typeof t?((r=document.createElement("button")).classList.add("button"),r.classList.add("right"),r.appendChild(f.at(t))):r=t;var i=this;if("function"!=typeof e){var o=e;e=function(){i.result=o}}var s;s=n?function(t){d.A(e)&&e(t),i.close()}:e,d.A(s)&&r.addEventListener("click",s),this.buttons.push(r)}},{key:"show",value:function(){var t=r(regeneratorRuntime.mark(function t(){var e,n,r,i,o,s,a,u,l;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:for((e=document.createElement("span")).classList.add("title"),this.Is&&""!==this.title?e.appendChild(f.at(this.title)):e.innerHTML=this.title,(n=document.createElement("div")).appendChild(e),(r=document.createElement("div")).classList.add("content-container"),(i=document.createElement("div")).className=this.Us,i.classList.add("modal"),i.appendChild(n),i.appendChild(r),(o=document.createElement("div")).classList.add("modal-button-container"),s=0,a=this.buttons.length;s0&&e.Js(e.Ks,i),e.Ks++}}]),e}();x.Ks=0,x.Xs=3500,x.$s=1e3,x.qs="success",x.Gs="error",x.Qs="default",x.Ys="info",x.Zs="warning";var E=function(){function t(){s(this,t)}return n(t,null,[{key:"ti",value:function(e){if("function"==typeof e){var n=e;e=t.ei.then(function(t){return n(t)})}t.ni.push(e)}},{key:"resolve",value:function(e){return t.si(e),t.ei.then(function(){return Promise.all(t.ni)})}}]),t}();E.ni=[],E.ei=new Promise(function(t){E.si=t});var A=function(){function t(e,n){s(this,t);var r=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB||window.ii;this.ri=r.open(e,n);var i=this;this.ri.onupgradeneeded=function(t){i.oi(i.ri.result,t.oldVersion,t.newVersion,t)},this.ai=new Promise(function(t){i.ri.onsuccess=function(e){i.Pt=i.ri.result,t(e)}})}return n(t,[{key:"li",value:function(t,e,n){var r=this;"function"==typeof e&&d.ct(n)&&(n=e,e="read"),this.ai.then(function(){var i=null;try{i=r.ri.result.transaction(t,e)}catch(e){console.warn(e),i=r.ri.result.transaction(t)}n(i)})}},{key:"hi",value:function(t,e,n){"function"==typeof e&&d.ct(n)&&(n=e,e="readonly"),this.li(t,e,function(e){n(e.objectStore(t))})}},{key:"ui",value:function(t,e){var n=this;return new Promise(function(r){n.hi(e,"readwrite",function(e){var n=e.put(t);n.onsuccess=r,n.onerror=function(t){throw{type:"indexed-db-error",event:t}}})})}},{key:"ci",value:function(t,e){var n=this;return new Promise(function(r){n.hi(e,"readwrite",function(e){for(var n=[],i=function(r,i){n.push(new Promise(function(n){var r=e.put(t[i]);r.onsuccess=n,r.onerror=function(t){throw{type:"indexed-db-error",event:t}}}))},o=0,s=t.length;o=0){var n=new P("optimistic-locking-dialog","optimistic-locking-dialog-title");n.Vs(),n.show()}else t(e)}:t,this.Gi=n}},{key:"Yi",value:function(){if(!this.Ki){var t=this;return this.submit().then(function(e){if(e.success){if(null!==t.$i)return t.$i(e.result)}else if(d.A(t.Gi))return t.Gi(e.errors)})}}},{key:"load",value:function(t,e){return this.tr(F.load(t,e).then(function(t){return t.success?t.result:{}})),this}},{key:"tr",value:function(t){this.er(!0);var e=this;return Promise.resolve(t).then(function(t){for(var n in e.er(!1),t)if(d.A(e.zi.elements[n])){if(d.A(e.zi.elements[n].options)&&d.A(t[n+"Options"])){var r=e.zi.elements[n].options;for(var i in t[n+"Options"]){var o=document.createElement("option");o.value=i,o.innerText=t[n+"Options"][i],r.add(o)}}e.zi.elements[n].value=d.ue(t[n]),d.A(t[n])&&""!==(""+t[n]).trim()?e.zi.elements[n].classList.add("notEmpty"):e.zi.elements[n].classList.remove("notEmpty")}return e})}},{key:"Qi",value:function(){var t=r(regeneratorRuntime.mark(function t(e){var n,r,i,o;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:for(i in n=!1,r=null,e)d.A(this.zi.elements[i])&&"hidden"!==this.zi.elements[i].type&&d.ct(this.zi.elements[i].nr)&&(d.ct(this.zi.elements[i].disabled)||!this.zi.elements[i].disabled)&&(this.zi.elements[i].setCustomValidity(f.translate(d.t(e[i],"form-default-error"))),n=!0),d.ct(r)&&(r=d.t(e[i],"form-default-error"));if(n||!d.A(r)){t.next=11;break}t.t0=regeneratorRuntime.keys(this.zi.elements);case 4:if((t.t1=t.t0()).done){t.next=11;break}if(o=t.t1.value,"hidden"===this.zi.elements[o].type){t.next=9;break}return this.zi.elements[o].setCustomValidity(f.translate(r)),n=!0,t.abrupt("break",11);case 9:t.next=4;break;case 11:n&&this.zi.querySelector("input[type=submit]").click();case 12:case"end":return t.stop()}},t,this)}));return function(){return t.apply(this,arguments)}}()},{key:"er",value:function(t){this.Ki=t,this.Ki?this.zi.classList.add("sending"):this.zi.classList.remove("sending")}},{key:"submit",value:function(){var t=this;return new Promise(function(e){t.er(!0);var n=new FormData(t.zi);e(t.Xi(n))}).then(function(e){return t.er(!1),e})}},{key:"sr",value:function(t){this.$i=t}}]),t}(),z=function(){function t(){s(this,t),this.ye=null,this.rr="settings"}return n(t,null,[{key:"_t",value:function(){return null===t.ir&&(t.ir=new t),t.ir}}]),n(t,[{key:"or",value:function(){return d.ct(this.ye)&&this.ar(),this.ye}},{key:"lr",value:function(t,e){var n=this.or();return d.A(n[t])?n[t].value:e}},{key:"hr",value:function(t){this.or(),delete this.ye[t],this.ur()}},{key:"cr",value:function(t,e){this.or(),this.ye[t]={dr:(new Date).getTime(),value:e},this.ur()}},{key:"gr",value:function(t){for(var e in this.or(),t)this.ye[e]=t[e];this.ur()}},{key:"mr",value:function(t){return d.t(this.ye[t])}},{key:"ar",value:function(){this.ye=localStorage.getItem(this.rr),null===this.ye?this.ye={}:this.ye=JSON.parse(this.ye)}},{key:"ur",value:function(){null!==this.ye&&localStorage.setItem(this.rr,JSON.stringify(this.ye))}}]),t}();z.ir=null;var H=function(){function t(){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,R),n(t,[{key:"en",value:function(){for(var n=e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"en",this).call(this),r=this.on(".setting",!0),i=z._t(),o=function(t){var e=r[t],n=e.name,o=i.lr(n),s=!1;e instanceof HTMLInputElement&&("checkbox"===e.type||"radio"===e.type)&&(s=!0),!i.mr(n)&&d.A(r[t].dataset.default)&&(o=e.dataset.default,d.A(e.dataset.defaultTranslateable)&&(e.dataset.translation="",e.dataset.translationValue=o,o=f.translate(o))),d.A(o)&&(s?e.checked=o===e.value:e.value=o,""!==o&&e.classList.add("notEmpty")),e.addEventListener("change",function(){var t=this.value;s?this.checked?i.cr(n,t):i.cr(n,null):i.cr(n,t),delete e.dataset.translationValue,delete e.dataset.translation})},s=0;sn&&o.kr[n].click(e,i,t)}),this.list=i,i}},{key:"Er",value:function(){for(var t=document.createElement("tr"),e=document.createElement("tr"),n=[],r=0,i=this.kr.length;r=1&&(n=this.Ir(n),r[0].values(n))}},{key:"Nr",value:function(t){t?this.xr.classList.add("sending"):this.xr.classList.remove("sending")}}]),t}(),U=function(){function t(e){s(this,t);var n=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,t._r,"settings"));for(var r in t.jr)n.Vr(r,new t.jr[r](n));return n.active=null,n}return o(t,w),n(t,[{key:"Vr",value:function(t,e){this.rn("#settings-fragments",e),delete this.Qe["#settings-fragments"],this.Qe[t]=e}},{key:"tn",value:function(){var n=e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"tn",this).call(this);return d.A(this.active)&&!this.Qe[this.active].nn()&&this.setActive(null),this.Jr(),n}},{key:"setActive",value:function(t){d.A(this.active)&&(this.Qe[this.active].$e.then(function(t){t.classList.remove("active")}),this.on("#show-fragment-"+this.active).classList.remove("active")),this.active=t,d.A(this.active)&&(this.Qe[this.active].$e.then(function(t){t.classList.add("active")}),this.on("#show-fragment-"+this.active).classList.add("active"))}},{key:"Jr",value:function(){var t=this,e=this.on("#settings-fragment-list");e.removeAllChildren();var n=this,r=function(r){if(t.Qe[r].nn()){var i=document.createElement("li");i.id="show-fragment-"+r,i.appendChild(f.at(r,null,"a")),i.addEventListener("click",function(){n.setActive(r)}),e.appendChild(i),d.ct(t.active)&&t.setActive(r)}};for(var i in this.Qe)r(i)}}],[{key:"Vr",value:function(e,n){t.jr[e]=n}},{key:"zr",value:function(e){t.qr=e}},{key:"Kr",value:function(e){t._r=e}}]),t}();U._r="core/html/settings.html",U.jr={},U.qr=!0,U.Xr=null,U.$r=!0,E.ti(function(t){if(U.qr){if(t.Ls("settings",U),d.ct(U.Xr)){var e=new a("settings",function(){t.Sn(U)},a.J,1e4);e.W("img/settings.png"),U.Xr=e}U.$r&&t.ss(U.Xr)}});var X=function(){function t(){s(this,t)}return n(t,null,[{key:"init",value:function(e){t.Gr=null,t.Qr={Yr:!1,id:null,accesses:["default"]},t.app=e,t.Zr=new Promise(function(e){t.to=e})}},{key:"setData",value:function(e){t.Qr=Object.assign(t.Qr,e);var n=t.app.Ms();n&&n.hs()}},{key:"eo",value:function(e){return t.Gr=d.t(e,t.Gr),F.load(t.Gr).then(function(e){e.success&&t.setData(e.result),t.to()})}},{key:"no",value:function(){return F.load("u/logout").then(function(e){if(e.success){t.setData(e.result);var n=t.app.Ms();n&&n.refreshCurrentSite(),x.zs(x.qs,f.translate("logged-out-successfully"))}})}},{key:"so",value:function(e){return t.Qr.accesses.indexOf(e)>=0}},{key:"io",value:function(e,n){t.ro(function(r){n(r&&t.oo(e))})}},{key:"ro",value:function(e){this.Zr.then(function(){e(t.ao())})}},{key:"oo",value:function(e){return t.Qr.id===e}},{key:"ao",value:function(){return d.A(t.Qr)&&d.A(t.Qr.id)}}]),t}();E.ti(function(t){return X.init(t),X.eo("u/me").then(function(){X.ro(function(t){if(t){var e=z._t(),n=d.he(e.or());for(var r in n)n[r].value=JSON.stringify(n[r].value);F.send("u/syncSettings",n).then(function(t){if(t.success){for(var n in t.result)t.result[n].value=JSON.parse(t.result[n].value);e.gr(t.result)}})}})})});var K=function(){function t(e,n,r,o,a){var u;return s(this,t),(u=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,r,o))).lo=d.t(a,"default"),u}return o(t,a),n(t,[{key:"D",value:function(){return e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"D",this).call(this)&&X.so(this.lo)}},{key:"ho",value:function(){return this.lo}},{key:"_",value:function(n){var r=e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_",this).call(this,d.t(n,new t));return r.lo=this.lo,r}}]),t}(),Q=function(){function t(e){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,"userManagement/html/403.html"))}return o(t,w),t}(),Y=function(){function t(e,n,r,o){var a;return s(this,t),(a=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,r))).lo=o,a}return o(t,w),n(t,[{key:"Ze",value:function(n){return X.so(this.lo)?e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"Ze",this).call(this,n):(this.Sn(Q),void this.finish({error:403}))}},{key:"tn",value:function(n){return X.so(this.lo)?e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"tn",this).call(this,n):(this.Sn(Q),void this.finish({error:403}))}}]),t}(),J=function(){function t(e,n,r,o){s(this,t);var a=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,r,o)),u=e.querySelector("#email"),l=e.querySelector("#password"),c=function(){u.setCustomValidity(""),l.setCustomValidity("")};return u.addEventListener("keydown",c),l.addEventListener("keydown",c),a}return o(t,B),t}(),W=function(){function t(e,n,r,o){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,r,o))}return o(t,B),n(t,[{key:"uo",value:function(){}}]),t}(),tt=function(){function t(e,n,r){var o;return s(this,t),(o=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n))).lo=r,o}return o(t,R),n(t,[{key:"nn",value:function(){return e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"nn",this).call(this)&&X.so(this.lo)}}]),t}(),et=function(){function t(e){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,"userManagement/html/fragments/passwordSettings.html","online"))}return o(t,tt),n(t,[{key:"en",value:function(){var n=e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"en",this).call(this),r=new B(document.getElementById("change-password-form"),"u/passwordSettings/set","post");return r.sr(function(t){for(var e=0,n=t.length;e0,!t.t0){t.next=8;break}return t.next=8,new Promise(function(t){setTimeout(t,u),n.style.fontSize=c+"px"});case 8:return h=this,f=function(){setTimeout(function(){h.Mo(e,n,r,i,o,s,a,u,!1)},"number"==typeof l?l:255)},t.abrupt("return",(!1!==l&&window.addEventListener("resize",f),f));case 10:case"end":return t.stop()}},t,this)}));return function(){return t.apply(this,arguments)}}()},{key:"yo",value:function(){var t=r(regeneratorRuntime.mark(function t(e,n,r,i,o,s,a,u){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return t.abrupt("return",this.Mo(1,e,n,r,i,o,s,a,u));case 1:case"end":return t.stop()}},t,this)}));return function(){return t.apply(this,arguments)}}()},{key:"Ho",value:function(){var t=r(regeneratorRuntime.mark(function t(e,n,r,i,o,s,a,u){var l,c,h,f,v,p,y,m,g,k;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:s=d.t(s,10),i=d.t(i,!1),o=d.t(o,!1),a=d.t(a,n.innerHTML.length),u=d.t(u,!0),(l=r.classList.contains("no-transition"))||r.classList.add("no-transition"),c=n.style.fontSize,h=1,f=0,v=0,p=0,y=0,m=0;case 4:if(h+=f/(a+1),n.style.fontSize=h+"px",g=window.getComputedStyle(r),y=g.getPropertyValue("width").replace("px",""),m=g.getPropertyValue("height").replace("px",""),v=y-n.offsetWidth,p=m-n.offsetHeight,(k=o?p:i?v:Math.min(v,p))!==f){t.next=10;break}return t.abrupt("break",12);case 10:f=k;case 11:if((v>(1-e)*y||o)&&(p>(1-e)*m||i)){t.next=4;break}case 12:if(h-=s,n.style.fontSize=u?h+"px":c,t.t0=l,t.t0){t.next=19;break}return t.next=18,new Promise(function(t){setTimeout(t,50)});case 18:r.classList.remove("no-transition");case 19:return t.abrupt("return",h);case 20:case"end":return t.stop()}},t,this)}));return function(){return t.apply(this,arguments)}}()}]),t}(),lt=function(){function t(e){s(this,t),"string"==typeof e&&(e={code:e}),this.vo=e,this.To=!1}return n(t,[{key:"Po",value:function(t){this.To=t}},{key:"Lo",value:function(){return this.To}},{key:"bo",value:function(){return F.send("c/code",this.vo)}}]),t}(),ct=function(){function t(e){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,"core/html/load.html","code"))}return o(t,w),n(t,[{key:"Ze",value:function(n){e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"Ze",this).call(this,n),console.log(n);Promise.resolve();if(d.A(n.code)){var r=n.code,i=d.t(n.cachable,!1),o=new lt(r);o.Po(i);var s=this;o.bo().then(function(t){t.success?x.zs(x.qs,f.translate(d.t(t.result.successMessage,"code-activated"))):x.zs(x.qs,f.translate(t.errors[0])),s.finish()})}}}]),t}();E.ti(function(t){t.Ls("code",ct)});var ht=function(){function t(){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,"wordRotator",3))}return o(t,A),n(t,null,[{key:"_t",value:function(){return d.ct(t.qt)&&(t.qt=new t),t.qt}}]),n(t,[{key:"oi",value:function(e,n,r,i){(d.ct(n)||n<1&&r>=1)&&e.createObjectStore(t.Fo.Ao,{keyPath:"id"}),(d.ct(n)||n<2&&r>=2)&&i.target.transaction.objectStore(t.Fo.Ao).createIndex("played",["deleted","played","difficulty","id"],{unique:!1}),(d.ct(n)||n<3&&r>=3)&&i.target.transaction.objectStore(t.Fo.Ao).createIndex("difficulty","difficulty",{unique:!1})}},{key:"Co",value:function(){var e=r(regeneratorRuntime.mark(function e(n){return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",this.ci(n,t.Fo.Ao));case 1:case"end":return e.stop()}},e,this)}));return function(){return e.apply(this,arguments)}}()},{key:"Ro",value:function(){var e=r(regeneratorRuntime.mark(function e(n){return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",this.load(n,t.Fo.Ao));case 1:case"end":return e.stop()}},e,this)}));return function(){return e.apply(this,arguments)}}()},{key:"xo",value:function(){var e=r(regeneratorRuntime.mark(function e(n){var r,i,o,s,a,u;return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this.gi("difficulty",IDBKeyRange.lowerBound(0),t.Fo.Ao);case 2:for(r=e.sent,i=[],o=[],s=-1,a=0,u=r.length;a=2&&this.mn.classList.add("layer-"+t),this.Ko||this.mn.classList.add("locked");var e=this.mn.querySelector(".child-container");e.removeAllChildren(),this.Yo(),this.mn.removeEventListener("mouseup",this.Go),this.mn.removeEventListener("touchend",this.$o),this.mn.addEventListener("mouseup",this.Go),this.mn.addEventListener("touchend",this.$o);for(var n=0,r=this.children.length;n=1&&this.children[0]&&this.children[0]instanceof t?this.children[0].na()+1:1}}]),t}();dt.Jo();var vt=function(){function t(e,n){var r;return s(this,t),(r=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))).sa="A",d.A(n)&&r.ia(n),r}return o(t,ft),n(t,[{key:"ko",value:function(e){return e instanceof t&&e.sa===this.sa}},{key:"ia",value:function(t){this.sa=t}},{key:"Oo",value:function(){this.mn.querySelector(".leaf-element").removeAllChildren().appendChild(document.createTextNode(this.sa))}}]),t}(),pt=function(){function t(e,n,r,i){s(this,t),this.ra=e,this.oa=n,this.aa=r,this.la=i}return n(t,[{key:"ha",value:function(){return d.cloneNode(this.ra)}},{key:"ua",value:function(){return d.cloneNode(this.oa)}},{key:"ca",value:function(){return d.cloneNode(this.aa)}},{key:"da",value:function(){return d.cloneNode(this.la)}}]),t}(),yt=function(){function t(e){s(this,t),this.ga=null,this.words=[],this.ma=[],this.pa=e,this.fa=!1,this.id=null,this.Sa=null,this.wa=null;var n=this;this.Ma=new Promise(function(t,e){n.Sa=t,n.wa=e})}return n(t,[{key:"Ha",value:function(){var t=this.Bo(),e=this.jo();localStorage.setItem("currentLevel",JSON.stringify({id:this.id,rotations:t,locks:e}))}},{key:"jo",value:function(){return null!==this.ga?this.ga.jo([]):[]}},{key:"Bo",value:function(){return null!==this.ga?this.ga.Bo([]):[]}},{key:"ya",value:function(t){null!==this.ga&&this.ga._o(t)}},{key:"va",value:function(t){this.id=t}},{key:"O",value:function(){return this.id}},{key:"Uo",value:function(){return this}},{key:"Ta",value:function(t){this.ga=t,this.ga.Io(this),this.ma&&this.No()}},{key:"Pa",value:function(t){this.words=[];for(var e=0,n=t.length;e=2&&this.words[0].length>=this.Da&&this.words[1].length>=this.Da){for(var t=yt.xa(this.words[0],this.pa.ha()),e=yt.xa(this.words[1],this.pa.ha()),n=new mt(this.pa.ca()),r=0,i=this.Da/2;r=6&&this.words[0].length>=this.Da&&this.words[1].length>=this.Da&&this.words[2].length>=this.Da&&this.words[3].length>=this.Da&&this.words[4].length>=this.Da&&this.words[5].length>=this.Da){var t=[];t[0]=yt.xa(this.words[0],this.pa.ha()),t[1]=yt.xa(this.words[1],this.pa.ha()),t[2]=yt.xa(this.words[2],this.pa.ha()),t[3]=yt.xa(this.words[3],this.pa.ha()),t[4]=yt.xa(this.words[4],this.pa.ha()),t[5]=yt.xa(this.words[5],this.pa.ha());for(var e=new mt(this.pa.ca()),n=0;n=4&&this.words[0].length>=this.Da&&this.words[1].length>=this.Da&&this.words[2].length>=this.Da&&this.words[3].length>=this.Da){var t=[];t[0]=yt.xa(this.words[0],this.pa.ha()),t[1]=yt.xa(this.words[1],this.pa.ha()),t[2]=yt.xa(this.words[2],this.pa.ha()),t[3]=yt.xa(this.words[3],this.pa.ha());for(var e=new mt(this.pa.ca()),n=0;n=t){e-=t,localStorage.setItem("coins",e),this.Ua.title=e,this.Ua.k();for(var n=this.level.Ca(),r=(n=n.filter(function(t){return 0!==t.rotation}))[Math.floor(Math.random()*n.length)];0!==r.rotation;)r.rotate();r.qo(!1),this.level.Ha()}else x.zs("not-enough-coins")}}]),t}(),Mt=function(){function t(e){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,"html/application/menu.html"))}return o(t,Ct),n(t,[{key:"en",value:function(){var n=this;e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"en",this).call(this),this.on("#play-button").addEventListener("click",function(){n.Sn(Tt)})}}]),t}(),It=function(){function t(e){return s(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,"html/application/sync.html"))}return o(t,Ct),n(t,[{key:"Ze",value:function(){var n=r(regeneratorRuntime.mark(function n(r){var i;return regeneratorRuntime.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:return n.next=2,e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"Ze",this).call(this,r);case 2:return i=n.sent,n.next=5,this.nl();case 5:return n.abrupt("return",i);case 6:case"end":return n.stop()}},n,this)}));return function(){return n.apply(this,arguments)}}()},{key:"en",value:function(){e(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"en",this).call(this),this.Sn(Mt),this.finish()}},{key:"nl",value:function(){var t=r(regeneratorRuntime.mark(function t(){var e,n,r,i,o,s,a,u,l,c,h,f;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:e=d.t(localStorage.getItem("date-last-sync"),0),n=ht._t(),r=null,i=1,o=[],s=0;case 3:if(!(sn.length)&&(e=n.length),e-=t.length;var r=n.indexOf(t,e);return-1!==r&&r===e}),window.fetch=d.t(window.fetch,function(t){console.log("customFetch",t);var e=null;if(window.XMLHttpRequest)e=new XMLHttpRequest;else if(window.Oi)try{e=new ActiveXObject("Msxml2.XMLHTTP")}catch(t){try{e=new ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}var n=new Promise(function(t){e.onload=function(){var e=this.responseText;t({json:function(){return Promise.resolve(JSON.parse(e))},text:function(){return Promise.resolve(e)}})},e.onerror=function(e){t(Promise.reject(e))}});return e.open("get",t,!0),e.send(),n}),p.Ce(new N("red","")),p.Ce(new N("blue","blue")),p.Ce(new N("black","black")),p.Ce(new N("green","green")),p.Ce(new N("pink","pink")),j.xi(new I("img/whatsapp.svg")),j.xi(new T("img/sms.svg")),j.xi(new M("img/telegram.svg"));var Dt=new L;window.ThemeManager=p,window.ThemeManager.addChangeListener=p.addChangeListener,window.app=Dt,window.app.refreshCurrentSite=Dt.refreshCurrentSite,window.Translator=f,window.Translator.setLanguage=f.setLanguage,U.Kr("html/application/setting-template.html"),st.tt=!1,ot.So=!1,E.resolve(Dt).then(function(){U.Xr.i=a.V,Dt.start(It),f.setLanguage("de")}); \ No newline at end of file +class MenuAction { + constructor(title, callback, showFor, order) { + this.title = Helper.nonNull(title, null); + this.callback = callback; + this.showFor = Helper.nonNull(showFor, MenuAction.SHOW_FOR_MEDIUM); + this.order = Helper.nonNull(order, 1000); + this._liClass = ""; + + this._menu = null; + this._activated = true; + this._visible = true; + this.id = MenuAction.maxId++; + this._icon = null; + this._shouldTranslate = true; + this._copies = []; + } + + setTitle(title) + { + this.title = title; + } + + setShouldTranslate(shouldTranslate) + { + this._shouldTranslate = shouldTranslate; + } + + getShowFor(){ + return this.showFor; + } + + getTitle() + { + return this.title; + } + + getShouldTranslate() + { + return this._shouldTranslate; + } + + remove(removeCopies) { + removeCopies = Helper.nonNull(removeCopies, false); + if (Helper.isNotNull(this._menu)) { + console.log(this._menu); + this._menu.removeAction(this); + this._menu = null; + } + if (removeCopies) + { + for (let i = 0; i < this._copies.length; i++) { + this._copies[i].remove(); + } + } + } + + getMenu() { + return this._menu; + } + + setMenu(value) { + this._menu = value; + } + + getVisible() { + return this._visible; + } + + setVisible(value) { + if (value !== this._visible) { + this._visible = value; + this.redraw(); + } + } + + getActivated() { + return this._activated; + } + + getIcon() { + return this._icon; + } + + setIcon(value) { + this._icon = value; + } + + getId() + { + return this.id; + } + + redraw() { + if (Helper.isNotNull(this._menu)) { + this._menu.updateAction(this); + } + } + copy(instance){ + let copy = Helper.nonNull(instance, new MenuAction()); + copy.title = this.title; + copy.callback = this.callback; + copy.showFor = this.showFor; + copy.order = this.order; + copy._liClass = this._liClass; + + copy._activated = this._activated; + copy._visible = this._visible; + copy._icon = this._icon; + copy._shouldTranslate = this._shouldTranslate; + + copy._menu = null; + copy.id = MenuAction.maxId++; + this._copies.push(copy); + return copy; + } + + redrawMenu() + { + if (Helper.isNotNull(this._menu)) { + this._menu.redraw(); + } + } +} +MenuAction.maxId = 0; + +MenuAction.SHOW_ALWAYS = "always"; +MenuAction.SHOW_FOR_MEDIUM = "medium"; +MenuAction.SHOW_FOR_LARGE = "large"; +MenuAction.SHOW_NEVER = "never"; + +class OpenSubmenuAction extends MenuAction { + constructor(title, menu, showFor, order) { + super(title, function (action) { + action.getSubmenu().toggle(); + action.redraw(); + }, showFor, order); + + this.submenu = menu; + menu.setParentAction(this); + } + + getSubmenu() { + return this.submenu; + } + + copy(instance) { + instance = super.copy(Helper.nonNull(instance, new OpenSubmenuAction(null, this.submenu.copy()))); + return instance; + } +} + +class Menu { + constructor(parentElementSelector) { + this.actions = []; + this.submenus = []; + if (typeof parentElementSelector === 'string') { + this.parentElements = document.querySelectorAll(parentElementSelector); + } + else if (Array.isArray(parentElementSelector)) { + this.parentElements = parentElementSelector; + } + else { + this.parentElements = [parentElementSelector]; + } + } + + copy(instance) { + instance = Helper.nonNull(instance, new Menu([])); + + instance.actions = []; + for (let i = 0, n = this.actions.length; i < n; i++) { + instance.actions.push(this.actions[i].copy()); + } + + instance.submenus = []; + for (let i = 0, n = this.submenus.length; i < n; i++) { + instance.submenus.push(this.submenus[i].copy()); + } + + return instance; + } + + addAction(action) { + if (Helper.includesNot(this.actions, action)) { + this.actions.push(action); + this.redraw(); + action.setMenu(this); + if (action instanceof OpenSubmenuAction) { + this.submenus.push(action.getSubmenu()); + } + } + } + + draw() { + if (Helper.isNotNull(this.parentElements)) { + this.sortActions(); + + let actionElements = []; + for (let i = 0; i < this.actions.length; i++) { + let element = this.renderAction(this.actions[i]); + this.actions[i]._htmlElement = element; + actionElements.push(element); + } + for (let i = 0, n = this.parentElements.length; i < n; i++) { + this.parentElements[i].removeAllChildren(); + for (let i2 = 0, n2 = actionElements.length; i2 < n2; i2++) { + this.parentElements[i].appendChild(Helper.cloneNode(actionElements[i2])); + } + this.parentElements[i].onclick = this._getOnClickListener(); + } + } + } + + _getOnClickListener() { + let menu = this; + return function (event) { + let _element = event.target; + if (_element.matches('.action') || _element.matches('.action *')) { + // while (!_element.matches('.action > a')) { + // _element = _element.parentNode; + // } + _element = _element.closest(".action"); + let actionId = parseInt(_element.dataset["id"]); + for (let i = 0, n = menu.actions.length; i < n; i++) { + if (menu.actions[i].id === actionId) { + if (typeof menu.actions[i].callback === 'function' && menu.actions[i].getActivated()) { + menu.actions[i].callback(menu.actions[i], event); + } + return menu.actions[i]; + } + } + for (let i = 0, n = menu.submenus.length; i < n; i++) { + if (menu.submenus[i].click(actionId, event)) { + return menu.submenus[i]; + } + } + } + return null; + }; + } + + /** @protected */ + renderAction(action) { + let aElement = document.createElement("a"); + if (typeof action.callback === 'string') { + aElement.href = action.callback; + } + + if (Helper.isNotNull(action.getIcon())) { + let iconElement = document.createElement("img"); + iconElement.src = action.getIcon(); + iconElement.classList.add('action-image'); + if (action.getShouldTranslate()) { + iconElement.dataset["translationTitle"] = action.title; + } + aElement.appendChild(iconElement); + } + let title = action.getTitle(); + if (action.getShouldTranslate()) { + title = Translator.makePersistentTranslation(title); + } + else { + title = document.createTextNode(title); + } + aElement.appendChild(title); + + return this.renderLiElement(aElement, action) + } + + /** @protected */ + renderLiElement(aElement, action) { + let liElement = document.createElement("li"); + liElement.classList.add('action'); + if (action._liClass.trim() !== "") { + liElement.classList.add(action._liClass); + } + liElement.appendChild(aElement); + liElement.dataset["id"] = action.id; + if (Helper.isNotNull(action.getIcon())) { + liElement.classList.add("img"); + } + + if (!action.getVisible()) { + liElement.classList.add("hidden"); + } + + if (action instanceof OpenSubmenuAction) { + action.getSubmenu().draw(); + liElement.appendChild(action.getSubmenu().getParentElement()); + liElement.classList.add("is-dropdown-submenu-parent"); + liElement.classList.add("opens-right"); + } + return liElement; + } + + /** @private */ + sortActions() { + this.actions = this.actions.sort(function (first, second) { + return first.order - second.order; + }); + } + + _getElementsForAction(action) { + let elements = []; + for (let i = 0; i < this.parentElements.length; i++) { + let elem = this.parentElements[i].querySelector("[data-id=\"" + action.getId() + "\"]"); + Helper.isNull(elem) || elements.push(elem); + } + return elements + } + + updateAction(action) { + let oldElements = this._getElementsForAction(action); + if (oldElements.length === 0) { + return; + } + + let element = this.renderAction(action); + action._htmlElement = element; + + for (let i = 0; i < oldElements.length; i++) { + oldElements[i].replaceWith(Helper.cloneNode(element)); + } + } + + removeAction(action) { + let index = this.actions.indexOf(action); + if (index > 0) { + this.actions.splice(index, 1); + let oldElements = this._getElementsForAction(action); + for (let i = 0, n = oldElements.length; i < n; i++) { + oldElements[i].remove(); + } + if (action instanceof OpenSubmenuAction) { + let index = this.submenus.indexOf(action.getSubmenu()); + this.submenus.splice(index, 1); + } + } + } + + redraw() { + this.draw(); + } +} + +Menu.SHOW_ALWAYS = "always"; +Menu.SHOW_FOR_MEDIUM = "medium"; +Menu.SHOW_FOR_SMEDIUM = "smedium"; +Menu.SHOW_FOR_LARGE = "large"; +Menu.SHOW_NEVER = "never"; + +class Submenu extends Menu +{ + constructor() + { + let menuElement = document.createElement("ul"); + menuElement.classList.add("menu"); + menuElement.classList.add("vertical"); + menuElement.classList.add("submenu"); + menuElement.classList.add("is-dropdown-submenu"); + menuElement.classList.add("first-sub"); + super(menuElement); + + this.parentAction = null; + this.isOpen = false; + } + + + + copy(instance) + { + instance = super.copy(Helper.nonNull(instance, new Submenu())); + instance.parentElements = []; + for (let i = 0, n = this.parentElements.length; i < n; i++) { + instance.parentElements.push(Helper.cloneNode(this.parentElements[i])); + } + instance.parentAction = this.parentAction; + instance.isOpen = this.isOpen; + return instance; + } + + setParentAction(action) + { + this.parentAction = action; + } + + draw() + { + super.draw(); + if (Helper.isNotNull(this.parentElements)) + { + let self = this; + for (let i = 0; i < this.parentElements.length; i++) { + let closeListener = document.createElement("div"); + closeListener.classList.add("close-listener"); + closeListener.onclick = function(e){ + console.log(e); + self.close(); + }; + this.parentElements[i].insertBefore(closeListener, this.parentElements[i].firstElementChild); + } + } + } + + getParentElement() + { + return this.parentElements[0]; + } + + _getOnClickListener() + { + return function () {}; + } + + click(actionId, event) + { + for (let i = 0, n = this.actions.length; i < n; i++) { + if (this.actions[i].id === actionId) + { + if (typeof this.actions[i].callback === 'function' && this.actions[i].getActivated()) { + this.actions[i].callback(this.actions[i], event); + } + this.close(); + return true; + } + } + return false; + } + + toggle() + { + if (this.isOpen) + { + this.close(); + } + else + { + this.open(); + } + } + + open() + { + this.isOpen = true; + for (let i = 0, n = this.parentElements.length; i < n; i++) { + this.parentElements[i].classList.add("js-dropdown-active"); + } + if (Helper.isNotNull(this.parentAction)) + { + this.parentAction.redraw(); + } + } + close() + { + this.isOpen = false; + for (let i = 0, n = this.parentElements.length; i < n; i++) { + this.parentElements[i].classList.remove("js-dropdown-active"); + } + if (Helper.isNotNull(this.parentAction)) + { + this.parentAction.redraw(); + } + } +} + +class TranslatorDB { + constructor() { + this._indexedDB = indexedDB || mozIndexedDB || webkitIndexedDB || msIndexedDB; + this._version = 3; + + let self = this; + this._dbPromise = new Promise(function (resolve, reject) { + let request = self._indexedDB.open("Translator", self._version); + request.onupgradeneeded = function (event) { + let db = event.target.result; + self._upgradeDb(db); + }; + request.onsuccess = function (event) { + let db = event.target.result; + resolve(db); + }; + request.onerror = function (event) { + reject(event); + }; + }).catch(function(e){ + console.error(e); + }); + } + + _upgradeDb(db) { + try { + db.deleteObjectStore("currentLang"); + db.deleteObjectStore("translations"); + } + catch (e) { + console.warn(e); + } + let currentLangObjectStore = db.createObjectStore("currentLang", {"keyPath": "id"}); + let translationsObjectStore = db.createObjectStore("translations", {"keyPath": ["lang","key"]}); + translationsObjectStore.createIndex("lang", "lang", {"unique": false}); + } + + setLanguage(lang) { + this._dbPromise.then(function (db) { + let transaction = TranslatorDB._openTransaction(["currentLang"], "readwrite", db); + let currentLangObjectStore = transaction.objectStore("currentLang"); + currentLangObjectStore.put({"id": 1, "lang": lang}); + }).catch(function(e){ + console.error(e); + }); + } + + saveTranslationsForLang(lang, translations) { + return this._dbPromise.then(function (db) { + return new Promise(function (resolve) { + let transaction = TranslatorDB._openTransaction(["translations"], "readwrite", db); + let translationsObjectStore = transaction.objectStore("translations"); + for (let k in translations) { + translationsObjectStore.put({"lang": lang, "key": k, "translation": translations[k]}); + } + transaction.oncomplete = function () { + resolve(); + }; + }); + }).catch(function(e){ + // console.error(e); + }); + } + + loadTranslationsForLang(lang) { + return this._dbPromise.then(function (db) { + return new Promise(function (resolve) { + let transaction = TranslatorDB._openTransaction(["translations"], "readonly", db); + let translationsObjectStore = transaction.objectStore("translations"); + let index = translationsObjectStore.index("lang"); + let request = index.openCursor(IDBKeyRange.only(lang)); + + let translations = {}; + request.onsuccess = function (e) { + let cursor = e.target.result; + if (cursor) { + + let translation = cursor.value; + translations[translation["key"]] = translation["translation"]; + cursor.continue(); + } + }; + transaction.oncomplete = function(){ + resolve(translations); + }; + }); + }).catch(function(e){ + console.error(e); + return {}; + }); + } + + getLanguage() { + return this._dbPromise.then(function (db) { + return new Promise(function (resolve) { + let transaction = TranslatorDB._openTransaction(["currentLang"], "readonly", db); + let currentLangObjectStore = transaction.objectStore("currentLang"); + let req = currentLangObjectStore.get(1); + req.onsuccess = function (e) { + let data = e.currentTarget.result; + if (data) + { + resolve(data["lang"]); + } + else + { + resolve(null); + } + }; + req.onerror = function (e) { + resolve(null); + }; + }); + }).catch(function(e){ + // console.error(e); + }); + } + + static _openTransaction(name, transactionMode, db) { + let transaction = null; + try { + transaction = db.transaction(name, transactionMode); + } + catch (e) { + console.warn(e); + transaction = db.transaction(name); + } + return transaction; + } +} + +class Translator { + constructor() { + this._translations = []; + this._db = new TranslatorDB(); + this._currentLanguage = null; + this._supportedLanguages = Translator.supportedLanguages; + this._baseLanguage = Translator.baseLanguage; + this._languageBasePath = Translator.languageBasePath; + this._markUntranslatedTranslations = Translator.markUntranslatedTranslations; + this._markTranslations = Translator.markTranslations; + + let self = this; + this._initPromise = this.loadBaseLanguage().then(function () { + return self.loadUserLanguage(); + }); + } + + _loadLanguage(language) { + let self = this; + return fetch(Helper.basePath(this._languageBasePath + language + ".json")).then(function (result) { + return result.json(); + }).then(function (res) { + self._translations[language] = Object.assign(res, self._translations[language]); + self._db.saveTranslationsForLang(language, self._translations[language]); + }).catch(function (err) { + console.error("could not load lang " + language + " because of error: ", err); + }); + } + + loadBaseLanguage() { + let self = this; + return this._loadLanguage(this._baseLanguage).then(function () { + self._currentLanguage = self._baseLanguage; + if (typeof document !== 'undefined') { + document.getElementsByTagName("html")[0].setAttribute("lang", self._baseLanguage); + } + }); + }; + + static setLanguage(language) { + let instance = Translator.getInstance(); + if (instance) { + return instance.setLanguage(language); + } + } + + setLanguage(language) { + if (this._currentLanguage === language) { + this.updateTranslations(); + return Promise.resolve(); + } + + if (this._supportedLanguages.indexOf(language) === -1) { + return Promise.resolve(); + } + + this._currentLanguage = language; + if (typeof localStorage !== 'undefined') { + localStorage.setItem("language", language); + } + this._db.setLanguage(language); + + let self = this; + return this._loadLanguage(language).then(function () { + if (typeof document !== 'undefined') { + document.getElementsByTagName("html")[0].setAttribute("lang", language); + } + self.updateTranslations(); + }); + } + + static translate(key, args) { + let instance = Translator.getInstance(); + if (instance) { + return instance.translate(key, args); + } + return ""; + } + + translate(key, args) { + if (typeof key === 'object' && Helper.isNotNull(key)) { + key = this.addDynamicTranslation(key); + } + + let translation = null; + if (Helper.isNotNull(this._translations[this._currentLanguage]) && Helper.isNotNull(this._translations[this._currentLanguage][key])) { + translation = this._translations[this._currentLanguage][key]; + } + + if (Helper.isNull(translation)) { + if (Translator.logMissingTranslations) { + console.warn("missing translation for language " + this._currentLanguage + " and key " + key); + } + if (Helper.isNotNull(this._translations[this._baseLanguage])) { + translation = this._translations[this._baseLanguage][key]; + } + + if (Helper.isNull(translation)) { + if (Translator.logMissingTranslations) { + console.error("missing base translation for key " + key + ". FIX IT"); + } + translation = key; + } + if (this._markUntranslatedTranslations) { + translation = ">>" + translation + "<<"; + } + } + + if (this._markTranslations) { + translation = "$" + translation + "$"; + } + + if (args !== undefined) { + translation = translation.format(args); + } + + return translation; + } + + static addDynamicTranslation(trans) { + let instance = Translator.getInstance(); + if (instance) { + return instance.addDynamicTranslation(trans); + } + } + + addDynamicTranslation(trans) { + let key = trans["key"]; + delete trans["key"]; + for (let lang in trans) { + if (trans.hasOwnProperty(lang)) { + if (Helper.isNull(this._translations[lang])) { + this._translations[lang] = {}; + } + this._translations[lang][key] = trans[lang]; + } + } + return key; + } + + updateTranslations() { + if (typeof document !== 'undefined') { + let elements = document.querySelectorAll("[data-translation]"); + for (let i = 0, max = elements.length; i < max; i++) { + if (elements[i].dataset["translation"] != "") { + try { + elements[i].innerHTML = this.translate(elements[i].dataset["translation"], (elements[i].dataset["translationArgs"] !== undefined) ? JSON.parse(elements[i].dataset["translationArgs"]) : undefined); + } + catch (err) { + console.error("wrong configured translation: " + err); + } + } + for (let k in elements[i].dataset) { + if (k.startsWith("translation") && !k.endsWith("Args")) { + try { + elements[i][k.substr(11).toLowerCase()] = this.translate(elements[i].dataset[k], (elements[i].dataset[k + "Args"] !== undefined) ? JSON.parse(elements[i].dataset[k + "Args"]) : undefined); + } + catch (err) { + console.error("wrong configured translation: " + err); + } + } + } + } + } + } + + loadUserLanguage() { + let userLanguage = localStorage.getItem("language"); + if (Helper.isNull(userLanguage) || this._supportedLanguages.indexOf(userLanguage) === -1) { + let userLanguages = []; + if (Helper.isNotNull(navigator.languages)) { + userLanguages = navigator.languages.slice(0); //.slice(0) klont das Array. Behebt einen Bug in Firefox + } + + if (navigator.language !== undefined) { + userLanguages.push(navigator.language); + } + //sicherstellen, dass überhaupt eine Sprache gefunden wird + userLanguages.push(this._baseLanguage); + + if (userLanguages !== undefined) { + for (let i = 0, numLanguages = userLanguages.length; i < numLanguages; i++) { + if (this._supportedLanguages.indexOf(userLanguages[i]) !== -1) { + userLanguage = userLanguages[i]; + break; + } + } + } + } + return this.setLanguage(userLanguage.toLowerCase()) + } + + static makePersistentTranslation(key, args, tag) { + tag = Helper.nonNull(tag, "span"); + if (typeof key === 'object') { + key = Translator.addDynamicTranslation(key); + } + + if (typeof document !== 'undefined') { + let htmlElem = document.createElement(tag); + htmlElem.dataset["translation"] = key; + if (args !== undefined) { + htmlElem.dataset["translationArgs"] = JSON.stringify(args); + } + htmlElem.innerHTML = Translator.translate(key, args); + return htmlElem; + } + } + + static generateChangeLanguageMenuAction() { + let submenu = new Submenu(); + submenu.addAction(new MenuAction("en", function () { + Translator.getInstance().setLanguage("en"); + })); + submenu.addAction(new MenuAction("de", function () { + Translator.getInstance().setLanguage("de"); + })); + return new OpenSubmenuAction("current-lang", submenu, Menu.SHOW_ALWAYS) + } + + static init() { + Translator.instance = new Translator(); + // Translator.loadBaseLanguage().then(function () { + // Translator.loadUserLanguage(); + // }); + } + + static getInstance() { + return Translator.instance; + } +} +Translator.logMissingTranslations = false; + +Translator.instance = null; + +Translator.baseLanguage = "en"; +Translator.supportedLanguages = [ + "de", + "en" +]; +Translator.markUntranslatedTranslations = true; +Translator.markTranslations = false; +Translator.languageBasePath = "js/lang/"; +Translator.currentLanguage = null; +Translator.translations = {}; + +class Helper { + static init() { + Helper.heightMmToPxFactor = null; + Helper.widthMmToPxFactor = null; + } + + static includesNot(array, value, fromIndex) { + return -1 === array.indexOf(value, fromIndex); + } + + static includes(array, value, fromIndex) { + return !Helper.includesNot(array, value, fromIndex); + } + + static isSet() { + if (arguments.length > 0) { + const object = arguments[0]; + let keys = Array.prototype.slice.call(arguments, 1); + return (Helper.isNotNull(object) && (keys.length === 0 || Helper.isSet.apply(null, [object[keys[0]]].concat(keys.slice(1))))); + } + return false; + } + + static isNull(variable) { + return (variable === null || variable === undefined); + } + + static isNotNull(variable) { + return !Helper.isNull(variable); + } + + static nonNull(val1, val2) { + if (Helper.isNotNull(val1)) { + return val1; + } + return val2; + } + + static notEmpty(value) { + return !Helper.empty(value); + } + + static buildQuery(values) { + let queryStrings = []; + for (let k in values) { + queryStrings.push(encodeURIComponent(k) + "=" + encodeURIComponent(values[k])); + } + return "?" + queryStrings.join("&"); + } + + static empty(value) { + return (Helper.isNull(value) || (typeof value === 'string' && value.trim() === "")) + } + + static inflateElementsFromString(string) { + let template = document.createElement('template'); + template.innerHTML = string; + return template.content.childNodes; + } + + static createLoadingSymbol() { + let svgNS = "http://www.w3.org/2000/svg"; + + let loader = document.createElement("div"); + loader.className = 'loader'; + + let svg = document.createElementNS(svgNS, "svg"); + svg.setAttribute('viewBox', "0 0 32 32"); + svg.setAttribute("widh", "32"); + svg.setAttribute("height", "32"); + + let circle = document.createElementNS(svgNS, "circle"); + circle.setAttribute("id", "spinner"); + circle.setAttribute("cx", "16"); + circle.setAttribute("cy", "16"); + circle.setAttribute("r", "14"); + circle.setAttribute("fill", "none"); + + svg.appendChild(circle); + loader.appendChild(svg); + + return loader; + } + + static basePath(url) { + return SystemSettings.getBasePath() + url; + } + + static isMobileApple() { + return navigator.userAgent.match(/iPhone|iPad|iPod/i); + } + + static isMobile() { + return (navigator.userAgent.match(/Android|BlackBerry|Opera Mini|IEMobile/i) !== null || Helper.isMobileApple() || (typeof window.orientation !== "undefined" || window.orientation === false || window.orientation === null)); + } + + static select(e) { + let range = document.createRange(); + range.selectNodeContents(e); + let sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } + + static format(number, leadingZeros) { + number = "" + number; + while (number.length < leadingZeros) { + number = "0" + number; + } + return number; + } + + static cloneNode(srcNode) { + let destNode = srcNode.cloneNode(true); + destNode.onclick = srcNode.onclick; + return destNode; + } + + static encodeToBase(stringToEncode, base) { + let encodedString = ""; + let charlength = Math.floor(Math.log(265) / Math.log(base)); + for (let i = 0; i < stringToEncode.length; i++) { + let value = stringToEncode.charCodeAt(i).toString(base); + let joinLength = value.length % charlength; + if (joinLength > 0) { + let joinArray = new Array(charlength + 1 - (joinLength)); //+1, da join nur zwischen elemente einfügt + value = joinArray.join("0") + value; + } + encodedString += value; + } + return encodedString; + } + + static decodeToBase(stringToDecode, base) { + let charlength = Math.floor(Math.log(265) / Math.log(base)); + let values = stringToDecode.match(new RegExp(".{1," + charlength + "}", "g")) || []; + let encodedString = ""; + for (let i = 0, n = values.length; i < n; i++) { + encodedString += String.fromCharCode(parseInt(values[i], base)); + } + return encodedString; + } + + static toggleVisibility(elem) { + if (elem.style.display === "none") { + elem.style.display = ""; + return true; + } + else { + elem.style.display = "none"; + return false; + } + } + + static print(content) { + let printContent = document.getElementById("print-content"); + if (content instanceof Element) { + printContent.removeAllChildren(); + printContent.appendChild(content); + } + else { + printContent.innerHTML = content; + } + window.print(); + } + + static strftime(sFormat, date, useUTC) { + if (!(date instanceof Date)) date = new Date(date); + useUTC = Helper.nonNull(useUTC, false); + let nDay = (useUTC) ? date.getUTCDay() : date.getDay(), + nDate = (useUTC) ? date.getUTCDate() : date.getDate(), + nMonth = (useUTC) ? date.getUTCMonth() : date.getMonth(), + nYear = (useUTC) ? date.getUTCFullYear() : date.getFullYear(), + nHour = (useUTC) ? date.getUTCHours() : date.getHours(), + aDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + aMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + aDayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], + isLeapYear = function () { + if ((nYear & 3) !== 0) return false; + return nYear % 100 !== 0 || nYear % 400 === 0; + }, + getThursday = function () { + let target = new Date(date); + target.setDate(nDate - ((nDay + 6) % 7) + 3); + return target; + }, + zeroPad = function (nNum, nPad) { + return ('' + (Math.pow(10, nPad) + nNum)).slice(1); + }; + + return sFormat.replace(/%[a-z]/gi, function (sMatch) { + return { + '%a': Translator.makePersistentTranslation(aDays[nDay].slice(0, 3)).outerHTML, + '%A': Translator.makePersistentTranslation(aDays[nDay]).outerHTML, + '%b': Translator.makePersistentTranslation(aMonths[nMonth].slice(0, 3)).outerHTML, + '%B': Translator.makePersistentTranslation(aMonths[nMonth]).outerHTML, + '%c': date.toUTCString(), + '%C': Math.floor(nYear / 100), + '%d': zeroPad(nDate, 2), + '%e': nDate, + '%f': zeroPad(date.getTime() % 1000, 4), + '%F': date.toISOString().slice(0, 10), + '%G': getThursday().getFullYear(), + '%g': ('' + getThursday().getFullYear()).slice(2), + '%H': zeroPad(nHour, 2), + '%I': zeroPad((nHour + 11) % 12 + 1, 2), + '%j': zeroPad(aDayCount[nMonth] + nDate + ((nMonth > 1 && isLeapYear()) ? 1 : 0), 3), + '%k': '' + nHour, + '%l': (nHour + 11) % 12 + 1, + '%m': zeroPad(nMonth + 1, 2), + '%M': zeroPad(date.getMinutes(), 2), + '%p': (nHour < 12) ? 'AM' : 'PM', + '%P': (nHour < 12) ? 'am' : 'pm', + '%s': Math.round(date.getTime() / 1000), + '%S': zeroPad(date.getSeconds(), 2), + '%u': nDay || 7, + '%V': (function () { + let target = getThursday(), + n1stThu = target.valueOf(); + target.setMonth(0, 1); + let nJan1 = target.getDay(); + if (nJan1 !== 4) target.setMonth(0, 1 + ((4 - nJan1) + 7) % 7); + return zeroPad(1 + Math.ceil((n1stThu - target) / 604800000), 2); + })(), + '%w': '' + nDay, + '%x': date.toLocaleDateString(), + '%X': date.toLocaleTimeString(), + '%y': ('' + nYear).slice(2), + '%Y': nYear, + '%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'), + '%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1') + }[sMatch] || sMatch; + }); + } + + static cloneJson(obj) { + // https://stackoverflow.com/questions/4120475/how-to-create-and-clone-a-json-object/17502990#17502990 + let i; + + // basic type deep copy + if (Helper.isNull(obj) || typeof obj !== 'object') { + return obj + } + // array deep copy + if (obj instanceof Array) { + let cloneA = []; + for (i = 0; i < obj.length; ++i) { + cloneA[i] = Helper.cloneJson(obj[i]); + } + return cloneA; + } + if (obj instanceof Date) + { + return new Date(obj.getTime()); + } + // object deep copy + let cloneO = {}; + for (i in obj) { + cloneO[i] = Helper.cloneJson(obj[i]); + } + return cloneO; + } + + static htmlspecialcharsDecode(text) { + const map = { + '&': '&', + '&': "&", + '<': '<', + '>': '>', + '"': '"', + ''': "'", + '’': "’", + '‘': "‘", + '–': "–", + '—': "—", + '…': "…", + '”': '”' + }; + + if (Helper.isNotNull(text) && typeof text.replace === "function") { + return text.replace(/\&[\w\d\#]{2,5}\;/g, function (m) { + return map[m]; + }); + } + return text; + } + + static formDataFromObject(obj) { + let formData = new FormData(); + for (let k in obj) { + formData.set(k, obj[k]); + } + return formData; + } + + static scaleContentRecursive(element, content) { + + let elementStyle = window.getComputedStyle(element); + let contentStyle = window.getComputedStyle(content); + + if (contentStyle.height > elementStyle.height || contentStyle.width > elementStyle.width) { + return Helper.scaleDownContentRecursive(element, content); + } + } + + static scaleDownContentRecursive(element, content) { + Helper.convertChildrenToRelativeRecursive(element); + + let elementStyle = window.getComputedStyle(element); + let contentStyle = window.getComputedStyle(content); + + let runs = 0; + let fontSize = parseFloat(contentStyle.getPropertyValue("font-size")); + let width = contentStyle.width; + let height = contentStyle.height; + while (contentStyle.height > elementStyle.height || contentStyle.width > elementStyle.width) { + fontSize *= 0.95; + + if (height > elementStyle.height) { + height *= 0.95; + } + if (width > contentStyle.width) { + width *= 0.95; + } + content.style["font-size"] = fontSize + "px"; + content.style["max-height"] = height + "px"; + content.style["max-width"] = width + "px"; + + runs++; + if (runs > 2000) { + console.log("breaked"); + break; + } + } + Helper.convertToRelative(content); + + contentStyle = window.getComputedStyle(content); + content.style["font-size"] = (parseFloat(contentStyle.getPropertyValue("font-size")) / parseFloat(document.documentElement.clientHeight) * 100) + "vh"; + } + + static convertChildrenToRelativeRecursive(element) { + let children = element.childNodes; + for (let i = 0, n = children.length; i < n; i++) { + if (children[i] instanceof Element) { + Helper.convertToRelative(children[i]); + Helper.convertChildrenToRelativeRecursive(children[i]); + } + } + } + + static convertToRelative(element) { + let hasTransitionClass = (element.classList.contains("no-transtition")); + + element.classList.add("no-transition"); + + let parent = element.parentNode; + + console.log(element); + let elementStyle = window.getComputedStyle(element); + let parentStyle = window.getComputedStyle(parent); + + let fontSize = parseFloat(elementStyle.getPropertyValue("font-size")) / parseFloat(parentStyle.getPropertyValue("font-size")); + + let maxHeight = elementStyle.height; + let maxWidth = elementStyle.width; + + let pHeight = parentStyle.height; + let pWidth = parentStyle.width; + + let relativeAttributes = element.style; + relativeAttributes['max-height'] = Math.floor(maxHeight / pHeight * 100) + "%"; + relativeAttributes['margin-left'] = Math.floor(parseFloat(elementStyle.getPropertyValue('margin-left')) / pWidth * 100) + "%"; + relativeAttributes['margin-right'] = Math.floor(parseFloat(elementStyle.getPropertyValue('margin-right')) / pWidth * 100) + "%"; + relativeAttributes['margin-top'] = Math.floor(parseFloat(elementStyle.getPropertyValue('margin-top')) / pHeight * 100) + "%"; + relativeAttributes['margin-bottom'] = Math.floor(parseFloat(elementStyle.getPropertyValue('margin-bottom')) / pHeight * 100) + "%"; + relativeAttributes['max-width'] = Math.floor(maxWidth / pWidth * 100) + "%"; + relativeAttributes["font-size"] = fontSize + "em"; + // console.log(relativeAttributes); + // element.css(relativeAttributes); + + if (!hasTransitionClass) { + element.classList.remove("no-transition"); + } + } + + static isChrome() { + let isChromium = window.chrome, + winNav = window.navigator, + vendorName = winNav.vendor, + isOpera = winNav.userAgent.indexOf("OPR") > -1, + isIEedge = winNav.userAgent.indexOf("Edge") > -1, + isIOSChrome = winNav.userAgent.match("CriOS"); + + if (isIOSChrome) { + return true; + } else { + return isChromium !== null && + typeof isChromium !== "undefined" && + vendorName === "Google Inc." && + isOpera === false && + isIEedge === false; + } + } + + static getIndexedObject(array, keyValue) { + let obj = {}; + for (let i = 0, n = array.length; i < n; i++) { + obj[array[i][keyValue]] = array[i]; + } + return obj; + } + + static invertKeyValues(obj) { + let new_obj = {}; + + for (let prop in obj) { + if (obj.hasOwnProperty(prop)) { + new_obj[obj[prop]] = prop; + } + } + + return new_obj; + } + + static toArray(object) { + let res = []; + for (let k in object) { + res.push(object[k]); + } + return res; + } +} +Helper.init(); + +class SystemSettings { + static setBasePath(basePath) { + SystemSettings._basePath = basePath; + } + + static getBasePath() { + return SystemSettings._basePath; + } + + static set(key, value) { + SystemSettings._settings[key] = value; + } + + static get(key, defaultValue) { + return Helper.nonNull(SystemSettings._settings[key], defaultValue); + } + + static has(key){ + return Helper.nonNull(SystemSettings._settings[key]); + } +} + +SystemSettings.setBasePath("/"); +SystemSettings._settings = {}; + +class ThemeManager { + static init() { + ThemeManager.loadCurrentTheme(); + } + + static changeCurrentTheme(newTheme) { + let theme = null; + if (typeof newTheme === 'string') { + let themes = ThemeManager.themes.filter(function (theme) { + return theme._name === newTheme; + }); + if (themes.length > 0) { + theme = themes[0]; + } + } + else if (ThemeManager.themes.indexOf(newTheme) !== -1) { + theme = newTheme; + } + if (Helper.isNotNull(theme)) { + localStorage.setItem("currentTheme", theme._name); + let themePromise = new Promise(function (resolve) { + document.querySelector("nav.top-bar").addEventListener("transitionend", function(){ + resolve(); + }); + }); + document.body.className = theme._className; + ThemeManager.currentTheme = theme; + for (let i = 0, n = ThemeManager.changeListeners.length; i < n; i++) { + ThemeManager.changeListeners[i](ThemeManager.currentTheme, themePromise); + } + } + } + + static addTheme(theme) { + ThemeManager.themes.push(theme); + } + + static loadCurrentTheme() { + ThemeManager.changeCurrentTheme(localStorage.getItem("currentTheme")); + if (Helper.isNull(ThemeManager.currentTheme)) { + let className = document.body.className; + let themes = ThemeManager.themes.filter(function (theme) { + return theme._className === className; + }); + if (themes.length > 0) { + ThemeManager.changeCurrentTheme(themes[0]); + } + else if (ThemeManager.themes.length > 0) { + ThemeManager.changeCurrentTheme(ThemeManager.themes[0]); + } + } + } + + static generateChangeThemeMenuAction() { + return new MenuAction(ThemeManager.currentTheme._name, function (action) { + let currentThemeIndex = ThemeManager.themes.indexOf(ThemeManager.currentTheme); + let nextIndex = (currentThemeIndex + 1) % ThemeManager.themes.length; + ThemeManager.changeCurrentTheme(ThemeManager.themes[nextIndex]); + action.title = ThemeManager.currentTheme._name; + action._menu.redraw(); + }, Menu.SHOW_ALWAYS) + } + + static addChangeListener(listener) { + ThemeManager.changeListeners.push(listener); + } +} + +ThemeManager.themes = []; +ThemeManager.changeListeners = []; + +class CookieCompliance { + constructor(cookieContainerId) { + this.cookieContainerId = cookieContainerId; + this.dropCookie = true; + this.cookieDuration = 365 * 10; + this.cookieName = 'complianceCookie'; + this.cookieValue = 'true'; + } + + showIfNeeded() + { + if (CookieCompliance.checkCookie(this.cookieName) !== this.cookieValue) { + this.show(); + } + } + + removeMe() { + this.createCookie(this.cookieName, this.cookieValue, this.cookieDuration); + } + + createCookie(name, value, days) { + let expires; + if (Helper.isNotNull(days)) { + const date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + } + else { + expires = ""; + } + if (this.dropCookie) { + document.cookie = name + "=" + value + expires + "; path=/"; + } + } + + eraseCookie(name) { + this.createCookie(name, "", -1); + } + + static checkCookie(name) { + const nameEQ = name + "="; + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + let c = cookies[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) === 0) { + return c.substring(nameEQ.length, c.length); + } + } + return null; + } + + show() { + let cookieCompliance = this; + const cookieMessage = document.getElementById(this.cookieContainerId); + cookieMessage.style.display='block'; + cookieMessage.querySelector("#close-cookie-msg").onclick = function(){ + cookieCompliance.removeMe(); + cookieMessage.remove(); + }; + + } +} + +class ActionBarMenu extends Menu { + static init() { + function parseStyleToObject(str) { + let styleObject = {}; + + if (typeof str !== 'string') { + return styleObject; + } + + str = str.trim().slice(1, -1); // browsers re-quote string style values + + if (!str) { + return styleObject; + } + + styleObject = str.split('&').reduce(function (ret, param) { + const parts = param.replace(/\+/g, ' ').split('='); + let key = parts[0]; + let val = parts[1]; + key = decodeURIComponent(key); + + // missing `=` should be `null`: + // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters + val = val === undefined ? null : decodeURIComponent(val); + + if (!ret.hasOwnProperty(key)) { + ret[key] = val; + } else if (Array.isArray(ret[key])) { + ret[key].push(val); + } else { + ret[key] = [ret[key], val]; + } + return ret; + }, {}); + + return styleObject; + } + + let cssStyle = document.getElementsByClassName('foundation-mq'); + if (cssStyle.length === 0) { + return; + } + let queries = []; + cssStyle = parseStyleToObject(window.getComputedStyle(cssStyle[0]).getPropertyValue('font-family')); + for (let key in cssStyle) { + if (cssStyle.hasOwnProperty(key)) { + queries.push({ + _name: key, + value: 'only screen and (min-width: ' + cssStyle[key] + ')' + }); + } + } + + window.addEventListener('resize', function () { + if (Helper.isNotNull(ActionBarMenu.currentMenu)) { + ActionBarMenu.currentMenu.updateToggleButton(); + } + }); + let responsiveMenu = document.getElementById("responsive-menu"); + document.getElementById("responsive-menu-toggle").onclick = function () { + if (window.getComputedStyle(responsiveMenu).getPropertyValue('display') === 'none') { + responsiveMenu.style.display = 'block'; + } + else if (Helper.isNotNull(ActionBarMenu.currentMenu)) { + ActionBarMenu.currentMenu.close(); + + } + }; + responsiveMenu.firstElementChild.addEventListener("click", function (e) { + if (e.target === responsiveMenu.firstElementChild && Helper.isNotNull(ActionBarMenu.currentMenu)) { + ActionBarMenu.currentMenu.close(); + } + } + ); + ActionBarMenu.queries = queries; + } + + static _getCurrentSize() { + let matched; + + for (let i = 0; i < ActionBarMenu.queries.length; i++) { + let query = ActionBarMenu.queries[i]; + + if (matchMedia(query.value).matches) { + matched = query; + } + } + + if (typeof matched === 'object') { + return matched._name; + } else { + return matched; + } + } + + static filterVisibleElements(elements) { + let visibleElements = []; + for (let i = 0, n = elements.length; i < n; i++) { + if (!elements[i].classList.contains("hidden")) { + visibleElements.push(elements[i]); + } + } + return visibleElements; + } + + renderLiElement(aElement, action) { + let liElement = super.renderLiElement(aElement, action); + liElement.classList.add(action.getShowFor()); + return liElement; + } + + updateToggleButton() { + let size = ActionBarMenu._getCurrentSize(); + let firstParentElement = this.parentElements[0]; + if ((size === "medium" || size === "smedium" || size === "small") && ActionBarMenu.filterVisibleElements(firstParentElement.getElementsByClassName(Menu.SHOW_FOR_LARGE)).length > 0 || + (size === "smedium" || size === "small") && ActionBarMenu.filterVisibleElements(firstParentElement.getElementsByClassName(Menu.SHOW_FOR_MEDIUM)).length > 0 || + (size === "small") && ActionBarMenu.filterVisibleElements(firstParentElement.getElementsByClassName(Menu.SHOW_FOR_SMEDIUM)).length > 0 || + ActionBarMenu.filterVisibleElements(firstParentElement.getElementsByClassName(Menu.SHOW_NEVER)).length > 0) { + document.getElementById("responsive-menu-toggle").style.display = 'block'; + } else { + document.getElementById("responsive-menu-toggle").style.display = 'none'; + if (Helper.isNotNull(ActionBarMenu.currentMenu)) { + ActionBarMenu.currentMenu.close(); + } + } + } + + _getOnClickListener() { + let superListener = super._getOnClickListener(); + return function (event) { + let action = superListener(event); + if (!(action instanceof OpenSubmenuAction) && Helper.isNotNull(ActionBarMenu.currentMenu)) { + ActionBarMenu.currentMenu.close(); + } + } + } + + draw(parentElement) { + let returnValue = super.draw(parentElement); + this.updateToggleButton(); + + ActionBarMenu.currentMenu = this; + return returnValue; + } + + close() { + document.getElementById("responsive-menu").style.display = 'none'; + for (let i = 0, n = this.submenus.length; i < n; i++) { + this.submenus[i].close(); + } + } + + removeAction(action) { + let res = super.removeAction(action); + this.updateToggleButton(); + return res; + } +} + +ActionBarMenu.queries = []; +ActionBarMenu.currentMenu = null; +ActionBarMenu.init(); + +class ViewInflater { + static inflate(viewUrl, parentUrls) { + parentUrls = Helper.nonNull(parentUrls, []).slice(0); + + let resultPromise = Promise.resolve(); + if (viewUrl instanceof Element) { + resultPromise = Promise.resolve(viewUrl); + } + else { + if (parentUrls.indexOf(viewUrl) !== -1) { + return Promise.reject("views are in a circuit! cannot resolve view for url " + parentUrls[0] + "! url " + viewUrl + " is in stack before!"); + } + parentUrls.push(viewUrl); + resultPromise = fetch(Helper.basePath(viewUrl), {credentials: "same-origin"}).then(function (result) { + return result.text(); + }).then(function (htmlText) { + let doc = (new DOMParser()).parseFromString(htmlText, "text/html"); + if (Helper.isNull(doc)) { + doc = document.implementation.createHTMLDocument(''); + doc.body.innerHTML = htmlText; + } + return doc.body.firstChild + }); + } + + return resultPromise.then(function (parentElement) { + let promises = []; + let childViews = parentElement.querySelectorAll("[data-view]"); + + for (let i = 0, n = childViews.length; i < n; i++) { + promises.push(ViewInflater.inflate(childViews[i].dataset["view"], parentUrls).then(function (element) { + childViews[i].replaceWith(element); + })); + } + return Promise.all(promises).then(function () { + return parentElement; + }); + }); + } +} + +class Context { + constructor(view) { + let self = this; + this._siteContent = null; + this.firstStart = true; + this.inflatePromise = new Promise(function (resolver) { + self.inflatePromiseResolver = resolver; + }); + this.fragments = {}; + + if (Helper.isNotNull(view)) { + this.inflateView(view); + } + } + + onConstruct() { + let results = []; + for (let k in this.fragments) { + results.push(this.fragments[k].onConstruct.apply(this.fragments[k], arguments)); + results.push(this.fragments[k].inflatePromise); + } + return Promise.all(results); + } + + onStart() { + if (this.firstStart) { + this.onFirstStart(); + this.firstStart = false; + } + + for (let k in this.fragments) { + let fragment = this.fragments[k]; + fragment.onStart.apply(this.fragments[k], arguments); + this.fragments[k].inflatePromise.then(function (fragmentView) { + if (fragment.isActive()) { + fragmentView.classList.remove("hidden"); + } + else { + fragmentView.classList.add("hidden"); + } + }); + } + } + + onFirstStart() { + // for (let k in this.fragments) { + // this.fragments[k].onFirstStart.apply(this.fragments[k], arguments); + // } + } + + onPause() { + for (let k in this.fragments) { + this.fragments[k].onPause.apply(this.fragments[k], arguments); + } + } + + onDestroy() { + for (let k in this.fragments) { + this.fragments[k].onDestroy.apply(this.fragments[k], arguments); + } + } + + addFragment(viewQuery, fragment) { + this.fragments[viewQuery] = fragment; + this.inflatePromise = this.inflatePromise.then(function (siteContent) { + return fragment.inflatePromise.then(function (fragmentView) { + siteContent.querySelector(viewQuery).appendChild(fragmentView); + return siteContent; + }); + }); + } + + /** @protected */ + inflateView(link) { + let self = this; + this.inflatePromiseResolver(ViewInflater.inflate(link).then(function (siteContent) { + self._siteContent = siteContent; + return siteContent; + })); + + return this.inflatePromise; + } + + findBy(query, all, asPromise) { + all = Helper.nonNull(all, false); + asPromise = Helper.nonNull(asPromise, false); + + let getVal = function (root) { + let res = null; + if (all) { + res = root.querySelectorAll(query); + if (root.matches(query)) { + res.push(root); + } + } + else { + if (root.matches(query)) { + res = root; + } + else { + res = root.querySelector(query); + } + } + return res; + }; + + if (asPromise) { + return this.inflatePromise.then(function (rootView) { + return getVal(rootView); + }); + } + return getVal(this._siteContent); + } +} + +class AbstractSite extends Context { + constructor(siteManager, view, deepLink) { + super(view); + + this.isVisible = false; + this.siteManager = siteManager; + this.isFinishing = false; + this.actionMenu = null; + this.url = ""; + this.deepLink = deepLink; + this.startArgs = {}; + this.title = siteManager.getDefaultTitle(); + } + + setTitle(titleElement, title) { + if (typeof titleElement === "string") { + title = titleElement; + titleElement = document.createTextNode(titleElement); + } + this.title = { + element: titleElement + }; + this.title["title"] = Helper.nonNull(title, this.title["title"]); + + if (this.isVisible) { + this.siteManager.updateTitle(); + } + } + + startStartsite() { + return this.startSite(this.siteManager.getStartSiteName()); + } + + inflateView(link) { + let self = this; + return super.inflateView(link).then(function (res) { + let promises = []; + for (let i = 0, n = self.fragments.length; i < n; i++) { + promises.push(self.fragments[i].inflatePromise); + } + return Promise.all(promises).then(function () { + return res; + }); + }); + } + + onConstruct(args) { + this.startArgs = args; + if (Helper.isNotNull(this.deepLink)) { + this.setUrlFromParams(args); + } + return super.onConstruct(args); + } + + onStart(args) { + this.isVisible = true; + let res = super.onStart(args); + this.actionMenu.redraw(); + return res; + } + + onPause(args) { + super.onPause(args); + this.isVisible = false; + } + + finish(result) { + if (!this.isFinishing) { + this.isFinishing = true; + this.siteManager.endSite(this, result); + } + } + + startSite(siteName, args) { + return this.siteManager.startSite(siteName, args); + } + + toForeground() { + this.siteManager.toForeground(this); + } + + finishAndStartNext(siteName, startParams, finishResult) { + this.startSite(siteName, startParams); + this.finish(finishResult); + } + + createActionBarMenu(menu) { + let defaultActions = this.siteManager.getDefaultActions(); + for (let i = 0, n = defaultActions.length; i < n; i++) { + menu.addAction(defaultActions[i].copy()); + } + return menu; + } + + setUrl(url) { + this.url = url; + this.siteManager.updateUrl(this); + } + + setUrlFromParams(params) { + this.setUrl(this.deepLink + Helper.buildQuery(params)); + } + + updateUrlParams(params) { + this.startArgs = Object.assign(this.startArgs, params); + this.setUrlFromParams(this.startArgs); + } + + getUrl() { + return this.url; + } + + getFullUrl() { + return Helper.basePath(this.url); + } + + onBackPressed() { + } + + addListener(event, selector, listenerFunction) { + this.siteManager.addListener(this, event, selector, listenerFunction); + } + + addKeyListener(keycode, listenerFunction) + { + this.siteManager.addKeyListener(this, keycode, listenerFunction); + } + + addKeyAndEventListener(keycode, event, selector, listenerFunction) { + this.siteManager.addKeyAndEventListener(this, keycode, event, selector, listenerFunction); + } +} + +class SiteContainer { + constructor(site, finishResolver) { + this._site = site; + this._siteContent = null; + this._pauseParameters = {}; + this._startParameters = {}; + this._finishResolver = finishResolver; + } + getSite() { + return this._site; + } + + setSite(site) { + if (site instanceof AbstractSite) { + this._site = site; + } + } + + getSiteContent() { + return this._siteContent; + } + + setSiteContent(value) { + this._siteContent = value; + } + + getPauseParameters() { + return this._pauseParameters; + } + + setPauseParameters(value) { + this._pauseParameters = value; + } + + getStartParameters() { + return this._startParameters; + } + + setStartParameters(value) { + this._startParameters = value; + } + + getFinishResolver() { + return this._finishResolver; + } + + setFinishResolver(value) { + this._finishResolver = value; + } +} + +class SiteManager { + constructor(siteDivId, actionBarMenuSelector) { + this.siteDiv = document.getElementById(siteDivId); + this.siteContainerStack = []; + this.currentSiteContainerToShow = null; + this.actionBarMenuSelector = Helper.nonNull(actionBarMenuSelector, '.action-bar'); + + this.siteStartingPromise = Promise.resolve(); + this.defaultActions = []; + this.startSiteName = null; + + this.titleElement = document.querySelector(".top-bar-title"); + + const defaultTitleElem = document.createElement("span"); + while (this.titleElement.childNodes.length > 0) { + const child = this.titleElement.firstChild; + child.remove(); + defaultTitleElem.appendChild(child); + } + + this.defaultTitle = { + element: defaultTitleElem, + title: document.title + }; + + let siteManager = this; + window.onpopstate = function (e) { + if (siteManager.siteContainerStack.length >= 1) { + let site = siteManager.siteContainerStack[siteManager.siteContainerStack.length - 1].getSite(); + if (site.onBackPressed() !== false) { + siteManager.endSite(site); + } + } + }; + } + + getDefaultTitle() { + return this.defaultTitle; + } + + setStartSiteName(startSiteName) { + this.startSiteName = startSiteName; + } + + getStartSiteName() { + return this.startSiteName; + } + + addDefaultAction(action) { + this.defaultActions.push(action); + } + + getDefaultActions() { + return this.defaultActions; + } + + async startSite(siteConstructor, paramsPromise) { + if (!(siteConstructor.prototype instanceof AbstractSite)) { + throw { + "error": "wrong class given! Expected AbstractSite, given " + siteConstructor.name + }; + } + + let site = new siteConstructor(this); + let resolver = {}; + let finishPromise = new Promise(function (resolve, reject) { + resolver.resolve = resolve; + resolver.reject = reject; + }); + let siteContainer = new SiteContainer(site, resolver); + this.siteDiv.removeAllChildren().appendChild(Helper.createLoadingSymbol()); + + this.siteStartingPromise = Promise.resolve(paramsPromise).then(async (params) => { + siteContainer.setStartParameters(params); + await Promise.all([site.onConstruct(params), site.inflatePromise]); + + site.actionMenu = site.createActionBarMenu(this.buildActionBarMenu()); + return this.show(siteContainer); + }).catch((e) => { + console.error("site start error:", e); + }); + + return finishPromise; + } + + endSite(site, result) { + let manager = this; + this.siteStartingPromise.then(function () { + let index = manager.findContainerIndexBySite(site); + let container = manager.siteContainerStack.splice(index, 1); + container = container[0]; + + let showSiteContainer = null; + if (container === manager.currentSiteContainerToShow) { + manager.currentSiteContainerToShow.getSite().onPause(); + manager.currentSiteContainerToShow = null; + let newSiteContainerIndex = manager.siteContainerStack.length - 1; + if (newSiteContainerIndex < 0) { + + manager.showAppEndedMessage(); + manager.startSite(manager.startSiteName); + return; + } + manager.siteDiv.removeAllChildren().appendChild(Helper.createLoadingSymbol()); + showSiteContainer = manager.siteContainerStack[newSiteContainerIndex]; + } + container.getSite().onDestroy(); + + Promise.resolve(result).then(function (resValue) { + container.getFinishResolver().resolve(resValue); + if (Helper.isNotNull(showSiteContainer)) { + manager.show(showSiteContainer); + } + }); + }); + } + + addListener(site, event, _selector, listener) { + this.siteDiv.addEventListener(event, function (_event) { + let _element = _event.target; + if (site.isVisible && _element.matches(_selector)) { + listener(_element, _event); + } + }); + } + + addKeyAndEventListener(site, keycode, event, selector, listener) { + this.addListener(site, event, selector, listener); + this.addKeyListener(site, keycode, listener); + } + + addKeyListener(site, keycode, listener) { + window.addEventListener("keydown", function (e) { + if (site.isVisible && e.which === keycode) { + listener(this, e); + } + }); + } + + toForeground(site) { + let index = this.findContainerIndexBySite(site); + let container = this.siteContainerStack.splice(index, 1); + container = container[0]; + + this.show(container); + } + + refreshCurrentSite() { + return this.show(this.currentSiteContainerToShow); + } + + /** @private */ + show(siteContainer) { + if (Helper.isNotNull(this.currentSiteContainerToShow)) { + this.currentSiteContainerToShow.setPauseParameters(this.currentSiteContainerToShow.getSite().onPause()); + this.currentSiteContainerToShow.setSiteContent(this.siteDiv.innerHTML); + } + this.siteDiv.removeAllChildren().appendChild(Helper.createLoadingSymbol()); + + let siteManager = this; + this.currentSiteContainerToShow = siteContainer; + if (-1 === this.siteContainerStack.indexOf(siteContainer)) { + this.siteContainerStack.push(siteContainer); + } + + return siteContainer.getSite().inflatePromise.then(function (data) { + siteContainer.getSite().actionMenu.redraw(); + siteManager.siteDiv.removeAllChildren().appendChild(data); + siteManager.updateTitle(); + Translator.getInstance().updateTranslations(); + return data; + }).then(function (data) { + siteContainer.getSite().onStart(siteContainer.getPauseParameters()); + history.pushState({ + 'siteName': siteContainer.getSite().constructor.name, + 'siteData': data.outerHTML, + 'stackPosition': siteManager.siteContainerStack.length - 1 + }, siteContainer.getSite().constructor.name, siteContainer.getSite().getFullUrl()); + }); + } + + updateUrl(site) { + if (Helper.isNotNull(this.currentSiteContainerToShow) && this.currentSiteContainerToShow.getSite() === site) { + let self = this; + history.replaceState({ + 'siteName': site.constructor.name, + 'siteData': site._siteContent.outerHTML, + 'stackPosition': self.siteContainerStack.length - 1 + }, site.constructor.name, site.getFullUrl()); + } + } + + getCurrentSite() { + if (this.currentSiteContainerToShow != null) + return this.currentSiteContainerToShow.getSite(); + } + + redrawCurrentActionBar() { + if (this.currentSiteContainerToShow != null) + this.currentSiteContainerToShow.getSite().actionMenu.redraw(); + } + + updateTitle() { + let title = this.getCurrentSite().title; + this.titleElement.removeAllChildren().appendChild(title.element); + document.title = Helper.nonNull(title.title, this.defaultTitle.title); + } + + /** @private */ + findContainerIndexBySite(site) { + for (let i = 0, n = this.siteContainerStack.length; i < n; i++) { + if (this.siteContainerStack[i].getSite() === site) { + return i; + } + } + return -1; + } + + /** @private */ + findContainerBySite(site) { + let index = this.findContainerIndexBySite(site); + if (index === -1) { + return null; + } + return this.siteContainerStack[index]; + } + + /** @private */ + showAppEndedMessage() { + this.siteDiv.removeAllChildren().appendChild(Translator.makePersistentTranslation("The app has ended! Please close the window.")); + } + + /** @private */ + buildActionBarMenu() { + return new ActionBarMenu(this.actionBarMenuSelector); + } +} + +class PauseSite extends AbstractSite { + onConstruct(args) { + let pausedElement = null; + + if (Helper.isSet(args, "url")) { + pausedElement = args["url"]; + } + else { + pausedElement = document.createElement("div"); + pausedElement.innerHTML = "Paused..."; + } + + this.inflateView(pausedElement); + } +} + +class App { + constructor() { + this._siteManager = null; + this._actionBarMenuSelector = '.action-bar'; + this._basePath = SystemSettings.getBasePath(); + this._siteContentId = 'site-content'; + this._deepLinks = new Map(); + this._defaultActions = []; + this._addThemeAction = false; + this._showCookieCompliance = true; + this._startSite = null; + } + + getSiteManager() + { + return this._siteManager; + } + + addDefaultAction(action) { + this._defaultActions.push(action); + } + + setAddThemeAction(addThemeAction) { + this._addThemeAction = addThemeAction; + } + + getSiteContentId() { + return this._siteContentId; + } + + setSiteContentId(value) { + this._siteContentId = value; + } + + getActionBarMenuSelector() { + return this._actionBarMenuSelector; + } + + setActionBarMenuSelector(value) { + this._actionBarMenuSelector = value; + } + + getBasePath() { + return this._basePath; + } + + setBasePath(value) { + this._basePath = value; + } + + addDeepLink(alias, site) { + this._deepLinks.set(alias.toLowerCase(), site); + } + + setShowCookieCompliance(cookieCompliance) + { + this._showCookieCompliance = cookieCompliance; + } + + refreshCurrentSite() + { + this._siteManager.refreshCurrentSite(); + } + + pause(elementToShow){ + this.startSite(PauseSite, {"url": elementToShow}); + } + + resume(){ + const currentSite = this._siteManager.getCurrentSite(); + if (currentSite instanceof PauseSite) + { + currentSite.finish(); + } + } + + _resolveDeepLink(deepLink) { + deepLink = deepLink.toLowerCase(); + if (this._deepLinks.has(deepLink)) { + return this._deepLinks.get(deepLink); + } + return null; + } + + _getDeepLink() { + let deepLink = ""; + if (window.location.pathname.search(this._basePath) === 0) { + deepLink = window.location.pathname.substr(this._basePath.length).trim(); + } + if (deepLink.charAt(0) === '/') { + deepLink = deepLink.substr(1).trim(); + } + if (deepLink.charAt(deepLink.length - 1) === '/') { + deepLink = deepLink.substr(0, deepLink.length - 2).trim(); + } + if (deepLink.length === 0 && window.location.hash) { + deepLink = window.location.hash.substr(1).trim(); + } + + return this._resolveDeepLink(deepLink); + } + + _addDeepLinksListener() { + let app = this; + let elements = document.getElementsByClassName("deep-link"); + for (let i = 0, n = elements.length; i < n; i++) { + elements[i].addEventListener("click", function (e) { + e.preventDefault(); + app._siteManager.startSite(Helper.nonNull(app._resolveDeepLink(this.dataset["siteName"]), app._startSite), App._extractParams(this.dataset["siteArgs"])); + return true; + }); + } + } + + removeDefaultAction(action) + { + let index = this._defaultActions.indexOf(action); + if (index >= 0) + { + this._defaultActions[index].remove(true); + this._defaultActions.splice(index, 1); + } + } + + startSite(site, parameter) + { + return this._siteManager.startSite(site, parameter); + } + + start(fallbackStartSite) { + SystemSettings.setBasePath(this._basePath); + let startSite = Helper.nonNull(this._getDeepLink(), fallbackStartSite); + let startParams = App._getStartParams(); + this._startSite = fallbackStartSite; + + Translator.init(); + ThemeManager.init(); + if (this._addThemeAction) { + this.addDefaultAction(ThemeManager.generateChangeThemeMenuAction()); + } + this._siteManager = new SiteManager(this._siteContentId, this._actionBarMenuSelector); + this._siteManager.defaultActions = this._defaultActions; + this._siteManager.setStartSiteName(fallbackStartSite); + this._siteManager.startSite(startSite, startParams); + this._addDeepLinksListener(); + + if (this._showCookieCompliance) + { + new CookieCompliance('cookie-compliance').showIfNeeded(); + } + } + + static _extractParams(paramString) { + if (Helper.isNull(paramString)) { + return null; + } + let result = {}, tmp = []; + let items = paramString.split("&"); + for (let index = 0; index < items.length; index++) { + tmp = items[index].split("="); + if (tmp[0].trim().length > 0) { + result[tmp[0]] = decodeURIComponent(tmp[1]); + } + } + return result; + } + + static _getStartParams() { + return App._extractParams(window.location.search.substr(1)); + } +} + +class Dialog { + constructor(content, title) { + this.resolver = null; + this.content = null; + this.backgroundElement = null; + this.cancelable = true; + this.title = Helper.nonNull(title, ""); + this.translatable = true; + this.additionalClasses = ""; + this.buttons = []; + this.result = null; + + if (Helper.isNotNull(content)) { + this.setContent(content); + } + } + + setTitle(title) { + this.title = title; + return this; + } + + setTranslatable(translatable) { + this.translatable = translatable; + } + + setAdditionalClasses(classes) { + this.additionalClasses = classes; + } + + getTitle() { + return this.title; + } + + setCancelable(cancelable) { + this.cancelable = (cancelable === true); + return this; + } + + async setContent(content) { + this.contentPromise = Promise.resolve(content); + this.content = await this.contentPromise; + return this; + } + + addButton(elementOrText, listenerOrResult, shouldClose) { + shouldClose = Helper.nonNull(shouldClose, true); + + let button = null; + if (typeof elementOrText === "string") { + button = document.createElement("button"); + button.classList.add("button"); + button.classList.add("right"); + button.appendChild(Translator.makePersistentTranslation(elementOrText)); + } + else { + button = elementOrText; + } + + let self = this; + if (typeof listenerOrResult !== "function") { + let result = listenerOrResult; + listenerOrResult = function () { + self.result = result; + }; + } + + let callback = null; + if (shouldClose) { + callback = function (e) { + if (Helper.isNotNull(listenerOrResult)) { + listenerOrResult(e); + } + self.close(); + }; + } + else { + callback = listenerOrResult; + } + + if (Helper.isNotNull(callback)) { + button.addEventListener("click", callback); + } + this.buttons.push(button); + } + + async show() { + + let titleElement = document.createElement("span"); + titleElement.classList.add("title"); + if (this.translatable && this.title !== "") { + titleElement.appendChild(Translator.makePersistentTranslation(this.title)); + } + else { + titleElement.innerHTML = this.title; + } + + let titleBar = document.createElement("div"); + titleBar.appendChild(titleElement); + + let contentContainer = document.createElement("div"); + contentContainer.classList.add("content-container"); + + let modalDialog = document.createElement("div"); + modalDialog.className = this.additionalClasses; + modalDialog.classList.add("modal"); + modalDialog.appendChild(titleBar); + modalDialog.appendChild(contentContainer); + + let buttonBar = document.createElement("div"); + buttonBar.classList.add("modal-button-container"); + + for (let i = 0, n = this.buttons.length; i < n; i++) { + buttonBar.appendChild(this.buttons[i]); + } + + await this.contentPromise; + if (!(this.content instanceof Node)) { + this.content = (this.translatable) ? Translator.makePersistentTranslation(this.content) : document.createTextNode(this.content); + } + contentContainer.appendChild(this.content); + + this.backgroundElement = document.createElement("div"); + this.backgroundElement.classList.add("background"); + this.backgroundElement.appendChild(modalDialog); + + this.backgroundElement.querySelector(".modal").appendChild(buttonBar); + this.backgroundElement.style.display = "block"; + + let self = this; + if (this.cancelable) { + let closeButton = document.createElement("span"); + closeButton.classList.add("close"); + closeButton.innerHTML = "×"; + + titleBar.appendChild(closeButton); + closeButton.addEventListener("click", function () { + self.close(); + }); + window.addEventListener("click", function (e) { + if (e.target === self.backgroundElement) { + self.close(); + } + }); + } + + document.body.appendChild(this.backgroundElement); + Translator.getInstance().updateTranslations(); + + return new Promise(function (resolve) { + self.resolver = resolve; + }); + } + + close() { + if (Helper.isNotNull(this.backgroundElement)) { + this.backgroundElement.style.display = "none"; + this.backgroundElement.remove(); + this.backgroundElement = null; + } + if (Helper.isNotNull(this.resolver)) { + this.resolver(this.result); + } + } + + addDefaultButton(){ + this.addButton("confirm-button"); + } +} + +class FlashMessenger { + static deleteMessage(_idNumber, _delayInMilliSeconds) { + _delayInMilliSeconds = Helper.nonNull(_delayInMilliSeconds, 0); + setTimeout(function () { + let elem = document.getElementById("flashMessage" + _idNumber); + elem.fadeOut(.2).then(function () { + elem.remove(); + }); + }, _delayInMilliSeconds); + } + + static addMessage(messageType, messageText, timeToShow, translate){ + + let translationArgs = null; + if (Helper.isNull(messageText) || typeof messageText === "object") + { + translationArgs = messageText; + messageText = messageType; + messageType = FlashMessenger.MESSAGE_TYPE_SUCCESS; + translate = true; + } + translate = Helper.nonNull(translate, false); + + let id = FlashMessenger.messageCount; + + let wrapper = document.createElement("div"); + + let _flashMessage = document.createElement("div"); + _flashMessage.className = "flashMessage " + messageType; + _flashMessage.id = "flashMessage" + id; + _flashMessage.style.opacity = '0'; + _flashMessage.addEventListener("click", function () { + FlashMessenger.deleteMessage(id); + }); + _flashMessage.appendChild((translate) ? Translator.makePersistentTranslation(messageText, translationArgs, "span") : document.createTextNode(messageText)); + + wrapper.appendChild(_flashMessage); + document.getElementById("flashMessageContainer").appendChild(wrapper); + _flashMessage.fadeIn(); + timeToShow = Helper.nonNull(timeToShow, FlashMessenger.defaultTimeToShow); + if (timeToShow > 0) { + FlashMessenger.deleteMessage(FlashMessenger.messageCount, timeToShow); + } + FlashMessenger.messageCount++; + } +} + +FlashMessenger.messageCount = 0; +FlashMessenger.defaultTimeToShow = 3500; +FlashMessenger.LENGTH_SHORT= 1000; + +FlashMessenger.MESSAGE_TYPE_SUCCESS = 'success'; +FlashMessenger.MESSAGE_TYPE_ERROR = 'error'; +FlashMessenger.MESSAGE_TYPE_DEFAULT = 'default'; +FlashMessenger.MESSAGE_TYPE_INFO = 'info'; +FlashMessenger.MESSAGE_TYPE_WARNING = 'warning'; + +class InitPromise +{ + static addPromise(promise) + { + if (typeof promise === 'function') + { + let func = promise; + promise = InitPromise.mainPromise.then(function(app){ + return (func(app)); + }); + } + InitPromise.promises.push(promise); + } + + static resolve(app) + { + InitPromise.mainResolver(app); + return InitPromise.mainPromise.then(function(){ + return Promise.all(InitPromise.promises); + }); + } +} +InitPromise.promises = []; +InitPromise.mainPromise = new Promise(function(resolver){ + InitPromise.mainResolver = resolver; +}); + +class MyDb { + constructor(dbName, version) { + let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB; + this._conn = indexedDB.open(dbName, version); + + let myDB = this; + this._conn.onupgradeneeded = function (upgradeEvent) { + myDB.upgrade(myDB._conn.result, upgradeEvent.oldVersion, upgradeEvent.newVersion, upgradeEvent); + }; + this.queryPromise = new Promise(function (resolve) { + myDB._conn.onsuccess = function (e) { + myDB._db = myDB._conn.result; + resolve(e); + }; + }); + } + + openTransaction(name, transactionMode, callback) { + let myDb = this; + if (typeof transactionMode === 'function' && Helper.isNull(callback)) { + callback = transactionMode; + transactionMode = "read"; + } + + this.queryPromise.then(function () { + let res = null; + try { + res = myDb._conn.result.transaction(name, transactionMode); + } + catch (e) { + console.warn(e); + res = myDb._conn.result.transaction(name); + } + callback(res); + }); + } + + openStore(name, transactionMode, callback) { + if (typeof transactionMode === 'function' && Helper.isNull(callback)) { + callback = transactionMode; + transactionMode = "readonly"; + } + this.openTransaction(name, transactionMode, function (t) { + callback(t.objectStore(name)); + }); + } + + saveObj(obj, objectStore) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, "readwrite", function (store) { + let request = store.put(obj); + request.onsuccess = resolve; + request.onerror = function (e) { + throw { + "type": "indexed-db-error", + "event": e + } + }; + }); + }); + } + + saveMany(manyObj, objectStore) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, "readwrite", function (store) { + let promises = []; + for (let i = 0, n = manyObj.length; i < n; i++) { + promises.push(new Promise(function (resolveInner) { + let request = store.put(manyObj[i]); + request.onsuccess = resolveInner; + request.onerror = function (e) { + throw { + "type": "indexed-db-error", + "event": e + } + }; + })); + } + resolve(Promise.all(promises)); + }); + }); + } + + load(key, objectStore) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, function (store) { + let request = store.get(key); + request.onsuccess = function (e) { + resolve(e.currentTarget.result); + }; + request.onerror = function (e) { + console.warn(e); + throw { + "type": "indexed-db-load-error", + "event": e + } + }; + }); + }); + } + + loadAll(objectStore, query, count) + { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, function (store) { + let request = store.getAll(query, count); + request.onsuccess = function (e) { + resolve(e.currentTarget.result); + }; + request.onerror = function (e) { + console.warn(e); + throw { + "type": "indexed-db-load-error", + "event": e + } + }; + }); + }); + } + + loadMany(index, value, objectStore, limit, direction) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, function (store) { + let indexRequest = store.index(index); + indexRequest.onerror = function (e) { + throw { + "type": "indexed-db-index-error", + "event": e + } + }; + let request = indexRequest.openCursor(value, direction); + request.onerror = function (e) { + throw { + "type": "indexed-db-index-error", + "event": e + } + }; + let objects = []; + let numberResults = 0; + request.onsuccess = function (e) { + let cursor = e.target.result; + if (cursor) { + objects.push(cursor.value); + numberResults++; + if (Helper.isNull(limit) || numberResults < limit) { + cursor.continue(); + return; + } + } + resolve(objects); + }; + }); + }); + } + + remove(id, objectStore) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, "readwrite", function (store) { + let deleteRequest = store.delete(id); + deleteRequest.onerror = function (e) { + throw { + "type": "indexed-db-delete-error", + "event": e + } + }; + deleteRequest.onsuccess = function (e) { + resolve(); + }; + }); + }); + } + + removeMany(ids, objectStore) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, "readwrite", function (store) { + let promises = []; + for (let i = 0, n = ids.length; i < n; i++) { + let deleteRequest = store.delete(ids[i]); + deleteRequest.onerror = function (e) { + throw { + "type": "indexed-db-delete-error", + "event": e + } + }; + promises.push(new Promise(function (resolve) { + deleteRequest.onsuccess = function () { + resolve(); + }; + })); + } + resolve(Promise.all(promises)); + }); + }); + } + + removeWithIndex(index, value, objectStore) { + let self = this; + return new Promise(function (resolve) { + self.openStore(objectStore, "readwrite", function (store) { + let indexRequest = store.index(index); + indexRequest.onerror = function (e) { + throw { + "type": "indexed-db-index-error", + "event": e + } + }; + let request = indexRequest.openCursor(value); + request.onerror = function (e) { + throw { + "type": "indexed-db-index-error", + "event": e + } + }; + request.onsuccess = function (e) { + let cursor = e.target.result; + if (cursor) { + cursor.delete(); + cursor.continue(); + } + else { + resolve(); + } + }; + }); + }); + } + + removeAll(objectStore){ + return new Promise((resolve) => { + this.openStore(objectStore, "readwrite", (store) => { + let req = store.clear(); + req.onerror = (e) => { + throw { + "type":"indexed-db-index-error", + "event": e + } + }; + req.onsuccess = resolve; + }); + }) + } + + upgrade(db) { + }; +} + +class ScriptLoader { + static loadScript(scriptSrc) { + if (Helper.isNotNull(ScriptLoader.scriptPromises[scriptSrc])) { + return ScriptLoader.scriptPromises[scriptSrc]; + } + else { + let scriptPromise = new Promise(function (resolve) { + let script = document.createElement("script"); + script.src = Helper.basePath(scriptSrc); + script.onload = resolve; + + document.body.appendChild(script); + }); + ScriptLoader.scriptPromises[scriptSrc] = scriptPromise; + return scriptPromise; + } + } + static loadCss(cssFile, media){ + if (Helper.isNotNull(ScriptLoader.cssPromises[cssFile])) { + return ScriptLoader.cssPromises[cssFile]; + } + else { + media = Helper.nonNull(media, "all"); + let cssPromise = new Promise(function (resolve) { + let link = document.createElement("link"); + link.rel='stylesheet'; + link.type="text/css"; + link.href = Helper.basePath(cssFile); + link.media = media; + link.onload = resolve; + + document.head.appendChild(link); + }); + ScriptLoader.cssPromises[cssFile] = cssPromise; + return cssPromise; + } + } +} + +ScriptLoader.scriptPromises = {}; +ScriptLoader.cssPromises = {}; + +class ShareButton { + constructor(deviceType, icon, callback) + { + this._deviceType = deviceType; + this._icon = icon; + this._callback = callback; + } + + shouldShowFor(deviceType) + { + return (deviceType === (deviceType & this._deviceType)) + } + + getIcon() + { + return this._icon; + } + + getCallback() + { + return this._callback; + } +} +ShareButton.TYPE_DESKTOP = 1; +ShareButton.TYPE_MOBILE_APPLE = 2; +ShareButton.TYPE_MOBILE_LEFTOVER = 4; +ShareButton.TYPE_MOBILE = ShareButton.TYPE_MOBILE_APPLE+ShareButton.TYPE_MOBILE_LEFTOVER; +ShareButton.TYPE_ALL = ShareButton.TYPE_DESKTOP+ShareButton.TYPE_MOBILE; + +class ShareManager { + static init() { + ShareManager.shareButtons = []; + } + + static addShareButton(shareButton) { + ShareManager.shareButtons.push(shareButton); + } + + static generateDefaultShareElement(shareUrl) + { + return ShareManager.generateShareElement(shareUrl, ShareManager.getDefaultGenerateCallback()); + } + + static generateDefaultShareElementForButtons(shareUrl, buttons) + { + return ShareManager.generateShareElementForButtons(shareUrl, buttons, ShareManager.getDefaultGenerateCallback()); + } + + static generateShareElement(shareUrl, generateCallback) { + return ShareManager.generateShareElementForButtons(shareUrl, ShareManager.shareButtons, generateCallback); + } + + static generateShareElementForButtons(shareUrl, buttons, generateCallback) + { + let shareButtonElement = document.createElement("div"); + let currentDeviceType = ShareManager.getCurrentDeviceType(); + for (let i = 0, n = buttons.length; i < n; i++) { + if (buttons[i].shouldShowFor(currentDeviceType)) { + let elem = generateCallback(buttons[i], shareUrl); + elem.onclick = function(event){ + buttons[i].getCallback()(shareUrl, this, event); + }; + shareButtonElement.appendChild(elem); + } + } + return shareButtonElement; + } + + static getCurrentDeviceType() { + if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) { + return ShareButton.TYPE_MOBILE_APPLE; + } + else if ((navigator.userAgent.match(/Android|BlackBerry|Opera Mini|IEMobile/i) !== null || (typeof window.orientation !== "undefined"))) { + return ShareButton.TYPE_MOBILE_LEFTOVER; + } + else { + return ShareButton.TYPE_DESKTOP; + } + } + + static getDefaultGenerateCallback() + { + return function(button){ + let linkElement = document.createElement("a"); + let iconElement = document.createElement("img"); + linkElement.appendChild(iconElement); + + iconElement.src = Helper.basePath(button.getIcon()); + iconElement.classList.add("share-icon"); + + return linkElement; + } + } +} + +ShareManager.init(); + +class SmsShareButton extends ShareButton +{ + constructor(icon) { + super(ShareButton.TYPE_MOBILE, icon, function (link) { + let linkToOpen = ""; + if (ShareManager.getCurrentDeviceType() === ShareButton.TYPE_MOBILE_APPLE) { + linkToOpen = "sms:&body="+encodeURIComponent(link); + } + else { + linkToOpen = "sms:?body=" + encodeURIComponent(link); + } + window.open(linkToOpen, '_blank'); + }); + } +} + +class TelegramShareButton extends ShareButton { + constructor(icon) { + super(ShareButton.TYPE_ALL, icon, function (link) { + let linkToOpen = "https://t.me/share/url?url="+encodeURIComponent(link); + window.open(linkToOpen, '_blank'); + }); + } +} + +class WhatsappShareButton extends ShareButton { + constructor(icon) { + super(ShareButton.TYPE_ALL, icon, function (link) { + let linkToOpen = ""; + if (ShareManager.getCurrentDeviceType() === ShareButton.TYPE_DESKTOP) { + linkToOpen = "https://web.whatsapp.com/send?text="+encodeURIComponent(link); + } + else { + linkToOpen = "whatsapp://send?text=" + encodeURIComponent(link); + } + window.open(linkToOpen, '_blank'); + }); + } +} + +class Fragment extends Context +{ + constructor(site, view) + { + super(view); + this.site = site; + this.active = true; + } + + getSite() + { + return this.site; + } + + isActive() + { + return this.active; + } +} + +class Theme +{ + constructor(name, className, icon) + { + this._name = name; + this._className = className; + this._icon = icon; + } +} + +function applyPolyfills(){ + if (!String.prototype.format) { + String.prototype["format"] = function (args) { + return this.replace(/{(\d+)}/g, function (match, number) { + return args[number] !== undefined + ? args[number] + : match + ; + }); + }; + } + Object["assign"] = Helper.nonNull(Object["assign"], function (base, obj) { + base = Helper.nonNull(base, {}); + if (obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj) + return base; + + // if (obj instanceof Date) { + // temp = new obj.constructor(); //or new Date(obj); + // } + // else { + // temp = obj.constructor(); + // } + + for (let key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + obj['isActiveClone'] = null; + base[key] = obj[key]; + delete obj['isActiveClone']; + } + } + + return base; + }); + + if (typeof window !== 'undefined') { + if (Helper.isNotNull(window["Node"]) && !window["Node"]["prototype"]["removeAllChildren"]) { + Node.prototype["removeAllChildren"] = function () { + while (this.firstChild) { + this.removeChild(this.firstChild); + } + return this; + }; + } + + if (HTMLElement) { + HTMLElement.prototype["fadeOut"] = Helper.nonNull(HTMLElement.prototype["fadeOut"], + function (time, effect, delay) { + time = Helper.nonNull(time, 0.5); + effect = Helper.nonNull(effect, "ease-in-out"); + delay = Helper.nonNull(delay, 0); + this.style.transition = "opacity " + time + "s " + effect + " " + delay + "s"; + let elem = this; + let animPromise = new Promise(function (resolve) { + let transEndLis = function (e) { + elem.removeEventListener("transitionend", transEndLis); + elem.removeEventListener("transitioncancel", transCancelledLis); + elem.style.opacity = null; + elem.style.transition = null; + resolve(true, e); + }; + + let transCancelledLis = function (e) { + elem.removeEventListener("transitionend", transEndLis); + elem.removeEventListener("transitioncancel", transCancelledLis); + elem.style.opacity = null; + elem.style.transition = null; + resolve(false, e); + }; + elem.addEventListener("transitionend", transEndLis); + elem.addEventListener("transitioncancel", transCancelledLis); + }); + //Nach Seitenneuzeichnen, damit chrome das immer macht (und FF auch) + requestAnimationFrame(function () { + requestAnimationFrame(function () { + elem.style.opacity = 0; + }); + }); + return animPromise + }); + + HTMLElement.prototype["fadeIn"] = Helper.nonNull(HTMLElement.prototype["fadeIn"], function (time, effect, delay) { + time = Helper.nonNull(time, 0.5); + effect = Helper.nonNull(effect, "ease-in-out"); + delay = Helper.nonNull(delay, 0); + this.style.transition = "opacity " + time + "s " + effect + " " + delay + "s"; + + let elem = this; + let animPromise = new Promise(function (resolve) { + let transEndLis = function (e) { + elem.removeEventListener("transitionend", transEndLis); + elem.removeEventListener("transitioncancel", transCancelledLis); + elem.style.opacity = null; + elem.style.transition = null; + resolve(true, e); + }; + + let transCancelledLis = function (e) { + elem.removeEventListener("transitionend", transEndLis); + elem.removeEventListener("transitioncancel", transCancelledLis); + elem.style.opacity = null; + elem.style.transition = null; + resolve(false, e); + }; + elem.addEventListener("transitionend", transEndLis); + elem.addEventListener("transitioncancel", transCancelledLis); + }); + + //Nach Seitenneuzeichnen, damit chrome das immer macht (und FF auch) + requestAnimationFrame(function () { + requestAnimationFrame(function () { + elem.style.opacity = 1; + }); + }); + return animPromise; + }); + } + + if (Node) { + Node.prototype["replaceWith"] = Helper.nonNull(Node.prototype["replaceWith"], function (elem) { + this.parentElement.replaceChild(elem, this); + }); + Node.prototype["remove"] = Helper.nonNull(Node.prototype["remove"], function () { + this.parentElement.removeChild(this); + }); + } + + if (Element) { + Element.prototype.matches = Helper.nonNull(Element.prototype.matches, Helper.nonNull(Element.prototype["matchesSelector"], Element.prototype["webkitMatchesSelector"])); + + window["Element"]["prototype"]["closest"] = Helper.nonNull(window["Element"]["prototype"]["getAll"], function (s) { + // if (!Element.prototype.matches) + // Element.prototype.matches = Element.prototype.msMatchesSelector || + // Element.prototype.webkitMatchesSelector; + // + // if (!Element.prototype.closest) + // Element.prototype.closest = function(s) { + let el = this; + if (!document.documentElement.contains(el)) return null; + do { + if (el.matches(s)) return el; + el = el.parentElement; + } while (el !== null); + return null; + // }; + }); + } + + window["IDBObjectStore"]["prototype"]["getAll"] = Helper.nonNull(window["IDBObjectStore"]["prototype"]["getAll"], function () { + let res = {}; + let items = []; + this.openCursor().onsuccess = function (e) { + let cursor = e.target.result; + if (Helper.isNotNull(cursor)) { + items.push(cursor.value); + cursor.continue(); + } + else if (Helper.isNotNull(res.onsuccess)) { + res.onsuccess({currentTarget: {result: items}}); + } + }; + return res; + }); + } + + String.prototype.startsWith = Helper.nonNull(String.prototype.startsWith, function (searchString, position) { + position = position || 0; + return this.indexOf(searchString, position) === position; + }); + + String.prototype.endsWith = Helper.nonNull(String.prototype.endsWith, function (searchString, position) { + var subjectString = this.toString(); + if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { + position = subjectString.length; + } + position -= searchString.length; + var lastIndex = subjectString.indexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; + }); + + + window["fetch"] = Helper.nonNull(window["fetch"], function (url) { + console.log("customFetch", url); + let request = null; + if (window.XMLHttpRequest) { // Mozilla, Safari, ... + request = new XMLHttpRequest(); + } else if (window.ActiveXObject) { // IE + try { + request = new ActiveXObject('Msxml2.XMLHTTP'); + } + catch (e) { + try { + request = new ActiveXObject('Microsoft.XMLHTTP'); + } + catch (e) { + } + } + } + + let resultPromise = new Promise(function (resolve) { + request.onload = function () { + let data = this.responseText; + let response = { + json: function () { + return Promise.resolve(JSON.parse(data)); + }, + text: function () { + return Promise.resolve(data); + } + }; + resolve(response); + }; + request.onerror = function (err) { + resolve(Promise.reject(err)); + }; + }); + request.open('get', url, true); + request.send(); + return resultPromise; + }); +} + +class Constants{} +Constants.SCRIPTS = { + CKEDITOR:"version/2/ckeditor/ckeditor.js", + LIST_JS: "version/1/listjs/list.min.js" +}; + +class DataManager { + static load(url, isCachable, raw) { + isCachable = Helper.nonNull(isCachable, false); + raw = Helper.nonNull(raw, false); + let fullUrl = (isCachable) ? Helper.basePath(DataManager.cachePath + url) : Helper.basePath(DataManager.dataPath + url); + return fetch(fullUrl, {"credentials": "same-origin"}).then(function (res) { + if (raw) { + return res.text(); + } + return res.json(); + }).catch(function (e) { + console.error("error", e); + if (!raw) { + return { + "success": false, + "errors": [ + "not-online" + ] + } + } + }); + } + + static send(url, params) { + let fullUrl = Helper.basePath(DataManager.dataPath + url); + + if (!(params instanceof FormData)) { + let newParams = new FormData(); + for (let k in params) { + newParams.append(k, params[k]); + } + params = newParams; + } + + return fetch(fullUrl, { + "credentials": "same-origin", + "method": "POST", + "body": params + }).then(function (res) { + return res.json(); + }).catch(function (e) { + console.error("error", e); + return { + "success": false, + "errors": [ + "not-online" + ] + } + }); + } + + static buildQuery(values) { + return Helper.buildQuery(values); + } +} + +DataManager.dataPath = "data/"; +DataManager.cachePath = "cached/"; + +class Form { + constructor(formElem, url, method, isCachable) { + this.formElem = formElem; + this.method = Helper.nonNull(method, Helper.nonNull(formElem["method"], "POST")); + this.isCachable = (Helper.nonNull(isCachable, this.method.toLowerCase() === "get") === true); + + this.isBusy = false; + + if (typeof url === "string") + { + this.submitHandler = function(values){ + if (self.method.toLowerCase() === "get") { + return (DataManager.load(url + DataManager.buildQuery(values), self.isCachable)); + } + else { + return (DataManager.send(url, values)); + } + }; + } + else { + this.submitHandler = url; + } + + let self = this; + + this.submitCallback = null; + this.errorCallback = async function (errors) { + await self.setErrors(errors); + }; + + formElem.addEventListener("submit", async function (e) { + console.log("submitting!", e); + e.preventDefault(); + await self.doSubmit(e); + }); + + for (let i = 0, n = formElem.elements.length; i < n; i++) { + let elem = formElem.elements[i]; + elem.addEventListener("change", function () { + if (this.value.trim() !== "") { + this.classList.add("notEmpty"); + } + else { + this.classList.remove("notEmpty"); + } + this.setCustomValidity(""); + }); + elem.addEventListener("keydown", function () { + this.setCustomValidity(""); + }); + } + } + + onError(errorHandler, ownHandlerForOptimisticLocking){ + ownHandlerForOptimisticLocking = Helper.nonNull(ownHandlerForOptimisticLocking, true); + let callback = null; + + if (ownHandlerForOptimisticLocking){ + callback = function(errors){ + if (Array.isArray(errors) && errors.indexOf("optimistic-locking-exception") >= 0){ + let dialog = new Dialog("optimistic-locking-dialog", "optimistic-locking-dialog-title"); + dialog.addDefaultButton(); + dialog.show(); + } + else + { + errorHandler(errors); + } + }; + } + else + { + callback = errorHandler; + } + this.errorCallback = callback; + } + + doSubmit() { + if (!this.isBusy) { + let self = this; + return this.submit().then(function (res) { + if (res["success"]) { + if (self.submitCallback !== null) { + return self.submitCallback(res["result"]); + } + } + else if (Helper.isNotNull(self.errorCallback)) { + return self.errorCallback(res["errors"]); + } + }); + } + } + + load(url, isCached) { + this.setValues(DataManager.load(url, isCached).then(function (values) { + if (values["success"]) { + return values["result"]; + } + return {}; + })); + return this; + } + + setValues(valuePromise) { + this.setIsBusy(true); + + let self = this; + return Promise.resolve(valuePromise).then(function (values) { + self.setIsBusy(false); + for (let k in values) { + if (Helper.isNotNull(self.formElem.elements[k])) { + if (Helper.isNotNull(self.formElem.elements[k].options) && Helper.isNotNull(values[k+"Options"])) + { + let options = self.formElem.elements[k].options; + for (let val in values[k+"Options"]) + { + let option = document.createElement("option"); + option.value = val; + option.innerText = values[k+"Options"][val]; + options.add(option); + } + } + + self.formElem.elements[k].value = Helper.htmlspecialcharsDecode(values[k]); + if (Helper.isNotNull(values[k]) && (""+values[k]).trim() !== "") { + self.formElem.elements[k].classList.add("notEmpty"); + } + else { + self.formElem.elements[k].classList.remove("notEmpty"); + } + } + } + return self; + }); + } + + async setErrors(errors) { + let hasElem = false; + let firstError = null; + + for (let k in errors) { + if (Helper.isNotNull(this.formElem.elements[k]) && this.formElem.elements[k].type !== "hidden" + && Helper.isNull(this.formElem.elements[k].readonly) && ( + Helper.isNull(this.formElem.elements[k].disabled) || !this.formElem.elements[k].disabled) + ) { + this.formElem.elements[k].setCustomValidity(Translator.translate(Helper.nonNull(errors[k], "form-default-error"))); + hasElem = true; + } + if (Helper.isNull(firstError)) { + firstError = Helper.nonNull(errors[k], "form-default-error"); + } + } + if (!hasElem && Helper.isNotNull(firstError)) { + for (let k in this.formElem.elements) { + if (this.formElem.elements[k].type !== "hidden") { + this.formElem.elements[k].setCustomValidity(Translator.translate(firstError)); + hasElem = true; + break; + } + } + } + + if (hasElem) { + this.formElem.querySelector("input[type=submit]").click(); + } + } + + setIsBusy(isBusy) { + this.isBusy = isBusy; + if (this.isBusy) { + this.formElem.classList.add("sending"); + } + else { + this.formElem.classList.remove("sending"); + } + } + + submit() { + let self = this; + return new Promise(function (resolve) { + self.setIsBusy(true); + let values = new FormData(self.formElem); + resolve(self.submitHandler(values)); + }).then(function (data) { + self.setIsBusy(false); + return data; + }); + } + + onSubmit(callback) { + this.submitCallback = callback; + } +} + +class SettingsManager { + static getInstance() { + if (SettingsManager._instance === null) { + SettingsManager._instance = new SettingsManager(); + } + return SettingsManager._instance; + } + + constructor() { + this._settings = null; + this._localStorageKey = "settings"; + } + + getSettings() { + if (Helper.isNull(this._settings)) { + this._loadSettings(); + } + return this._settings; + } + + getSetting(name, defaultValue) { + const settings = this.getSettings(); + + if (Helper.isNotNull(settings[name])) { + return settings[name].value; + } + else { + return defaultValue; + } + } + + deleteSetting(name) { + this.getSettings(); + delete this._settings[name]; + this._saveSettings(); + } + + setSetting(name, value) { + this.getSettings(); + this._settings[name] = { + date: new Date().getTime(), + value: value + }; + this._saveSettings(); + } + + setSettings(settingsObject) { + this.getSettings(); + for (const k in settingsObject) { + this._settings[k] = settingsObject[k]; + } + this._saveSettings(); + } + + hasSetting(name) + { + return Helper.nonNull(this._settings[name]); + } + + _loadSettings() { + this._settings = localStorage.getItem(this._localStorageKey); + if (this._settings === null) { + this._settings = {}; + } + else { + this._settings = JSON.parse(this._settings); + } + } + + _saveSettings() { + if (this._settings !== null) { + localStorage.setItem(this._localStorageKey, JSON.stringify(this._settings)); + } + } +} + +SettingsManager._instance = null; + +class LocalStorageSettingsFragment extends Fragment { + onFirstStart() { + let res = super.onFirstStart(); + let settings = this.findBy(".setting", true); + const settingsManager = SettingsManager.getInstance(); + + for (let i = 0; i < settings.length; i++) { + let setting = settings[i]; + const name = setting.name; + let value = settingsManager.getSetting(name); + + let isCheckable = false; + if (setting instanceof HTMLInputElement && (setting.type === 'checkbox' || setting.type === 'radio')) { + isCheckable = true; + } + if (!settingsManager.hasSetting(name) && Helper.isNotNull(settings[i]["dataset"]["default"])) { + value = setting["dataset"]["default"]; + if (Helper.isNotNull(setting["dataset"]["defaultTranslateable"])) { + + setting["dataset"]["translation"] = ""; + setting["dataset"]["translationValue"] = value; + value = Translator.translate(value); + } + } + + if (Helper.isNotNull(value)) { + if (isCheckable) { + setting.checked = (value === setting.value); + } + else { + setting.value = value; + } + if (value !== "") { + setting.classList.add("notEmpty"); + } + } + + setting.addEventListener("change", function () { + let value = this.value; + if (isCheckable) { + if (this.checked) + { + settingsManager.setSetting(name, value); + } + else + { + settingsManager.setSetting(name, null); + } + } + else { + settingsManager.setSetting(name, value); + } + delete setting["dataset"]["translationValue"]; + delete setting["dataset"]["translation"]; + }); + } + return res; + } +} + +class SmartColumn{ + constructor(name, label, translateable){ + this._name = name; + this._label = label; + this._translateable = Helper.nonNull(translateable, true); + this._sortable = true; + + this._index = -1; + + this._clickListener = null; + } + + setClickListener(listener) + { + this._clickListener = listener; + return this; + } + + setIndex(index) + { + this._index = index; + } + + getName() + { + return this._name; + } + + getLabel() + { + return this._label; + } + + getHeadElement() + { + const headElement = document.createElement("th"); + headElement.appendChild((this._translateable)?Translator.makePersistentTranslation(this._label):document.createTextNode(this._label)); + + if (this._sortable) + { + headElement.classList.add("sort"); + headElement["dataset"]["sort"] = this._name; + } + + headElement["dataset"]["column"] = this._index; + + this._headElement = headElement; + return this._headElement; + } + + getValueName(){ + return this._name; + } + + prepareData(myData, rowData) + { + return myData; + } + + getItemElement(){ + const element = document.createElement("td"); + element.classList.add(this._name); + element["dataset"]["column"] = this._index; + + if (Helper.isNotNull(this._clickListener)) + { + element.classList.add("clickable"); + } + + return element; + } + + click(tableCell, table, event){ + if (Helper.isNotNull(this._clickListener)) + { + this._clickListener(tableCell, table, event); + } + } +} + +class ConstSmartColumn extends SmartColumn{ + constructor(name, label, translatable, valueTranslatable) { + super(name, label, translatable); + this._sortable = false; + this._valueTranslatable = Helper.nonNull(valueTranslatable, false); + } + + getValueName() { + return null; + } + + getItemElement(){ + const element = super.getItemElement(); + element.classList.remove(this._name); + element.appendChild((this._valueTranslatable)?Translator.makePersistentTranslation(this._name):document.createTextNode(this._name)); + return element; + } +} + +class DataSmartColumn extends SmartColumn{ + constructor(name, label, translateable) { + translateable = Helper.nonNull(translateable, false); + super(name, label, translateable); + } + + getHeadElement() { + return document.createTextNode(""); + } + + getValueName() { + return { + "data":[this._name] + }; + } + + getItemElement() { + return document.createTextNode(""); + } +} + +class ImgConstSmartColumn extends ConstSmartColumn{ + constructor(name, label, translateable) { + super(name, label, translateable); + this._valueTranslatable = false; + } + + getItemElement() { + const element = super.getItemElement(); + const imgElement = document.createElement("img"); + imgElement["src"] = this._name; + + element.removeAllChildren().appendChild(imgElement); + return element; + } +} + +class ListHelper { + constructor(id, options, values) { + this._tableElement = id; + this._options = Helper.nonNull(options, {}); + this._values = values; + + if (typeof this._tableElement === "string") { + this._tableElement = document.getElementById(this._tableElement); + } + + this._columns = []; + if (Array.isArray(options)) { + this._columns = options; + } + else if (Helper.isNotNull(options["columns"])) { + this._columns = options["columns"]; + } + } + + prepareData(data) { + console.log("prepareData", data); + if (Helper.isNotNull(data)) { + for (let i = 0, n = data.length; i < n; i++) { + data[i] = this.prepareDataset(data[i]); + } + } + return data; + } + + prepareDataset(dataset) { + console.log("prepareDataset", dataset); + for (let i = 0, n = this._columns.length; i < n; i++) { + if (Helper.isNotNull(dataset[this._columns[i].getName()])) { + dataset[this._columns[i].getName()] = this._columns[i].prepareData(dataset[this._columns[i].getName()], dataset); + } + } + return dataset; + } + + createTable() { + if (Helper.isNotNull(this._columns)) { + this.updateColumns(); + } + + let id = this._tableElement; + let options = this._options; + let values = this._values; + + options["item"] = Helper.nonNull(options["item"], id["id"] + "-template-item"); + options["page"] = Helper.nonNull(options["page"], 5); + options["pagination"] = Helper.nonNull(options["pagination"], { + "outerWindow": 1, + "innerWindow": 1 + }); + + let template = document.getElementById(options["item"]); + if (template) { + options["item"] = template.outerHTML; + template.remove(); + } + + values = this.prepareData(values); + + const list = new List(id, options, values); + let self = this; + id.querySelector("." + Helper.nonNull(options["listClass"], "list")).addEventListener("click", function (e) { + let columnElem = e.target.closest("td[data-column]"); + const column = parseInt(columnElem["dataset"]["column"]); + if (self._columns.length > column) { + self._columns[column].click(columnElem, list, e); + } + }); + this.list = list; + + return list; + } + + updateColumns() { + const head = document.createElement("tr"); + const item = document.createElement("tr"); + const valueNames = []; + + for (let i = 0, n = this._columns.length; i < n; i++) { + this._columns[i].setIndex(i); + + head.appendChild(this._columns[i].getHeadElement()); + item.appendChild(this._columns[i].getItemElement()); + + const valueName = this._columns[i].getValueName(); + if (Helper.isNotNull(valueName)) { + valueNames.push(valueName); + } + } + const header = this._tableElement.querySelector("thead"); + const footer = this._tableElement.querySelector("tfoot"); + + if (Helper.isNotNull(header)) { + header.removeAllChildren().appendChild(head); + } + if (Helper.isNotNull(footer)) { + footer.removeAllChildren().appendChild(Helper.cloneNode(head)); + } + + + this._options["item"] = item.outerHTML; + this._options["valueNames"] = valueNames; + } + + getList() { + return this.list; + } + + updateItem(valueName, value, newValues) { + const items = this.list.get(valueName, value); + if (Helper.isNotNull(items) && items.length >= 1) { + newValues = this.prepareDataset(newValues); + items[0].values(newValues); + } + } + + setBusy(isBusy) { + if (isBusy) { + this._tableElement.classList.add("sending"); + } + else { + this._tableElement.classList.remove("sending"); + } + } +} + +class SettingsSite extends AbstractSite { + constructor(siteManager) { + super(siteManager, SettingsSite.template, "settings"); + for (let k in SettingsSite.settingsFragments) { + this.addSettingsFragment(k, new SettingsSite.settingsFragments[k](this)); + } + this.active = null; + } + + addSettingsFragment(name, settingsFragment) { + this.addFragment("#settings-fragments", settingsFragment); + delete this.fragments["#settings-fragments"]; + this.fragments[name] = settingsFragment; + } + + onStart() { + let res = super.onStart(); + if (Helper.isNotNull(this.active) && !this.fragments[this.active].isActive()) { + this.setActive(null); + } + + this.buildList(); + return res; + } + + setActive(name) { + if (Helper.isNotNull(this.active)) { + this.fragments[this.active].inflatePromise.then(function (view) { + view.classList.remove("active"); + }); + this.findBy("#show-fragment-" + this.active).classList.remove("active"); + } + this.active = name; + if (Helper.isNotNull(this.active)) { + this.fragments[this.active].inflatePromise.then(function (view) { + view.classList.add("active"); + }); + this.findBy("#show-fragment-" + this.active).classList.add("active"); + } + } + + buildList() { + let listNameElem = this.findBy("#settings-fragment-list"); + listNameElem.removeAllChildren(); + + let self = this; + for (let k in this.fragments) { + if (this.fragments[k].isActive()) { + + let liElement = document.createElement("li"); + liElement.id = "show-fragment-" + k; + liElement.appendChild(Translator.makePersistentTranslation(k, null, "a")); + liElement.addEventListener("click", function () { + self.setActive(k); + }); + listNameElem.appendChild(liElement); + + if (Helper.isNull(this.active)) { + this.setActive(k); + } + } + } + } + + static addSettingsFragment(name, settingsFragment) { + SettingsSite.settingsFragments[name] = settingsFragment; + } + + static setAddSettingsSite(addLink) { + SettingsSite.shouldAddSettingsSite = addLink; + } + + static setTemplate(template) { + SettingsSite.template = template; + } +} + +SettingsSite.template = 'core/html/settings.html'; +SettingsSite.settingsFragments = {}; +SettingsSite.shouldAddSettingsSite = true; +SettingsSite.settingsAction = null; +SettingsSite.shouldAddSettingsAction = true; + +InitPromise.addPromise(function (app) { + if (SettingsSite.shouldAddSettingsSite) { + app.addDeepLink("settings", SettingsSite); + + if (Helper.isNull(SettingsSite.settingsAction)) { + let settingsAction = new MenuAction("settings", function () { + app.startSite(SettingsSite); + }, MenuAction.SHOW_FOR_LARGE, 10000); + settingsAction.setIcon("img/settings.png"); + SettingsSite.settingsAction = settingsAction; + } + if (SettingsSite.shouldAddSettingsAction) { + app.addDefaultAction(SettingsSite.settingsAction); + } + } +}); + +class UserManager { + static init(app) { + UserManager.getMeUrl = null; + UserManager.userData = { + online: false, + id: null, + accesses: ["default"] + }; + UserManager.app = app; + + UserManager.fetchMePromise = new Promise(function (resolve) { + UserManager.fetchMePromiseResolver = resolve; + }); + } + + static setData(data) { + UserManager.userData = Object.assign(UserManager.userData, data); + let siteManager = UserManager.app.getSiteManager(); + + if (siteManager) + siteManager.redrawCurrentActionBar(); + } + + static fetchMe(url) { + UserManager.getMeUrl = Helper.nonNull(url, UserManager.getMeUrl); + return DataManager.load(UserManager.getMeUrl).then(function (result) { + if (result["success"]) { + UserManager.setData(result["result"]); + } + UserManager.fetchMePromiseResolver(); + }); + } + + static logOut() { + return DataManager.load("u/logout").then(function (data) { + if (data["success"]) { + UserManager.setData(data["result"]); + let siteManager = UserManager.app.getSiteManager(); + + if (siteManager) + siteManager.refreshCurrentSite(); + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate("logged-out-successfully")); + } + }); + } + + static hasAccess(access) { + // console.log("Has access", access, UserManager.userData["accesses"].indexOf(access), UserManager.userData); + return (UserManager.userData["accesses"].indexOf(access) >= 0) + } + + static addCurrentUserListener(userId, listener) { + UserManager.addIsLoggedInListener(function (isLoggedIn) { + listener(isLoggedIn && UserManager.isCurrentUser(userId)); + }); + } + + static addIsLoggedInListener(listener) { + this.fetchMePromise.then(function () { + listener(UserManager.isLoggedIn()); + }); + } + + static isCurrentUser(userId) { + return UserManager.userData.id === userId; + } + + static isLoggedIn() { + return Helper.isNotNull(UserManager.userData) && Helper.isNotNull(UserManager.userData.id); + } +} + +InitPromise.addPromise(function(app){ + UserManager.init(app); + return UserManager.fetchMe("u/me").then(function(){ + UserManager.addIsLoggedInListener(function (isLoggedIn) { + if (isLoggedIn) { + const settingsManager = SettingsManager.getInstance(); + const settings = Helper.cloneJson(settingsManager.getSettings()); + for (let k in settings) { + settings[k]["value"] = JSON.stringify(settings[k]["value"]); + } + DataManager.send("u/syncSettings", settings).then(function(res){ + if (res["success"]) + { + for (let k in res["result"]) + { + res["result"][k]["value"] = JSON.parse(res["result"][k]["value"]); + } + settingsManager.setSettings(res["result"]); + } + }); + } + }); + }); +}); + +class UserAction extends MenuAction { + constructor(title, callback, icon, order, access) { + super(title, callback, icon, order); + this._access = Helper.nonNull(access, "default"); + } + + getVisible() { + // console.log("Action-access: ", this._access); + return (super.getVisible() && UserManager.hasAccess(this._access)); + } + + getAccess() { + return this._access; + } + + copy(instance){ + let copy = super.copy(Helper.nonNull(instance, new UserAction())); + copy._access = this._access; + return copy; + } +} + +class NotAllowedSite extends AbstractSite{ + constructor(siteManager) { + super(siteManager, 'userManagement/html/403.html'); + } +} + +class UserSite extends AbstractSite { + + constructor(siteManager, view, deepLink, access) { + super(siteManager, view, deepLink); + this._access = access; + } + + onConstruct(args) { + if (!UserManager.hasAccess(this._access)) + { + this.startSite(NotAllowedSite); + this.finish({ + "error":403 + }); + return; + } + return super.onConstruct(args); + } + + onStart(args) { + if (!UserManager.hasAccess(this._access)) + { + this.startSite(NotAllowedSite); + this.finish({ + "error":403 + }); + return; + } + return super.onStart(args); + } +} + +class LoginForm extends Form { + + constructor(formElem, url, method, isCachable) { + super(formElem, url, method, isCachable); + + let emailElem = formElem.querySelector("#email"); + let passwordElem = formElem.querySelector("#password"); + + let listener = function(){ + emailElem.setCustomValidity(""); + passwordElem.setCustomValidity(""); + }; + + emailElem.addEventListener("keydown", listener); + passwordElem.addEventListener("keydown", listener); + } +} + +class RegistrationForm extends Form { + constructor(formElem, url, method, isCachable) { + super(formElem, url, method, isCachable); + + // this.pw1 = formElem.querySelector("#password1"); + // this.pw2 = formElem.querySelector("#password2"); + + // let self=this; + // this.pw1.addEventListener("change", function(){ + // self.checkPw(); + // }); + // this.pw2.addEventListener("change", function(){ + // self.checkPw(); + // }); + } + + checkPw(){ + // if (this.pw1.value !== this.pw2.value || this.pw1.value.length < 8) + // { + // + // } + } +} + +class UserFragment extends Fragment{ + + constructor(site, view, access) { + super(site, view); + this._access = access; + } + + isActive() { + return super.isActive() && UserManager.hasAccess(this._access); + } +} + +class PasswordSettingsFragment extends UserFragment{ + constructor(site) + { + super(site, "userManagement/html/fragments/passwordSettings.html", "online"); + } + onFirstStart() { + let res = super.onFirstStart(); + let form = new Form(document.getElementById("change-password-form"), "u/passwordSettings/set", "post"); + form.onSubmit(function(res){ + for (let i = 0, n = res.length; i < n; i++) + { + FlashMessenger.addMessage(res[i]); + } + form.setValues({ + "oldPassword":"", + "newPassword1":"", + "newPassword2":"" + }); + }); + return res; + } +} +InitPromise.addPromise(function(){ + SettingsSite.addSettingsFragment("password-settings", PasswordSettingsFragment); +}); + +class UserSettingsFragment extends UserFragment{ + constructor(site) + { + super(site, "userManagement/html/fragments/userSettings.html", "online"); + } + + onFirstStart() { + let res = super.onFirstStart(); + (new Form(document.getElementById("user-settings-form"), "u/userSettings/set", "post")).load('u/userSettings').onSubmit(function(res){ + for (let i = 0, n = res.length; i < n; i++) + { + FlashMessenger.addMessage(res[i]); + } + }); + return res; + } +} +InitPromise.addPromise(function(){ + SettingsSite.addSettingsFragment("user-settings", UserSettingsFragment); +}); + +class EditUserRolesSite extends UserSite { + constructor(siteManager) { + super(siteManager, 'userManagement/html/editUserRoles.html', "userRoles", "admin"); + } + + onConstruct(args) { + let res = super.onConstruct(args); + this.userId = args["id"]; + + let self = this; + return Promise.all([ + ScriptLoader.loadScript(Constants.SCRIPTS.LIST_JS), + DataManager.load("u/userRoles" + DataManager.buildQuery({"id": self.userId})).then(function (res) { + if (!res["success"]) { + FlashMessenger.addMessage(res["errors"][0]); + self.finish(); + } + else { + self.setUserRoles(res["result"]["userRoles"]); + self.setAvailableRoles(res["result"]["availableRoles"]); + self.setUsername(res["result"]["username"]); + } + }) + ]).then(function () { + return res; + }); + } + + onFirstStart() { + this.findBy("#username").innerHTML = this.username; + + const userRolesElement = this.findBy("#userRoles"); + const availableRolesElement = this.findBy("#availableRoles"); + + const imgColumnUserRoles = new ImgConstSmartColumn("img/minus.png", "", false); + const imgColumnAvailableRoles = new ImgConstSmartColumn("img/plus.png", "", false); + + const userRolesColumns = [ + new DataSmartColumn("id"), + new SmartColumn("name", "name"), + new SmartColumn("description", "description"), + imgColumnUserRoles, + ]; + + const availableRolesColumns = [ + new DataSmartColumn("id"), + new SmartColumn("name", "name"), + new SmartColumn("description", "description"), + imgColumnAvailableRoles, + ]; + + const userRolesListHelper = new ListHelper(userRolesElement, userRolesColumns, this.userRoles); + const availableRolesListHelper = new ListHelper(availableRolesElement, availableRolesColumns, this.availableRoles); + + const userRolesTable = userRolesListHelper.createTable(); + const availableRolesTable = availableRolesListHelper.createTable(); + + let self = this; + const changeRoleFunction = function (roleId, addRole) { + userRolesListHelper.setBusy(true); + availableRolesListHelper.setBusy(true); + + return DataManager.send("u/changeUserRole", { + "id": roleId, + "userId": self.userId, + "add": addRole + }).then(function (res) { + userRolesListHelper.setBusy(false); + availableRolesListHelper.setBusy(false); + + if (!res["success"]) { + FlashMessenger.addMessage(res["errors"][0]); + return res; + } + + let removingTable = null; + let addingTable = null; + if (res["result"]["hasRole"]) { + removingTable = availableRolesTable; + addingTable = userRolesTable; + } + else { + addingTable = availableRolesTable; + removingTable = userRolesTable; + } + + const rowData = removingTable.get("id", roleId); + if (rowData.length === 1) { + addingTable.add(rowData[0].values()); + removingTable.remove("id", roleId); + } + + return res; + }); + }; + + imgColumnUserRoles.setClickListener(function (cell) { + let userRoleId = cell.closest("tr")["dataset"]["id"]; + changeRoleFunction(userRoleId, false); + }); + + imgColumnAvailableRoles.setClickListener(function (cell) { + let availableRoleId = cell.closest("tr")["dataset"]["id"]; + changeRoleFunction(availableRoleId, true); + }); + + } + + setUserRoles(userRoles) { + this.userRoles = userRoles; + } + + setAvailableRoles(availableRoles) { + this.availableRoles = availableRoles; + } + + setUsername(username) { + this.username = username; + } +} + +InitPromise.addPromise(function (app) { + app.addDeepLink("userRoles", EditUserRolesSite); + app.addDefaultAction(new UserAction('userRoles', function(){ + app.startSite(EditUserRolesSite); + }, null, 1100, "admin")); +}); + +class ForgotPasswordSite extends UserSite{ + + constructor(siteManager) { + super(siteManager, 'userManagement/html/forgotPassword.html', "forgotPassword", "offline"); + } + + onFirstStart() { + let self = this; + (new Form(document.getElementById("forgot-password-form"), "u/newPassword", "post")).onSubmit(function(res){ + // UserManager.setData(res); + // self.startStartsite(); + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate("new-password-code-send")); + self.finish(); + }); + } +} +InitPromise.addPromise(function(app){ + app.addDeepLink("forgotPassword", ForgotPasswordSite); +}); + +class LoginSite extends UserSite { + constructor(siteManager) { + super(siteManager, 'userManagement/html/login.html', "login", "offline"); + } + + onFirstStart() { + let self = this; + (new LoginForm(document.getElementById("login-form"), "u/login", "post")).onSubmit(function (res) { + UserManager.setData(res); + self.startStartsite(); + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate("login-success")); + self.finish(); + }); + + this.findBy("#forgot-password-link").addEventListener("click", function () { + self.startSite(ForgotPasswordSite); + self.finish(); + }); + } +} + +LoginSite.loginAction = null; +LoginSite.logoutAction = null; +LoginSite.addLoginAction = true; +LoginSite.addLogoutAction = true; + +InitPromise.addPromise(function (app) { + app.addDeepLink("login", LoginSite); + + if (Helper.isNull(LoginSite.loginAction)) { + LoginSite.loginAction = new UserAction('login', function () { + app.startSite(LoginSite); + }, Menu.SHOW_NEVER, 1100, "offline"); + } + if (Helper.isNull(LoginSite.logoutAction)) { + LoginSite.logoutAction = new UserAction('logout', function () { + UserManager.logOut(); + }, Menu.SHOW_NEVER, 1100, "online"); + } + if (LoginSite.addLoginAction){ + app.addDefaultAction(LoginSite.loginAction); + } + if (LoginSite.addLogoutAction){ + app.addDefaultAction(LoginSite.logoutAction); + } +}); + +class RegistrationSite extends UserSite { + constructor(siteManager) { + super(siteManager, 'userManagement/html/registration.html', "registration", "offline"); + } + + onFirstStart() { + (new RegistrationForm(document.getElementById("registration-form"), "u/registration", "post")).onSubmit(function (res) { + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate("registration-success")); + }); + } +} + +RegistrationSite.action = null; +RegistrationSite.addAction = true; + +InitPromise.addPromise(function (app) { + app.addDeepLink("registration", RegistrationSite); + + if (Helper.isNull(RegistrationSite.action)) { + RegistrationSite.action = new UserAction('registration', function () { + app.startSite(RegistrationSite); + }, null, 1100, "offline"); + } + if (RegistrationSite.addAction) { + app.addDefaultAction(RegistrationSite.action); + } +}); + +class SetNewPasswordSite extends UserSite { + constructor(siteManager) { + super(siteManager, 'userManagement/html/setNewPassword.html', "newPassword", "offline"); + } + + onConstruct(args) { + this.code = args["code"]; + return super.onConstruct(args); + } + + onFirstStart() { + let formElem = document.getElementById("new-password-form"); + document.getElementById("code").value = this.code; + + let self = this; + (new Form(formElem, "c/code", "post")).onSubmit(function(res){ + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate("password-updated")); + self.startSite(LoginSite); + self.finish(); + }); + } +} +InitPromise.addPromise(function(app){ + app.addDeepLink("newPassword", SetNewPasswordSite); +}); + +class ScaleHelper { + async scaleTo(scale, fontElement, container, ignoreHeight, ignoreWidth, margin, fontWeight, animationDelay, addListener) { + + addListener = Helper.nonNull(addListener, true); + animationDelay = Helper.nonNull(animationDelay, 0); + + let newFontSize = await this._getNewFontSize(scale, fontElement, container, ignoreHeight, ignoreWidth, margin, fontWeight, animationDelay === 0); + + if (animationDelay > 0) { + await new Promise(r => { + setTimeout(r, animationDelay); + fontElement.style.fontSize = newFontSize + "px"; + }); + } + + let self = this; + let listener = function () { + let timeout = (typeof addListener === 'number')?addListener:255; + setTimeout(() => { + self.scaleTo(scale, fontElement, container, ignoreHeight, ignoreWidth, margin, fontWeight, animationDelay, false); + }, timeout); + }; + if (addListener !== false) { + window.addEventListener("resize", listener); + } + return listener; + } + + async scaleToFull(fontElement, container, ignoreHeight, ignoreWidth, margin, fontWeight, animDelay, addListener) { + return this.scaleTo(1, fontElement, container, ignoreHeight, ignoreWidth, margin, fontWeight, animDelay, addListener); + } + + async _getNewFontSize(scale, fontElement, container, ignoreHeight, ignoreWidth, margin, fontWeight, setFontSize) { + margin = Helper.nonNull(margin, 10); + ignoreHeight = Helper.nonNull(ignoreHeight, false); + ignoreWidth = Helper.nonNull(ignoreWidth, false); + fontWeight = Helper.nonNull(fontWeight, fontElement.innerHTML.length); + setFontSize = Helper.nonNull(setFontSize, true); + + let hasNoTransitionClass = container.classList.contains("no-transition"); + + if (!hasNoTransitionClass) { + container.classList.add("no-transition"); + } + + let beforeFontSize = fontElement.style.fontSize; + let currentFontSize = 1; + let diff = 0; + let widthDiff = 0; + let heightDiff = 0; + let containerWidth = 0; + let containerHeight = 0; + do { + currentFontSize += diff / (fontWeight + 1); + fontElement.style.fontSize = currentFontSize + 'px'; + + let containerStyle = window.getComputedStyle(container); + + containerWidth = containerStyle.getPropertyValue("width").replace('px', ''); + containerHeight = containerStyle.getPropertyValue("height").replace('px', ''); + + widthDiff = containerWidth - fontElement.offsetWidth; + heightDiff = containerHeight - fontElement.offsetHeight; + + let newDiff = (ignoreWidth ? heightDiff : (ignoreHeight ? widthDiff : Math.min(widthDiff, heightDiff))); + if (newDiff === diff) { + break; + } + diff = newDiff; + } while ((widthDiff > (1 - scale) * containerWidth || ignoreWidth) && (heightDiff > (1 - scale) * containerHeight || ignoreHeight)); + + currentFontSize -= margin; + fontElement.style.fontSize = ((setFontSize) ? currentFontSize + "px" : beforeFontSize); + + if (!hasNoTransitionClass) { + await new Promise((r) => { + setTimeout(r, 50); + }); + container.classList.remove("no-transition"); + } + + return currentFontSize; + } +} + +class Code { + constructor(args) { + if (typeof args === "string") { + args = { + "code": args + }; + } + this.args = args; + this.isCacheable = false; + } + + setIsCacheable(isCacheable) { + this.isCacheable = isCacheable; + } + + getIsCacheable() { + return this.isCacheable; + } + + activate() { + return DataManager.send("c/code", this.args); + } +} + +class CodeSite extends AbstractSite { + constructor(siteManager) { + super(siteManager, "core/html/load.html", "code"); + } + + onConstruct(args) { + super.onConstruct(args); + console.log(args); + + let resPromise = Promise.resolve(); + if (Helper.isNotNull(args["code"])) { + let code = args["code"]; + let isCachable = Helper.nonNull(args["cachable"], false); + + let codeObject = new Code(code); + codeObject.setIsCacheable(isCachable); + + let self = this; + resPromise = codeObject.activate().then(function (res) { + if (!res["success"]) { + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate(res["errors"][0])); + } + else { + FlashMessenger.addMessage(FlashMessenger.MESSAGE_TYPE_SUCCESS, Translator.translate(Helper.nonNull(res["result"]["successMessage"], "code-activated"))); + } + self.finish(); + }); + } + } +} + +InitPromise.addPromise(function (app) { + app.addDeepLink("code", CodeSite); +}); + +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(rendererTypes) { + const levels = await this.loadMany("difficulty", IDBKeyRange.lowerBound(0), WordRotatorDb.OBJECT_STORE.LEVEL); + + let wrongLevels = []; + let newLevels = []; + let difficulty = -1; + for (let i = 0, n = levels.length; i < n; i++) { + if ((difficulty < 0 || difficulty === levels[i]["difficulty"]) && !levels[i]["deleted"] && !levels[i]["played"] && rendererTypes.indexOf(levels[i]["rendererType"]) !== -1) { + newLevels.push(levels[i]); + difficulty = levels[i]["difficulty"]; + } + else if (levels[i]["difficulty"] !== 0 && !levels[i]["deleted"] && !levels[i]["played"] ) { + wrongLevels.push(levels[i]); + } + } + + if (newLevels.length === 0) { + return null; + } + + return newLevels[Math.round(Math.random() * newLevels.length) % newLevels.length]; + } + + async saveLevelPlayed(levelId) { + const level = await this.loadLevel(levelId); + level.played = true; + return await this.saveObj(level, WordRotatorDb.OBJECT_STORE.LEVEL); + } +} + +WordRotatorDb.OBJECT_STORE = { + LEVEL: "level", +}; +WordRotatorDb.instance = null; + +class Segment{ + constructor(element){ + this.rotation = 0; + this.element = element; + this.parent = null; + } + + getCurrentRotations(rotations){ + return rotations; + } + + sameAs(otherSegment){ + return false; + } + + setParent(parent) + { + this.parent = parent; + } + + getLevel() + { + if (this.parent!==null) + { + return this.parent.getLevel(); + } + } + + canRotate(){ + return false; + } + + isSolved(){ + return (this.rotation === 0); + } + + async rotate(){ + return Promise.resolve(); + }; + + _updateElement(){}; + + applyRotations(rotations){ + return rotations; + } + + applyLocks(locks) + { + return locks; + } + + getCurrentLocked(lockedArray){ + return lockedArray; + } + + getElement() + { + return this.element; + } +} + +class ParentSegment extends Segment { + static initListener() { + window.addEventListener("mousedown", (e) => { + ParentSegment.mouseDownTarget = e.target; + // ParentSegment.mouseDownTarget = e.originalTarget; + }); + window.addEventListener("mouseup", (e) => { + ParentSegment.mouseDownTarget = null; + }); + + window.addEventListener("touchstart", (e) => { + console.log("start", e); + if (e.targetTouches.length === 1) { + ParentSegment.mouseDownTarget = e.targetTouches[0].target; + } + }); + window.addEventListener("touchend", (e) => { + console.log("end", e); + ParentSegment.mouseDownTarget = null; + }); + } + + setIsRotatable(rotatable){ + this.rotatable = rotatable; + this._updateElement(); + } + + constructor(element) { + super(element); + this.children = []; + this.class = "rotate-0"; + this.rotatable = true; + + let self = this; + this.touchendListener = function (e) { + if (e.targetTouches.length === 0 && e.changedTouches.length === 1 && self.element.contains(ParentSegment.mouseDownTarget) && self.element.contains(document.elementFromPoint(e.changedTouches[0].pageX, e.changedTouches[0].pageY))) { + self.rotate(); + e.stopPropagation(); + e.preventDefault(); + } + }; + this.mouseupListener = function (e) { + if (ParentSegment.mouseDownTarget !== null && self.element.contains(ParentSegment.mouseDownTarget) && self.element.contains(e.target)) { + self.rotate(); + e.stopPropagation(); + e.preventDefault(); + } + }; + } + + canRotate() { + return (this.rotatable && !this.getLevel().getHasWon()); + } + + async rotate() { + let timeout = 250; + if (this.canRotate()) { + this.rotation += 90; + this.rotation %= 360; + + let currentRotation = this.rotation; + + this._updateRotationClass(); + this.element.classList.add("rotating"); + + let self = this; + let delayPromise = new Promise(function (resolve) { + setTimeout(resolve, timeout); + }).then(() => { + if (self.rotation === currentRotation) { + self.element.classList.remove("rotating"); + } + }); + this.getLevel().checkHasWon(delayPromise); + return delayPromise; + } + } + + sameAs(otherSegment) { + if (!(otherSegment instanceof ParentSegment) || otherSegment.children.length !== this.children.length) { + return false; + } + for (let i = 0; i < this.children.length; i++) { + if (!this.children[i].sameAs(otherSegment.children[i])) { + return false; + } + } + return true; + } + + applyRotations(rotations) { + 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; + } + + applyLocks(locks) { + this.rotatable = locks[0]; + locks.splice(0, 1); + for (let i = 0, n = this.children.length; i < n; i++) { + locks = this.children[i].applyLocks(locks); + } + return locks; + } + + getCurrentRotations(rotations) { + rotations.push(this.rotation); + for (let i = 0, n = this.children.length; i < n; i++) { + rotations = this.children[i].getCurrentRotations(rotations); + } + return rotations; + } + + getCurrentLocked(locked) { + locked.push(this.rotatable); + for (let i = 0, n = this.children.length; i < n; i++) { + locked = this.children[i].getCurrentLocked(locked); + } + return locked; + } + + isSolved() { + for (let i = 0, n = this.children.length; i < n; i++) { + if (!this.children[i].isSolved()) { + return false; + } + } + return (this.rotation === 0 || ( + this.children[0].sameAs(this.children[2]) && this.children[1].sameAs(this.children[3]) && ( + this.rotation === 2 || this.children[0].sameAs(this.children[1])))) + } + + 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() { + let layer = this._getLayer(); + if (layer >= 2) { + this.element.classList.add("layer-" + layer); + } + + if (!this.rotatable){ + this.element.classList.add("locked"); + } + + const childContainer = this.element.querySelector(".child-container"); + childContainer.removeAllChildren(); + + this._updateRotationClass(); + + this.element.removeEventListener("mouseup", this.mouseupListener); + this.element.removeEventListener("touchend", this.touchendListener); + + this.element.addEventListener("mouseup", this.mouseupListener); + this.element.addEventListener("touchend", this.touchendListener); + + for (let i = 0, n = this.children.length; i < n; i++) { + this.children[i]._updateElement(); + childContainer.appendChild(this.children[i].getElement()); + if (i % 2 === 1 && this.children.length - 1 !== i) { + childContainer.appendChild(document.createElement("br")); + } + } + } + + _getLayer() { + if (this.children.length >= 1 && this.children[0] && this.children[0] instanceof ParentSegment) { + return this.children[0]._getLayer() + 1; + } + return 1; + } +} + +ParentSegment.initListener(); + +class LeafSegment extends Segment { + + constructor(element, leaf) { + super(element); + this.leaf = 'A'; + if (Helper.isNotNull(leaf)) { + this.setLeaf(leaf); + } + } + + sameAs(otherSegment) { + return (otherSegment instanceof LeafSegment && otherSegment.leaf === this.leaf); + } + + setLeaf(leaf) { + this.leaf = leaf; + } + + _updateElement() { + this.element.querySelector(".leaf-element").removeAllChildren().appendChild(document.createTextNode(this.leaf)); + } +} + +class TemplateContainer{ + constructor(leafTemplate, parentTemplate, rowTemplate, triangleTemplate){ + this.leafTemplate = leafTemplate; + this.parentTemplate = parentTemplate; + this.rowTemplate = rowTemplate; + this.triangleTemplate = triangleTemplate; + } + + copyLeafTemplate() + { + return Helper.cloneNode(this.leafTemplate); + } + + copyParentTemplate() + { + return Helper.cloneNode(this.parentTemplate); + } + + copyRowTemplate() + { + return Helper.cloneNode(this.rowTemplate); + } + + copyTriangleTemplate() + { + return Helper.cloneNode(this.triangleTemplate); + } +} + +class Level { + constructor(templateContainer) { + this.rootSegment = null; + this.words = []; + this.startRotations = []; + this.templateContainer = templateContainer; + + this.hasWon = false; + this.id = null; + + this.wonResolver = null; + this.giveUpResolver = null; + + const self = this; + this.wonPromise = new Promise((resolve, reject) => { + self.wonResolver = resolve; + self.giveUpResolver = reject; + }); + } + + saveAsCurrentLevel(){ + let rotations = this.getCurrentRotations(); + let locked = this.getCurrentLocked(); + localStorage.setItem("currentLevel", JSON.stringify({"id": this.id, "rotations": rotations, "locks":locked})); + } + + getCurrentLocked(){ + if (this.rootSegment !== null) + { + return this.rootSegment.getCurrentLocked([]); + } + return []; + } + + getCurrentRotations(){ + if (this.rootSegment !== null) + { + return this.rootSegment.getCurrentRotations([]); + } + return []; + } + + setLocks(locks) + { + if (this.rootSegment !== null){ + this.rootSegment.applyLocks(locks); + } + } + + setId(id) + { + this.id = id; + } + + getId() + { + return this.id; + } + + getLevel() + { + return this; + } + + setRootSegment(rootSegment) + { + this.rootSegment = rootSegment; + this.rootSegment.setParent(this); + if (this.startRotations) + { + this.applyRotations(); + } + } + + 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; + } + + applyRotations(rotations) + { + if (this.rootSegment) + { + rotations = Helper.nonNull(rotations, this.startRotations); + this.rootSegment.applyRotations(rotations); + } + } + + getHasWon() + { + return this.hasWon; + } + + checkHasWon(delayPromise) { + if (this.rootSegment.isSolved()){ + this.hasWon = true; + const self = this; + delayPromise.then(()=>{ + self.wonResolver(true); + }); + return true; + } + this.saveAsCurrentLevel(); + return false; + } + + getWonPromise(){ + return this.wonPromise; + } + + getRootSegment(){ + return this.rootSegment; + } + + createSegments() {}; + + getRotatableSegments(){ + return Level._getRotatableSegmentsFrom(this.rootSegment); + } + + static _getRotatableSegmentsFrom(segment){ + let rotatable = []; + if (segment.canRotate()) + { + rotatable.push(segment); + } + if (segment instanceof ParentSegment){ + for (let i = 0; i < segment.children.length; i++) { + rotatable.push.apply(rotatable, Level._getRotatableSegmentsFrom(segment.children[i])); + } + } + return rotatable; + } + + 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{ + constructor(element) { + super(element); + this.rotatable = false; + } + + applyRotations(rotations) + { + for (let i = 0, n = this.children.length; i < n; i++) { + rotations = this.children[i].applyRotations(rotations); + } + return rotations; + } + + getCurrentRotations(rotations){ + for (let i = 0, n = this.children.length; i < n; i++) { + rotations = this.children[i].getCurrentRotations(rotations); + } + return rotations; + } + + getCurrentLocked(locked) { + for (let i = 0, n = this.children.length; i < n; i++) { + locked = this.children[i].getCurrentLocked(locked); + } + return locked; + } + + applyLocks(locks) { + for (let i = 0, n = this.children.length; i < n; i++) { + locks = this.children[i].applyLocks(locks); + } + return locks; + } + + _updateElement() { + const childContainer = this.element.querySelector(".child-container"); + childContainer.removeAllChildren(); + + this._updateRotationClass(); + + const self = this; + this.element.onclick = function (e) { + self.rotate(); + e.stopPropagation(); + }; + + for (let i = 0, n = this.children.length; i < n; i++) { + this.children[i]._updateElement(); + childContainer.appendChild(this.children[i].getElement()); + } + } +} + +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 SimpleLevel extends RowLevel{ + constructor(container) { + super(container, 6); + } +} + +class RowLevel8 extends RowLevel{ + constructor(container) { + super(container, 8); + } +} + +class RowLevel10 extends RowLevel{ + constructor(container) { + super(container, 10); + } +} + +class TriangleSegment extends RowSegment{ + +} + +class SixWordsRowLevel extends Level { + + constructor(templateContainer, wordLength) { + super(templateContainer); + this.wordLength = wordLength; + } + + createSegments() { + if (this.words.length >= 6 && + this.words[0].length >= this.wordLength && + this.words[1].length >= this.wordLength && + this.words[2].length >= this.wordLength && + this.words[3].length >= this.wordLength && + this.words[4].length >= this.wordLength && + this.words[5].length >= this.wordLength + ) { + let leafsWords = []; + leafsWords[0] = Level._createLeafsForWord(this.words[0], this.templateContainer.copyLeafTemplate()); + leafsWords[1] = Level._createLeafsForWord(this.words[1], this.templateContainer.copyLeafTemplate()); + leafsWords[2] = Level._createLeafsForWord(this.words[2], this.templateContainer.copyLeafTemplate()); + leafsWords[3] = Level._createLeafsForWord(this.words[3], this.templateContainer.copyLeafTemplate()); + leafsWords[4] = Level._createLeafsForWord(this.words[4], this.templateContainer.copyLeafTemplate()); + leafsWords[5] = Level._createLeafsForWord(this.words[5], this.templateContainer.copyLeafTemplate()); + + let rootSegment = new RowSegment(this.templateContainer.copyRowTemplate()); + for (let i = 0; i < this.wordLength / 4; i++) { + + let parents = []; + parents[0] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[1] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[2] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[3] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[4] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[5] = new ParentSegment(this.templateContainer.copyParentTemplate()); + + parents[0].addChild(leafsWords[0][4*i]); + parents[0].addChild(leafsWords[0][4*i+1]); + parents[0].addChild(leafsWords[1][4*i]); + parents[0].addChild(leafsWords[1][4*i+1]); + + parents[1].addChild(leafsWords[0][4*i+2]); + parents[1].addChild(leafsWords[0][4*i+3]); + parents[1].addChild(leafsWords[1][4*i+2]); + parents[1].addChild(leafsWords[1][4*i+3]); + + parents[2].addChild(leafsWords[2][4*i]); + parents[2].addChild(leafsWords[2][4*i+1]); + parents[2].addChild(leafsWords[3][4*i]); + parents[2].addChild(leafsWords[3][4*i+1]); + + parents[3].addChild(leafsWords[2][4*i+2]); + parents[3].addChild(leafsWords[2][4*i+3]); + parents[3].addChild(leafsWords[3][4*i+2]); + parents[3].addChild(leafsWords[3][4*i+3]); + + parents[4].addChild(leafsWords[4][4*i]); + parents[4].addChild(leafsWords[4][4*i+1]); + parents[4].addChild(leafsWords[5][4*i]); + parents[4].addChild(leafsWords[5][4*i+1]); + + parents[5].addChild(leafsWords[4][4*i+2]); + parents[5].addChild(leafsWords[4][4*i+3]); + parents[5].addChild(leafsWords[5][4*i+2]); + parents[5].addChild(leafsWords[5][4*i+3]); + + + let parent = new ParentSegment(this.templateContainer.copyParentTemplate()); + let triangle = new TriangleSegment(this.templateContainer.copyTriangleTemplate()); + if (i % 2 === 0) { + parent.addChild(parents[0]); + parent.addChild(parents[1]); + parent.addChild(parents[2]); + parent.addChild(parents[3]); + + let rowSegment = new RowSegment(this.templateContainer.copyRowTemplate()); + + rowSegment.addChild(parents[4]); + rowSegment.addChild(parents[5]); + + triangle.addChild(parent); + triangle.addChild(rowSegment); + + triangle.getElement().classList.add("type-1"); + } + else { + + let rowSegment = new RowSegment(this.templateContainer.copyRowTemplate()); + + rowSegment.addChild(parents[0]); + rowSegment.addChild(parents[1]); + + triangle.addChild(rowSegment); + triangle.addChild(parent); + + parent.addChild(parents[2]); + parent.addChild(parents[3]); + parent.addChild(parents[4]); + parent.addChild(parents[5]); + + triangle.getElement().classList.add("type-2"); + } + rootSegment.addChild(triangle); + } + this.setRootSegment(rootSegment); + } + } +} + +class SixWordsRowLevel8 extends SixWordsRowLevel { + constructor(templateContainer) { + super(templateContainer, 8); + } +} + +class SixWordsRowLevel12 extends SixWordsRowLevel { + constructor(templateContainer) { + super(templateContainer, 12); + } +} + +class FourWordsLevel extends Level { + + constructor(templateContainer, wordLength) { + super(templateContainer); + this.wordLength = wordLength; + } + + createSegments() { + if (this.words.length >= 4 && + this.words[0].length >= this.wordLength && + this.words[1].length >= this.wordLength && + this.words[2].length >= this.wordLength && + this.words[3].length >= this.wordLength + ) { + let leafsWords = []; + leafsWords[0] = Level._createLeafsForWord(this.words[0], this.templateContainer.copyLeafTemplate()); + leafsWords[1] = Level._createLeafsForWord(this.words[1], this.templateContainer.copyLeafTemplate()); + leafsWords[2] = Level._createLeafsForWord(this.words[2], this.templateContainer.copyLeafTemplate()); + leafsWords[3] = Level._createLeafsForWord(this.words[3], this.templateContainer.copyLeafTemplate()); + + let rootSegment = new RowSegment(this.templateContainer.copyRowTemplate()); + for (let i = 0; i < this.wordLength / 4; i++) { + + let parents = []; + parents[0] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[1] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[2] = new ParentSegment(this.templateContainer.copyParentTemplate()); + parents[3] = new ParentSegment(this.templateContainer.copyParentTemplate()); + + parents[0].addChild(leafsWords[0][4 * i]); + parents[0].addChild(leafsWords[0][4 * i + 1]); + parents[0].addChild(leafsWords[1][4 * i]); + parents[0].addChild(leafsWords[1][4 * i + 1]); + + parents[1].addChild(leafsWords[0][4 * i + 2]); + parents[1].addChild(leafsWords[0][4 * i + 3]); + parents[1].addChild(leafsWords[1][4 * i + 2]); + parents[1].addChild(leafsWords[1][4 * i + 3]); + + parents[2].addChild(leafsWords[2][4 * i]); + parents[2].addChild(leafsWords[2][4 * i + 1]); + parents[2].addChild(leafsWords[3][4 * i]); + parents[2].addChild(leafsWords[3][4 * i + 1]); + + parents[3].addChild(leafsWords[2][4 * i + 2]); + parents[3].addChild(leafsWords[2][4 * i + 3]); + parents[3].addChild(leafsWords[3][4 * i + 2]); + parents[3].addChild(leafsWords[3][4 * i + 3]); + + let parent = new ParentSegment(this.templateContainer.copyParentTemplate()); + parent.addChild(parents[0]); + parent.addChild(parents[1]); + parent.addChild(parents[2]); + parent.addChild(parents[3]); + + rootSegment.addChild(parent); + } + this.setRootSegment(rootSegment); + } + } +} + +class FourWordsLevel8 extends FourWordsLevel{ + constructor(templateContainer) { + super(templateContainer, 8); + } +} + +class FourWordsLevel12 extends FourWordsLevel{ + constructor(templateContainer) { + super(templateContainer, 12); + } +} + +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.setId(jsonLevel["id"]); + + for (let i = 0, n = jsonLevel["rotations"].length; i < n; i++) { + if (jsonLevel["rotations"][i] <= 4) { + jsonLevel["rotations"][i] = 90 * jsonLevel["rotations"][i]; + } + } + + level.setStartRotations(jsonLevel["rotations"]); + return level; + } +} + +LevelHelper.types = { + 20: SimpleLevel, + 40: RowLevel8, + 60: RowLevel10, + 100: SixWordsRowLevel8, + 120: FourWordsLevel8, + 140: SixWordsRowLevel12, + 160: FourWordsLevel12, +}; + +class WordRotatorBaseSite extends AbstractSite { + // createActionBarMenu(menu) { + // menu = super.createActionBarMenu(menu); + // // menu.addAction(SettingsSite.settingsAction.copy()); + // // let actions = menu.actions; + // // for (let i = 0; i < actions.length; i++) { + // // if (actions[i].title === "login" || actions[i].title === "registration"){ + // // actions[i].setVisible(false); + // // } + // // } + // return menu; + // } +} + +class EndSite extends WordRotatorBaseSite{ + constructor(siteManager) { + super(siteManager, "html/application/end.html"); + } +} + +class LevelSite extends WordRotatorBaseSite { + constructor(siteManager) { + super(siteManager, "html/application/level.html"); + } + + createActionBarMenu(menu) { + menu = super.createActionBarMenu(menu); + + let coinAction = new MenuAction(Helper.nonNull(localStorage.getItem("coins"), "0"), () => { + }, MenuAction.SHOW_ALWAYS, 900); + coinAction.setShouldTranslate(false); + coinAction._liClass = "coin-counter"; + menu.addAction(coinAction); + this.coinAction = coinAction; + + return menu; + } + + onConstruct(args) { + this.levelCounter = Helper.nonNull(localStorage.getItem("levelCounter"), 1); + this.levelScaler = () => { + }; + this.wonParams = { + aborted: false, + coinCounterTimer: null, + audio: new Audio() + }; + this.wonParams.audioPromise = Promise.race([new Promise(resolve => { + this.wonParams.audio.addEventListener('loadeddata', resolve); + }), + new Promise(resolve => { + this.wonParams.audio.addEventListener('error', resolve); + }) + ]); + this.wonParams.audio.src = Helper.basePath("sound/single_coin_fall_on_concrete_.mp3"); + + return super.onConstruct(args); + } + + async onFirstStart() { + super.onFirstStart(); + let leafSegmentTemplate = this.findBy("#segment-leaf-template"); + let parentSegmentTemplate = this.findBy("#segment-parent-template"); + let rowSegmentTemplate = this.findBy("#segment-row-template"); + let triangleTemplate = this.findBy("#segment-triangle-template"); + + leafSegmentTemplate.id = null; + parentSegmentTemplate.id = null; + rowSegmentTemplate.id = null; + triangleTemplate.id = null; + + leafSegmentTemplate.remove(); + parentSegmentTemplate.remove(); + rowSegmentTemplate.remove(); + triangleTemplate.remove(); + + let self = this; + let continueButton = this.findBy("#continue-button"); + continueButton.addEventListener("click", () => { + self.nextLevel(); + }); + + let wonText = this.findBy("#won-text"); + + let scaleHelper = new ScaleHelper(); + this.continueButtonScaler = await scaleHelper.scaleToFull(continueButton, continueButton.parentElement, false, true); + this.wonTextScaler = await scaleHelper.scaleToFull(wonText, wonText.parentElement, false, false, 10, null, 5); + this.wonText = wonText; + this.wonText.style.fontSize = "0"; + + //Benutze Document, da Element außerhalb von Seite (eigentlich unschön!) + this.levelCounterActionContainer = document.getElementById("level-number-container"); + this.levelCounterAction = document.getElementById("level-number"); + this.levelCounterAction.innerText = this.levelCounter; + this.levelNumberScaler = await scaleHelper.scaleToFull(this.levelCounterAction, this.levelCounterActionContainer, false, false, 4); + this.levelCounterActionContainer.classList.add("visible"); + this.templateContainer = new TemplateContainer(leafSegmentTemplate, parentSegmentTemplate, rowSegmentTemplate, triangleTemplate); + + this.coinTemplate = this.findBy("#coin-template"); + this.coinContainer = this.findBy("#coin-container"); + + this.coinTemplate.id = null; + this.coinContainer.removeAllChildren(); + + this.findBy("#help-button").addEventListener("click", () => { + this.help(); + }); + + this.loadLastLevel(); + } + + async loadLastLevel() { + try { + let currentLevelInfo = localStorage.getItem("currentLevel"); + if (currentLevelInfo !== null) { + currentLevelInfo = JSON.parse(currentLevelInfo); + // console.log("LevelID: ", currentLevelInfo["id"]); + + const db = WordRotatorDb.getInstance(); + const levelJson = await db.loadLevel(currentLevelInfo["id"]); + if (levelJson === null) { + return this.nextLevel(); + } + + const level = LevelHelper.inflateLevel(levelJson, this.templateContainer); + level.setStartRotations(currentLevelInfo["rotations"]); + + const self = this; + level.getWonPromise().then(() => { + self.levelWon(level); + }); + + level.createSegments(); + level.setLocks(currentLevelInfo["locks"]); + level.getRootSegment()._updateElement(); + + level.saveAsCurrentLevel(); + + let levelSegment = this.findBy("#level"); + levelSegment.removeAllChildren().appendChild(level.getRootSegment().getElement()); + let scaleHelper = new ScaleHelper(); + this.levelScaler = await scaleHelper.scaleToFull(levelSegment, levelSegment.parentElement, false, false, 2, level.words[0].length * 2, null, 0); + + this.level = level; + return; + } + } + catch (e) { + console.error(e); + } + return this.nextLevel(); + } + + async nextLevel() { + try { + this._siteContent.classList.remove('won'); + this.wonText.style.fontSize = "0"; + + const db = WordRotatorDb.getInstance(); + const nextLevelJson = await db.loadNextLevel([20, 40, 60, 100, 120, 140, 160]); + + if (nextLevelJson === null) { + this.startSite(EndSite); + return; + } + const level = LevelHelper.inflateLevel(nextLevelJson, this.templateContainer); + const self = this; + level.getWonPromise().then(() => { + self.levelWon(level); + }); + + level.createSegments(); + level.getRootSegment()._updateElement(); + + level.saveAsCurrentLevel(); + + let levelSegment = this.findBy("#level"); + levelSegment.removeAllChildren().appendChild(level.getRootSegment().getElement()); + let scaleHelper = new ScaleHelper(); + this.levelScaler = await scaleHelper.scaleToFull(levelSegment, levelSegment.parentElement, false, false, 2, level.words[0].length * 2, null, 0); + + this.level = level; + this.levelCounterAction.innerText = this.levelCounter; + this.levelNumberScaler(); + + this.coinAction.setTitle(Helper.nonNull(localStorage.getItem("coins"), "0")); + this.coinAction.redraw(); + + this.wonParams.aborted = true; + clearTimeout(this.wonParams.coinCounterTimer); + } + catch (e) { + console.error(e); + } + } + + onStart(args) { + let res = super.onStart(args); + + if (this.levelCounterAction) { + + this.levelCounterAction.innerText = this.levelCounter; + this.levelCounterActionContainer.classList.add("visible"); + } + this.levelScaler(); + return res; + } + + onPause(args) { + super.onPause(args); + this.levelCounterActionContainer.classList.remove("visible"); + } + + async levelWon(level) { + try { + const db = WordRotatorDb.getInstance(); + const savePromise = db.saveLevelPlayed(level.getId()); + + this.levelCounter++; + localStorage.setItem("levelCounter", this.levelCounter); + + this._siteContent.classList.add('won'); + localStorage.removeItem("currentLevel"); + + let continueButton = this.findBy("#continue-button"); + continueButton.style.transition = "none"; + continueButton.style.opacity = 0; + + this.coinContainer.removeAllChildren(); + let coinsPerLevel = SystemSettings.get("coinsPerLevel", 5); + let coinsBefore = parseInt(Helper.nonNull(localStorage.getItem("coins"), "0")); + localStorage.setItem("coins", coinsBefore + parseInt(coinsPerLevel)); + + let coinPromise = Promise.all([new Promise((r) => { + setTimeout(() => { + r(continueButton.fadeIn()); + }, 500); + }), this.wonParams.audioPromise]); + + this.wonParams.aborted = false; + + let audio = this.wonParams.audio; + for (let i = 0; i < coinsPerLevel; i++) { + let coinElem = Helper.cloneNode(this.coinTemplate); + this.coinContainer.appendChild(coinElem); + coinPromise = coinPromise.then(() => { + return new Promise(r => { + let timeout = 350; + + if (!this.wonParams.aborted) { + coinElem.fadeIn(timeout / 1000); + if (audio !== null) { + audio.pause(); + audio.currentTime = 0; + audio.play(); + } + + this.wonParams.coinCounterTimer = setTimeout(() => { + this.coinAction.setTitle(coinsBefore++); + this.coinAction.redraw(); + }, timeout / 2); + } + //Always do the next promise for garbage collection + setTimeout(r, timeout); + }) + }); + } + + this.wonTextScaler(); + this.continueButtonScaler(); + this.levelScaler(); + + // coinPromise.then(() => { + // continueButton.fadeIn(); + // }); + await savePromise; + } + catch (e) { + console.error(e); + } + } + + help() { + let cost = SystemSettings.get("costForHelp", 25); + let currentCoins = parseInt(Helper.nonNull(localStorage.getItem("coins"), 0)); + + if (currentCoins >= cost) { + currentCoins -= cost; + localStorage.setItem("coins", currentCoins); + this.coinAction.title = currentCoins; + this.coinAction.redraw(); + + let rotatables = this.level.getRotatableSegments(); + rotatables = rotatables.filter((segment) => { + return (segment.rotation !== 0); + }); + + let index = Math.floor(Math.random() * rotatables.length); + + let segmentToHelp = rotatables[index]; + while (segmentToHelp.rotation !== 0) { + segmentToHelp.rotate(); + } + segmentToHelp.setIsRotatable(false); + this.level.saveAsCurrentLevel(); + } + else { + FlashMessenger.addMessage("not-enough-coins"); + } + } +} + +class MenuSite extends WordRotatorBaseSite { + constructor(siteManager) { + super(siteManager, "html/application/menu.html"); + + this.listener = null; + } + + async onFirstStart() { + super.onFirstStart(); + + let playButton = this.findBy("#play-button"); + playButton.addEventListener("click", () => { + this.startSite(LevelSite); + }); + + this.listener = async () => { + let levelNumber = this.findBy("#level-number"); + levelNumber.innerText = Helper.nonNull(localStorage.getItem("levelCounter"), 1); + + let levelSegment = this.findBy("#level"); + let scaleHelper = new ScaleHelper(); + scaleHelper.scaleToFull(levelSegment, levelSegment.parentElement, false, false, 2, 8, null, false); + + let levelStyle = getComputedStyle(levelSegment); + playButton.style.width = levelStyle.getPropertyValue("width"); + scaleHelper.scaleToFull(playButton.children[0], playButton, null, null, null, null ,null ,false); + + await scaleHelper.scaleTo(0.4, levelNumber.parentElement, levelNumber.parentElement.parentElement, null, null, null, 1 ,null ,false); + scaleHelper.scaleToFull(levelNumber, levelNumber.parentElement, false, false, 8, null, null, false); + }; + + this.listener(); + window.addEventListener("resize", this.listener); + } + + onDestroy() { + window.removeEventListener("resize", this.listener); + super.onDestroy(); + } +} + +class SynchronizeSite extends WordRotatorBaseSite { + + 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.startSite(MenuSite); + this.finish(); + } + + async loadLevels() { + const dateLastSync = Helper.nonNull(localStorage.getItem("date-last-sync"), 0); + const db = WordRotatorDb.getInstance(); + + let newLastSync = null; + let maxRuns = 1; + let levelPromises = []; + for (let run = 0; run < maxRuns; run++) { + let res = await DataManager.load("wordRotator/levels" + DataManager.buildQuery({ + "currentRun": run, + "dateLastSync": dateLastSync + })); + if (!res["success"]) { + FlashMessenger.addMessage("sync-error", null, 6000); + newLastSync = null; + break; + } + res = res["result"]; + newLastSync = Helper.nonNull(newLastSync, res["currentSyncDate"]); + maxRuns = res["maxRuns"]; + + let levels = res["levels"]; + for (let i = 0, n = levels.length; i < n; i++) { + let currentLevel = levels[i]; + levelPromises.push(db.loadLevel(levels[i]["id"]).then(level => { + currentLevel["played"] = (Helper.nonNull(Helper.nonNull(level, {}).played, false)); + return currentLevel; + })); + } + } + let levels = await Promise.all(levelPromises); + await db.saveManyLevels(levels); + + if (newLastSync != null && newLastSync !== "null") + { + localStorage.setItem("date-last-sync", newLastSync); + } + } +} + +class WordRotatorSettingFragment extends LocalStorageSettingsFragment { + constructor(site) { + super(site, "html/application/fragment/settings.html"); + } + + onFirstStart() { + let themeTemplate = this.findBy("#theme-radio-template"); + delete themeTemplate["id"]; + let themeTemplateContainer = themeTemplate.parentNode; + themeTemplateContainer.removeAllChildren(); + + for (let i = 0; i < ThemeManager.themes.length; i++) { + let themeElem = Helper.cloneNode(themeTemplate); + let theme = ThemeManager.themes[i]; + themeElem.appendChild(Translator.makePersistentTranslation(theme._name)); + + let inputElem = themeElem.querySelector("input"); + inputElem.value = theme._className; + + inputElem.addEventListener("change", function() { + if (this.checked){ + ThemeManager.changeCurrentTheme(theme); + } + }); + themeTemplateContainer.appendChild(themeElem); + } + + SettingsManager.getInstance().setSetting("theme", ThemeManager.currentTheme._name); + + this.findBy("#reset-levels").addEventListener("click", () => { + localStorage.removeItem("currentLevel"); + localStorage.removeItem("date-last-sync"); + localStorage.removeItem("levelCounter"); + WordRotatorDb.getInstance().removeAll(WordRotatorDb.OBJECT_STORE.LEVEL); + }); + + return super.onFirstStart(); + } +} + +InitPromise.addPromise(function () { + SettingsSite.addSettingsFragment("settings", WordRotatorSettingFragment); +}); + +let basePath = "/pwa/wordRotator/public/"; +if (window.location.pathname.endsWith("publicTest/")) +{ + basePath = "/pwa/wordRotator/publicTest/"; +} + +SystemSettings.setBasePath(basePath); +Translator.supportedLanguages = ["de", "en"]; +Translator.markTranslations = false; + +applyPolyfills(); + +ThemeManager.addTheme(new Theme('red', '')); +ThemeManager.addTheme(new Theme("blue", "blue")); +ThemeManager.addTheme(new Theme("black", "black")); +ThemeManager.addTheme(new Theme("green", "green")); +ThemeManager.addTheme(new Theme("pink", "pink")); + +ShareManager.addShareButton(new WhatsappShareButton('img/whatsapp.svg')); +ShareManager.addShareButton(new SmsShareButton('img/sms.svg')); +ShareManager.addShareButton(new TelegramShareButton('img/telegram.svg')); +// ShareManager.addShareButton(new CopyShareButton('img/copy.svg')); + +let app = new App(); +// app.addDeepLink("policy", PrivatePolicySite.name); +// app.setAddThemeAction(true); +// app.addDefaultAction(Translator.generateChangeLanguageMenuAction()); + +// bridge für Android +window["ThemeManager"] = ThemeManager; +window["ThemeManager"]["addChangeListener"] = ThemeManager.addChangeListener; +window["app"] = app; +window["app"]["refreshCurrentSite"] = app.refreshCurrentSite; +window["Translator"] = Translator; +window["Translator"]["setLanguage"] = Translator.setLanguage; + +SettingsSite.setTemplate("html/application/setting-template.html"); +// SettingsSite.shouldAddSettingsAction = false; + +RegistrationSite.addAction = false; +LoginSite.addLoginAction = false; + +InitPromise.resolve(app).then(function(){ + SettingsSite.settingsAction.showFor = MenuAction.SHOW_ALWAYS; + + app.start(SynchronizeSite); + Translator.setLanguage("de"); +}); diff --git a/public/js/lang/de.json b/public/js/lang/de.json index b838e09..585973a 100755 --- a/public/js/lang/de.json +++ b/public/js/lang/de.json @@ -1 +1 @@ -{"won":"Gewonnen!","continue":"Weiter","help":"?","not-enough-coins":"Du hast zu wenig Münzen!","sync-error":"Es gab einen Fehler beim Aktualisieren der Level. Bitte stelle sicher, dass du eine aktive Internetverbindung hast und versuche es später erneut.","game-ended":"Oh nein!
Es sieht so aus, als ob du schon alle Level gespielt hast...
Schau später noch einmal rein, evtl gibt es dann neue Level.","Sunday":"Sonntag","Monday":"Montag","Tuesday":"Dienstag","Wednesday":"Mittwoch","Thursday":"Donnerstag","Friday":"Freitag","Saturday":"Samstag","January":"Januar","February":"Februar","March":"März","April":"April","May":"Mai","June":"Juni","July":"Juli","August":"August","September":"September","October":"Oktober","November":"November","December":"Dezember","Sun":"So","Mon":"Mo","Tue":"Di","Wed":"Mi","Thu":"Do","Fri":"Fr","Sat":"Sa","Jan":"Jan","Feb":"Feb","Mar":"Mär","Apr":"Apr","Jun":"Jun","Jul":"Jul","Aug":"Aug","Sep":"Sep","Oct":"Okt","Nov":"Nov","Dec":"Dez","code-not-valid":"Der angegebebe Code ist nicht gültig!","code-activated":"Der Code wurde erfolgreich aktiviert!","current-lang":"DE","en":"Englisch","de":"Deutsch","black":"Schwarz","red":"Rot","blue":"Blau","green":"Grün","pink":"Rosa","cancel-button":"ABBRECHEN","confirm-button":"OK","we-use-cookie-hint":"Diese Seite nutzt Cookies. Durch das weitere Benutzen dieser Seite geben Sie uns das Recht Cookies so zu benutzen, wie es in unserer Datenschutzerklärung steht.","policy-heading":"Datenschutzerklärung","area-of-validity-heading":"Geltungsbereich","area-of-validity":"Diese Datenschutzerklärung klärt Nutzer über die Art, den Umfang und Zwecke der Erhebung und Verwendung personenbezogener Daten durch den verantwortlichen Anbieter Silas Günther, Langenbusch 263b - 42897 Remscheid, matrix[at]silas.link auf dieser Website (im folgenden \"Angebot\") auf.

Die rechtlichen Grundlagen des Datenschutzes finden sich im Bundesdatenschutzgesetz (BDSG) und dem Telemediengesetz (TMG).","logfiles-heading":"Zugriffsdaten / Server-Logfiles","logfiles":"Der Anbieter (beziehungsweise sein Webspace-Provider) erhebt Daten über jeden Zugriff auf das Angebot (so genannte Serverlogfiles). Zu den Zugriffsdaten gehören:

Name der abgerufenen Webseite, Datei, Datum und Uhrzeit des Abrufs, übertragene Datenmenge, Meldung über erfolgreichen Abruf, Browsertyp nebst Version, das Betriebssystem des Nutzers, Referrer URL (die zuvor besuchte Seite), IP-Adresse und der anfragende Provider.

Der Anbieter verwendet die Protokolldaten nur für statistische Auswertungen zum Zweck des Betriebs, der Sicherheit und der Optimierung des Angebotes. Der Anbieter behält sich jedoch vor, die Protokolldaten nachträglich zu überprüfen, wenn aufgrund konkreter Anhaltspunkte der berechtigte Verdacht einer rechtswidrigen Nutzung besteht.","contact-support-heading":"Kontaktaufnahme","contact-support":"Bei der Kontaktaufnahme mit dem Anbieter (zum Beispiel per Post oder E-Mail) werden die Angaben des Nutzers zwecks Bearbeitung der Anfrage sowie für den Fall, dass Anschlussfragen entstehen, gespeichert.","cookies-heading":"Cookies","cookies":"Cookies sind kleine Dateien, die es ermöglichen, auf dem Zugriffsgerät der Nutzer (PC, Smartphone o.ä.) spezifische, auf das Gerät bezogene Informationen zu speichern. Sie dienen zum einem der Benutzerfreundlichkeit von Webseiten und damit den Nutzern (z.B. Speicherung von Logindaten). Zum anderen dienen sie, um die statistische Daten der Webseitennutzung zu erfassen und sie zwecks Verbesserung des Angebotes analysieren zu können. Die Nutzer können auf den Einsatz der Cookies Einfluss nehmen. Die meisten Browser verfügen eine Option mit der das Speichern von Cookies eingeschränkt oder komplett verhindert wird. Allerdings wird darauf hingewiesen, dass die Nutzung und insbesondere der Nutzungskomfort ohne Cookies eingeschränkt werden.

Sie können viele Online-Anzeigen-Cookies von Unternehmen über die US-amerikanische Seite http://www.aboutads.info/choices/ oder die EU-Seite http://www.youronlinechoices.com/uk/your-ad-choices/ verwalten.","google-analytics-heading":"Google Analytics","google-analytics":"Dieses Angebot benutzt Google Analytics, einen Webanalysedienst der Google Inc. („Google“). Google Analytics verwendet sog. „Cookies“, Textdateien, die auf Computer der Nutzer gespeichert werden und die eine Analyse der Benutzung der Website durch sie ermöglichen. Die durch den Cookie erzeugten Informationen über Benutzung dieser Website durch die Nutzer werden in der Regel an einen Server von Google in den USA übertragen und dort gespeichert.

Im Falle der Aktivierung der IP-Anonymisierung auf dieser Webseite, wird die IP-Adresse der Nutzer von Google jedoch innerhalb von Mitgliedstaaten der Europäischen Union oder in anderen Vertragsstaaten des Abkommens über den Europäischen Wirtschaftsraum zuvor gekürzt. Nur in Ausnahmefällen wird die volle IP-Adresse an einen Server von Google in den USA übertragen und dort gekürzt. Die IP-Anonymisierung ist auf dieser Website aktiv. Im Auftrag des Betreibers dieser Website wird Google diese Informationen benutzen, um die Nutzung der Website durch die Nutzer auszuwerten, um Reports über die Websiteaktivitäten zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen gegenüber dem Websitebetreiber zu erbringen.

Die im Rahmen von Google Analytics von Ihrem Browser übermittelte IP-Adresse wird nicht mit anderen Daten von Google zusammengeführt. Die Nutzer können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser-Software verhindern; Dieses Angebot weist die Nutzer jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website vollumfänglich werden nutzen können. Die Nutzer können darüber hinaus die Erfassung der durch das Cookie erzeugten und auf ihre Nutzung der Website bezogenen Daten (inkl. Ihrer IP-Adresse) an Google sowie die Verarbeitung dieser Daten durch Google verhindern, indem sie das unter dem folgenden Link verfügbare Browser-Plugin herunterladen und installieren: http://tools.google.com/dlpage/gaoptout?hl=de.

Weitere Informationen zur Datennutzung zu Werbezwecken durch Google, Einstellungs- und Widerspruchsmöglichkeiten erfahren Sie auf den Webseiten von Google:
https://www.google.com/intl/de/policies/privacy/partners/ („Datennutzung durch Google bei Ihrer Nutzung von Websites oder Apps unserer Partner“),
http://www.google.com/policies/technologies/ads („Datennutzung zu Werbezwecken“),
http://www.google.de/settings/ads („Informationen verwalten, die Google verwendet, um Ihnen Werbung einzublenden“) und
http://www.google.com/ads/preferences/ („Bestimmen Sie, welche Werbung Google Ihnen zeigt“).","edited-hint":"Der generierte Text wurde vom Webseiteninhaber angepasst.","generated-hint":"Erstellt mit Datenschutz-Generator.de von RA Dr. Thomas Schwenke","google-play-services-heading":"Google Play Dienste","google-play-services":"Features wie die Bestenliste und Erfolge benötigen einen Login bei Google Play. Hierfür wird die Identität benötigt, um die entsprechenden Punktzahlen und Erfolge an das jeweilige Google Play-Konto zu knüpfen. Alle anderen Features sind weiterhin auch ohne Login bei Google Play nutzbar. Außerdem kann sich jederzeit in den Einstellungen von Google Play abgemeldet werden.","settings":"Einstellungen","close":"Schließen","other-apps":"Andere Apps","optimistic-locking-dialog":"Deine Änderungen können nicht gespeichert werden! Ein anderer Benutzer hat die Daten bereits verändert. Bitte lade die Daten neu und speichere danach.","optimistic-locking-dialog-title":"Nicht gespeichert!","not-online":"Du bist nicht mit dem Internet verbunden. Bitte überprüfe deine Verbindung.","search":"Suchen...","site":"Seite","HTTP-Exception (403) Forbidden":"Nicht erlaubt!","login":"Login","login-email":"E-Mail","login-password":"Passwort","login-automated-login":"Automatischer Login","login-submit":"Login","logout":"Ausloggen","username-or-password-wrong":"Entweder der Username oder das Passwort stimmt nicht!","login-success":"Willkommen zurück!","logged-out-successfully":"Tschüss!","registration":"Registrieren","registration-username":"Username","registration-email":"E-Mail","registration-password1":"Passwort","registration-password2":"Passwort wiederholen","registration-submit":"Registrieren","registration-success":"Ein Registrierungscode wurde an Ihre E-Mailadresse gesendet.","not-allowed-title":"Nicht erlaubt!","not-allowed":"Du hast keine Berechtigung für diese Seite. Wenn das ein Fehler ist, wende dich bitte an einen Admin.","forgot-password":"Passwort vergessen?","forgot-password-title":"Passwort vergessen","forgot-password-email":"E-Mail","forgot-password-submit":"Absenden","forgot-password-text":"Gib deine E-Mailadresse in das Feld ein. Ist die Adresse registriert, werden wir eine E-Mail mit einem Passwort-Resetcode senden.","no-user-found":"Es gibt keinen Benutzer mit dieser E-Mailadresse","new-password-code-send":"Es wurde ein Reset-Code an deine E-Mailadresse gesendet.","new-password":"Neues Passwort","new-password-password1":"Passwort","new-password-password2":"Passwort wiederholen","new-password-submit":"Passwort setzten","password-updated":"Das Passwort ist geupdated!","user-settings":"E-Mail & Username","user-settings-title":"E-Mail & Username","user-settings-form-username":"Username","user-settings-form-old-email":"Aktuelle E-Mail","user-settings-form-new-email":"Neue E-Mail","user-settings-form-submit":"Speichern","user-data-is-changed":"Die Daten wurden gespeichert.","email-code-send":"Ein Änderungscode wurde an die neue E-Mailadresse gesendet. Sobald der Code aktiviert wurde, werden Ihnen E-Mails an die neue Adresse gesendet.","change-email-new-automated-login":"Wenn die E-Mailadresse geändert wird, muss der automatische Login erneut aktiviert werden!","password-settings":"Passwort","change-password-title":"Passwort","change-password-new-automated-login":"Wenn das Passwort geändert wird, muss der automatische Login erneut aktiviert werden!","change-password-old-password":"Altes Passwort","change-password-new-password1":"Neues Passwort","change-password-new-password2":"Neues Passwort wiederholen","change-password-submit":"Speichern","password-changed":"Das Passwort wurde erfolgreich geändert!","registration-username-empty":"Der Username darf nicht leer sein.","registration-username-wrong-char":"Der Username darf nur aus Buchstaben, Zahlen oder den folgenden Zeichen bestehen: -_.&;()#!?$+\",","registration-username-already-taken":"Der Username ist schon vergeben. Bitte wähle einen anderen.","registration-password-empty":"Das Passwort darf nicht leer sein.","registration-password-short":"Das Passwort muss mindestens 8 Zeichen lang sein.","registration-password-not-identical":"Die Passwörter sind nicht identlisch.","registration-email-empty":"Die Email darf nicht leer sein.","registration-email-not-valid":"Die Emailadresse ist keine gültige Emailadresse.","registration-email-already-taken":"Es gibt bereits einen Account mit der Emailadresse.","change-password-old-password-wrong":"Das Passwort stimmt nicht!","user-roles-heading":"Benutzerrollen","user-roles-list":"Aktuelle Rollen:","available-roles-list":"Verfügbare Rollen:","name":"Name","description":"Beschreibung"} \ No newline at end of file +{"won":"Gewonnen!","continue":"Weiter","help":"?","not-enough-coins":"Du hast zu wenig Münzen!","sync-error":"Es gab einen Fehler beim Aktualisieren der Level. Bitte stelle sicher, dass du eine aktive Internetverbindung hast und versuche es später erneut.","game-ended":"Oh nein!
Es sieht so aus, als ob du schon alle Level gespielt hast...
Schau später noch einmal rein, evtl gibt es dann neue Level.","play":"Spielen!","Sunday":"Sonntag","Monday":"Montag","Tuesday":"Dienstag","Wednesday":"Mittwoch","Thursday":"Donnerstag","Friday":"Freitag","Saturday":"Samstag","January":"Januar","February":"Februar","March":"März","April":"April","May":"Mai","June":"Juni","July":"Juli","August":"August","September":"September","October":"Oktober","November":"November","December":"Dezember","Sun":"So","Mon":"Mo","Tue":"Di","Wed":"Mi","Thu":"Do","Fri":"Fr","Sat":"Sa","Jan":"Jan","Feb":"Feb","Mar":"Mär","Apr":"Apr","Jun":"Jun","Jul":"Jul","Aug":"Aug","Sep":"Sep","Oct":"Okt","Nov":"Nov","Dec":"Dez","code-not-valid":"Der angegebebe Code ist nicht gültig!","code-activated":"Der Code wurde erfolgreich aktiviert!","current-lang":"DE","en":"Englisch","de":"Deutsch","black":"Schwarz","red":"Rot","blue":"Blau","green":"Grün","pink":"Rosa","cancel-button":"ABBRECHEN","confirm-button":"OK","we-use-cookie-hint":"Diese Seite nutzt Cookies. Durch das weitere Benutzen dieser Seite geben Sie uns das Recht Cookies so zu benutzen, wie es in unserer Datenschutzerklärung steht.","policy-heading":"Datenschutzerklärung","area-of-validity-heading":"Geltungsbereich","area-of-validity":"Diese Datenschutzerklärung klärt Nutzer über die Art, den Umfang und Zwecke der Erhebung und Verwendung personenbezogener Daten durch den verantwortlichen Anbieter Silas Günther, Langenbusch 263b - 42897 Remscheid, matrix[at]silas.link auf dieser Website (im folgenden \"Angebot\") auf.

Die rechtlichen Grundlagen des Datenschutzes finden sich im Bundesdatenschutzgesetz (BDSG) und dem Telemediengesetz (TMG).","logfiles-heading":"Zugriffsdaten / Server-Logfiles","logfiles":"Der Anbieter (beziehungsweise sein Webspace-Provider) erhebt Daten über jeden Zugriff auf das Angebot (so genannte Serverlogfiles). Zu den Zugriffsdaten gehören:

Name der abgerufenen Webseite, Datei, Datum und Uhrzeit des Abrufs, übertragene Datenmenge, Meldung über erfolgreichen Abruf, Browsertyp nebst Version, das Betriebssystem des Nutzers, Referrer URL (die zuvor besuchte Seite), IP-Adresse und der anfragende Provider.

Der Anbieter verwendet die Protokolldaten nur für statistische Auswertungen zum Zweck des Betriebs, der Sicherheit und der Optimierung des Angebotes. Der Anbieter behält sich jedoch vor, die Protokolldaten nachträglich zu überprüfen, wenn aufgrund konkreter Anhaltspunkte der berechtigte Verdacht einer rechtswidrigen Nutzung besteht.","contact-support-heading":"Kontaktaufnahme","contact-support":"Bei der Kontaktaufnahme mit dem Anbieter (zum Beispiel per Post oder E-Mail) werden die Angaben des Nutzers zwecks Bearbeitung der Anfrage sowie für den Fall, dass Anschlussfragen entstehen, gespeichert.","cookies-heading":"Cookies","cookies":"Cookies sind kleine Dateien, die es ermöglichen, auf dem Zugriffsgerät der Nutzer (PC, Smartphone o.ä.) spezifische, auf das Gerät bezogene Informationen zu speichern. Sie dienen zum einem der Benutzerfreundlichkeit von Webseiten und damit den Nutzern (z.B. Speicherung von Logindaten). Zum anderen dienen sie, um die statistische Daten der Webseitennutzung zu erfassen und sie zwecks Verbesserung des Angebotes analysieren zu können. Die Nutzer können auf den Einsatz der Cookies Einfluss nehmen. Die meisten Browser verfügen eine Option mit der das Speichern von Cookies eingeschränkt oder komplett verhindert wird. Allerdings wird darauf hingewiesen, dass die Nutzung und insbesondere der Nutzungskomfort ohne Cookies eingeschränkt werden.

Sie können viele Online-Anzeigen-Cookies von Unternehmen über die US-amerikanische Seite http://www.aboutads.info/choices/ oder die EU-Seite http://www.youronlinechoices.com/uk/your-ad-choices/ verwalten.","google-analytics-heading":"Google Analytics","google-analytics":"Dieses Angebot benutzt Google Analytics, einen Webanalysedienst der Google Inc. („Google“). Google Analytics verwendet sog. „Cookies“, Textdateien, die auf Computer der Nutzer gespeichert werden und die eine Analyse der Benutzung der Website durch sie ermöglichen. Die durch den Cookie erzeugten Informationen über Benutzung dieser Website durch die Nutzer werden in der Regel an einen Server von Google in den USA übertragen und dort gespeichert.

Im Falle der Aktivierung der IP-Anonymisierung auf dieser Webseite, wird die IP-Adresse der Nutzer von Google jedoch innerhalb von Mitgliedstaaten der Europäischen Union oder in anderen Vertragsstaaten des Abkommens über den Europäischen Wirtschaftsraum zuvor gekürzt. Nur in Ausnahmefällen wird die volle IP-Adresse an einen Server von Google in den USA übertragen und dort gekürzt. Die IP-Anonymisierung ist auf dieser Website aktiv. Im Auftrag des Betreibers dieser Website wird Google diese Informationen benutzen, um die Nutzung der Website durch die Nutzer auszuwerten, um Reports über die Websiteaktivitäten zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen gegenüber dem Websitebetreiber zu erbringen.

Die im Rahmen von Google Analytics von Ihrem Browser übermittelte IP-Adresse wird nicht mit anderen Daten von Google zusammengeführt. Die Nutzer können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser-Software verhindern; Dieses Angebot weist die Nutzer jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website vollumfänglich werden nutzen können. Die Nutzer können darüber hinaus die Erfassung der durch das Cookie erzeugten und auf ihre Nutzung der Website bezogenen Daten (inkl. Ihrer IP-Adresse) an Google sowie die Verarbeitung dieser Daten durch Google verhindern, indem sie das unter dem folgenden Link verfügbare Browser-Plugin herunterladen und installieren: http://tools.google.com/dlpage/gaoptout?hl=de.

Weitere Informationen zur Datennutzung zu Werbezwecken durch Google, Einstellungs- und Widerspruchsmöglichkeiten erfahren Sie auf den Webseiten von Google:
https://www.google.com/intl/de/policies/privacy/partners/ („Datennutzung durch Google bei Ihrer Nutzung von Websites oder Apps unserer Partner“),
http://www.google.com/policies/technologies/ads („Datennutzung zu Werbezwecken“),
http://www.google.de/settings/ads („Informationen verwalten, die Google verwendet, um Ihnen Werbung einzublenden“) und
http://www.google.com/ads/preferences/ („Bestimmen Sie, welche Werbung Google Ihnen zeigt“).","edited-hint":"Der generierte Text wurde vom Webseiteninhaber angepasst.","generated-hint":"Erstellt mit Datenschutz-Generator.de von RA Dr. Thomas Schwenke","google-play-services-heading":"Google Play Dienste","google-play-services":"Features wie die Bestenliste und Erfolge benötigen einen Login bei Google Play. Hierfür wird die Identität benötigt, um die entsprechenden Punktzahlen und Erfolge an das jeweilige Google Play-Konto zu knüpfen. Alle anderen Features sind weiterhin auch ohne Login bei Google Play nutzbar. Außerdem kann sich jederzeit in den Einstellungen von Google Play abgemeldet werden.","settings":"Einstellungen","close":"Schließen","other-apps":"Andere Apps","optimistic-locking-dialog":"Deine Änderungen können nicht gespeichert werden! Ein anderer Benutzer hat die Daten bereits verändert. Bitte lade die Daten neu und speichere danach.","optimistic-locking-dialog-title":"Nicht gespeichert!","not-online":"Du bist nicht mit dem Internet verbunden. Bitte überprüfe deine Verbindung.","search":"Suchen...","site":"Seite","HTTP-Exception (403) Forbidden":"Nicht erlaubt!","login":"Login","login-email":"E-Mail","login-password":"Passwort","login-automated-login":"Automatischer Login","login-submit":"Login","logout":"Ausloggen","username-or-password-wrong":"Entweder der Username oder das Passwort stimmt nicht!","login-success":"Willkommen zurück!","logged-out-successfully":"Tschüss!","registration":"Registrieren","registration-username":"Username","registration-email":"E-Mail","registration-password1":"Passwort","registration-password2":"Passwort wiederholen","registration-submit":"Registrieren","registration-success":"Ein Registrierungscode wurde an Ihre E-Mailadresse gesendet.","not-allowed-title":"Nicht erlaubt!","not-allowed":"Du hast keine Berechtigung für diese Seite. Wenn das ein Fehler ist, wende dich bitte an einen Admin.","forgot-password":"Passwort vergessen?","forgot-password-title":"Passwort vergessen","forgot-password-email":"E-Mail","forgot-password-submit":"Absenden","forgot-password-text":"Gib deine E-Mailadresse in das Feld ein. Ist die Adresse registriert, werden wir eine E-Mail mit einem Passwort-Resetcode senden.","no-user-found":"Es gibt keinen Benutzer mit dieser E-Mailadresse","new-password-code-send":"Es wurde ein Reset-Code an deine E-Mailadresse gesendet.","new-password":"Neues Passwort","new-password-password1":"Passwort","new-password-password2":"Passwort wiederholen","new-password-submit":"Passwort setzten","password-updated":"Das Passwort ist geupdated!","user-settings":"E-Mail & Username","user-settings-title":"E-Mail & Username","user-settings-form-username":"Username","user-settings-form-old-email":"Aktuelle E-Mail","user-settings-form-new-email":"Neue E-Mail","user-settings-form-submit":"Speichern","user-data-is-changed":"Die Daten wurden gespeichert.","email-code-send":"Ein Änderungscode wurde an die neue E-Mailadresse gesendet. Sobald der Code aktiviert wurde, werden Ihnen E-Mails an die neue Adresse gesendet.","change-email-new-automated-login":"Wenn die E-Mailadresse geändert wird, muss der automatische Login erneut aktiviert werden!","password-settings":"Passwort","change-password-title":"Passwort","change-password-new-automated-login":"Wenn das Passwort geändert wird, muss der automatische Login erneut aktiviert werden!","change-password-old-password":"Altes Passwort","change-password-new-password1":"Neues Passwort","change-password-new-password2":"Neues Passwort wiederholen","change-password-submit":"Speichern","password-changed":"Das Passwort wurde erfolgreich geändert!","registration-username-empty":"Der Username darf nicht leer sein.","registration-username-wrong-char":"Der Username darf nur aus Buchstaben, Zahlen oder den folgenden Zeichen bestehen: -_.&;()#!?$+\",","registration-username-already-taken":"Der Username ist schon vergeben. Bitte wähle einen anderen.","registration-password-empty":"Das Passwort darf nicht leer sein.","registration-password-short":"Das Passwort muss mindestens 8 Zeichen lang sein.","registration-password-not-identical":"Die Passwörter sind nicht identlisch.","registration-email-empty":"Die Email darf nicht leer sein.","registration-email-not-valid":"Die Emailadresse ist keine gültige Emailadresse.","registration-email-already-taken":"Es gibt bereits einen Account mit der Emailadresse.","change-password-old-password-wrong":"Das Passwort stimmt nicht!","user-roles-heading":"Benutzerrollen","user-roles-list":"Aktuelle Rollen:","available-roles-list":"Verfügbare Rollen:","name":"Name","description":"Beschreibung"} \ No newline at end of file diff --git a/src/module/Application/pwa/html/application/menu.html b/src/module/Application/pwa/html/application/menu.html index aad7b61..cb1f4ac 100644 --- a/src/module/Application/pwa/html/application/menu.html +++ b/src/module/Application/pwa/html/application/menu.html @@ -1,77 +1,86 @@
- WordRotator -
-
-
+ +
+
+
-
-
W
+
+
+
+
W
+
+
+
O
+
+
+
+
R
+
+
+
 
+
+
-
-
O
+
+
+
+
R
+
+
+
D
+
+
+
+
 
+
+
+
 
+
+

-
-
R
+
+
+
+
O
+
+
+
 
+
+
+
+
T
+
+
+
A
+
+
-
-
 
-
-
-
-
-
-
-
R
-
-
-
D
-
-
-
-
 
-
-
-
 
-
-
-
-
-
-
-
-
O
-
-
-
 
-
-
-
-
T
-
-
-
A
-
-
-
-
-
-
-
 
-
-
-
R
-
-
-
-
T
-
-
-
O
+
+
+
+
 
+
+
+
R
+
+
+
+
T
+
+
+
O
+
+
+ + 999 + +
+
+
-
\ No newline at end of file diff --git a/src/module/Application/pwa/js/site/MenuSite.js b/src/module/Application/pwa/js/site/MenuSite.js index 0b04e26..5263c93 100644 --- a/src/module/Application/pwa/js/site/MenuSite.js +++ b/src/module/Application/pwa/js/site/MenuSite.js @@ -1,15 +1,45 @@ import {WordRotatorBaseSite} from "./WordRotatorBaseSite"; import {LevelSite} from "./LevelSite"; +import {ScaleHelper} from "../../../../../js/lib/pwa-assets"; +import {Helper} from "../../../../../js/lib/pwa-lib"; -export class MenuSite extends WordRotatorBaseSite{ +export class MenuSite extends WordRotatorBaseSite { constructor(siteManager) { super(siteManager, "html/application/menu.html"); + + this.listener = null; } - onFirstStart() { + async onFirstStart() { super.onFirstStart(); - this.findBy("#play-button").addEventListener("click", () => { + + let playButton = this.findBy("#play-button"); + playButton.addEventListener("click", () => { this.startSite(LevelSite); - }) + }); + + this.listener = async () => { + let levelNumber = this.findBy("#level-number"); + levelNumber.innerText = Helper.nonNull(localStorage.getItem("levelCounter"), 1); + + let levelSegment = this.findBy("#level"); + let scaleHelper = new ScaleHelper(); + scaleHelper.scaleToFull(levelSegment, levelSegment.parentElement, false, false, 2, 8, null, false); + + let levelStyle = getComputedStyle(levelSegment); + playButton.style.width = levelStyle.getPropertyValue("width"); + scaleHelper.scaleToFull(playButton.children[0], playButton, null, null, null, null ,null ,false); + + await scaleHelper.scaleTo(0.4, levelNumber.parentElement, levelNumber.parentElement.parentElement, null, null, null, 1 ,null ,false); + scaleHelper.scaleToFull(levelNumber, levelNumber.parentElement, false, false, 8, null, null, false); + }; + + this.listener(); + window.addEventListener("resize", this.listener); + } + + onDestroy() { + window.removeEventListener("resize", this.listener); + super.onDestroy(); } } \ No newline at end of file diff --git a/src/module/Application/pwa/translations/de.json b/src/module/Application/pwa/translations/de.json index 954e95b..3667585 100755 --- a/src/module/Application/pwa/translations/de.json +++ b/src/module/Application/pwa/translations/de.json @@ -6,5 +6,7 @@ "not-enough-coins":"Du hast zu wenig Münzen!", "sync-error":"Es gab einen Fehler beim Aktualisieren der Level. Bitte stelle sicher, dass du eine aktive Internetverbindung hast und versuche es später erneut.", - "game-ended":"Oh nein!
Es sieht so aus, als ob du schon alle Level gespielt hast...
Schau später noch einmal rein, evtl gibt es dann neue Level." + "game-ended":"Oh nein!
Es sieht so aus, als ob du schon alle Level gespielt hast...
Schau später noch einmal rein, evtl gibt es dann neue Level.", + + "play":"Spielen!" } \ No newline at end of file diff --git a/src/scss/wordRotator.scss b/src/scss/wordRotator.scss index 6b9e5a6..2b4e99e 100755 --- a/src/scss/wordRotator.scss +++ b/src/scss/wordRotator.scss @@ -17,6 +17,7 @@ nav.top-bar.title-bar { } #level-number-container { + z-index: 1; transition: none; position: absolute; left: 50%; @@ -34,6 +35,17 @@ nav.top-bar.title-bar { &.visible { visibility: visible; } + &.in-main-menu{ + background: white; + border-color: black; + + height: 1em; + width: 1em; + min-height: 1em; + min-width: 1em; + max-height:1em; + max-width:1em; + } #level-number { transition: none;