diff --git a/src/css/augmentedsteam.css b/src/css/augmentedsteam.css index 7f4d7f800..e07f5024e 100644 --- a/src/css/augmentedsteam.css +++ b/src/css/augmentedsteam.css @@ -923,38 +923,6 @@ video.highlight_movie:hover + .html5_video_overlay { color: black; } -.es-wexport { - margin-bottom: 30px; -} -.es-wexport__label { - margin-right: 30px; - vertical-align: baseline; -} -.es-wexport__label input[type=radio] { - position: relative; - top: 2px; -} -.es-wexport__input { - width: 400px; - color: #b9bfc6; - background-color: #313c48; - box-shadow: 1px 1px 0 rgba(0,0,0,0.2) inset; - border-radius: 3px; - font-size: 12px; - padding: 3px 4px; - border: none; -} -.es-wexport__symbols { - margin-top: 2px; - font-size: 11px; -} -.es-wexport__format.es-grayout { - opacity: 0.4; - pointer-events: none; - -webkit-user-select: none; - user-select: none; -} - /*************************************** * App pages * Common/UserNotes diff --git a/src/js/Content/Features/Store/Wishlist/Components/ExportWishlistForm.svelte b/src/js/Content/Features/Store/Wishlist/Components/ExportWishlistForm.svelte new file mode 100644 index 000000000..60a0aaf5e --- /dev/null +++ b/src/js/Content/Features/Store/Wishlist/Components/ExportWishlistForm.svelte @@ -0,0 +1,127 @@ + + + + + +
+

{L(__export_type)}

+
+ + +
+
+ +{#if type === "text"} +
+

{L(__export_format)}

+
+ +
+ {#each ["%title%", "%id%", "%appid%", "%url%", "%release_date%", "%price%", "%discount%", "%base_price%", "%type%", "%note%"] as str, index} + {#if index > 0}, {/if} + + {/each} +
+
+
+{/if} + + + \ No newline at end of file diff --git a/src/js/Content/Features/Store/Wishlist/FExportWishlist.ts b/src/js/Content/Features/Store/Wishlist/FExportWishlist.ts index 5e9339a85..a0eef514f 100644 --- a/src/js/Content/Features/Store/Wishlist/FExportWishlist.ts +++ b/src/js/Content/Features/Store/Wishlist/FExportWishlist.ts @@ -1,22 +1,15 @@ import Downloader from "@Core/Downloader"; import {L} from "@Core/Localization/Localization"; -import { - __export_copyClipboard, - __export_download, - __export_format, - __export_text, - __export_type, - __export_wishlist, -} from "@Strings/_strings"; +import {__export_copyClipboard, __export_download, __export_wishlist,} from "@Strings/_strings"; import Feature from "@Content/Modules/Context/Feature"; import type CWishlist from "@Content/Features/Store/Wishlist/CWishlist"; import HTML from "@Core/Html/Html"; import SteamFacade from "@Content/Modules/Facades/SteamFacade"; import UserNotes from "@Content/Features/Store/Common/UserNotes"; import Clipboard from "@Content/Modules/Clipboard"; -import TimeUtils from "@Core/Utils/TimeUtils"; +import ExportWishlistForm from "@Content/Features/Store/Wishlist/Components/ExportWishlistForm.svelte"; -type Wishlist = Array<[string, { +type WishlistData = Array<[string, { name: string, type: string, release_string: string, @@ -29,15 +22,15 @@ type Wishlist = Array<[string, { enum ExportMethod { download, - copyToClipboard + copy } class WishlistExporter { - private readonly wishlist: Wishlist; + private readonly wishlist: WishlistData; private readonly notes: Promise>; - constructor(wishlist: Wishlist) { + constructor(wishlist: WishlistData) { this.wishlist = wishlist; const userNotes = new UserNotes() @@ -114,102 +107,84 @@ class WishlistExporter { export default class FExportWishlist extends Feature { + private type: "text"|"json" = "text"; + private format: string = "%title%"; + override apply(): void { HTML.afterBegin("#cart_status_data", `
${L(__export_wishlist)}
`); - document.querySelector("#es_export_wishlist")!.addEventListener("click", async() => { - const appInfo = await SteamFacade.global("g_rgAppInfo"); - const wl: Wishlist = (await SteamFacade.global<{rgVisibleApps: string[]}>("g_Wishlist")).rgVisibleApps.map( - appid => [appid, appInfo[appid]] - ); - this._showDialog(wl); + document.querySelector("#es_export_wishlist")!.addEventListener("click", () => { + this.showDialog(); }); } - /* - * Using Valve's CModal API here is very hard, since, when trying to copy data to the clipboard, it has to originate from - * a short-lived event handler for a user action. - * Since we'd use our Messenger class to pass information in between these two contexts, we would "outrange" this specific event - * handler, resulting in a denial of access to the clipboard function. - * This could be circumvented by adding the appropriate permissions, but doing so would prompt users to explicitly accept the - * changed permissions on an update. - * - * If we don't use the Messenger, we'd have to move the whole handler part (including WishlistExporter) to - * the page context side. - * - * Final solution is to query the action buttons of the dialog and adding some extra click handlers on the content script side. - */ - async _showDialog(wl: Array<[string, any]>): Promise { - - async function exportWishlist(method: ExportMethod): Promise { - const type = document.querySelector("input[name='es_wexport_type']:checked")!.value; - const format = document.querySelector("#es-wexport-format")!.value; - - const wishlist = new WishlistExporter(wl); - - let result = ""; - let filename = ""; - let filetype = ""; - if (type === "json") { - result = await wishlist.toJson(); - filename = "wishlist.json"; - filetype = "application/json"; - } else if (type === "text" && format) { - result = await wishlist.toText(format); - filename = "wishlist.txt"; - filetype = "text/plain"; - } + private async showDialog(): Promise { + + let form: ExportWishlistForm|undefined; - if (method === ExportMethod.copyToClipboard) { - Clipboard.set(result); - } else if (method === ExportMethod.download) { - Downloader.download(new Blob([result], {"type": `${filetype};charset=UTF-8`}), filename); + const observer = new MutationObserver(() => { + const modal = document.querySelector("#as_export_form"); + if (modal) { + form = new ExportWishlistForm({ + target: modal, + props: { + type: this.type, + format: this.format + } + }); + form.$on("setup", () => { + this.format = form!.format; + this.type = form!.type; + }); + observer.disconnect(); } - } + }); + observer.observe(document.body, { + childList: true, + subtree: true + }); - SteamFacade.showConfirmDialog( + const response = await SteamFacade.showConfirmDialog( L(__export_wishlist), - `
-
-

${L(__export_type)}

-
- - -
-
-
-

${L(__export_format)}

-
-
-
%title%, %id%, %appid%, %url%, %release_date%, %price%, %discount%, %base_price%, %type%, %note%
-
-
-
`, + `
`, L(__export_download), null, // use default "Cancel" L(__export_copyClipboard) ); - for (let i=0; i<10; i++) { - const [dlBtn, copyBtn] = document.querySelectorAll(".newmodal_buttons > .btn_medium"); + form?.$destroy(); - if (!dlBtn || !copyBtn) { - // wait for popup to show up to apply events - await TimeUtils.timer(10); - continue; - } + if (response === "CANCEL") { + return; + } - // Capture this s.t. the CModal doesn't get destroyed before we can grab this information - dlBtn!.addEventListener("click", () => exportWishlist(ExportMethod.download), true); - copyBtn!.addEventListener("click", () => exportWishlist(ExportMethod.copyToClipboard), true); + const method = response === "OK" + ? ExportMethod.download + : ExportMethod.copy; - const format = document.querySelector(".es-wexport__format"); - for (const el of document.getElementsByName("es_wexport_type")) { - el.addEventListener("click", e => { - const target = e.target as HTMLInputElement; - format!.classList.toggle("es-grayout", target.value === "json"); - }); - } + const appInfo = await SteamFacade.global("g_rgAppInfo"); + const wl: WishlistData = (await SteamFacade.global<{rgVisibleApps: string[]}>("g_Wishlist")).rgVisibleApps.map( + appid => [appid, appInfo[appid]] + ); + const wishlist = new WishlistExporter(wl); + + let data = ""; + let filename = ""; + let filetype = ""; + if (this.type === "json") { + data = await wishlist.toJson(); + filename = "wishlist.json"; + filetype = "application/json"; + } else if (this.type === "text" && this.format) { + data = await wishlist.toText(this.format); + filename = "wishlist.txt"; + filetype = "text/plain"; + } + + if (method === ExportMethod.copy) { + Clipboard.set(data); + } else if (method === ExportMethod.download) { + Downloader.download(new Blob([data], {"type": `${filetype};charset=UTF-8`}), filename); } } }