From 6aa66c66681507f8c31d7c16fb8c8e1e968dd5ac Mon Sep 17 00:00:00 2001 From: LuoRain Date: Tue, 16 Mar 2021 22:55:17 +0800 Subject: [PATCH] Add internal event system --- README-zh_CN.md | 12 ++++++++++++ README.md | 12 ++++++++++++ package.json | 2 +- src/typescript/controller.ts | 6 +++--- src/typescript/global.d.ts | 2 ++ src/typescript/lyric.ts | 3 ++- src/typescript/modules/event.ts | 24 +++++++++++++++++++++++- src/typescript/player.ts | 11 ++++++++--- src/typescript/ui.ts | 6 +++--- 9 files changed, 66 insertions(+), 12 deletions(-) diff --git a/README-zh_CN.md b/README-zh_CN.md index d1bf1ab..91a1c03 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -34,6 +34,8 @@ | pause() | 暂停 | | next() | 下一首 | | previous() | 上一首 | +| addEventListener(```name: string, handler: Function```) | 添加一个事件监听器 | +| removeEventListener(```name: string, handler: Function```) | 移除一个事件监听器 | | volume: ```number``` | 音量。有效值在```0-1```之间 | | currentTime: ```number``` | 当前时间位置 | | duration: ```number``` | ```getter``` 歌曲时长 | @@ -41,6 +43,16 @@ | song: ```Song``` | 当前歌曲 | | playlist: ```Song[]``` | 歌单 | +## 事件 +所有在此表格内声明的事件除特殊声明外都需要通过```PPlayer.addEventListener()```来监听。 +| 事件名称 | 描述 | 参数 | +| ---------- | ----------- | --------- | +| penguinready | 在```window.PPlayer```上下文可用时被触发。 **此事件在```window.addEventListener```中监听** | *无参数* | +| setup | 在播放器开始准备时触发 | *无参数* | +| initialized | 在播放器初始化完毕时触发 | *无参数* | +| songchange | 在音乐改变时触发 | song: ```Song``` | +| themecolorchange | 在主题颜色改变时触发 | color: ```Color```, palette: ```Color[]``` | + ### 提示 如果你正在查看预览页面,你可以通过在网址后面添加```?playlist=[你的歌单ID]```来使用你自己的歌单。 diff --git a/README.md b/README.md index e875928..2b99af9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ Every API of the player is exposed in ```PPlayer``` object of ```window``` conte | pause() | Pause | | next() | Next song | | previous() | Previous song | +| addEventListener(```name: string, handler: Function```) | Add a event listener | +| removeEventListener(```name: string, handler: Function```) | Remove a event listener | | volume: ```number``` | Volume. Valid values are between ```0-1``` | | currentTime: ```number``` | Current time position | | duration: ```number``` | ```getter``` Song duration | @@ -43,6 +45,16 @@ Every API of the player is exposed in ```PPlayer``` object of ```window``` conte | song: ```Song``` | Current song | | playlist: ```Song[]``` | Current playlist | +## Events +All events declared in this table needed to be listened by using ```PPlayer.addEventListener()``` unless there is a special note. +| Event name | Description | Parameter | +| ---------- | ----------- | --------- | +| penguinready | Triggered when ```window.PPlayer``` context is ready. **This is triggered in ```window.addEventListener```** | *No parameter* | +| setup | Triggered when the player starts setting up | *No parameter* | +| initialized | Trigger when the player is initialized | *No parameter* | +| songchange | Triggered when the song has changed | song: ```Song``` | +| themecolorchange | Trigger when the theme color has changed | color: ```Color```, palette: ```Color[]``` | + ### Note If you are visiting the demo page, you can use your own playlist by append ```?playlist=[YOUR PLAYLIST ID HERE]``` after the URL diff --git a/package.json b/package.json index 10f6e82..f7417bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@m4tec/penguinplayer", - "version": "1.0.5", + "version": "1.1.0", "description": "A simple player based on Netease Cloud Music", "main": "dist/player.js", "scripts": { diff --git a/src/typescript/controller.ts b/src/typescript/controller.ts index 73906aa..018f353 100644 --- a/src/typescript/controller.ts +++ b/src/typescript/controller.ts @@ -3,7 +3,7 @@ import { container as el } from "./player"; import { setSong as setMediaSession } from "./modules/mediaSession"; import { getLyric } from "./lyric"; import { progressSlider, resetRotate, setThemeColor, volumeSlider } from "./ui"; -import { dispatchEvent } from "./modules/event"; +import { addEventListener, dispatchEvent } from "./modules/event"; import ajax from "./modules/ajax"; export let songs: Song[] = []; @@ -23,7 +23,7 @@ const playFailedHandler = () => { let audio: HTMLAudioElement; -window.addEventListener("penguininitialized", () => { +addEventListener("setup", () => { audio = (el.querySelector(".penguin-player__audio")); audio.addEventListener("playing", () => errorAmount = 0); audio.addEventListener("error", playFailedHandler); @@ -81,7 +81,7 @@ export function play(id?: number) { } else { playFailedHandler(); } }).catch(playFailedHandler); getLyric(song); - dispatchEvent("penguinsongchange", { detail: song }); + dispatchEvent("songchange", song); } else { audio.play(); } } diff --git a/src/typescript/global.d.ts b/src/typescript/global.d.ts index 7de1ff9..dca76ed 100644 --- a/src/typescript/global.d.ts +++ b/src/typescript/global.d.ts @@ -76,6 +76,8 @@ interface PenguinPlayerAPI { pause(): void next(): void previous(): void + addEventListener(name: string, handler: Function): void + removeEventListener(name: string, handler: Function): void readonly paused: boolean readonly song: Song readonly duration: number diff --git a/src/typescript/lyric.ts b/src/typescript/lyric.ts index 0af145e..13ec8d1 100644 --- a/src/typescript/lyric.ts +++ b/src/typescript/lyric.ts @@ -5,12 +5,13 @@ import { container as el } from "./player"; import tickIcon from "../icons/tick.svg"; import errorIcon from "../icons/error.svg"; +import { addEventListener } from "./modules/event"; let audio: HTMLAudioElement, lrcInfos = { main: {}, sub: {} }; -window.addEventListener("penguininitialized", () => { +addEventListener("setup", () => { audio = el.querySelector(".penguin-player__audio"); [lrcInfos.main.el, lrcInfos.sub.el] = [ el.querySelector(".penguin-player__lyric--line[line-name=main]"), diff --git a/src/typescript/modules/event.ts b/src/typescript/modules/event.ts index 72e3988..5ff4bb6 100644 --- a/src/typescript/modules/event.ts +++ b/src/typescript/modules/event.ts @@ -1,4 +1,26 @@ -export function dispatchEvent(name: string, detail?: object) { +let events = {}; + +export function addEventListener(name: string, handler: Function) { + events[name] = events[name]?.concat([handler]) || [handler]; +} + +export function removeEventListener(name: string, handler: Function) { + if (events[name] && events[name].indexOf(handler) != -1) { + events[name].splice(events[name].indexOf(handler), 1); + } +} + +export function dispatchEvent(name: string, ...parameters: any) { + for (let handler of (events[name] || [])) { + try { + handler.apply(null, parameters); + } catch (e) { + console.error(e); + } + } +} + +export function dispatchWindowEvent(name: string, detail?: object) { let event: Event; if (typeof(Event) === "function") { event = detail == undefined ? new Event(name) : new CustomEvent(name, detail); diff --git a/src/typescript/player.ts b/src/typescript/player.ts index 6f6456f..d47edcb 100644 --- a/src/typescript/player.ts +++ b/src/typescript/player.ts @@ -21,7 +21,7 @@ import { setCircleProgress, setThemeColor, rotateToggle } from "./ui"; import "../sass/player.sass"; import template from "../template.pug"; -import { dispatchEvent } from "./modules/event"; +import { addEventListener, removeEventListener, dispatchEvent, dispatchWindowEvent } from "./modules/event"; import ajax from "./modules/ajax"; /// #if IE_SUPPORT import { schedule } from "./modules/task"; @@ -84,7 +84,7 @@ const colorthief = new ColorThief(); player.classList.add("penguin-player__player-playlist"); } }); - window.addEventListener("penguininitialized", () => { + addEventListener("initialized", () => { // Volume setup setVolume(1); try { @@ -94,6 +94,7 @@ const colorthief = new ColorThief(); } } catch { print("Invalid volume storage"); } }); + dispatchEvent("setup"); } let lazyLoad: ILazyLoadInstance; @@ -156,7 +157,7 @@ function initialize(list: any) { callback_loaded: onPlaylistSongLoaded }); document.body.appendChild(el); - dispatchEvent("penguininitialized"); + dispatchEvent("initialized"); play(Math.floor(Math.random() * songs.length)); print("Player ready"); } @@ -193,6 +194,8 @@ window.PPlayer = { initialize: (playlist) => { fetchPlaylist(playlist); }, play, pause, next, previous: prev, + addEventListener, + removeEventListener, get volume() { return (el.querySelector(".penguin-player__audio")).volume; }, @@ -219,6 +222,8 @@ window.PPlayer = { } } +dispatchWindowEvent("penguineventready"); + print("https://github.com/M4TEC/PenguinPlayer"); print("Player loaded"); if (typeof window.penguinplayer_id === "string") { diff --git a/src/typescript/ui.ts b/src/typescript/ui.ts index 4471d5f..380ca9e 100644 --- a/src/typescript/ui.ts +++ b/src/typescript/ui.ts @@ -4,7 +4,7 @@ const StackBlur = require('stackblur-canvas'); /// #endif import { findHighContrastColor } from "./modules/color"; -import { dispatchEvent } from "./modules/event"; +import { addEventListener, dispatchEvent } from "./modules/event"; import { container as el } from "./player"; import Slider from "./modules/slider"; import { currentSong, getRealDuration, songs, trialInfo } from "./controller"; @@ -13,7 +13,7 @@ import { isBlurSupported } from "./modules/helper"; export let volumeSlider: Slider; export let progressSlider: Slider; -window.addEventListener("penguininitialized", () => { +addEventListener("setup", () => { let audio: HTMLAudioElement = el.querySelector(".penguin-player__audio"); // Progress bar setup let playerOldState: boolean; @@ -105,7 +105,7 @@ export function setThemeColor(color: Color, palette: Color[]) { el.querySelectorAll(".penguin-player__player--progress-inner, .penguin-player__player--progress-dot, .penguin-player__player--controls-volume-inner, .penguin-player__player--controls-volume-dot").forEach((el) => { (el).style.backgroundColor = foregroundRgb; }); - dispatchEvent("penguinthemecolorchange", { color, palette }); + dispatchEvent("themecolorchange", { color, palette }); } export function rotateToggle(rotate: boolean) {