Create a standard copy button component and remove a lot of redundant code

This commit is contained in:
2024-02-20 17:33:15 +01:00
parent 47028f85b8
commit 99eba76c2e
12 changed files with 153 additions and 297 deletions

View File

@@ -1,6 +1,7 @@
<script> <script>
import CopyButton from "../layout/CopyButton.svelte";
import ThemePicker from "../util/ThemePicker.svelte"; import ThemePicker from "../util/ThemePicker.svelte";
import { copy_text, domain_url } from "../util/Util.svelte"; import { domain_url } from "../util/Util.svelte";
import { file_type } from "./FileUtilities.svelte"; import { file_type } from "./FileUtilities.svelte";
export let file = { export let file = {
@@ -87,16 +88,6 @@ let html_escape = s => {
replace(/'/g, "&#039;"); replace(/'/g, "&#039;");
} }
let copy_status = "" // empty, success or error
const copy = () => {
if (copy_text(embed_html)) {
copy_status = "success"
} else {
copy_status = "error"
alert("Your browser does not support copying text.")
}
}
let example = false let example = false
const toggle_example = () => { const toggle_example = () => {
example = !example example = !example
@@ -177,16 +168,7 @@ const update_example = () => {
<div class="center"> <div class="center">
<textarea bind:value={embed_html} style="width: 99%; height: 4em;"></textarea> <textarea bind:value={embed_html} style="width: 99%; height: 4em;"></textarea>
<br/> <br/>
<button on:click={copy} class:button_highlight={copy_status === "success"} class:button_red={copy_status === "error"}> <CopyButton text={embed_html}>Copy HTML</CopyButton>
<i class="icon">content_copy</i>
{#if copy_status === "success"}
Copied!
{:else if copy_status === "error"}
Error!
{:else}
Copy HTML
{/if}
</button>
<button on:click={toggle_example} class:button_highlight={example}> <button on:click={toggle_example} class:button_highlight={example}>
<i class="icon">visibility</i> Show example <i class="icon">visibility</i> Show example
</button> </button>

View File

@@ -1,6 +1,5 @@
<script> <script>
import { onMount, tick } from "svelte"; import { onMount, tick } from "svelte";
import { copy_text } from "../util/Util.svelte";
import { file_struct, list_struct, file_set_href } from "./FileUtilities.svelte"; import { file_struct, list_struct, file_set_href } from "./FileUtilities.svelte";
import Modal from "../util/Modal.svelte"; import Modal from "../util/Modal.svelte";
import DetailsWindow from "./DetailsWindow.svelte"; import DetailsWindow from "./DetailsWindow.svelte";
@@ -20,6 +19,7 @@ import TransferLimit from "./TransferLimit.svelte";
import ListStats from "./ListStats.svelte"; import ListStats from "./ListStats.svelte";
import ListUpdater from "./ListUpdater.svelte"; import ListUpdater from "./ListUpdater.svelte";
import HomeButton from "./HomeButton.svelte"; import HomeButton from "./HomeButton.svelte";
import CopyButton from "../layout/CopyButton.svelte";
let loading = true let loading = true
let embedded = false let embedded = false
@@ -277,18 +277,6 @@ const apply_customizations = file => {
} }
} }
let copy_url_status = "" // empty, copied, or error
const copy_url = () => {
if (copy_text(window.location.href)) {
copy_url_status = "copied"
} else {
copy_url_status = "error"
alert("Your browser does not support copying text.")
}
setTimeout(() => { copy_url_status = "" }, 60000)
}
const grab_file = async () => { const grab_file = async () => {
if (!window.user_authenticated) { if (!window.user_authenticated) {
return return
@@ -313,6 +301,7 @@ const grab_file = async () => {
} }
} }
let copy_btn
const keyboard_event = evt => { const keyboard_event = evt => {
if (evt.ctrlKey || evt.altKey || evt.metaKey) { if (evt.ctrlKey || evt.altKey || evt.metaKey) {
return // prevent custom shortcuts from interfering with system shortcuts return // prevent custom shortcuts from interfering with system shortcuts
@@ -355,7 +344,7 @@ const keyboard_event = evt => {
} }
break break
case "c": // C to copy to clipboard case "c": // C to copy to clipboard
copy_url() copy_btn.copy()
break break
case "i": // I to open the details window case "i": // I to open the details window
details_window.toggle() details_window.toggle()
@@ -455,23 +444,9 @@ const keyboard_event = evt => {
</button> </button>
{/if} {/if}
<button <CopyButton bind:this={copy_btn} text={window.location.href} style="width: calc(100% - 6px)">
on:click={copy_url}
class="toolbar_button"
class:button_highlight={copy_url_status === "copied"}
class:button_red={copy_url_status === "error"}
title="Copy a link to this page to your clipboard">
<i class="icon">content_copy</i>
<span>
{#if copy_url_status === "copied"}
Copied!
{:else if copy_url_status === "error"}
Error!
{:else}
<u>C</u>opy link <u>C</u>opy link
{/if} </CopyButton>
</span>
</button>
{#if !disable_share_button} {#if !disable_share_button}
<button <button
@@ -731,10 +706,8 @@ const keyboard_event = evt => {
} }
.toolbar.toolbar_visible { left: 0; } .toolbar.toolbar_visible { left: 0; }
.toolbar_button { .toolbar_button{
text-align: left; width: calc(100% - 6px);
margin: 4px;
width: calc(100% - 8px);
} }
.toolbar_button > span { .toolbar_button > span {
vertical-align: middle; vertical-align: middle;

View File

@@ -2,11 +2,11 @@
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import Magnet from "../../icons/Magnet.svelte"; import Magnet from "../../icons/Magnet.svelte";
import { formatDate } from "../../util/Formatting.svelte" import { formatDate } from "../../util/Formatting.svelte"
import { copy_text } from "../../util/Util.svelte";
import IconBlock from "./IconBlock.svelte"; import IconBlock from "./IconBlock.svelte";
import TextBlock from "./TextBlock.svelte"; import TextBlock from "./TextBlock.svelte";
import TorrentItem from "./TorrentItem.svelte" import TorrentItem from "./TorrentItem.svelte"
import FileTitle from "./FileTitle.svelte"; import FileTitle from "./FileTitle.svelte";
import CopyButton from "../../layout/CopyButton.svelte";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
@@ -66,18 +66,6 @@ let torrent = {
} }
let magnet = "" let magnet = ""
let copy_magnet_status = "" // empty, copied, or error
const copy_magnet = () => {
if (copy_text(magnet)) {
copy_magnet_status = "copied"
} else {
copy_magnet_status = "error"
alert("Your browser does not support copying text.")
}
setTimeout(() => { copy_magnet_status = "" }, 60000)
}
</script> </script>
<FileTitle title={file.name}/> <FileTitle title={file.name}/>
@@ -92,22 +80,7 @@ const copy_magnet = () => {
<Magnet/> <Magnet/>
<span>Open magnet link</span> <span>Open magnet link</span>
</a> </a>
<button <CopyButton text={magnet}>Copy magnet link</CopyButton>
on:click={copy_magnet}
class:button_highlight={copy_magnet_status === "copied"}
class:button_red={copy_magnet_status === "error"}
>
<Magnet/>
<span>
{#if copy_magnet_status === ""}
Copy magnet link
{:else if copy_magnet_status === "copied"}
Copied magnet
{:else if copy_magnet_status === "error"}
Error!
{/if}
</span>
</button>
{:else if status === "too_large"} {:else if status === "too_large"}
<p> <p>
Torrent file is too large to parse. Please download the file and Torrent file is too large to parse. Please download the file and

View File

@@ -5,9 +5,9 @@ import Modal from "../util/Modal.svelte";
import { fs_timeseries } from "./FilesystemAPI"; import { fs_timeseries } from "./FilesystemAPI";
import { fs_path_url } from "./FilesystemUtil"; import { fs_path_url } from "./FilesystemUtil";
import { generate_share_path, generate_share_url } from "./Sharebar.svelte"; import { generate_share_path, generate_share_url } from "./Sharebar.svelte";
import { color_by_name, copy_text } from "../util/Util.svelte"; import { color_by_name } from "../util/Util.svelte";
import { tick } from "svelte"; import { tick } from "svelte";
import Button from "../layout/Button.svelte"; import CopyButton from "../layout/CopyButton.svelte";
export let state export let state
export let visible = false export let visible = false
@@ -176,7 +176,7 @@ let update_chart = async (base, timespan, interval) => {
<tr> <tr>
<td>Direct link</td> <td>Direct link</td>
<td> <td>
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(direct_url)}/> <CopyButton text={direct_url}>Copy</CopyButton>
<a href="{direct_url}">{direct_url}</a> <a href="{direct_url}">{direct_url}</a>
</td> </td>
</tr> </tr>
@@ -184,14 +184,14 @@ let update_chart = async (base, timespan, interval) => {
<tr> <tr>
<td>Sharing link</td> <td>Sharing link</td>
<td> <td>
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(share_url)}/> <CopyButton text={share_url}>Copy</CopyButton>
<a href="{share_url}">{share_url}</a> <a href="{share_url}">{share_url}</a>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Direct sharing link</td> <td>Direct sharing link</td>
<td> <td>
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(direct_share_url)}/> <CopyButton text={direct_share_url}>Copy</CopyButton>
<a href="{direct_share_url}">{direct_share_url}</a> <a href="{direct_share_url}">{direct_share_url}</a>
</td> </td>
</tr> </tr>

View File

@@ -1,7 +1,7 @@
<script> <script>
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { copy_text, domain_url } from "../../util/Util.svelte"; import { domain_url } from "../../util/Util.svelte";
import Button from "../../layout/Button.svelte"; import CopyButton from "../../layout/CopyButton.svelte";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
export let shared export let shared
@@ -27,16 +27,6 @@ let embed_iframe = file => {
`></iframe>` `></iframe>`
} }
let copy_status = "" // empty, success or error
const copy = () => {
if (copy_text(embed_html)) {
copy_status = "success"
} else {
copy_status = "error"
alert("Your browser does not support copying text.")
}
}
let example = false let example = false
const toggle_example = () => { const toggle_example = () => {
if (is_shared) { if (is_shared) {
@@ -67,7 +57,7 @@ const toggle_example = () => {
{#if is_shared} {#if is_shared}
<span>Your sharing link: <a href={share_link}>{share_link}</a></span> <span>Your sharing link: <a href={share_link}>{share_link}</a></span>
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(share_link)}/> <CopyButton text={share_link}>Copy</CopyButton>
{/if} {/if}
</div> </div>
@@ -87,16 +77,7 @@ const toggle_example = () => {
<div class="center"> <div class="center">
<textarea bind:value={embed_html} style="width: 100%; height: 4em;"></textarea> <textarea bind:value={embed_html} style="width: 100%; height: 4em;"></textarea>
<br/> <br/>
<button on:click={copy} class:button_highlight={copy_status === "success"} class:button_red={copy_status === "error"}> <CopyButton text={embed_html} label="Copy HTML"/>
<i class="icon">content_copy</i>
{#if copy_status === "success"}
Copied!
{:else if copy_status === "error"}
Error!
{:else}
Copy HTML
{/if}
</button>
<button on:click={toggle_example} class:button_highlight={example} disabled={!is_shared}> <button on:click={toggle_example} class:button_highlight={example} disabled={!is_shared}>
<i class="icon">visibility</i> Show example <i class="icon">visibility</i> Show example
</button> </button>

View File

@@ -2,11 +2,11 @@
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import Magnet from "../../icons/Magnet.svelte"; import Magnet from "../../icons/Magnet.svelte";
import { formatDate } from "../../util/Formatting.svelte" import { formatDate } from "../../util/Formatting.svelte"
import { copy_text } from "../../util/Util.svelte";
import TorrentItem from "./TorrentItem.svelte" import TorrentItem from "./TorrentItem.svelte"
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte"; import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte"; import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
import { fs_node_icon, fs_path_url } from "../FilesystemUtil"; import { fs_node_icon, fs_path_url } from "../FilesystemUtil";
import CopyButton from "../../layout/CopyButton.svelte";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
@@ -59,18 +59,6 @@ let torrent = {
} }
let magnet = "" let magnet = ""
let copy_magnet_status = "" // empty, copied, or error
const copy_magnet = () => {
if (copy_text(magnet)) {
copy_magnet_status = "copied"
} else {
copy_magnet_status = "error"
alert("Your browser does not support copying text.")
}
setTimeout(() => { copy_magnet_status = "" }, 60000)
}
</script> </script>
<slot></slot> <slot></slot>
@@ -87,22 +75,7 @@ const copy_magnet = () => {
<Magnet style=""/> <Magnet style=""/>
<span>Open magnet link</span> <span>Open magnet link</span>
</a> </a>
<button <CopyButton text={magnet}>Copy magnet link</CopyButton>
on:click={copy_magnet}
class:button_highlight={copy_magnet_status === "copied"}
class:button_red={copy_magnet_status === "error"}
>
<Magnet style=""/>
<span>
{#if copy_magnet_status === ""}
Copy magnet link
{:else if copy_magnet_status === "copied"}
Copied magnet
{:else if copy_magnet_status === "error"}
Error!
{/if}
</span>
</button>
{:else if status === "too_large"} {:else if status === "too_large"}
<p> <p>
Torrent file is too large to parse. Please download the file and Torrent file is too large to parse. Please download the file and

View File

@@ -1,6 +1,6 @@
<script> <script>
import UploadProgressBar from "./UploadProgressBar.svelte" import UploadProgressBar from "./UploadProgressBar.svelte"
import { copy_text, domain_url } from "../util/Util.svelte" import { domain_url } from "../util/Util.svelte"
import { tick } from "svelte" import { tick } from "svelte"
import Facebook from "../icons/Facebook.svelte" import Facebook from "../icons/Facebook.svelte"
import Reddit from "../icons/Reddit.svelte" import Reddit from "../icons/Reddit.svelte"
@@ -9,6 +9,7 @@ import Tumblr from "../icons/Tumblr.svelte"
import StorageProgressBar from "../user_home/StorageProgressBar.svelte" import StorageProgressBar from "../user_home/StorageProgressBar.svelte"
import Konami from "../util/Konami.svelte" import Konami from "../util/Konami.svelte"
import UploadStats from "./UploadStats.svelte"; import UploadStats from "./UploadStats.svelte";
import CopyButton from "../layout/CopyButton.svelte";
// === UPLOAD LOGIC === // === UPLOAD LOGIC ===
@@ -134,7 +135,7 @@ let btn_copy_links
let btn_copy_markdown let btn_copy_markdown
let btn_copy_bbcode let btn_copy_bbcode
const uploads_finished = () => { const uploads_finished = async () => {
let count = upload_queue.reduce( let count = upload_queue.reduce(
(acc, curr) => curr.status === "finished" ? acc + 1 : acc, 0, (acc, curr) => curr.status === "finished" ? acc + 1 : acc, 0,
) )
@@ -143,14 +144,17 @@ const uploads_finished = () => {
share_title = "Download " + upload_queue[0].name + " here" share_title = "Download " + upload_queue[0].name + " here"
share_link = domain_url() + "/u/" + upload_queue[0].id share_link = domain_url() + "/u/" + upload_queue[0].id
} else if (count > 1) { } else if (count > 1) {
create_list(count+" files", true).then(resp => { try {
const resp = await create_list(count+" files", true)
console.log("Automatic list ID " + resp.id) console.log("Automatic list ID " + resp.id)
share_title = "View a collection of "+count+" files here" share_title = "View a collection of "+count+" files here"
share_link = domain_url() + "/l/" + resp.id share_link = domain_url() + "/l/" + resp.id
}).catch(err => { } catch (err) {
alert("Failed to generate link. Please check your internet connection and try again.\nError: " + err) alert("Failed to generate link. Please check your internet connection and try again.\nError: " + err)
})
} }
}
generate_link_list()
} }
async function create_list(title, anonymous) { async function create_list(title, anonymous) {
@@ -182,19 +186,6 @@ async function create_list(title, anonymous) {
return await resp.json() return await resp.json()
} }
const copy_link = () => {
if (copy_text(share_link)) {
console.log('Text copied')
btn_copy_link.querySelector("span").textContent = "Copied!"
btn_copy_link.classList.add("button_highlight")
} else {
console.log('Copying not supported')
btn_copy_link.querySelector("span").textContent = "Failed"
btn_copy_link.classList.add("button_red")
alert("Your browser does not support copying text.")
}
}
let qr_visible = false let qr_visible = false
const open_link = () => window.open(share_link, "_blank") const open_link = () => window.open(share_link, "_blank")
const show_qr_code = () => qr_visible = !qr_visible const show_qr_code = () => qr_visible = !qr_visible
@@ -229,69 +220,35 @@ const get_finished_files = () => {
[], [],
) )
} }
const copy_links = () => {
let link_list = ""
let bbcode = ""
let markdown = ""
const generate_link_list = () => {
// Add the text to the textarea // Add the text to the textarea
let text = "" link_list = ""
bbcode = ""
markdown = ""
let files = get_finished_files() let files = get_finished_files()
files.forEach(file => { files.forEach(file => {
// Example: https://pixeldrain.com/u/abcd1234 Some_file.png // Link list example: https://pixeldrain.com/u/abcd1234 Some_file.png
text += domain_url() + "/u/" + file.id + " " + file.name + "\n" link_list += domain_url() + "/u/" + file.id + " " + file.name + "\n"
// BBCode example: [url=https://pixeldrain.com/u/abcd1234]Some_file.png[/url]
bbcode += "[url=" + domain_url() + "/u/" + file.id + "]" + file.name + "[/url]\n"
// Markdown example: * [Some_file.png](https://pixeldrain.com/u/abcd1234)
if (files.length > 1) {
markdown += " * "
}
markdown += "[" + file.name + "](" + domain_url() + "/u/" + file.id + ")\n"
}) })
if (share_link.includes("/l/")) { if (share_link.includes("/l/")) {
text += "\n" + share_link + " All " + files.length + " files\n" link_list += "\n" + share_link + " All " + files.length + " files\n"
} bbcode += "\n[url=" + share_link + "]All " + files.length + " files[/url]\n"
markdown += " * [All " + files.length + " files](" + share_link + ")\n"
// Copy the selected text
if (copy_text(text)) {
btn_copy_links.classList.add("button_highlight")
btn_copy_links.innerHTML = "Links copied to clipboard!"
} else {
btn_copy_links.classList.add("button_red")
btn_copy_links.innerHTML = "Copying links failed"
}
}
const copy_bbcode = () => {
// Add the text to the textarea
let text = ""
let files = get_finished_files()
files.forEach(file => {
// Example: [url=https://pixeldrain.com/u/abcd1234]Some_file.png[/url]
text += "[url=" + domain_url() + "/u/" + file.id + "]" + file.name + "[/url]\n"
})
if (share_link.includes("/l/")) {
text += "\n[url=" + share_link + "]All " + files.length + " files[/url]\n"
}
// Copy the selected text
if (copy_text(text)) {
btn_copy_bbcode.classList.add("button_highlight")
btn_copy_bbcode.innerHTML = "BBCode copied to clipboard!"
} else {
btn_copy_bbcode.classList.add("button_red")
btn_copy_bbcode.innerHTML = "Copying links failed"
}
}
const copy_markdown = () => {
// Add the text to the textarea
let text = ""
let files = get_finished_files()
files.forEach(file => {
// Example: * [Some_file.png](https://pixeldrain.com/u/abcd1234)
if (files.length > 1) { text += " * " }
text += "[" + file.name + "](" + domain_url() + "/u/" + file.id + ")\n"
})
if (share_link.includes("/l/")) {
text += " * [All " + files.length + " files](" + share_link + ")\n"
}
// Copy the selected text
if (copy_text(text)) {
btn_copy_markdown.classList.add("button_highlight")
btn_copy_markdown.innerHTML = "Markdown copied to clipboard!"
} else {
btn_copy_markdown.classList.add("button_red")
btn_copy_markdown.innerHTML = "Copying links failed"
} }
} }
@@ -305,7 +262,7 @@ const keydown = (e) => {
switch (e.key) { switch (e.key) {
case "u": file_input_field.click(); break case "u": file_input_field.click(); break
case "t": btn_upload_text.click(); break case "t": btn_upload_text.click(); break
case "c": btn_copy_link.click(); break case "c": btn_copy_link.copy(); break
case "o": btn_open_link.click(); break case "o": btn_open_link.click(); break
case "q": btn_show_qr.click(); break case "q": btn_show_qr.click(); break
case "l": btn_create_list.click(); break case "l": btn_create_list.click(); break
@@ -314,9 +271,9 @@ const keydown = (e) => {
case "f": btn_share_facebook.click(); break case "f": btn_share_facebook.click(); break
case "r": btn_share_reddit.click(); break case "r": btn_share_reddit.click(); break
case "m": btn_share_tumblr.click(); break case "m": btn_share_tumblr.click(); break
case "a": btn_copy_links.click(); break case "a": btn_copy_links.copy(); break
case "d": btn_copy_markdown.click(); break case "d": btn_copy_markdown.copy(); break
case "b": btn_copy_bbcode.click(); break case "b": btn_copy_bbcode.copy(); break
} }
} }
@@ -408,38 +365,35 @@ const keydown = (e) => {
Share Share
</button> </button>
</div> </div>
<button bind:this={btn_copy_link} on:click={copy_link} class="social_buttons" disabled={state !== "finished"}> <CopyButton bind:this={btn_copy_link} text={share_link} large_icon><u>C</u>opy link</CopyButton>
<i class="icon">content_copy</i><br/>
<span><u>C</u>opy link</span>
</button>
<button bind:this={btn_open_link} on:click={open_link} class="social_buttons" disabled={state !== "finished"}> <button bind:this={btn_open_link} on:click={open_link} class="social_buttons" disabled={state !== "finished"}>
<i class="icon">open_in_new</i><br/> <i class="icon">open_in_new</i>
<span><u>O</u>pen link</span> <span><u>O</u>pen link</span>
</button> </button>
<button bind:this={btn_show_qr} on:click={show_qr_code} class="social_buttons" disabled={state !== "finished"} class:button_highlight={qr_visible}> <button bind:this={btn_show_qr} on:click={show_qr_code} class="social_buttons" disabled={state !== "finished"} class:button_highlight={qr_visible}>
<i class="icon">qr_code</i><br/> <i class="icon">qr_code</i>
<span><u>Q</u>R code</span> <span><u>Q</u>R code</span>
</button> </button>
<div class="social_buttons" class:hide={navigator_share}> <div style="display: inline-block;" class:hide={navigator_share}>
<button bind:this={btn_share_email} on:click={share_mail} class="social_buttons" disabled={state !== "finished"}> <button bind:this={btn_share_email} on:click={share_mail} class="social_buttons" disabled={state !== "finished"}>
<i class="icon">email</i><br/> <i class="icon">email</i>
<u>E</u>-Mail <span><u>E</u>-Mail</span>
</button> </button>
<button bind:this={btn_share_twitter} on:click={share_twitter} class="social_buttons" disabled={state !== "finished"}> <button bind:this={btn_share_twitter} on:click={share_twitter} class="social_buttons" disabled={state !== "finished"}>
<Twitter style="width: 40px; height: 40px; margin: 5px 15px;"></Twitter><br/> <Twitter style="width: 40px; height: 40px;"></Twitter>
T<u>w</u>itter <span>T<u>w</u>itter</span>
</button> </button>
<button bind:this={btn_share_facebook} on:click={share_facebook} class="social_buttons" disabled={state !== "finished"}> <button bind:this={btn_share_facebook} on:click={share_facebook} class="social_buttons" disabled={state !== "finished"}>
<Facebook style="width: 40px; height: 40px; margin: 5px 15px;"></Facebook><br/> <Facebook style="width: 40px; height: 40px;"></Facebook>
<u>F</u>acebook <span><u>F</u>acebook</span>
</button> </button>
<button bind:this={btn_share_reddit} on:click={share_reddit} class="social_buttons" disabled={state !== "finished"}> <button bind:this={btn_share_reddit} on:click={share_reddit} class="social_buttons" disabled={state !== "finished"}>
<Reddit style="width: 40px; height: 40px; margin: 5px 15px;"></Reddit><br/> <Reddit style="width: 40px; height: 40px;"></Reddit>
<u>R</u>eddit <span><u>R</u>eddit</span>
</button> </button>
<button bind:this={btn_share_tumblr} on:click={share_tumblr} class="social_buttons" disabled={state !== "finished"}> <button bind:this={btn_share_tumblr} on:click={share_tumblr} class="social_buttons" disabled={state !== "finished"}>
<Tumblr style="width: 40px; height: 40px; margin: 5px 15px;"></Tumblr><br/> <Tumblr style="width: 40px; height: 40px;"></Tumblr>
Tu<u>m</u>blr <span>Tu<u>m</u>blr</span>
</button> </button>
</div> </div>
<br/> <br/>
@@ -447,18 +401,10 @@ const keydown = (e) => {
<img src="/api/misc/qr?text={encodeURIComponent(share_link)}" alt="QR code" style="width: 300px; max-width: 100%;"> <img src="/api/misc/qr?text={encodeURIComponent(share_link)}" alt="QR code" style="width: 300px; max-width: 100%;">
<br/> <br/>
{/if} {/if}
<button bind:this={btn_copy_links} on:click={copy_links} disabled={state !== "finished"}>
<i class="icon">content_copy</i> <CopyButton bind:this={btn_copy_links} text={link_list}>Copy <u>a</u>ll links to clipboard</CopyButton>
<span>Copy <u>a</u>ll links to clipboard</span> <CopyButton bind:this={btn_copy_markdown} text={markdown}>Copy mark<u>d</u>own to clipboard</CopyButton>
</button> <CopyButton bind:this={btn_copy_bbcode} text={bbcode}>Copy <u>B</u>BCode to clipboard</CopyButton>
<button bind:this={btn_copy_markdown} on:click={copy_markdown} disabled={state !== "finished"}>
<i class="icon">content_copy</i>
<span>Copy mark<u>d</u>own to clipboard</span>
</button>
<button bind:this={btn_copy_bbcode} on:click={copy_bbcode} disabled={state !== "finished"}>
<i class="icon">content_copy</i>
<span>Copy <u>B</u>BCode to clipboard</span>
</button>
<br/> <br/>
{#if window.user.subscription.name === ""} {#if window.user.subscription.name === ""}
@@ -498,7 +444,7 @@ const keydown = (e) => {
width: 40%; width: 40%;
min-width: 300px; min-width: 300px;
max-width: 400px; max-width: 400px;
margin: 10px !important; margin: 10px;
border-radius: 32px; border-radius: 32px;
font-size: 1.8em; font-size: 1.8em;
justify-content: center; justify-content: center;
@@ -537,8 +483,8 @@ const keydown = (e) => {
} }
.social_buttons { .social_buttons {
margin: 5px; flex-direction: column;
display: inline-block min-width: 5em;
} }
.social_buttons.hide { .social_buttons.hide {
display: none; display: none;
@@ -546,9 +492,6 @@ const keydown = (e) => {
.social_buttons > .icon { .social_buttons > .icon {
font-size: 40px; font-size: 40px;
display: inline-block; display: inline-block;
width: 40px;
height: 40px;
margin: 5px 15px;
} }
.hide { .hide {
display: none; display: none;

View File

@@ -0,0 +1,58 @@
<script>
import { copy_text } from "../util/Util.svelte";
export let text = ""
export let style = ""
export let large_icon = false
let failed = false
let success = false
// Exported so it can be called manually
export const copy = () => {
try {
copy_text(text)
success = true
} catch (err) {
console.error("Failed to copy text", err)
failed = true
}
setTimeout(() => {
success = false
failed = false
}, 10000)
}
</script>
<button
on:click={copy}
style={style}
class="button"
class:button_highlight={success}
class:button_red={failed}
class:large_icon
title="Copy text to clipboard"
disabled={text === ""}
>
<i class="icon">content_copy</i>
<span>
{#if success}
Copied!
{:else if failed}
Copy failed
{:else}
<slot></slot>
{/if}
</span>
</button>
<style>
.large_icon {
flex-direction: column;
min-width: 5em;
}
.large_icon>.icon {
font-size: 40px;
display: block;
}
</style>

View File

@@ -20,9 +20,9 @@ import Speedtest from "./Speedtest.svelte";
</p> </p>
<p> <p>
The speed measured is the maximum speed reached for two continuous The speed measured is the maximum speed reached for two continuous
seconds during the test. The normal test has a time limit of 15 seconds during the test. The normal test has a time limit of 12
seconds and the long test 30 seconds. When the maximum speed has not seconds and the long test 30 seconds. When the maximum speed has not
changed for a third of the test duration (5 or 10 seconds) the test changed for a third of the test duration (4 or 10 seconds) the test
will end and the result will be final. The long test will use much will end and the result will be final. The long test will use much
more bandwidth, so if you're on a cap it's recommended to use the more bandwidth, so if you're on a cap it's recommended to use the
normal test. normal test.

View File

@@ -3,7 +3,7 @@ import { onMount } from "svelte";
import Button from "../layout/Button.svelte"; import Button from "../layout/Button.svelte";
import { formatDataVolume, formatDataVolumeBits } from "../util/Formatting.svelte"; import { formatDataVolume, formatDataVolumeBits } from "../util/Formatting.svelte";
import ProgressBar from "../util/ProgressBar.svelte"; import ProgressBar from "../util/ProgressBar.svelte";
import { copy_text } from "../util/Util.svelte"; import CopyButton from "../layout/CopyButton.svelte";
let running = false let running = false
let data_received = 0 let data_received = 0
@@ -161,15 +161,9 @@ onMount(() => {
<section class="highlight_border"> <section class="highlight_border">
<div style="text-align: center"> <div style="text-align: center">
<Button icon="speed" label="Start test" click={() => start(15000)} disabled={running} highlight={!running}/> <Button icon="speed" label="Start test" click={() => start(12000)} disabled={running} highlight={!running}/>
<Button icon="speed" label="Long test" click={() => start(30000)} disabled={running}/> <Button icon="speed" label="Long test" click={() => start(30000)} disabled={running}/>
<Button <CopyButton text={result_link}>Copy test result</CopyButton>
highlight_on_click
disabled={result_link === ""}
icon="content_copy"
label="Copy test result"
click={e => copy_text(result_link)}
/>
</div> </div>
<!-- This progress bar shows either the progress for the test duration, or <!-- This progress bar shows either the progress for the test duration, or

View File

@@ -1,7 +1,7 @@
<script> <script>
import { onMount } from "svelte"; import { onMount } from "svelte";
import LoadingIndicator from "../util/LoadingIndicator.svelte"; import LoadingIndicator from "../util/LoadingIndicator.svelte";
import { copy_text } from "../util/Util.svelte"; import CopyButton from "../layout/CopyButton.svelte";
let loading = false let loading = false
let app_name = "" let app_name = ""
@@ -31,13 +31,6 @@ const create_key = async () => {
} }
} }
let copied = false
const copy_key = () => {
if (copy_text(api_key)) {
copied = true
}
}
let show_key = "" let show_key = ""
const toggle_show_key = () => { const toggle_show_key = () => {
if (show_key === "") { if (show_key === "") {
@@ -109,14 +102,7 @@ onMount(() => {
<h4>Key created</h4> <h4>Key created</h4>
<div class="copy_container"> <div class="copy_container">
<button on:click={copy_key} class="copy_button" class:button_highlight={copied}> <CopyButton text={api_key}>Copy key to clipboard</CopyButton>
<i class="icon">content_copy</i>
{#if copied}
Copied!
{:else}
Copy key to clipboard
{/if}
</button>
<button on:click={toggle_show_key} class="copy_button" class:button_highlight={show_key !== ""}> <button on:click={toggle_show_key} class="copy_button" class:button_highlight={show_key !== ""}>
<i class="icon">visibility</i> <i class="icon">visibility</i>
{#if show_key === ""} {#if show_key === ""}

View File

@@ -12,19 +12,12 @@ export function print_date(date, hours, minutes, seconds) {
} }
export function copy_text(text) { export function copy_text(text) {
// Create a textarea to copy the text from try {
let ta = document.createElement("textarea"); navigator.clipboard.writeText(text)
ta.setAttribute("readonly", "readonly") } catch (err) {
ta.style.position = "absolute"; return false
ta.style.left = "-9999px"; }
ta.value = text; // Put the text in the textarea return true;
// Add the textarea to the DOM so it can be seleted by the user
document.body.appendChild(ta);
ta.select() // Select the contents of the textarea
let success = document.execCommand("copy"); // Copy the selected text
document.body.removeChild(ta); // Remove the textarea
return success;
} }
export function domain_url() { export function domain_url() {