2018-09-18 06:37:59 +08:00
|
|
|
class PageEvents{
|
|
|
|
constructor(){
|
|
|
|
this.allEvents = new Map()
|
|
|
|
this.keyListeners = new Map()
|
2018-09-18 21:59:40 +08:00
|
|
|
this.mouseListeners = new Map()
|
2019-04-17 02:06:41 +08:00
|
|
|
this.blurListeners = new Map()
|
2018-12-16 03:13:16 +08:00
|
|
|
this.lastKeyEvent = -Infinity
|
2018-09-18 06:37:59 +08:00
|
|
|
this.add(window, "keydown", this.keyEvent.bind(this))
|
|
|
|
this.add(window, "keyup", this.keyEvent.bind(this))
|
2018-09-18 21:59:40 +08:00
|
|
|
this.add(window, "mousemove", this.mouseEvent.bind(this))
|
2019-04-17 02:06:41 +08:00
|
|
|
this.add(window, "blur", this.blurEvent.bind(this))
|
2019-04-06 03:53:51 +08:00
|
|
|
this.kbd = []
|
2018-09-18 06:37:59 +08:00
|
|
|
}
|
|
|
|
add(target, type, callback){
|
2018-10-13 02:04:28 +08:00
|
|
|
if(Array.isArray(type)){
|
|
|
|
type.forEach(type => this.add(target, type, callback))
|
|
|
|
return
|
|
|
|
}
|
2018-09-18 06:37:59 +08:00
|
|
|
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){
|
2018-10-13 02:04:28 +08:00
|
|
|
if(Array.isArray(type)){
|
|
|
|
type.forEach(type => this.remove(target, type))
|
|
|
|
return
|
|
|
|
}
|
2018-09-18 06:37:59 +08:00
|
|
|
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 => {
|
2018-12-04 06:23:11 +08:00
|
|
|
switch(response.type){
|
|
|
|
case "load":
|
|
|
|
return resolve(response.event)
|
|
|
|
case "error":
|
|
|
|
return reject(["Loading error", target])
|
|
|
|
case "abort":
|
|
|
|
return reject("Loading aborted")
|
2018-09-18 06:37:59 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
keyEvent(event){
|
2019-04-06 03:53:51 +08:00
|
|
|
if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){
|
2018-12-23 22:29:03 +08:00
|
|
|
this.lastKeyEvent = Date.now()
|
2019-04-06 18:19:10 +08:00
|
|
|
event.preventDefault()
|
2018-12-23 22:29:03 +08:00
|
|
|
}
|
2018-09-18 06:37:59 +08:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2018-09-18 21:59:40 +08:00
|
|
|
mouseEvent(event){
|
|
|
|
this.lastMouse = event
|
|
|
|
this.mouseListeners.forEach(callback => callback(event))
|
|
|
|
}
|
|
|
|
mouseAdd(target, callback){
|
|
|
|
this.mouseListeners.set(target, callback)
|
|
|
|
}
|
|
|
|
mouseRemove(target){
|
|
|
|
this.mouseListeners.delete(target)
|
|
|
|
}
|
2019-04-17 02:06:41 +08:00
|
|
|
blurEvent(event){
|
|
|
|
this.blurListeners.forEach(callback => callback(event))
|
|
|
|
}
|
|
|
|
blurAdd(target, callback){
|
|
|
|
this.blurListeners.set(target, callback)
|
|
|
|
}
|
|
|
|
blurRemove(target){
|
|
|
|
this.blurListeners.delete(target)
|
|
|
|
}
|
2018-09-18 21:59:40 +08:00
|
|
|
getMouse(){
|
|
|
|
return this.lastMouse
|
|
|
|
}
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 17:32:45 +08:00
|
|
|
send(name, detail){
|
|
|
|
dispatchEvent(new CustomEvent(name, {detail: detail}))
|
|
|
|
}
|
2019-04-06 03:53:51 +08:00
|
|
|
setKbd(){
|
2019-04-17 02:06:41 +08:00
|
|
|
this.kbd = []
|
2019-04-06 03:53:51 +08:00
|
|
|
var kbdSettings = settings.getItem("keyboardSettings")
|
2019-04-17 02:06:41 +08:00
|
|
|
for(var name in kbdSettings){
|
|
|
|
var keys = kbdSettings[name]
|
|
|
|
for(var i in keys){
|
|
|
|
this.kbd.push(keys[i])
|
|
|
|
}
|
|
|
|
}
|
2019-04-06 03:53:51 +08:00
|
|
|
}
|
2018-09-18 06:37:59 +08:00
|
|
|
}
|