From e8809285e0fb2e694270bcaf5bbf9e6ff50aa679 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Tue, 18 Sep 2018 01:37:59 +0300 Subject: [PATCH 1/2] Clean up classes before exiting them --- public/index.html | 2 +- public/src/css/animations.css | 58 ----- public/src/css/loadsong.css | 42 ++-- public/src/css/main.css | 357 +++++++++++++----------------- public/src/css/songselect.css | 235 +++++++++++--------- public/src/css/titlescreen.css | 80 +++---- public/src/js/assets.js | 209 ++++++++--------- public/src/js/controller.js | 71 +++--- public/src/js/game.js | 29 ++- public/src/js/keyboard.js | 279 +++++++++++------------ public/src/js/loader.js | 114 ++++++---- public/src/js/loadsong.js | 68 +++--- public/src/js/p2.js | 147 ++++++------ public/src/js/pageevents.js | 115 ++++++++++ public/src/js/scoresheet.js | 20 +- public/src/js/songselect.js | 325 ++++++++++++--------------- public/src/js/soundbuffer.js | 22 +- public/src/js/titlescreen.js | 75 ++----- public/src/js/tutorial.js | 36 +-- public/src/js/view.js | 37 +++- public/src/views/loader.html | 6 +- public/src/views/loadsong.html | 10 +- public/src/views/songselect.html | 7 +- public/src/views/titlescreen.html | 8 +- server.py | 3 + 25 files changed, 1183 insertions(+), 1172 deletions(-) delete mode 100644 public/src/css/animations.css create mode 100644 public/src/js/pageevents.js diff --git a/public/index.html b/public/index.html index 6c35a2f..5d452c6 100644 --- a/public/index.html +++ b/public/index.html @@ -22,7 +22,6 @@ - @@ -47,6 +46,7 @@ + diff --git a/public/src/css/animations.css b/public/src/css/animations.css deleted file mode 100644 index 82dce8a..0000000 --- a/public/src/css/animations.css +++ /dev/null @@ -1,58 +0,0 @@ -@keyframes don-normal { -0%{background-position-y:0px} -6.35%{background-position-y:-184px} -7.94%{background-position-y:-368px} -9.52%{background-position-y:-552px} -11.11%{background-position-y:-736px} -12.7%{background-position-y:-920px} -14.29%{background-position-y:-1104px} -15.87%{background-position-y:-1104px} -17.46%{background-position-y:-920px} -19.05%{background-position-y:-736px} -20.63%{background-position-y:-552px} -22.22%{background-position-y:-368px} -23.81%{background-position-y:-184px} -25.4%{background-position-y:0px} -31.75%{background-position-y:-184px} -33.33%{background-position-y:-368px} -34.92%{background-position-y:-552px} -36.51%{background-position-y:-736px} -38.1%{background-position-y:-920px} -39.68%{background-position-y:-1104px} -41.27%{background-position-y:-1104px} -42.86%{background-position-y:-920px} -44.44%{background-position-y:-736px} -46.03%{background-position-y:-552px} -47.62%{background-position-y:-368px} -49.21%{background-position-y:-184px} -50.79%{background-position-y:0px} -57.14%{background-position-y:-184px} -58.73%{background-position-y:-368px} -60.32%{background-position-y:-552px} -61.9%{background-position-y:-736px} -63.49%{background-position-y:-920px} -65.08%{background-position-y:-1104px} -66.67%{background-position-y:-1104px} -68.25%{background-position-y:-920px} -69.84%{background-position-y:-1288px} -71.43%{background-position-y:-1472px} -73.02%{background-position-y:-1656px} -74.6%{background-position-y:-1840px} -76.19%{background-position-y:-2024px} -77.78%{background-position-y:-2024px} -79.37%{background-position-y:-2024px} -80.95%{background-position-y:-2024px} -82.54%{background-position-y:-1840px} -84.13%{background-position-y:-1656px} -85.71%{background-position-y:-1472px} -87.3%{background-position-y:-1288px} -88.89%{background-position-y:-2392px} -90.48%{background-position-y:-2208px} -92.06%{background-position-y:-2208px} -93.65%{background-position-y:-2392px} -95.24%{background-position-y:-2576px} -96.83%{background-position-y:-2760px} -98.41%{background-position-y:-2944px} -100%{background-position-y:-3128px} -} - diff --git a/public/src/css/loadsong.css b/public/src/css/loadsong.css index a726880..78e368d 100644 --- a/public/src/css/loadsong.css +++ b/public/src/css/loadsong.css @@ -1,31 +1,31 @@ #load-song{ width: 100%; height: 100%; - margin:0; - padding: 0%; } - #loading-song{ - width:20%; - height:30%; position: absolute; - top:35%; - left:40%; - background: rgba(0,0,0,0.75); + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 20vw; + height: 15vw; + background: rgba(0, 0, 0, 0.75); border-radius: 5px; - border:3px solid white; + border: 3px solid white; + color: #fff; } - #loading-don{ - position: relative; - width:50%; - height:65%; - top: 12%; - left: 30%; + width: 50%; +} +.loading-text{ + position: relative; + font-size: 1.5vw; + text-align: center; + z-index: 1; } - -#loading-song p{ - position: absolute; - left:28%; - font-size: 3vmin; -} \ No newline at end of file diff --git a/public/src/css/main.css b/public/src/css/main.css index 064fc54..405920a 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -1,229 +1,190 @@ -@font-face { - font-family: 'TnT'; - src: url('../../assets/fonts/TnT.ttf') format('truetype'); +@font-face{ + font-family: TnT; + src: url("/assets/fonts/TnT.ttf") format("truetype"); } - -@font-face { - font-family: 'Kozuka'; - src: url('../../assets/fonts/KozGoPro-Bold.otf') format('truetype'); +@font-face{ + font-family: Kozuka; + src: url("/assets/fonts/KozGoPro-Bold.otf") format("truetype"); } - -html, body{ - padding: 0; +html, +body{ margin: 0; - width:100%; + width: 100%; height: 100%; - background: black; - color:white; - user-select: none; + background: #fe7839; + user-select: none; } - #screen{ - width:100%; - height:100%; - margin:0; - padding:0; - background: url('/assets/img/bg-pattern-1.png') top center; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + background: #fe7839 url("/assets/img/bg-pattern-1.png") top center; + font-family: TnT; } - #assets{ - display:none; + display: none; } - .window{ - width: 60vmin; - height: 23vmin; - padding: 3vmin; - color: black; - background: rgba(255, 220, 47, 0.95); - border: .5vmin outset #f4ae00; - box-shadow: 2px 2px 10px black; - margin: auto; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: flex; - flex-direction: column; - justify-content: space-between; - + width: 60vmin; + height: 23vmin; + padding: 3vmin; + color: black; + background: rgba(255, 220, 47, 0.95); + border: .5vmin outset #f4ae00; + box-shadow: 2px 2px 10px black; + margin: auto; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + } - -.stroke-main { - font-weight: 300; +.stroke-main{ + font-weight: 300; } - -.result-title { - margin-top: 9px !important; - margin-left: 5px !important; - z-index: 1; +.result-title{ + margin-top: 9px !important; + margin-left: 5px !important; + z-index: 1; } - -.result-song, .game-song { - position: absolute; - right: 0; - font-size: 5vmin; - margin: 3vmin 3vmin 0px 0px; - color: white; - float: right; - z-index: 1; - font-weight: 300; +.result-song, +.game-song{ + position: absolute; + right: 0; + font-size: 5vmin; + margin: 3vmin 3vmin 0px 0px; + color: white; + float: right; + z-index: 1; + font-weight: 300; } - -.stroke-main:before { - content: attr(alt); - left: 0; - z-index: -1; - position: absolute; - -webkit-text-stroke: 0.3em #fb3c0c; +.stroke-main::before{ + content: attr(alt); + left: 0; + z-index: -1; + position: absolute; + -webkit-text-stroke: 0.3em #fb3c0c; } - -.stroke-main:after { - content: attr(alt); - left: 0; - z-index: -2; - position: absolute; - -webkit-text-stroke: 0.5em #000; +.stroke-main::after{ + content: attr(alt); + left: 0; + z-index: -2; + position: absolute; + -webkit-text-stroke: 0.5em #000; } - -.stroke-sub:before { - content: attr(alt); - position: absolute; - -webkit-text-stroke: 0.25em #000; - left: 0; - z-index: -1; +.stroke-sub::before{ + content: attr(alt); + position: absolute; + -webkit-text-stroke: 0.25em #000; + left: 0; + z-index: -1; } - -.songsel-title { - position: absolute; - z-index: 1; - font-size: 7vmin; - margin: 20px; +.don{ + background-position-y: 0; + position: absolute; + top: 0px; } - -.click-to-continue:before { - width: 100%; +.alpha-title .song-title-char{ + transform: scale(1.3, 1); + font-size: 80%; + line-height: 22px; } - - -.don { - background-position-y: 0; - position: absolute; - top: 0px; +.song-title-apos{ + padding-left: 4px; } - -.alpha-title .song-title-char { - transform: scale(1.3, 1); - font-size: 80%; - line-height: 22px; +.song-title-char[alt="ぁ"], +.song-title-char[alt="ぃ"], +.song-title-char[alt="ぅ"], +.song-title-char[alt="ぇ"], +.song-title-char[alt="ぉ"], +.song-title-char[alt="ゃ"], +.song-title-char[alt="ゅ"], +.song-title-char[alt="ょ"], +.song-title-char[alt="っ"], +.song-title-char[alt="ァ"], +.song-title-char[alt="ィ"], +.song-title-char[alt="ゥ"], +.song-title-char[alt="ェ"], +.song-title-char[alt="ォ"], +.song-title-char[alt="ャ"], +.song-title-char[alt="ュ"], +.song-title-char[alt="ョ"], +.song-title-char[alt="ッ"]{ + margin-top: -6px; } - -.song-title-apos { - padding-left: 4px; +.song-title-char[alt="ー"], +.song-title-char[alt="-"]{ + transform: rotate(95deg); + font-size: 90%; } - -.song-title-char[alt="ぁ"],.song-title-char[alt="ぃ"],.song-title-char[alt="ぅ"],.song-title-char[alt="ぇ"],.song-title-char[alt="ぉ"], -.song-title-char[alt="ゃ"],.song-title-char[alt="ゅ"],.song-title-char[alt="ょ"],.song-title-char[alt="っ"], -.song-title-char[alt="ァ"],.song-title-char[alt="ィ"],.song-title-char[alt="ゥ"],.song-title-char[alt="ェ"],.song-title-char[alt="ォ"], -.song-title-char[alt="ャ"],.song-title-char[alt="ュ"],.song-title-char[alt="ョ"],.song-title-char[alt="ッ"] -{ - margin-top: -6px; +#tutorial-outer{ + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + position: absolute; + width: 100%; + height: 100%; } - -.song-title-char[alt="ー"], .song-title-char[alt="-"] { - transform: rotate(95deg); - font-size: 90%; +#tutorial{ + background: rgb(246, 234, 212); + color: black; + border: 5px black solid; + border-radius: 10px; + height: 65%; + width: 50%; + padding: 20px; + font-size: 16pt; + position: relative; } - - -#tutorial-outer { - display: flex; - justify-content: center; - align-items: center; - overflow: hidden; - position: absolute; - width: 100%; - height: 100%; +#tutorial-title{ + z-index: 1; + position: absolute; + color: white; + top: -25px; + font-size: 26pt; } - -#tutorial { - background: rgb(246, 234, 212); - color: black; - border: 5px black solid; - border-radius: 10px; - height: 65%; - width: 50%; - padding: 20px; - font-size: 16pt; - position: relative; +#tutorial-content{ + padding: 15px 30px; } - -#tutorial-title { - z-index: 1; - position: absolute; - color: white; - top: -25px; - font-size: 26pt; +kbd{ + font-family: inherit; + padding: 0.1em 0.6em; + border: 1px solid #ccc; + font-size: 13px; + background-color: #f7f7f7; + color: #333; + box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; + border-radius: 3px; + display: inline-block; + text-shadow: 0 1px 0 #fff; + line-height: 1.4; + white-space: nowrap; } - -#tutorial-content { - padding: 15px 30px; +.taibtn{ + bottom: 15px; + margin: 0 auto; + position: absolute; + right: 15px; + padding: 10px 40px; + border-radius: 15px; + border: 3px rgba(218, 205, 178, 1) solid; + cursor: pointer; } - -kbd { - font-family: inherit; - padding: 0.1em 0.6em; - border: 1px solid #ccc; - font-size: 13px; - background-color: #f7f7f7; - color: #333; - -moz-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2),0 0 0 2px #ffffff inset; - -webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; - box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; - display: inline-block; - text-shadow: 0 1px 0 #fff; - line-height: 1.4; - white-space: nowrap; +.taibtn:hover{ + z-index: 1; + color: white; + background: rgb(255, 181, 71); + border-color: white; } - -.taibtn { - bottom: 15px; - margin: 0 auto; - position: absolute; - right: 15px; - padding: 10px 40px; - border-radius: 15px; - border: 3px rgba(218, 205, 178, 1) solid; - cursor: pointer; +.taibtn::before{ + padding: 0 40px; } - -.taibtn:hover { - z-index: 1; - color: white; - background: rgb(255, 181, 71); - border-color: white; +#tutorial-end-button{ + font-size: 22pt; } - -.taibtn:before { - padding: 0 40px; -} - -#tutorial-end-button { - font-size: 22pt; -} - -#songsel-help { - float: right; - background: rgba(255, 255, 255, 0.5); - color: black; - padding: 15px; - margin: 10px; - font-size: 18px; - border: 3px black solid; - border-radius: 50px; - cursor: pointer; -} \ No newline at end of file diff --git a/public/src/css/songselect.css b/public/src/css/songselect.css index 81a8298..6addc3f 100644 --- a/public/src/css/songselect.css +++ b/public/src/css/songselect.css @@ -1,139 +1,174 @@ -@-webkit-keyframes bgscroll { - from {background-position:0 0;} - to {background-position:-200px 0;} +@-webkit-keyframes bgscroll{ + from{ + background-position: 0 0; + } + to{ + background-position: -200px 0; + } } - -@keyframes bgscroll { - from {background-position:0 0;} - to {background-position:-200px 0;} +@keyframes bgscroll{ + from{ + background-position: 0 0; + } + to{ + background-position: -200px 0; + } } - #song-select{ width: 100%; - height:100%; - background: url('/assets/img/bg-pattern-1.png'); + height: 100%; + background: url("/assets/img/bg-pattern-1.png"); animation: bgscroll 3s infinite linear; - -webkit-animation: bgscroll 3s infinite linear; + white-space: nowrap; } - #song-container{ - width:98%; - height:80%; + width: 98%; + height: 80%; padding: 5% 1% 1% 1%; - text-align: center; + text-align: center; } - ul li{ - list-style:none; + list-style: none; } - .difficulties{ - float:left; - display:inline-block; - width:70%; - height: 100%; + position: absolute; + left: 0; + display: block; + width: 303px; + height: 100%; + opacity: 0; + transition: opacity 0.1s; } - -.song-title-char { - text-align: center; - width: 45px; - display: block; +.song.opened .difficulties{ + opacity: 1; + transition: opacity 0.1s 0.2s; } - -.song-title-char:before { - content: attr(alt); - position: absolute; - -webkit-text-stroke: 0.25em #000; - z-index: -1; +.song-title-char{ + text-align: center; + width: 45px; + display: block; +} +.song-title-char::before{ + content: attr(alt); + position: absolute; + -webkit-text-stroke: 0.25em #000; + z-index: -1; } - .song-title{ - float: right; - width: 45px; - padding: 10px 2px; - word-wrap: break-word; - font-size: 22pt; - color: white; - position: relative; - z-index: 1; - line-height: 28px; + float: right; + width: 45px; + height: 100%; + padding: 10px 2px; + word-wrap: break-word; + font-size: 22pt; + color: white; + position: relative; + z-index: 1; + line-height: 28px; } - -.song-title-space { - line-height: 25px; +.song-title-space{ + line-height: 25px; } - .song{ - font-size: 14pt; - width: 50px; - margin-right:15px; - height:100%; - color: black; - display: inline-block; - background: rgba(255, 220, 47, 0.90); - border: 7px outset #f4ae00; - box-shadow: 2px 2px 10px black; - overflow: hidden; + font-size: 14pt; + width: 50px; + margin-right: 15px; + height: 100%; + color: black; + display: inline-block; + background: rgba(255, 220, 47, 0.90); + border: 7px outset #f4ae00; + box-shadow: 2px 2px 10px black; + overflow: hidden; cursor: pointer; position: relative; + transition: width 0.3s; +} +.song:not(.opened):hover{ + background: rgba(255, 233, 125, 0.90); } - .opened{ - width:375px; + width: 375px; } - .difficulty{ - display:none; - cursor:pointer; - width: 35px; - height: 70%; - border-radius: 5px; - display: inline-block; - margin: 5px; - float: left; - background:white; - border:10px solid #ae7a26; - position:relative; + display: none; + cursor: pointer; + width: 35px; + height: 70%; + border-radius: 5px; + display: inline-block; + margin: 5px; + float: left; + background: white; + border: 10px solid #ae7a26; + position: relative; } - .difficulty .diffname{ - word-wrap: break-word; - width: 20px; - display: block; - margin: auto; - margin-top:10px; - font-size: 20pt; - margin-left: 6px; + word-wrap: break-word; + width: 20px; + display: block; + margin: auto; + margin-top: 10px; + font-size: 20pt; + margin-left: 6px; + white-space: normal; } - .difficulty .stars{ - position:absolute; - color: #f12b69; - margin-left: -17px; - width:100%; - bottom:10px; + position: absolute; + color: #f12b69; + margin-left: -17px; + width: 100%; + bottom: 10px; } - .difficulty:hover{ - border-color:#fa5d3a; - color:white; - background:#0c6577; + border-color: #fa5d3a; + color: white; + background: #0c6577; } - .difficulty:hover .diffname{ - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: black; + -webkit-text-stroke-width: 1px; + -webkit-text-stroke-color: black; } - .difficulty:hover .stars{ - color:white; + color: white; } - .song.p2:not(.opened)::after, .difficulty.p2::after{ - content:"P2"; - display:block; - position:absolute; - bottom:0; - width:100%; + content: "P2"; + display: block; + position: absolute; + bottom: 0; + width: 100%; +} +#songsel-help{ + float: right; + background: rgba(255, 255, 255, 0.5); + color: black; + padding: 15px; + margin: 10px; + font-size: 18px; + border: 3px black solid; + border-radius: 50px; + cursor: pointer; +} +.songsel-title-song, +.songsel-title-difficulty{ + position: absolute; + left: -300px; + opacity: 0; + margin: 20px; + color: #fff; + font-size: 7vmin; + z-index: 1; + transition: left 0s 0.2s, opacity 0.2s; +} +#song-select.difficulty-select .songsel-title-difficulty{ + left: 0; + opacity: 1; + transition: left 0.4s 0.2s, opacity 0.4s 0.2s; +} +#song-select:not(.difficulty-select) .songsel-title-song{ + left: 0; + opacity: 1; + transition: left 0.4s 0.2s, opacity 0.4s 0.2s; } diff --git a/public/src/css/titlescreen.css b/public/src/css/titlescreen.css index 4da86c8..95ef9b0 100644 --- a/public/src/css/titlescreen.css +++ b/public/src/css/titlescreen.css @@ -1,51 +1,39 @@ -@keyframes toggleFade { - - 0%{ - opacity:1; - } - 50% { - opacity: 0; - } +@keyframes toggleFade{ + 40%{ + opacity: 1; + } + 70%{ + opacity: 0.2; + } } - - #title-screen{ - position:absolute; - top:0; - left:0; - width:100%; - height:100%; - display: none; - margin:0px; - cursor: pointer; - background: url('/assets/img/title-screen.png'); - -webkit-background-size: cover; /* pour Chrome et Safari */ - -moz-background-size: cover; /* pour Firefox */ - -o-background-size: cover; /* pour Opera */ - background-size: cover; /* version standardis�e */ + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + background: #1389f0 url("/assets/img/title-screen.png") no-repeat center; + background-size: cover; + cursor: pointer; } - -#logo-big-cont{ - position:absolute; - max-width: 654px; - max-height: 300px; +.logo-big{ + width: 90vmin; + height: auto; } - -#logo-big-cont img{ - width:100%; - height:100%; -} - .click-to-continue{ - - display:block; - font-size: 8vmin; - color:white; - text-align: center; - position:absolute; - bottom:2%; - width:100%; - animation: toggleFade 1s infinite ease-out; - z-index: 1; - -} \ No newline at end of file + position:absolute; + bottom: 10%; + color: #fff; + font-size: 8vmin; + text-align: center; + z-index: 1; + animation: toggleFade 2s infinite ease-in-out; +} +.click-to-continue::before{ + -webkit-text-stroke: 0.25em #f00; + filter: blur(0.3vmin); + left: auto; +} diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 6ddc3d0..cb91c81 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -1,106 +1,109 @@ var assets = { - - img: [ - 'background.png', - 'title-screen.png', - 'logo-big.png', - 'don-0.png', - 'don-1.png', - 'big-don-0.png', - 'big-don-1.png', - 'taiko.png', - 'taiko-key-blue.png', - 'taiko-key-red.png', - 'hp-bar-bg.png', - 'hp-bar-colour.png', - 'score-0.png', - 'score-0-b.png', - 'score-230.png', - 'score-450.png', - 'dancing-don.gif', - 'scoresheet.jpg', - 'bg-pattern-1.png', - 'bg-pattern-2.png', - 'ranking-S.png', - 'ranking-X.png', - 'muzu_easy.png', - 'muzu_normal.png', - 'muzu_hard.png', - 'muzu_oni.png', - 'don_anim_normal.png', - 'don_anim_10combo.png', - 'balloon.png' + "img": [ + "background.png", + "title-screen.png", + "logo-big.png", + "don-0.png", + "don-1.png", + "big-don-0.png", + "big-don-1.png", + "taiko.png", + "taiko-key-blue.png", + "taiko-key-red.png", + "hp-bar-bg.png", + "hp-bar-colour.png", + "score-0.png", + "score-0-b.png", + "score-230.png", + "score-450.png", + "dancing-don.gif", + "scoresheet.jpg", + "bg-pattern-1.png", + "bg-pattern-2.png", + "ranking-S.png", + "ranking-X.png", + "muzu_easy.png", + "muzu_normal.png", + "muzu_hard.png", + "muzu_oni.png", + "don_anim_normal.png", + "don_anim_10combo.png", + "balloon.png" + ], + "audioSfx": [ + "start.wav", + "don.wav", + "ka.wav", + + "combo-50.wav", + "combo-100.wav", + "combo-200.wav", + "combo-300.wav", + "combo-400.wav", + "combo-500.wav", + "combo-600.wav", + "combo-700.wav", + "combo-800.wav", + "combo-900.wav", + "combo-1000.wav", + "combo-1100.wav", + "combo-1200.wav", + "combo-1300.wav", + "combo-1400.wav", + "fullcombo.wav", + + "combo-50-meka.wav", + "combo-100-meka.wav", + "combo-200-meka.wav", + "combo-300-meka.wav", + "combo-400-meka.wav", + "combo-500-meka.wav", + "combo-600-meka.wav", + "combo-700-meka.wav", + "combo-800-meka.wav", + "combo-900-meka.wav", + "combo-1000-meka.wav", + "combo-1100-meka.wav", + "combo-1200-meka.wav", + "combo-1300-meka.wav", + "combo-1400-meka.wav", + "fullcombo-meka.wav", + + "song-select.wav", + "title.ogg", + "pause.wav", + "cancel.wav", + "results.wav", + "diffsel.wav", + + "gamefullcombo.wav", + "gameclear.wav", + "gamefail.wav", + + "note_don.ogg", + "note_ka.ogg", + "balloon.ogg" + ], + "audioMusic": [ + "bgm_songsel.ogg", + "bgm_result.ogg", + "bgm_setsume.ogg" + ], + "fonts": [ + "Kozuka", + "TnT" + ], + "views": [ + "game.html", + "loadsong.html", + "scoresheet.html", + "songselect.html", + "titlescreen.html", + "tutorial.html" ], - audioSfx: [ - 'start.wav', - 'don.wav', - 'ka.wav', - - 'combo-50.wav', - 'combo-100.wav', - 'combo-200.wav', - 'combo-300.wav', - 'combo-400.wav', - 'combo-500.wav', - 'combo-600.wav', - 'combo-700.wav', - 'combo-800.wav', - 'combo-900.wav', - 'combo-1000.wav', - 'combo-1100.wav', - 'combo-1200.wav', - 'combo-1300.wav', - 'combo-1400.wav', - 'fullcombo.wav', - - 'combo-50-meka.wav', - 'combo-100-meka.wav', - 'combo-200-meka.wav', - 'combo-300-meka.wav', - 'combo-400-meka.wav', - 'combo-500-meka.wav', - 'combo-600-meka.wav', - 'combo-700-meka.wav', - 'combo-800-meka.wav', - 'combo-900-meka.wav', - 'combo-1000-meka.wav', - 'combo-1100-meka.wav', - 'combo-1200-meka.wav', - 'combo-1300-meka.wav', - 'combo-1400-meka.wav', - 'fullcombo-meka.wav', - - 'song-select.wav', - 'title.ogg', - 'pause.wav', - 'cancel.wav', - 'results.wav', - 'diffsel.wav', - - 'gamefullcombo.wav', - 'gameclear.wav', - 'gamefail.wav', - - 'note_don.ogg', - 'note_ka.ogg', - 'balloon.ogg' - ], - - audioMusic:[ - 'bgm_songsel.ogg', - 'bgm_result.ogg', - 'bgm_setsume.ogg' - ], - - songs: [], - - fonts: [ - 'Kozuka', - 'TnT' - ], - - sounds: {}, - image: {} - -}; \ No newline at end of file + "songs": [], + "sounds": {}, + "image": {}, + "pages": {} +} diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 2414dc2..613b308 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -4,7 +4,6 @@ class Controller{ this.songData = songData this.autoPlayEnabled = autoPlayEnabled this.multiplayer = multiplayer - this.pauseMenu = false var backgroundURL = "/songs/" + this.selectedSong.folder + "/bg.png" var songParser = new ParseSong(songData) @@ -40,16 +39,19 @@ class Controller{ } } loadUIEvents(){ - $("#song-selection-butt").click(() => { - assets.sounds["don"].play() - this.songSelection() + this.continueBtn = document.getElementById("song-selection-butt") + this.restartBtn = document.getElementById("song-selection-butt") + this.songSelBtn = document.getElementById("song-selection-butt") + pageEvents.add(this.continueBtn, "click", () => { + this.togglePauseMenu() }) - $("#restart-butt").click(() => { + pageEvents.add(this.restartBtn, "click", () => { assets.sounds["don"].play() this.restartSong() }) - $("#continue-butt").click(() => { - this.togglePauseMenu() + pageEvents.add(this.songSelBtn, "click", () => { + assets.sounds["don"].play() + this.songSelection() }) } startMainLoop(){ @@ -66,7 +68,7 @@ class Controller{ } mainLoop(){ if(this.mainLoopRunning){ - if(this.multiplayer != 2){ + if(this.multiplayer !== 2){ requestAnimationFrame(() => { if(this.syncWith){ this.syncWith.game.elapsedTime.ms = this.game.elapsedTime.ms @@ -87,6 +89,9 @@ class Controller{ } if(this.mainLoopStarted){ this.game.update() + if(!this.mainLoopRunning){ + return + } this.game.playMainMusic() } this.view.refresh() @@ -99,10 +104,10 @@ class Controller{ this.togglePause() this.view.togglePauseMenu() } - displayResults(){ + gameEnded(){ var score = this.getGlobalScore() var vp - if(score.fail == 0){ + if(score.fail === 0){ vp = "fullcombo" this.playSoundMeka("fullcombo", 1.350) }else if(score.hp >= 50){ @@ -111,33 +116,29 @@ class Controller{ vp = "fail" } assets.sounds["game" + vp].play() - setTimeout(() => { - if(this.mainLoopRunning){ - this.stopMainLoop() - if(this.multiplayer != 2){ - new Scoresheet(this, this.getGlobalScore(), this.multiplayer) - } - } - }, 7000) + } + displayResults(){ + this.clean() + if(this.multiplayer !== 2){ + new Scoresheet(this, this.getGlobalScore(), this.multiplayer) + } } displayScore(score, notPlayed){ this.view.displayScore(score, notPlayed) } songSelection(){ - $("#music-bg").remove() - this.stopMainLoop() + this.clean() new SongSelect() } restartSong(){ - this.stopMainLoop() - $("#screen").load("/src/views/game.html", () => { - if(this.multiplayer){ - new loadSong(this.selectedSong, false, true) - }else{ - var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) - taikoGame.run() - } - }) + this.clean() + if(this.multiplayer){ + new loadSong(this.selectedSong, false, true) + }else{ + loader.changePage("game") + var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) + taikoGame.run() + } } playSoundMeka(soundID, time){ var meka = "" @@ -195,4 +196,16 @@ class Controller{ this.mekadon.play(circle) } } + clean(){ + this.stopMainLoop() + this.keyboard.clean() + this.view.clean() + + pageEvents.remove(this.continueBtn, "click") + delete this.continueBtn + pageEvents.remove(this.restartBtn, "click") + delete this.restartBtn + pageEvents.remove(this.songSelBtn, "click") + delete this.songSelBtn + } } diff --git a/public/src/js/game.js b/public/src/js/game.js index 7d660dd..d879ce2 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -219,27 +219,32 @@ class Game{ whenLastCirclePlayed(){ var circles = this.songData.circles var lastCircle = circles[this.songData.circles.length - 1] - if(!this.fadeOutStarted && this.getElapsedTime().ms >= lastCircle.getEndTime() + 1900){ - this.fadeOutStarted=this.getElapsedTime().ms + var ms = this.getElapsedTime().ms + if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 1900){ + this.fadeOutStarted = ms } } whenFadeoutMusic(){ - if(this.fadeOutStarted){ - if(this.musicFadeOut==0){ + var started = this.fadeOutStarted + if(started){ + var ms = this.getElapsedTime().ms + if(this.musicFadeOut === 0){ snd.musicGain.fadeOut(1.6) - if(this.controller.multiplayer == 1){ + if(this.controller.multiplayer === 1){ p2.send("gameresults", this.controller.getGlobalScore()) } this.musicFadeOut++ - } - if(this.musicFadeOut == 1 && this.getElapsedTime().ms >= this.fadeOutStarted + 1600){ - this.controller.displayResults() + }else if(this.musicFadeOut === 1 && ms >= started + 1600){ + this.controller.gameEnded() this.mainAsset.stop() p2.send("gameend") - setTimeout(() => { - snd.musicGain.fadeIn() - snd.musicGain.unmute() - }, 1000) + this.musicFadeOut++ + }else if(this.musicFadeOut === 2 && ms >= started + 2600){ + snd.musicGain.fadeIn() + snd.musicGain.unmute() + this.musicFadeOut++ + }else if(this.musicFadeOut === 3 && ms >= started + 8600){ + this.controller.displayResults() this.musicFadeOut++ } } diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js index ee3ebe2..23fc160 100644 --- a/public/src/js/keyboard.js +++ b/public/src/js/keyboard.js @@ -1,145 +1,134 @@ -function Keyboard(controller){ - - var _kbd = { - "don_l": 86, // V - "don_r": 66, // B - "ka_l": 67, // C - "ka_r": 78, // N - "pause": 81, // Q - "back": 8 // Backspace - } - var _this = this; - var _keys = {}; - var _waitKeyupScore = {}; - var _waitKeyupSound = {}; - var _waitKeyupMenu = {}; - var _keyTime = { - "don": -Infinity, - "ka": -Infinity - } - - this.getBindings = function(){ - return _kbd - } - - var _gamepad = new Gamepad(this) - - $(document).keydown(function(e){ - - if (e.which === 8 && !$(e.target).is("input, textarea")) - // Disable back navigation when pressing backspace - e.preventDefault(); - - if(_this.buttonEnabled(e.which)){ - _this.setKey(e.which, true); - } - }); - - $(document).keyup(function(e){ - if(_this.buttonEnabled(e.which)){ - _this.setKey(e.which, false); - } - }); - - this.buttonEnabled = function(keyCode){ - if(controller.autoPlayEnabled){ - switch(keyCode){ - case _kbd["don_l"]: - case _kbd["don_r"]: - case _kbd["ka_l"]: - case _kbd["ka_r"]: - return false - } - } - return true - } - - this.checkGameKeys = function(){ - if(!controller.autoPlayEnabled){ - _gamepad.play() - } - _this.checkKeySound(_kbd["don_l"], "don") - _this.checkKeySound(_kbd["don_r"], "don") - _this.checkKeySound(_kbd["ka_l"], "ka") - _this.checkKeySound(_kbd["ka_r"], "ka") - } - - this.checkMenuKeys = function(){ - if(!controller.multiplayer){ - _gamepad.play(1) - _this.checkKey(_kbd["pause"], "menu", function(){ - controller.togglePauseMenu(); - }) - } - if(controller.multiplayer != 2){ - _this.checkKey(_kbd["back"], "menu", function(){ - if(controller.multiplayer == 1){ - p2.send("gameend") - } - controller.togglePause(); - controller.songSelection(); - }) - } - } - - this.checkKey = function(keyCode, keyup, callback){ - if(_keys[keyCode] && !_this.isWaitingForKeyup(keyCode, keyup)){ - _this.waitForKeyup(keyCode, keyup); - callback() - } - } - - this.checkKeySound = function(keyCode, sound){ - _this.checkKey(keyCode, "sound", function(){ - var circles = controller.parsedSongData.circles - var circle = circles[controller.game.getCurrentCircle()] - if( - (keyCode == _kbd["don_l"] || keyCode == _kbd["don_r"]) - && circle - && !circle.getPlayed() - && circle.getStatus() != -1 - && circle.getType() == "balloon" - && circle.requiredHits - circle.timesHit <= 1 - ){ - assets.sounds["balloon"].play() - }else{ - assets.sounds["note_"+sound].play() - } - _keyTime[sound] = controller.getElapsedTime().ms - }) - } - - this.getKeys = function(){ - return _keys; - } - - this.setKey=function(keyCode, down){ - if(down){ - _keys[keyCode]=true; - }else{ - delete _keys[keyCode]; - delete _waitKeyupScore[keyCode]; - delete _waitKeyupSound[keyCode]; - delete _waitKeyupMenu[keyCode]; - } - } - - this.isWaitingForKeyup = function(key, type){ - var isWaiting; - if(type == "score") isWaiting = _waitKeyupScore[key]; - else if(type == "sound") isWaiting = _waitKeyupSound[key]; - else if(type == "menu") isWaiting = _waitKeyupMenu[key]; - return isWaiting; - } - - this.waitForKeyup = function(key, type){ - if(type == "score") _waitKeyupScore[key] = true; - else if(type == "sound") _waitKeyupSound[key] = true; - else if(type == "menu") _waitKeyupMenu[key] = true; - } - - this.getKeyTime = function(){ - return _keyTime; - } - -} \ No newline at end of file +class Keyboard{ + constructor(controller){ + this.controller = controller + this.kbd = { + "don_l": 86, // V + "don_r": 66, // B + "ka_l": 67, // C + "ka_r": 78, // N + "pause": 81, // Q + "back": 8 // Backspace + } + this.keys = {} + this.waitKeyupScore = {} + this.waitKeyupSound = {} + this.waitKeyupMenu = {} + this.keyTime = { + "don": -Infinity, + "ka": -Infinity + } + this.gamepad = new Gamepad(this) + pageEvents.keyAdd(this, "all", "both", event => { + if (event.keyCode === 8){ + // Disable back navigation when pressing backspace + event.preventDefault() + } + if(this.buttonEnabled(event.keyCode)){ + this.setKey(event.keyCode, event.type === "keydown") + } + }) + } + getBindings(){ + return this.kbd + } + buttonEnabled(keyCode){ + if(this.controller.autoPlayEnabled){ + switch(keyCode){ + case this.kbd["don_l"]: + case this.kbd["don_r"]: + case this.kbd["ka_l"]: + case this.kbd["ka_r"]: + return false + } + } + return true + } + checkGameKeys(){ + if(!this.controller.autoPlayEnabled){ + this.gamepad.play() + } + this.checkKeySound(this.kbd["don_l"], "don") + this.checkKeySound(this.kbd["don_r"], "don") + this.checkKeySound(this.kbd["ka_l"], "ka") + this.checkKeySound(this.kbd["ka_r"], "ka") + } + checkMenuKeys(){ + if(!this.controller.multiplayer){ + this.gamepad.play(true) + this.checkKey(this.kbd["pause"], "menu", () => { + this.controller.togglePauseMenu() + }) + } + if(this.controller.multiplayer !== 2){ + this.checkKey(this.kbd["back"], "menu", () => { + if(this.controller.multiplayer === 1){ + p2.send("gameend") + } + this.controller.togglePause() + this.controller.songSelection() + }) + } + } + checkKey(keyCode, keyup, callback){ + if(this.keys[keyCode] && !this.isWaitingForKeyup(keyCode, keyup)){ + this.waitForKeyup(keyCode, keyup) + callback() + } + } + checkKeySound(keyCode, sound){ + this.checkKey(keyCode, "sound", () => { + var circles = this.controller.parsedSongData.circles + var circle = circles[this.controller.game.getCurrentCircle()] + if( + (keyCode === this.kbd["don_l"] || keyCode === this.kbd["don_r"]) + && circle + && !circle.getPlayed() + && circle.getStatus() !== -1 + && circle.getType() === "balloon" + && circle.requiredHits - circle.timesHit <= 1 + ){ + assets.sounds["balloon"].play() + }else{ + assets.sounds["note_" + sound].play() + } + this.keyTime[sound] = this.controller.getElapsedTime().ms + }) + } + getKeys(){ + return this.keys + } + setKey(keyCode, down){ + if(down){ + this.keys[keyCode] = true + }else{ + delete this.keys[keyCode] + delete this.waitKeyupScore[keyCode] + delete this.waitKeyupSound[keyCode] + delete this.waitKeyupMenu[keyCode] + } + } + isWaitingForKeyup(key, type){ + if(type === "score"){ + return this.waitKeyupScore[key] + }else if(type === "sound"){ + return this.waitKeyupSound[key] + }else if(type === "menu"){ + return this.waitKeyupMenu[key] + } + } + waitForKeyup(key, type){ + if(type === "score"){ + this.waitKeyupScore[key] = true + }else if(type === "sound"){ + this.waitKeyupSound[key] = true + }else if(type === "menu"){ + this.waitKeyupMenu[key] = true + } + } + getKeyTime(){ + return this.keyTime + } + clean(){ + pageEvents.keyRemove(this, "all") + } +} diff --git a/public/src/js/loader.js b/public/src/js/loader.js index deb91aa..4633fe9 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -1,15 +1,15 @@ class Loader{ constructor(){ this.loadedAssets = 0 - this.errorCount = 0 this.assetsDiv = document.getElementById("assets") - this.promises = [] - $("#screen").load("/src/views/loader.html", () => { - this.run() - }) + this.ajax("src/views/loader.html").then(this.run.bind(this)) } - run(){ + run(page){ + this.promises = [] + this.screen = document.getElementById("screen") + this.screen.innerHTML = page this.loaderPercentage = document.querySelector("#loader .percentage") + this.loaderProgress = document.querySelector("#loader .progress") assets.fonts.forEach(name => { var font = document.createElement("h1") @@ -20,11 +20,13 @@ class Loader{ FontDetect.onFontLoaded(name, resolve, reject, {msTimeout: 90000}) })) }) + var fontDetectDiv = document.getElementById("fontdetectHelper") + fontDetectDiv.parentNode.removeChild(fontDetectDiv) assets.img.forEach(name => { - var id = name.substr(0, name.length - 4) + var id = this.getFilename(name) var image = document.createElement("img") - this.promises.push(promiseLoad(image)) + this.promises.push(pageEvents.load(image)) image.id = name image.src = "/assets/img/" + name this.assetsDiv.appendChild(image) @@ -39,68 +41,82 @@ class Loader{ snd.previewGain.setVolume(0.5) assets.audioSfx.forEach(name => { - var id = name.substr(0, name.length-4) - this.promises.push(snd.sfxGain.load("/assets/audio/" + name).then(sound => { - assets.sounds[id] = sound - })) + this.promises.push(this.loadSound(name, snd.sfxGain)) }) assets.audioMusic.forEach(name => { - var id = name.substr(0, name.length-4) - this.promises.push(snd.musicGain.load("/assets/audio/" + name).then(sound => { - assets.sounds[id] = sound - })) + this.promises.push(this.loadSound(name, snd.musicGain)) }) p2 = new P2Connection() - this.promises.push(ajax("/api/songs").then(songs => { + this.promises.push(this.ajax("/api/songs").then(songs => { assets.songs = JSON.parse(songs) })) + assets.views.forEach(name => { + var id = this.getFilename(name) + this.promises.push(this.ajax("src/views/" + name).then(page => { + assets.pages[id] = page + })) + }) + this.promises.forEach(promise => { - promise.then(() => { - this.assetLoaded() - }, () => { - this.errorMsg() - }) + promise.then(this.assetLoaded.bind(this)) }) Promise.all(this.promises).then(() => { + this.clean() new Titlescreen() + }, this.errorMsg.bind(this)) + } + loadSound(name, gain){ + var id = this.getFilename(name) + return gain.load("/assets/audio/" + name).then(sound => { + assets.sounds[id] = sound }) } + getFilename(name){ + return name.slice(0, name.lastIndexOf(".")) + } errorMsg(){ - if(this.errorCount == 0){ - this.loaderPercentage.appendChild(document.createElement("br")) - this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh")) - } - this.errorCount++ + this.error = true + this.loaderPercentage.appendChild(document.createElement("br")) + this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh")) + this.clean() } assetLoaded(){ - this.loadedAssets++ - var percentage = parseInt(this.loadedAssets * 100 / this.promises.length) - document.querySelector("#loader .progress").style.width = percentage + "%" - this.loaderPercentage.firstChild.data = percentage + "%" + if(!this.error){ + this.loadedAssets++ + var percentage = Math.floor(this.loadedAssets * 100 / this.promises.length) + this.loaderProgress.style.width = percentage + "%" + this.loaderPercentage.firstChild.data = percentage + "%" + } + } + changePage(name){ + document.getElementById("screen").innerHTML = assets.pages[name] + } + ajax(url, customRequest){ + return new Promise((resolve, reject) => { + var request = new XMLHttpRequest() + request.open("GET", url) + pageEvents.load(request).then(() => { + resolve(request.response) + }, reject) + if(customRequest){ + customRequest(request) + } + request.send() + }) + } + clean(){ + delete this.assetsDiv + delete this.loaderPercentage + delete this.loaderProgress + delete this.promises } } -function ajax(url){ - return new Promise((resolve, reject) => { - var request = new XMLHttpRequest() - request.open("GET", url) - promiseLoad(request).then(() => { - resolve(request.response) - }, reject) - request.send() - }) -} -function promiseLoad(asset){ - return new Promise((resolve, reject) => { - asset.addEventListener("load", resolve) - asset.addEventListener("error", reject) - asset.addEventListener("abort", reject) - }) -} +var pageEvents = new PageEvents() +var loader = new Loader() var snd = {} var p2 -new Loader() diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index af8f3e3..8a6f925 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -5,9 +5,8 @@ class loadSong{ this.autoPlayEnabled = autoPlayEnabled this.diff = this.selectedSong.difficulty.slice(0, -4) this.songFilePath = "/songs/" + this.selectedSong.folder + "/" + this.selectedSong.difficulty - $("#screen").load("/src/views/loadsong.html", () => { - this.run() - }) + loader.changePage("loadsong") + this.run() } run(){ var id = this.selectedSong.folder @@ -15,7 +14,7 @@ class loadSong{ assets.sounds["start"].play() var img = document.createElement("img") - promises.push(promiseLoad(img)) + promises.push(pageEvents.load(img)) img.id = "music-bg" img.src = "/songs/" + id + "/bg.png" document.getElementById("assets").appendChild(img) @@ -37,15 +36,11 @@ class loadSong{ }, reject) } })) - - promises.push(ajax(this.songFilePath).then(data => { + promises.push(loader.ajax(this.songFilePath).then(data => { this.songData = data.replace(/\0/g, "").split("\n") })) - Promise.all(promises).then(() => { - $("#screen").load("/src/views/game.html", () => { - this.setupMultiplayer() - }) + this.setupMultiplayer() }, error => { console.error(error) alert("An error occurred, please refresh") @@ -53,37 +48,50 @@ class loadSong{ } setupMultiplayer(){ if(this.multiplayer){ + var loadingText = document.getElementsByClassName("loading-text")[0] + var waitingText = "Waiting for Another Player..." + loadingText.firstChild.data = waitingText + loadingText.setAttribute("alt", waitingText) + this.song2Data = this.songData this.selectedSong2 = this.selectedSong - p2.onmessage("gamestart", () => { - var taikoGame1 = new Controller(this.selectedSong, this.songData, false, 1) - var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2) - taikoGame1.run(taikoGame2) - }, true) - p2.onmessage("gameload", response => { - if(response == this.diff){ - p2.send("gamestart") - }else{ - this.selectedSong2 = { - title: this.selectedSong.title, - folder: this.selectedSong.folder, - difficulty: response + ".osu" + pageEvents.add(p2, "message", event => { + if(event.type === "gameload"){ + if(event.value === this.diff){ + p2.send("gamestart") + }else{ + this.selectedSong2 = { + title: this.selectedSong.title, + folder: this.selectedSong.folder, + difficulty: event.value + ".osu" + } + loader.ajax("/songs/" + this.selectedSong2.folder + "/" + this.selectedSong2.difficulty).then(data => { + this.song2Data = data.replace(/\0/g, "").split("\n") + p2.send("gamestart") + }, () => { + p2.send("gamestart") + }) } - ajax("/songs/" + this.selectedSong2.folder + "/" + this.selectedSong2.difficulty).then(data => { - this.song2Data = data.replace(/\0/g, "").split("\n") - p2.send("gamestart") - }, () => { - p2.send("gamestart") - }) + }else if(event.type === "gamestart"){ + this.clean() + loader.changePage("game") + var taikoGame1 = new Controller(this.selectedSong, this.songData, false, 1) + var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2) + taikoGame1.run(taikoGame2) } - }, true) + }) p2.send("join", { id: this.selectedSong.folder, diff: this.diff }) }else{ + this.clean() + loader.changePage("game") var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled) taikoGame.run() } } + clean(){ + pageEvents.remove(p2, "message") + } } diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 205cb0d..9160510 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -2,128 +2,119 @@ class P2Connection{ constructor(){ this.closed = true this.lastMessages = {} - this.msgCallbacks = {} - this.closeCallbacks = new Set() - this.openCallbacks = new Set() this.otherConnected = false - this.onmessage("gamestart", () => { - this.otherConnected = true - this.notes = [] - this.drumrollPace = 45 - this.results = false - }) - this.onmessage("gameend", () => { - this.otherConnected = false - }) - this.onmessage("gameresults", response => { - this.results = response - }) - this.onmessage("note", response => { - this.notes.push(response) - }) - this.onmessage("drumroll", response => { - this.drumrollPace = response.pace - }) + this.allEvents = new Map() + this.addEventListener("message", this.message.bind(this)) + } + addEventListener(type, callback){ + var addedType = this.allEvents.get(type) + if(!addedType){ + addedType = new Set() + this.allEvents.set(type, addedType) + } + return addedType.add(callback) + } + removeEventListener(type, callback){ + var addedType = this.allEvents.get(type) + if(addedType){ + return addedType.delete(callback) + } } open(){ this.closed = false var wsProtocol = location.protocol == "https:" ? "wss:" : "ws:" this.socket = new WebSocket(wsProtocol + "//" + location.host + "/p2") - var events = ["open", "close", "message"] - events.forEach(eventName => { - this.socket.addEventListener(eventName, event => { - this[eventName + "Event"](event) - }) - }) - } - openEvent(event){ - this.openCallbacks.forEach(obj => { - obj.callback() - if(obj.once){ - this.openCallbacks.delete(obj) + pageEvents.race(this.socket, "open", "close", listener =>{ + if(listener === "open"){ + return this.openEvent() } + return this.closeEvent() }) + pageEvents.add(this.socket, "message", this.messageEvent.bind(this)) } - onopen(callback, once){ - this.openCallbacks.add({ - callback: callback, - once: once - }) + openEvent(){ + var addedType = this.allEvents.get("open") + if(addedType){ + addedType.forEach(callback => callback()) + } } close(){ this.closed = true this.socket.close() } - closeEvent(event){ + closeEvent(){ + this.removeEventListener(onmessage) + this.otherConnected = false if(!this.closed){ setTimeout(() => { - if(this.socket.readyState != this.socket.OPEN){ + if(this.socket.readyState !== this.socket.OPEN){ this.open() } }, 500) } - this.closeCallbacks.forEach(obj => { - obj.callback() - if(obj.once){ - this.closeCallbacks.delete(obj) - } - }) - } - onclose(callback, once){ - this.closeCallbacks.add({ - callback: callback, - once: once - }) + var addedType = this.allEvents.get("close") + if(addedType){ + addedType.forEach(callback => callback()) + } } send(type, value){ - if(this.socket.readyState == this.socket.OPEN){ - if(typeof value == "undefined"){ + if(this.socket.readyState === this.socket.OPEN){ + if(typeof value === "undefined"){ this.socket.send(JSON.stringify({type: type})) }else{ this.socket.send(JSON.stringify({type: type, value: value})) } }else{ - this.onopen(() => { + pageEvents.once(this, "open").then(() => { this.send(type, value) - }, true) + }) } } messageEvent(event){ try{ - var data = JSON.parse(event.data) + var response = JSON.parse(event.data) }catch(e){ - var data = {} + var response = {} } - this.lastMessages[data.type] = data.value - if(this.msgCallbacks[data.type]){ - this.msgCallbacks[data.type].forEach(obj => { - obj.callback(data.value) - if(obj.once){ - this.msgCallbacks[data.type].delete(obj) - } - }) + this.lastMessages[response.type] = response.value + var addedType = this.allEvents.get("message") + if(addedType){ + addedType.forEach(callback => callback(response)) } } - onmessage(type, callback, once){ - if(!(type in this.msgCallbacks)){ - this.msgCallbacks[type] = new Set() - } - this.msgCallbacks[type].add({ - callback: callback, - once: once - }) - } getMessage(type, callback){ if(type in this.lastMessages){ - callback(this.lastMessages[type]) + return this.lastMessages[type] + } + } + message(response){ + switch(response.type){ + case "gamestart": + this.otherConnected = true + this.notes = [] + this.drumrollPace = 45 + this.results = false + break + case "gameend": + this.otherConnected = false + break + case "gameresults": + this.results = response.value + break + case "note": + this.notes.push(response.value) + break + case "drumroll": + this.drumrollPace = response.value.pace + break } } play(circle, mekadon){ if(this.otherConnected || this.notes.length > 0){ var type = circle.getType() - if(type == "balloon"|| type == "drumroll" || type == "daiDrumroll"){ + if(type === "balloon"|| type === "drumroll" || type === "daiDrumroll"){ mekadon.playDrumrollAt(circle, 0, this.drumrollPace) - }else if(this.notes.length == 0){ + }else if(this.notes.length === 0){ mekadon.play(circle) }else{ var note = this.notes[0] diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js new file mode 100644 index 0000000..1847f1c --- /dev/null +++ b/public/src/js/pageevents.js @@ -0,0 +1,115 @@ +class PageEvents{ + constructor(){ + this.allEvents = new Map() + this.keyListeners = new Map() + this.add(window, "keydown", this.keyEvent.bind(this)) + this.add(window, "keyup", this.keyEvent.bind(this)) + } + add(target, type, callback){ + this.remove(target, type) + var addedEvent = this.allEvents.get(target) + if(!addedEvent){ + addedEvent = new Map() + this.allEvents.set(target, addedEvent) + } + addedEvent.set(type, callback) + return target.addEventListener(type, callback) + } + remove(target, type){ + var addedEvent = this.allEvents.get(target) + if(addedEvent){ + var callback = addedEvent.get(type) + if(callback){ + target.removeEventListener(type, callback) + addedEvent.delete(type) + if(addedEvent.size == 0){ + return this.allEvents.delete(target) + } + } + } + } + once(target, type){ + return new Promise(resolve => { + this.add(target, type, event => { + this.remove(target, type) + return resolve(event) + }) + }) + } + race(){ + var target = arguments[0] + return new Promise(resolve => { + for(var i = 1;i < arguments.length; i++){ + let type = arguments[i] + this.add(target, type, event => { + resolve({ + type: type, + event: event + }) + }) + } + }).then(response => { + for(var i = 1;i < arguments.length; i++){ + this.remove(target, arguments[i]) + } + return response + }) + } + load(target){ + return new Promise((resolve, reject) => { + this.race(target, "load", "error", "abort").then(response => { + if(response.type === "load"){ + return resolve(response.event) + } + return reject() + }) + }) + } + keyEvent(event){ + this.keyListeners.forEach(addedKeyCode => { + this.checkListener(addedKeyCode.get("all"), event) + this.checkListener(addedKeyCode.get(event.keyCode), event) + }) + } + checkListener(keyObj, event){ + if(keyObj && ( + keyObj.type === "both" + || keyObj.type === "down" && event.type === "keydown" + || keyObj.type === "up" && event.type === "up" + )){ + keyObj.callback(event) + } + } + keyAdd(target, keyCode, type, callback){ + // keyCode="all", type="both" + var addedKeyCode = this.keyListeners.get(target) + if(!addedKeyCode){ + addedKeyCode = new Map() + this.keyListeners.set(target, addedKeyCode) + } + addedKeyCode.set(keyCode, { + type: type, + callback: callback + }) + } + keyRemove(target, keyCode){ + var addedKeyCode = this.keyListeners.get(target) + if(addedKeyCode){ + var keyObj = addedKeyCode.get(keyCode) + if(keyObj){ + addedKeyCode.delete(keyCode) + if(addedKeyCode.size == 0){ + return this.keyListeners.delete(target) + } + } + } + } + keyOnce(target, keyCode, type){ + return new Promise(resolve => { + this.keyAdd(target, keyCode, type, event => { + this.keyRemove(target, keyCode) + return resolve(event) + }) + }) + } +} diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 766f2a9..79b9bf8 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -3,9 +3,8 @@ class Scoresheet{ this.controller = controller this.score = score this.multiplayer = multiplayer - $("#screen").load("/src/views/scoresheet.html", () =>{ - this.run() - }) + loader.changePage("scoresheet") + this.run() } setResults(score, scoreCont){ this.positionning(scoreCont) @@ -36,7 +35,7 @@ class Scoresheet{ this.altText(this.elem("max-combo", scoreCont), score.maxCombo) this.altText(this.elem("nb-drumroll", scoreCont), score.drumroll) - addEventListener("resize", () => { + pageEvents.add(window, "resize", () => { this.positionning(scoreCont) }) } @@ -82,17 +81,16 @@ class Scoresheet{ this.setResults(this.score, scoreCont) this.altText(this.elem("result-song", this.scoresheet), this.score.song) - this.elem("song-select", this.scoresheet).addEventListener("click", () => { + pageEvents.once(this.elem("song-select", this.scoresheet), "click").then(() => { + this.clean() assets.sounds["don"].play() - assets.sounds["bgm_result"].stop() this.controller.songSelection() }) - this.elem("replay", this.scoresheet).addEventListener("click", () => { + pageEvents.once(this.elem("replay", this.scoresheet), "click").then(() => { + this.clean() assets.sounds["don"].play() - assets.sounds["bgm_result"].stop() this.controller.restartSong() }) - if(this.multiplayer && p2.results){ var scoreCont2 = document.createElement("div") scoreCont2.classList.add("score-cont") @@ -101,4 +99,8 @@ class Scoresheet{ this.setResults(p2.results, scoreCont2) } } + clean(){ + assets.sounds["bgm_result"].stop() + pageEvents.remove(window, "resize") + } } diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 4832901..9c87356 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -1,202 +1,153 @@ -function SongSelect(){ - var _this=this; - var _songs; - var _selectedSong = {title:'', folder:'', difficulty:''}; - var _preview; - var _preview_id = 0 - var _diffNames={ - easy:"かんたん", - normal:"ふつう", - hard:"むずかしい", - oni:"おに" +class SongSelect{ + constructor(){ + this.songs + this.selectedSong = { + "title": "", + "folder": "", + "difficulty": "" + } + this.previewId = 0 + this.diffNames={ + "easy": "かんたん", + "normal": "ふつう", + "hard": "むずかしい", + "oni": "おに" + } + loader.changePage("songselect") + this.run() } - - this.startPreview = function(id, prvtime, first_open=true) { - _this.endPreview(); + startPreview(id, prvtime, switchedTo){ + this.endPreview() var startLoad = +new Date - var current_id = _preview_id - if(first_open){ + var currentId = this.previewId + if(!switchedTo){ snd.musicGain.fadeOut(0.4) } - var songObj - assets.songs.forEach(song => { - if(song.id == id){ - songObj = song - } - }) + var songObj = assets.songs.find(song => song.id == id) if(songObj.sound){ - _preview = songObj.sound - _preview.gain = snd.previewGain - this.previewLoaded(startLoad, prvtime, first_open) + this.preview = songObj.sound + this.preview.gain = snd.previewGain + this.previewLoaded(startLoad, prvtime, switchedTo) }else{ snd.previewGain.load("/songs/" + id + "/main.mp3").then(sound => { - if(current_id == _preview_id){ + if(currentId == this.previewId){ songObj.sound = sound - _preview = sound - this.previewLoaded(startLoad, prvtime, first_open) + this.preview = sound + this.previewLoaded(startLoad, prvtime, switchedTo) } }) } - }; - - this.previewLoaded = function(startLoad, prvtime, first_open){ + } + previewLoaded(startLoad, prvtime, switchedTo){ var endLoad = +new Date var difference = endLoad - startLoad - var minDelay = first_open ? 1000 : 300 + var minDelay = switchedTo ? 300 : 1000 var delay = minDelay - Math.min(minDelay, difference) - _preview.playLoop(delay / 1000, false, prvtime / 1000) + this.preview.playLoop(delay / 1000, false, prvtime / 1000) } - - this.endPreview = function() { - _preview_id++ - if (_preview) { - _preview.stop(); - }; - }; - - this.run = function(){ - _this.createCode(); - _this.startP2(); + endPreview() { + this.previewId++ + if(this.preview){ + this.preview.stop() + } + } + run(){ + this.createCode() + this.startP2() - $("#song-container").show(); + this.songselHelp = document.getElementById("songsel-help") + pageEvents.once(this.songselHelp, "click").then(() => { + this.clean() + assets.sounds["don"].play() + new Tutorial() + }) + this.diffElements = document.getElementsByClassName("difficulty") + for(let difficulty of this.diffElements){ + pageEvents.once(difficulty, "click").then(this.onDifficulty.bind(this)) + } + this.songElements = document.getElementsByClassName("song") + for(let song of this.songElements){ + pageEvents.add(song, "click", this.onSong.bind(this)) + } + this.songSelect = document.getElementById("song-select") + } + onDifficulty(event){ + this.clean() + var target = event.currentTarget + var song = target.parentNode.parentNode + assets.sounds["don"].play() - $('#songsel-help').click(function(){ - assets.sounds["bgm_songsel"].stop() + this.selectedSong.difficulty = target.classList[1] + ".osu" + this.selectedSong.title = song.dataset.title + this.selectedSong.folder = song.dataset.songId + + new loadSong(this.selectedSong, event.shiftKey, event.ctrlKey) + } + onSong(event){ + var target = event.currentTarget + var opened = document.getElementsByClassName("opened")[0] + if(!opened){ + this.startPreview(target.dataset.songId, target.dataset.preview) + assets.sounds["don"].play() assets.sounds["song-select"].stop() + assets.sounds["diffsel"].play(0.3) + target.classList.add("opened") + this.songSelect.classList.add("difficulty-select") + }else if(opened == target){ + this.endPreview() + snd.musicGain.fadeIn(0.4) assets.sounds["diffsel"].stop() - assets.sounds["don"].play() - snd.musicGain.fadeIn() - _this.endPreview(); - - new Tutorial(); - }); - - $(".difficulty").click(function(e){ - _this.endPreview(); - assets.sounds["bgm_songsel"].stop() - assets.sounds["diffsel"].stop() - assets.sounds["don"].play() - - var difficultyElement = (e.target.className=="stars" || e.target.className=="diffname") ? e.target.parentElement : e.target; - _selectedSong.difficulty = difficultyElement.classList[1]+'.osu'; - var parentID = $(this).parent().closest(".song").attr("id"); - var songID = parseInt(parentID.substr(5, parentID.length-1)); - _selectedSong.title = $(this).parent().closest('.song').data('title'); - _selectedSong.folder = songID; - - snd.musicGain.fadeIn() - new loadSong(_selectedSong, e.shiftKey, e.ctrlKey); - }); - - $(".song").hover(function(){ - if(!$(this).hasClass("opened")) - $(this).css("background", "rgba(255, 233, 125, 0.90)"); - }, - function(){ - if(!$(this).hasClass("opened")) - $(this).css("background", "rgba(255, 220, 47, 0.90)"); - }); - - $(".song").click(function(e){ - if (!$(e.target).parents('.difficulties').length) { - if ($(".opened").length && $(".opened").attr('id') == $(this).attr('id')) { - _this.endPreview(); - snd.musicGain.fadeIn(0.4) - assets.sounds["diffsel"].stop() - assets.sounds["cancel"].play() - assets.sounds["song-select"].play(0.3) - - $(".difficulty").hide(); - $(".opened").removeClass("opened", 300); - - $('.songsel-title').fadeOut(200, function(){ - $('.songsel-title').attr('alt', '曲をえらぶ').html('曲をえらぶ').css('left', -300); - $('.songsel-title').animate({left:0, opacity:"show"}, 400); - }); - - return; - } - - if(!$('.opened').length) { - _this.startPreview($(this).data('song-id'), $(this).data('preview')); - assets.sounds["don"].play() - assets.sounds["song-select"].stop() - assets.sounds["diffsel"].play(0.3) - - $('.songsel-title').fadeOut(200, function(){ - $('.songsel-title').attr('alt', 'むずかしさをえらぶ').html('むずかしさをえらぶ').css('left', -300); - $('.songsel-title').animate({left:0, opacity:"show"}, 400); - }); - } else { - _this.startPreview($(this).data('song-id'), $(this).data('preview'), false); - assets.sounds["ka"].play(); - } - }; - - $(".difficulty").hide(); - $(".opened").removeClass("opened", 300); - $(this).addClass("opened", 300, "linear", function(){ - $(this).find(".difficulty").show(); - $(this).css("background", "rgba(255, 220, 47, 0.90)"); - }); - }); - + assets.sounds["cancel"].play() + assets.sounds["song-select"].play(0.3) + opened.classList.remove("opened") + this.songSelect.classList.remove("difficulty-select") + }else{ + this.startPreview(target.dataset.songId, target.dataset.preview, true) + assets.sounds["ka"].play() + opened.classList.remove("opened") + target.classList.add("opened") + } } - - this.createCode = function(){ + createCode(){ assets.sounds["bgm_songsel"].playLoop(0.1, false, 0, 1.442, 3.506) - assets.sounds["song-select"].play(0.2); - + assets.sounds["song-select"].play(0.2) var songElements = [0] - for(var i=0; i { + var songTitle = song.title var charElements = [0] var diffElements = [0] - for (var c=0; c -1) { - continue; - }; - - var ch = songTitle.charAt(c) == " " ? "\xa0" : songTitle.charAt(c); - - var isApos = false; - if (songTitle.charAt(c+1) == "'") { - ch = ch + "'"; - skipChars.push(c+1); - isApos = true; - }; - - var cl = ch == "\xa0" ? "song-title-char song-title-space" : "song-title-char"; - cl = isApos ? cl + " song-title-apos" : cl; - + for(var charIndex = 0; charIndex < songTitle.length; charIndex++){ + var ch = songTitle.charAt(charIndex) + var cl = "song-title-char" + if(ch == " "){ + ch = "\xa0" + cl += " song-title-space" + }else if(songTitle.charAt(charIndex + 1) == "'"){ + ch = ch + "'" + cl += " song-title-apos" + charIndex++ + } charElements.push( ["span", { class: cl, alt: ch }, ch] ) - }; - - for(var diff in _diffNames){ - var diffName = diff; - var diffLevel = song.stars[diff]; + } + for(var diff in this.diffNames){ + var diffName = diff + var diffLevel = song.stars[diff] if (!diffLevel) { - continue; + continue } - var starsDisplay = [0] - for(var x=1; x<=diffLevel; x++){ + for(var star = 1; star <= diffLevel; star++){ starsDisplay.push("\u2605") starsDisplay.push(["br"]) } - - var diffTxt=_diffNames[diffName] - + var diffTxt = this.diffNames[diffName] diffElements.push( ["li", { class: "difficulty " + diffName @@ -209,9 +160,7 @@ function SongSelect(){ }, starsDisplay] ] ) - } - songElements.push( ["div", { id: "song-" + song.id, @@ -228,25 +177,22 @@ function SongSelect(){ }, diffElements] ] ) - } - + }) element( document.getElementById("song-container"), songElements ) - $('.difficulty').hide(); } - - this.onusers = function(response){ + onusers(response){ var oldP2Elements = document.getElementsByClassName("p2") for(var i = oldP2Elements.length; i--;){ oldP2Elements[i].classList.remove("p2") } if(response){ response.forEach(idDiff => { - id = idDiff.id |0 - diff = idDiff.diff - if(diff in _diffNames){ + var id = idDiff.id |0 + var diff = idDiff.diff + if(diff in this.diffNames){ var idElement = document.getElementById("song-" + id) if(idElement){ idElement.classList.add("p2") @@ -259,19 +205,34 @@ function SongSelect(){ }) } } - - this.startP2 = function(){ - p2.getMessage("users", response =>{ - this.onusers(response) - }) - p2.onmessage("users", response => { - this.onusers(response) + startP2(){ + this.onusers(p2.getMessage("users")) + pageEvents.add(p2, "message", response => { + if(response.type == "users"){ + this.onusers(response.value) + } }) if(p2.closed){ p2.open() } } - - $("#screen").load("/src/views/songselect.html", _this.run); - -} \ No newline at end of file + clean(){ + assets.sounds["bgm_songsel"].stop() + assets.sounds["song-select"].stop() + assets.sounds["diffsel"].stop() + this.endPreview() + snd.musicGain.fadeIn() + pageEvents.remove(p2, "message") + for(let difficulty of this.diffElements){ + pageEvents.remove(difficulty, "click") + } + delete this.diffElements + for(let song of this.songElements){ + pageEvents.remove(song, "click") + } + delete this.songElements + pageEvents.remove(this.songselHelp, "click") + delete this.songselHelp + delete this.songSelect + } +} diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js index b8943b2..d185f6d 100644 --- a/public/src/js/soundbuffer.js +++ b/public/src/js/soundbuffer.js @@ -1,27 +1,19 @@ class SoundBuffer{ constructor(){ this.context = new AudioContext() - var resume = () => { + pageEvents.once(window, "click").then(() => { if(this.context.state == "suspended"){ this.context.resume() } - removeEventListener("click", resume) - } - addEventListener("click", resume) + }) } load(url, gain){ - return new Promise((resolve, reject) => { - var request = new XMLHttpRequest() - request.open("GET", url) + return loader.ajax(url, request => { request.responseType = "arraybuffer" - request.addEventListener("load", () => { - this.context.decodeAudioData(request.response, buffer => { - resolve(new Sound(gain || {soundBuffer: this}, buffer)) - }, reject) - }) - request.addEventListener("error", reject) - request.addEventListener("abort", reject) - request.send() + }).then(response => { + return this.context.decodeAudioData(response) + }).then(buffer => { + return new Sound(gain || {soundBuffer: this}, buffer) }) } createGain(){ diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index c1eb80e..4354acb 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -1,53 +1,24 @@ -function Titlescreen(){ - - var _this = this; - $("body").css("font-family", "TnT"); - - this.positionning = function(){ - - var width = 0.70*$(window).width(); - var logoW = (width>=654) ? 654 : width; - var logoH = logoW/2.18; - - $("#logo-big-cont").width(logoW); - $("#logo-big-cont").height(logoH); - $("#logo-big-cont").css("left", $(window).width()/2-($("#logo-big-cont").width()/2)); - $("#logo-big-cont").css("top", $(window).height()/2-($("#logo-big-cont").height()/2)); - +class Titlescreen{ + constructor(){ + loader.changePage("titlescreen") + this.titleScreen = document.getElementById("title-screen") + pageEvents.keyOnce(this, 13, "down").then(this.goNext.bind(this)) + pageEvents.once(this.titleScreen, "click").then(this.goNext.bind(this)) + assets.sounds["title"].play() } - - this.run = function(){ - - $(document).keypress(function(e){ - if(e.keyCode==13 && $("#screen").find("#title-screen").html()) - _this.goNext(); - }); - - $("#screen").find("#title-screen").click(function(){ - _this.goNext(); - }); - - - _this.positionning(); - $("#screen").find("#title-screen").show(); - $(window).resize(_this.positionning); - - assets.sounds["title"].play(); - - } - - this.goNext = function(){ - assets.sounds["title"].pause(); - assets.sounds["title"].currentTime = 0; - - assets.sounds["don"].play(); - if (localStorage.getItem('tutorial') !== 'true') { - new Tutorial(); - } else { - new SongSelect(); - }; - } - - $("#screen").load("/src/views/titlescreen.html", _this.run); - -} \ No newline at end of file + goNext(){ + this.clean() + assets.sounds["don"].play() + if(localStorage.getItem("tutorial") !== "true"){ + new Tutorial() + } else { + new SongSelect() + } + } + clean(){ + assets.sounds["title"].stop() + pageEvents.keyRemove(this, 13) + pageEvents.remove(this.titleScreen, "click") + delete this.titleScreen + } +} diff --git a/public/src/js/tutorial.js b/public/src/js/tutorial.js index 725d0f4..f2ef292 100644 --- a/public/src/js/tutorial.js +++ b/public/src/js/tutorial.js @@ -1,17 +1,19 @@ -function Tutorial() { - var _this = this; - - this.run = function() { - assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054) - - $('#tutorial-end-button').click(function(){ - assets.sounds["bgm_setsume"].stop(); - assets.sounds["don"].play(); - - localStorage.setItem('tutorial', 'true'); - new SongSelect(); - }); - }; - - $('#screen').load('/src/views/tutorial.html', _this.run); -}; +class Tutorial{ + constructor(){ + loader.changePage("tutorial") + assets.sounds["bgm_setsume"].playLoop(0.1, false, 0, 1.054, 16.054) + this.endButton = document.getElementById("tutorial-end-button") + pageEvents.once(this.endButton, "click").then(this.onEnd.bind(this)) + } + onEnd(){ + this.clean() + assets.sounds["don"].play() + localStorage.setItem("tutorial", "true") + new SongSelect() + } + clean(){ + assets.sounds["bgm_setsume"].stop() + pageEvents.remove(this.endButton, "click") + delete this.endButton + } +} diff --git a/public/src/js/view.js b/public/src/js/view.js index 572485c..068c3ed 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -4,17 +4,21 @@ class View{ this.bg = bg this.diff = diff - if(this.controller.multiplayer == 2){ - this.canvas = new ScalableCanvas("canvas-p2", $(window).width(), $(window).height() / 3 * 2) + this.pauseMenu = document.getElementById("pause-menu") + + var docW = document.body.offsetWidth + var docH = document.body.offsetHeight + if(this.controller.multiplayer === 2){ + this.canvas = new ScalableCanvas("canvas-p2", docW, docH / 3 * 2) this.canvas.canvas.style.position = "absolute" this.canvas.canvas.style.top = "33%" document.getElementById("game").appendChild(this.canvas.canvas) }else{ - this.canvas = new ScalableCanvas("canvas", $(window).width(), $(window).height()) + this.canvas = new ScalableCanvas("canvas", docW, docH) } this.winW = this.canvas.scaledWidth this.winH = this.canvas.scaledHeight - if(this.controller.multiplayer == 2){ + if(this.controller.multiplayer === 2){ this.winH = this.winH / 2 * 3 } this.ctx = this.canvas.ctx @@ -74,19 +78,22 @@ class View{ run(){ this.ctx.font = "normal 14pt TnT" this.setBackground() - $(".game-song").attr("alt", this.songTitle).html(this.songTitle) + var gameSong = document.getElementsByClassName("game-song")[0] + gameSong.appendChild(document.createTextNode(this.songTitle)) + gameSong.setAttribute("alt", this.songTitle) this.refresh() } setBackground(){ - $("#game").css("background-image", "url('" + this.bg + "')") + document.getElementById("game").style.backgroundImage = "url('" + this.bg + "')" } positionning(){ + var docW = document.body.offsetWidth + var docH = document.body.offsetHeight this.canvas.rescale() - var height = $(window).height() if(this.controller.multiplayer == 2){ - height = height / 3 * 2 + docH = docH / 3 * 2 } - this.canvas.resize($(window).width(), height) + this.canvas.resize(docW, docH) this.winW = this.canvas.scaledWidth this.winH = this.canvas.scaledHeight if(this.controller.multiplayer == 2){ @@ -597,10 +604,10 @@ class View{ } } togglePauseMenu(){ - if($("#pause-menu").is(":visible")){ - $("#pause-menu").hide() + if(this.controller.game.isPaused()){ + this.pauseMenu.style.display = "block" }else{ - $("#pause-menu").show() + this.pauseMenu.style.display = "" } } drawDifficulty(){ @@ -728,4 +735,10 @@ class View{ }) } } + clean(){ + delete this.pauseMenu + delete this.canvas + delete this.ctx + + } } diff --git a/public/src/views/loader.html b/public/src/views/loader.html index 8199983..865568a 100644 --- a/public/src/views/loader.html +++ b/public/src/views/loader.html @@ -1,4 +1,4 @@
-
- 0% -
\ No newline at end of file +
+ 0% + diff --git a/public/src/views/loadsong.html b/public/src/views/loadsong.html index b3fb412..aa37d1f 100644 --- a/public/src/views/loadsong.html +++ b/public/src/views/loadsong.html @@ -1,6 +1,6 @@ -
-
- -

