v1.2.0 - Add manual URL generation

This commit is contained in:
Solninja A committed 2025-01-27 14:25:00 +10:00
1 parent 888138e93b
commit ebe07d8f8b
7 files changed
+387 -39

No files matched your search

+157
View File
@@ -0,0 +1,157 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
display: flex;
flex-direction: column;
padding: 5px;
height: 300px;
}
div {
display: flex;
align-items: baseline;
}
label {
padding: 0 10px;
width: 600px;
align-items: baseline;
padding: 5px 0;
}
input {
min-width: 150px;
min-height: 17px;
padding: 5px;
border: 2px solid black;
border-radius: 7px;
text-align: center;
}
.warning {
color: red;
display: block !important;
}
.note {
font-weight: bold;
margin-top: 0px;
}
p,
label {
font-size: 15px;
}
code {
font-weight: bold;
}
main {
display: flex;
flex-direction: column;
}
#message,
#message2 {
display: none;
}
.header {
display: flex;
align-items: center;
}
.header img {
padding-right: 10px;
}
.settings {
border: 2px solid black;
padding: 10px;
border-radius: 10px;
margin-top: 5px;
}
.settings h2 {
min-width: 110px;
}
.checkbox {
flex-wrap: wrap;
}
</style>
</head>
<body>
<div class="header">
<img src="/icons/chhoto-url-48.png"></img>
<h1>Chhoto URL Settings</h1>
</div>
<div class="settings">
<h2>Instance URL</h2>
<label>
<input type="text" id="host" placeholder="https://l.example.com">
<br>
<p>Don't have one? See <a target="_blank" href="https://github.com/sintan1729/chhoto-url#building-and-running-with-docker">here</a> for more information.</p>
</label>
</div>
<p id="message" class="note">A non-HTTPS connection is insecure! This is disallowed as per Firefox's <a target="_blank" href="https://extensionworkshop.com/documentation/publish/add-on-policies/#development-practices"">development practices</a>.</p>
<div class="settings">
<h2>API Key</h2>
<label>
<input type="password" id="key" placeholder="Long API Key">
<p>This is the API key that the extension will use to connect to your Chhoto URL instance. To enable this, set the <strong>"api_key"</strong> environment variable in the server configuration.</p>
<p>See <strong>Section 1.c</strong> <a target="_blank" href="https://github.com/sintan1729/chhoto-url#building-and-running-with-docker">here</a> for more information.</p>
</label>
</div>
<p class="note">Important: The Chhoto URL server (not the extension) will output in the console whether or not your key is secure. If it isn't, it will generate a suggested key and output it. Always follow its advice.</p>
<div class="settings checkbox">
<h2>Protocol Filters</h2>
<label>
Allow <code>http://</code> links
<input type="checkbox" id="allow-http">
</label>
<label>
Allow <code>https://</code> links
<input type="checkbox" id="allow-https">
</label>
<label>
Allow <code>file://</code> links
<input type="checkbox" id="allow-file">
</label>
<label>
Allow <code>ftp://</code> links
<input type="checkbox" id="allow-ftp">
</label>
</div>
<p class="note">Disabling all filters will allow a link to be created from any URL.</p>
<div class="settings checkbox">
<h2>URL Generation</h2>
<label>
Create shortened links with the website's title
<input type="checkbox" id="generate-with-title">
</label>
<label id="title-word-limit-label">
Short URL word limit
<input type="input" id="title-word-limit">
<p class="note">Inputting "0" will remove the character limit</p>
</label>
<p id="message2" class="note">Inputted value is not a number.</p>
</div>
<script type="application/javascript" src="/lib/browser-polyfill.min.js"></script>
<script type="application/javascript" src="/options/options.js"></script>
</body>
</html>
+221
View File
@@ -0,0 +1,221 @@
/*
* An unofficial extension for easy link shortening using the Chhoto URL API.
* Copyright (C) 2025 Solomon Tech
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* File Overview
* @file This file handles the logic behind the options page
* @copyright Solomon Tech 2025
*/
// Use JavaScript's "strict" mode
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
"use strict";
// Get elements, and define a variable for them
const hostKeyEle = document.getElementById("host");
const apiKeyEle = document.getElementById("key");
const AllowHttpEle = document.getElementById("allow-http");
const AllowHttpsEle = document.getElementById("allow-https");
const AllowFileEle = document.getElementById("allow-file");
const AllowFtpEle = document.getElementById("allow-ftp");
const messageEle = document.getElementById("message");
const generateWithTitleEle = document.getElementById("generate-with-title");
const titleWordLimitLabelEle = document.getElementById("title-word-limit-label");
const titleWordLimitEle = document.getElementById("title-word-limit");
const message2Ele = document.getElementById("message2");
// Get the browser storage
const browserStorage = browser.storage.local;
/*
* Event Listeners
*/
// Chhoto URL host
hostKeyEle.oninput = (event) => {
if (event.type === "click") {
event.preventDefault();
}
// Get the Chhoto URL host
const chhotoHost = hostKeyEle.value.replace(/\/$/, '');
// Catch the exception from the URL constructor
// (this always activates because as the user begins typing, the URL is invalid)
try {
const url = new URL(chhotoHost);
// If a non-HTTPS protocol is selected.
if (url.protocol !== "https:") {
throw new Error("Non-HTTPS protocol is selected.");
};
// Save the host
browserStorage.set({ chhotoHost });
// Remove the "warning" class
messageEle.classList.remove("warning");
} catch (err) {
// If the URL is NOT invalid because of a TypeError
if (err.name !== "TypeError") {
messageEle.classList.add("warning");
// Else, remove warning
} else {
messageEle.classList.remove("warning");
};
};
};
// Chhoto URL API key
apiKeyEle.oninput = (event) => {
if (event.type === "click") {
event.preventDefault();
};
// Get the Chhoto URL API key
const chhotoKey = apiKeyEle.value;
browserStorage.set({ chhotoKey });
};
// Allowed protocols
const allowProtocolsMapping = [
[AllowHttpEle, "http:"],
[AllowHttpsEle, "https:"],
[AllowFileEle, "file:"],
[AllowFtpEle, "ftp:"],
];
for (const [ele, protocol] of allowProtocolsMapping) {
ele.onclick = () => {
// Get allowedProtocols
browserStorage.get("allowedProtocols").then(({ allowedProtocols }) => {
// New set
allowedProtocols = new Set(allowedProtocols);
if (ele.checked) {
allowedProtocols.add(protocol);
} else {
allowedProtocols.delete(protocol);
}
// Save to browser storage
browserStorage.set({ allowedProtocols: Array(...allowedProtocols) });
});
};
}
/*
* URL Generation Options
*/
// Generate with title
generateWithTitleEle.onclick = () => {
browserStorage.get("generateWithTitle").then(({ generateWithTitle }) => {
// Get value
generateWithTitle = generateWithTitleEle.checked;
// Set default display option
let display = "none";
// If generateWithTitle is true
if (generateWithTitle) {
// Reassign variable
display = "block";
}
// Set display and save
titleWordLimitLabelEle.style.display = display;
browserStorage.set({ generateWithTitle });
});
};
// Title character limit
titleWordLimitEle.oninput = (event) => {
if (event.type === "click") {
event.preventDefault();
};
// Get the inputted value
const titleWordLimit = titleWordLimitEle.value;
// If the inputted value is not a number (NaN)
if (isNaN(titleWordLimit)) {
message2Ele.classList.add("warning");
} else {
message2Ele.classList.remove("warning");
browserStorage.set({ titleWordLimit });
};
}
function setCurrentChoice({ chhotoHost, chhotoKey, allowedProtocols, generateWithTitle, titleWordLimit }) {
hostKeyEle.value = chhotoHost || "";
apiKeyEle.value = chhotoKey || "";
// If "allowedProtocols" doesn't exist, set default protocols
// If the user deselects every protocol, this does not activate
// since the value would be empty, not undefined.
//
// In other words, this only gets activated when there is absolutely no data
// regarding "allowedProtocols".
if (!allowedProtocols) {
allowedProtocols = allowProtocolsMapping.flatMap(([_, protocol]) => protocol);
browserStorage.set({ allowedProtocols: allowedProtocols });
}
// If generateWithTitle is undefined, set the default value
if (generateWithTitle === undefined) {
generateWithTitle = false;
browserStorage.set({ generateWithTitle: generateWithTitle });
}
// If titleWordLimit is undefined, set the default value
if (titleWordLimit === undefined) {
titleWordLimit = "0";
browserStorage.set({ titleWordLimit: titleWordLimit });
}
// Initialize a list of protocols that are allowed if unset. This needs
// to be synced with the initialization code in background.js#validateURL.
allowedProtocols = new Set(allowedProtocols);
AllowHttpEle.checked = allowedProtocols.has("http:");
AllowHttpsEle.checked = allowedProtocols.has("https:");
AllowFileEle.checked = allowedProtocols.has("file:");
AllowFtpEle.checked = allowedProtocols.has("ftp:");
generateWithTitleEle.checked = generateWithTitle;
// Set default display
let display = "none";
// If generateWithTitle is true, reassign variable
if (generateWithTitle === true) {
display = "block";
}
// Save
titleWordLimitLabelEle.style.display = display;
titleWordLimitEle.value = titleWordLimit || "0";
}
browserStorage.get().then(setCurrentChoice, (error) => {
console.log(`Error: ${error}`);
});