-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
84 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
env: | ||
browser: true | ||
es2021: true | ||
extends: standard | ||
parserOptions: | ||
ecmaVersion: latest | ||
rules: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,79 @@ | ||
'use strict' | ||
import { twitch, extensionUri } from './globals.js' | ||
import htmx from 'htmx' | ||
import Sortable from 'Sortable' | ||
|
||
let authorization | ||
|
||
twitch.onAuthorized(function (auth) { | ||
authorization = 'Bearer ' + auth.token | ||
// wait for user to be authorized before getting content for layout-select-form | ||
htmx.trigger("#layout-select-form", "authed") | ||
htmx.trigger('#layout-select-form', 'authed') | ||
}) | ||
|
||
// add the auth token to the request as a header | ||
htmx.on("htmx:configRequest", (e)=> { | ||
e.detail.headers["Authorization"] = authorization | ||
htmx.on('htmx:configRequest', (e) => { | ||
e.detail.headers.Authorization = authorization | ||
|
||
// update the URL to the proper extension URI | ||
if (!e.detail.path.startsWith("https")) { | ||
if (!e.detail.path.startsWith('https')) { | ||
e.detail.path = extensionUri + e.detail.path | ||
} | ||
}) | ||
|
||
htmx.onLoad(function(content) { | ||
htmx.onLoad(function (content) { | ||
// allow sorting of elements in the panel | ||
var sortables = content.querySelectorAll(".grid-container"); | ||
for (var i = 0; i < sortables.length; i++) { | ||
var sortable = sortables[i]; | ||
var sortableInstance = new Sortable(sortable, { | ||
const sortables = content.querySelectorAll('.grid-container') | ||
for (let i = 0; i < sortables.length; i++) { | ||
const sortable = sortables[i] | ||
const sortableInstance = new Sortable(sortable, { | ||
animation: 150, | ||
|
||
filter: ".add-new-button", | ||
filter: '.add-new-button', | ||
// disable sorting on the `end` event | ||
onEnd: function (evt) { | ||
this.option("disabled", true); | ||
this.option('disabled', true) | ||
} | ||
}); | ||
}) | ||
|
||
// re-enable sorting on the `htmx:afterSwap` event | ||
sortable.addEventListener("htmx:afterSwap", function() { | ||
sortableInstance.option("disabled", false); | ||
}); | ||
sortable.addEventListener('htmx:afterSwap', function () { | ||
sortableInstance.option('disabled', false) | ||
}) | ||
} | ||
}); | ||
}) | ||
|
||
htmx.on("htmx:afterSwap", (e) => { | ||
if (e.detail.target.id == "dialog") { | ||
// set up event listeners to close dialog | ||
const dialog = document.querySelector("dialog") | ||
const closeButton = document.getElementById("dialog-close-button") | ||
dialog.showModal() | ||
dialog.addEventListener("close", () => { | ||
dialog.remove() | ||
}) | ||
closeButton.addEventListener("click", () => { | ||
dialog.close() | ||
}) | ||
htmx.on('htmx:afterSwap', (e) => { | ||
if (e.detail.target.id === 'dialog') { | ||
// set up event listeners to close dialog | ||
const dialog = document.querySelector('dialog') | ||
const closeButton = document.getElementById('dialog-close-button') | ||
dialog.showModal() | ||
dialog.addEventListener('close', () => { | ||
dialog.remove() | ||
}) | ||
closeButton.addEventListener('click', () => { | ||
dialog.close() | ||
}) | ||
} | ||
|
||
}) | ||
|
||
htmx.on("htmx:beforeSwap", (e) => { | ||
if (e.detail.target.id == "dialog-status") { | ||
|
||
if (e.detail.shouldSwap){ | ||
// workaround to ensure the dialog doesn't close after the webhook is tested | ||
const close_dialog = (e.detail.serverResponse !== "<p class='success-message'>Webhook OK</p>") | ||
htmx.on('htmx:beforeSwap', (e) => { | ||
if (e.detail.target.id === 'dialog-status') { | ||
if (e.detail.shouldSwap) { | ||
// workaround to ensure the dialog doesn't close after the webhook is tested | ||
const closeDialog = (e.detail.serverResponse !== "<p class='success-message'>Webhook OK</p>") | ||
|
||
if (close_dialog) { | ||
// close the dialog after the success message has been shown for 0.5s | ||
const dialog = document.querySelector("dialog") | ||
setTimeout(() => { | ||
dialog.close() | ||
}, 500) | ||
} | ||
|
||
} else { | ||
// Show the error message on a non-200 response | ||
e.detail.shouldSwap = true | ||
if (closeDialog) { | ||
// close the dialog after the success message has been shown for 0.5s | ||
const dialog = document.querySelector('dialog') | ||
setTimeout(() => { | ||
dialog.close() | ||
}, 500) | ||
} | ||
} else { | ||
// Show the error message on a non-200 response | ||
e.detail.shouldSwap = true | ||
} | ||
} | ||
|
||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,84 @@ | ||
'use strict' | ||
import { twitch, extensionUri } from './globals.js' | ||
import htmx from 'htmx' | ||
|
||
let authorization | ||
|
||
|
||
twitch.onAuthorized(function (auth) { | ||
authorization = 'Bearer ' + auth.token | ||
// wait for user to be authorized before getting content for layout-loader | ||
htmx.trigger("#layout-loader", "authed") | ||
htmx.trigger('#layout-loader', 'authed') | ||
}) | ||
|
||
|
||
htmx.on("htmx:configRequest", (e)=> { | ||
htmx.on('htmx:configRequest', (e) => { | ||
// add the auth token to the request as a header | ||
e.detail.headers["Authorization"] = authorization | ||
e.detail.headers.Authorization = authorization | ||
// update the URL to the proper extension URI | ||
if (!e.detail.path.startsWith("https")) { | ||
if (!e.detail.path.startsWith('https')) { | ||
e.detail.path = extensionUri + e.detail.path | ||
} | ||
}) | ||
|
||
twitch.listen("broadcast", function (target, contentType, message) { | ||
twitch.listen('broadcast', function (target, contentType, message) { | ||
// handle refreshing the panel if the streamer updates the layout | ||
if (message === "refresh") { | ||
if (message === 'refresh') { | ||
// refresh after a random interval between 0-5s (to reduce EBS load) | ||
setTimeout(function () { | ||
htmx.trigger("#layout-loader", "refresh") | ||
htmx.trigger('#layout-loader', 'refresh') | ||
}, Math.floor(Math.random() * 5000)) | ||
} | ||
}) | ||
|
||
htmx.on("htmx:afterSwap", (e) => { | ||
|
||
htmx.on('htmx:afterSwap', (e) => { | ||
// start a bits transaction if the user clicks one of the webhook buttons | ||
if (e.detail.target.id == "layout") { | ||
var webhookButtons = document.querySelectorAll(".webhook-button"); | ||
for (var i = 0; i < webhookButtons.length; i++) { | ||
var webhookButton = webhookButtons[i]; | ||
if (e.detail.target.id === 'layout') { | ||
const webhookButtons = document.querySelectorAll('.webhook-button') | ||
for (let i = 0; i < webhookButtons.length; i++) { | ||
const webhookButton = webhookButtons[i] | ||
// the webhookId is available in the data-id attribute of the button | ||
const webhookID = webhookButton.getAttribute("data-id") | ||
const webhookID = webhookButton.getAttribute('data-id') | ||
// the bitsProduct is available in the data-product attribute of the button | ||
const webhookBitsProduct = webhookButton.getAttribute("data-product") | ||
const webhookBitsProduct = webhookButton.getAttribute('data-product') | ||
webhookButton.addEventListener( | ||
"click", | ||
'click', | ||
async function () { | ||
webhookRedeem(webhookID, webhookBitsProduct) | ||
}, | ||
false, | ||
false | ||
) | ||
} | ||
} | ||
}) | ||
|
||
|
||
// handle the bits transaction and trigger the webhook in the EBS if successful | ||
async function webhookRedeem (webhookID, webhookBitsProduct) { | ||
try { | ||
const bitsTransaction = new Promise((complete, cancel) => { | ||
twitch.bits.onTransactionComplete(complete); | ||
twitch.bits.onTransactionCancelled(cancel); | ||
const bitsTransaction = new Promise((resolve, reject) => { | ||
twitch.bits.onTransactionComplete(resolve) | ||
twitch.bits.onTransactionCancelled(reject) | ||
}) | ||
twitch.bits.useBits(webhookBitsProduct); | ||
const tx = await bitsTransaction; | ||
twitch.bits.useBits(webhookBitsProduct) | ||
const tx = await bitsTransaction | ||
|
||
const response = await fetch( | ||
extensionUri + '/webhook/' + webhookID, { | ||
method: "POST", | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Authorization: authorization | ||
}, | ||
body: JSON.stringify({"transaction": tx}) | ||
body: JSON.stringify({ transaction: tx }) | ||
} | ||
) | ||
if (!response.ok) { | ||
const errorMsg = 'webhook failed: ' + response.status | ||
console.error(errorMsg) | ||
return false | ||
} | ||
} catch (error) { | ||
console.error(error) | ||
console.error('error sending webhook: ' + error) | ||
} finally { | ||
twitch.bits.onTransactionComplete(() => {}); | ||
twitch.bits.onTransactionCancelled(() => {}); | ||
twitch.bits.onTransactionComplete(() => {}) | ||
twitch.bits.onTransactionCancelled(() => {}) | ||
} | ||
} |