Implement tags and modernize CSS
This commit is contained in:
parent
ef70175403
commit
87352df5b2
758
Client.js
758
Client.js
|
@ -1,335 +1,429 @@
|
||||||
|
WebSocket.prototype.send = new Proxy(WebSocket.prototype.send, {
|
||||||
|
apply: (target, thisArg, args) => {
|
||||||
|
if (localStorage.token && !args[0].startsWith(`[{"m":"hi"`))
|
||||||
|
args[0] = args[0].replace(localStorage.token, "[REDACTED]");
|
||||||
|
return target.apply(thisArg, args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if(typeof module !== "undefined") {
|
class Client extends EventEmitter {
|
||||||
module.exports = Client;
|
constructor(uri) {
|
||||||
WebSocket = require("ws");
|
super();
|
||||||
EventEmitter = require("events").EventEmitter;
|
|
||||||
} else {
|
this.uri = uri;
|
||||||
this.Client = Client;
|
this.ws = undefined;
|
||||||
|
this.serverTimeOffset = 0;
|
||||||
|
this.user = undefined;
|
||||||
|
this.participantId = undefined;
|
||||||
|
this.channel = undefined;
|
||||||
|
this.ppl = {};
|
||||||
|
this.connectionTime = undefined;
|
||||||
|
this.connectionAttempts = 0;
|
||||||
|
this.desiredChannelId = undefined;
|
||||||
|
this.desiredChannelSettings = undefined;
|
||||||
|
this.pingInterval = undefined;
|
||||||
|
this.canConnect = false;
|
||||||
|
this.noteBuffer = [];
|
||||||
|
this.noteBufferTime = 0;
|
||||||
|
this.noteFlushInterval = undefined;
|
||||||
|
this.permissions = {};
|
||||||
|
this["🐈"] = 0;
|
||||||
|
this.loginInfo = undefined;
|
||||||
|
|
||||||
|
this.bindEventListeners();
|
||||||
|
|
||||||
|
this.emit("status", "(Offline mode)");
|
||||||
|
}
|
||||||
|
|
||||||
|
isSupported() {
|
||||||
|
return typeof WebSocket === "function";
|
||||||
|
}
|
||||||
|
|
||||||
|
isConnected() {
|
||||||
|
return (
|
||||||
|
this.isSupported() &&
|
||||||
|
this.ws &&
|
||||||
|
this.ws.readyState === WebSocket.OPEN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isConnecting() {
|
||||||
|
return (
|
||||||
|
this.isSupported() &&
|
||||||
|
this.ws &&
|
||||||
|
this.ws.readyState === WebSocket.CONNECTING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
start(enableTokens = true, enableChallenge = true) {
|
||||||
|
this.canConnect = true;
|
||||||
|
if (!this.connectionTime) {
|
||||||
|
this.connect(enableTokens, enableChallenge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.canConnect = false;
|
||||||
|
this.ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(enableTokens, enableChallenge) {
|
||||||
|
if (
|
||||||
|
!this.canConnect ||
|
||||||
|
!this.isSupported() ||
|
||||||
|
this.isConnected() ||
|
||||||
|
this.isConnecting()
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
this.emit("status", "Connecting...");
|
||||||
|
if (typeof module !== "undefined") {
|
||||||
|
// nodejsicle
|
||||||
|
this.ws = new WebSocket(this.uri, {
|
||||||
|
origin: "https://www.multiplayerpiano.com"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// browseroni
|
||||||
|
this.ws = new WebSocket(this.uri);
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
this.ws.addEventListener("close", function (evt) {
|
||||||
|
self.user = undefined;
|
||||||
|
self.participantId = undefined;
|
||||||
|
self.channel = undefined;
|
||||||
|
self.setParticipants([]);
|
||||||
|
clearInterval(self.pingInterval);
|
||||||
|
clearInterval(self.noteFlushInterval);
|
||||||
|
|
||||||
|
self.emit("disconnect", evt);
|
||||||
|
self.emit("status", "Offline mode");
|
||||||
|
|
||||||
|
// reconnect!
|
||||||
|
if (self.connectionTime) {
|
||||||
|
self.connectionTime = undefined;
|
||||||
|
self.connectionAttempts = 0;
|
||||||
|
} else {
|
||||||
|
++self.connectionAttempts;
|
||||||
|
}
|
||||||
|
var ms_lut = [50, 2500, 10000];
|
||||||
|
var idx = self.connectionAttempts;
|
||||||
|
if (idx >= ms_lut.length) idx = ms_lut.length - 1;
|
||||||
|
var ms = ms_lut[idx];
|
||||||
|
setTimeout(self.connect.bind(self), ms);
|
||||||
|
});
|
||||||
|
this.ws.addEventListener("error", function (err) {
|
||||||
|
self.emit("wserror", err);
|
||||||
|
self.ws.close(); // self.ws.emit("close");
|
||||||
|
});
|
||||||
|
this.ws.addEventListener("open", function (evt) {
|
||||||
|
self.pingInterval = setInterval(function () {
|
||||||
|
self.sendPing();
|
||||||
|
}, 20000);
|
||||||
|
self.noteBuffer = [];
|
||||||
|
self.noteBufferTime = 0;
|
||||||
|
self.noteFlushInterval = setInterval(function () {
|
||||||
|
if (self.noteBufferTime && self.noteBuffer.length > 0) {
|
||||||
|
self.sendArray([
|
||||||
|
{
|
||||||
|
m: "n",
|
||||||
|
t: self.noteBufferTime + self.serverTimeOffset,
|
||||||
|
n: self.noteBuffer
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
self.noteBufferTime = 0;
|
||||||
|
self.noteBuffer = [];
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
self.emit("connect");
|
||||||
|
self.emit("status", "Joining channel...");
|
||||||
|
|
||||||
|
if (!enableChallenge) {
|
||||||
|
const token = localStorage.token;
|
||||||
|
var hiMsg = { m: "hi", token };
|
||||||
|
self.sendArray([hiMsg]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.ws.addEventListener("message", async function (evt) {
|
||||||
|
var transmission = JSON.parse(evt.data);
|
||||||
|
for (var i = 0; i < transmission.length; i++) {
|
||||||
|
var msg = transmission[i];
|
||||||
|
self.emit(msg.m, msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEventListeners() {
|
||||||
|
var self = this;
|
||||||
|
this.on("hi", function (msg) {
|
||||||
|
self.connectionTime = Date.now();
|
||||||
|
self.user = msg.u;
|
||||||
|
self.receiveServerTime(msg.t, msg.e || undefined);
|
||||||
|
if (self.desiredChannelId) {
|
||||||
|
self.setChannel();
|
||||||
|
}
|
||||||
|
if (msg.token) localStorage.token = msg.token;
|
||||||
|
if (msg.permissions) {
|
||||||
|
self.permissions = msg.permissions;
|
||||||
|
} else {
|
||||||
|
self.permissions = {};
|
||||||
|
}
|
||||||
|
if (msg.accountInfo) {
|
||||||
|
self.accountInfo = msg.accountInfo;
|
||||||
|
} else {
|
||||||
|
self.accountInfo = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.on("t", function (msg) {
|
||||||
|
self.receiveServerTime(msg.t, msg.e || undefined);
|
||||||
|
});
|
||||||
|
this.on("ch", function (msg) {
|
||||||
|
self.desiredChannelId = msg.ch._id;
|
||||||
|
self.desiredChannelSettings = msg.ch.settings;
|
||||||
|
self.channel = msg.ch;
|
||||||
|
if (msg.p) self.participantId = msg.p;
|
||||||
|
self.setParticipants(msg.ppl);
|
||||||
|
});
|
||||||
|
this.on("p", function (msg) {
|
||||||
|
self.participantUpdate(msg);
|
||||||
|
self.emit("participant update", self.findParticipantById(msg.id));
|
||||||
|
});
|
||||||
|
this.on("m", function (msg) {
|
||||||
|
if (self.ppl.hasOwnProperty(msg.id)) {
|
||||||
|
self.participantMoveMouse(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.on("bye", function (msg) {
|
||||||
|
self.removeParticipant(msg.p);
|
||||||
|
});
|
||||||
|
this.on("b", function (msg) {
|
||||||
|
var hiMsg = { m: "hi" };
|
||||||
|
hiMsg["🐈"] = self["🐈"]++ || undefined;
|
||||||
|
if (this.loginInfo) hiMsg.login = this.loginInfo;
|
||||||
|
this.loginInfo = undefined;
|
||||||
|
console.log(msg);
|
||||||
|
if (msg.code) {
|
||||||
|
try {
|
||||||
|
if (msg.code.startsWith("~")) {
|
||||||
|
hiMsg.code = Function(msg.code.substring(1))();
|
||||||
|
} else {
|
||||||
|
hiMsg.code = Function(msg.code)();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
hiMsg.code = "broken";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (localStorage.token) {
|
||||||
|
hiMsg.token = localStorage.token;
|
||||||
|
}
|
||||||
|
self.sendArray([hiMsg]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
send(raw) {
|
||||||
|
if (this.isConnected()) this.ws.send(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendArray(arr) {
|
||||||
|
this.send(JSON.stringify(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
setChannel(id, set) {
|
||||||
|
this.desiredChannelId = id || this.desiredChannelId || "lobby";
|
||||||
|
this.desiredChannelSettings =
|
||||||
|
set || this.desiredChannelSettings || undefined;
|
||||||
|
this.sendArray([
|
||||||
|
{
|
||||||
|
m: "ch",
|
||||||
|
_id: this.desiredChannelId,
|
||||||
|
set: this.desiredChannelSettings
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
offlineChannelSettings = {
|
||||||
|
color: "#ecfaed"
|
||||||
|
};
|
||||||
|
|
||||||
|
getChannelSetting(key) {
|
||||||
|
if (!this.isConnected() || !this.channel || !this.channel.settings) {
|
||||||
|
return this.offlineChannelSettings[key];
|
||||||
|
}
|
||||||
|
return this.channel.settings[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
setChannelSettings(settings) {
|
||||||
|
if (!this.isConnected() || !this.channel || !this.channel.settings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.desiredChannelSettings) {
|
||||||
|
for (var key in settings) {
|
||||||
|
this.desiredChannelSettings[key] = settings[key];
|
||||||
|
}
|
||||||
|
this.sendArray([{ m: "chset", set: this.desiredChannelSettings }]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offlineParticipant = {
|
||||||
|
_id: "",
|
||||||
|
name: "",
|
||||||
|
color: "#777"
|
||||||
|
};
|
||||||
|
|
||||||
|
getOwnParticipant() {
|
||||||
|
return this.findParticipantById(this.participantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
setParticipants(ppl) {
|
||||||
|
// remove participants who left
|
||||||
|
for (var id in this.ppl) {
|
||||||
|
if (!this.ppl.hasOwnProperty(id)) continue;
|
||||||
|
var found = false;
|
||||||
|
for (var j = 0; j < ppl.length; j++) {
|
||||||
|
if (ppl[j].id === id) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
this.removeParticipant(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update all
|
||||||
|
for (var i = 0; i < ppl.length; i++) {
|
||||||
|
this.participantUpdate(ppl[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countParticipants() {
|
||||||
|
var count = 0;
|
||||||
|
for (var i in this.ppl) {
|
||||||
|
if (this.ppl.hasOwnProperty(i)) ++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
participantUpdate(update) {
|
||||||
|
var part = this.ppl[update.id] || null;
|
||||||
|
if (part === null) {
|
||||||
|
part = update;
|
||||||
|
this.ppl[part.id] = part;
|
||||||
|
this.emit("participant added", part);
|
||||||
|
this.emit("count", this.countParticipants());
|
||||||
|
} else {
|
||||||
|
Object.keys(update).forEach(key => {
|
||||||
|
part[key] = update[key];
|
||||||
|
});
|
||||||
|
if (!update.tag) delete part.tag;
|
||||||
|
if (!update.vanished) delete part.vanished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
participantMoveMouse(update) {
|
||||||
|
var part = this.ppl[update.id] || null;
|
||||||
|
if (part !== null) {
|
||||||
|
part.x = update.x;
|
||||||
|
part.y = update.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeParticipant(id) {
|
||||||
|
if (this.ppl.hasOwnProperty(id)) {
|
||||||
|
var part = this.ppl[id];
|
||||||
|
delete this.ppl[id];
|
||||||
|
this.emit("participant removed", part);
|
||||||
|
this.emit("count", this.countParticipants());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findParticipantById(id) {
|
||||||
|
return this.ppl[id] || this.offlineParticipant;
|
||||||
|
}
|
||||||
|
|
||||||
|
isOwner() {
|
||||||
|
return (
|
||||||
|
this.channel &&
|
||||||
|
this.channel.crown &&
|
||||||
|
this.channel.crown.participantId === this.participantId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
preventsPlaying() {
|
||||||
|
return (
|
||||||
|
this.isConnected() &&
|
||||||
|
!this.isOwner() &&
|
||||||
|
this.getChannelSetting("crownsolo") === true &&
|
||||||
|
!this.permissions.playNotesAnywhere
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveServerTime(time, echo) {
|
||||||
|
var self = this;
|
||||||
|
var now = Date.now();
|
||||||
|
var target = time - now;
|
||||||
|
// console.log("Target serverTimeOffset: " + target);
|
||||||
|
var duration = 1000;
|
||||||
|
var step = 0;
|
||||||
|
var steps = 50;
|
||||||
|
var step_ms = duration / steps;
|
||||||
|
var difference = target - this.serverTimeOffset;
|
||||||
|
var inc = difference / steps;
|
||||||
|
var iv;
|
||||||
|
iv = setInterval(function () {
|
||||||
|
self.serverTimeOffset += inc;
|
||||||
|
if (++step >= steps) {
|
||||||
|
clearInterval(iv);
|
||||||
|
// console.log("serverTimeOffset reached: " + self.serverTimeOffset);
|
||||||
|
self.serverTimeOffset = target;
|
||||||
|
}
|
||||||
|
}, step_ms);
|
||||||
|
// smoothen
|
||||||
|
|
||||||
|
// this.serverTimeOffset = time - now; // mostly time zone offset ... also the lags so todo smoothen this
|
||||||
|
// not smooth:
|
||||||
|
// if(echo) this.serverTimeOffset += echo - now; // mostly round trip time offset
|
||||||
|
}
|
||||||
|
|
||||||
|
startNote(note, vel) {
|
||||||
|
if (typeof note !== "string") return;
|
||||||
|
if (this.isConnected()) {
|
||||||
|
var vel = typeof vel === "undefined" ? undefined : +vel.toFixed(3);
|
||||||
|
if (!this.noteBufferTime) {
|
||||||
|
this.noteBufferTime = Date.now();
|
||||||
|
this.noteBuffer.push({ n: note, v: vel });
|
||||||
|
} else {
|
||||||
|
this.noteBuffer.push({
|
||||||
|
d: Date.now() - this.noteBufferTime,
|
||||||
|
n: note,
|
||||||
|
v: vel
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopNote(note) {
|
||||||
|
if (typeof note !== "string") return;
|
||||||
|
if (this.isConnected()) {
|
||||||
|
if (!this.noteBufferTime) {
|
||||||
|
this.noteBufferTime = Date.now();
|
||||||
|
this.noteBuffer.push({ n: note, s: 1 });
|
||||||
|
} else {
|
||||||
|
this.noteBuffer.push({
|
||||||
|
d: Date.now() - this.noteBufferTime,
|
||||||
|
n: note,
|
||||||
|
s: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendPing() {
|
||||||
|
var msg = { m: "t", e: Date.now() };
|
||||||
|
this.sendArray([msg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoginInfo(loginInfo) {
|
||||||
|
this.loginInfo = loginInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.Client = Client;
|
||||||
function mixin(obj1, obj2) {
|
|
||||||
for(var i in obj2) {
|
|
||||||
if(obj2.hasOwnProperty(i)) {
|
|
||||||
obj1[i] = obj2[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function Client(uri) {
|
|
||||||
EventEmitter.call(this);
|
|
||||||
this.uri = uri;
|
|
||||||
this.ws = undefined;
|
|
||||||
this.serverTimeOffset = 0;
|
|
||||||
this.user = undefined;
|
|
||||||
this.participantId = undefined;
|
|
||||||
this.channel = undefined;
|
|
||||||
this.ppl = {};
|
|
||||||
this.connectionTime = undefined;
|
|
||||||
this.connectionAttempts = 0;
|
|
||||||
this.desiredChannelId = undefined;
|
|
||||||
this.desiredChannelSettings = undefined;
|
|
||||||
this.pingInterval = undefined;
|
|
||||||
this.canConnect = false;
|
|
||||||
this.noteBuffer = [];
|
|
||||||
this.noteBufferTime = 0;
|
|
||||||
this.noteFlushInterval = undefined;
|
|
||||||
this['🐈'] = 0;
|
|
||||||
|
|
||||||
this.bindEventListeners();
|
|
||||||
|
|
||||||
this.emit("status", "(Offline mode)");
|
|
||||||
};
|
|
||||||
|
|
||||||
mixin(Client.prototype, EventEmitter.prototype);
|
|
||||||
|
|
||||||
Client.prototype.constructor = Client;
|
|
||||||
|
|
||||||
Client.prototype.isSupported = function() {
|
|
||||||
return typeof WebSocket === "function";
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.isConnected = function() {
|
|
||||||
return this.isSupported() && this.ws && this.ws.readyState === WebSocket.OPEN;
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.isConnecting = function() {
|
|
||||||
return this.isSupported() && this.ws && this.ws.readyState === WebSocket.CONNECTING;
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.start = function() {
|
|
||||||
this.canConnect = true;
|
|
||||||
this.connect();
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.stop = function() {
|
|
||||||
this.canConnect = false;
|
|
||||||
this.ws.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.connect = function() {
|
|
||||||
if(!this.canConnect || !this.isSupported() || this.isConnected() || this.isConnecting())
|
|
||||||
return;
|
|
||||||
this.emit("status", "Connecting...");
|
|
||||||
if(typeof module !== "undefined") {
|
|
||||||
// nodejsicle
|
|
||||||
this.ws = new WebSocket(this.uri, {
|
|
||||||
origin: "https://www.multiplayerpiano.com"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// browseroni
|
|
||||||
this.ws = new WebSocket(this.uri);
|
|
||||||
}
|
|
||||||
var self = this;
|
|
||||||
this.ws.addEventListener("close", function(evt) {
|
|
||||||
self.user = undefined;
|
|
||||||
self.participantId = undefined;
|
|
||||||
self.channel = undefined;
|
|
||||||
self.setParticipants([]);
|
|
||||||
clearInterval(self.pingInterval);
|
|
||||||
clearInterval(self.noteFlushInterval);
|
|
||||||
|
|
||||||
self.emit("disconnect", evt);
|
|
||||||
self.emit("status", "Offline mode");
|
|
||||||
|
|
||||||
// reconnect!
|
|
||||||
if(self.connectionTime) {
|
|
||||||
self.connectionTime = undefined;
|
|
||||||
self.connectionAttempts = 0;
|
|
||||||
} else {
|
|
||||||
++self.connectionAttempts;
|
|
||||||
}
|
|
||||||
var ms_lut = [50, 2950, 7000, 10000];
|
|
||||||
var idx = self.connectionAttempts;
|
|
||||||
if(idx >= ms_lut.length) idx = ms_lut.length - 1;
|
|
||||||
var ms = ms_lut[idx];
|
|
||||||
setTimeout(self.connect.bind(self), ms);
|
|
||||||
});
|
|
||||||
this.ws.addEventListener("error", function(err) {
|
|
||||||
self.emit("wserror", err);
|
|
||||||
self.ws.close(); // self.ws.emit("close");
|
|
||||||
});
|
|
||||||
this.ws.addEventListener("open", function(evt) {
|
|
||||||
self.connectionTime = Date.now();
|
|
||||||
self.sendArray([{"m": "hi", "🐈": self['🐈']++ || undefined }]);
|
|
||||||
self.pingInterval = setInterval(function() {
|
|
||||||
self.sendArray([{m: "t", e: Date.now()}]);
|
|
||||||
}, 20000);
|
|
||||||
//self.sendArray([{m: "t", e: Date.now()}]);
|
|
||||||
self.noteBuffer = [];
|
|
||||||
self.noteBufferTime = 0;
|
|
||||||
self.noteFlushInterval = setInterval(function() {
|
|
||||||
if(self.noteBufferTime && self.noteBuffer.length > 0) {
|
|
||||||
self.sendArray([{m: "n", t: self.noteBufferTime + self.serverTimeOffset, n: self.noteBuffer}]);
|
|
||||||
self.noteBufferTime = 0;
|
|
||||||
self.noteBuffer = [];
|
|
||||||
}
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
self.emit("connect");
|
|
||||||
self.emit("status", "Joining channel...");
|
|
||||||
});
|
|
||||||
this.ws.addEventListener("message", function(evt) {
|
|
||||||
var transmission = JSON.parse(evt.data);
|
|
||||||
for(var i = 0; i < transmission.length; i++) {
|
|
||||||
var msg = transmission[i];
|
|
||||||
self.emit(msg.m, msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.bindEventListeners = function() {
|
|
||||||
var self = this;
|
|
||||||
this.on("hi", function(msg) {
|
|
||||||
self.user = msg.u;
|
|
||||||
self.receiveServerTime(msg.t, msg.e || undefined);
|
|
||||||
if(self.desiredChannelId) {
|
|
||||||
self.setChannel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.on("t", function(msg) {
|
|
||||||
self.receiveServerTime(msg.t, msg.e || undefined);
|
|
||||||
});
|
|
||||||
this.on("ch", function(msg) {
|
|
||||||
self.desiredChannelId = msg.ch._id;
|
|
||||||
self.desiredChannelSettings = msg.ch.settings;
|
|
||||||
self.channel = msg.ch;
|
|
||||||
if(msg.p) self.participantId = msg.p;
|
|
||||||
self.setParticipants(msg.ppl);
|
|
||||||
});
|
|
||||||
this.on("p", function(msg) {
|
|
||||||
self.participantUpdate(msg);
|
|
||||||
self.emit("participant update", self.findParticipantById(msg.id));
|
|
||||||
});
|
|
||||||
this.on("m", function(msg) {
|
|
||||||
if(self.ppl.hasOwnProperty(msg.id)) {
|
|
||||||
self.participantUpdate(msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.on("bye", function(msg) {
|
|
||||||
self.removeParticipant(msg.p);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.send = function(raw) {
|
|
||||||
if(this.isConnected()) this.ws.send(raw);
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.sendArray = function(arr) {
|
|
||||||
this.send(JSON.stringify(arr));
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.setChannel = function(id, set) {
|
|
||||||
this.desiredChannelId = id || this.desiredChannelId || "lobby";
|
|
||||||
this.desiredChannelSettings = set || this.desiredChannelSettings || undefined;
|
|
||||||
this.sendArray([{m: "ch", _id: this.desiredChannelId, set: this.desiredChannelSettings}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.offlineChannelSettings = {
|
|
||||||
color:"#ecfaed"
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.getChannelSetting = function(key) {
|
|
||||||
if(!this.isConnected() || !this.channel || !this.channel.settings) {
|
|
||||||
return this.offlineChannelSettings[key];
|
|
||||||
}
|
|
||||||
return this.channel.settings[key];
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.setChannelSettings = function(settings) {
|
|
||||||
if(!this.isConnected() || !this.channel || !this.channel.settings) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.desiredChannelSettings){
|
|
||||||
for(var key in settings) {
|
|
||||||
this.desiredChannelSettings[key] = settings[key];
|
|
||||||
}
|
|
||||||
this.sendArray([{m: "chset", set: this.desiredChannelSettings}]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.offlineParticipant = {
|
|
||||||
_id: "",
|
|
||||||
name: "",
|
|
||||||
color: "#777"
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.getOwnParticipant = function() {
|
|
||||||
return this.findParticipantById(this.participantId);
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.setParticipants = function(ppl) {
|
|
||||||
// remove participants who left
|
|
||||||
for(var id in this.ppl) {
|
|
||||||
if(!this.ppl.hasOwnProperty(id)) continue;
|
|
||||||
var found = false;
|
|
||||||
for(var j = 0; j < ppl.length; j++) {
|
|
||||||
if(ppl[j].id === id) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found) {
|
|
||||||
this.removeParticipant(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// update all
|
|
||||||
for(var i = 0; i < ppl.length; i++) {
|
|
||||||
this.participantUpdate(ppl[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.countParticipants = function() {
|
|
||||||
var count = 0;
|
|
||||||
for(var i in this.ppl) {
|
|
||||||
if(this.ppl.hasOwnProperty(i)) ++count;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.participantUpdate = function(update) {
|
|
||||||
var part = this.ppl[update.id] || null;
|
|
||||||
if(part === null) {
|
|
||||||
part = update;
|
|
||||||
this.ppl[part.id] = part;
|
|
||||||
this.emit("participant added", part);
|
|
||||||
this.emit("count", this.countParticipants());
|
|
||||||
} else {
|
|
||||||
if(update.x) part.x = update.x;
|
|
||||||
if(update.y) part.y = update.y;
|
|
||||||
if(update.color) part.color = update.color;
|
|
||||||
if(update.name) part.name = update.name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.removeParticipant = function(id) {
|
|
||||||
if(this.ppl.hasOwnProperty(id)) {
|
|
||||||
var part = this.ppl[id];
|
|
||||||
delete this.ppl[id];
|
|
||||||
this.emit("participant removed", part);
|
|
||||||
this.emit("count", this.countParticipants());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.findParticipantById = function(id) {
|
|
||||||
return this.ppl[id] || this.offlineParticipant;
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.isOwner = function() {
|
|
||||||
return this.channel && this.channel.crown && this.channel.crown.participantId === this.participantId;
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.preventsPlaying = function() {
|
|
||||||
return this.isConnected() && !this.isOwner() && this.getChannelSetting("crownsolo") === true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.receiveServerTime = function(time, echo) {
|
|
||||||
var self = this;
|
|
||||||
var now = Date.now();
|
|
||||||
var target = time - now;
|
|
||||||
//console.log("Target serverTimeOffset: " + target);
|
|
||||||
var duration = 1000;
|
|
||||||
var step = 0;
|
|
||||||
var steps = 50;
|
|
||||||
var step_ms = duration / steps;
|
|
||||||
var difference = target - this.serverTimeOffset;
|
|
||||||
var inc = difference / steps;
|
|
||||||
var iv;
|
|
||||||
iv = setInterval(function() {
|
|
||||||
self.serverTimeOffset += inc;
|
|
||||||
if(++step >= steps) {
|
|
||||||
clearInterval(iv);
|
|
||||||
//console.log("serverTimeOffset reached: " + self.serverTimeOffset);
|
|
||||||
self.serverTimeOffset=target;
|
|
||||||
}
|
|
||||||
}, step_ms);
|
|
||||||
// smoothen
|
|
||||||
|
|
||||||
//this.serverTimeOffset = time - now; // mostly time zone offset ... also the lags so todo smoothen this
|
|
||||||
// not smooth:
|
|
||||||
//if(echo) this.serverTimeOffset += echo - now; // mostly round trip time offset
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.startNote = function(note, vel) {
|
|
||||||
if(this.isConnected()) {
|
|
||||||
var vel = typeof vel === "undefined" ? undefined : +vel.toFixed(3);
|
|
||||||
if(!this.noteBufferTime) {
|
|
||||||
this.noteBufferTime = Date.now();
|
|
||||||
this.noteBuffer.push({n: note, v: vel});
|
|
||||||
} else {
|
|
||||||
this.noteBuffer.push({d: Date.now() - this.noteBufferTime, n: note, v: vel});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.prototype.stopNote = function(note) {
|
|
||||||
if(this.isConnected()) {
|
|
||||||
if(!this.noteBufferTime) {
|
|
||||||
this.noteBufferTime = Date.now();
|
|
||||||
this.noteBuffer.push({n: note, s: 1});
|
|
||||||
} else {
|
|
||||||
this.noteBuffer.push({d: Date.now() - this.noteBufferTime, n: note, s: 1});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
65
index.html
65
index.html
|
@ -8,11 +8,76 @@
|
||||||
content="An online piano you can play alone or with others in real-time. MIDI support, 88 keys, velocity sensitive. You can show off your skill or chat while listening to others play."
|
content="An online piano you can play alone or with others in real-time. MIDI support, 88 keys, velocity sensitive. You can show off your skill or chat while listening to others play."
|
||||||
/>
|
/>
|
||||||
<link rel="stylesheet" href="/screen.css" />
|
<link rel="stylesheet" href="/screen.css" />
|
||||||
|
{% if usersConfig.enableTags %}
|
||||||
|
<link rel="stylesheet" href="/tags.css" />
|
||||||
|
{% endif %} {% if config.topButtons == "mppnet" %}
|
||||||
|
<link rel="stylesheet" href="/top-button.css" />
|
||||||
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{% if config.topButtons == "original" %}
|
||||||
<div id="social">
|
<div id="social">
|
||||||
<div id="more-button"></div>
|
<div id="more-button"></div>
|
||||||
</div>
|
</div>
|
||||||
|
{% elif config.topButtons == "mppnet" %}
|
||||||
|
<a
|
||||||
|
href="https://mpp.community/"
|
||||||
|
title="MPPNet Community Forum"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="mppcommunity-button icon-button top-button"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<img src="/mppcommunity.ico" style="vertical-align: middle" />
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/mppnet/frontend"
|
||||||
|
title="MPPNet Frontend Repo"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="github-button icon-button top-button"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<img src="/github.ico" style="vertical-align: middle" />
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://www.reddit.com/r/multiplayerpianonet/"
|
||||||
|
title="MPPNet Reddit"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="reddit-button icon-button top-button"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<img src="/reddit.ico" style="vertical-align: middle" />
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://discord.gg/338D2xMufC"
|
||||||
|
title="MPPNet Discord"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="discord-button icon-button top-button"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<img src="/discord.ico" style="vertical-align: middle" />
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://docs.google.com/document/d/1wQvGwQdaI8PuEjSWxKDDThVIoAlCYIxQOyfyi4o6HcM/edit?usp=sharing"
|
||||||
|
title="Multiplayer Piano Rules"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<button class="mpp-rules-button top-button" aria-hidden="true">
|
||||||
|
Rules
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="chat">
|
<div id="chat">
|
||||||
<ul></ul>
|
<ul></ul>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
85
screen.css
85
screen.css
|
@ -8,9 +8,6 @@
|
||||||
|
|
||||||
* {
|
* {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
|
@ -27,49 +24,27 @@ body {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property --color {
|
||||||
|
syntax: "<color>";
|
||||||
|
inherits: false;
|
||||||
|
/* initial-value: #ecfafd; */
|
||||||
|
initial-value: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property --color2 {
|
||||||
|
syntax: "<color>";
|
||||||
|
inherits: false;
|
||||||
|
/* initial-value: #c5d5d8; */
|
||||||
|
initial-value: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: #3b5054; /* Old browsers */
|
|
||||||
background: -moz-radial-gradient(
|
|
||||||
center,
|
|
||||||
ellipse cover,
|
|
||||||
#ecfafd 0%,
|
|
||||||
#c5d5d8 100%
|
|
||||||
); /* FF3.6+ */
|
|
||||||
background: -webkit-gradient(
|
|
||||||
radial,
|
|
||||||
center center,
|
|
||||||
0px,
|
|
||||||
center center,
|
|
||||||
100%,
|
|
||||||
color-stop(0%, #ecfafd),
|
|
||||||
color-stop(100%, #c5d5d8)
|
|
||||||
); /* Chrome,Safari4+ */
|
|
||||||
background: -webkit-radial-gradient(
|
|
||||||
center,
|
|
||||||
ellipse cover,
|
|
||||||
#ecfafd 0%,
|
|
||||||
#c5d5d8 100%
|
|
||||||
); /* Chrome10+,Safari5.1+ */
|
|
||||||
background: -o-radial-gradient(
|
|
||||||
center,
|
|
||||||
ellipse cover,
|
|
||||||
#ecfafd 0%,
|
|
||||||
#c5d5d8 100%
|
|
||||||
); /* Opera 12+ */
|
|
||||||
background: -ms-radial-gradient(
|
|
||||||
center,
|
|
||||||
ellipse cover,
|
|
||||||
#ecfafd 0%,
|
|
||||||
#c5d5d8 100%
|
|
||||||
); /* IE10+ */
|
|
||||||
background: radial-gradient(
|
background: radial-gradient(
|
||||||
ellipse at center,
|
ellipse at center,
|
||||||
#ecfafd 0%,
|
var(--color) 0%,
|
||||||
#c5d5d8 100%
|
var(--color2) 100%
|
||||||
); /* W3C */
|
); /* W3C */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ecfafd', endColorstr='#c5d5d8',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
|
transition: --color 1000ms, --color2 1000ms;
|
||||||
transition: background 1000ms linear;
|
|
||||||
-webkit-transition: background 1000ms linear;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -221,11 +196,11 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
.ease-out {
|
.ease-out {
|
||||||
transition: left 0.1s ease-out;
|
transition: left 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ease-in {
|
.ease-in {
|
||||||
transition: left 0.1s ease-in;
|
transition: left 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-left {
|
.slide-left {
|
||||||
|
@ -364,8 +339,10 @@ table {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
background: #9a9;
|
/* background: #9a9; */
|
||||||
|
background: var(--color2);
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
|
transition: --color 1000ms, --color2 1000ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
#room,
|
#room,
|
||||||
|
@ -794,9 +771,6 @@ table {
|
||||||
#modal,
|
#modal,
|
||||||
#modal * {
|
#modal * {
|
||||||
user-select: text;
|
user-select: text;
|
||||||
-webkit-user-select: text;
|
|
||||||
-moz-user-select: text;
|
|
||||||
-ms-user-select: text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog {
|
.dialog {
|
||||||
|
@ -1087,6 +1061,21 @@ table {
|
||||||
z-index: 300;
|
z-index: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#names .name.admin:before {
|
||||||
|
content: url("/silvercrown.png");
|
||||||
|
position: absolute;
|
||||||
|
top: -8px;
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#names .name.webmaster:before {
|
||||||
|
content: url("/cat.png");
|
||||||
|
position: absolute;
|
||||||
|
top: -8px;
|
||||||
|
left: 4px;
|
||||||
|
z-index: 302;
|
||||||
|
}
|
||||||
|
|
||||||
#piano {
|
#piano {
|
||||||
z-index: 400;
|
z-index: 400;
|
||||||
}
|
}
|
||||||
|
|
490
script.js
490
script.js
|
@ -1,15 +1,15 @@
|
||||||
// 钢琴
|
// 钢琴
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
var test_mode =
|
const test_mode =
|
||||||
window.location.hash &&
|
window.location.hash &&
|
||||||
window.location.hash.match(/^(?:#.+)*#test(?:#.+)*$/i);
|
window.location.hash.match(/^(?:#.+)*#test(?:#.+)*$/i);
|
||||||
|
|
||||||
var gSeeOwnCursor =
|
const gSeeOwnCursor =
|
||||||
window.location.hash &&
|
window.location.hash &&
|
||||||
window.location.hash.match(/^(?:#.+)*#seeowncursor(?:#.+)*$/i);
|
window.location.hash.match(/^(?:#.+)*#seeowncursor(?:#.+)*$/i);
|
||||||
|
|
||||||
var gMidiVolumeTest =
|
const gMidiVolumeTest =
|
||||||
window.location.hash &&
|
window.location.hash &&
|
||||||
window.location.hash.match(/^(?:#.+)*#midivolumetest(?:#.+)*$/i);
|
window.location.hash.match(/^(?:#.+)*#midivolumetest(?:#.+)*$/i);
|
||||||
|
|
||||||
|
@ -1166,8 +1166,13 @@ $(function () {
|
||||||
(isSecure ? "wss://" : "ws://") + window.location.hostname + ":" + port
|
(isSecure ? "wss://" : "ws://") + window.location.hostname + ":" + port
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let enableTokens = true;
|
||||||
|
let enableChallenge = true;
|
||||||
|
if (configs.usersConfig.tokenAuth == "none") enableTokens = false;
|
||||||
|
if (configs.usersConfig.browserChallenge == "none") enableChallenge = false;
|
||||||
|
|
||||||
gClient.setChannel(channel_id);
|
gClient.setChannel(channel_id);
|
||||||
gClient.start();
|
gClient.start(enableTokens, enableChallenge);
|
||||||
|
|
||||||
gClient.on("disconnect", function (evt) {
|
gClient.on("disconnect", function (evt) {
|
||||||
console.log(evt);
|
console.log(evt);
|
||||||
|
@ -1226,6 +1231,25 @@ $(function () {
|
||||||
part.nameDiv = $("#names")[0].appendChild(div);
|
part.nameDiv = $("#names")[0].appendChild(div);
|
||||||
$(part.nameDiv).fadeIn(2000);
|
$(part.nameDiv).fadeIn(2000);
|
||||||
|
|
||||||
|
if (part.tag) {
|
||||||
|
if (configs.usersConfig.enableTags) {
|
||||||
|
console.log(part.tag);
|
||||||
|
const tag = document.createElement("div");
|
||||||
|
$(tag).addClass("nametag");
|
||||||
|
$(tag).text(part.tag.text);
|
||||||
|
$(tag).css("background", part.tag.color);
|
||||||
|
part.tagDiv = $(part.nameDiv).prepend(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.tag.text === "ADMIN") {
|
||||||
|
$(part.nameDiv).addClass("admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.tag.text === "OWNER") {
|
||||||
|
$(part.nameDiv).addClass("webmaster");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sort names
|
// sort names
|
||||||
var arr = $("#names .name");
|
var arr = $("#names .name");
|
||||||
arr.sort(function (a, b) {
|
arr.sort(function (a, b) {
|
||||||
|
@ -1275,6 +1299,24 @@ $(function () {
|
||||||
.find(".name")
|
.find(".name")
|
||||||
.text(name)
|
.text(name)
|
||||||
.css("background-color", color);
|
.css("background-color", color);
|
||||||
|
if (part.tag) {
|
||||||
|
if (configs.usersConfig.enableTags) {
|
||||||
|
console.log(part.tag);
|
||||||
|
const tag = document.createElement("div");
|
||||||
|
$(tag).addClass("nametag");
|
||||||
|
$(tag).text(part.tag.text);
|
||||||
|
$(tag).css("background", part.tag.color);
|
||||||
|
part.tagDiv = $(part.nameDiv).prepend(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.tag.text === "ADMIN") {
|
||||||
|
$(part.nameDiv).addClass("admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.tag.text === "OWNER") {
|
||||||
|
$(part.nameDiv).addClass("webmaster");
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
gClient.on("ch", function (msg) {
|
gClient.on("ch", function (msg) {
|
||||||
for (var id in gClient.ppl) {
|
for (var id in gClient.ppl) {
|
||||||
|
@ -1559,56 +1601,18 @@ $(function () {
|
||||||
|
|
||||||
var bottom = document.getElementById("bottom");
|
var bottom = document.getElementById("bottom");
|
||||||
|
|
||||||
var duration = 50;
|
document.body.style.setProperty("--color", color1.toHexa());
|
||||||
var step = 0;
|
document.body.style.setProperty("--color2", color2.toHexa());
|
||||||
var steps = 30;
|
|
||||||
var step_ms = duration / steps;
|
bottom.style.setProperty("--color", color1.toHexa());
|
||||||
var difference = new Color(color1.r, color1.g, color1.b);
|
bottom.style.setProperty("--color2", color2.toHexa());
|
||||||
difference.r -= old_color1.r;
|
|
||||||
difference.g -= old_color1.g;
|
|
||||||
difference.b -= old_color1.b;
|
|
||||||
var inc1 = new Color(
|
|
||||||
difference.r / steps,
|
|
||||||
difference.g / steps,
|
|
||||||
difference.b / steps
|
|
||||||
);
|
|
||||||
difference = new Color(color2.r, color2.g, color2.b);
|
|
||||||
difference.r -= old_color2.r;
|
|
||||||
difference.g -= old_color2.g;
|
|
||||||
difference.b -= old_color2.b;
|
|
||||||
var inc2 = new Color(
|
|
||||||
difference.r / steps,
|
|
||||||
difference.g / steps,
|
|
||||||
difference.b / steps
|
|
||||||
);
|
|
||||||
var iv;
|
|
||||||
iv = setInterval(function () {
|
|
||||||
old_color1.add(inc1.r, inc1.g, inc1.b);
|
|
||||||
old_color2.add(inc2.r, inc2.g, inc2.b);
|
|
||||||
document.body.style.background =
|
|
||||||
"radial-gradient(ellipse at center, " +
|
|
||||||
old_color1.toHexa() +
|
|
||||||
" 0%," +
|
|
||||||
old_color2.toHexa() +
|
|
||||||
" 100%)";
|
|
||||||
bottom.style.background = old_color2.toHexa();
|
|
||||||
if (++step >= steps) {
|
|
||||||
clearInterval(iv);
|
|
||||||
old_color1 = color1;
|
|
||||||
old_color2 = color2;
|
|
||||||
document.body.style.background =
|
|
||||||
"radial-gradient(ellipse at center, " +
|
|
||||||
color1.toHexa() +
|
|
||||||
" 0%," +
|
|
||||||
color2.toHexa() +
|
|
||||||
" 100%)";
|
|
||||||
bottom.style.background = color2.toHexa();
|
|
||||||
}
|
|
||||||
}, step_ms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setColorToDefault() {
|
function setColorToDefault() {
|
||||||
setColor("#000000", "#000000");
|
setColor(
|
||||||
|
configs.urlChannel.settings.color || "#000000",
|
||||||
|
configs.urlChannel.settings.color2 || "#000000"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setColorToDefault();
|
setColorToDefault();
|
||||||
|
@ -1616,7 +1620,6 @@ $(function () {
|
||||||
gClient.on("ch", function (ch) {
|
gClient.on("ch", function (ch) {
|
||||||
if (ch.ch.settings) {
|
if (ch.ch.settings) {
|
||||||
if (ch.ch.settings.color) {
|
if (ch.ch.settings.color) {
|
||||||
console.log("debug!!!", ch.ch.settings);
|
|
||||||
setColor(ch.ch.settings.color, ch.ch.settings.color2);
|
setColor(ch.ch.settings.color, ch.ch.settings.color2);
|
||||||
} else {
|
} else {
|
||||||
setColorToDefault();
|
setColorToDefault();
|
||||||
|
@ -2045,7 +2048,7 @@ $(function () {
|
||||||
eles.remove();
|
eles.remove();
|
||||||
}
|
}
|
||||||
this.domElement = $(
|
this.domElement = $(
|
||||||
'<div class="notification"><div class="notification-body"><div class="title"></div>' +
|
'<div class="notification" style="display: none;"><div class="notification-body"><div class="title"></div>' +
|
||||||
'<div class="text"></div></div><div class="x">Ⓧ</div></div>'
|
'<div class="text"></div></div><div class="x">Ⓧ</div></div>'
|
||||||
);
|
);
|
||||||
this.domElement[0].id = this.id;
|
this.domElement[0].id = this.id;
|
||||||
|
@ -2070,6 +2073,8 @@ $(function () {
|
||||||
self.close();
|
self.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(this.domElement).fadeIn(100);
|
||||||
|
|
||||||
if (this.duration > 0) {
|
if (this.duration > 0) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
self.close();
|
self.close();
|
||||||
|
@ -2098,7 +2103,7 @@ $(function () {
|
||||||
Notification.prototype.close = function () {
|
Notification.prototype.close = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
window.removeEventListener("resize", this.onresize);
|
window.removeEventListener("resize", this.onresize);
|
||||||
this.domElement.fadeOut(500, function () {
|
this.domElement.fadeOut(250, function () {
|
||||||
self.domElement.remove();
|
self.domElement.remove();
|
||||||
self.emit("close");
|
self.emit("close");
|
||||||
});
|
});
|
||||||
|
@ -2239,16 +2244,24 @@ $(function () {
|
||||||
var room_name = "Room" + Math.floor(Math.random() * 1000000000000);
|
var room_name = "Room" + Math.floor(Math.random() * 1000000000000);
|
||||||
changeRoom(room_name, "right", { visible: false });
|
changeRoom(room_name, "right", { visible: false });
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
new Notification({
|
let html =
|
||||||
id: "share",
|
"You are playing alone in a room by yourself, but you can always invite \
|
||||||
title: "Playing alone",
|
friends by sending them the link.";
|
||||||
html:
|
|
||||||
|
if (configs.config.playingAloneSocialLinks) {
|
||||||
|
html =
|
||||||
"You are playing alone in a room by yourself, but you can always invite \
|
"You are playing alone in a room by yourself, but you can always invite \
|
||||||
friends by sending them the link.<br/><br/>\
|
friends by sending them the link.<br/><br/>\
|
||||||
<a href=\"#\" onclick=\"window.open('https://www.facebook.com/sharer/sharer.php?u='+encodeURIComponent(location.href),'facebook-share-dialog','width=626,height=436');return false;\">Share on Facebook</a><br/><br/>\
|
<a href=\"#\" onclick=\"window.open('https://www.facebook.com/sharer/sharer.php?u='+encodeURIComponent(location.href),'facebook-share-dialog','width=626,height=436');return false;\">Share on Facebook</a><br/><br/>\
|
||||||
<a href=\"http://twitter.com/home?status=" +
|
<a href=\"http://twitter.com/home?status=" +
|
||||||
encodeURIComponent(location.href) +
|
encodeURIComponent(location.href) +
|
||||||
'" target="_blank">Tweet</a>',
|
'" target="_blank">Tweet</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
new Notification({
|
||||||
|
id: "share",
|
||||||
|
title: "Playing alone",
|
||||||
|
html,
|
||||||
duration: 25000
|
duration: 25000
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
@ -2279,8 +2292,8 @@ $(function () {
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
$(document).off("keydown", modalHandleEsc);
|
$(document).off("keydown", modalHandleEsc);
|
||||||
$("#modal").fadeOut(100);
|
$("#modal").fadeOut(300);
|
||||||
$("#modal #modals > *").hide();
|
// $("#modal #modals > *").hide();
|
||||||
captureKeyboard();
|
captureKeyboard();
|
||||||
gModal = null;
|
gModal = null;
|
||||||
}
|
}
|
||||||
|
@ -2302,6 +2315,18 @@ $(function () {
|
||||||
closeModal();
|
closeModal();
|
||||||
changeRoom(name, "right", settings);
|
changeRoom(name, "right", settings);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
let html =
|
||||||
|
"You can invite friends to your room by sending them the link.<br/><br/>\
|
||||||
|
<a href=\"#\" onclick=\"window.open('https://www.facebook.com/sharer/sharer.php?u='+encodeURIComponent(location.href),'facebook-share-dialog','width=626,height=436');return false;\">Share on Facebook</a><br/><br/>\
|
||||||
|
<a href=\"http://twitter.com/home?status=" +
|
||||||
|
encodeURIComponent(location.href) +
|
||||||
|
'" target="_blank">Tweet</a>';
|
||||||
|
|
||||||
|
if (configs.config.createdRoomSocialLinks) {
|
||||||
|
html =
|
||||||
|
"You can invite friends to your room by sending them the link.";
|
||||||
|
}
|
||||||
|
|
||||||
new Notification({
|
new Notification({
|
||||||
id: "share",
|
id: "share",
|
||||||
title: "Created a Room",
|
title: "Created a Room",
|
||||||
|
@ -2359,27 +2384,33 @@ $(function () {
|
||||||
var t = 0,
|
var t = 0,
|
||||||
d = 100;
|
d = 100;
|
||||||
|
|
||||||
$("#piano").addClass("slide");
|
if (configs.config.enableSlide) {
|
||||||
|
$("#piano").addClass("slide");
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
$("#piano")
|
|
||||||
.addClass("ease-out")
|
|
||||||
.addClass("slide-" + opposite);
|
|
||||||
setTimeout(function () {
|
|
||||||
$("#piano")
|
$("#piano")
|
||||||
.removeClass("ease-out")
|
.addClass("ease-out")
|
||||||
.removeClass("slide-" + opposite)
|
.addClass("slide-" + opposite);
|
||||||
.addClass("slide-" + direction);
|
setTimeout(function () {
|
||||||
}, (t += d));
|
$("#piano")
|
||||||
setTimeout(function () {
|
.removeClass("ease-out")
|
||||||
$("#piano")
|
.removeClass("slide-" + opposite)
|
||||||
.addClass("ease-in")
|
.addClass("slide-" + direction);
|
||||||
.removeClass("slide-" + direction);
|
}, (t += d));
|
||||||
}, (t += d));
|
setTimeout(function () {
|
||||||
setTimeout(function () {
|
$("#piano")
|
||||||
$("#piano").removeClass("ease-in");
|
.addClass("ease-in")
|
||||||
}, (t += d));
|
.removeClass("slide-" + direction);
|
||||||
});
|
}, (t += d));
|
||||||
|
setTimeout(function () {
|
||||||
|
$("#piano").removeClass("ease-in");
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
$("#piano").removeClass("slide");
|
||||||
|
}, d);
|
||||||
|
}, (t += d));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gHistoryDepth = 0;
|
var gHistoryDepth = 0;
|
||||||
|
@ -2939,105 +2970,105 @@ $(function () {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
window.onerror = function (message, url, line) {
|
// window.onerror = function (message, url, line) {
|
||||||
var url = url || "(no url)";
|
// var url = url || "(no url)";
|
||||||
var line = line || "(no line)";
|
// var line = line || "(no line)";
|
||||||
// errors in socket.io
|
// // errors in socket.io
|
||||||
if (url.indexOf("socket.io.js") !== -1) {
|
// if (url.indexOf("socket.io.js") !== -1) {
|
||||||
if (message.indexOf("INVALID_STATE_ERR") !== -1) return;
|
// if (message.indexOf("INVALID_STATE_ERR") !== -1) return;
|
||||||
if (message.indexOf("InvalidStateError") !== -1) return;
|
// if (message.indexOf("InvalidStateError") !== -1) return;
|
||||||
if (message.indexOf("DOM Exception 11") !== -1) return;
|
// if (message.indexOf("DOM Exception 11") !== -1) return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Property 'open' of object #<c> is not a function"
|
// "Property 'open' of object #<c> is not a function"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf("Cannot call method 'close' of undefined") !==
|
// message.indexOf("Cannot call method 'close' of undefined") !==
|
||||||
-1
|
// -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (message.indexOf("Cannot call method 'close' of null") !== -1)
|
// if (message.indexOf("Cannot call method 'close' of null") !== -1)
|
||||||
return;
|
// return;
|
||||||
if (message.indexOf("Cannot call method 'onClose' of null") !== -1)
|
// if (message.indexOf("Cannot call method 'onClose' of null") !== -1)
|
||||||
return;
|
// return;
|
||||||
if (message.indexOf("Cannot call method 'payload' of null") !== -1)
|
// if (message.indexOf("Cannot call method 'payload' of null") !== -1)
|
||||||
return;
|
// return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Unable to get value of the property 'close'"
|
// "Unable to get value of the property 'close'"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (message.indexOf("NS_ERROR_NOT_CONNECTED") !== -1) return;
|
// if (message.indexOf("NS_ERROR_NOT_CONNECTED") !== -1) return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Unable to get property 'close' of undefined or null reference"
|
// "Unable to get property 'close' of undefined or null reference"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Unable to get value of the property 'close': object is null or undefined"
|
// "Unable to get value of the property 'close': object is null or undefined"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (message.indexOf("this.transport is null") !== -1) return;
|
// if (message.indexOf("this.transport is null") !== -1) return;
|
||||||
}
|
// }
|
||||||
// errors in soundmanager2
|
// // errors in soundmanager2
|
||||||
if (url.indexOf("soundmanager2.js") !== -1) {
|
// if (url.indexOf("soundmanager2.js") !== -1) {
|
||||||
// operation disabled in safe mode?
|
// // operation disabled in safe mode?
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Could not complete the operation due to error c00d36ef"
|
// "Could not complete the operation due to error c00d36ef"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (message.indexOf("_s.o._setVolume is not a function") !== -1)
|
// if (message.indexOf("_s.o._setVolume is not a function") !== -1)
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// errors in midibridge
|
// // errors in midibridge
|
||||||
if (url.indexOf("midibridge") !== -1) {
|
// if (url.indexOf("midibridge") !== -1) {
|
||||||
if (message.indexOf("Error calling method on NPObject") !== -1)
|
// if (message.indexOf("Error calling method on NPObject") !== -1)
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// too many failing extensions injected in my html
|
// // too many failing extensions injected in my html
|
||||||
if (url.indexOf(".js") !== url.length - 3) return;
|
// if (url.indexOf(".js") !== url.length - 3) return;
|
||||||
// extensions inject cross-domain embeds too
|
// // extensions inject cross-domain embeds too
|
||||||
if (url.toLowerCase().indexOf("multiplayerpiano.com") == -1) return;
|
// if (url.toLowerCase().indexOf("multiplayerpiano.com") == -1) return;
|
||||||
|
|
||||||
// errors in my code
|
// // errors in my code
|
||||||
if (url.indexOf("script.js") !== -1) {
|
// if (url.indexOf("script.js") !== -1) {
|
||||||
if (
|
// if (
|
||||||
message.indexOf("Object [object Object] has no method 'on'") !==
|
// message.indexOf("Object [object Object] has no method 'on'") !==
|
||||||
-1
|
// -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Object [object Object] has no method 'off'"
|
// "Object [object Object] has no method 'off'"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
if (
|
// if (
|
||||||
message.indexOf(
|
// message.indexOf(
|
||||||
"Property '$' of object [object Object] is not a function"
|
// "Property '$' of object [object Object] is not a function"
|
||||||
) !== -1
|
// ) !== -1
|
||||||
)
|
// )
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
var enc =
|
// var enc =
|
||||||
"/bugreport/" +
|
// "/bugreport/" +
|
||||||
(message ? encodeURIComponent(message) : "") +
|
// (message ? encodeURIComponent(message) : "") +
|
||||||
"/" +
|
// "/" +
|
||||||
(url ? encodeURIComponent(url) : "") +
|
// (url ? encodeURIComponent(url) : "") +
|
||||||
"/" +
|
// "/" +
|
||||||
(line ? encodeURIComponent(line) : "");
|
// (line ? encodeURIComponent(line) : "");
|
||||||
var img = new Image();
|
// var img = new Image();
|
||||||
img.src = enc;
|
// img.src = enc;
|
||||||
};
|
// };
|
||||||
|
|
||||||
// more button
|
// more button
|
||||||
(function () {
|
(function () {
|
||||||
|
@ -3085,7 +3116,8 @@ $(function () {
|
||||||
chat: chat,
|
chat: chat,
|
||||||
noteQuota: gNoteQuota,
|
noteQuota: gNoteQuota,
|
||||||
soundSelector: gSoundSelector,
|
soundSelector: gSoundSelector,
|
||||||
Notification: Notification
|
Notification: Notification,
|
||||||
|
configs
|
||||||
};
|
};
|
||||||
|
|
||||||
// record mp3
|
// record mp3
|
||||||
|
@ -3384,105 +3416,3 @@ $(function () {
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
function catSound() {
|
|
||||||
let sounds = [
|
|
||||||
"cat-sounds/meow1.mp3",
|
|
||||||
"cat-sounds/meow2.mp3",
|
|
||||||
"cat-sounds/meow3.mp3",
|
|
||||||
"cat-sounds/meow4.mp3",
|
|
||||||
"cat-sounds/meow5.mp3",
|
|
||||||
"cat-sounds/meow6.mp3",
|
|
||||||
"cat-sounds/meow7.mp3",
|
|
||||||
"cat-sounds/meow8.mp3",
|
|
||||||
"cat-sounds/meow9.mp3",
|
|
||||||
"cat-sounds/meow10.mp3"
|
|
||||||
];
|
|
||||||
let random = sounds[Math.floor(Math.random() * sounds.length)];
|
|
||||||
const meow = new Audio(random);
|
|
||||||
meow.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("more-button").onclick = catSound;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// misc
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// analytics
|
|
||||||
window.google_analytics_uacct = "UA-882009-7";
|
|
||||||
var _gaq = _gaq || [];
|
|
||||||
_gaq.push(["_setAccount", "UA-882009-7"]);
|
|
||||||
_gaq.push(["_trackPageview"]);
|
|
||||||
_gaq.push(["_setAllowAnchor", true]);
|
|
||||||
(function () {
|
|
||||||
var ga = document.createElement("script");
|
|
||||||
ga.type = "text/javascript";
|
|
||||||
ga.async = true;
|
|
||||||
ga.src =
|
|
||||||
("https:" == document.location.protocol
|
|
||||||
? "https://ssl"
|
|
||||||
: "http://www") + ".google-analytics.com/ga.js";
|
|
||||||
var s = document.getElementsByTagName("script")[0];
|
|
||||||
s.parentNode.insertBefore(ga, s);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// twitter
|
|
||||||
!(function (d, s, id) {
|
|
||||||
var js,
|
|
||||||
fjs = d.getElementsByTagName(s)[0];
|
|
||||||
if (!d.getElementById(id)) {
|
|
||||||
js = d.createElement(s);
|
|
||||||
js.id = id;
|
|
||||||
js.src = "//platform.twitter.com/widgets.js";
|
|
||||||
fjs.parentNode.insertBefore(js, fjs);
|
|
||||||
}
|
|
||||||
})(document, "script", "twitter-wjs");
|
|
||||||
|
|
||||||
// fb
|
|
||||||
(function (d, s, id) {
|
|
||||||
var js,
|
|
||||||
fjs = d.getElementsByTagName(s)[0];
|
|
||||||
if (d.getElementById(id)) return;
|
|
||||||
js = d.createElement(s);
|
|
||||||
js.id = id;
|
|
||||||
js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8";
|
|
||||||
fjs.parentNode.insertBefore(js, fjs);
|
|
||||||
})(document, "script", "facebook-jssdk");
|
|
||||||
|
|
||||||
// non-ad-free experience
|
|
||||||
/*(function() {
|
|
||||||
function adsOn() {
|
|
||||||
if(window.localStorage) {
|
|
||||||
var div = document.querySelector("#inclinations");
|
|
||||||
div.innerHTML = "Ads:<br>ON / <a id=\"adsoff\" href=\"#\">OFF</a>";
|
|
||||||
div.querySelector("#adsoff").addEventListener("click", adsOff);
|
|
||||||
localStorage.ads = true;
|
|
||||||
}
|
|
||||||
// adsterra
|
|
||||||
var script = document.createElement("script");
|
|
||||||
script.src = "//pl132070.puhtml.com/68/7a/97/687a978dd26d579c788cb41e352f5a41.js";
|
|
||||||
document.head.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
function adsOff() {
|
|
||||||
if(window.localStorage) localStorage.ads = false;
|
|
||||||
document.location.reload(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function noAds() {
|
|
||||||
var div = document.querySelector("#inclinations");
|
|
||||||
div.innerHTML = "Ads:<br><a id=\"adson\" href=\"#\">ON</a> / OFF";
|
|
||||||
div.querySelector("#adson").addEventListener("click", adsOn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(window.localStorage) {
|
|
||||||
if(localStorage.ads === undefined || localStorage.ads === "true")
|
|
||||||
adsOn();
|
|
||||||
else
|
|
||||||
noAds();
|
|
||||||
} else {
|
|
||||||
adsOn();
|
|
||||||
}
|
|
||||||
})();*/
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 164 B |
|
@ -0,0 +1,67 @@
|
||||||
|
.top-button {
|
||||||
|
height: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: #111;
|
||||||
|
border: 1px solid #444;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
|
-moz-border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-button:hover {
|
||||||
|
background: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-button.stuck {
|
||||||
|
background: rgba(204, 187, 170, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
position: fixed;
|
||||||
|
top: 6px;
|
||||||
|
z-index: 200;
|
||||||
|
width: 26px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mppcommunity-button {
|
||||||
|
right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discord-button {
|
||||||
|
right: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-button {
|
||||||
|
right: 66px;
|
||||||
|
background-color: white;
|
||||||
|
filter: invert(100%);
|
||||||
|
border-color: #c6c6c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-button:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reddit-button {
|
||||||
|
right: 96px;
|
||||||
|
z-index: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mpp-rules-button {
|
||||||
|
position: fixed;
|
||||||
|
right: 6px;
|
||||||
|
top: 32px;
|
||||||
|
z-index: 200;
|
||||||
|
}
|
Loading…
Reference in New Issue