From c7a3ec8458e531dffa5a96c04ff2980f0c632472 Mon Sep 17 00:00:00 2001 From: Somajit Dey Date: Thu, 19 Sep 2024 17:21:11 +0530 Subject: [PATCH 1/5] js disabled alerts --- app/spa.js | 6 ++++++ index.html | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/app/spa.js b/app/spa.js index 27b8702..151a529 100644 --- a/app/spa.js +++ b/app/spa.js @@ -11,6 +11,12 @@ let spaCurrentPageID = spaHomePageID; for (let el of pages) { el.style.display = 'none'; } + + const jsAlerts = document.getElementsByClassName("spa-js"); + + for (let el of jsAlerts) { + el.style.display = 'none'; + } } function spaTop(){ diff --git a/index.html b/index.html index b1f5087..1d53f36 100755 --- a/index.html +++ b/index.html @@ -39,6 +39,10 @@

Menu

Server: None yet
+ + +

You don't have JavaScript enabled! This page cannot function without it.

+

About

From 76c10166018c3653529ec2626c89d8f90caa193f Mon Sep 17 00:00:00 2001 From: Somajit Dey Date: Thu, 19 Sep 2024 17:47:18 +0530 Subject: [PATCH 2/5] Using template literals --- app/bg-worker.js | 12 ++++++------ app/server.js | 21 ++++++++++++--------- app/spa.js | 8 ++++---- index.html | 1 - 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/app/bg-worker.js b/app/bg-worker.js index 61a68be..17be65d 100644 --- a/app/bg-worker.js +++ b/app/bg-worker.js @@ -11,7 +11,7 @@ function urlEncoded2Json(str){ for (let el of arr) { let elArray = el.split('='); let val = decodeURIComponent(elArray[1].replace( /\+/g, ' ' )).replace(/"/g,'\\"'); // Decoded and escaped - eval('obj.' + elArray[0] +'="' + val +'"'); + eval(`obj.${elArray[0]}="${val}"`); } return JSON.stringify(obj); @@ -29,7 +29,7 @@ async function pollApi(getFrom, postTo, TGchatID) { if (! response.ok) { errLvl = 1; // Set error to critical/fatal - throw "GET @ " + getFrom + " status: " + response.status; + throw `GET @ ${getFrom} status: ${response.status}`; } data = urlEncoded2Json(await response.text()); @@ -37,7 +37,7 @@ async function pollApi(getFrom, postTo, TGchatID) { postMessage([data, 0]); } catch (error) { - console.error(Date() + ': Error making GET request --', error); + console.error(`${Date()}: Error making GET request -- ${error}`); // Send error to main for logging. Error level: 1 for high priority / fatal. postMessage(['Failed to fetch form data.', errLvl]); return; @@ -57,17 +57,17 @@ async function pollApi(getFrom, postTo, TGchatID) { }) if (! response.ok) { - throw "POST @ " + postTo + " status: " + response.status +". Is chat ID = " + TGchatID + " ok?"; + throw `POST @ ${postTo} status: ${response.status}. Is chat ID = ${TGchatID} ok?`; } } catch (error) { - console.error(Date() + ': Error making POST request --', error); + console.error(`${Date()}: Error making POST request -- ${error}`); // Send error to main for logging. Error level: 2 for low priority / non-fatal. postMessage(['Failed to post form data to Telegram.', errLvl]); return; } - console.log(Date() + ": Relay complete."); + console.log(`${Date()}: Relay complete.`); }; relay(); // Start the first relay diff --git a/app/server.js b/app/server.js index 541bf14..005ab30 100644 --- a/app/server.js +++ b/app/server.js @@ -9,7 +9,7 @@ const toggleServer = document.getElementById("toggleServer"); function logThis(report) { const row = document.createElement("p"); - row.append(Date() + ": " + report); + row.append(`${Date()}: ${report}`); logs.prepend(row); } @@ -37,7 +37,7 @@ function inbox(json){ const cell = document.createElement("td"); // Create a text entry: - entry = eval("data." + keysEnumArray[key]); + entry = eval(`data.${keysEnumArray[key]}`); // Append entry to cell: cell.append(entry); @@ -74,12 +74,16 @@ const fetchChatID = async () => { const apiEndpoint = 'https://api.telegram.org/bot' + document.getElementById("apiKey").value + '/getUpdates'; const response = await fetch(apiEndpoint); // Make request if (! response.ok) { - logThis("Telegram API status code:" + response.status +". Is Bot API Token ok?"); + logThis(`Telegram API status code: ${response.status}. Is Bot API Token ok?`); alert("Failed to fetch chat ID. Check your Bot API Token!"); return; } const data = await response.json(); - document.getElementById("chatID").value = data.result[0].message.chat.id; + try { + TGchatID = data.result[0].message.chat.id; + } catch (e) { + alert("Failed to fetch chat ID. Send any text to the Telegram Bot then try again."); + } } function config() { @@ -89,8 +93,7 @@ function config() { const randomIdx = Math.floor(parseInt(uuid.substr(0,2),16)*relayList.length/256); getFrom = relayList[randomIdx] + '/' + uuid; postTo = 'https://api.telegram.org/bot' + document.getElementById("apiKey").value + '/sendMessage'; - TGchatID = document.getElementById("chatID").value; - document.getElementById("config").innerHTML = '

HTML Form Action URL: ' + getFrom + '

'; + document.getElementById("config").innerHTML = `

HTML Form Action URL: ${getFrom}

`; document.getElementById("testFormBtn").setAttribute("formaction", getFrom); spaShowHide("testForm"); document.getElementById("config").scrollIntoView(); @@ -109,13 +112,13 @@ function startWorker() { const msg = e.data[0]; if (! errLvl) { inbox(msg); - logThis('RECEIVED: ' + msg); + logThis(`RECEIVED: ${msg}`); } else if (errLvl === 1) { stopWorker(); - logThis('FATAL ERROR: ' + msg + ' See console for details.'); + logThis(`FATAL ERROR: ${msg}. See console for details.`); alert('Server stopped due to some critical error'); } else { - logThis('ERROR: ' + msg + ' See console for details.'); + logThis(`ERROR: ${msg}. See console for details.`); } } diff --git a/app/spa.js b/app/spa.js index 151a529..6c08bb6 100644 --- a/app/spa.js +++ b/app/spa.js @@ -6,15 +6,15 @@ const spaHomePageID = document.querySelector(".spa-page").id; // Assuming first let spaCurrentPageID = spaHomePageID; { - const pages = document.getElementsByClassName("spa-page"); + const jsAlerts = document.getElementsByClassName("spa-js"); - for (let el of pages) { + for (let el of jsAlerts) { el.style.display = 'none'; } - const jsAlerts = document.getElementsByClassName("spa-js"); + const pages = document.getElementsByClassName("spa-page"); - for (let el of jsAlerts) { + for (let el of pages) { el.style.display = 'none'; } } diff --git a/index.html b/index.html index 1d53f36..6a7c862 100755 --- a/index.html +++ b/index.html @@ -104,7 +104,6 @@

Server


2. Send any text to the Bot. Then, click Fetch Chat ID. Or, enter your chat ID if you know what you're doing :-)

-

3. Generate or enter your EasyForm API Key:

From fb230790fe7e818f7daa24563d7f1ac2e532a2c2 Mon Sep 17 00:00:00 2001 From: Somajit Dey Date: Fri, 20 Sep 2024 01:46:54 +0530 Subject: [PATCH 3/5] Uses localstorage --- app/server.js | 58 +++++++++++++++++++++++++++++++----------- app/spa.js | 44 ++++++++++++++++---------------- index.html | 70 +++++++++++++++++++++++---------------------------- 3 files changed, 98 insertions(+), 74 deletions(-) diff --git a/app/server.js b/app/server.js index 005ab30..31ec187 100644 --- a/app/server.js +++ b/app/server.js @@ -1,7 +1,8 @@ // Main entry point for the server. Deploys background worker in "bg-worker.js" for handling networking. +spaHide("jsAlert"); + let myWorker = null; -let getFrom, postTo, TGchatID; let numReadMsgs = 0; let numTotalMsgs = 0; const logs = document.getElementById("logs"); @@ -70,8 +71,8 @@ function genUUID() { } const fetchChatID = async () => { - logThis("Fetching Telegram chat ID") - const apiEndpoint = 'https://api.telegram.org/bot' + document.getElementById("apiKey").value + '/getUpdates'; + logThis("Fetching Telegram chat ID"); + const apiEndpoint = 'https://api.telegram.org/bot' + document.getElementById("TGbotKey").value + '/getUpdates'; const response = await fetch(apiEndpoint); // Make request if (! response.ok) { logThis(`Telegram API status code: ${response.status}. Is Bot API Token ok?`); @@ -80,7 +81,9 @@ const fetchChatID = async () => { } const data = await response.json(); try { - TGchatID = data.result[0].message.chat.id; + const TGchatID = data.result[0].message.chat.id; + document.getElementById("chatID").value = TGchatID; + localStorage.setItem("TGchatID", TGchatID); } catch (e) { alert("Failed to fetch chat ID. Send any text to the Telegram Bot then try again."); } @@ -91,19 +94,18 @@ function config() { const uuid = document.getElementById("uuid").value; // Choose a random index in [0, relayList.length]. Use first two nibbles of uuid as random number in range [0,256]. const randomIdx = Math.floor(parseInt(uuid.substr(0,2),16)*relayList.length/256); - getFrom = relayList[randomIdx] + '/' + uuid; - postTo = 'https://api.telegram.org/bot' + document.getElementById("apiKey").value + '/sendMessage'; - document.getElementById("config").innerHTML = `

HTML Form Action URL: ${getFrom}

`; - document.getElementById("testFormBtn").setAttribute("formaction", getFrom); - spaShowHide("testForm"); - document.getElementById("config").scrollIntoView(); + const getFrom = relayList[randomIdx] + '/' + uuid; + localStorage.setItem("getFrom", getFrom); + const postTo = 'https://api.telegram.org/bot' + document.getElementById("TGbotKey").value + '/sendMessage'; + localStorage.setItem("postTo", postTo); + spaGoTo("server"); + localStorage.setItem("loggedIn", "true"); } function startWorker() { - if (getFrom === undefined) { - config(); + if (myWorker) { + return; } - myWorker = new Worker("app/bg-worker.js"); // Register handler for messages from the background worker @@ -122,17 +124,26 @@ function startWorker() { } } + const getFrom = localStorage.getItem("getFrom"); + // Communicate key data to the background worker - myWorker.postMessage([getFrom, postTo, TGchatID]); + myWorker.postMessage([getFrom, localStorage.getItem("postTo"), localStorage.getItem("TGchatID")]); toggleServer.value = "Kill Server"; toggleServer.disabled = false; logThis("Server started"); document.getElementById("serverStatus").innerHTML = 'Live '; + + document.getElementById("formActionURL").innerHTML = `

HTML Form Action URL: ${getFrom}

`; + document.getElementById("testFormBtn").setAttribute("formaction", getFrom); + spaShow("testForm"); } function stopWorker() { + if (! myWorker) { + return; + } myWorker.terminate(); myWorker = null; console.log("Worker terminated"); @@ -148,3 +159,22 @@ function toggleWorker() { startWorker(); } } + +function signout() { + stopWorker(); + localStorage.clear(); + location.reload(); +} + +function main() { + // Enable config if no prior settings found in localStorage + if (localStorage.getItem("loggedIn")) { + startWorker(); + spaGoTo("server"); + } else { + spaGoTo("setup"); + } + +} + +spaHide("jsAlert"); diff --git a/app/spa.js b/app/spa.js index 6c08bb6..a092d5e 100644 --- a/app/spa.js +++ b/app/spa.js @@ -5,20 +5,30 @@ const spaHomePageID = document.querySelector(".spa-page").id; // Assuming first spa-page class is the home / hero page let spaCurrentPageID = spaHomePageID; -{ - const jsAlerts = document.getElementsByClassName("spa-js"); - - for (let el of jsAlerts) { - el.style.display = 'none'; - } +function spaShow(id) { + document.getElementById(id).style.display = 'block'; +} - const pages = document.getElementsByClassName("spa-page"); +function spaHide(id) { + document.getElementById(id).style.display = 'none'; +} - for (let el of pages) { - el.style.display = 'none'; +function spaToggle(id) { + let x = document.getElementById(id); + if (x.style.display === "none") { + x.style.display = "block"; + } else { + x.style.display = "none"; } } +function spaGoTo(id) { + document.getElementById(spaCurrentPageID).style.display = 'none'; + spaShow(id); + spaCurrentPageID = id; + spaTop(); +} + function spaTop(){ document.getElementById(spaCurrentPageID).scrollIntoView(); } @@ -27,19 +37,11 @@ function spaBottom(){ document.getElementById(spaCurrentPageID).scrollIntoView(false); } -function spaGoTo(id) { - document.getElementById(spaCurrentPageID).style.display = 'none'; - document.getElementById(id).style.display = 'block'; - spaCurrentPageID = id; - spaTop(); -} +{ + const pages = document.getElementsByClassName("spa-page"); -function spaShowHide(id) { - let x = document.getElementById(id); - if (x.style.display === "none") { - x.style.display = "block"; - } else { - x.style.display = "none"; + for (let el of pages) { + el.style.display = 'none'; } } diff --git a/index.html b/index.html index 6a7c862..36ed78e 100755 --- a/index.html +++ b/index.html @@ -22,11 +22,9 @@

Welcome to EasyForm

-

Menu

- - + Source Donate Contact @@ -41,45 +39,31 @@

Menu

-

You don't have JavaScript enabled! This page cannot function without it.

+

You don't have JavaScript enabled! This page cannot function without it.

About

-

EasyForm gives you a free and easy, self-hosted form backend solution for adding (contact) forms to your static website(s). You don't, however, need - to configure any server or install anything. Your browser becomes your server! -

-

Your smartphone or PC is perhaps always connected to the internet, even on the move. So, if you keep your browser open there, and a very - light-weight JavaScript server runs in it, you are essentially "self-hosting" for free. EasyForm capitalizes on this. Also, the ability to run in a - browser makes EasyForm platform-independent! +

EasyForm gives you a free and easy, self-hosted form backend solution that runs in your browser! Just sign up and then embed the following HTML + form in your website. Therefrom, as long as this Tab is open in your browser, whenever your users submit the form in your website, your Inbox here + will be populated. You will also be notified via Telegram.

- Working with EasyForm is dead simple. All you need to do is the following: -
    -
  • Create a Telegram Bot and store its API token. This is easy. Just open a chat with @BotFather in Telegram - and send: /newbot -
  • -
  • Follow instructions in the Config: section below. You will be required to choose a Form Action URL there
  • -
  • Use your chosen Form Action URL in your (contact) form
  • -
- Whenever your users submit the form, you will get a Telegram text containing the users' form data from the Telegram Bot you created. -

Here is an HTML code snippet you can readily embed as a basic contact form in your website. Just replace FormActionURL with the actual URL.


-<form action="FormActionURL" method="POST" target="hidden_iframe" autocomplete="on">
+<!-- Replace XXXXX with the form action URL given by this app upon sign up` -->
+<form action="XXXXX" method="POST" target="hidden_iframe" autocomplete="on">
     <input type="hidden" name="From" value="sample">
     <input type="email" name="Email" placeholder="Your Email">
     <input type="text" name="Name" placeholder="Your Name">
     <input type="text" name="Message" placeholder="Your Message" autocomplete="off">
-    <input type="submit" value="Submit">
-    <input type="reset" value="Reset">
+    <button type="submit">Submit<button>
+    <input type="reset">Reset<button>
 </form>
 <!-- when the form is submitted, the server response will appear in this iframe, hidden from view -->
 <iframe name="hidden_iframe" src="about:blank" hidden></iframe>
 
- Tips: -
    -
  • Securely store your Bot API token and Form Action URL for future reference.
  • -
  • For reproducibility upon page reload/refresh, reuse the previous values, often suggested by the browser, during config.
  • -
+ +

+

Powered by

-
+
-

Server

-
-
+

Setup

+

Setup in just 3 easy steps.

- - + +
-

2. Send any text to the Bot. Then, click Fetch Chat ID. Or, enter your chat ID if you know what you're doing :-)

+

2. Send any text to the Bot. Then, click Fetch Chat ID. Do not enter your chat ID by hand.

+

3. Generate or enter your EasyForm API Key:



- +
-
-
+
+
+
+

Server

+
+

Test if everything is working properly with the following sample form. You should get a Telegram message upon clicking Post! Your posted data should also be logged below.

@@ -132,11 +121,14 @@

Server



Log

+ + + +

Server logs will be shown here



-
From 9a478cd7a4f4c2b684829b5f0d40f14a14d25be6 Mon Sep 17 00:00:00 2001 From: Somajit Dey Date: Fri, 20 Sep 2024 02:33:47 +0530 Subject: [PATCH 4/5] server lock using sessionStorage --- app/server.js | 7 ++++++- index.html | 8 +++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/server.js b/app/server.js index 31ec187..5e3dd9f 100644 --- a/app/server.js +++ b/app/server.js @@ -103,9 +103,13 @@ function config() { } function startWorker() { - if (myWorker) { + if (myWorker || sessionStorage.getItem("server")) { + alert('Another server is already running. Only one server can run at a time.'); return; + } else { + sessionStorage.setItem("server", "live"); } + myWorker = new Worker("app/bg-worker.js"); // Register handler for messages from the background worker @@ -146,6 +150,7 @@ function stopWorker() { } myWorker.terminate(); myWorker = null; + sessionStorage.removeItem("server"); console.log("Worker terminated"); toggleServer.value = "Launch Server" logThis("Server stopped"); diff --git a/index.html b/index.html index 36ed78e..2ee8cec 100755 --- a/index.html +++ b/index.html @@ -50,11 +50,11 @@

About


 <!-- Replace XXXXX with the form action URL given by this app upon sign up` -->
-<form action="XXXXX" method="POST" target="hidden_iframe" autocomplete="on">
+<form action="XXXXX" method="POST" target="hidden_iframe">
     <input type="hidden" name="From" value="sample">
     <input type="email" name="Email" placeholder="Your Email">
     <input type="text" name="Name" placeholder="Your Name">
-    <input type="text" name="Message" placeholder="Your Message" autocomplete="off">
+    <input type="text" name="Message" placeholder="Your Message">
     <button type="submit">Submit<button>
     <input type="reset">Reset<button>
 </form>
@@ -102,7 +102,9 @@ 

Setup

Server

-

Test if everything is working properly with the following sample form. You should get a Telegram message upon clicking Post! Your posted data should also be logged below.

+

Test if everything is working properly with the following sample form (embed in your own website with + ). You should get a Telegram message upon clicking Post! Your posted data + should also be logged below.

From 5f683403c8a592ebf374b8ae47ddb21346aa0630 Mon Sep 17 00:00:00 2001 From: Somajit Dey Date: Fri, 20 Sep 2024 03:51:41 +0530 Subject: [PATCH 5/5] ready form URL --- 404.html | 39 +++++++++++++++++++++++++++++++++++++++ app/server.js | 1 + index.html | 7 +++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 404.html diff --git a/404.html b/404.html new file mode 100644 index 0000000..5f8a0a4 --- /dev/null +++ b/404.html @@ -0,0 +1,39 @@ + + + + EasyForm + + + + + + + + + + + + + +

Hello there! Feel free to post your message/comment/query to me

+ + +
+
+ +
+
+ +
+ +
+ + + + + + + + diff --git a/app/server.js b/app/server.js index 5e3dd9f..3d93ded 100644 --- a/app/server.js +++ b/app/server.js @@ -140,6 +140,7 @@ function startWorker() { document.getElementById("serverStatus").innerHTML = 'Live '; document.getElementById("formActionURL").innerHTML = `

HTML Form Action URL: ${getFrom}

`; + document.getElementById("readyForm").href = `./${btoa(getFrom).replace(/\+/g,'_').replace(/\//g,'-')}`; document.getElementById("testFormBtn").setAttribute("formaction", getFrom); spaShow("testForm"); } diff --git a/index.html b/index.html index 2ee8cec..04da7fe 100755 --- a/index.html +++ b/index.html @@ -45,8 +45,7 @@

Welcome to EasyForm

About

EasyForm gives you a free and easy, self-hosted form backend solution that runs in your browser! Just sign up and then embed the following HTML - form in your website. Therefrom, as long as this Tab is open in your browser, whenever your users submit the form in your website, your Inbox here - will be populated. You will also be notified via Telegram. + form in your website. You also get your own contact form URL that you can use if you don't have a website.


 <!-- Replace XXXXX with the form action URL given by this app upon sign up` -->
@@ -61,6 +60,9 @@ 

About

<!-- when the form is submitted, the server response will appear in this iframe, hidden from view --> <iframe name="hidden_iframe" src="about:blank" hidden></iframe>
+

As long as this Tab is open in your browser, whenever your users submit the form, your Inbox here will be populated. + You will also be notified via Telegram. +

@@ -105,6 +107,7 @@

Server

Test if everything is working properly with the following sample form (embed in your own website with ). You should get a Telegram message upon clicking Post! Your posted data should also be logged below.

+

You also get your own contact form URL.