| @@ -0,0 +1,62 @@ | |||
| function checkActive() { | |||
| chrome.storage.local.get('vaccineFinderActive', (result) => { | |||
| if (!!result['vaccineFinderActive']) { | |||
| location.reload(); | |||
| } else { | |||
| setTimeout(checkActive, 4000); | |||
| } | |||
| }); | |||
| } | |||
| function onLoad() { | |||
| chrome.storage.local.get(['vaccineFinderActive', 'vaccineFinderTime'], (result) => { | |||
| let active = result['vaccineFinderActive']; | |||
| if (active === undefined) { | |||
| chrome.storage.local.set({ vaccineFinderActive: false }); | |||
| active = false; | |||
| } | |||
| if (active) { | |||
| const slots = document.getElementsByClassName('slotdetailaction nextstep firstslot'); | |||
| if (slots.length === 0) { | |||
| location.reload(); | |||
| } else { | |||
| let strTime = result['vaccineFinderTime']; | |||
| if (strTime === undefined) { | |||
| chrome.storage.local.set({ vaccineFinderTime: '09:00' }); | |||
| strTime = '09:00'; | |||
| } | |||
| const targetParts = strTime.split(':'); | |||
| const targetTime = parseInt(targetParts[0]) * 60 + parseInt(targetParts[1]); | |||
| let minDistance = Infinity; | |||
| let targetNode = null; | |||
| for (const slot of slots) { | |||
| const str = slot.childNodes[0].textContent; | |||
| const amSplit = str.split(' '); | |||
| const hrSplit = amSplit[0].split(':'); | |||
| let time = parseInt(hrSplit[0]) * 60 + parseInt(hrSplit[1]); | |||
| if (amSplit[1] === 'PM') { | |||
| time += 12 * 60; | |||
| } | |||
| if (Math.abs(targetTime - time) < minDistance) { | |||
| minDistance = Math.abs(targetTime - time); | |||
| targetNode = slot; | |||
| } | |||
| } | |||
| targetNode.click(); | |||
| } | |||
| } else { | |||
| setTimeout(checkActive, 4000); | |||
| } | |||
| }); | |||
| } | |||
| function checkLoaded() { | |||
| const loadingDiv = document.getElementsByClassName('loadingmessage')[0]; | |||
| if (loadingDiv.offsetWidth > 0) { | |||
| window.requestAnimationFrame(checkLoaded); | |||
| } else { | |||
| onLoad(); | |||
| } | |||
| } | |||
| window.requestAnimationFrame(checkLoaded); | |||
| @@ -0,0 +1,43 @@ | |||
| body { | |||
| padding: 10px; | |||
| width: 204px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| font-family: 'Courier New'; | |||
| font-size: 14px; | |||
| } | |||
| .TimeRow { | |||
| display: flex; | |||
| align-items: center; | |||
| } | |||
| #TimePicker { | |||
| margin-left: 8px; | |||
| } | |||
| .ToggleContainer { | |||
| margin-top: 16px; | |||
| } | |||
| #ActiveButton { | |||
| padding: 6px; | |||
| padding-top: 4px; | |||
| padding-bottom: 4px; | |||
| border: 1px solid black; | |||
| background-color: black; | |||
| color: white; | |||
| display: none; | |||
| user-select: none; | |||
| cursor: pointer; | |||
| } | |||
| #InactiveButton { | |||
| padding: 6px; | |||
| padding-top: 4px; | |||
| padding-bottom: 4px; | |||
| border: 1px solid black; | |||
| display: none; | |||
| user-select: none; | |||
| cursor: pointer; | |||
| } | |||
| @@ -0,0 +1,19 @@ | |||
| <!DOCTYPE html> | |||
| <html> | |||
| <head> | |||
| <link rel="stylesheet" href="index.css"> | |||
| </head> | |||
| <body> | |||
| <div class="TimeRow"> | |||
| <div class="TimeLabel">Ideal time:</div> | |||
| <input id="TimePicker" type="time"> | |||
| </div> | |||
| <div class="ToggleContainer"> | |||
| <div id="ActiveButton">Active</div> | |||
| <div id="InactiveButton">Inactive</div> | |||
| </div> | |||
| <script src="index.js"></script> | |||
| </body> | |||
| <html> | |||
| @@ -0,0 +1,38 @@ | |||
| const activeButton = document.getElementById('ActiveButton'); | |||
| const inactiveButton = document.getElementById('InactiveButton'); | |||
| const timePicker = document.getElementById('TimePicker'); | |||
| chrome.storage.local.get(['vaccineFinderActive', 'vaccineFinderTime'], (result) => { | |||
| let active = result['vaccineFinderActive']; | |||
| if (active === undefined) { | |||
| chrome.storage.local.set({ vaccineFinderActive: false }); | |||
| active = false; | |||
| } | |||
| if (active) { | |||
| activeButton.style.display = 'block'; | |||
| } else { | |||
| inactiveButton.style.display = 'block'; | |||
| } | |||
| let time = result['vaccineFinderTime']; | |||
| if (time === undefined) { | |||
| chrome.storage.local.set({ vaccineFinderTime: '09:00' }); | |||
| time = '09:00'; | |||
| } | |||
| timePicker.value = time; | |||
| timePicker.oninput = () => { | |||
| chrome.storage.local.set({ vaccineFinderTime: timePicker.value }); | |||
| } | |||
| }); | |||
| activeButton.onclick = () => { | |||
| activeButton.style.display = 'none'; | |||
| inactiveButton.style.display = 'block'; | |||
| chrome.storage.local.set({ vaccineFinderActive: false }); | |||
| }; | |||
| inactiveButton.onclick = () => { | |||
| activeButton.style.display = 'block'; | |||
| inactiveButton.style.display = 'none'; | |||
| chrome.storage.local.set({ vaccineFinderActive: true }); | |||
| }; | |||
| @@ -0,0 +1,20 @@ | |||
| { | |||
| "name": "Vaccine Finder", | |||
| "description": "Vaccine Finder", | |||
| "manifest_version": 2, | |||
| "version": "1.0", | |||
| "browser_action": { | |||
| "default_popup": "index.html" | |||
| }, | |||
| "content_scripts": [ | |||
| { | |||
| "matches": ["https://epicmychart.nychhc.org/*"], | |||
| "js": ["content.js"], | |||
| "run_at": "document_end" | |||
| } | |||
| ], | |||
| "permissions": [ | |||
| "https://epicmychart.nychhc.org/*", | |||
| "storage" | |||
| ] | |||
| } | |||