|
// ==UserScript== |
|
// @name Games Done Quick Schedule Highlight |
|
// @namespace FichteFoll |
|
// @author FichteFoll |
|
// @description Highlights currently active Event on GDQ schedule and adds an anchor. Also non-AM/PM timestamps. |
|
// @include https://gamesdonequick.com/schedule* |
|
// @version 0.1.2 |
|
// @updateURL https://gist.github.com/FichteFoll/642b567943c0f957eef9ce32601ce944/raw/Games_Done_Quick_Schedule_Enhancer.user.js |
|
// @grant none |
|
// ==/UserScript== |
|
|
|
/* |
|
* The MIT License (MIT) |
|
* |
|
* Copyright (c) 2016 FichteFoll <[email protected]> |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
* of this software and associated documentation files (the "Software"), to deal |
|
* in the Software without restriction, including without limitation the rights |
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
* copies of the Software, and to permit persons to whom the Software is |
|
* furnished to do so, subject to the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be included in all |
|
* copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
* SOFTWARE. |
|
*/ |
|
|
|
|
|
/* jshint esversion: 6, strict: true */ |
|
/* globals moment */ |
|
|
|
$(function() { |
|
'use strict'; |
|
const DATE_FORMAT = "dddd, MMMM Do"; |
|
const TIME_FORMAT = "LT"; |
|
|
|
const ACTIVE_CSS = {"background-color": "lightcoral", "transition": "400ms"}; |
|
const RESET_CSS = {"background-color": ""}; |
|
|
|
|
|
// Parse times (in combination with split-days) |
|
// and add them as .data('time'). |
|
// Also better display format. |
|
let lastDateString = null; |
|
$("tbody .start-time, tbody .day-split").each(function (index) { |
|
const $this = $(this); |
|
if (this.nodeName == 'TR') { |
|
// tr.day-split |
|
lastDateString = $this.find("td").html(); |
|
} |
|
else { |
|
if (!lastDateString) { |
|
// TODO if js disabled |
|
console.log("no date for this element; maybe js disabled?"); |
|
console.log(this); |
|
return; |
|
} |
|
|
|
// parse time |
|
const timeString = $this.html(); |
|
const time = moment(`${lastDateString} ${timeString}`, `${DATE_FORMAT} ${TIME_FORMAT}`); |
|
// console.log(time); |
|
$this.data('time', time.format()); // and store it |
|
|
|
// write better format |
|
$this.html(time.format("HH:mm")); |
|
} |
|
}); |
|
|
|
|
|
let $currentEvent = null; |
|
let $currentAnchor = null; |
|
|
|
/** |
|
* Update currently active event. |
|
* |
|
* @return |
|
*/ |
|
function onTick() { |
|
console.log("checking for event update"); |
|
const now = moment(); |
|
const elements = $("tbody .start-time"); |
|
|
|
for (let i = 0; i + 1 < elements.length; ++i) { |
|
const $elem = $(elements[i]); |
|
const $newElem = $(elements[i + 1]); |
|
|
|
if (moment($elem.data('time')) < now && now < moment($newElem.data('time'))) { |
|
const $newCurrentEvent = $elem.parent(); |
|
if ($currentEvent != $newCurrentEvent) { |
|
if ($currentEvent) { |
|
$currentEvent.css(RESET_CSS); |
|
$currentEvent.next(".second-row").css(RESET_CSS); |
|
$currentAnchor.detach(); |
|
} |
|
$currentEvent = $newCurrentEvent; |
|
$currentEvent.css(ACTIVE_CSS); |
|
$currentEvent.next(".second-row").css(ACTIVE_CSS); |
|
$currentAnchor = $('<a name="current" />').insertBefore($currentEvent); |
|
console.log("new active event"); |
|
console.log($newCurrentEvent); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
// nothing found, GDQ event is over |
|
$currentEvent.removeClass("currentEvent"); |
|
console.log("no active event found"); |
|
$currentEvent = null; |
|
} |
|
|
|
// do it every minute |
|
setInterval(onTick, 60 * 1000); |
|
onTick(); |
|
|
|
|
|
/* // doesn't do anything useful over the default |
|
function onHashChange() { |
|
if ($currentEvent && location.hash == "#current") { |
|
let offset = $currentEvent.offset().top; |
|
offset -= window.innerHeight * 0.4; |
|
if (Math.abs(offset - window.screenY) > window.innerHeight) { |
|
console.log("scrolling..."); |
|
window.scrollTo(0, offset); |
|
// $('html, body').animate({ |
|
// scrollTop: offset, |
|
// }); |
|
} |
|
// not reliable: |
|
// $currentEvent[0].scrollIntoView({block: 'end', behavior: 'smooth'}); // gecko |
|
// $currentEvent[0].scrollIntoViewIfNeeded(false); // webkit |
|
} |
|
} |
|
// onHashChange(); |
|
// doesn't do anything; browser overrides |
|
// window.addEventListener('hashchange', onHashChange); |
|
*/ |
|
|
|
// add link to "#current" anchor |
|
const $button = $('<a class="well extra-spacing" style="display: block; margin: 0px 0px 20px;" href="#current">Jump to current event</a>'); |
|
$("h4").after($button); |
|
}); |