diff options
| -rw-r--r-- | build/server.js | 4 | ||||
| -rw-r--r-- | res/client.js | 102 | ||||
| -rw-r--r-- | res/index.html | 1 | ||||
| -rw-r--r-- | res/langs/en.json | 1 | ||||
| -rw-r--r-- | res/langs/ru.json | 1 | ||||
| -rw-r--r-- | src/KeyCode.hx | 202 | ||||
| -rw-r--r-- | src/client/Buttons.hx | 57 | ||||
| -rw-r--r-- | src/client/ClientSettings.hx | 3 | ||||
| -rw-r--r-- | src/client/Main.hx | 18 |
9 files changed, 361 insertions, 28 deletions
diff --git a/build/server.js b/build/server.js index 7e5c7f8..5d559b7 100644 --- a/build/server.js +++ b/build/server.js @@ -3285,7 +3285,9 @@ server_HttpServer.proxyUrl = function(req,res) { if(url1.host == req.headers["host"]) { return false; } - var proxy = (url1.protocol == "https:" ? js_node_Https.request : js_node_Http.request)({ host : url1.host, port : Std.parseInt(url1.port), path : url1.pathname + url1.search, method : req.method},function(proxyRes) { + var url2 = url1.host; + var options = Std.parseInt(url1.port); + var proxy = (url1.protocol == "https:" ? js_node_Https.request : js_node_Http.request)({ host : url2, port : options, path : url1.pathname + url1.search, method : req.method},function(proxyRes) { res.writeHead(proxyRes.statusCode,proxyRes.headers); return proxyRes.pipe(res,{ end : true}); }); diff --git a/res/client.js b/res/client.js index cb8ea2a..d348a2d 100644 --- a/res/client.js +++ b/res/client.js @@ -764,26 +764,96 @@ client_Buttons.initNavBar = function(main) { client_Buttons.initTextButtons = function(main) { var synchThresholdBtn = window.document.querySelector("#synchThresholdBtn"); synchThresholdBtn.onclick = function(e) { - var secs = main.settings.synchThreshold + 1; + var secs = client_Buttons.settings.synchThreshold + 1; if(secs > 5) { secs = 1; } main.setSynchThreshold(secs); - client_Buttons.updateSynchThresholdBtn(main); + client_Buttons.updateSynchThresholdBtn(); synchThresholdBtn.blur(); return; }; - client_Buttons.updateSynchThresholdBtn(main); + client_Buttons.updateSynchThresholdBtn(); + var hotkeysBtn = window.document.querySelector("#hotkeysBtn"); + hotkeysBtn.onclick = function(e1) { + client_Buttons.settings.hotkeysEnabled = !client_Buttons.settings.hotkeysEnabled; + client_Settings.write(client_Buttons.settings); + client_Buttons.updateHotkeysBtn(); + hotkeysBtn.blur(); + return; + }; + client_Buttons.updateHotkeysBtn(); +}; +client_Buttons.initHotkeys = function(main,player) { + window.document.querySelector("#mediarefresh").title += " (Alt-R)"; + window.document.querySelector("#voteskip").title += " (Alt-S)"; + window.document.querySelector("#getplaylist").title += " (Alt-C)"; + window.document.querySelector("#fullscreenbtn").title += " (Alt-F)"; + window.document.querySelector("#leader_btn").title += " (Alt-L)"; + window.onkeydown = function(e) { + if(!client_Buttons.settings.hotkeysEnabled) { + return; + } + var target = e.target; + if(target.isContentEditable) { + return; + } + var tagName = target.tagName; + if(tagName == "INPUT" || tagName == "TEXTAREA") { + return; + } + var key = e.keyCode; + if(key == 8) { + e.preventDefault(); + } + if(!e.altKey) { + return; + } + switch(key) { + case 67: + window.document.querySelector("#getplaylist").onclick(); + break; + case 70: + window.document.querySelector("#fullscreenbtn").onclick(); + break; + case 76: + window.document.querySelector("#leader_btn").onclick(); + break; + case 80: + if((main.personal.group & 2) == 0) { + haxe_Timer.delay(function() { + player.pause(); + return; + },500); + } + window.document.querySelector("#leader_btn").onclick(); + break; + case 82: + window.document.querySelector("#mediarefresh").onclick(); + break; + case 83: + window.document.querySelector("#voteskip").onclick(); + break; + default: + return; + } + e.preventDefault(); + }; }; client_Buttons.hideMenus = function() { var menus = window.document.querySelectorAll(".dropdown-menu"); var _g = 0; while(_g < menus.length) menus[_g++].style.display = ""; }; -client_Buttons.updateSynchThresholdBtn = function(main) { - var tmp = "" + Lang.get("synchThreshold") + ": " + main.settings.synchThreshold; +client_Buttons.updateSynchThresholdBtn = function() { + var tmp = "" + Lang.get("synchThreshold") + ": " + client_Buttons.settings.synchThreshold; window.document.querySelector("#synchThresholdBtn").innerText = tmp + "s"; }; +client_Buttons.updateHotkeysBtn = function() { + var text = Lang.get("hotkeys"); + var state = client_Buttons.settings.hotkeysEnabled ? Lang.get("on") : Lang.get("off"); + window.document.querySelector("#hotkeysBtn").innerText = "" + text + ": " + state; +}; client_Buttons.initChatInput = function(main) { var guestName = window.document.querySelector("#guestname"); guestName.onkeydown = function(e) { @@ -946,7 +1016,7 @@ var client_Main = function(host,port) { if(port == "") { port = "80"; } - client_Settings.init({ version : 1, name : "", hash : "", isExtendedPlayer : false, chatSize : 40, playerSize : 60, synchThreshold : 2, isSwapped : false, isUserListHidden : false, latestLinks : []},$bind(this,this.settingsPatcher)); + client_Settings.init({ version : 2, name : "", hash : "", isExtendedPlayer : false, chatSize : 40, playerSize : 60, synchThreshold : 2, isSwapped : false, isUserListHidden : false, latestLinks : [], hotkeysEnabled : true},$bind(this,this.settingsPatcher)); this.settings = client_Settings.read(); this.initListeners(); this.onTimeGet = new haxe_Timer(this.settings.synchThreshold * 1000); @@ -961,6 +1031,7 @@ var client_Main = function(host,port) { }; Lang.init("langs",function() { client_Buttons.initTextButtons(_gthis); + client_Buttons.initHotkeys(_gthis,_gthis.player); _gthis.openWebSocket(host,port); return; }); @@ -971,11 +1042,16 @@ client_Main.main = function() { }; client_Main.prototype = { settingsPatcher: function(data,version) { - if(version == 1) { + switch(version) { + case 1: + data.hotkeysEnabled = true; + break; + case 2: throw new js__$Boot_HaxeError("skipped version " + version); - } else { + default: throw new js__$Boot_HaxeError("skipped version " + version); } + return data; } ,requestTime: function() { if(!this.isSyncActive) { @@ -1204,7 +1280,7 @@ client_Main.prototype = { var data = JSON.parse(e.data); var t = data.type; var t1 = t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null); - haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 326, className : "client.Main", methodName : "onMessage", customParams : [data[t1]]}); + haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 324, className : "client.Main", methodName : "onMessage", customParams : [data[t1]]}); switch(data.type) { case "AddVideo": this.player.addVideoItem(data.addVideo.item,data.addVideo.atEnd); @@ -1235,10 +1311,11 @@ client_Main.prototype = { if(this.player.getPlaybackRate() != data.getTime.rate) { this.player.setPlaybackRate(data.getTime.rate); } + var synchThreshold = this.settings.synchThreshold; var newTime = data.getTime.time; var time = this.player.getTime(); if((this.personal.group & 1 << ClientGroup.Leader._hx_index) != 0) { - if(Math.abs(time - newTime) < this.settings.synchThreshold) { + if(Math.abs(time - newTime) < synchThreshold) { return; } this.player.setTime(time,false); @@ -1252,7 +1329,7 @@ client_Main.prototype = { } else { this.player.pause(); } - if(Math.abs(time - newTime) < this.settings.synchThreshold) { + if(Math.abs(time - newTime) < synchThreshold) { return; } this.player.setTime(newTime); @@ -1329,9 +1406,10 @@ client_Main.prototype = { this.player.setPlaybackRate(data.setRate.rate); break; case "SetTime": + var synchThreshold1 = this.settings.synchThreshold; var newTime1 = data.setTime.time; var time1 = this.player.getTime(); - if(Math.abs(time1 - newTime1) < this.settings.synchThreshold) { + if(Math.abs(time1 - newTime1) < synchThreshold1) { return; } this.player.setTime(newTime1); diff --git a/res/index.html b/res/index.html index 27962d4..36d79be 100644 --- a/res/index.html +++ b/res/index.html @@ -35,6 +35,7 @@ <li class="dropdown"><a class="dropdown-toggle" href="#" data-toggle="dropdown">${settings}<b class="caret"></b></a> <ul class="dropdown-menu"> <li><a href="#" id="synchThresholdBtn">${synchThreshold}</a></li> + <li><a href="#" id="hotkeysBtn">${hotkeys}</a></li> </ul> </li> <li class="dropdown"><a class="dropdown-toggle" href="#" data-toggle="dropdown">${layout}<b class="caret"></b></a> diff --git a/res/langs/en.json b/res/langs/en.json index 3524b15..36cb672 100644 --- a/res/langs/en.json +++ b/res/langs/en.json @@ -27,6 +27,7 @@ "exit": "Exit", "settings": "Settings", "synchThreshold": "Synch Threshold", + "hotkeys": "Hotkeys", "channel": "Channel", "layout": "Layout", "swapLayout": "Swap Layout", diff --git a/res/langs/ru.json b/res/langs/ru.json index 8297c36..808eb56 100644 --- a/res/langs/ru.json +++ b/res/langs/ru.json @@ -27,6 +27,7 @@ "exit": "Выход", "settings": "Настройки", "synchThreshold": "Частота синхронизации", + "hotkeys": "Горячие клавиши", "channel": "Канал", "layout": "Разметка", "swapLayout": "Сменить разметку", diff --git a/src/KeyCode.hx b/src/KeyCode.hx new file mode 100644 index 0000000..c380329 --- /dev/null +++ b/src/KeyCode.hx @@ -0,0 +1,202 @@ +package; + +// https://github.com/Kode/Kha/blob/master/Sources/kha/input/KeyCode.hx +enum abstract KeyCode(Int) to Int { + var Unknown = 0; + var Back = 1; // Android + var Cancel = 3; + var Help = 6; + var Backspace = 8; + var Tab = 9; + var Clear = 12; + var Return = 13; + var Shift = 16; + var Control = 17; + var Alt = 18; + var Pause = 19; + var CapsLock = 20; + var Kana = 21; + var Hangul = 21; + var Eisu = 22; + var Junja = 23; + var Final = 24; + var Hanja = 25; + var Kanji = 25; + var Escape = 27; + var Convert = 28; + var NonConvert = 29; + var Accept = 30; + var ModeChange = 31; + var Space = 32; + var PageUp = 33; + var PageDown = 34; + var End = 35; + var Home = 36; + var Left = 37; + var Up = 38; + var Right = 39; + var Down = 40; + var Select = 41; + var Print = 42; + var Execute = 43; + var PrintScreen = 44; + var Insert = 45; + var Delete = 46; + var Zero = 48; + var One = 49; + var Two = 50; + var Three = 51; + var Four = 52; + var Five = 53; + var Six = 54; + var Seven = 55; + var Eight = 56; + var Nine = 57; + var Colon = 58; + var Semicolon = 59; + var LessThan = 60; + var Equals = 61; + var GreaterThan = 62; + var QuestionMark = 63; + var At = 64; + var A = 65; + var B = 66; + var C = 67; + var D = 68; + var E = 69; + var F = 70; + var G = 71; + var H = 72; + var I = 73; + var J = 74; + var K = 75; + var L = 76; + var M = 77; + var N = 78; + var O = 79; + var P = 80; + var Q = 81; + var R = 82; + var S = 83; + var T = 84; + var U = 85; + var V = 86; + var W = 87; + var X = 88; + var Y = 89; + var Z = 90; + var Win = 91; + var ContextMenu = 93; + var Sleep = 95; + var Numpad0 = 96; + var Numpad1 = 97; + var Numpad2 = 98; + var Numpad3 = 99; + var Numpad4 = 100; + var Numpad5 = 101; + var Numpad6 = 102; + var Numpad7 = 103; + var Numpad8 = 104; + var Numpad9 = 105; + var Multiply = 106; + var Add = 107; + var Separator = 108; + var Subtract = 109; + var Decimal = 110; + var Divide = 111; + var F1 = 112; + var F2 = 113; + var F3 = 114; + var F4 = 115; + var F5 = 116; + var F6 = 117; + var F7 = 118; + var F8 = 119; + var F9 = 120; + var F10 = 121; + var F11 = 122; + var F12 = 123; + var F13 = 124; + var F14 = 125; + var F15 = 126; + var F16 = 127; + var F17 = 128; + var F18 = 129; + var F19 = 130; + var F20 = 131; + var F21 = 132; + var F22 = 133; + var F23 = 134; + var F24 = 135; + var NumLock = 144; + var ScrollLock = 145; + var WinOemFjJisho = 146; + var WinOemFjMasshou = 147; + var WinOemFjTouroku = 148; + var WinOemFjLoya = 149; + var WinOemFjRoya = 150; + var Circumflex = 160; + var Exclamation = 161; + var DoubleQuote = 162; + var Hash = 163; + var Dollar = 164; + var Percent = 165; + var Ampersand = 166; + var Underscore = 167; + var OpenParen = 168; + var CloseParen = 169; + var Asterisk = 170; + var Plus = 171; + var Pipe = 172; + var HyphenMinus = 173; + var OpenCurlyBracket = 174; + var CloseCurlyBracket = 175; + var Tilde = 176; + var VolumeMute = 181; + var VolumeDown = 182; + var VolumeUp = 183; + var Comma = 188; + var Period = 190; + var Slash = 191; + var BackQuote = 192; + var OpenBracket = 219; + var BackSlash = 220; + var CloseBracket = 221; + var Quote = 222; + var Meta = 224; + var AltGr = 225; + var WinIcoHelp = 227; + var WinIco00 = 228; + var WinIcoClear = 230; + var WinOemReset = 233; + var WinOemJump = 234; + var WinOemPA1 = 235; + var WinOemPA2 = 236; + var WinOemPA3 = 237; + var WinOemWSCTRL = 238; + var WinOemCUSEL = 239; + var WinOemATTN = 240; + var WinOemFinish = 241; + var WinOemCopy = 242; + var WinOemAuto = 243; + var WinOemENLW = 244; + var WinOemBackTab = 245; + var ATTN = 246; + var CRSEL = 247; + var EXSEL = 248; + var EREOF = 249; + var Play = 250; + var Zoom = 251; + var PA1 = 253; + var WinOemClear = 254; + + function normalize():KeyCode { + return switch (this) { + case 91, 93: Meta; // left/right in Chrome + case 186: Semicolon; + case 187: Equals; + case 189: HyphenMinus; + default: cast this; + } + } +} diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx index a04b444..769cb25 100644 --- a/src/client/Buttons.hx +++ b/src/client/Buttons.hx @@ -288,13 +288,54 @@ class Buttons { public static function initTextButtons(main:Main):Void { final synchThresholdBtn = ge("#synchThresholdBtn"); synchThresholdBtn.onclick = e -> { - var secs = main.synchThreshold + 1; + var secs = settings.synchThreshold + 1; if (secs > 5) secs = 1; main.setSynchThreshold(secs); - updateSynchThresholdBtn(main); + updateSynchThresholdBtn(); synchThresholdBtn.blur(); } - updateSynchThresholdBtn(main); + updateSynchThresholdBtn(); + + final hotkeysBtn = ge("#hotkeysBtn"); + hotkeysBtn.onclick = e -> { + settings.hotkeysEnabled = !settings.hotkeysEnabled; + Settings.write(settings); + updateHotkeysBtn(); + hotkeysBtn.blur(); + } + updateHotkeysBtn(); + } + + public static function initHotkeys(main:Main, player:Player):Void { + ge("#mediarefresh").title += " (Alt-R)"; + ge("#voteskip").title += " (Alt-S)"; + ge("#getplaylist").title += " (Alt-C)"; + ge("#fullscreenbtn").title += " (Alt-F)"; + ge("#leader_btn").title += " (Alt-L)"; + window.onkeydown = function(e:KeyboardEvent) { + if (!settings.hotkeysEnabled) return; + final target:Element = cast e.target; + if (target.isContentEditable) return; + final tagName = target.tagName; + if (tagName == "INPUT" || tagName == "TEXTAREA") return; + final key:KeyCode = cast e.keyCode; + if (key == Backspace) e.preventDefault(); + if (!e.altKey) return; + switch (key) { + case R: ge("#mediarefresh").onclick(); + case S: ge("#voteskip").onclick(); + case C: ge("#getplaylist").onclick(); + case F: ge("#fullscreenbtn").onclick(); + case L: ge("#leader_btn").onclick(); + case P: + if (!main.isLeader()) { + Timer.delay(() -> player.pause(), 500); + } + ge("#leader_btn").onclick(); + default: return; + } + e.preventDefault(); + } } static function hideMenus():Void { @@ -302,12 +343,18 @@ class Buttons { for (menu in menus) menu.style.display = ""; } - static function updateSynchThresholdBtn(main:Main):Void { + static function updateSynchThresholdBtn():Void { final text = Lang.get("synchThreshold"); - final secs = main.synchThreshold; + final secs = settings.synchThreshold; ge("#synchThresholdBtn").innerText = '$text: ${secs}s'; } + static function updateHotkeysBtn():Void { + final text = Lang.get("hotkeys"); + final state = settings.hotkeysEnabled ? Lang.get("on") : Lang.get("off"); + ge("#hotkeysBtn").innerText = '$text: $state'; + } + static function initChatInput(main:Main):Void { final guestName:InputElement = cast ge("#guestname"); guestName.onkeydown = e -> { diff --git a/src/client/ClientSettings.hx b/src/client/ClientSettings.hx index 4e931d3..213d463 100644 --- a/src/client/ClientSettings.hx +++ b/src/client/ClientSettings.hx @@ -10,5 +10,6 @@ typedef ClientSettings = { synchThreshold:Int, isSwapped:Bool, isUserListHidden:Bool, - latestLinks:Array<String> + latestLinks:Array<String>, + hotkeysEnabled:Bool } diff --git a/src/client/Main.hx b/src/client/Main.hx index 9ecae82..deeb2ec 100644 --- a/src/client/Main.hx +++ b/src/client/Main.hx @@ -22,10 +22,9 @@ using ClientTools; class Main { - static inline var SETTINGS_VERSION = 1; + static inline var SETTINGS_VERSION = 2; public final settings:ClientSettings; public var isSyncActive = true; - public var synchThreshold(get, never):Int; final clients:Array<Client> = []; var pageTitle = document.title; final host:String; @@ -59,7 +58,8 @@ class Main { synchThreshold: 2, isSwapped: false, isUserListHidden: false, - latestLinks: [] + latestLinks: [], + hotkeysEnabled: true } Settings.init(defaults, settingsPatcher); settings = Settings.read(); @@ -76,18 +76,16 @@ class Main { } Lang.init("langs", () -> { Buttons.initTextButtons(this); + Buttons.initHotkeys(this, player); openWebSocket(host, port); }); } - inline function get_synchThreshold():Int { - return settings.synchThreshold; - } - function settingsPatcher(data:Any, version:Int):Any { switch (version) { - // case 1: - // final data:ClientSettings = data; + case 1: + final data:ClientSettings = data; + data.hotkeysEnabled = true; case SETTINGS_VERSION, _: throw 'skipped version $version'; } @@ -400,6 +398,7 @@ class Main { player.setPlaybackRate(data.getTime.rate); } + final synchThreshold = settings.synchThreshold; final newTime = data.getTime.time; final time = player.getTime(); if (isLeader()) { @@ -416,6 +415,7 @@ class Main { player.setTime(newTime); case SetTime: + final synchThreshold = settings.synchThreshold; final newTime = data.setTime.time; final time = player.getTime(); if (Math.abs(time - newTime) < synchThreshold) return; |