Loading...

+
+
+ +
Loading...
-
\ No newline at end of file +
diff --git a/public/src/views/songselect.html b/public/src/views/songselect.html index 0118dd3..b99b5d1 100644 --- a/public/src/views/songselect.html +++ b/public/src/views/songselect.html @@ -1,5 +1,6 @@
-

曲をえらぶ

+

曲をえらぶ

+

むずかしさをえらぶ

?
-
-
\ No newline at end of file +
+
diff --git a/public/src/views/titlescreen.html b/public/src/views/titlescreen.html index 0a9f3e7..82dedc0 100644 --- a/public/src/views/titlescreen.html +++ b/public/src/views/titlescreen.html @@ -1,4 +1,4 @@ -
-
太鼓の達人ウェブ
-

Click or press enter

-
\ No newline at end of file +
+ 太鼓の達人ウェブ +
Click or Press Enter! +
diff --git a/server.py b/server.py index de7ed04..e38705f 100644 --- a/server.py +++ b/server.py @@ -51,6 +51,9 @@ async def connection(ws, path): except asyncio.TimeoutError: # Disconnect break + except websockets.exceptions.ConnectionClosed: + # Connection closed + break else: # Message received try: From 9665ed2c132bc547604bb90d1be0ab88c364ced9 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Tue, 18 Sep 2018 01:38:44 +0300 Subject: [PATCH 2/2] Delete jQuery --- public/index.html | 2 - public/src/js/lib/jquery-ui.js | 16617 ------------------------------- public/src/js/lib/jquery.js | 4 - 3 files changed, 16623 deletions(-) delete mode 100644 public/src/js/lib/jquery-ui.js delete mode 100644 public/src/js/lib/jquery.js diff --git a/public/index.html b/public/index.html index 5d452c6..ef60072 100644 --- a/public/index.html +++ b/public/index.html @@ -23,8 +23,6 @@ - - diff --git a/public/src/js/lib/jquery-ui.js b/public/src/js/lib/jquery-ui.js deleted file mode 100644 index 31ee9cd..0000000 --- a/public/src/js/lib/jquery-ui.js +++ /dev/null @@ -1,16617 +0,0 @@ -/*! jQuery UI - v1.11.4 - 2015-03-11 -* http://jqueryui.com -* Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js -* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ - -(function( factory ) { - if ( typeof define === "function" && define.amd ) { - - // AMD. Register as an anonymous module. - define([ "jquery" ], factory ); - } else { - - // Browser globals - factory( jQuery ); - } -}(function( $ ) { -/*! - * jQuery UI Core 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/category/ui-core/ - */ - - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.11.4", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - scrollParent: function( includeHidden ) { - var position = this.css( "position" ), - excludeStaticParent = position === "absolute", - overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, - scrollParent = this.parents().filter( function() { - var parent = $( this ); - if ( excludeStaticParent && parent.css( "position" ) === "static" ) { - return false; - } - return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); - }).eq( 0 ); - - return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; - }, - - uniqueId: (function() { - var uuid = 0; - - return function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + ( ++uuid ); - } - }); - }; - })(), - - removeUniqueId: function() { - return this.each(function() { - if ( /^ui-id-\d+$/.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap='#" + mapName + "']" )[ 0 ]; - return !!img && visible( img ); - } - return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - disableSelection: (function() { - var eventType = "onselectstart" in document.createElement( "div" ) ? - "selectstart" : - "mousedown"; - - return function() { - return this.bind( eventType + ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }; - })(), - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
- value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - } -}); - -// $.ui.plugin is deprecated. Use $.widget() extensions instead. -$.ui.plugin = { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args, allowDisconnected ) { - var i, - set = instance.plugins[ name ]; - - if ( !set ) { - return; - } - - if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } -}; - - -/*! - * jQuery UI Widget 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/jQuery.widget/ - */ - - -var widget_uuid = 0, - widget_slice = Array.prototype.slice; - -$.cleanData = (function( orig ) { - return function( elems ) { - var events, elem, i; - for ( i = 0; (elem = elems[i]) != null; i++ ) { - try { - - // Only trigger remove when necessary to save time - events = $._data( elem, "events" ); - if ( events && events.remove ) { - $( elem ).triggerHandler( "remove" ); - } - - // http://bugs.jquery.com/ticket/8235 - } catch ( e ) {} - } - orig( elems ); - }; -})( $.cleanData ); - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); - - return constructor; -}; - -$.widget.extend = function( target ) { - var input = widget_slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = widget_slice.call( arguments, 1 ), - returnValue = this; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( options === "instance" ) { - returnValue = instance; - return false; - } - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - - // Allow multiple hashes to be passed on init - if ( args.length ) { - options = $.widget.extend.apply( null, [ options ].concat(args) ); - } - - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} ); - if ( instance._init ) { - instance._init(); - } - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = widget_uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( arguments.length === 1 ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( arguments.length === 1 ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled", !!value ); - - // If the widget is becoming disabled, then nothing is interactive - if ( value ) { - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - } - - return this; - }, - - enable: function() { - return this._setOptions({ disabled: false }); - }, - disable: function() { - return this._setOptions({ disabled: true }); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^([\w:-]*)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + - this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - - // Clear the stack to avoid memory leaks (#10056) - this.bindings = $( this.bindings.not( element ).get() ); - this.focusable = $( this.focusable.not( element ).get() ); - this.hoverable = $( this.hoverable.not( element ).get() ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -var widget = $.widget; - - -/*! - * jQuery UI Mouse 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/mouse/ - */ - - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -var mouse = $.widget("ui.mouse", { - version: "1.11.4", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown." + this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click." + this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("." + this.widgetName); - if ( this._mouseMoveDelegate ) { - this.document - .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup." + this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if ( mouseHandled ) { - return; - } - - this._mouseMoved = false; - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - - this.document - .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) - .bind( "mouseup." + this.widgetName, this._mouseUpDelegate ); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // Only check for mouseups outside the document if you've moved inside the document - // at least once. This prevents the firing of mouseup in the case of IE<9, which will - // fire a mousemove event if content is placed under the cursor. See #7778 - // Support: IE <9 - if ( this._mouseMoved ) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - - // Iframe mouseup check - mouseup occurred in another document - } else if ( !event.which ) { - return this._mouseUp( event ); - } - } - - if ( event.which || event.button ) { - this._mouseMoved = true; - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - this.document - .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) - .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate ); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - mouseHandled = false; - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - - -/*! - * jQuery UI Position 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/position/ - */ - -(function() { - -$.ui = $.ui || {}; - -var cachedScrollbarWidth, supportsOffsetFractions, - max = Math.max, - abs = Math.abs, - round = Math.round, - rhorizontal = /left|center|right/, - rvertical = /top|center|bottom/, - roffset = /[\+\-]\d+(\.[\d]+)?%?/, - rposition = /^\w+/, - rpercent = /%$/, - _position = $.fn.position; - -function getOffsets( offsets, width, height ) { - return [ - parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), - parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) - ]; -} - -function parseCss( element, property ) { - return parseInt( $.css( element, property ), 10 ) || 0; -} - -function getDimensions( elem ) { - var raw = elem[0]; - if ( raw.nodeType === 9 ) { - return { - width: elem.width(), - height: elem.height(), - offset: { top: 0, left: 0 } - }; - } - if ( $.isWindow( raw ) ) { - return { - width: elem.width(), - height: elem.height(), - offset: { top: elem.scrollTop(), left: elem.scrollLeft() } - }; - } - if ( raw.preventDefault ) { - return { - width: 0, - height: 0, - offset: { top: raw.pageY, left: raw.pageX } - }; - } - return { - width: elem.outerWidth(), - height: elem.outerHeight(), - offset: elem.offset() - }; -} - -$.position = { - scrollbarWidth: function() { - if ( cachedScrollbarWidth !== undefined ) { - return cachedScrollbarWidth; - } - var w1, w2, - div = $( "
" ), - innerDiv = div.children()[0]; - - $( "body" ).append( div ); - w1 = innerDiv.offsetWidth; - div.css( "overflow", "scroll" ); - - w2 = innerDiv.offsetWidth; - - if ( w1 === w2 ) { - w2 = div[0].clientWidth; - } - - div.remove(); - - return (cachedScrollbarWidth = w1 - w2); - }, - getScrollInfo: function( within ) { - var overflowX = within.isWindow || within.isDocument ? "" : - within.element.css( "overflow-x" ), - overflowY = within.isWindow || within.isDocument ? "" : - within.element.css( "overflow-y" ), - hasOverflowX = overflowX === "scroll" || - ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), - hasOverflowY = overflowY === "scroll" || - ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); - return { - width: hasOverflowY ? $.position.scrollbarWidth() : 0, - height: hasOverflowX ? $.position.scrollbarWidth() : 0 - }; - }, - getWithinInfo: function( element ) { - var withinElement = $( element || window ), - isWindow = $.isWindow( withinElement[0] ), - isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; - return { - element: withinElement, - isWindow: isWindow, - isDocument: isDocument, - offset: withinElement.offset() || { left: 0, top: 0 }, - scrollLeft: withinElement.scrollLeft(), - scrollTop: withinElement.scrollTop(), - - // support: jQuery 1.6.x - // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows - width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), - height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() - }; - } -}; - -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } - - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); - - var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, - target = $( options.of ), - within = $.position.getWithinInfo( options.within ), - scrollInfo = $.position.getScrollInfo( within ), - collision = ( options.collision || "flip" ).split( " " ), - offsets = {}; - - dimensions = getDimensions( target ); - if ( target[0].preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - } - targetWidth = dimensions.width; - targetHeight = dimensions.height; - targetOffset = dimensions.offset; - // clone to reuse original targetOffset later - basePosition = $.extend( {}, targetOffset ); - - // force my and at to have valid horizontal and vertical positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[ this ] || "" ).split( " " ), - horizontalOffset, - verticalOffset; - - if ( pos.length === 1) { - pos = rhorizontal.test( pos[ 0 ] ) ? - pos.concat( [ "center" ] ) : - rvertical.test( pos[ 0 ] ) ? - [ "center" ].concat( pos ) : - [ "center", "center" ]; - } - pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; - pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; - - // calculate offsets - horizontalOffset = roffset.exec( pos[ 0 ] ); - verticalOffset = roffset.exec( pos[ 1 ] ); - offsets[ this ] = [ - horizontalOffset ? horizontalOffset[ 0 ] : 0, - verticalOffset ? verticalOffset[ 0 ] : 0 - ]; - - // reduce to just the positions without the offsets - options[ this ] = [ - rposition.exec( pos[ 0 ] )[ 0 ], - rposition.exec( pos[ 1 ] )[ 0 ] - ]; - }); - - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } - - if ( options.at[ 0 ] === "right" ) { - basePosition.left += targetWidth; - } else if ( options.at[ 0 ] === "center" ) { - basePosition.left += targetWidth / 2; - } - - if ( options.at[ 1 ] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[ 1 ] === "center" ) { - basePosition.top += targetHeight / 2; - } - - atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); - basePosition.left += atOffset[ 0 ]; - basePosition.top += atOffset[ 1 ]; - - return this.each(function() { - var collisionPosition, using, - elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - marginLeft = parseCss( this, "marginLeft" ), - marginTop = parseCss( this, "marginTop" ), - collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, - collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, - position = $.extend( {}, basePosition ), - myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); - - if ( options.my[ 0 ] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[ 0 ] === "center" ) { - position.left -= elemWidth / 2; - } - - if ( options.my[ 1 ] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[ 1 ] === "center" ) { - position.top -= elemHeight / 2; - } - - position.left += myOffset[ 0 ]; - position.top += myOffset[ 1 ]; - - // if the browser doesn't support fractions, then round for consistent results - if ( !supportsOffsetFractions ) { - position.left = round( position.left ); - position.top = round( position.top ); - } - - collisionPosition = { - marginLeft: marginLeft, - marginTop: marginTop - }; - - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[ i ] ] ) { - $.ui.position[ collision[ i ] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - collisionPosition: collisionPosition, - collisionWidth: collisionWidth, - collisionHeight: collisionHeight, - offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], - my: options.my, - at: options.at, - within: within, - elem: elem - }); - } - }); - - if ( options.using ) { - // adds feedback as second argument to using callback, if present - using = function( props ) { - var left = targetOffset.left - position.left, - right = left + targetWidth - elemWidth, - top = targetOffset.top - position.top, - bottom = top + targetHeight - elemHeight, - feedback = { - target: { - element: target, - left: targetOffset.left, - top: targetOffset.top, - width: targetWidth, - height: targetHeight - }, - element: { - element: elem, - left: position.left, - top: position.top, - width: elemWidth, - height: elemHeight - }, - horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", - vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" - }; - if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { - feedback.horizontal = "center"; - } - if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { - feedback.vertical = "middle"; - } - if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { - feedback.important = "horizontal"; - } else { - feedback.important = "vertical"; - } - options.using.call( this, props, feedback ); - }; - } - - elem.offset( $.extend( position, { using: using } ) ); - }); -}; - -$.ui.position = { - fit: { - left: function( position, data ) { - var within = data.within, - withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, - outerWidth = within.width, - collisionPosLeft = position.left - data.collisionPosition.marginLeft, - overLeft = withinOffset - collisionPosLeft, - overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, - newOverRight; - - // element is wider than within - if ( data.collisionWidth > outerWidth ) { - // element is initially over the left side of within - if ( overLeft > 0 && overRight <= 0 ) { - newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; - position.left += overLeft - newOverRight; - // element is initially over right side of within - } else if ( overRight > 0 && overLeft <= 0 ) { - position.left = withinOffset; - // element is initially over both left and right sides of within - } else { - if ( overLeft > overRight ) { - position.left = withinOffset + outerWidth - data.collisionWidth; - } else { - position.left = withinOffset; - } - } - // too far left -> align with left edge - } else if ( overLeft > 0 ) { - position.left += overLeft; - // too far right -> align with right edge - } else if ( overRight > 0 ) { - position.left -= overRight; - // adjust based on position and margin - } else { - position.left = max( position.left - collisionPosLeft, position.left ); - } - }, - top: function( position, data ) { - var within = data.within, - withinOffset = within.isWindow ? within.scrollTop : within.offset.top, - outerHeight = data.within.height, - collisionPosTop = position.top - data.collisionPosition.marginTop, - overTop = withinOffset - collisionPosTop, - overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, - newOverBottom; - - // element is taller than within - if ( data.collisionHeight > outerHeight ) { - // element is initially over the top of within - if ( overTop > 0 && overBottom <= 0 ) { - newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; - position.top += overTop - newOverBottom; - // element is initially over bottom of within - } else if ( overBottom > 0 && overTop <= 0 ) { - position.top = withinOffset; - // element is initially over both top and bottom of within - } else { - if ( overTop > overBottom ) { - position.top = withinOffset + outerHeight - data.collisionHeight; - } else { - position.top = withinOffset; - } - } - // too far up -> align with top - } else if ( overTop > 0 ) { - position.top += overTop; - // too far down -> align with bottom edge - } else if ( overBottom > 0 ) { - position.top -= overBottom; - // adjust based on position and margin - } else { - position.top = max( position.top - collisionPosTop, position.top ); - } - } - }, - flip: { - left: function( position, data ) { - var within = data.within, - withinOffset = within.offset.left + within.scrollLeft, - outerWidth = within.width, - offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, - collisionPosLeft = position.left - data.collisionPosition.marginLeft, - overLeft = collisionPosLeft - offsetLeft, - overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - atOffset = data.at[ 0 ] === "left" ? - data.targetWidth : - data.at[ 0 ] === "right" ? - -data.targetWidth : - 0, - offset = -2 * data.offset[ 0 ], - newOverRight, - newOverLeft; - - if ( overLeft < 0 ) { - newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; - if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { - position.left += myOffset + atOffset + offset; - } - } else if ( overRight > 0 ) { - newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; - if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { - position.left += myOffset + atOffset + offset; - } - } - }, - top: function( position, data ) { - var within = data.within, - withinOffset = within.offset.top + within.scrollTop, - outerHeight = within.height, - offsetTop = within.isWindow ? within.scrollTop : within.offset.top, - collisionPosTop = position.top - data.collisionPosition.marginTop, - overTop = collisionPosTop - offsetTop, - overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, - top = data.my[ 1 ] === "top", - myOffset = top ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - data.at[ 1 ] === "bottom" ? - -data.targetHeight : - 0, - offset = -2 * data.offset[ 1 ], - newOverTop, - newOverBottom; - if ( overTop < 0 ) { - newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; - if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { - position.top += myOffset + atOffset + offset; - } - } else if ( overBottom > 0 ) { - newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; - if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { - position.top += myOffset + atOffset + offset; - } - } - } - }, - flipfit: { - left: function() { - $.ui.position.flip.left.apply( this, arguments ); - $.ui.position.fit.left.apply( this, arguments ); - }, - top: function() { - $.ui.position.flip.top.apply( this, arguments ); - $.ui.position.fit.top.apply( this, arguments ); - } - } -}; - -// fraction support test -(function() { - var testElement, testElementParent, testElementStyle, offsetLeft, i, - body = document.getElementsByTagName( "body" )[ 0 ], - div = document.createElement( "div" ); - - //Create a "fake body" for testing based on method used in jQuery.support - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - $.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || document.documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - div.style.cssText = "position: absolute; left: 10.7432222px;"; - - offsetLeft = $( div ).offset().left; - supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); -})(); - -})(); - -var position = $.ui.position; - - -/*! - * jQuery UI Accordion 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/accordion/ - */ - - -var accordion = $.widget( "ui.accordion", { - version: "1.11.4", - options: { - active: 0, - animate: {}, - collapsible: false, - event: "click", - header: "> li > :first-child,> :not(li):even", - heightStyle: "auto", - icons: { - activeHeader: "ui-icon-triangle-1-s", - header: "ui-icon-triangle-1-e" - }, - - // callbacks - activate: null, - beforeActivate: null - }, - - hideProps: { - borderTopWidth: "hide", - borderBottomWidth: "hide", - paddingTop: "hide", - paddingBottom: "hide", - height: "hide" - }, - - showProps: { - borderTopWidth: "show", - borderBottomWidth: "show", - paddingTop: "show", - paddingBottom: "show", - height: "show" - }, - - _create: function() { - var options = this.options; - this.prevShow = this.prevHide = $(); - this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) - // ARIA - .attr( "role", "tablist" ); - - // don't allow collapsible: false and active: false / null - if ( !options.collapsible && (options.active === false || options.active == null) ) { - options.active = 0; - } - - this._processPanels(); - // handle negative values - if ( options.active < 0 ) { - options.active += this.headers.length; - } - this._refresh(); - }, - - _getCreateEventData: function() { - return { - header: this.active, - panel: !this.active.length ? $() : this.active.next() - }; - }, - - _createIcons: function() { - var icons = this.options.icons; - if ( icons ) { - $( "" ) - .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) - .prependTo( this.headers ); - this.active.children( ".ui-accordion-header-icon" ) - .removeClass( icons.header ) - .addClass( icons.activeHeader ); - this.headers.addClass( "ui-accordion-icons" ); - } - }, - - _destroyIcons: function() { - this.headers - .removeClass( "ui-accordion-icons" ) - .children( ".ui-accordion-header-icon" ) - .remove(); - }, - - _destroy: function() { - var contents; - - // clean up main element - this.element - .removeClass( "ui-accordion ui-widget ui-helper-reset" ) - .removeAttr( "role" ); - - // clean up headers - this.headers - .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " + - "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) - .removeAttr( "role" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-controls" ) - .removeAttr( "tabIndex" ) - .removeUniqueId(); - - this._destroyIcons(); - - // clean up content panels - contents = this.headers.next() - .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " + - "ui-accordion-content ui-accordion-content-active ui-state-disabled" ) - .css( "display", "" ) - .removeAttr( "role" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-labelledby" ) - .removeUniqueId(); - - if ( this.options.heightStyle !== "content" ) { - contents.css( "height", "" ); - } - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "event" ) { - if ( this.options.event ) { - this._off( this.headers, this.options.event ); - } - this._setupEvents( value ); - } - - this._super( key, value ); - - // setting collapsible: false while collapsed; open first panel - if ( key === "collapsible" && !value && this.options.active === false ) { - this._activate( 0 ); - } - - if ( key === "icons" ) { - this._destroyIcons(); - if ( value ) { - this._createIcons(); - } - } - - // #5332 - opacity doesn't cascade to positioned elements in IE - // so we need to add the disabled class to the headers and panels - if ( key === "disabled" ) { - this.element - .toggleClass( "ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.headers.add( this.headers.next() ) - .toggleClass( "ui-state-disabled", !!value ); - } - }, - - _keydown: function( event ) { - if ( event.altKey || event.ctrlKey ) { - return; - } - - var keyCode = $.ui.keyCode, - length = this.headers.length, - currentIndex = this.headers.index( event.target ), - toFocus = false; - - switch ( event.keyCode ) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[ ( currentIndex + 1 ) % length ]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._eventHandler( event ); - break; - case keyCode.HOME: - toFocus = this.headers[ 0 ]; - break; - case keyCode.END: - toFocus = this.headers[ length - 1 ]; - break; - } - - if ( toFocus ) { - $( event.target ).attr( "tabIndex", -1 ); - $( toFocus ).attr( "tabIndex", 0 ); - toFocus.focus(); - event.preventDefault(); - } - }, - - _panelKeyDown: function( event ) { - if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { - $( event.currentTarget ).prev().focus(); - } - }, - - refresh: function() { - var options = this.options; - this._processPanels(); - - // was collapsed or no panel - if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { - options.active = false; - this.active = $(); - // active false only when collapsible is true - } else if ( options.active === false ) { - this._activate( 0 ); - // was active, but active panel is gone - } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { - // all remaining panel are disabled - if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { - options.active = false; - this.active = $(); - // activate previous panel - } else { - this._activate( Math.max( 0, options.active - 1 ) ); - } - // was active, active panel still exists - } else { - // make sure active index is correct - options.active = this.headers.index( this.active ); - } - - this._destroyIcons(); - - this._refresh(); - }, - - _processPanels: function() { - var prevHeaders = this.headers, - prevPanels = this.panels; - - this.headers = this.element.find( this.options.header ) - .addClass( "ui-accordion-header ui-state-default ui-corner-all" ); - - this.panels = this.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) - .filter( ":not(.ui-accordion-content-active)" ) - .hide(); - - // Avoid memory leaks (#10056) - if ( prevPanels ) { - this._off( prevHeaders.not( this.headers ) ); - this._off( prevPanels.not( this.panels ) ); - } - }, - - _refresh: function() { - var maxHeight, - options = this.options, - heightStyle = options.heightStyle, - parent = this.element.parent(); - - this.active = this._findActive( options.active ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) - .removeClass( "ui-corner-all" ); - this.active.next() - .addClass( "ui-accordion-content-active" ) - .show(); - - this.headers - .attr( "role", "tab" ) - .each(function() { - var header = $( this ), - headerId = header.uniqueId().attr( "id" ), - panel = header.next(), - panelId = panel.uniqueId().attr( "id" ); - header.attr( "aria-controls", panelId ); - panel.attr( "aria-labelledby", headerId ); - }) - .next() - .attr( "role", "tabpanel" ); - - this.headers - .not( this.active ) - .attr({ - "aria-selected": "false", - "aria-expanded": "false", - tabIndex: -1 - }) - .next() - .attr({ - "aria-hidden": "true" - }) - .hide(); - - // make sure at least one header is in the tab order - if ( !this.active.length ) { - this.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active.attr({ - "aria-selected": "true", - "aria-expanded": "true", - tabIndex: 0 - }) - .next() - .attr({ - "aria-hidden": "false" - }); - } - - this._createIcons(); - - this._setupEvents( options.event ); - - if ( heightStyle === "fill" ) { - maxHeight = parent.height(); - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); - }) - .height( maxHeight ); - } - }, - - _activate: function( index ) { - var active = this._findActive( index )[ 0 ]; - - // trying to activate the already active panel - if ( active === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the currently active header - active = active || this.active[ 0 ]; - - this._eventHandler({ - target: active, - currentTarget: active, - preventDefault: $.noop - }); - }, - - _findActive: function( selector ) { - return typeof selector === "number" ? this.headers.eq( selector ) : $(); - }, - - _setupEvents: function( event ) { - var events = { - keydown: "_keydown" - }; - if ( event ) { - $.each( event.split( " " ), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - } - - this._off( this.headers.add( this.headers.next() ) ); - this._on( this.headers, events ); - this._on( this.headers.next(), { keydown: "_panelKeyDown" }); - this._hoverable( this.headers ); - this._focusable( this.headers ); - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - clicked = $( event.currentTarget ), - clickedIsActive = clicked[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : clicked.next(), - toHide = active.next(), - eventData = { - oldHeader: active, - oldPanel: toHide, - newHeader: collapsing ? $() : clicked, - newPanel: toShow - }; - - event.preventDefault(); - - if ( - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.headers.index( clicked ); - - // when the call to ._toggle() comes after the class changes - // it causes a very odd bug in IE 8 (see #6720) - this.active = clickedIsActive ? $() : clicked; - this._toggle( eventData ); - - // switch classes - // corner classes on the previously active header stay after the animation - active.removeClass( "ui-accordion-header-active ui-state-active" ); - if ( options.icons ) { - active.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.activeHeader ) - .addClass( options.icons.header ); - } - - if ( !clickedIsActive ) { - clicked - .removeClass( "ui-corner-all" ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); - if ( options.icons ) { - clicked.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.header ) - .addClass( options.icons.activeHeader ); - } - - clicked - .next() - .addClass( "ui-accordion-content-active" ); - } - }, - - _toggle: function( data ) { - var toShow = data.newPanel, - toHide = this.prevShow.length ? this.prevShow : data.oldPanel; - - // handle activating a panel during the animation for another activation - this.prevShow.add( this.prevHide ).stop( true, true ); - this.prevShow = toShow; - this.prevHide = toHide; - - if ( this.options.animate ) { - this._animate( toShow, toHide, data ); - } else { - toHide.hide(); - toShow.show(); - this._toggleComplete( data ); - } - - toHide.attr({ - "aria-hidden": "true" - }); - toHide.prev().attr({ - "aria-selected": "false", - "aria-expanded": "false" - }); - // if we're switching panels, remove the old header from the tab order - // if we're opening from collapsed state, remove the previous header from the tab order - // if we're collapsing, then keep the collapsing header in the tab order - if ( toShow.length && toHide.length ) { - toHide.prev().attr({ - "tabIndex": -1, - "aria-expanded": "false" - }); - } else if ( toShow.length ) { - this.headers.filter(function() { - return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow - .attr( "aria-hidden", "false" ) - .prev() - .attr({ - "aria-selected": "true", - "aria-expanded": "true", - tabIndex: 0 - }); - }, - - _animate: function( toShow, toHide, data ) { - var total, easing, duration, - that = this, - adjust = 0, - boxSizing = toShow.css( "box-sizing" ), - down = toShow.length && - ( !toHide.length || ( toShow.index() < toHide.index() ) ), - animate = this.options.animate || {}, - options = down && animate.down || animate, - complete = function() { - that._toggleComplete( data ); - }; - - if ( typeof options === "number" ) { - duration = options; - } - if ( typeof options === "string" ) { - easing = options; - } - // fall back from options to animation in case of partial down settings - easing = easing || options.easing || animate.easing; - duration = duration || options.duration || animate.duration; - - if ( !toHide.length ) { - return toShow.animate( this.showProps, duration, easing, complete ); - } - if ( !toShow.length ) { - return toHide.animate( this.hideProps, duration, easing, complete ); - } - - total = toShow.show().outerHeight(); - toHide.animate( this.hideProps, { - duration: duration, - easing: easing, - step: function( now, fx ) { - fx.now = Math.round( now ); - } - }); - toShow - .hide() - .animate( this.showProps, { - duration: duration, - easing: easing, - complete: complete, - step: function( now, fx ) { - fx.now = Math.round( now ); - if ( fx.prop !== "height" ) { - if ( boxSizing === "content-box" ) { - adjust += fx.now; - } - } else if ( that.options.heightStyle !== "content" ) { - fx.now = Math.round( total - toHide.outerHeight() - adjust ); - adjust = 0; - } - } - }); - }, - - _toggleComplete: function( data ) { - var toHide = data.oldPanel; - - toHide - .removeClass( "ui-accordion-content-active" ) - .prev() - .removeClass( "ui-corner-top" ) - .addClass( "ui-corner-all" ); - - // Work around for rendering bug in IE (#5421) - if ( toHide.length ) { - toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; - } - this._trigger( "activate", null, data ); - } -}); - - -/*! - * jQuery UI Menu 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/menu/ - */ - - -var menu = $.widget( "ui.menu", { - version: "1.11.4", - defaultElement: "